From af7f79818ddeb17836b31bbdf9fdd7c336af73d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20FIDRY?= Date: Sun, 4 Feb 2024 20:08:42 +0100 Subject: [PATCH] revert undesired changes --- composer.json | 253 +- preload.php | 1497 ---------- src/Analyser/Analyser.php | 190 +- src/Analyser/AnalyserResult.php | 62 +- src/Analyser/ArgumentsNormalizer.php | 97 +- src/Analyser/ConditionalExpressionHolder.php | 45 +- src/Analyser/ConstantResolver.php | 14 +- src/Analyser/ConstantResolverFactory.php | 21 +- src/Analyser/DirectInternalScopeFactory.php | 182 +- src/Analyser/EnsuredNonNullabilityResult.php | 12 +- .../EnsuredNonNullabilityResultExpression.php | 28 +- src/Analyser/Error.php | 220 +- src/Analyser/ExpressionContext.php | 28 +- src/Analyser/ExpressionResult.php | 33 +- src/Analyser/ExpressionTypeHolder.php | 23 +- src/Analyser/FileAnalyser.php | 497 ++-- src/Analyser/FileAnalyserResult.php | 34 +- src/Analyser/Ignore/IgnoreLexer.php | 5 +- src/Analyser/Ignore/IgnoreParseException.php | 7 +- src/Analyser/Ignore/IgnoredError.php | 11 +- src/Analyser/Ignore/IgnoredErrorHelper.php | 32 +- .../IgnoredErrorHelperProcessedResult.php | 22 +- .../Ignore/IgnoredErrorHelperResult.php | 92 +- src/Analyser/InternalScopeFactory.php | 20 +- src/Analyser/LazyInternalScopeFactory.php | 115 +- src/Analyser/MutatingScope.php | 2412 ++++++++++------ src/Analyser/NameScope.php | 85 +- src/Analyser/ResultCache/ResultCache.php | 58 +- .../ResultCache/ResultCacheClearer.php | 7 +- .../ResultCache/ResultCacheManager.php | 128 +- .../ResultCache/ResultCacheProcessResult.php | 12 +- src/Analyser/RuleErrorTransformer.php | 22 +- src/Analyser/ScopeContext.php | 22 +- src/Analyser/ScopeFactory.php | 7 +- src/Analyser/SpecifiedTypes.php | 34 +- src/Analyser/StatementContext.php | 10 +- src/Analyser/StatementExitPoint.php | 12 +- src/Analyser/StatementResult.php | 34 +- src/Analyser/ThrowPoint.php | 34 +- src/Analyser/TypeSpecifier.php | 2470 ++++++++++------- src/Analyser/TypeSpecifierContext.php | 11 +- src/Analyser/TypeSpecifierFactory.php | 26 +- src/Analyser/UndefinedVariableException.php | 12 +- src/Broker/AnonymousClassNameHelper.php | 48 +- src/Broker/Broker.php | 20 +- src/Broker/BrokerFactory.php | 12 +- src/Broker/ClassAutoloadingException.php | 23 +- src/Broker/ClassNotFoundException.php | 7 +- src/Broker/ConstantNotFoundException.php | 7 +- src/Broker/FunctionNotFoundException.php | 7 +- src/Cache/Cache.php | 7 +- src/Cache/CacheItem.php | 12 +- src/Cache/FileCacheStorage.php | 16 +- src/Cache/MemoryCacheStorage.php | 2 +- src/Collectors/CollectedData.php | 39 +- src/Collectors/Registry.php | 4 +- src/Collectors/RegistryFactory.php | 11 +- src/Command/AnalyseApplication.php | 335 +-- src/Command/AnalyseCommand.php | 85 +- src/Command/AnalyserRunner.php | 128 +- src/Command/AnalysisResult.php | 70 +- src/Command/ClearResultCacheCommand.php | 25 +- src/Command/CommandHelper.php | 97 +- src/Command/DumpParametersCommand.php | 24 +- .../BaselineNeonErrorFormatter.php | 97 +- .../BaselinePhpErrorFormatter.php | 149 +- .../CheckstyleErrorFormatter.php | 140 +- .../CiDetectedErrorFormatter.php | 18 +- src/Command/ErrorFormatter/ErrorFormatter.php | 5 +- .../ErrorFormatter/GithubErrorFormatter.php | 10 +- .../ErrorFormatter/GitlabErrorFormatter.php | 16 +- .../ErrorFormatter/JsonErrorFormatter.php | 7 +- .../ErrorFormatter/JunitErrorFormatter.php | 90 +- .../ErrorFormatter/RawErrorFormatter.php | 17 +- .../ErrorFormatter/TableErrorFormatter.php | 301 +- .../ErrorFormatter/TeamcityErrorFormatter.php | 7 +- src/Command/ErrorsConsoleStyle.php | 20 +- src/Command/FixerApplication.php | 536 ++-- src/Command/FixerWorkerCommand.php | 64 +- src/Command/IgnoredRegexValidator.php | 24 +- src/Command/IgnoredRegexValidatorResult.php | 34 +- src/Command/InceptionResult.php | 51 +- src/Command/Symfony/SymfonyOutput.php | 16 +- src/Command/Symfony/SymfonyStyle.php | 7 +- src/Command/WorkerCommand.php | 39 +- src/Dependency/DependencyResolver.php | 64 +- .../ExportedNode/ExportedAttributeNode.php | 26 +- .../ExportedClassConstantNode.php | 36 +- .../ExportedClassConstantsNode.php | 45 +- .../ExportedNode/ExportedClassNode.php | 96 +- .../ExportedNode/ExportedEnumCaseNode.php | 29 +- .../ExportedNode/ExportedEnumNode.php | 62 +- .../ExportedNode/ExportedFunctionNode.php | 62 +- .../ExportedNode/ExportedInterfaceNode.php | 38 +- .../ExportedNode/ExportedMethodNode.php | 102 +- .../ExportedNode/ExportedParameterNode.php | 60 +- .../ExportedNode/ExportedPhpDocNode.php | 22 +- .../ExportedNode/ExportedPropertiesNode.php | 76 +- .../ExportedNode/ExportedTraitNode.php | 7 +- .../ExportedTraitUseAdaptation.php | 109 +- src/Dependency/ExportedNodeFetcher.php | 18 +- src/Dependency/ExportedNodeResolver.php | 194 +- src/Dependency/ExportedNodeVisitor.php | 14 +- src/Dependency/NodeDependencies.php | 22 +- .../BleedingEdgeToggle.php | 5 +- .../ConditionalTagsExtension.php | 4 +- src/DependencyInjection/Configurator.php | 21 +- src/DependencyInjection/ContainerFactory.php | 334 ++- .../DerivativeContainerFactory.php | 73 +- .../DuplicateIncludedFilesException.php | 7 +- .../InvalidIgnoredErrorPatternsException.php | 7 +- src/DependencyInjection/LoaderFactory.php | 28 +- .../MemoizingContainer.php | 9 +- src/DependencyInjection/NeonAdapter.php | 28 +- src/DependencyInjection/NeonLoader.php | 16 +- .../Nette/NetteContainer.php | 11 +- ...assReflectionExtensionRegistryProvider.php | 23 +- ...micReturnTypeExtensionRegistryProvider.php | 22 +- .../LazyDynamicThrowTypeExtensionProvider.php | 7 +- ...nTypeResolverExtensionRegistryProvider.php | 18 +- ...ypeSpecifyingExtensionRegistryProvider.php | 19 +- .../ValidateIgnoredErrorsExtension.php | 34 +- src/File/FileExcluder.php | 15 +- src/File/FileExcluderFactory.php | 22 +- src/File/FileExcluderRawFactory.php | 4 +- src/File/FileFinder.php | 26 +- src/File/FileFinderResult.php | 12 +- src/File/FileHelper.php | 5 +- src/File/FileMonitor.php | 18 +- src/File/FileMonitorResult.php | 28 +- src/File/FileWriter.php | 5 +- src/File/FuzzyRelativePathHelper.php | 163 +- .../ParentDirectoryRelativePathHelper.php | 7 +- src/File/PathNotFoundException.php | 7 +- src/File/SimpleRelativePathHelper.php | 7 +- src/Internal/ComposerHelper.php | 7 +- src/Internal/DirectoryCreator.php | 9 +- src/Internal/DirectoryCreatorException.php | 16 +- src/Node/BooleanAndNode.php | 15 +- src/Node/BooleanOrNode.php | 15 +- src/Node/BreaklessWhileLoopNode.php | 12 +- src/Node/CatchWithUnthrownExceptionNode.php | 17 +- src/Node/ClassConstantsNode.php | 22 +- src/Node/ClassMethod.php | 11 +- src/Node/ClassMethodsNode.php | 22 +- src/Node/ClassPropertiesNode.php | 67 +- src/Node/ClassPropertyNode.php | 88 +- src/Node/ClassStatementsGatherer.php | 35 +- src/Node/ClosureReturnStatementsNode.php | 33 +- src/Node/CollectedDataNode.php | 12 +- src/Node/Constant/ClassConstantFetch.php | 12 +- src/Node/DoWhileLoopConditionNode.php | 12 +- src/Node/ExecutionEndNode.php | 22 +- src/Node/Expr/AlwaysRememberedExpr.php | 17 +- src/Node/Expr/GetIterableKeyTypeExpr.php | 7 +- src/Node/Expr/GetIterableValueTypeExpr.php | 7 +- src/Node/Expr/GetOffsetValueTypeExpr.php | 12 +- src/Node/Expr/OriginalPropertyTypeExpr.php | 15 +- src/Node/Expr/PropertyInitializationExpr.php | 7 +- src/Node/Expr/SetOffsetValueTypeExpr.php | 17 +- src/Node/Expr/TypeExpr.php | 7 +- src/Node/FileNode.php | 7 +- src/Node/FinallyExitPointsNode.php | 12 +- src/Node/FunctionCallableNode.php | 15 +- src/Node/FunctionReturnStatementsNode.php | 40 +- src/Node/InArrowFunctionNode.php | 12 +- src/Node/InClassMethodNode.php | 22 +- src/Node/InClassNode.php | 12 +- src/Node/InClosureNode.php | 12 +- src/Node/InForeachNode.php | 7 +- src/Node/InFunctionNode.php | 16 +- src/Node/InTraitNode.php | 12 +- src/Node/InstantiationCallableNode.php | 15 +- src/Node/IssetExpr.php | 10 +- src/Node/LiteralArrayItem.php | 12 +- src/Node/LiteralArrayNode.php | 7 +- src/Node/MatchExpressionArm.php | 17 +- src/Node/MatchExpressionArmBody.php | 12 +- src/Node/MatchExpressionArmCondition.php | 17 +- src/Node/MatchExpressionNode.php | 23 +- src/Node/Method/MethodCall.php | 19 +- src/Node/MethodCallableNode.php | 25 +- src/Node/MethodReturnStatementsNode.php | 45 +- src/Node/Printer/ExprPrinter.php | 7 +- src/Node/Property/PropertyRead.php | 19 +- src/Node/Property/PropertyWrite.php | 20 +- src/Node/PropertyAssignNode.php | 30 +- src/Node/ReturnStatement.php | 14 +- src/Node/StaticMethodCallableNode.php | 26 +- src/Node/UnreachableStatementNode.php | 7 +- src/Node/VarTagChangedExpressionTypeNode.php | 12 +- src/Parallel/ParallelAnalyser.php | 439 +-- src/Parallel/Process.php | 36 +- src/Parallel/ProcessPool.php | 9 +- src/Parallel/Schedule.php | 12 +- src/Parallel/Scheduler.php | 63 +- src/Parser/CachedParser.php | 38 +- src/Parser/CleaningParser.php | 12 +- src/Parser/CleaningVisitor.php | 5 +- src/Parser/DeclarePositionVisitor.php | 5 +- src/Parser/LexerFactory.php | 7 +- src/Parser/ParentStmtTypesVisitor.php | 2 +- src/Parser/ParserErrorsException.php | 53 +- src/Parser/PathRoutingParser.php | 31 +- src/Parser/PhpParserDecorator.php | 7 +- .../RemoveUnusedCodeByPhpVersionIdVisitor.php | 12 +- src/Parser/RichParser.php | 57 +- src/Parser/SimpleParser.php | 16 +- src/Parser/TraitCollectingVisitor.php | 2 +- src/Parser/TryCatchTypeVisitor.php | 2 +- src/Parser/TypeTraverserInstanceofVisitor.php | 5 +- src/Php/PhpVersion.php | 8 +- src/Php/PhpVersionFactory.php | 16 +- src/Php/PhpVersionFactoryFactory.php | 18 +- src/PhpDoc/ConstExprParserFactory.php | 7 +- src/PhpDoc/CountableStubFilesExtension.php | 7 +- src/PhpDoc/DefaultStubFilesProvider.php | 29 +- ...eNodeResolverExtensionRegistryProvider.php | 7 +- src/PhpDoc/JsonValidateStubFilesExtension.php | 7 +- ...eNodeResolverExtensionRegistryProvider.php | 19 +- src/PhpDoc/PhpDocBlock.php | 201 +- src/PhpDoc/PhpDocInheritanceResolver.php | 127 +- src/PhpDoc/PhpDocNodeResolver.php | 105 +- src/PhpDoc/PhpDocStringResolver.php | 12 +- .../ReflectionEnumStubFilesExtension.php | 7 +- src/PhpDoc/ResolvedPhpDocBlock.php | 317 ++- src/PhpDoc/StubPhpDocProvider.php | 95 +- src/PhpDoc/StubSourceLocatorFactory.php | 46 +- src/PhpDoc/StubValidator.php | 45 +- src/PhpDoc/Tag/AssertTag.php | 34 +- src/PhpDoc/Tag/AssertTagParameter.php | 28 +- src/PhpDoc/Tag/DeprecatedTag.php | 7 +- src/PhpDoc/Tag/ExtendsTag.php | 7 +- src/PhpDoc/Tag/ImplementsTag.php | 7 +- src/PhpDoc/Tag/MethodTag.php | 22 +- src/PhpDoc/Tag/MethodTagParameter.php | 34 +- src/PhpDoc/Tag/MixinTag.php | 7 +- src/PhpDoc/Tag/ParamOutTag.php | 7 +- src/PhpDoc/Tag/ParamTag.php | 12 +- src/PhpDoc/Tag/PropertyTag.php | 22 +- src/PhpDoc/Tag/RequireExtendsTag.php | 7 +- src/PhpDoc/Tag/RequireImplementsTag.php | 7 +- src/PhpDoc/Tag/ReturnTag.php | 12 +- src/PhpDoc/Tag/SelfOutTypeTag.php | 7 +- src/PhpDoc/Tag/TemplateTag.php | 17 +- src/PhpDoc/Tag/ThrowsTag.php | 7 +- src/PhpDoc/Tag/TypeAliasImportTag.php | 17 +- src/PhpDoc/Tag/TypeAliasTag.php | 27 +- src/PhpDoc/Tag/UsesTag.php | 7 +- src/PhpDoc/Tag/VarTag.php | 7 +- src/PhpDoc/TypeNodeResolver.php | 126 +- ...TypeNodeResolverExtensionAwareRegistry.php | 39 +- src/PhpDoc/TypeStringResolver.php | 17 +- src/Process/CpuCoreCounter.php | 7 +- src/Process/ProcessHelper.php | 17 +- src/Process/ProcessPromise.php | 32 +- .../AnnotationMethodReflection.php | 57 +- .../AnnotationPropertyReflection.php | 34 +- .../AnnotationsMethodParameterReflection.php | 32 +- ...tationsMethodsClassReflectionExtension.php | 38 +- ...ionsPropertiesClassReflectionExtension.php | 30 +- src/Reflection/Assertions.php | 48 +- .../BetterReflectionProvider.php | 216 +- .../BetterReflectionProviderFactory.php | 4 +- .../BetterReflectionSourceLocatorFactory.php | 102 +- .../Reflector/MemoizingReflector.php | 13 +- .../AutoloadFunctionsSourceLocator.php | 16 +- .../SourceLocator/AutoloadSourceLocator.php | 60 +- .../SourceLocator/CachingVisitor.php | 47 +- ...JsonAndInstalledJsonSourceLocatorMaker.php | 109 +- .../SourceLocator/FetchedNode.php | 22 +- .../SourceLocator/FetchedNodesResult.php | 22 +- .../SourceLocator/FileNodesFetcher.php | 24 +- .../FileReadTrapStreamWrapper.php | 22 +- .../NewOptimizedDirectorySourceLocator.php | 53 +- .../OptimizedDirectorySourceLocator.php | 63 +- ...OptimizedDirectorySourceLocatorFactory.php | 51 +- ...imizedDirectorySourceLocatorRepository.php | 9 +- .../OptimizedPsrAutoloaderLocator.php | 17 +- .../OptimizedSingleFileSourceLocator.php | 68 +- ...mizedSingleFileSourceLocatorRepository.php | 9 +- .../SourceLocator/PhpFileCleaner.php | 22 +- .../PhpVersionBlacklistSourceLocator.php | 16 +- .../ReflectionClassSourceLocator.php | 22 +- .../RewriteClassAliasSourceLocator.php | 7 +- .../SkipClassAliasSourceLocator.php | 7 +- .../PhpStormStubsSourceStubberFactory.php | 17 +- src/Reflection/ClassConstantReflection.php | 63 +- src/Reflection/ClassReflection.php | 386 ++- .../ClassReflectionExtensionRegistry.php | 79 +- .../Constant/RuntimeConstantReflection.php | 22 +- src/Reflection/ConstructorsHelper.php | 19 +- .../Dummy/ChangedTypeMethodReflection.php | 22 +- .../Dummy/ChangedTypePropertyReflection.php | 22 +- .../Dummy/DummyConstantReflection.php | 7 +- .../Dummy/DummyConstructorReflection.php | 18 +- .../Dummy/DummyMethodReflection.php | 7 +- src/Reflection/EnumCaseReflection.php | 17 +- src/Reflection/ExtendedMethodReflection.php | 5 +- src/Reflection/FunctionReflectionFactory.php | 17 +- src/Reflection/FunctionVariant.php | 39 +- src/Reflection/FunctionVariantWithPhpDocs.php | 31 +- .../GenericParametersAcceptorResolver.php | 37 +- src/Reflection/InaccessibleMethod.php | 7 +- src/Reflection/InitializerExprContext.php | 107 +- .../InitializerExprTypeResolver.php | 239 +- src/Reflection/MethodPrototypeReflection.php | 64 +- ...MissingConstantFromReflectionException.php | 13 +- .../MissingMethodFromReflectionException.php | 13 +- ...MissingPropertyFromReflectionException.php | 13 +- .../Mixin/MixinMethodReflection.php | 12 +- .../MixinMethodsClassReflectionExtension.php | 9 +- ...ixinPropertiesClassReflectionExtension.php | 9 +- .../Native/NativeFunctionReflection.php | 59 +- .../Native/NativeMethodReflection.php | 81 +- .../Native/NativeParameterReflection.php | 49 +- .../NativeParameterWithPhpDocsReflection.php | 70 +- ...onEnumReturnDynamicReturnTypeExtension.php | 17 +- src/Reflection/ParametersAcceptorSelector.php | 190 +- src/Reflection/PassedByReference.php | 9 +- .../Php/BuiltinMethodReflection.php | 15 +- .../Php/ClosureCallMethodReflection.php | 50 +- ...allUnresolvedMethodPrototypeReflection.php | 12 +- src/Reflection/Php/DummyParameter.php | 32 +- .../Php/DummyParameterWithPhpDocs.php | 28 +- .../Php/EnumCasesMethodReflection.php | 22 +- src/Reflection/Php/EnumPropertyReflection.php | 12 +- ...mUnresolvedPropertyPrototypeReflection.php | 7 +- .../Php/NativeBuiltinMethodReflection.php | 22 +- .../Php/PhpClassReflectionExtension.php | 399 ++- .../PhpFunctionFromParserNodeReflection.php | 133 +- src/Reflection/Php/PhpFunctionReflection.php | 142 +- .../Php/PhpMethodFromParserNodeReflection.php | 132 +- src/Reflection/Php/PhpMethodReflection.php | 190 +- .../Php/PhpMethodReflectionFactory.php | 19 +- .../PhpParameterFromParserNodeReflection.php | 58 +- src/Reflection/Php/PhpParameterReflection.php | 71 +- src/Reflection/Php/PhpPropertyReflection.php | 94 +- .../Php/SimpleXMLElementProperty.php | 24 +- .../Php/Soap/SoapClientMethodReflection.php | 20 +- .../Php/UniversalObjectCrateProperty.php | 22 +- ...alObjectCratesClassReflectionExtension.php | 35 +- src/Reflection/PhpVersionStaticAccessor.php | 5 +- src/Reflection/ReflectionProvider.php | 5 +- .../DirectReflectionProviderProvider.php | 7 +- .../LazyReflectionProviderProvider.php | 7 +- .../MemoizingReflectionProvider.php | 13 +- .../ReflectionProviderFactory.php | 10 +- .../SetterReflectionProviderProvider.php | 5 +- .../ReflectionProviderStaticAccessor.php | 5 +- src/Reflection/ResolvedFunctionVariant.php | 110 +- src/Reflection/ResolvedMethodReflection.php | 58 +- src/Reflection/ResolvedPropertyReflection.php | 65 +- .../SignatureMap/FunctionSignature.php | 28 +- .../FunctionSignatureMapProvider.php | 59 +- .../NativeFunctionReflectionProvider.php | 66 +- .../SignatureMap/ParameterSignature.php | 52 +- .../SignatureMap/Php8SignatureMapProvider.php | 141 +- .../SignatureMap/SignatureMapParser.php | 32 +- .../SignatureMapProviderFactory.php | 22 +- ...ackUnresolvedMethodPrototypeReflection.php | 80 +- ...kUnresolvedPropertyPrototypeReflection.php | 52 +- ...ypeUnresolvedMethodPrototypeReflection.php | 89 +- ...eUnresolvedPropertyPrototypeReflection.php | 61 +- .../Type/IntersectionTypeMethodReflection.php | 73 +- .../IntersectionTypePropertyReflection.php | 47 +- ...ypeUnresolvedMethodPrototypeReflection.php | 37 +- ...eUnresolvedPropertyPrototypeReflection.php | 37 +- .../Type/UnionTypeMethodReflection.php | 44 +- .../Type/UnionTypePropertyReflection.php | 47 +- ...ypeUnresolvedMethodPrototypeReflection.php | 37 +- ...eUnresolvedPropertyPrototypeReflection.php | 37 +- .../WrappedExtendedMethodReflection.php | 30 +- src/Rules/Api/ApiClassConstFetchRule.php | 25 +- src/Rules/Api/ApiClassExtendsRule.php | 24 +- src/Rules/Api/ApiClassImplementsRule.php | 24 +- src/Rules/Api/ApiInstanceofRule.php | 35 +- src/Rules/Api/ApiInstanceofTypeRule.php | 32 +- src/Rules/Api/ApiInstantiationRule.php | 24 +- src/Rules/Api/ApiInterfaceExtendsRule.php | 24 +- src/Rules/Api/ApiMethodCallRule.php | 16 +- src/Rules/Api/ApiStaticCallRule.php | 25 +- src/Rules/Api/ApiTraitUseRule.php | 26 +- src/Rules/Api/GetTemplateTypeRule.php | 15 +- .../NodeConnectingVisitorAttributesRule.php | 7 +- .../PhpStanNamespaceIn3rdPartyPackageRule.php | 11 +- .../Api/RuntimeReflectionFunctionRule.php | 11 +- .../RuntimeReflectionInstantiationRule.php | 11 +- .../Arrays/AppendedArrayItemTypeRule.php | 22 +- src/Rules/Arrays/AppendedArrayKeyTypeRule.php | 22 +- src/Rules/Arrays/ArrayDestructuringRule.php | 44 +- src/Rules/Arrays/ArrayUnpackingRule.php | 27 +- .../DuplicateKeysInLiteralArraysRule.php | 18 +- .../Arrays/InvalidKeyInArrayDimFetchRule.php | 29 +- .../Arrays/InvalidKeyInArrayItemRule.php | 15 +- src/Rules/Arrays/IterableInForeachRule.php | 21 +- .../NonexistentOffsetInArrayDimFetchCheck.php | 162 +- .../NonexistentOffsetInArrayDimFetchRule.php | 49 +- src/Rules/Arrays/OffsetAccessAssignOpRule.php | 36 +- .../Arrays/OffsetAccessAssignmentRule.php | 36 +- .../OffsetAccessValueAssignmentRule.php | 22 +- .../Arrays/UnpackIterableInArrayRule.php | 24 +- src/Rules/AttributesCheck.php | 286 +- src/Rules/Cast/EchoRule.php | 22 +- src/Rules/Cast/InvalidCastRule.php | 31 +- .../Cast/InvalidPartOfEncapsedStringRule.php | 31 +- src/Rules/Cast/PrintRule.php | 21 +- src/Rules/Cast/UnsetCastRule.php | 7 +- src/Rules/ClassCaseSensitivityCheck.php | 19 +- src/Rules/ClassNameNodePair.php | 12 +- ...AccessPrivateConstantThroughStaticRule.php | 6 +- src/Rules/Classes/AllowedSubTypesRule.php | 6 +- src/Rules/Classes/ClassAttributesRule.php | 14 +- .../Classes/ClassConstantAttributesRule.php | 14 +- src/Rules/Classes/ClassConstantRule.php | 69 +- .../Classes/DuplicateClassDeclarationRule.php | 24 +- .../Classes/DuplicateDeclarationRule.php | 30 +- src/Rules/Classes/EnumSanityRule.php | 73 +- .../ExistingClassInClassExtendsRule.php | 52 +- .../Classes/ExistingClassInInstanceOfRule.php | 33 +- .../Classes/ExistingClassInTraitUseRule.php | 22 +- .../ExistingClassesInClassImplementsRule.php | 46 +- .../ExistingClassesInEnumImplementsRule.php | 46 +- .../ExistingClassesInInterfaceExtendsRule.php | 46 +- .../Classes/ImpossibleInstanceOfRule.php | 45 +- src/Rules/Classes/InstantiationRule.php | 92 +- .../Classes/InvalidPromotedPropertiesRule.php | 23 +- src/Rules/Classes/LocalTypeAliasesCheck.php | 22 +- src/Rules/Classes/LocalTypeAliasesRule.php | 7 +- .../Classes/LocalTypeTraitAliasesRule.php | 12 +- src/Rules/Classes/MixinRule.php | 63 +- .../Classes/NonClassAttributeClassRule.php | 5 +- src/Rules/Classes/ReadOnlyClassRule.php | 7 +- src/Rules/Classes/RequireExtendsRule.php | 18 +- src/Rules/Classes/RequireImplementsRule.php | 9 +- .../UnusedConstructorParametersRule.php | 24 +- .../BooleanAndConstantConditionRule.php | 64 +- .../BooleanNotConstantConditionRule.php | 33 +- .../BooleanOrConstantConditionRule.php | 64 +- .../ConstantConditionRuleHelper.php | 22 +- .../ConstantLooseComparisonRule.php | 36 +- .../DoWhileLoopConstantConditionRule.php | 21 +- .../ElseIfConstantConditionRule.php | 33 +- .../Comparison/IfConstantConditionRule.php | 27 +- .../ImpossibleCheckTypeFunctionCallRule.php | 40 +- .../Comparison/ImpossibleCheckTypeHelper.php | 550 ++-- .../ImpossibleCheckTypeMethodCallRule.php | 49 +- ...mpossibleCheckTypeStaticMethodCallRule.php | 50 +- .../LogicalXorConstantConditionRule.php | 37 +- src/Rules/Comparison/MatchExpressionRule.php | 61 +- ...mparisonOperatorsConstantConditionRule.php | 25 +- .../StrictComparisonOfDifferentTypesRule.php | 36 +- .../TernaryOperatorConstantConditionRule.php | 27 +- .../Comparison/UnreachableIfBranchesRule.php | 22 +- .../UnreachableTernaryElseBranchRule.php | 22 +- .../WhileLoopAlwaysFalseConditionRule.php | 22 +- .../WhileLoopAlwaysTrueConditionRule.php | 22 +- src/Rules/Constants/ConstantRule.php | 5 +- .../DynamicClassConstantFetchRule.php | 26 +- src/Rules/Constants/FinalConstantRule.php | 7 +- ...aysUsedClassConstantsExtensionProvider.php | 9 +- .../Constants/MagicConstantContextRule.php | 16 +- .../MissingClassConstantTypehintRule.php | 29 +- .../NativeTypedClassConstantRule.php | 7 +- .../Constants/OverridingConstantRule.php | 65 +- .../ValueAssignedToClassConstantRule.php | 39 +- src/Rules/DateTimeInstantiationRule.php | 9 +- src/Rules/DeadCode/NoopRule.php | 31 +- .../DeadCode/UnusedPrivateConstantRule.php | 7 +- .../DeadCode/UnusedPrivateMethodRule.php | 4 +- .../DeadCode/UnusedPrivatePropertyRule.php | 32 +- src/Rules/Debug/DumpTypeRule.php | 14 +- src/Rules/Debug/FileAssertRule.php | 7 +- src/Rules/DirectRegistry.php | 4 +- .../EnumCases/EnumCaseAttributesRule.php | 14 +- .../CatchWithUnthrownExceptionRule.php | 24 +- .../CaughtExceptionExistenceRule.php | 27 +- .../DefaultExceptionTypeResolver.php | 34 +- ...ngCheckedExceptionInFunctionThrowsRule.php | 13 +- ...singCheckedExceptionInMethodThrowsRule.php | 14 +- .../MissingCheckedExceptionInThrowsCheck.php | 14 +- .../Exceptions/NoncapturingCatchRule.php | 7 +- src/Rules/Exceptions/ThrowExprTypeRule.php | 24 +- src/Rules/Exceptions/ThrowExpressionRule.php | 7 +- ...VoidFunctionWithExplicitThrowPointRule.php | 29 +- ...wsVoidMethodWithExplicitThrowPointRule.php | 30 +- .../TooWideFunctionThrowTypeRule.php | 13 +- .../Exceptions/TooWideMethodThrowTypeRule.php | 27 +- src/Rules/FoundTypeResult.php | 28 +- src/Rules/FunctionCallParametersCheck.php | 1039 +++---- src/Rules/FunctionDefinitionCheck.php | 832 +++--- src/Rules/FunctionReturnTypeCheck.php | 151 +- src/Rules/Functions/ArrayFilterRule.php | 31 +- .../Functions/ArrowFunctionAttributesRule.php | 14 +- .../ArrowFunctionReturnNullsafeByRefRule.php | 7 +- .../Functions/ArrowFunctionReturnTypeRule.php | 19 +- src/Rules/Functions/CallCallablesRule.php | 79 +- .../CallToFunctionParametersRule.php | 28 +- ...unctionStatementWithoutSideEffectsRule.php | 20 +- .../CallToNonExistentFunctionRule.php | 22 +- src/Rules/Functions/CallUserFuncRule.php | 21 +- src/Rules/Functions/ClosureAttributesRule.php | 14 +- src/Rules/Functions/ClosureReturnTypeRule.php | 19 +- src/Rules/Functions/DefineParametersRule.php | 11 +- .../DuplicateFunctionDeclarationRule.php | 20 +- ...ingClassesInArrowFunctionTypehintsRule.php | 23 +- .../ExistingClassesInClosureTypehintsRule.php | 18 +- .../ExistingClassesInTypehintsRule.php | 30 +- .../Functions/FunctionAttributesRule.php | 14 +- src/Rules/Functions/FunctionCallableRule.php | 50 +- src/Rules/Functions/ImplodeFunctionRule.php | 29 +- ...eArrowFunctionDefaultParameterTypeRule.php | 8 +- ...patibleClosureDefaultParameterTypeRule.php | 8 +- .../IncompatibleDefaultParameterTypeRule.php | 9 +- src/Rules/Functions/InnerFunctionRule.php | 4 +- ...nvalidLexicalVariablesInClosureUseRule.php | 7 +- .../MissingFunctionParameterTypehintRule.php | 38 +- .../MissingFunctionReturnTypehintRule.php | 28 +- src/Rules/Functions/ParamAttributesRule.php | 14 +- src/Rules/Functions/PrintfParametersRule.php | 22 +- .../Functions/RandomIntParametersRule.php | 18 +- .../Functions/ReturnNullsafeByRefRule.php | 7 +- src/Rules/Functions/ReturnTypeRule.php | 34 +- src/Rules/Functions/UnusedClosureUsesRule.php | 17 +- src/Rules/Generators/YieldFromTypeRule.php | 50 +- src/Rules/Generators/YieldInGeneratorRule.php | 16 +- src/Rules/Generators/YieldTypeRule.php | 22 +- src/Rules/Generics/ClassAncestorsRule.php | 52 +- src/Rules/Generics/ClassTemplateTypeRule.php | 21 +- .../Generics/CrossCheckInterfacesHelper.php | 9 +- src/Rules/Generics/EnumAncestorsRule.php | 52 +- .../FunctionSignatureVarianceRule.php | 18 +- .../Generics/FunctionTemplateTypeRule.php | 35 +- src/Rules/Generics/GenericAncestorsCheck.php | 249 +- src/Rules/Generics/GenericObjectTypeCheck.php | 64 +- src/Rules/Generics/InterfaceAncestorsRule.php | 52 +- .../Generics/InterfaceTemplateTypeRule.php | 21 +- .../Generics/MethodSignatureVarianceRule.php | 18 +- src/Rules/Generics/MethodTemplateTypeRule.php | 35 +- src/Rules/Generics/PropertyVarianceRule.php | 22 +- src/Rules/Generics/TemplateTypeCheck.php | 204 +- src/Rules/Generics/TraitTemplateTypeRule.php | 35 +- src/Rules/Generics/UsedTraitsRule.php | 42 +- src/Rules/Generics/VarianceCheck.php | 148 +- src/Rules/IssetCheck.php | 87 +- .../Keywords/ContinueBreakInLoopRule.php | 10 +- src/Rules/Keywords/DeclareStrictTypesRule.php | 22 +- src/Rules/LazyRegistry.php | 11 +- .../AbstractMethodInNonAbstractClassRule.php | 13 +- .../Methods/AbstractPrivateMethodRule.php | 6 +- src/Rules/Methods/CallMethodsRule.php | 32 +- .../CallPrivateMethodThroughStaticRule.php | 6 +- src/Rules/Methods/CallStaticMethodsRule.php | 44 +- ...tructorStatementWithoutSideEffectsRule.php | 13 +- ...oMethodStatementWithoutSideEffectsRule.php | 23 +- ...cMethodStatementWithoutSideEffectsRule.php | 32 +- .../Methods/ConsistentConstructorRule.php | 10 +- .../ExistingClassesInTypehintsRule.php | 34 +- src/Rules/Methods/FinalPrivateMethodRule.php | 16 +- .../IllegalConstructorStaticCallRule.php | 4 +- .../IncompatibleDefaultParameterTypeRule.php | 10 +- src/Rules/Methods/MethodAttributesRule.php | 14 +- src/Rules/Methods/MethodCallCheck.php | 219 +- src/Rules/Methods/MethodCallableRule.php | 12 +- .../MethodParameterComparisonHelper.php | 170 +- src/Rules/Methods/MethodSignatureRule.php | 106 +- .../MethodVisibilityInInterfaceRule.php | 6 +- .../MissingMagicSerializationMethodsRule.php | 19 +- .../MissingMethodImplementationRule.php | 11 +- .../MissingMethodParameterTypehintRule.php | 39 +- .../MissingMethodReturnTypehintRule.php | 35 +- src/Rules/Methods/OverridingMethodRule.php | 176 +- src/Rules/Methods/ReturnTypeRule.php | 35 +- src/Rules/Methods/StaticMethodCallCheck.php | 468 ++-- .../Methods/StaticMethodCallableRule.php | 12 +- src/Rules/Missing/MissingReturnRule.php | 24 +- src/Rules/MissingTypehintCheck.php | 39 +- src/Rules/Names/UsedNamesRule.php | 17 +- .../ExistingNamesInGroupUseRule.php | 28 +- .../Namespaces/ExistingNamesInUseRule.php | 34 +- src/Rules/Operators/InvalidAssignVarRule.php | 7 +- .../Operators/InvalidBinaryOperationRule.php | 45 +- .../InvalidComparisonOperationRule.php | 36 +- .../Operators/InvalidIncDecOperationRule.php | 18 +- .../Operators/InvalidUnaryOperationRule.php | 6 +- src/Rules/PhpDoc/AssertRuleHelper.php | 26 +- .../ConditionalReturnTypeRuleHelper.php | 8 +- src/Rules/PhpDoc/FunctionAssertRule.php | 7 +- .../FunctionConditionalReturnTypeRule.php | 7 +- ...ncompatibleClassConstantPhpDocTypeRule.php | 72 +- .../PhpDoc/IncompatiblePhpDocTypeRule.php | 126 +- .../IncompatiblePropertyPhpDocTypeRule.php | 81 +- .../PhpDoc/IncompatibleSelfOutTypeRule.php | 8 +- src/Rules/PhpDoc/InvalidPHPStanDocTagRule.php | 26 +- .../PhpDoc/InvalidPhpDocTagValueRule.php | 42 +- .../PhpDoc/InvalidPhpDocVarTagTypeRule.php | 100 +- .../PhpDoc/InvalidThrowsPhpDocValueRule.php | 24 +- src/Rules/PhpDoc/MethodAssertRule.php | 7 +- .../MethodConditionalReturnTypeRule.php | 7 +- src/Rules/PhpDoc/RequireExtendsCheck.php | 23 +- .../RequireExtendsDefinitionClassRule.php | 10 +- .../RequireExtendsDefinitionTraitRule.php | 16 +- .../RequireImplementsDefinitionTraitRule.php | 29 +- .../VarTagChangedExpressionTypeRule.php | 7 +- src/Rules/PhpDoc/VarTagTypeRuleHelper.php | 25 +- .../PhpDoc/WrongVariableNameInVarTagRule.php | 81 +- src/Rules/Playground/FunctionNeverRule.php | 13 +- src/Rules/Playground/MethodNeverRule.php | 14 +- src/Rules/Playground/NeverRuleHelper.php | 2 +- src/Rules/Playground/NotAnalysedTraitRule.php | 5 +- ...AccessPrivatePropertyThroughStaticRule.php | 6 +- .../AccessPropertiesInAssignRule.php | 7 +- src/Rules/Properties/AccessPropertiesRule.php | 66 +- .../AccessStaticPropertiesInAssignRule.php | 7 +- .../Properties/AccessStaticPropertiesRule.php | 92 +- ...aultValueTypesAssignedToPropertiesRule.php | 16 +- ...ctReadWritePropertiesExtensionProvider.php | 7 +- .../ExistingClassesInPropertiesRule.php | 72 +- .../Properties/FoundPropertyReflection.php | 36 +- .../InvalidCallablePropertyTypeRule.php | 6 +- ...zyReadWritePropertiesExtensionProvider.php | 9 +- .../MissingPropertyTypehintRule.php | 35 +- ...singReadOnlyByPhpDocPropertyAssignRule.php | 28 +- .../MissingReadOnlyPropertyAssignRule.php | 28 +- .../Properties/OverridingPropertyRule.php | 122 +- .../Properties/PropertyAttributesRule.php | 14 +- .../Properties/PropertyReflectionFinder.php | 34 +- .../ReadOnlyByPhpDocPropertyAssignRefRule.php | 7 +- .../ReadOnlyByPhpDocPropertyAssignRule.php | 16 +- .../ReadOnlyPropertyAssignRefRule.php | 7 +- .../Properties/ReadOnlyPropertyAssignRule.php | 16 +- src/Rules/Properties/ReadOnlyPropertyRule.php | 7 +- .../ReadingWriteOnlyPropertiesRule.php | 33 +- .../TypesAssignedToPropertiesRule.php | 36 +- .../Properties/UninitializedPropertyRule.php | 22 +- .../WritingToReadOnlyPropertiesRule.php | 33 +- src/Rules/RuleErrorBuilder.php | 13 +- src/Rules/RuleErrors/RuleError1.php | 5 +- src/Rules/RuleErrors/RuleError101.php | 17 +- src/Rules/RuleErrors/RuleError103.php | 22 +- src/Rules/RuleErrors/RuleError105.php | 12 +- src/Rules/RuleErrors/RuleError107.php | 17 +- src/Rules/RuleErrors/RuleError109.php | 22 +- src/Rules/RuleErrors/RuleError11.php | 19 +- src/Rules/RuleErrors/RuleError111.php | 27 +- src/Rules/RuleErrors/RuleError113.php | 12 +- src/Rules/RuleErrors/RuleError115.php | 17 +- src/Rules/RuleErrors/RuleError117.php | 22 +- src/Rules/RuleErrors/RuleError119.php | 27 +- src/Rules/RuleErrors/RuleError121.php | 17 +- src/Rules/RuleErrors/RuleError123.php | 22 +- src/Rules/RuleErrors/RuleError125.php | 27 +- src/Rules/RuleErrors/RuleError127.php | 32 +- src/Rules/RuleErrors/RuleError13.php | 26 +- src/Rules/RuleErrors/RuleError15.php | 25 +- src/Rules/RuleErrors/RuleError17.php | 12 +- src/Rules/RuleErrors/RuleError19.php | 19 +- src/Rules/RuleErrors/RuleError21.php | 26 +- src/Rules/RuleErrors/RuleError23.php | 25 +- src/Rules/RuleErrors/RuleError25.php | 19 +- src/Rules/RuleErrors/RuleError27.php | 26 +- src/Rules/RuleErrors/RuleError29.php | 25 +- src/Rules/RuleErrors/RuleError3.php | 12 +- src/Rules/RuleErrors/RuleError31.php | 40 +- src/Rules/RuleErrors/RuleError33.php | 7 +- src/Rules/RuleErrors/RuleError35.php | 12 +- src/Rules/RuleErrors/RuleError37.php | 17 +- src/Rules/RuleErrors/RuleError39.php | 22 +- src/Rules/RuleErrors/RuleError41.php | 12 +- src/Rules/RuleErrors/RuleError43.php | 17 +- src/Rules/RuleErrors/RuleError45.php | 22 +- src/Rules/RuleErrors/RuleError47.php | 27 +- src/Rules/RuleErrors/RuleError49.php | 12 +- src/Rules/RuleErrors/RuleError5.php | 19 +- src/Rules/RuleErrors/RuleError51.php | 17 +- src/Rules/RuleErrors/RuleError53.php | 22 +- src/Rules/RuleErrors/RuleError55.php | 27 +- src/Rules/RuleErrors/RuleError57.php | 17 +- src/Rules/RuleErrors/RuleError59.php | 22 +- src/Rules/RuleErrors/RuleError61.php | 27 +- src/Rules/RuleErrors/RuleError63.php | 32 +- src/Rules/RuleErrors/RuleError65.php | 5 +- src/Rules/RuleErrors/RuleError67.php | 12 +- src/Rules/RuleErrors/RuleError69.php | 19 +- src/Rules/RuleErrors/RuleError7.php | 26 +- src/Rules/RuleErrors/RuleError71.php | 26 +- src/Rules/RuleErrors/RuleError73.php | 12 +- src/Rules/RuleErrors/RuleError75.php | 19 +- src/Rules/RuleErrors/RuleError77.php | 26 +- src/Rules/RuleErrors/RuleError79.php | 25 +- src/Rules/RuleErrors/RuleError81.php | 12 +- src/Rules/RuleErrors/RuleError83.php | 19 +- src/Rules/RuleErrors/RuleError85.php | 26 +- src/Rules/RuleErrors/RuleError87.php | 25 +- src/Rules/RuleErrors/RuleError89.php | 19 +- src/Rules/RuleErrors/RuleError9.php | 12 +- src/Rules/RuleErrors/RuleError91.php | 26 +- src/Rules/RuleErrors/RuleError93.php | 25 +- src/Rules/RuleErrors/RuleError95.php | 40 +- src/Rules/RuleErrors/RuleError97.php | 7 +- src/Rules/RuleErrors/RuleError99.php | 12 +- src/Rules/RuleLevelHelper.php | 123 +- src/Rules/RuleLevelHelperAcceptsResult.php | 23 +- ...TooWideArrowFunctionReturnTypehintRule.php | 5 +- .../TooWideClosureReturnTypehintRule.php | 5 +- .../TooWideFunctionReturnTypehintRule.php | 6 +- .../TooWideMethodReturnTypehintRule.php | 19 +- .../Traits/ConflictingTraitConstantsRule.php | 119 +- src/Rules/Traits/ConstantsInTraitsRule.php | 11 +- src/Rules/Traits/NotAnalysedTraitRule.php | 5 +- src/Rules/Traits/TraitUseCollector.php | 4 +- src/Rules/UnusedFunctionParametersCheck.php | 68 +- src/Rules/Variables/CompactVariablesRule.php | 15 +- src/Rules/Variables/DefinedVariableRule.php | 16 +- src/Rules/Variables/EmptyRule.php | 7 +- src/Rules/Variables/IssetRule.php | 7 +- src/Rules/Variables/NullCoalesceRule.php | 7 +- src/Rules/Variables/ThrowTypeRule.php | 24 +- src/Rules/Variables/UnsetRule.php | 12 +- src/Rules/Variables/VariableCloningRule.php | 27 +- src/Rules/Whitespace/FileWhitespaceRule.php | 2 +- src/Testing/ErrorFormatterTestCase.php | 21 +- src/Testing/LevelsTestCase.php | 17 +- src/Testing/PHPStanTestCase.php | 40 +- src/Testing/RuleTestCase.php | 69 +- src/Testing/TestCaseSourceLocatorFactory.php | 65 +- src/Testing/TypeInferenceTestCase.php | 80 +- src/TrinaryLogic.php | 46 +- src/Type/AcceptsResult.php | 36 +- src/Type/Accessory/AccessoryArrayListType.php | 15 +- .../Accessory/AccessoryLiteralStringType.php | 8 +- .../Accessory/AccessoryNonEmptyStringType.php | 8 +- .../Accessory/AccessoryNonFalsyStringType.php | 8 +- .../Accessory/AccessoryNumericStringType.php | 8 +- src/Type/Accessory/HasMethodType.php | 16 +- src/Type/Accessory/HasOffsetType.php | 7 +- src/Type/Accessory/HasOffsetValueType.php | 27 +- src/Type/Accessory/HasPropertyType.php | 7 +- src/Type/ArrayType.php | 110 +- src/Type/BitwiseFlagHelper.php | 7 +- src/Type/BooleanType.php | 23 +- src/Type/CallableType.php | 101 +- src/Type/CallableTypeHelper.php | 28 +- src/Type/ClosureType.php | 148 +- src/Type/ClosureTypeFactory.php | 132 +- src/Type/ConditionalType.php | 90 +- src/Type/ConditionalTypeForParameter.php | 86 +- src/Type/Constant/ConstantArrayType.php | 324 ++- .../Constant/ConstantArrayTypeAndMethod.php | 45 +- .../Constant/ConstantArrayTypeBuilder.php | 72 +- src/Type/Constant/ConstantBooleanType.php | 7 +- src/Type/Constant/ConstantFloatType.php | 16 +- src/Type/Constant/ConstantIntegerType.php | 16 +- src/Type/Constant/ConstantStringType.php | 42 +- src/Type/Constant/OversizedArrayBuilder.php | 10 +- src/Type/DirectTypeAliasResolverProvider.php | 7 +- .../DynamicReturnTypeExtensionRegistry.php | 84 +- src/Type/Enum/EnumCaseObjectType.php | 33 +- src/Type/ErrorType.php | 12 +- ...xpressionTypeResolverExtensionRegistry.php | 10 +- src/Type/FileTypeMapper.php | 388 +-- src/Type/FloatType.php | 8 +- src/Type/GeneralizePrecision.php | 11 +- src/Type/Generic/GenericClassStringType.php | 14 +- src/Type/Generic/GenericObjectType.php | 62 +- src/Type/Generic/TemplateArrayType.php | 8 +- .../Generic/TemplateBenevolentUnionType.php | 17 +- src/Type/Generic/TemplateBooleanType.php | 8 +- .../Generic/TemplateConstantArrayType.php | 8 +- .../Generic/TemplateConstantIntegerType.php | 8 +- .../Generic/TemplateConstantStringType.php | 8 +- src/Type/Generic/TemplateFloatType.php | 8 +- .../Generic/TemplateGenericObjectType.php | 17 +- src/Type/Generic/TemplateIntegerType.php | 8 +- src/Type/Generic/TemplateIntersectionType.php | 9 +- src/Type/Generic/TemplateKeyOfType.php | 16 +- src/Type/Generic/TemplateMixedType.php | 17 +- src/Type/Generic/TemplateObjectShapeType.php | 8 +- src/Type/Generic/TemplateObjectType.php | 9 +- .../TemplateObjectWithoutClassType.php | 9 +- src/Type/Generic/TemplateStrictMixedType.php | 8 +- src/Type/Generic/TemplateStringType.php | 8 +- .../Generic/TemplateTypeArgumentStrategy.php | 6 +- src/Type/Generic/TemplateTypeFactory.php | 2 +- src/Type/Generic/TemplateTypeHelper.php | 9 +- src/Type/Generic/TemplateTypeMap.php | 31 +- src/Type/Generic/TemplateTypeReference.php | 12 +- src/Type/Generic/TemplateTypeScope.php | 17 +- src/Type/Generic/TemplateTypeTrait.php | 107 +- src/Type/Generic/TemplateTypeVariance.php | 22 +- src/Type/Generic/TemplateTypeVarianceMap.php | 12 +- src/Type/Generic/TemplateUnionType.php | 9 +- src/Type/Generic/TypeProjectionHelper.php | 9 +- src/Type/GenericTypeVariableResolver.php | 9 +- src/Type/Helper/GetTemplateTypeType.php | 30 +- src/Type/IntegerRangeType.php | 28 +- src/Type/IntegerType.php | 8 +- src/Type/IntersectionType.php | 401 +-- src/Type/IterableType.php | 45 +- src/Type/KeyOfType.php | 11 +- src/Type/LazyTypeAliasResolverProvider.php | 7 +- src/Type/MixedType.php | 118 +- src/Type/NeverType.php | 7 +- src/Type/NullType.php | 6 +- src/Type/ObjectShapePropertyReflection.php | 7 +- src/Type/ObjectShapeType.php | 105 +- src/Type/ObjectType.php | 220 +- src/Type/ObjectWithoutClassType.php | 26 +- src/Type/OffsetAccessType.php | 35 +- ...peratorTypeSpecifyingExtensionRegistry.php | 50 +- ...gumentBasedFunctionReturnTypeExtension.php | 5 +- .../ArrayChunkFunctionReturnTypeExtension.php | 7 +- ...ArrayColumnFunctionReturnTypeExtension.php | 7 +- ...rrayCombineFunctionReturnTypeExtension.php | 18 +- .../ArrayFillFunctionReturnTypeExtension.php | 12 +- ...rayFillKeysFunctionReturnTypeExtension.php | 7 +- ...rFunctionReturnTypeReturnTypeExtension.php | 14 +- .../ArrayFlipFunctionReturnTypeExtension.php | 7 +- ...ntersectKeyFunctionReturnTypeExtension.php | 7 +- ...yExistsFunctionTypeSpecifyingExtension.php | 56 +- ...KeysFunctionDynamicReturnTypeExtension.php | 7 +- .../ArrayMapFunctionReturnTypeExtension.php | 26 +- ...ergeFunctionDynamicReturnTypeExtension.php | 11 +- ...terFunctionsDynamicReturnTypeExtension.php | 11 +- ...ArrayReduceFunctionReturnTypeExtension.php | 6 +- ...archFunctionDynamicReturnTypeExtension.php | 7 +- ...ySearchFunctionTypeSpecifyingExtension.php | 27 +- ...ArraySpliceFunctionReturnTypeExtension.php | 8 +- ...luesFunctionDynamicReturnTypeExtension.php | 7 +- .../AssertFunctionTypeSpecifyingExtension.php | 5 +- ...codeDynamicFunctionReturnTypeExtension.php | 11 +- .../BcMathStringOrNullReturnTypeExtension.php | 7 +- ...sExistsFunctionTypeSpecifyingExtension.php | 29 +- ...sImplementsFunctionReturnTypeExtension.php | 6 +- ...FromCallableDynamicReturnTypeExtension.php | 9 +- .../CompactFunctionReturnTypeExtension.php | 16 +- .../ConstantFunctionReturnTypeExtension.php | 17 +- .../Php/CountFunctionReturnTypeExtension.php | 8 +- .../CountFunctionTypeSpecifyingExtension.php | 19 +- ...peDigitFunctionTypeSpecifyingExtension.php | 9 +- ...infoFunctionDynamicReturnTypeExtension.php | 10 +- src/Type/Php/CurlInitReturnTypeExtension.php | 7 +- .../DateFormatFunctionReturnTypeExtension.php | 13 +- .../DateFormatMethodReturnTypeExtension.php | 6 +- .../Php/DateFunctionReturnTypeExtension.php | 14 +- ...DateIntervalDynamicReturnTypeExtension.php | 2 +- .../Php/DateTimeModifyReturnTypeExtension.php | 2 +- .../DefineConstantTypeSpecifyingExtension.php | 29 +- ...DefinedConstantTypeSpecifyingExtension.php | 36 +- ...lodeFunctionDynamicReturnTypeExtension.php | 16 +- .../Php/FilterFunctionReturnTypeHelper.php | 34 +- .../FilterInputDynamicReturnTypeExtension.php | 14 +- ...lterVarArrayDynamicReturnTypeExtension.php | 43 +- .../FilterVarDynamicReturnTypeExtension.php | 7 +- ...nExistsFunctionTypeSpecifyingExtension.php | 29 +- .../GetClassDynamicReturnTypeExtension.php | 7 +- ...lassDynamicFunctionReturnTypeExtension.php | 98 +- .../GettypeFunctionReturnTypeExtension.php | 13 +- .../Php/HashFunctionsReturnTypeExtension.php | 16 +- .../ImplodeFunctionReturnTypeExtension.php | 9 +- ...InArrayFunctionTypeSpecifyingExtension.php | 37 +- src/Type/Php/IniGetReturnTypeExtension.php | 15 +- .../IsAFunctionTypeSpecifyingExtension.php | 22 +- .../Php/IsAFunctionTypeSpecifyingHelper.php | 30 +- ...IsArrayFunctionTypeSpecifyingExtension.php | 14 +- ...allableFunctionTypeSpecifyingExtension.php | 12 +- ...terableFunctionTypeSpecifyingExtension.php | 5 +- ...classOfFunctionTypeSpecifyingExtension.php | 22 +- ...atorToArrayFunctionReturnTypeExtension.php | 5 +- ...ThrowOnErrorDynamicReturnTypeExtension.php | 80 +- src/Type/Php/JsonThrowTypeExtension.php | 63 +- ...ertEncodingFunctionReturnTypeExtension.php | 8 +- .../Php/MbFunctionsReturnTypeExtension.php | 13 +- .../MbFunctionsReturnTypeExtensionTrait.php | 9 +- .../MbStrlenFunctionReturnTypeExtension.php | 37 +- ...uteCharacterDynamicReturnTypeExtension.php | 14 +- .../MethodExistsTypeSpecifyingExtension.php | 40 +- .../Php/MinMaxFunctionReturnTypeExtension.php | 48 +- ...mptyStringFunctionsReturnTypeExtension.php | 8 +- ...eUrlFunctionDynamicReturnTypeExtension.php | 11 +- ...infoFunctionDynamicReturnTypeExtension.php | 18 +- .../PregSplitDynamicReturnTypeExtension.php | 15 +- .../PropertyExistsTypeSpecifyingExtension.php | 43 +- .../RandomIntFunctionReturnTypeExtension.php | 19 +- .../Php/RangeFunctionReturnTypeExtension.php | 24 +- ...assIsSubclassOfTypeSpecifyingExtension.php | 15 +- ...nFunctionConstructorThrowTypeExtension.php | 7 +- ...GetAttributesMethodReturnTypeExtension.php | 7 +- ...ionMethodConstructorThrowTypeExtension.php | 7 +- ...nPropertyConstructorThrowTypeExtension.php | 7 +- ...aceFunctionsDynamicReturnTypeExtension.php | 32 +- .../Php/RoundFunctionReturnTypeExtension.php | 20 +- ...intfFunctionDynamicReturnTypeExtension.php | 14 +- ...canfFunctionDynamicReturnTypeExtension.php | 10 +- .../StrCaseFunctionsReturnTypeExtension.php | 34 +- .../StrContainingTypeSpecifyingExtension.php | 22 +- ...ntDecrementFunctionReturnTypeExtension.php | 10 +- .../Php/StrPadFunctionReturnTypeExtension.php | 11 +- .../StrRepeatFunctionReturnTypeExtension.php | 14 +- .../StrSplitFunctionReturnTypeExtension.php | 11 +- ...ountFunctionDynamicReturnTypeExtension.php | 7 +- .../Php/StrlenFunctionReturnTypeExtension.php | 14 +- .../StrtotimeFunctionReturnTypeExtension.php | 8 +- ...trvalFamilyFunctionReturnTypeExtension.php | 8 +- .../Php/SubstrDynamicReturnTypeExtension.php | 19 +- ...TriggerErrorDynamicReturnTypeExtension.php | 7 +- ...ingFunctionsDynamicReturnTypeExtension.php | 45 +- ...pareFunctionDynamicReturnTypeExtension.php | 25 +- src/Type/RecursionGuard.php | 2 +- src/Type/ResourceType.php | 8 +- src/Type/StaticType.php | 99 +- src/Type/StrictMixedType.php | 15 +- src/Type/StringType.php | 12 +- src/Type/ThisType.php | 10 +- src/Type/Traits/LateResolvableTypeTrait.php | 5 +- src/Type/Traits/MaybeObjectTypeTrait.php | 18 +- src/Type/Traits/NonGeneralizableTypeTrait.php | 4 +- src/Type/Traits/ObjectTypeTrait.php | 18 +- src/Type/TypeAlias.php | 27 +- src/Type/TypeCombinator.php | 79 +- src/Type/TypeUtils.php | 18 +- src/Type/TypehintHelper.php | 42 +- src/Type/UnionType.php | 582 ++-- src/Type/UsefulTypeAliasResolver.php | 37 +- src/Type/ValueOfType.php | 11 +- src/Type/VerbosityLevel.php | 23 +- .../Analyser/AnalyserIntegrationTest.php | 12 +- tests/PHPStan/Analyser/AnalyserTest.php | 81 +- .../AnalyserTraitsIntegrationTest.php | 53 +- .../Analyser/AnonymousClassNameRule.php | 9 +- .../ArgumentsNormalizerLegacyTest.php | 48 +- .../Analyser/ArgumentsNormalizerTest.php | 61 +- tests/PHPStan/Analyser/AssertStubTest.php | 6 +- .../Analyser/ClassConstantStubFileTest.php | 6 +- ...onditionalReturnTypeFromMethodStubTest.php | 6 +- ...memberPossiblyImpureFunctionValuesTest.php | 6 +- .../DynamicMethodThrowTypeExtensionTest.php | 6 +- ...icReturnTypeExtensionTypeInferenceTest.php | 6 +- .../ExpressionTypeResolverExtensionTest.php | 6 +- .../Analyser/LegacyNodeScopeResolverTest.php | 1455 ++++++++-- .../Analyser/LooseConstComparisonPhp7Test.php | 6 +- .../Analyser/LooseConstComparisonPhp8Test.php | 6 +- .../Analyser/NodeScopeResolverTest.php | 6 +- tests/PHPStan/Analyser/ParamOutTypeTest.php | 6 +- tests/PHPStan/Analyser/PathConstantsTest.php | 6 +- .../PHPStan/Analyser/StatementResultTest.php | 16 +- .../ThrowsTagFromNativeFunctionStubTest.php | 6 +- tests/PHPStan/Analyser/TraitStubFilesTest.php | 6 +- tests/PHPStan/Analyser/TypeSpecifierTest.php | 510 +++- ...cifyingExtensionTypeInferenceFalseTest.php | 6 +- ...ecifyingExtensionTypeInferenceNullTest.php | 6 +- ...ecifyingExtensionTypeInferenceTrueTest.php | 6 +- tests/PHPStan/Collectors/RegistryTest.php | 8 +- .../AnalyseApplicationIntegrationTest.php | 34 +- tests/PHPStan/Command/AnalysisResultTest.php | 20 +- tests/PHPStan/Command/CommandHelperTest.php | 46 +- ...elineNeonErrorFormatterIntegrationTest.php | 9 +- .../BaselineNeonErrorFormatterTest.php | 129 +- .../BaselinePhpErrorFormatterTest.php | 88 +- .../CheckstyleErrorFormatterTest.php | 59 +- .../GithubErrorFormatterTest.php | 19 +- .../ErrorFormatter/GitlabFormatterTest.php | 15 +- .../ErrorFormatter/JsonErrorFormatterTest.php | 30 +- .../JunitErrorFormatterTest.php | 35 +- .../ErrorFormatter/RawErrorFormatterTest.php | 15 +- .../TableErrorFormatterTest.php | 53 +- .../TeamcityErrorFormatterTest.php | 19 +- .../Command/IgnoredRegexValidatorTest.php | 8 +- tests/PHPStan/Composer/AutoloadFilesTest.php | 4 +- .../ConditionalTagsExtensionTest.php | 4 +- tests/PHPStan/File/FileExcluderTest.php | 16 +- .../ParentDirectoryRelativePathHelperTest.php | 11 +- tests/PHPStan/File/RelativePathHelperTest.php | 36 +- .../Generics/TemplateTypeFactoryTest.php | 19 +- tests/PHPStan/Node/FileNodeTest.php | 4 +- tests/PHPStan/Node/ParentStmtTypesRule.php | 5 +- tests/PHPStan/Node/TryCatchTypeRule.php | 9 +- .../ParallelAnalyserIntegrationTest.php | 13 +- tests/PHPStan/Parallel/SchedulerTest.php | 15 +- tests/PHPStan/Parser/CachedParserTest.php | 17 +- tests/PHPStan/Parser/CleaningParserTest.php | 14 +- tests/PHPStan/Php/PhpVersionFactoryTest.php | 9 +- .../PhpDoc/DefaultStubFilesProviderTest.php | 5 +- ...edSubTypesClassReflectionExtensionTest.php | 6 +- ...onsMethodsClassReflectionExtensionTest.php | 75 +- ...PropertiesClassReflectionExtensionTest.php | 35 +- .../AutoloadSourceLocatorTest.php | 10 +- .../OptimizedDirectorySourceLocatorTest.php | 27 +- .../OptimizedSingleFileSourceLocatorTest.php | 22 +- .../Reflection/ClassReflectionTest.php | 24 +- .../GenericParametersAcceptorResolverTest.php | 412 ++- .../InitializerExprTypeResolverTest.php | 10 +- .../ParametersAcceptorSelectorTest.php | 313 ++- ...jectCratesClassReflectionExtensionTest.php | 46 +- .../ReflectionProviderGoldenTest.php | 13 +- .../Reflection/ReflectionProviderTest.php | 10 +- .../SignatureMap/FunctionMetadataTest.php | 6 +- .../Php8SignatureMapProviderTest.php | 43 +- .../SignatureMap/SignatureMapParserTest.php | 423 ++- .../IntersectionTypeMethodReflectionTest.php | 14 +- .../Type/UnionTypeMethodReflectionTest.php | 14 +- .../Rules/Api/ApiClassConstFetchRuleTest.php | 5 +- .../Rules/Api/ApiClassExtendsRuleTest.php | 5 +- .../Rules/Api/ApiClassImplementsRuleTest.php | 5 +- .../Rules/Api/ApiInstanceofRuleTest.php | 10 +- .../Rules/Api/ApiInstantiationRuleTest.php | 10 +- .../Rules/Api/ApiInterfaceExtendsRuleTest.php | 5 +- .../Rules/Api/ApiMethodCallRuleTest.php | 5 +- tests/PHPStan/Rules/Api/ApiRuleHelperTest.php | 8 +- .../Rules/Api/ApiStaticCallRuleTest.php | 5 +- .../PHPStan/Rules/Api/ApiTraitUseRuleTest.php | 5 +- .../Arrays/AppendedArrayItemTypeRuleTest.php | 12 +- .../Arrays/AppendedArrayKeyTypeRuleTest.php | 5 +- .../Arrays/ArrayDestructuringRuleTest.php | 10 +- .../Rules/Arrays/ArrayUnpackingRuleTest.php | 15 +- .../DuplicateKeysInLiteralArraysRuleTest.php | 4 +- .../Arrays/IterableInForeachRuleTest.php | 14 +- ...nexistentOffsetInArrayDimFetchRuleTest.php | 21 +- .../Arrays/OffsetAccessAssignOpRuleTest.php | 5 +- .../Arrays/OffsetAccessAssignmentRuleTest.php | 19 +- ...fsetAccessWithoutDimForReadingRuleTest.php | 7 +- .../Arrays/UnpackIterableInArrayRuleTest.php | 14 +- tests/PHPStan/Rules/Cast/EchoRuleTest.php | 4 +- .../Rules/Cast/InvalidCastRuleTest.php | 14 +- .../InvalidPartOfEncapsedStringRuleTest.php | 5 +- tests/PHPStan/Rules/Cast/PrintRuleTest.php | 4 +- .../PHPStan/Rules/Cast/UnsetCastRuleTest.php | 5 +- .../Rules/Classes/ClassAttributesRuleTest.php | 20 +- .../ClassConstantAttributesRuleTest.php | 20 +- .../Rules/Classes/ClassConstantRuleTest.php | 14 +- .../DuplicateClassDeclarationRuleTest.php | 8 +- .../Classes/DuplicateDeclarationRuleTest.php | 9 +- .../ExistingClassInClassExtendsRuleTest.php | 5 +- .../ExistingClassInInstanceOfRuleTest.php | 15 +- .../ExistingClassInTraitUseRuleTest.php | 5 +- ...istingClassesInClassImplementsRuleTest.php | 5 +- ...xistingClassesInEnumImplementsRuleTest.php | 5 +- ...stingClassesInInterfaceExtendsRuleTest.php | 5 +- .../Classes/ImpossibleInstanceOfRuleTest.php | 29 +- .../Rules/Classes/InstantiationRuleTest.php | 20 +- .../InvalidPromotedPropertiesRuleTest.php | 5 +- .../Classes/LocalTypeAliasesRuleTest.php | 8 +- .../Classes/LocalTypeTraitAliasesRuleTest.php | 9 +- tests/PHPStan/Rules/Classes/MixinRuleTest.php | 9 +- .../UnusedConstructorParametersRuleTest.php | 4 +- .../BooleanAndConstantConditionRuleTest.php | 32 +- .../BooleanNotConstantConditionRuleTest.php | 26 +- .../BooleanOrConstantConditionRuleTest.php | 32 +- .../ConstantLooseComparisonRuleTest.php | 15 +- .../DoWhileLoopConstantConditionRuleTest.php | 20 +- .../ElseIfConstantConditionRuleTest.php | 26 +- .../IfConstantConditionRuleTest.php | 20 +- ...mpossibleCheckTypeFunctionCallRuleTest.php | 53 +- ...sibleCheckTypeGenericOverwriteRuleTest.php | 13 +- ...sibleCheckTypeMethodCallRuleEqualsTest.php | 13 +- .../ImpossibleCheckTypeMethodCallRuleTest.php | 23 +- ...sibleCheckTypeStaticMethodCallRuleTest.php | 23 +- .../LogicalXorConstantConditionRuleTest.php | 26 +- ...otRememberPossiblyImpureValuesRuleTest.php | 7 +- .../Comparison/MatchExpressionRuleTest.php | 33 +- ...isonOperatorsConstantConditionRuleTest.php | 5 +- ...rictComparisonOfDifferentTypesRuleTest.php | 29 +- ...rnaryOperatorConstantConditionRuleTest.php | 20 +- .../UnreachableIfBranchesRuleTest.php | 21 +- .../UnreachableTernaryElseBranchRuleTest.php | 21 +- .../WhileLoopAlwaysFalseConditionRuleTest.php | 20 +- .../WhileLoopAlwaysTrueConditionRuleTest.php | 20 +- ...aysUsedClassConstantsExtensionProvider.php | 7 +- .../DynamicClassConstantFetchRuleTest.php | 5 +- .../Rules/Constants/FinalConstantRuleTest.php | 5 +- .../Rules/DateTimeInstantiationRuleTest.php | 7 +- .../DeadCode/UnreachableStatementRuleTest.php | 5 +- .../UnusedPrivateConstantRuleTest.php | 6 +- .../UnusedPrivatePropertyRuleTest.php | 13 +- tests/PHPStan/Rules/DirectRegistryTest.php | 16 +- .../EnumCases/EnumCaseAttributesRuleTest.php | 20 +- .../AbilityToDisableImplicitThrowsTest.php | 13 +- .../PHPStan/Rules/Exceptions/Bug5364Test.php | 10 +- .../CatchWithUnthrownExceptionRuleTest.php | 15 +- ...xceptionRuleWithDisabledMultiCatchTest.php | 13 +- .../CaughtExceptionExistenceRuleTest.php | 6 +- .../DefaultExceptionTypeResolverTest.php | 9 +- ...eckedExceptionInFunctionThrowsRuleTest.php | 10 +- ...CheckedExceptionInMethodThrowsRuleTest.php | 10 +- .../Exceptions/NoncapturingCatchRuleTest.php | 5 +- .../Exceptions/ThrowExprTypeRuleTest.php | 7 +- .../Exceptions/ThrowExpressionRuleTest.php | 5 +- ...FunctionWithExplicitThrowPointRuleTest.php | 15 +- ...idMethodWithExplicitThrowPointRuleTest.php | 15 +- .../Rules/Functions/ArrayFilterRuleTest.php | 5 +- .../ArrowFunctionAttributesRuleTest.php | 20 +- .../ArrowFunctionReturnTypeRuleTest.php | 11 +- .../Rules/Functions/CallCallablesRuleTest.php | 22 +- .../CallToFunctionParametersRuleTest.php | 10 +- .../Functions/ClosureAttributesRuleTest.php | 20 +- .../DuplicateFunctionDeclarationRuleTest.php | 8 +- ...lassesInArrowFunctionTypehintsRuleTest.php | 5 +- ...stingClassesInClosureTypehintsRuleTest.php | 5 +- .../ExistingClassesInTypehintsRuleTest.php | 5 +- .../Functions/FunctionAttributesRuleTest.php | 20 +- .../Functions/FunctionCallableRuleTest.php | 8 +- .../Functions/ParamAttributesRuleTest.php | 20 +- .../Rules/Functions/ReturnTypeRuleTest.php | 10 +- .../Rules/Generics/ClassAncestorsRuleTest.php | 11 +- .../Generics/ClassTemplateTypeRuleTest.php | 10 +- .../Rules/Generics/EnumAncestorsRuleTest.php | 11 +- .../FunctionSignatureVarianceRuleTest.php | 4 +- .../Generics/FunctionTemplateTypeRuleTest.php | 5 +- .../Generics/InterfaceAncestorsRuleTest.php | 11 +- .../InterfaceTemplateTypeRuleTest.php | 4 +- .../MethodSignatureVarianceRuleTest.php | 4 +- .../Generics/MethodTemplateTypeRuleTest.php | 5 +- .../Generics/PropertyVarianceRuleTest.php | 5 +- .../Generics/TraitTemplateTypeRuleTest.php | 5 +- .../Rules/Generics/UsedTraitsRuleTest.php | 11 +- .../CallMethodsRuleNoBleedingEdgeTest.php | 10 +- .../Rules/Methods/CallMethodsRuleTest.php | 35 +- .../Methods/CallStaticMethodsRuleTest.php | 24 +- ...hodStatementWithoutSideEffectsRuleTest.php | 5 +- .../Methods/ConsistentConstructorRuleTest.php | 5 +- .../ExistingClassesInTypehintsRuleTest.php | 5 +- .../Methods/FinalPrivateMethodRuleTest.php | 9 +- .../Methods/MethodAttributesRuleTest.php | 25 +- .../Rules/Methods/MethodCallableRuleTest.php | 10 +- .../Rules/Methods/MethodSignatureRuleTest.php | 57 +- .../Methods/OverridingMethodRuleTest.php | 36 +- .../Rules/Methods/ReturnTypeRuleTest.php | 15 +- .../Methods/StaticMethodCallableRuleTest.php | 10 +- .../Rules/Missing/MissingReturnRuleTest.php | 10 +- .../InvalidBinaryOperationRuleTest.php | 5 +- .../InvalidComparisonOperationRuleTest.php | 4 +- .../PhpDoc/IncompatiblePhpDocTypeRuleTest.php | 6 +- ...IncompatiblePropertyPhpDocTypeRuleTest.php | 5 +- .../PhpDoc/InvalidPHPStanDocTagRuleTest.php | 11 +- ...idPhpDocTagValueRuleNoBleedingEdgeTest.php | 12 +- .../PhpDoc/InvalidPhpDocTagValueRuleTest.php | 12 +- .../InvalidPhpDocVarTagTypeRuleTest.php | 11 +- .../InvalidThrowsPhpDocValueRuleTest.php | 6 +- .../RequireExtendsDefinitionClassRuleTest.php | 7 +- .../RequireExtendsDefinitionTraitRuleTest.php | 8 +- ...quireImplementsDefinitionTraitRuleTest.php | 6 +- .../WrongVariableNameInVarTagRuleTest.php | 16 +- .../AccessPropertiesInAssignRuleTest.php | 4 +- .../Properties/AccessPropertiesRuleTest.php | 36 +- ...AccessStaticPropertiesInAssignRuleTest.php | 4 +- .../AccessStaticPropertiesRuleTest.php | 6 +- .../PHPStan/Rules/Properties/Bug7074Test.php | 5 +- .../ExistingClassesInPropertiesRuleTest.php | 23 +- ...ReadOnlyByPhpDocPropertyAssignRuleTest.php | 9 +- .../MissingReadOnlyPropertyAssignRuleTest.php | 9 +- .../Properties/OverridingPropertyRuleTest.php | 21 +- .../Properties/PropertyAttributesRuleTest.php | 20 +- ...ReadOnlyByPhpDocPropertyAssignRuleTest.php | 10 +- .../ReadOnlyPropertyAssignRuleTest.php | 10 +- .../Properties/ReadOnlyPropertyRuleTest.php | 5 +- .../ReadingWriteOnlyPropertiesRuleTest.php | 5 +- ...gnedToPropertiesRuleNoBleedingEdgeTest.php | 5 +- .../TypesAssignedToPropertiesRuleTest.php | 12 +- .../UninitializedPropertyRuleTest.php | 9 +- .../WritingToReadOnlyPropertiesRuleTest.php | 5 +- .../RegularExpressionPatternRuleTest.php | 14 +- .../TooWideMethodReturnTypehintRuleTest.php | 10 +- .../Traits/ConstantsInTraitsRuleTest.php | 5 +- .../Variables/CompactVariablesRuleTest.php | 5 +- .../Variables/DefinedVariableRuleTest.php | 31 +- .../PHPStan/Rules/Variables/EmptyRuleTest.php | 18 +- .../PHPStan/Rules/Variables/IssetRuleTest.php | 18 +- .../Rules/Variables/NullCoalesceRuleTest.php | 18 +- .../Rules/Variables/ThrowTypeRuleTest.php | 7 +- ...tionClassMethodTypeSpecifyingExtension.php | 22 +- ...assStaticMethodTypeSpecifyingExtension.php | 22 +- tests/PHPStan/TrinaryLogicTest.php | 42 +- .../Type/Accessory/HasMethodTypeTest.php | 18 +- .../Type/Accessory/HasPropertyTypeTest.php | 18 +- tests/PHPStan/Type/ArrayTypeTest.php | 97 +- .../PHPStan/Type/BenevolentUnionTypeTest.php | 96 +- tests/PHPStan/Type/BitwiseFlagHelperTest.php | 20 +- tests/PHPStan/Type/BooleanTypeTest.php | 18 +- tests/PHPStan/Type/CallableTypeTest.php | 120 +- tests/PHPStan/Type/ClassStringTypeTest.php | 18 +- tests/PHPStan/Type/ClosureTypeFactoryTest.php | 4 +- tests/PHPStan/Type/ClosureTypeTest.php | 12 +- .../Constant/ConstantArrayTypeBuilderTest.php | 12 +- .../Type/Constant/ConstantArrayTypeTest.php | 129 +- .../Type/Constant/ConstantFloatTypeTest.php | 5 +- .../Type/Constant/ConstantIntegerTypeTest.php | 12 +- .../Type/Constant/ConstantStringTypeTest.php | 41 +- .../Constant/OversizedArrayBuilderTest.php | 4 +- .../Type/Enum/EnumCaseObjectTypeTest.php | 19 +- tests/PHPStan/Type/FileTypeMapperTest.php | 36 +- tests/PHPStan/Type/FloatTypeTest.php | 12 +- .../Generic/GenericClassStringTypeTest.php | 114 +- .../Type/Generic/GenericObjectTypeTest.php | 313 ++- .../Type/Generic/TemplateTypeHelperTest.php | 43 +- .../Type/Generic/TemplateTypeVarianceTest.php | 20 +- tests/PHPStan/Type/IntegerTypeTest.php | 18 +- tests/PHPStan/Type/IntersectionTypeTest.php | 40 +- tests/PHPStan/Type/IterableTypeTest.php | 94 +- tests/PHPStan/Type/MixedTypeTest.php | 205 +- tests/PHPStan/Type/ObjectTypeTest.php | 83 +- .../Type/ObjectWithoutClassTypeTest.php | 6 +- .../Type/SimultaneousTypeTraverserTest.php | 18 +- tests/PHPStan/Type/StaticTypeTest.php | 23 +- tests/PHPStan/Type/StringTypeTest.php | 95 +- tests/PHPStan/Type/TemplateTypeTest.php | 77 +- tests/PHPStan/Type/TypeCombinatorTest.php | 495 +++- tests/PHPStan/Type/TypeGetFiniteTypesTest.php | 12 +- tests/PHPStan/Type/TypeToPhpDocNodeTest.php | 16 +- tests/PHPStan/Type/UnionTypeTest.php | 555 +++- tests/e2e/ResultCacheEndToEndTest.php | 11 +- 1210 files changed, 28780 insertions(+), 23681 deletions(-) diff --git a/composer.json b/composer.json index 245afc4e607..8a1df53fa7a 100644 --- a/composer.json +++ b/composer.json @@ -1,127 +1,128 @@ { - "name": "phpstan/phpstan", - "description": "PHPStan - PHP Static Analysis Tool", - "license": [ - "MIT" - ], - "require": { - "php": "^7.2", - "composer-runtime-api": "^2.0", - "clue/ndjson-react": "^1.0", - "composer/ca-bundle": "^1.2", - "composer/xdebug-handler": "^3.0.3", - "fidry/cpu-core-counter": "^0.5.0", - "hoa/compiler": "3.17.08.08", - "hoa/exception": "^1.0", - "hoa/regex": "1.17.01.13", - "jetbrains/phpstorm-stubs": "dev-master#8ea3bf44722f76a3a32c89fe769b6144c253f8a6", - "nette/bootstrap": "^3.0", - "nette/di": "^3.1.4", - "nette/finder": "^2.5", - "nette/neon": "^3.3.1", - "nette/schema": "^1.2.2", - "nette/utils": "^3.2.5", - "nikic/php-parser": "^4.17.1", - "ondram/ci-detector": "^3.4.0", - "ondrejmirtes/better-reflection": "6.21.0", - "phpstan/php-8-stubs": "0.3.82", - "phpstan/phpdoc-parser": "1.25.0", - "react/async": "^3", - "react/child-process": "^0.6.4", - "react/dns": "^1.10", - "react/event-loop": "^1.2", - "react/http": "^1.1", - "react/promise": "^2.8", - "react/socket": "^1.3", - "react/stream": "^1.1", - "symfony/console": "^5.4.3", - "symfony/finder": "^5.4.3", - "symfony/polyfill-intl-grapheme": "^1.23", - "symfony/polyfill-intl-normalizer": "^1.23", - "symfony/polyfill-mbstring": "^1.23", - "symfony/polyfill-php73": "^1.23", - "symfony/polyfill-php74": "^1.23", - "symfony/polyfill-php80": "^1.23", - "symfony/polyfill-php81": "^1.27", - "symfony/process": "^5.4.3", - "symfony/service-contracts": "^2.5.0", - "symfony/string": "^5.4.3" - }, - "require-dev": { - "brianium/paratest": "^6.5", - "cweagans/composer-patches": "^1.7.3", - "ondrejmirtes/simple-downgrader": "^1.0", - "php-parallel-lint/php-parallel-lint": "^1.2.0", - "phpstan/phpstan-deprecation-rules": "^1.2", - "phpstan/phpstan-nette": "^1.0", - "phpstan/phpstan-phpunit": "^1.0", - "phpstan/phpstan-strict-rules": "^1.6", - "phpunit/phpunit": "^9.5.4", - "shipmonk/name-collision-detector": "^2.0" - }, - "config": { - "platform": { - "php": "8.1.99" - }, - "platform-check": false, - "sort-packages": true, - "allow-plugins": { - "cweagans/composer-patches": true - } - }, - "extra": { - "composer-exit-on-patch-failure": true, - "patches": { - "hoa/iterator": [ - "patches/Buffer.patch", - "patches/Lookahead.patch" - ], - "hoa/compiler": [ - "patches/Rule.patch" - ], - "hoa/consistency": [ - "patches/Consistency.patch" - ], - "hoa/protocol": [ - "patches/Node.patch", - "patches/Wrapper.patch" - ], - "hoa/stream": [ - "patches/Stream.patch" - ], - "jetbrains/phpstorm-stubs": [ - "patches/PDO.patch", - "patches/ReflectionProperty.patch", - "patches/SessionHandler.patch", - "patches/xmlreader.patch", - "patches/dom_c.patch" - ] - } - }, - "autoload": { - "psr-4": { - "PHPStan\\": "src/" - }, - "files": [ - "src/dumpType.php", - "src/autoloadFunctions.php", - "src/Testing/functions.php" - ] - }, - "autoload-dev": { - "psr-4": { - "PHPStan\\": [ - "build/PHPStan" - ] - }, - "classmap": [ - "tests/e2e", - "tests/PHPStan" - ] - }, - "minimum-stability": "dev", - "prefer-stable": true, - "bin": [ - "bin/phpstan" - ] -} \ No newline at end of file + "name": "phpstan/phpstan-src", + "description": "PHPStan - PHP Static Analysis Tool", + "license": [ + "MIT" + ], + "require": { + "php": "^8.1", + "composer-runtime-api": "^2.0", + "clue/ndjson-react": "^1.0", + "composer/ca-bundle": "^1.2", + "composer/xdebug-handler": "^3.0.3", + "fidry/cpu-core-counter": "^0.5.0", + "hoa/compiler": "3.17.08.08", + "hoa/exception": "^1.0", + "hoa/regex": "1.17.01.13", + "jetbrains/phpstorm-stubs": "dev-master#8ea3bf44722f76a3a32c89fe769b6144c253f8a6", + "nette/bootstrap": "^3.0", + "nette/di": "^3.1.4", + "nette/finder": "^2.5", + "nette/neon": "^3.3.1", + "nette/schema": "^1.2.2", + "nette/utils": "^3.2.5", + "nikic/php-parser": "^4.17.1", + "ondram/ci-detector": "^3.4.0", + "ondrejmirtes/better-reflection": "6.21.0", + "phpstan/php-8-stubs": "0.3.82", + "phpstan/phpdoc-parser": "1.25.0", + "react/async": "^3", + "react/child-process": "^0.6.4", + "react/dns": "^1.10", + "react/event-loop": "^1.2", + "react/http": "^1.1", + "react/promise": "^2.8", + "react/socket": "^1.3", + "react/stream": "^1.1", + "symfony/console": "^5.4.3", + "symfony/finder": "^5.4.3", + "symfony/polyfill-intl-grapheme": "^1.23", + "symfony/polyfill-intl-normalizer": "^1.23", + "symfony/polyfill-mbstring": "^1.23", + "symfony/polyfill-php73": "^1.23", + "symfony/polyfill-php74": "^1.23", + "symfony/polyfill-php80": "^1.23", + "symfony/polyfill-php81": "^1.27", + "symfony/process": "^5.4.3", + "symfony/service-contracts": "^2.5.0", + "symfony/string": "^5.4.3" + }, + "replace": { + "phpstan/phpstan": "self.version" + }, + "require-dev": { + "brianium/paratest": "^6.5", + "cweagans/composer-patches": "^1.7.3", + "ondrejmirtes/simple-downgrader": "^1.0", + "php-parallel-lint/php-parallel-lint": "^1.2.0", + "phpstan/phpstan-deprecation-rules": "^1.2", + "phpstan/phpstan-nette": "^1.0", + "phpstan/phpstan-phpunit": "^1.0", + "phpstan/phpstan-strict-rules": "^1.6", + "phpunit/phpunit": "^9.5.4", + "shipmonk/name-collision-detector": "^2.0" + }, + "config": { + "platform": { + "php": "8.1.99" + }, + "platform-check": false, + "sort-packages": true, + "allow-plugins": { + "cweagans/composer-patches": true + } + }, + "extra": { + "composer-exit-on-patch-failure": true, + "patches": { + "hoa/iterator": [ + "patches/Buffer.patch", + "patches/Lookahead.patch" + ], + "hoa/compiler": [ + "patches/Rule.patch" + ], + "hoa/consistency": [ + "patches/Consistency.patch" + ], + "hoa/protocol": [ + "patches/Node.patch", + "patches/Wrapper.patch" + ], + "hoa/stream": [ + "patches/Stream.patch" + ], + "jetbrains/phpstorm-stubs": [ + "patches/PDO.patch", + "patches/ReflectionProperty.patch", + "patches/SessionHandler.patch", + "patches/xmlreader.patch", + "patches/dom_c.patch" + ] + } + }, + "autoload": { + "psr-4": { + "PHPStan\\": [ + "src/" + ] + }, + "files": ["src/dumpType.php", "src/autoloadFunctions.php", "src/Testing/functions.php"] + }, + "autoload-dev": { + "psr-4": { + "PHPStan\\": [ + "build/PHPStan" + ] + }, + "classmap": [ + "tests/e2e", + "tests/PHPStan" + ] + }, + "minimum-stability": "dev", + "prefer-stable": true, + "bin": [ + "bin/phpstan" + ] +} diff --git a/preload.php b/preload.php index 8d65b2b775e..3c6b2651747 100644 --- a/preload.php +++ b/preload.php @@ -1,1498 +1 @@ fileAnalyser = $fileAnalyser; - $this->ruleRegistry = $ruleRegistry; - $this->collectorRegistry = $collectorRegistry; - $this->nodeScopeResolver = $nodeScopeResolver; - $this->internalErrorsCountLimit = $internalErrorsCountLimit; + + public function __construct( + private FileAnalyser $fileAnalyser, + private RuleRegistry $ruleRegistry, + private CollectorRegistry $collectorRegistry, + private NodeScopeResolver $nodeScopeResolver, + private int $internalErrorsCountLimit, + ) + { + } + + /** + * @param string[] $files + * @param Closure(string $file): void|null $preFileCallback + * @param Closure(int ): void|null $postFileCallback + * @param string[]|null $allAnalysedFiles + */ + public function analyse( + array $files, + ?Closure $preFileCallback = null, + ?Closure $postFileCallback = null, + bool $debug = false, + ?array $allAnalysedFiles = null, + ): AnalyserResult + { + if ($allAnalysedFiles === null) { + $allAnalysedFiles = $files; + } + + $this->nodeScopeResolver->setAnalysedFiles($allAnalysedFiles); + $allAnalysedFiles = array_fill_keys($allAnalysedFiles, true); + + /** @var list $errors */ + $errors = []; + + /** @var list $locallyIgnoredErrors */ + $locallyIgnoredErrors = []; + + /** @var list $collectedData */ + $collectedData = []; + + $internalErrorsCount = 0; + $reachedInternalErrorsCountLimit = false; + $dependencies = []; + $exportedNodes = []; + foreach ($files as $file) { + if ($preFileCallback !== null) { + $preFileCallback($file); + } + + try { + $fileAnalyserResult = $this->fileAnalyser->analyseFile( + $file, + $allAnalysedFiles, + $this->ruleRegistry, + $this->collectorRegistry, + null, + ); + $errors = array_merge($errors, $fileAnalyserResult->getErrors()); + $locallyIgnoredErrors = array_merge($locallyIgnoredErrors, $fileAnalyserResult->getLocallyIgnoredErrors()); + $collectedData = array_merge($collectedData, $fileAnalyserResult->getCollectedData()); + $dependencies[$file] = $fileAnalyserResult->getDependencies(); + + $fileExportedNodes = $fileAnalyserResult->getExportedNodes(); + if (count($fileExportedNodes) > 0) { + $exportedNodes[$file] = $fileExportedNodes; } - /** - * @param string[] $files - * @param Closure(string $file): void|null $preFileCallback - * @param Closure(int ): void|null $postFileCallback - * @param string[]|null $allAnalysedFiles - */ - public function analyse(array $files, ?Closure $preFileCallback = null, ?Closure $postFileCallback = null, bool $debug = false, ?array $allAnalysedFiles = null) : AnalyserResult - { - if ($allAnalysedFiles === null) { - $allAnalysedFiles = $files; - } - $this->nodeScopeResolver->setAnalysedFiles($allAnalysedFiles); - $allAnalysedFiles = array_fill_keys($allAnalysedFiles, true); - /** @var list $errors */ - $errors = []; - /** @var list $locallyIgnoredErrors */ - $locallyIgnoredErrors = []; - /** @var list $collectedData */ - $collectedData = []; - $internalErrorsCount = 0; - $reachedInternalErrorsCountLimit = false; - $dependencies = []; - $exportedNodes = []; - foreach ($files as $file) { - if ($preFileCallback !== null) { - $preFileCallback($file); - } - - try { - $fileAnalyserResult = $this->fileAnalyser->analyseFile($file, $allAnalysedFiles, $this->ruleRegistry, $this->collectorRegistry, null); - $errors = array_merge($errors, $fileAnalyserResult->getErrors()); - $locallyIgnoredErrors = array_merge($locallyIgnoredErrors, $fileAnalyserResult->getLocallyIgnoredErrors()); - $collectedData = array_merge($collectedData, $fileAnalyserResult->getCollectedData()); - $dependencies[$file] = $fileAnalyserResult->getDependencies(); - - $fileExportedNodes = $fileAnalyserResult->getExportedNodes(); - if (count($fileExportedNodes) > 0) { - $exportedNodes[$file] = $fileExportedNodes; - } - } catch (Throwable $t) { - if ($debug) { - throw $t; - } - $internalErrorsCount++; - $internalErrorMessage = sprintf('Internal error: %s', $t->getMessage()); - $internalErrorMessage .= sprintf('%sRun PHPStan with --debug option and post the stack trace to:%s%s', "\n", "\n", 'https://github.com/phpstan/phpstan/issues/new?template=Bug_report.yaml'); - $errors[] = (new Error($internalErrorMessage, $file, null, $t))->withIdentifier('phpstan.internal'); - if ($internalErrorsCount >= $this->internalErrorsCountLimit) { - $reachedInternalErrorsCountLimit = true; - break; - } - } - - if ($postFileCallback === null) { - continue; - } - - $postFileCallback(1); - } - return new AnalyserResult($errors, $locallyIgnoredErrors, [], $collectedData, $internalErrorsCount === 0 ? $dependencies : null, $exportedNodes, $reachedInternalErrorsCountLimit, memory_get_peak_usage(true)); + } catch (Throwable $t) { + if ($debug) { + throw $t; } + $internalErrorsCount++; + $internalErrorMessage = sprintf('Internal error: %s', $t->getMessage()); + $internalErrorMessage .= sprintf( + '%sRun PHPStan with --debug option and post the stack trace to:%s%s', + "\n", + "\n", + 'https://github.com/phpstan/phpstan/issues/new?template=Bug_report.yaml', + ); + $errors[] = (new Error($internalErrorMessage, $file, null, $t))->withIdentifier('phpstan.internal'); + if ($internalErrorsCount >= $this->internalErrorsCountLimit) { + $reachedInternalErrorsCountLimit = true; + break; + } + } + + if ($postFileCallback === null) { + continue; + } + + $postFileCallback(1); + } + + return new AnalyserResult( + $errors, + $locallyIgnoredErrors, + [], + $collectedData, + $internalErrorsCount === 0 ? $dependencies : null, + $exportedNodes, + $reachedInternalErrorsCountLimit, + memory_get_peak_usage(true), + ); + } + } diff --git a/src/Analyser/AnalyserResult.php b/src/Analyser/AnalyserResult.php index be9e6f47633..01c4fccfa32 100644 --- a/src/Analyser/AnalyserResult.php +++ b/src/Analyser/AnalyserResult.php @@ -9,40 +9,8 @@ class AnalyserResult { - /** - * @var list - */ - private $unorderedErrors; - /** - * @var list - */ - private $locallyIgnoredErrors; - /** - * @var list - */ - private $internalErrors; - /** - * @var list - */ - private $collectedData; - /** - * @var array>|null - */ - private $dependencies; - /** - * @var array> - */ - private $exportedNodes; - /** - * @var bool - */ - private $reachedInternalErrorsCountLimit; - /** - * @var int - */ - private $peakMemoryUsageBytes; /** @var list|null */ - private $errors = null; + private ?array $errors = null; /** * @param list $unorderedErrors @@ -52,16 +20,17 @@ class AnalyserResult * @param array>|null $dependencies * @param array> $exportedNodes */ - public function __construct(array $unorderedErrors, array $locallyIgnoredErrors, array $internalErrors, array $collectedData, ?array $dependencies, array $exportedNodes, bool $reachedInternalErrorsCountLimit, int $peakMemoryUsageBytes) + public function __construct( + private array $unorderedErrors, + private array $locallyIgnoredErrors, + private array $internalErrors, + private array $collectedData, + private ?array $dependencies, + private array $exportedNodes, + private bool $reachedInternalErrorsCountLimit, + private int $peakMemoryUsageBytes, + ) { - $this->unorderedErrors = $unorderedErrors; - $this->locallyIgnoredErrors = $locallyIgnoredErrors; - $this->internalErrors = $internalErrors; - $this->collectedData = $collectedData; - $this->dependencies = $dependencies; - $this->exportedNodes = $exportedNodes; - $this->reachedInternalErrorsCountLimit = $reachedInternalErrorsCountLimit; - $this->peakMemoryUsageBytes = $peakMemoryUsageBytes; } /** @@ -79,8 +48,9 @@ public function getErrors(): array { if (!isset($this->errors)) { $this->errors = $this->unorderedErrors; - usort($this->errors, static function (Error $a, Error $b) : int { - return [ + usort( + $this->errors, + static fn (Error $a, Error $b): int => [ $a->getFile(), $a->getLine(), $a->getMessage(), @@ -88,8 +58,8 @@ public function getErrors(): array $b->getFile(), $b->getLine(), $b->getMessage(), - ]; - }); + ], + ); } return $this->errors; diff --git a/src/Analyser/ArgumentsNormalizer.php b/src/Analyser/ArgumentsNormalizer.php index f1be05268ab..ff5f12089bc 100644 --- a/src/Analyser/ArgumentsNormalizer.php +++ b/src/Analyser/ArgumentsNormalizer.php @@ -30,12 +30,16 @@ final class ArgumentsNormalizer /** * @return array{ParametersAcceptor, FuncCall}|null */ - public static function reorderCallUserFuncArguments(FuncCall $callUserFuncCall, Scope $scope) : ?array + public static function reorderCallUserFuncArguments( + FuncCall $callUserFuncCall, + Scope $scope, + ): ?array { $args = $callUserFuncCall->getArgs(); if (count($args) < 1) { return null; } + $passThruArgs = []; $callbackArg = null; foreach ($args as $i => $arg) { @@ -52,51 +56,102 @@ public static function reorderCallUserFuncArguments(FuncCall $callUserFuncCall, $passThruArgs[] = $arg; } + if ($callbackArg === null) { return null; } + $calledOnType = $scope->getType($callbackArg->value); if (!$calledOnType->isCallable()->yes()) { return null; } - $parametersAcceptor = ParametersAcceptorSelector::selectFromArgs($scope, $passThruArgs, $calledOnType->getCallableParametersAcceptors($scope), null); - return [$parametersAcceptor, new FuncCall($callbackArg->value, $passThruArgs, $callUserFuncCall->getAttributes())]; + + $parametersAcceptor = ParametersAcceptorSelector::selectFromArgs( + $scope, + $passThruArgs, + $calledOnType->getCallableParametersAcceptors($scope), + null, + ); + + return [$parametersAcceptor, new FuncCall( + $callbackArg->value, + $passThruArgs, + $callUserFuncCall->getAttributes(), + )]; } - public static function reorderFuncArguments(ParametersAcceptor $parametersAcceptor, FuncCall $functionCall) : ?FuncCall + public static function reorderFuncArguments( + ParametersAcceptor $parametersAcceptor, + FuncCall $functionCall, + ): ?FuncCall { $reorderedArgs = self::reorderArgs($parametersAcceptor, $functionCall); + if ($reorderedArgs === null) { return null; } - return new FuncCall($functionCall->name, $reorderedArgs, $functionCall->getAttributes()); + + return new FuncCall( + $functionCall->name, + $reorderedArgs, + $functionCall->getAttributes(), + ); } - public static function reorderMethodArguments(ParametersAcceptor $parametersAcceptor, MethodCall $methodCall) : ?MethodCall + public static function reorderMethodArguments( + ParametersAcceptor $parametersAcceptor, + MethodCall $methodCall, + ): ?MethodCall { $reorderedArgs = self::reorderArgs($parametersAcceptor, $methodCall); + if ($reorderedArgs === null) { return null; } - return new MethodCall($methodCall->var, $methodCall->name, $reorderedArgs, $methodCall->getAttributes()); + + return new MethodCall( + $methodCall->var, + $methodCall->name, + $reorderedArgs, + $methodCall->getAttributes(), + ); } - public static function reorderStaticCallArguments(ParametersAcceptor $parametersAcceptor, StaticCall $staticCall) : ?StaticCall + public static function reorderStaticCallArguments( + ParametersAcceptor $parametersAcceptor, + StaticCall $staticCall, + ): ?StaticCall { $reorderedArgs = self::reorderArgs($parametersAcceptor, $staticCall); + if ($reorderedArgs === null) { return null; } - return new StaticCall($staticCall->class, $staticCall->name, $reorderedArgs, $staticCall->getAttributes()); + + return new StaticCall( + $staticCall->class, + $staticCall->name, + $reorderedArgs, + $staticCall->getAttributes(), + ); } - public static function reorderNewArguments(ParametersAcceptor $parametersAcceptor, New_ $new) : ?New_ + public static function reorderNewArguments( + ParametersAcceptor $parametersAcceptor, + New_ $new, + ): ?New_ { $reorderedArgs = self::reorderArgs($parametersAcceptor, $new); + if ($reorderedArgs === null) { return null; } - return new New_($new->class, $reorderedArgs, $new->getAttributes()); + + return new New_( + $new->class, + $reorderedArgs, + $new->getAttributes(), + ); } /** @@ -145,7 +200,13 @@ private static function reorderArgs(ParametersAcceptor $parametersAcceptor, Call // order named args into the position the signature expects them $attributes = $arg->getAttributes(); $attributes[self::ORIGINAL_ARG_ATTRIBUTE] = $arg; - $reorderedArgs[$argumentPositions[$argName]] = new Arg($arg->value, $arg->byRef, $arg->unpack, $attributes, null); + $reorderedArgs[$argumentPositions[$argName]] = new Arg( + $arg->value, + $arg->byRef, + $arg->unpack, + $attributes, + null, + ); } else { if (!$hasVariadic) { return null; @@ -153,7 +214,13 @@ private static function reorderArgs(ParametersAcceptor $parametersAcceptor, Call $attributes = $arg->getAttributes(); $attributes[self::ORIGINAL_ARG_ATTRIBUTE] = $arg; - $additionalNamedArgs[] = new Arg($arg->value, $arg->byRef, $arg->unpack, $attributes, null); + $additionalNamedArgs[] = new Arg( + $arg->value, + $arg->byRef, + $arg->unpack, + $attributes, + null, + ); } } @@ -195,7 +262,9 @@ private static function reorderArgs(ParametersAcceptor $parametersAcceptor, Call $defaultValue = new ConstantArrayType([], []); } - $reorderedArgs[$j] = new Arg(new TypeExpr($defaultValue)); + $reorderedArgs[$j] = new Arg( + new TypeExpr($defaultValue), + ); } ksort($reorderedArgs); diff --git a/src/Analyser/ConditionalExpressionHolder.php b/src/Analyser/ConditionalExpressionHolder.php index 51f9b403662..561feac059d 100644 --- a/src/Analyser/ConditionalExpressionHolder.php +++ b/src/Analyser/ConditionalExpressionHolder.php @@ -12,28 +12,22 @@ class ConditionalExpressionHolder { /** - * @var array - */ - private $conditionExpressionTypeHolders; - /** - * @var ExpressionTypeHolder - */ - private $typeHolder; - /** - * @param array $conditionExpressionTypeHolders - */ - public function __construct(array $conditionExpressionTypeHolders, ExpressionTypeHolder $typeHolder) - { - $this->conditionExpressionTypeHolders = $conditionExpressionTypeHolders; - $this->typeHolder = $typeHolder; - if (count($conditionExpressionTypeHolders) === 0) { - throw new ShouldNotHappenException(); - } - } - /** - * @return array - */ - public function getConditionExpressionTypeHolders(): array + * @param array $conditionExpressionTypeHolders + */ + public function __construct( + private array $conditionExpressionTypeHolders, + private ExpressionTypeHolder $typeHolder, + ) + { + if (count($conditionExpressionTypeHolders) === 0) { + throw new ShouldNotHappenException(); + } + } + + /** + * @return array + */ + public function getConditionExpressionTypeHolders(): array { return $this->conditionExpressionTypeHolders; } @@ -50,7 +44,12 @@ public function getKey(): string $parts[] = $exprString . '=' . $typeHolder->getType()->describe(VerbosityLevel::precise()); } - return sprintf('%s => %s (%s)', implode(' && ', $parts), $this->typeHolder->getType()->describe(VerbosityLevel::precise()), $this->typeHolder->getCertainty()->describe()); + return sprintf( + '%s => %s (%s)', + implode(' && ', $parts), + $this->typeHolder->getType()->describe(VerbosityLevel::precise()), + $this->typeHolder->getCertainty()->describe(), + ); } } diff --git a/src/Analyser/ConstantResolver.php b/src/Analyser/ConstantResolver.php index db4fade6492..19cf21bbf2c 100644 --- a/src/Analyser/ConstantResolver.php +++ b/src/Analyser/ConstantResolver.php @@ -28,24 +28,14 @@ class ConstantResolver { - /** - * @var ReflectionProviderProvider - */ - private $reflectionProviderProvider; - /** - * @var string[] - */ - private $dynamicConstantNames; /** @var array */ - private $currentlyResolving = []; + private array $currentlyResolving = []; /** * @param string[] $dynamicConstantNames */ - public function __construct(ReflectionProviderProvider $reflectionProviderProvider, array $dynamicConstantNames) + public function __construct(private ReflectionProviderProvider $reflectionProviderProvider, private array $dynamicConstantNames) { - $this->reflectionProviderProvider = $reflectionProviderProvider; - $this->dynamicConstantNames = $dynamicConstantNames; } public function resolveConstant(Name $name, ?NamespaceAnswerer $scope): ?Type diff --git a/src/Analyser/ConstantResolverFactory.php b/src/Analyser/ConstantResolverFactory.php index 23afba6d49f..bd63830f59c 100644 --- a/src/Analyser/ConstantResolverFactory.php +++ b/src/Analyser/ConstantResolverFactory.php @@ -8,22 +8,19 @@ class ConstantResolverFactory { - /** - * @var ReflectionProviderProvider - */ - private $reflectionProviderProvider; - /** - * @var Container - */ - private $container; - public function __construct(ReflectionProviderProvider $reflectionProviderProvider, Container $container) + public function __construct( + private ReflectionProviderProvider $reflectionProviderProvider, + private Container $container, + ) { - $this->reflectionProviderProvider = $reflectionProviderProvider; - $this->container = $container; } + public function create(): ConstantResolver { - return new ConstantResolver($this->reflectionProviderProvider, $this->container->getParameter('dynamicConstantNames')); + return new ConstantResolver( + $this->reflectionProviderProvider, + $this->container->getParameter('dynamicConstantNames'), + ); } } diff --git a/src/Analyser/DirectInternalScopeFactory.php b/src/Analyser/DirectInternalScopeFactory.php index 376102e57e5..07d7fbe09cc 100644 --- a/src/Analyser/DirectInternalScopeFactory.php +++ b/src/Analyser/DirectInternalScopeFactory.php @@ -19,97 +19,93 @@ class DirectInternalScopeFactory implements InternalScopeFactory { - /** - * @var class-string - */ - private $scopeClass; - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - /** - * @var InitializerExprTypeResolver - */ - private $initializerExprTypeResolver; - /** - * @var DynamicReturnTypeExtensionRegistryProvider - */ - private $dynamicReturnTypeExtensionRegistryProvider; - /** - * @var ExpressionTypeResolverExtensionRegistryProvider - */ - private $expressionTypeResolverExtensionRegistryProvider; - /** - * @var ExprPrinter - */ - private $exprPrinter; - /** - * @var TypeSpecifier - */ - private $typeSpecifier; - /** - * @var PropertyReflectionFinder - */ - private $propertyReflectionFinder; - /** - * @var Parser - */ - private $parser; - /** - * @var NodeScopeResolver - */ - private $nodeScopeResolver; - /** - * @var PhpVersion - */ - private $phpVersion; - /** - * @var bool - */ - private $explicitMixedInUnknownGenericNew; - /** - * @var bool - */ - private $explicitMixedForGlobalVariables; - /** - * @var ConstantResolver - */ - private $constantResolver; - /** - * @param class-string $scopeClass - */ - public function __construct(string $scopeClass, ReflectionProvider $reflectionProvider, InitializerExprTypeResolver $initializerExprTypeResolver, DynamicReturnTypeExtensionRegistryProvider $dynamicReturnTypeExtensionRegistryProvider, ExpressionTypeResolverExtensionRegistryProvider $expressionTypeResolverExtensionRegistryProvider, ExprPrinter $exprPrinter, TypeSpecifier $typeSpecifier, PropertyReflectionFinder $propertyReflectionFinder, Parser $parser, NodeScopeResolver $nodeScopeResolver, PhpVersion $phpVersion, bool $explicitMixedInUnknownGenericNew, bool $explicitMixedForGlobalVariables, ConstantResolver $constantResolver) - { - $this->scopeClass = $scopeClass; - $this->reflectionProvider = $reflectionProvider; - $this->initializerExprTypeResolver = $initializerExprTypeResolver; - $this->dynamicReturnTypeExtensionRegistryProvider = $dynamicReturnTypeExtensionRegistryProvider; - $this->expressionTypeResolverExtensionRegistryProvider = $expressionTypeResolverExtensionRegistryProvider; - $this->exprPrinter = $exprPrinter; - $this->typeSpecifier = $typeSpecifier; - $this->propertyReflectionFinder = $propertyReflectionFinder; - $this->parser = $parser; - $this->nodeScopeResolver = $nodeScopeResolver; - $this->phpVersion = $phpVersion; - $this->explicitMixedInUnknownGenericNew = $explicitMixedInUnknownGenericNew; - $this->explicitMixedForGlobalVariables = $explicitMixedForGlobalVariables; - $this->constantResolver = $constantResolver; - } - /** - * @param array $expressionTypes - * @param array $nativeExpressionTypes - * @param array $conditionalExpressions - * @param list $inFunctionCallsStack - * @param array $currentlyAssignedExpressions - * @param array $currentlyAllowedUndefinedExpressions - * @param FunctionReflection|MethodReflection|null $function - */ - public function create(ScopeContext $context, bool $declareStrictTypes = false, $function = null, ?string $namespace = null, array $expressionTypes = [], array $nativeExpressionTypes = [], array $conditionalExpressions = [], array $inClosureBindScopeClasses = [], ?ParametersAcceptor $anonymousFunctionReflection = null, bool $inFirstLevelStatement = true, array $currentlyAssignedExpressions = [], array $currentlyAllowedUndefinedExpressions = [], array $inFunctionCallsStack = [], bool $afterExtractCall = false, ?Scope $parentScope = null, bool $nativeTypesPromoted = false) : MutatingScope - { - $scopeClass = $this->scopeClass; - if (!is_a($scopeClass, MutatingScope::class, true)) { - throw new ShouldNotHappenException(); - } - return new $scopeClass($this, $this->reflectionProvider, $this->initializerExprTypeResolver, $this->dynamicReturnTypeExtensionRegistryProvider->getRegistry(), $this->expressionTypeResolverExtensionRegistryProvider->getRegistry(), $this->exprPrinter, $this->typeSpecifier, $this->propertyReflectionFinder, $this->parser, $this->nodeScopeResolver, $this->constantResolver, $context, $this->phpVersion, $declareStrictTypes, $function, $namespace, $expressionTypes, $nativeExpressionTypes, $conditionalExpressions, $inClosureBindScopeClasses, $anonymousFunctionReflection, $inFirstLevelStatement, $currentlyAssignedExpressions, $currentlyAllowedUndefinedExpressions, $inFunctionCallsStack, $afterExtractCall, $parentScope, $nativeTypesPromoted, $this->explicitMixedInUnknownGenericNew, $this->explicitMixedForGlobalVariables); - } + + /** + * @param class-string $scopeClass + */ + public function __construct( + private string $scopeClass, + private ReflectionProvider $reflectionProvider, + private InitializerExprTypeResolver $initializerExprTypeResolver, + private DynamicReturnTypeExtensionRegistryProvider $dynamicReturnTypeExtensionRegistryProvider, + private ExpressionTypeResolverExtensionRegistryProvider $expressionTypeResolverExtensionRegistryProvider, + private ExprPrinter $exprPrinter, + private TypeSpecifier $typeSpecifier, + private PropertyReflectionFinder $propertyReflectionFinder, + private Parser $parser, + private NodeScopeResolver $nodeScopeResolver, + private PhpVersion $phpVersion, + private bool $explicitMixedInUnknownGenericNew, + private bool $explicitMixedForGlobalVariables, + private ConstantResolver $constantResolver, + ) + { + } + + /** + * @param array $expressionTypes + * @param array $nativeExpressionTypes + * @param array $conditionalExpressions + * @param list $inFunctionCallsStack + * @param array $currentlyAssignedExpressions + * @param array $currentlyAllowedUndefinedExpressions + */ + public function create( + ScopeContext $context, + bool $declareStrictTypes = false, + FunctionReflection|MethodReflection|null $function = null, + ?string $namespace = null, + array $expressionTypes = [], + array $nativeExpressionTypes = [], + array $conditionalExpressions = [], + array $inClosureBindScopeClasses = [], + ?ParametersAcceptor $anonymousFunctionReflection = null, + bool $inFirstLevelStatement = true, + array $currentlyAssignedExpressions = [], + array $currentlyAllowedUndefinedExpressions = [], + array $inFunctionCallsStack = [], + bool $afterExtractCall = false, + ?Scope $parentScope = null, + bool $nativeTypesPromoted = false, + ): MutatingScope + { + $scopeClass = $this->scopeClass; + if (!is_a($scopeClass, MutatingScope::class, true)) { + throw new ShouldNotHappenException(); + } + + return new $scopeClass( + $this, + $this->reflectionProvider, + $this->initializerExprTypeResolver, + $this->dynamicReturnTypeExtensionRegistryProvider->getRegistry(), + $this->expressionTypeResolverExtensionRegistryProvider->getRegistry(), + $this->exprPrinter, + $this->typeSpecifier, + $this->propertyReflectionFinder, + $this->parser, + $this->nodeScopeResolver, + $this->constantResolver, + $context, + $this->phpVersion, + $declareStrictTypes, + $function, + $namespace, + $expressionTypes, + $nativeExpressionTypes, + $conditionalExpressions, + $inClosureBindScopeClasses, + $anonymousFunctionReflection, + $inFirstLevelStatement, + $currentlyAssignedExpressions, + $currentlyAllowedUndefinedExpressions, + $inFunctionCallsStack, + $afterExtractCall, + $parentScope, + $nativeTypesPromoted, + $this->explicitMixedInUnknownGenericNew, + $this->explicitMixedForGlobalVariables, + ); + } + } diff --git a/src/Analyser/EnsuredNonNullabilityResult.php b/src/Analyser/EnsuredNonNullabilityResult.php index 130e98d8619..258a16b18bb 100644 --- a/src/Analyser/EnsuredNonNullabilityResult.php +++ b/src/Analyser/EnsuredNonNullabilityResult.php @@ -5,21 +5,11 @@ class EnsuredNonNullabilityResult { - /** - * @var MutatingScope - */ - private $scope; - /** - * @var EnsuredNonNullabilityResultExpression[] - */ - private $specifiedExpressions; /** * @param EnsuredNonNullabilityResultExpression[] $specifiedExpressions */ - public function __construct(MutatingScope $scope, array $specifiedExpressions) + public function __construct(private MutatingScope $scope, private array $specifiedExpressions) { - $this->scope = $scope; - $this->specifiedExpressions = $specifiedExpressions; } public function getScope(): MutatingScope diff --git a/src/Analyser/EnsuredNonNullabilityResultExpression.php b/src/Analyser/EnsuredNonNullabilityResultExpression.php index 6b0c2e55e3a..33f94341e6e 100644 --- a/src/Analyser/EnsuredNonNullabilityResultExpression.php +++ b/src/Analyser/EnsuredNonNullabilityResultExpression.php @@ -9,29 +9,15 @@ class EnsuredNonNullabilityResultExpression { - /** - * @var Expr - */ - private $expression; - /** - * @var Type - */ - private $originalType; - /** - * @var Type - */ - private $originalNativeType; - /** - * @var TrinaryLogic - */ - private $certainty; - public function __construct(Expr $expression, Type $originalType, Type $originalNativeType, TrinaryLogic $certainty) + public function __construct( + private Expr $expression, + private Type $originalType, + private Type $originalNativeType, + private TrinaryLogic $certainty, + ) { - $this->expression = $expression; - $this->originalType = $originalType; - $this->originalNativeType = $originalNativeType; - $this->certainty = $certainty; } + public function getExpression(): Expr { return $this->expression; diff --git a/src/Analyser/Error.php b/src/Analyser/Error.php index f1e32c688c0..35b567fbcab 100644 --- a/src/Analyser/Error.php +++ b/src/Analyser/Error.php @@ -16,76 +16,32 @@ class Error implements JsonSerializable { - /** - * @var string - */ - private $message; - /** - * @var string - */ - private $file; - /** - * @var ?int - */ - private $line; - /** - * @var bool|Throwable - */ - private $canBeIgnored; - /** - * @var ?string - */ - private $filePath; - /** - * @var ?string - */ - private $traitFilePath; - /** - * @var ?string - */ - private $tip; - /** - * @var ?int - */ - private $nodeLine; - /** - * @var class-string|null - */ - private $nodeType; - /** - * @var ?string - */ - private $identifier; - /** - * @var mixed[] - */ - private $metadata; - public const PATTERN_IDENTIFIER = '[a-zA-Z0-9](?:[a-zA-Z0-9\\.]*[a-zA-Z0-9])?'; + public const PATTERN_IDENTIFIER = '[a-zA-Z0-9](?:[a-zA-Z0-9\\.]*[a-zA-Z0-9])?'; /** - * Error constructor. - * - * @param class-string|null $nodeType - * @param mixed[] $metadata - * @param bool|Throwable $canBeIgnored - */ - public function __construct(string $message, string $file, ?int $line = null, $canBeIgnored = true, ?string $filePath = null, ?string $traitFilePath = null, ?string $tip = null, ?int $nodeLine = null, ?string $nodeType = null, ?string $identifier = null, array $metadata = []) - { - $this->message = $message; - $this->file = $file; - $this->line = $line; - $this->canBeIgnored = $canBeIgnored; - $this->filePath = $filePath; - $this->traitFilePath = $traitFilePath; - $this->tip = $tip; - $this->nodeLine = $nodeLine; - $this->nodeType = $nodeType; - $this->identifier = $identifier; - $this->metadata = $metadata; - if ($this->identifier !== null && !self::validateIdentifier($this->identifier)) { - throw new ShouldNotHappenException(sprintf('Invalid identifier: %s', $this->identifier)); - } - } + * Error constructor. + * + * @param class-string|null $nodeType + * @param mixed[] $metadata + */ + public function __construct( + private string $message, + private string $file, + private ?int $line = null, + private bool|Throwable $canBeIgnored = true, + private ?string $filePath = null, + private ?string $traitFilePath = null, + private ?string $tip = null, + private ?int $nodeLine = null, + private ?string $nodeType = null, + private ?string $identifier = null, + private array $metadata = [], + ) + { + if ($this->identifier !== null && !self::validateIdentifier($this->identifier)) { + throw new ShouldNotHappenException(sprintf('Invalid identifier: %s', $this->identifier)); + } + } public function getMessage(): string { @@ -112,12 +68,36 @@ public function changeFilePath(string $newFilePath): self throw new ShouldNotHappenException('Errors in traits not yet supported'); } - return new self($this->message, $newFilePath, $this->line, $this->canBeIgnored, $newFilePath, null, $this->tip, $this->nodeLine, $this->nodeType, $this->identifier, $this->metadata); + return new self( + $this->message, + $newFilePath, + $this->line, + $this->canBeIgnored, + $newFilePath, + null, + $this->tip, + $this->nodeLine, + $this->nodeType, + $this->identifier, + $this->metadata, + ); } public function changeTraitFilePath(string $newFilePath): self { - return new self($this->message, $this->file, $this->line, $this->canBeIgnored, $this->filePath, $newFilePath, $this->tip, $this->nodeLine, $this->nodeType, $this->identifier, $this->metadata); + return new self( + $this->message, + $this->file, + $this->line, + $this->canBeIgnored, + $this->filePath, + $newFilePath, + $this->tip, + $this->nodeLine, + $this->nodeType, + $this->identifier, + $this->metadata, + ); } public function getTraitFilePath(): ?string @@ -151,7 +131,17 @@ public function withoutTip(): self return $this; } - return new self($this->message, $this->file, $this->line, $this->canBeIgnored, $this->filePath, $this->traitFilePath, null, $this->nodeLine, $this->nodeType); + return new self( + $this->message, + $this->file, + $this->line, + $this->canBeIgnored, + $this->filePath, + $this->traitFilePath, + null, + $this->nodeLine, + $this->nodeType, + ); } public function doNotIgnore(): self @@ -160,7 +150,17 @@ public function doNotIgnore(): self return $this; } - return new self($this->message, $this->file, $this->line, false, $this->filePath, $this->traitFilePath, $this->tip, $this->nodeLine, $this->nodeType); + return new self( + $this->message, + $this->file, + $this->line, + false, + $this->filePath, + $this->traitFilePath, + $this->tip, + $this->nodeLine, + $this->nodeType, + ); } public function withIdentifier(string $identifier): self @@ -169,7 +169,19 @@ public function withIdentifier(string $identifier): self throw new ShouldNotHappenException(sprintf('Error already has an identifier: %s', $this->identifier)); } - return new self($this->message, $this->file, $this->line, $this->canBeIgnored, $this->filePath, $this->traitFilePath, $this->tip, $this->nodeLine, $this->nodeType, $identifier, $this->metadata); + return new self( + $this->message, + $this->file, + $this->line, + $this->canBeIgnored, + $this->filePath, + $this->traitFilePath, + $this->tip, + $this->nodeLine, + $this->nodeType, + $identifier, + $this->metadata, + ); } public function getNodeLine(): ?int @@ -178,27 +190,27 @@ public function getNodeLine(): ?int } /** - * @return class-string|null - */ - public function getNodeType(): ?string + * @return class-string|null + */ + public function getNodeType(): ?string { return $this->nodeType; } /** - * Error identifier set via `RuleErrorBuilder::identifier()`. - * - * List of all current error identifiers in PHPStan: https://phpstan.org/error-identifiers - */ - public function getIdentifier(): ?string + * Error identifier set via `RuleErrorBuilder::identifier()`. + * + * List of all current error identifiers in PHPStan: https://phpstan.org/error-identifiers + */ + public function getIdentifier(): ?string { return $this->identifier; } /** - * @return mixed[] - */ - public function getMetadata(): array + * @return mixed[] + */ + public function getMetadata(): array { return $this->metadata; } @@ -225,19 +237,43 @@ public function jsonSerialize() } /** - * @param mixed[] $json - */ - public static function decode(array $json): self + * @param mixed[] $json + */ + public static function decode(array $json): self { - return new self($json['message'], $json['file'], $json['line'], $json['canBeIgnored'] === 'exception' ? new Exception() : $json['canBeIgnored'], $json['filePath'], $json['traitFilePath'], $json['tip'], $json['nodeLine'] ?? null, $json['nodeType'] ?? null, $json['identifier'] ?? null, $json['metadata'] ?? []); + return new self( + $json['message'], + $json['file'], + $json['line'], + $json['canBeIgnored'] === 'exception' ? new Exception() : $json['canBeIgnored'], + $json['filePath'], + $json['traitFilePath'], + $json['tip'], + $json['nodeLine'] ?? null, + $json['nodeType'] ?? null, + $json['identifier'] ?? null, + $json['metadata'] ?? [], + ); } /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): self + * @param mixed[] $properties + */ + public static function __set_state(array $properties): self { - return new self($properties['message'], $properties['file'], $properties['line'], $properties['canBeIgnored'], $properties['filePath'], $properties['traitFilePath'], $properties['tip'], $properties['nodeLine'] ?? null, $properties['nodeType'] ?? null, $properties['identifier'] ?? null, $properties['metadata'] ?? []); + return new self( + $properties['message'], + $properties['file'], + $properties['line'], + $properties['canBeIgnored'], + $properties['filePath'], + $properties['traitFilePath'], + $properties['tip'], + $properties['nodeLine'] ?? null, + $properties['nodeType'] ?? null, + $properties['identifier'] ?? null, + $properties['metadata'] ?? [], + ); } public static function validateIdentifier(string $identifier): bool diff --git a/src/Analyser/ExpressionContext.php b/src/Analyser/ExpressionContext.php index 0be6e20b410..c2a5a6c78ab 100644 --- a/src/Analyser/ExpressionContext.php +++ b/src/Analyser/ExpressionContext.php @@ -7,29 +7,15 @@ class ExpressionContext { - /** - * @var bool - */ - private $isDeep; - /** - * @var ?string - */ - private $inAssignRightSideVariableName; - /** - * @var ?Type - */ - private $inAssignRightSideType; - /** - * @var ?Type - */ - private $inAssignRightSideNativeType; - private function __construct(bool $isDeep, ?string $inAssignRightSideVariableName, ?Type $inAssignRightSideType, ?Type $inAssignRightSideNativeType) + private function __construct( + private bool $isDeep, + private ?string $inAssignRightSideVariableName, + private ?Type $inAssignRightSideType, + private ?Type $inAssignRightSideNativeType, + ) { - $this->isDeep = $isDeep; - $this->inAssignRightSideVariableName = $inAssignRightSideVariableName; - $this->inAssignRightSideType = $inAssignRightSideType; - $this->inAssignRightSideNativeType = $inAssignRightSideNativeType; } + public static function createTopLevel(): self { return new self(false, null, null, null); diff --git a/src/Analyser/ExpressionResult.php b/src/Analyser/ExpressionResult.php index da7b2d53f3a..93a3bdca25b 100644 --- a/src/Analyser/ExpressionResult.php +++ b/src/Analyser/ExpressionResult.php @@ -5,44 +5,29 @@ class ExpressionResult { - /** - * @var MutatingScope - */ - private $scope; - /** - * @var bool - */ - private $hasYield; - /** - * @var ThrowPoint[] - */ - private $throwPoints; /** @var (callable(): MutatingScope)|null */ private $truthyScopeCallback; - /** - * @var ?MutatingScope - */ - private $truthyScope = null; + private ?MutatingScope $truthyScope = null; /** @var (callable(): MutatingScope)|null */ private $falseyScopeCallback; - /** - * @var ?MutatingScope - */ - private $falseyScope = null; + private ?MutatingScope $falseyScope = null; /** * @param ThrowPoint[] $throwPoints * @param (callable(): MutatingScope)|null $truthyScopeCallback * @param (callable(): MutatingScope)|null $falseyScopeCallback */ - public function __construct(MutatingScope $scope, bool $hasYield, array $throwPoints, ?callable $truthyScopeCallback = null, ?callable $falseyScopeCallback = null) + public function __construct( + private MutatingScope $scope, + private bool $hasYield, + private array $throwPoints, + ?callable $truthyScopeCallback = null, + ?callable $falseyScopeCallback = null, + ) { - $this->scope = $scope; - $this->hasYield = $hasYield; - $this->throwPoints = $throwPoints; $this->truthyScopeCallback = $truthyScopeCallback; $this->falseyScopeCallback = $falseyScopeCallback; } diff --git a/src/Analyser/ExpressionTypeHolder.php b/src/Analyser/ExpressionTypeHolder.php index e76484e31d7..6211e211c85 100644 --- a/src/Analyser/ExpressionTypeHolder.php +++ b/src/Analyser/ExpressionTypeHolder.php @@ -10,23 +10,8 @@ class ExpressionTypeHolder { - /** - * @var Expr - */ - private $expr; - /** - * @var Type - */ - private $type; - /** - * @var TrinaryLogic - */ - private $certainty; - public function __construct(Expr $expr, Type $type, TrinaryLogic $certainty) + public function __construct(private Expr $expr, private Type $type, private TrinaryLogic $certainty) { - $this->expr = $expr; - $this->type = $type; - $this->certainty = $certainty; } public static function createYes(Expr $expr, Type $type): self @@ -55,7 +40,11 @@ public function and(self $other): self } else { $type = TypeCombinator::union($this->getType(), $other->getType()); } - return new self($this->expr, $type, $this->getCertainty()->and($other->getCertainty())); + return new self( + $this->expr, + $type, + $this->getCertainty()->and($other->getCertainty()), + ); } public function getExpr(): Expr diff --git a/src/Analyser/FileAnalyser.php b/src/Analyser/FileAnalyser.php index 4668de32246..fe795c92ffd 100644 --- a/src/Analyser/FileAnalyser.php +++ b/src/Analyser/FileAnalyser.php @@ -33,252 +33,261 @@ class FileAnalyser { - /** - * @var ScopeFactory - */ - private $scopeFactory; - /** - * @var NodeScopeResolver - */ - private $nodeScopeResolver; - /** - * @var Parser - */ - private $parser; - /** - * @var DependencyResolver - */ - private $dependencyResolver; - /** - * @var RuleErrorTransformer - */ - private $ruleErrorTransformer; - /** - * @var bool - */ - private $reportUnmatchedIgnoredErrors; - /** @var list */ - private $collectedErrors = []; - - public function __construct(ScopeFactory $scopeFactory, NodeScopeResolver $nodeScopeResolver, Parser $parser, DependencyResolver $dependencyResolver, RuleErrorTransformer $ruleErrorTransformer, bool $reportUnmatchedIgnoredErrors) - { - $this->scopeFactory = $scopeFactory; - $this->nodeScopeResolver = $nodeScopeResolver; - $this->parser = $parser; - $this->dependencyResolver = $dependencyResolver; - $this->ruleErrorTransformer = $ruleErrorTransformer; - $this->reportUnmatchedIgnoredErrors = $reportUnmatchedIgnoredErrors; - } + /** @var list */ + private array $collectedErrors = []; + + public function __construct( + private ScopeFactory $scopeFactory, + private NodeScopeResolver $nodeScopeResolver, + private Parser $parser, + private DependencyResolver $dependencyResolver, + private RuleErrorTransformer $ruleErrorTransformer, + private bool $reportUnmatchedIgnoredErrors, + ) + { + } /** - * @param array $analysedFiles - * @param callable(Node $node, Scope $scope): void|null $outerNodeCallback - */ - public function analyseFile(string $file, array $analysedFiles, RuleRegistry $ruleRegistry, CollectorRegistry $collectorRegistry, ?callable $outerNodeCallback) : FileAnalyserResult - { - /** @var list $fileErrors */ - $fileErrors = []; - /** @var list $locallyIgnoredErrors */ - $locallyIgnoredErrors = []; - /** @var list $fileCollectedData */ - $fileCollectedData = []; - $fileDependencies = []; - $exportedNodes = []; - if (is_file($file)) { - try { - $this->collectErrors($analysedFiles); - $parserNodes = $this->parser->parseFile($file); - $linesToIgnore = $unmatchedLineIgnores = [$file => $this->getLinesToIgnoreFromTokens($parserNodes)]; - $temporaryFileErrors = []; - $nodeCallback = function (Node $node, Scope $scope) use (&$fileErrors, &$fileCollectedData, &$fileDependencies, &$exportedNodes, $file, $ruleRegistry, $collectorRegistry, $outerNodeCallback, $analysedFiles, &$linesToIgnore, &$unmatchedLineIgnores, &$temporaryFileErrors): void { - if ($node instanceof Node\Stmt\Trait_) { - foreach (array_keys($linesToIgnore[$file] ?? []) as $lineToIgnore) { - if ($lineToIgnore < $node->getStartLine() || $lineToIgnore > $node->getEndLine()) { - continue; - } - - unset($unmatchedLineIgnores[$file][$lineToIgnore]); - } - } - if ($node instanceof InTraitNode) { - $traitNode = $node->getOriginalNode(); - $linesToIgnore[$scope->getFileDescription()] = $this->getLinesToIgnoreFromTokens([$traitNode]); - } - if ($outerNodeCallback !== null) { - $outerNodeCallback($node, $scope); - } - $uniquedAnalysedCodeExceptionMessages = []; - $nodeType = get_class($node); - foreach ($ruleRegistry->getRules($nodeType) as $rule) { - try { - $ruleErrors = $rule->processNode($node, $scope); - } catch (AnalysedCodeException $e) { - if (isset($uniquedAnalysedCodeExceptionMessages[$e->getMessage()])) { - continue; - } - - $uniquedAnalysedCodeExceptionMessages[$e->getMessage()] = true; - $fileErrors[] = (new Error($e->getMessage(), $file, $node->getStartLine(), $e, null, null, $e->getTip()))->withIdentifier('phpstan.internal'); - continue; - } catch (IdentifierNotFound $e) { - $fileErrors[] = (new Error(sprintf('Reflection error: %s not found.', $e->getIdentifier()->getName()), $file, $node->getStartLine(), $e, null, null, 'Learn more at https://phpstan.org/user-guide/discovering-symbols'))->withIdentifier('phpstan.reflection'); - continue; - } catch (UnableToCompileNode | CircularReference $e) { - $fileErrors[] = (new Error(sprintf('Reflection error: %s', $e->getMessage()), $file, $node->getStartLine(), $e))->withIdentifier('phpstan.reflection'); - continue; - } - - foreach ($ruleErrors as $ruleError) { - $temporaryFileErrors[] = $this->ruleErrorTransformer->transform($ruleError, $scope, $nodeType, $node->getStartLine()); - } - } - - foreach ($collectorRegistry->getCollectors($nodeType) as $collector) { - try { - $collectedData = $collector->processNode($node, $scope); - } catch (AnalysedCodeException $e) { - if (isset($uniquedAnalysedCodeExceptionMessages[$e->getMessage()])) { - continue; - } - - $uniquedAnalysedCodeExceptionMessages[$e->getMessage()] = true; - $fileErrors[] = (new Error($e->getMessage(), $file, $node->getStartLine(), $e, null, null, $e->getTip()))->withIdentifier('phpstan.internal'); - continue; - } catch (IdentifierNotFound $e) { - $fileErrors[] = (new Error(sprintf('Reflection error: %s not found.', $e->getIdentifier()->getName()), $file, $node->getStartLine(), $e, null, null, 'Learn more at https://phpstan.org/user-guide/discovering-symbols'))->withIdentifier('phpstan.reflection'); - continue; - } catch (UnableToCompileNode | CircularReference $e) { - $fileErrors[] = (new Error(sprintf('Reflection error: %s', $e->getMessage()), $file, $node->getStartLine(), $e))->withIdentifier('phpstan.reflection'); - continue; - } - - if ($collectedData === null) { - continue; - } - - $fileCollectedData[] = new CollectedData($collectedData, $scope->getFile(), get_class($collector)); - } - - try { - $dependencies = $this->dependencyResolver->resolveDependencies($node, $scope); - foreach ($dependencies->getFileDependencies($scope->getFile(), $analysedFiles) as $dependentFile) { - $fileDependencies[] = $dependentFile; - } - if ($dependencies->getExportedNode() !== null) { - $exportedNodes[] = $dependencies->getExportedNode(); - } - } catch (AnalysedCodeException $e) { - // pass - } catch (IdentifierNotFound $e) { - // pass - } catch (UnableToCompileNode $e) { - // pass - } - }; - - $scope = $this->scopeFactory->create(ScopeContext::create($file)); - $nodeCallback(new FileNode($parserNodes), $scope); - $this->nodeScopeResolver->processNodes($parserNodes, $scope, $nodeCallback); - foreach ($temporaryFileErrors as $tmpFileError) { - $line = $tmpFileError->getLine(); - if ( - $line !== null - && $tmpFileError->canBeIgnored() - && array_key_exists($tmpFileError->getFile(), $linesToIgnore) - && array_key_exists($line, $linesToIgnore[$tmpFileError->getFile()]) - ) { - $identifiers = $linesToIgnore[$tmpFileError->getFile()][$line]; - if ($identifiers === null) { - $locallyIgnoredErrors[] = $tmpFileError; - unset($unmatchedLineIgnores[$tmpFileError->getFile()][$line]); - continue; - } - - if ($tmpFileError->getIdentifier() === null) { - $fileErrors[] = $tmpFileError; - continue; - } - - foreach ($identifiers as $i => $ignoredIdentifier) { - if ($ignoredIdentifier !== $tmpFileError->getIdentifier()) { - continue; - } - - unset($identifiers[$i]); - $linesToIgnore[$tmpFileError->getFile()][$line] = array_values($identifiers); - - if ( - array_key_exists($tmpFileError->getFile(), $unmatchedLineIgnores) - && array_key_exists($line, $unmatchedLineIgnores[$tmpFileError->getFile()]) - ) { - $unmatchedIgnoredIdentifiers = $unmatchedLineIgnores[$tmpFileError->getFile()][$line]; - if (is_array($unmatchedIgnoredIdentifiers)) { - foreach ($unmatchedIgnoredIdentifiers as $j => $unmatchedIgnoredIdentifier) { - if ($ignoredIdentifier !== $unmatchedIgnoredIdentifier) { - continue; - } - - unset($unmatchedIgnoredIdentifiers[$j]); - $unmatchedLineIgnores[$tmpFileError->getFile()][$line] = array_values($unmatchedIgnoredIdentifiers); - break; - } - } - } - - $locallyIgnoredErrors[] = $tmpFileError; - continue 2; - } - } - - $fileErrors[] = $tmpFileError; - } - - if ($this->reportUnmatchedIgnoredErrors) { - foreach ($unmatchedLineIgnores as $ignoredFile => $lines) { - if ($ignoredFile !== $file) { - continue; - } - - foreach ($lines as $line => $identifiers) { - if ($identifiers === null) { - $fileErrors[] = (new Error(sprintf('No error to ignore is reported on line %d.', $line), $scope->getFileDescription(), $line, false, $scope->getFile()))->withIdentifier('ignore.unmatchedLine'); - continue; - } - - foreach ($identifiers as $identifier) { - $fileErrors[] = (new Error(sprintf('No error with identifier %s is reported on line %d.', $identifier, $line), $scope->getFileDescription(), $line, false, $scope->getFile()))->withIdentifier('ignore.unmatchedIdentifier'); - } - } - } - } - } catch (\PhpParser\Error $e) { - $fileErrors[] = (new Error($e->getMessage(), $file, $e->getStartLine() !== -1 ? $e->getStartLine() : null, $e))->withIdentifier('phpstan.parse'); - } catch (ParserErrorsException $e) { - foreach ($e->getErrors() as $error) { - $fileErrors[] = (new Error($error->getMessage(), $e->getParsedFile() ?? $file, $error->getLine() !== -1 ? $error->getStartLine() : null, $e))->withIdentifier('phpstan.parse'); - } - } catch (AnalysedCodeException $e) { - $fileErrors[] = (new Error($e->getMessage(), $file, null, $e, null, null, $e->getTip()))->withIdentifier('phpstan.internal'); - } catch (IdentifierNotFound $e) { - $fileErrors[] = (new Error(sprintf('Reflection error: %s not found.', $e->getIdentifier()->getName()), $file, null, $e, null, null, 'Learn more at https://phpstan.org/user-guide/discovering-symbols'))->withIdentifier('phpstan.reflection'); - } catch (UnableToCompileNode | CircularReference $e) { - $fileErrors[] = (new Error(sprintf('Reflection error: %s', $e->getMessage()), $file, null, $e))->withIdentifier('phpstan.reflection'); - } - } elseif (is_dir($file)) { - $fileErrors[] = (new Error(sprintf('File %s is a directory.', $file), $file, null, false))->withIdentifier('phpstan.path'); - } else { - $fileErrors[] = (new Error(sprintf('File %s does not exist.', $file), $file, null, false))->withIdentifier('phpstan.path'); - } - $this->restoreCollectErrorsHandler(); - $fileErrors = array_merge($fileErrors, $this->collectedErrors); - return new FileAnalyserResult($fileErrors, $locallyIgnoredErrors, $fileCollectedData, array_values(array_unique($fileDependencies)), $exportedNodes); + * @param array $analysedFiles + * @param callable(Node $node, Scope $scope): void|null $outerNodeCallback + */ + public function analyseFile( + string $file, + array $analysedFiles, + RuleRegistry $ruleRegistry, + CollectorRegistry $collectorRegistry, + ?callable $outerNodeCallback, + ): FileAnalyserResult + { + /** @var list $fileErrors */ + $fileErrors = []; + + /** @var list $locallyIgnoredErrors */ + $locallyIgnoredErrors = []; + + /** @var list $fileCollectedData */ + $fileCollectedData = []; + + $fileDependencies = []; + $exportedNodes = []; + if (is_file($file)) { + try { + $this->collectErrors($analysedFiles); + $parserNodes = $this->parser->parseFile($file); + $linesToIgnore = $unmatchedLineIgnores = [$file => $this->getLinesToIgnoreFromTokens($parserNodes)]; + $temporaryFileErrors = []; + $nodeCallback = function (Node $node, Scope $scope) use (&$fileErrors, &$fileCollectedData, &$fileDependencies, &$exportedNodes, $file, $ruleRegistry, $collectorRegistry, $outerNodeCallback, $analysedFiles, &$linesToIgnore, &$unmatchedLineIgnores, &$temporaryFileErrors): void { + if ($node instanceof Node\Stmt\Trait_) { + foreach (array_keys($linesToIgnore[$file] ?? []) as $lineToIgnore) { + if ($lineToIgnore < $node->getStartLine() || $lineToIgnore > $node->getEndLine()) { + continue; + } + + unset($unmatchedLineIgnores[$file][$lineToIgnore]); + } + } + if ($node instanceof InTraitNode) { + $traitNode = $node->getOriginalNode(); + $linesToIgnore[$scope->getFileDescription()] = $this->getLinesToIgnoreFromTokens([$traitNode]); + } + if ($outerNodeCallback !== null) { + $outerNodeCallback($node, $scope); + } + $uniquedAnalysedCodeExceptionMessages = []; + $nodeType = get_class($node); + foreach ($ruleRegistry->getRules($nodeType) as $rule) { + try { + $ruleErrors = $rule->processNode($node, $scope); + } catch (AnalysedCodeException $e) { + if (isset($uniquedAnalysedCodeExceptionMessages[$e->getMessage()])) { + continue; + } + + $uniquedAnalysedCodeExceptionMessages[$e->getMessage()] = true; + $fileErrors[] = (new Error($e->getMessage(), $file, $node->getStartLine(), $e, null, null, $e->getTip()))->withIdentifier('phpstan.internal'); + continue; + } catch (IdentifierNotFound $e) { + $fileErrors[] = (new Error(sprintf('Reflection error: %s not found.', $e->getIdentifier()->getName()), $file, $node->getStartLine(), $e, null, null, 'Learn more at https://phpstan.org/user-guide/discovering-symbols'))->withIdentifier('phpstan.reflection'); + continue; + } catch (UnableToCompileNode | CircularReference $e) { + $fileErrors[] = (new Error(sprintf('Reflection error: %s', $e->getMessage()), $file, $node->getStartLine(), $e))->withIdentifier('phpstan.reflection'); + continue; + } + + foreach ($ruleErrors as $ruleError) { + $temporaryFileErrors[] = $this->ruleErrorTransformer->transform($ruleError, $scope, $nodeType, $node->getStartLine()); + } + } + + foreach ($collectorRegistry->getCollectors($nodeType) as $collector) { + try { + $collectedData = $collector->processNode($node, $scope); + } catch (AnalysedCodeException $e) { + if (isset($uniquedAnalysedCodeExceptionMessages[$e->getMessage()])) { + continue; + } + + $uniquedAnalysedCodeExceptionMessages[$e->getMessage()] = true; + $fileErrors[] = (new Error($e->getMessage(), $file, $node->getStartLine(), $e, null, null, $e->getTip()))->withIdentifier('phpstan.internal'); + continue; + } catch (IdentifierNotFound $e) { + $fileErrors[] = (new Error(sprintf('Reflection error: %s not found.', $e->getIdentifier()->getName()), $file, $node->getStartLine(), $e, null, null, 'Learn more at https://phpstan.org/user-guide/discovering-symbols'))->withIdentifier('phpstan.reflection'); + continue; + } catch (UnableToCompileNode | CircularReference $e) { + $fileErrors[] = (new Error(sprintf('Reflection error: %s', $e->getMessage()), $file, $node->getStartLine(), $e))->withIdentifier('phpstan.reflection'); + continue; + } + + if ($collectedData === null) { + continue; + } + + $fileCollectedData[] = new CollectedData( + $collectedData, + $scope->getFile(), + get_class($collector), + ); + } + + try { + $dependencies = $this->dependencyResolver->resolveDependencies($node, $scope); + foreach ($dependencies->getFileDependencies($scope->getFile(), $analysedFiles) as $dependentFile) { + $fileDependencies[] = $dependentFile; + } + if ($dependencies->getExportedNode() !== null) { + $exportedNodes[] = $dependencies->getExportedNode(); + } + } catch (AnalysedCodeException) { + // pass + } catch (IdentifierNotFound) { + // pass + } catch (UnableToCompileNode) { + // pass + } + }; + + $scope = $this->scopeFactory->create(ScopeContext::create($file)); + $nodeCallback(new FileNode($parserNodes), $scope); + $this->nodeScopeResolver->processNodes( + $parserNodes, + $scope, + $nodeCallback, + ); + foreach ($temporaryFileErrors as $tmpFileError) { + $line = $tmpFileError->getLine(); + if ( + $line !== null + && $tmpFileError->canBeIgnored() + && array_key_exists($tmpFileError->getFile(), $linesToIgnore) + && array_key_exists($line, $linesToIgnore[$tmpFileError->getFile()]) + ) { + $identifiers = $linesToIgnore[$tmpFileError->getFile()][$line]; + if ($identifiers === null) { + $locallyIgnoredErrors[] = $tmpFileError; + unset($unmatchedLineIgnores[$tmpFileError->getFile()][$line]); + continue; + } + + if ($tmpFileError->getIdentifier() === null) { + $fileErrors[] = $tmpFileError; + continue; + } + + foreach ($identifiers as $i => $ignoredIdentifier) { + if ($ignoredIdentifier !== $tmpFileError->getIdentifier()) { + continue; + } + + unset($identifiers[$i]); + $linesToIgnore[$tmpFileError->getFile()][$line] = array_values($identifiers); + + if ( + array_key_exists($tmpFileError->getFile(), $unmatchedLineIgnores) + && array_key_exists($line, $unmatchedLineIgnores[$tmpFileError->getFile()]) + ) { + $unmatchedIgnoredIdentifiers = $unmatchedLineIgnores[$tmpFileError->getFile()][$line]; + if (is_array($unmatchedIgnoredIdentifiers)) { + foreach ($unmatchedIgnoredIdentifiers as $j => $unmatchedIgnoredIdentifier) { + if ($ignoredIdentifier !== $unmatchedIgnoredIdentifier) { + continue; + } + + unset($unmatchedIgnoredIdentifiers[$j]); + $unmatchedLineIgnores[$tmpFileError->getFile()][$line] = array_values($unmatchedIgnoredIdentifiers); + break; + } + } + } + + $locallyIgnoredErrors[] = $tmpFileError; + continue 2; + } + } + + $fileErrors[] = $tmpFileError; + } + + if ($this->reportUnmatchedIgnoredErrors) { + foreach ($unmatchedLineIgnores as $ignoredFile => $lines) { + if ($ignoredFile !== $file) { + continue; + } + + foreach ($lines as $line => $identifiers) { + if ($identifiers === null) { + $fileErrors[] = (new Error( + sprintf('No error to ignore is reported on line %d.', $line), + $scope->getFileDescription(), + $line, + false, + $scope->getFile(), + ))->withIdentifier('ignore.unmatchedLine'); + continue; + } + + foreach ($identifiers as $identifier) { + $fileErrors[] = (new Error( + sprintf('No error with identifier %s is reported on line %d.', $identifier, $line), + $scope->getFileDescription(), + $line, + false, + $scope->getFile(), + ))->withIdentifier('ignore.unmatchedIdentifier'); + } + } + } + } + } catch (\PhpParser\Error $e) { + $fileErrors[] = (new Error($e->getMessage(), $file, $e->getStartLine() !== -1 ? $e->getStartLine() : null, $e))->withIdentifier('phpstan.parse'); + } catch (ParserErrorsException $e) { + foreach ($e->getErrors() as $error) { + $fileErrors[] = (new Error($error->getMessage(), $e->getParsedFile() ?? $file, $error->getLine() !== -1 ? $error->getStartLine() : null, $e))->withIdentifier('phpstan.parse'); + } + } catch (AnalysedCodeException $e) { + $fileErrors[] = (new Error($e->getMessage(), $file, null, $e, null, null, $e->getTip()))->withIdentifier('phpstan.internal'); + } catch (IdentifierNotFound $e) { + $fileErrors[] = (new Error(sprintf('Reflection error: %s not found.', $e->getIdentifier()->getName()), $file, null, $e, null, null, 'Learn more at https://phpstan.org/user-guide/discovering-symbols'))->withIdentifier('phpstan.reflection'); + } catch (UnableToCompileNode | CircularReference $e) { + $fileErrors[] = (new Error(sprintf('Reflection error: %s', $e->getMessage()), $file, null, $e))->withIdentifier('phpstan.reflection'); + } + } elseif (is_dir($file)) { + $fileErrors[] = (new Error(sprintf('File %s is a directory.', $file), $file, null, false))->withIdentifier('phpstan.path'); + } else { + $fileErrors[] = (new Error(sprintf('File %s does not exist.', $file), $file, null, false))->withIdentifier('phpstan.path'); } + $this->restoreCollectErrorsHandler(); + + $fileErrors = array_merge($fileErrors, $this->collectedErrors); + + return new FileAnalyserResult($fileErrors, $locallyIgnoredErrors, $fileCollectedData, array_values(array_unique($fileDependencies)), $exportedNodes); + } + /** - * @param Node[] $nodes - * @return array|null> - */ - private function getLinesToIgnoreFromTokens(array $nodes): array + * @param Node[] $nodes + * @return array|null> + */ + private function getLinesToIgnoreFromTokens(array $nodes): array { if (!isset($nodes[0])) { return []; @@ -289,9 +298,9 @@ private function getLinesToIgnoreFromTokens(array $nodes): array } /** - * @param array $analysedFiles - */ - private function collectErrors(array $analysedFiles): void + * @param array $analysedFiles + */ + private function collectErrors(array $analysedFiles): void { $this->collectedErrors = []; set_error_handler(function (int $errno, string $errstr, string $errfile, int $errline) use ($analysedFiles): bool { diff --git a/src/Analyser/FileAnalyserResult.php b/src/Analyser/FileAnalyserResult.php index c505a80a658..0033368bfa9 100644 --- a/src/Analyser/FileAnalyserResult.php +++ b/src/Analyser/FileAnalyserResult.php @@ -8,26 +8,6 @@ class FileAnalyserResult { - /** - * @var list - */ - private $errors; - /** - * @var list - */ - private $locallyIgnoredErrors; - /** - * @var list - */ - private $collectedData; - /** - * @var list - */ - private $dependencies; - /** - * @var list - */ - private $exportedNodes; /** * @param list $errors * @param list $locallyIgnoredErrors @@ -35,14 +15,16 @@ class FileAnalyserResult * @param list $dependencies * @param list $exportedNodes */ - public function __construct(array $errors, array $locallyIgnoredErrors, array $collectedData, array $dependencies, array $exportedNodes) + public function __construct( + private array $errors, + private array $locallyIgnoredErrors, + private array $collectedData, + private array $dependencies, + private array $exportedNodes, + ) { - $this->errors = $errors; - $this->locallyIgnoredErrors = $locallyIgnoredErrors; - $this->collectedData = $collectedData; - $this->dependencies = $dependencies; - $this->exportedNodes = $exportedNodes; } + /** * @return list */ diff --git a/src/Analyser/Ignore/IgnoreLexer.php b/src/Analyser/Ignore/IgnoreLexer.php index ba9bea259e4..baa0cf7af4c 100644 --- a/src/Analyser/Ignore/IgnoreLexer.php +++ b/src/Analyser/Ignore/IgnoreLexer.php @@ -32,10 +32,7 @@ final class IgnoreLexer public const TYPE_OFFSET = 1; public const LINE_OFFSET = 2; - /** - * @var ?string - */ - private $regexp = null; + private ?string $regexp = null; /** * @return list diff --git a/src/Analyser/Ignore/IgnoreParseException.php b/src/Analyser/Ignore/IgnoreParseException.php index 0c3a99083aa..fc8eec134c0 100644 --- a/src/Analyser/Ignore/IgnoreParseException.php +++ b/src/Analyser/Ignore/IgnoreParseException.php @@ -7,13 +7,8 @@ class IgnoreParseException extends Exception { - /** - * @var int - */ - private $phpDocLine; - public function __construct(string $message, int $phpDocLine) + public function __construct(string $message, private int $phpDocLine) { - $this->phpDocLine = $phpDocLine; parent::__construct($message); } diff --git a/src/Analyser/Ignore/IgnoredError.php b/src/Analyser/Ignore/IgnoredError.php index 44100b61557..00cc1e7df86 100644 --- a/src/Analyser/Ignore/IgnoredError.php +++ b/src/Analyser/Ignore/IgnoredError.php @@ -60,13 +60,20 @@ public static function stringifyPattern($ignoredError): string /** * @return bool To ignore or not to ignore? */ - public static function shouldIgnore(FileHelper $fileHelper, Error $error, ?string $ignoredErrorPattern, ?string $identifier, ?string $path) : bool + public static function shouldIgnore( + FileHelper $fileHelper, + Error $error, + ?string $ignoredErrorPattern, + ?string $identifier, + ?string $path, + ): bool { if ($identifier !== null) { if ($error->getIdentifier() !== $identifier) { return false; } } + if ($ignoredErrorPattern !== null) { // normalize newlines to allow working with ignore-patterns independent of used OS newline-format $errorMessage = $error->getMessage(); @@ -76,6 +83,7 @@ public static function shouldIgnore(FileHelper $fileHelper, Error $error, ?strin return false; } } + if ($path !== null) { $fileExcluder = new FileExcluder($fileHelper, [$path]); $isExcluded = $fileExcluder->isExcludedFromAnalysing($error->getFilePath()); @@ -85,6 +93,7 @@ public static function shouldIgnore(FileHelper $fileHelper, Error $error, ?strin return $isExcluded; } + return true; } diff --git a/src/Analyser/Ignore/IgnoredErrorHelper.php b/src/Analyser/Ignore/IgnoredErrorHelper.php index 53679f53bbf..068114767c5 100644 --- a/src/Analyser/Ignore/IgnoredErrorHelper.php +++ b/src/Analyser/Ignore/IgnoredErrorHelper.php @@ -15,27 +15,17 @@ class IgnoredErrorHelper { - /** - * @var FileHelper - */ - private $fileHelper; - /** - * @var (string|mixed[])[] - */ - private $ignoreErrors; - /** - * @var bool - */ - private $reportUnmatchedIgnoredErrors; /** * @param (string|mixed[])[] $ignoreErrors */ - public function __construct(FileHelper $fileHelper, array $ignoreErrors, bool $reportUnmatchedIgnoredErrors) + public function __construct( + private FileHelper $fileHelper, + private array $ignoreErrors, + private bool $reportUnmatchedIgnoredErrors, + ) { - $this->fileHelper = $fileHelper; - $this->ignoreErrors = $ignoreErrors; - $this->reportUnmatchedIgnoredErrors = $reportUnmatchedIgnoredErrors; } + public function initialize(): IgnoredErrorHelperResult { $otherIgnoreErrors = []; @@ -46,7 +36,10 @@ public function initialize(): IgnoredErrorHelperResult foreach ($this->ignoreErrors as $ignoreError) { if (is_array($ignoreError)) { if (!isset($ignoreError['message']) && !isset($ignoreError['messages']) && !isset($ignoreError['identifier'])) { - $errors[] = sprintf('Ignored error %s is missing a message or an identifier.', Json::encode($ignoreError)); + $errors[] = sprintf( + 'Ignored error %s is missing a message or an identifier.', + Json::encode($ignoreError), + ); continue; } if (isset($ignoreError['messages'])) { @@ -110,7 +103,10 @@ public function initialize(): IgnoredErrorHelperResult try { if (is_array($ignoreError)) { if (!isset($ignoreError['message']) && !isset($ignoreError['identifier'])) { - $errors[] = sprintf('Ignored error %s is missing a message or an identifier.', Json::encode($ignoreError)); + $errors[] = sprintf( + 'Ignored error %s is missing a message or an identifier.', + Json::encode($ignoreError), + ); continue; } if (!isset($ignoreError['path'])) { diff --git a/src/Analyser/Ignore/IgnoredErrorHelperProcessedResult.php b/src/Analyser/Ignore/IgnoredErrorHelperProcessedResult.php index 6b199421102..4ffacf46d47 100644 --- a/src/Analyser/Ignore/IgnoredErrorHelperProcessedResult.php +++ b/src/Analyser/Ignore/IgnoredErrorHelperProcessedResult.php @@ -7,29 +7,19 @@ class IgnoredErrorHelperProcessedResult { - /** - * @var list - */ - private $notIgnoredErrors; - /** - * @var list - */ - private $ignoredErrors; - /** - * @var list - */ - private $otherIgnoreMessages; /** * @param list $notIgnoredErrors * @param list $ignoredErrors * @param list $otherIgnoreMessages */ - public function __construct(array $notIgnoredErrors, array $ignoredErrors, array $otherIgnoreMessages) + public function __construct( + private array $notIgnoredErrors, + private array $ignoredErrors, + private array $otherIgnoreMessages, + ) { - $this->notIgnoredErrors = $notIgnoredErrors; - $this->ignoredErrors = $ignoredErrors; - $this->otherIgnoreMessages = $otherIgnoreMessages; } + /** * @return list */ diff --git a/src/Analyser/Ignore/IgnoredErrorHelperResult.php b/src/Analyser/Ignore/IgnoredErrorHelperResult.php index 773f0ba2455..95d4273ef86 100644 --- a/src/Analyser/Ignore/IgnoredErrorHelperResult.php +++ b/src/Analyser/Ignore/IgnoredErrorHelperResult.php @@ -16,45 +16,23 @@ class IgnoredErrorHelperResult { - /** - * @var FileHelper - */ - private $fileHelper; - /** - * @var list - */ - private $errors; - /** - * @var array> - */ - private $otherIgnoreErrors; - /** - * @var array>> - */ - private $ignoreErrorsByFile; - /** - * @var (string|mixed[])[] - */ - private $ignoreErrors; - /** - * @var bool - */ - private $reportUnmatchedIgnoredErrors; /** * @param list $errors * @param array> $otherIgnoreErrors * @param array>> $ignoreErrorsByFile * @param (string|mixed[])[] $ignoreErrors */ - public function __construct(FileHelper $fileHelper, array $errors, array $otherIgnoreErrors, array $ignoreErrorsByFile, array $ignoreErrors, bool $reportUnmatchedIgnoredErrors) + public function __construct( + private FileHelper $fileHelper, + private array $errors, + private array $otherIgnoreErrors, + private array $ignoreErrorsByFile, + private array $ignoreErrors, + private bool $reportUnmatchedIgnoredErrors, + ) { - $this->fileHelper = $fileHelper; - $this->errors = $errors; - $this->otherIgnoreErrors = $otherIgnoreErrors; - $this->ignoreErrorsByFile = $ignoreErrorsByFile; - $this->ignoreErrors = $ignoreErrors; - $this->reportUnmatchedIgnoredErrors = $reportUnmatchedIgnoredErrors; } + /** * @return list */ @@ -67,10 +45,16 @@ public function getErrors(): array * @param Error[] $errors * @param string[] $analysedFiles */ - public function process(array $errors, bool $onlyFiles, array $analysedFiles, bool $hasInternalErrors) : IgnoredErrorHelperProcessedResult + public function process( + array $errors, + bool $onlyFiles, + array $analysedFiles, + bool $hasInternalErrors, + ): IgnoredErrorHelperProcessedResult { $unmatchedIgnoredErrors = $this->ignoreErrors; $stringErrors = []; + $processIgnoreError = function (Error $error, int $i, $ignore) use (&$unmatchedIgnoredErrors, &$stringErrors): bool { $shouldBeIgnored = false; if (is_string($ignore)) { @@ -127,7 +111,10 @@ public function process(array $errors, bool $onlyFiles, array $analysedFiles, bo if ($shouldBeIgnored) { if (!$error->canBeIgnored()) { - $stringErrors[] = sprintf('Error message "%s" cannot be ignored, use excludePaths instead.', $error->getMessage()); + $stringErrors[] = sprintf( + 'Error message "%s" cannot be ignored, use excludePaths instead.', + $error->getMessage(), + ); return true; } return false; @@ -135,6 +122,7 @@ public function process(array $errors, bool $onlyFiles, array $analysedFiles, bo return true; }; + $ignoredErrors = []; foreach ($errors as $errorIndex => $error) { $filePath = $this->fileHelper->normalizePath($error->getFilePath()); @@ -180,7 +168,9 @@ public function process(array $errors, bool $onlyFiles, array $analysedFiles, bo } } } + $errors = array_values($errors); + foreach ($unmatchedIgnoredErrors as $unmatchedIgnoredError) { if (!isset($unmatchedIgnoredError['count']) || !isset($unmatchedIgnoredError['realCount'])) { continue; @@ -190,9 +180,18 @@ public function process(array $errors, bool $onlyFiles, array $analysedFiles, bo continue; } - $errors[] = (new Error(sprintf('Ignored error pattern %s is expected to occur %d %s, but occurred %d %s.', IgnoredError::stringifyPattern($unmatchedIgnoredError), $unmatchedIgnoredError['count'], $unmatchedIgnoredError['count'] === 1 ? 'time' : 'times', $unmatchedIgnoredError['realCount'], $unmatchedIgnoredError['realCount'] === 1 ? 'time' : 'times'), $unmatchedIgnoredError['file'], $unmatchedIgnoredError['line'], false))->withIdentifier('ignore.count'); + $errors[] = (new Error(sprintf( + 'Ignored error pattern %s is expected to occur %d %s, but occurred %d %s.', + IgnoredError::stringifyPattern($unmatchedIgnoredError), + $unmatchedIgnoredError['count'], + $unmatchedIgnoredError['count'] === 1 ? 'time' : 'times', + $unmatchedIgnoredError['realCount'], + $unmatchedIgnoredError['realCount'] === 1 ? 'time' : 'times', + ), $unmatchedIgnoredError['file'], $unmatchedIgnoredError['line'], false))->withIdentifier('ignore.count'); } + $analysedFilesKeys = array_fill_keys($analysedFiles, true); + if (!$hasInternalErrors) { foreach ($unmatchedIgnoredErrors as $unmatchedIgnoredError) { $reportUnmatched = $unmatchedIgnoredError['reportUnmatched'] ?? $this->reportUnmatchedIgnoredErrors; @@ -205,19 +204,38 @@ public function process(array $errors, bool $onlyFiles, array $analysedFiles, bo && (isset($unmatchedIgnoredError['realPath']) || !$onlyFiles) ) { if ($unmatchedIgnoredError['realCount'] < $unmatchedIgnoredError['count']) { - $errors[] = (new Error(sprintf('Ignored error pattern %s is expected to occur %d %s, but occurred only %d %s.', IgnoredError::stringifyPattern($unmatchedIgnoredError), $unmatchedIgnoredError['count'], $unmatchedIgnoredError['count'] === 1 ? 'time' : 'times', $unmatchedIgnoredError['realCount'], $unmatchedIgnoredError['realCount'] === 1 ? 'time' : 'times'), $unmatchedIgnoredError['file'], $unmatchedIgnoredError['line'], false))->withIdentifier('ignore.count'); + $errors[] = (new Error(sprintf( + 'Ignored error pattern %s is expected to occur %d %s, but occurred only %d %s.', + IgnoredError::stringifyPattern($unmatchedIgnoredError), + $unmatchedIgnoredError['count'], + $unmatchedIgnoredError['count'] === 1 ? 'time' : 'times', + $unmatchedIgnoredError['realCount'], + $unmatchedIgnoredError['realCount'] === 1 ? 'time' : 'times', + ), $unmatchedIgnoredError['file'], $unmatchedIgnoredError['line'], false))->withIdentifier('ignore.count'); } } elseif (isset($unmatchedIgnoredError['realPath'])) { if (!array_key_exists($unmatchedIgnoredError['realPath'], $analysedFilesKeys)) { continue; } - $errors[] = (new Error(sprintf('Ignored error pattern %s was not matched in reported errors.', IgnoredError::stringifyPattern($unmatchedIgnoredError)), $unmatchedIgnoredError['realPath'], null, false))->withIdentifier('ignore.unmatched'); + $errors[] = (new Error( + sprintf( + 'Ignored error pattern %s was not matched in reported errors.', + IgnoredError::stringifyPattern($unmatchedIgnoredError), + ), + $unmatchedIgnoredError['realPath'], + null, + false, + ))->withIdentifier('ignore.unmatched'); } elseif (!$onlyFiles) { - $stringErrors[] = sprintf('Ignored error pattern %s was not matched in reported errors.', IgnoredError::stringifyPattern($unmatchedIgnoredError)); + $stringErrors[] = sprintf( + 'Ignored error pattern %s was not matched in reported errors.', + IgnoredError::stringifyPattern($unmatchedIgnoredError), + ); } } } + return new IgnoredErrorHelperProcessedResult($errors, $ignoredErrors, $stringErrors); } diff --git a/src/Analyser/InternalScopeFactory.php b/src/Analyser/InternalScopeFactory.php index 9a99b0a5ecf..7d3414f2979 100644 --- a/src/Analyser/InternalScopeFactory.php +++ b/src/Analyser/InternalScopeFactory.php @@ -18,8 +18,24 @@ interface InternalScopeFactory * @param array $currentlyAssignedExpressions * @param array $currentlyAllowedUndefinedExpressions * @param list $inFunctionCallsStack - * @param FunctionReflection|MethodReflection|null $function */ - public function create(ScopeContext $context, bool $declareStrictTypes = false, $function = null, ?string $namespace = null, array $expressionTypes = [], array $nativeExpressionTypes = [], array $conditionalExpressions = [], array $inClosureBindScopeClasses = [], ?ParametersAcceptor $anonymousFunctionReflection = null, bool $inFirstLevelStatement = true, array $currentlyAssignedExpressions = [], array $currentlyAllowedUndefinedExpressions = [], array $inFunctionCallsStack = [], bool $afterExtractCall = false, ?Scope $parentScope = null, bool $nativeTypesPromoted = false) : MutatingScope; + public function create( + ScopeContext $context, + bool $declareStrictTypes = false, + FunctionReflection|MethodReflection|null $function = null, + ?string $namespace = null, + array $expressionTypes = [], + array $nativeExpressionTypes = [], + array $conditionalExpressions = [], + array $inClosureBindScopeClasses = [], + ?ParametersAcceptor $anonymousFunctionReflection = null, + bool $inFirstLevelStatement = true, + array $currentlyAssignedExpressions = [], + array $currentlyAllowedUndefinedExpressions = [], + array $inFunctionCallsStack = [], + bool $afterExtractCall = false, + ?Scope $parentScope = null, + bool $nativeTypesPromoted = false, + ): MutatingScope; } diff --git a/src/Analyser/LazyInternalScopeFactory.php b/src/Analyser/LazyInternalScopeFactory.php index 1b9fb21b7fd..0d74666e85b 100644 --- a/src/Analyser/LazyInternalScopeFactory.php +++ b/src/Analyser/LazyInternalScopeFactory.php @@ -20,51 +20,86 @@ class LazyInternalScopeFactory implements InternalScopeFactory { - /** - * @var class-string - */ - private $scopeClass; - /** - * @var Container - */ - private $container; - /** - * @var bool - */ - private $explicitMixedInUnknownGenericNew; + private bool $explicitMixedInUnknownGenericNew; - /** - * @var bool - */ - private $explicitMixedForGlobalVariables; + private bool $explicitMixedForGlobalVariables; /** - * @param class-string $scopeClass - */ - public function __construct(string $scopeClass, Container $container) - { - $this->scopeClass = $scopeClass; - $this->container = $container; - $this->explicitMixedInUnknownGenericNew = $this->container->getParameter('featureToggles')['explicitMixedInUnknownGenericNew']; - $this->explicitMixedForGlobalVariables = $this->container->getParameter('featureToggles')['explicitMixedForGlobalVariables']; - } + * @param class-string $scopeClass + */ + public function __construct( + private string $scopeClass, + private Container $container, + ) + { + $this->explicitMixedInUnknownGenericNew = $this->container->getParameter('featureToggles')['explicitMixedInUnknownGenericNew']; + $this->explicitMixedForGlobalVariables = $this->container->getParameter('featureToggles')['explicitMixedForGlobalVariables']; + } /** - * @param array $expressionTypes - * @param array $nativeExpressionTypes - * @param array $conditionalExpressions - * @param array $currentlyAssignedExpressions - * @param array $currentlyAllowedUndefinedExpressions - * @param list $inFunctionCallsStack - * @param FunctionReflection|MethodReflection|null $function - */ - public function create(ScopeContext $context, bool $declareStrictTypes = false, $function = null, ?string $namespace = null, array $expressionTypes = [], array $nativeExpressionTypes = [], array $conditionalExpressions = [], array $inClosureBindScopeClasses = [], ?ParametersAcceptor $anonymousFunctionReflection = null, bool $inFirstLevelStatement = true, array $currentlyAssignedExpressions = [], array $currentlyAllowedUndefinedExpressions = [], array $inFunctionCallsStack = [], bool $afterExtractCall = false, ?Scope $parentScope = null, bool $nativeTypesPromoted = false) : MutatingScope - { - $scopeClass = $this->scopeClass; - if (!is_a($scopeClass, MutatingScope::class, true)) { - throw new ShouldNotHappenException(); - } - return new $scopeClass($this, $this->container->getByType(ReflectionProvider::class), $this->container->getByType(InitializerExprTypeResolver::class), $this->container->getByType(DynamicReturnTypeExtensionRegistryProvider::class)->getRegistry(), $this->container->getByType(ExpressionTypeResolverExtensionRegistryProvider::class)->getRegistry(), $this->container->getByType(ExprPrinter::class), $this->container->getByType(TypeSpecifier::class), $this->container->getByType(PropertyReflectionFinder::class), $this->container->getService('currentPhpVersionSimpleParser'), $this->container->getByType(NodeScopeResolver::class), $this->container->getByType(ConstantResolver::class), $context, $this->container->getByType(PhpVersion::class), $declareStrictTypes, $function, $namespace, $expressionTypes, $nativeExpressionTypes, $conditionalExpressions, $inClosureBindScopeClasses, $anonymousFunctionReflection, $inFirstLevelStatement, $currentlyAssignedExpressions, $currentlyAllowedUndefinedExpressions, $inFunctionCallsStack, $afterExtractCall, $parentScope, $nativeTypesPromoted, $this->explicitMixedInUnknownGenericNew, $this->explicitMixedForGlobalVariables); + * @param array $expressionTypes + * @param array $nativeExpressionTypes + * @param array $conditionalExpressions + * @param array $currentlyAssignedExpressions + * @param array $currentlyAllowedUndefinedExpressions + * @param list $inFunctionCallsStack + */ + public function create( + ScopeContext $context, + bool $declareStrictTypes = false, + FunctionReflection|MethodReflection|null $function = null, + ?string $namespace = null, + array $expressionTypes = [], + array $nativeExpressionTypes = [], + array $conditionalExpressions = [], + array $inClosureBindScopeClasses = [], + ?ParametersAcceptor $anonymousFunctionReflection = null, + bool $inFirstLevelStatement = true, + array $currentlyAssignedExpressions = [], + array $currentlyAllowedUndefinedExpressions = [], + array $inFunctionCallsStack = [], + bool $afterExtractCall = false, + ?Scope $parentScope = null, + bool $nativeTypesPromoted = false, + ): MutatingScope + { + $scopeClass = $this->scopeClass; + if (!is_a($scopeClass, MutatingScope::class, true)) { + throw new ShouldNotHappenException(); } + return new $scopeClass( + $this, + $this->container->getByType(ReflectionProvider::class), + $this->container->getByType(InitializerExprTypeResolver::class), + $this->container->getByType(DynamicReturnTypeExtensionRegistryProvider::class)->getRegistry(), + $this->container->getByType(ExpressionTypeResolverExtensionRegistryProvider::class)->getRegistry(), + $this->container->getByType(ExprPrinter::class), + $this->container->getByType(TypeSpecifier::class), + $this->container->getByType(PropertyReflectionFinder::class), + $this->container->getService('currentPhpVersionSimpleParser'), + $this->container->getByType(NodeScopeResolver::class), + $this->container->getByType(ConstantResolver::class), + $context, + $this->container->getByType(PhpVersion::class), + $declareStrictTypes, + $function, + $namespace, + $expressionTypes, + $nativeExpressionTypes, + $conditionalExpressions, + $inClosureBindScopeClasses, + $anonymousFunctionReflection, + $inFirstLevelStatement, + $currentlyAssignedExpressions, + $currentlyAllowedUndefinedExpressions, + $inFunctionCallsStack, + $afterExtractCall, + $parentScope, + $nativeTypesPromoted, + $this->explicitMixedInUnknownGenericNew, + $this->explicitMixedForGlobalVariables, + ); + } + } diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index 7d8985af0c5..63a70d42671 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -149,205 +149,82 @@ class MutatingScope implements Scope { - /** - * @var InternalScopeFactory - */ - private $scopeFactory; - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - /** - * @var InitializerExprTypeResolver - */ - private $initializerExprTypeResolver; - /** - * @var DynamicReturnTypeExtensionRegistry - */ - private $dynamicReturnTypeExtensionRegistry; - /** - * @var ExpressionTypeResolverExtensionRegistry - */ - private $expressionTypeResolverExtensionRegistry; - /** - * @var ExprPrinter - */ - private $exprPrinter; - /** - * @var TypeSpecifier - */ - private $typeSpecifier; - /** - * @var PropertyReflectionFinder - */ - private $propertyReflectionFinder; - /** - * @var Parser - */ - private $parser; - /** - * @var NodeScopeResolver - */ - private $nodeScopeResolver; - /** - * @var ConstantResolver - */ - private $constantResolver; - /** - * @var ScopeContext - */ - private $context; - /** - * @var PhpVersion - */ - private $phpVersion; - /** - * @var bool - */ - private $declareStrictTypes; - /** - * @var FunctionReflection|ExtendedMethodReflection|null - */ - private $function; - /** - * @var array - */ - private $expressionTypes; - /** - * @var array - */ - private $nativeExpressionTypes; - /** - * @var array - */ - private $conditionalExpressions; - /** - * @var list - */ - private $inClosureBindScopeClasses; - /** - * @var ?ParametersAcceptor - */ - private $anonymousFunctionReflection; - /** - * @var bool - */ - private $inFirstLevelStatement; - /** - * @var array - */ - private $currentlyAssignedExpressions; - /** - * @var array - */ - private $currentlyAllowedUndefinedExpressions; - /** - * @var list - */ - private $inFunctionCallsStack; - /** - * @var bool - */ - private $afterExtractCall; - /** - * @var ?Scope - */ - private $parentScope; - /** - * @var bool - */ - private $nativeTypesPromoted; - /** - * @var bool - */ - private $explicitMixedInUnknownGenericNew; - /** - * @var bool - */ - private $explicitMixedForGlobalVariables; - private const BOOLEAN_EXPRESSION_MAX_PROCESS_DEPTH = 4; + private const BOOLEAN_EXPRESSION_MAX_PROCESS_DEPTH = 4; private const KEEP_VOID_ATTRIBUTE_NAME = 'keepVoid'; /** @var Type[] */ - private $resolvedTypes = []; + private array $resolvedTypes = []; /** @var array */ - private $truthyScopes = []; + private array $truthyScopes = []; /** @var array */ - private $falseyScopes = []; + private array $falseyScopes = []; - /** - * @var ?string - */ - private $namespace; + private ?string $namespace; - /** - * @var ?self - */ - private $scopeOutOfFirstLevelStatement = null; + private ?self $scopeOutOfFirstLevelStatement = null; - /** - * @var ?self - */ - private $scopeWithPromotedNativeTypes = null; + private ?self $scopeWithPromotedNativeTypes = null; /** - * @param array $expressionTypes - * @param array $conditionalExpressions - * @param list $inClosureBindScopeClasses - * @param array $currentlyAssignedExpressions - * @param array $currentlyAllowedUndefinedExpressions - * @param array $nativeExpressionTypes - * @param list $inFunctionCallsStack - * @param FunctionReflection|ExtendedMethodReflection|null $function - */ - public function __construct(InternalScopeFactory $scopeFactory, ReflectionProvider $reflectionProvider, InitializerExprTypeResolver $initializerExprTypeResolver, DynamicReturnTypeExtensionRegistry $dynamicReturnTypeExtensionRegistry, ExpressionTypeResolverExtensionRegistry $expressionTypeResolverExtensionRegistry, ExprPrinter $exprPrinter, TypeSpecifier $typeSpecifier, PropertyReflectionFinder $propertyReflectionFinder, Parser $parser, NodeScopeResolver $nodeScopeResolver, ConstantResolver $constantResolver, ScopeContext $context, PhpVersion $phpVersion, bool $declareStrictTypes = false, $function = null, ?string $namespace = null, array $expressionTypes = [], array $nativeExpressionTypes = [], array $conditionalExpressions = [], array $inClosureBindScopeClasses = [], ?ParametersAcceptor $anonymousFunctionReflection = null, bool $inFirstLevelStatement = true, array $currentlyAssignedExpressions = [], array $currentlyAllowedUndefinedExpressions = [], array $inFunctionCallsStack = [], bool $afterExtractCall = false, ?Scope $parentScope = null, bool $nativeTypesPromoted = false, bool $explicitMixedInUnknownGenericNew = false, bool $explicitMixedForGlobalVariables = false) - { - $this->scopeFactory = $scopeFactory; - $this->reflectionProvider = $reflectionProvider; - $this->initializerExprTypeResolver = $initializerExprTypeResolver; - $this->dynamicReturnTypeExtensionRegistry = $dynamicReturnTypeExtensionRegistry; - $this->expressionTypeResolverExtensionRegistry = $expressionTypeResolverExtensionRegistry; - $this->exprPrinter = $exprPrinter; - $this->typeSpecifier = $typeSpecifier; - $this->propertyReflectionFinder = $propertyReflectionFinder; - $this->parser = $parser; - $this->nodeScopeResolver = $nodeScopeResolver; - $this->constantResolver = $constantResolver; - $this->context = $context; - $this->phpVersion = $phpVersion; - $this->declareStrictTypes = $declareStrictTypes; - $this->function = $function; - $this->expressionTypes = $expressionTypes; - $this->nativeExpressionTypes = $nativeExpressionTypes; - $this->conditionalExpressions = $conditionalExpressions; - $this->inClosureBindScopeClasses = $inClosureBindScopeClasses; - $this->anonymousFunctionReflection = $anonymousFunctionReflection; - $this->inFirstLevelStatement = $inFirstLevelStatement; - $this->currentlyAssignedExpressions = $currentlyAssignedExpressions; - $this->currentlyAllowedUndefinedExpressions = $currentlyAllowedUndefinedExpressions; - $this->inFunctionCallsStack = $inFunctionCallsStack; - $this->afterExtractCall = $afterExtractCall; - $this->parentScope = $parentScope; - $this->nativeTypesPromoted = $nativeTypesPromoted; - $this->explicitMixedInUnknownGenericNew = $explicitMixedInUnknownGenericNew; - $this->explicitMixedForGlobalVariables = $explicitMixedForGlobalVariables; - if ($namespace === '') { - $namespace = null; - } - $this->namespace = $namespace; - } + * @param array $expressionTypes + * @param array $conditionalExpressions + * @param list $inClosureBindScopeClasses + * @param array $currentlyAssignedExpressions + * @param array $currentlyAllowedUndefinedExpressions + * @param array $nativeExpressionTypes + * @param list $inFunctionCallsStack + */ + public function __construct( + private InternalScopeFactory $scopeFactory, + private ReflectionProvider $reflectionProvider, + private InitializerExprTypeResolver $initializerExprTypeResolver, + private DynamicReturnTypeExtensionRegistry $dynamicReturnTypeExtensionRegistry, + private ExpressionTypeResolverExtensionRegistry $expressionTypeResolverExtensionRegistry, + private ExprPrinter $exprPrinter, + private TypeSpecifier $typeSpecifier, + private PropertyReflectionFinder $propertyReflectionFinder, + private Parser $parser, + private NodeScopeResolver $nodeScopeResolver, + private ConstantResolver $constantResolver, + private ScopeContext $context, + private PhpVersion $phpVersion, + private bool $declareStrictTypes = false, + private FunctionReflection|ExtendedMethodReflection|null $function = null, + ?string $namespace = null, + private array $expressionTypes = [], + private array $nativeExpressionTypes = [], + private array $conditionalExpressions = [], + private array $inClosureBindScopeClasses = [], + private ?ParametersAcceptor $anonymousFunctionReflection = null, + private bool $inFirstLevelStatement = true, + private array $currentlyAssignedExpressions = [], + private array $currentlyAllowedUndefinedExpressions = [], + private array $inFunctionCallsStack = [], + private bool $afterExtractCall = false, + private ?Scope $parentScope = null, + private bool $nativeTypesPromoted = false, + private bool $explicitMixedInUnknownGenericNew = false, + private bool $explicitMixedForGlobalVariables = false, + ) + { + if ($namespace === '') { + $namespace = null; + } + + $this->namespace = $namespace; + } /** @api */ - public function getFile(): string + public function getFile(): string { return $this->context->getFile(); } /** @api */ - public function getFileDescription(): string + public function getFileDescription(): string { if ($this->context->getTraitReflection() === null) { return $this->getFile(); @@ -366,40 +243,51 @@ public function getFileDescription(): string throw new ShouldNotHappenException(); } - return sprintf('%s (in context of %s)', $traitReflection->getFileName(), $className); + return sprintf( + '%s (in context of %s)', + $traitReflection->getFileName(), + $className, + ); } /** @api */ - public function isDeclareStrictTypes(): bool + public function isDeclareStrictTypes(): bool { return $this->declareStrictTypes; } public function enterDeclareStrictTypes(): self { - return $this->scopeFactory->create($this->context, true, null, null, $this->expressionTypes, $this->nativeExpressionTypes); + return $this->scopeFactory->create( + $this->context, + true, + null, + null, + $this->expressionTypes, + $this->nativeExpressionTypes, + ); } /** @api */ - public function isInClass(): bool + public function isInClass(): bool { return $this->context->getClassReflection() !== null; } /** @api */ - public function isInTrait(): bool + public function isInTrait(): bool { return $this->context->getTraitReflection() !== null; } /** @api */ - public function getClassReflection(): ?ClassReflection + public function getClassReflection(): ?ClassReflection { return $this->context->getClassReflection(); } /** @api */ - public function getTraitReflection(): ?ClassReflection + public function getTraitReflection(): ?ClassReflection { return $this->context->getTraitReflection(); } @@ -414,32 +302,49 @@ public function getFunction() } /** @api */ - public function getFunctionName(): ?string + public function getFunctionName(): ?string { return $this->function !== null ? $this->function->getName() : null; } /** @api */ - public function getNamespace(): ?string + public function getNamespace(): ?string { return $this->namespace; } /** @api */ - public function getParentScope(): ?Scope + public function getParentScope(): ?Scope { return $this->parentScope; } /** @api */ - public function canAnyVariableExist(): bool + public function canAnyVariableExist(): bool { return ($this->function === null && !$this->isInAnonymousFunction()) || $this->afterExtractCall; } public function afterExtractCall(): self { - return $this->scopeFactory->create($this->context, $this->isDeclareStrictTypes(), $this->getFunction(), $this->getNamespace(), $this->expressionTypes, $this->nativeExpressionTypes, [], $this->inClosureBindScopeClasses, $this->anonymousFunctionReflection, $this->isInFirstLevelStatement(), $this->currentlyAssignedExpressions, $this->currentlyAllowedUndefinedExpressions, $this->inFunctionCallsStack, true, $this->parentScope, $this->nativeTypesPromoted); + return $this->scopeFactory->create( + $this->context, + $this->isDeclareStrictTypes(), + $this->getFunction(), + $this->getNamespace(), + $this->expressionTypes, + $this->nativeExpressionTypes, + [], + $this->inClosureBindScopeClasses, + $this->anonymousFunctionReflection, + $this->isInFirstLevelStatement(), + $this->currentlyAssignedExpressions, + $this->currentlyAllowedUndefinedExpressions, + $this->inFunctionCallsStack, + true, + $this->parentScope, + $this->nativeTypesPromoted, + ); } public function afterClearstatcacheCall(): self @@ -478,7 +383,24 @@ public function afterClearstatcacheCall(): self continue 2; } } - return $this->scopeFactory->create($this->context, $this->isDeclareStrictTypes(), $this->getFunction(), $this->getNamespace(), $expressionTypes, $this->nativeExpressionTypes, $this->conditionalExpressions, $this->inClosureBindScopeClasses, $this->anonymousFunctionReflection, $this->isInFirstLevelStatement(), $this->currentlyAssignedExpressions, $this->currentlyAllowedUndefinedExpressions, $this->inFunctionCallsStack, $this->afterExtractCall, $this->parentScope, $this->nativeTypesPromoted); + return $this->scopeFactory->create( + $this->context, + $this->isDeclareStrictTypes(), + $this->getFunction(), + $this->getNamespace(), + $expressionTypes, + $this->nativeExpressionTypes, + $this->conditionalExpressions, + $this->inClosureBindScopeClasses, + $this->anonymousFunctionReflection, + $this->isInFirstLevelStatement(), + $this->currentlyAssignedExpressions, + $this->currentlyAllowedUndefinedExpressions, + $this->inFunctionCallsStack, + $this->afterExtractCall, + $this->parentScope, + $this->nativeTypesPromoted, + ); } public function afterOpenSslCall(string $openSslFunctionName): self @@ -543,11 +465,28 @@ public function afterOpenSslCall(string $openSslFunctionName): self unset($expressionTypes['\openssl_error_string()']); } - return $this->scopeFactory->create($this->context, $this->isDeclareStrictTypes(), $this->getFunction(), $this->getNamespace(), $expressionTypes, $this->nativeExpressionTypes, $this->conditionalExpressions, $this->inClosureBindScopeClasses, $this->anonymousFunctionReflection, $this->isInFirstLevelStatement(), $this->currentlyAssignedExpressions, $this->currentlyAllowedUndefinedExpressions, $this->inFunctionCallsStack, $this->afterExtractCall, $this->parentScope, $this->nativeTypesPromoted); + return $this->scopeFactory->create( + $this->context, + $this->isDeclareStrictTypes(), + $this->getFunction(), + $this->getNamespace(), + $expressionTypes, + $this->nativeExpressionTypes, + $this->conditionalExpressions, + $this->inClosureBindScopeClasses, + $this->anonymousFunctionReflection, + $this->isInFirstLevelStatement(), + $this->currentlyAssignedExpressions, + $this->currentlyAllowedUndefinedExpressions, + $this->inFunctionCallsStack, + $this->afterExtractCall, + $this->parentScope, + $this->nativeTypesPromoted, + ); } /** @api */ - public function hasVariableType(string $variableName): TrinaryLogic + public function hasVariableType(string $variableName): TrinaryLogic { if ($this->isGlobalVariable($variableName)) { return TrinaryLogic::createYes(); @@ -566,14 +505,17 @@ public function hasVariableType(string $variableName): TrinaryLogic } /** @api */ - public function getVariableType(string $variableName): Type + public function getVariableType(string $variableName): Type { if ($this->hasVariableType($variableName)->maybe()) { if ($variableName === 'argc') { return IntegerRangeType::fromInterval(1, null); } if ($variableName === 'argv') { - return AccessoryArrayListType::intersectWith(TypeCombinator::intersect(new ArrayType(new IntegerType(), new StringType()), new NonEmptyArrayType())); + return AccessoryArrayListType::intersectWith(TypeCombinator::intersect( + new ArrayType(new IntegerType(), new StringType()), + new NonEmptyArrayType(), + )); } if ($this->canAnyVariableExist()) { return new MixedType(); @@ -597,10 +539,10 @@ public function getVariableType(string $variableName): Type } /** - * @api - * @return array - */ - public function getDefinedVariables(): array + * @api + * @return array + */ + public function getDefinedVariables(): array { $variables = []; foreach ($this->expressionTypes as $exprString => $holder) { @@ -633,7 +575,7 @@ private function isGlobalVariable(string $variableName): bool } /** @api */ - public function hasConstant(Name $name): bool + public function hasConstant(Name $name): bool { $isCompilerHaltOffset = $name->toString() === '__COMPILER_HALT_OFFSET__'; if ($isCompilerHaltOffset) { @@ -665,19 +607,19 @@ private function fileHasCompilerHaltStatementCalls(): bool } /** @api */ - public function isInAnonymousFunction(): bool + public function isInAnonymousFunction(): bool { return $this->anonymousFunctionReflection !== null; } /** @api */ - public function getAnonymousFunctionReflection(): ?ParametersAcceptor + public function getAnonymousFunctionReflection(): ?ParametersAcceptor { return $this->anonymousFunctionReflection; } /** @api */ - public function getAnonymousFunctionReturnType(): ?Type + public function getAnonymousFunctionReturnType(): ?Type { if ($this->anonymousFunctionReflection === null) { return null; @@ -687,7 +629,7 @@ public function getAnonymousFunctionReturnType(): ?Type } /** @api */ - public function getType(Expr $node): Type + public function getType(Expr $node): Type { if ($node instanceof GetIterableKeyTypeExpr) { return $this->getIterableKeyType($this->getType($node->getExpr())); @@ -702,7 +644,10 @@ public function getType(Expr $node): Type return $this->getType($node->getVar())->unsetOffset($this->getType($node->getDim())); } if ($node instanceof SetOffsetValueTypeExpr) { - return $this->getType($node->getVar())->setOffsetValueType($node->getDim() !== null ? $this->getType($node->getDim()) : null, $this->getType($node->getValue())); + return $this->getType($node->getVar())->setOffsetValueType( + $node->getDim() !== null ? $this->getType($node->getDim()) : null, + $this->getType($node->getValue()), + ); } if ($node instanceof TypeExpr) { return $node->getExprType(); @@ -836,9 +781,7 @@ private function resolveType(string $exprString, Expr $node): Type } if ($node instanceof Node\Expr\BitwiseNot) { - return $this->initializerExprTypeResolver->getBitwiseNotType($node->expr, function (Expr $expr) : Type { - return $this->getType($expr); - }); + return $this->initializerExprTypeResolver->getBitwiseNotType($node->expr, fn (Expr $expr): Type => $this->getType($expr)); } if ( @@ -913,7 +856,9 @@ private function resolveType(string $exprString, Expr $node): Type $leftBooleanType instanceof ConstantBooleanType && $rightBooleanType instanceof ConstantBooleanType ) { - return new ConstantBooleanType($leftBooleanType->getValue() xor $rightBooleanType->getValue()); + return new ConstantBooleanType( + $leftBooleanType->getValue() xor $rightBooleanType->getValue(), + ); } return new BooleanType(); @@ -1034,159 +979,107 @@ private function resolveType(string $exprString, Expr $node): Type } if ($node instanceof Node\Expr\UnaryMinus) { - return $this->initializerExprTypeResolver->getUnaryMinusType($node->expr, function (Expr $expr) : Type { - return $this->getType($expr); - }); + return $this->initializerExprTypeResolver->getUnaryMinusType($node->expr, fn (Expr $expr): Type => $this->getType($expr)); } if ($node instanceof Expr\BinaryOp\Concat) { - return $this->initializerExprTypeResolver->getConcatType($node->left, $node->right, function (Expr $expr) : Type { - return $this->getType($expr); - }); + return $this->initializerExprTypeResolver->getConcatType($node->left, $node->right, fn (Expr $expr): Type => $this->getType($expr)); } if ($node instanceof Expr\AssignOp\Concat) { - return $this->initializerExprTypeResolver->getConcatType($node->var, $node->expr, function (Expr $expr) : Type { - return $this->getType($expr); - }); + return $this->initializerExprTypeResolver->getConcatType($node->var, $node->expr, fn (Expr $expr): Type => $this->getType($expr)); } if ($node instanceof BinaryOp\BitwiseAnd) { - return $this->initializerExprTypeResolver->getBitwiseAndType($node->left, $node->right, function (Expr $expr) : Type { - return $this->getType($expr); - }); + return $this->initializerExprTypeResolver->getBitwiseAndType($node->left, $node->right, fn (Expr $expr): Type => $this->getType($expr)); } if ($node instanceof Expr\AssignOp\BitwiseAnd) { - return $this->initializerExprTypeResolver->getBitwiseAndType($node->var, $node->expr, function (Expr $expr) : Type { - return $this->getType($expr); - }); + return $this->initializerExprTypeResolver->getBitwiseAndType($node->var, $node->expr, fn (Expr $expr): Type => $this->getType($expr)); } if ($node instanceof BinaryOp\BitwiseOr) { - return $this->initializerExprTypeResolver->getBitwiseOrType($node->left, $node->right, function (Expr $expr) : Type { - return $this->getType($expr); - }); + return $this->initializerExprTypeResolver->getBitwiseOrType($node->left, $node->right, fn (Expr $expr): Type => $this->getType($expr)); } if ($node instanceof Expr\AssignOp\BitwiseOr) { - return $this->initializerExprTypeResolver->getBitwiseOrType($node->var, $node->expr, function (Expr $expr) : Type { - return $this->getType($expr); - }); + return $this->initializerExprTypeResolver->getBitwiseOrType($node->var, $node->expr, fn (Expr $expr): Type => $this->getType($expr)); } if ($node instanceof BinaryOp\BitwiseXor) { - return $this->initializerExprTypeResolver->getBitwiseXorType($node->left, $node->right, function (Expr $expr) : Type { - return $this->getType($expr); - }); + return $this->initializerExprTypeResolver->getBitwiseXorType($node->left, $node->right, fn (Expr $expr): Type => $this->getType($expr)); } if ($node instanceof Expr\AssignOp\BitwiseXor) { - return $this->initializerExprTypeResolver->getBitwiseXorType($node->var, $node->expr, function (Expr $expr) : Type { - return $this->getType($expr); - }); + return $this->initializerExprTypeResolver->getBitwiseXorType($node->var, $node->expr, fn (Expr $expr): Type => $this->getType($expr)); } if ($node instanceof Expr\BinaryOp\Spaceship) { - return $this->initializerExprTypeResolver->getSpaceshipType($node->left, $node->right, function (Expr $expr) : Type { - return $this->getType($expr); - }); + return $this->initializerExprTypeResolver->getSpaceshipType($node->left, $node->right, fn (Expr $expr): Type => $this->getType($expr)); } if ($node instanceof BinaryOp\Div) { - return $this->initializerExprTypeResolver->getDivType($node->left, $node->right, function (Expr $expr) : Type { - return $this->getType($expr); - }); + return $this->initializerExprTypeResolver->getDivType($node->left, $node->right, fn (Expr $expr): Type => $this->getType($expr)); } if ($node instanceof Expr\AssignOp\Div) { - return $this->initializerExprTypeResolver->getDivType($node->var, $node->expr, function (Expr $expr) : Type { - return $this->getType($expr); - }); + return $this->initializerExprTypeResolver->getDivType($node->var, $node->expr, fn (Expr $expr): Type => $this->getType($expr)); } if ($node instanceof BinaryOp\Mod) { - return $this->initializerExprTypeResolver->getModType($node->left, $node->right, function (Expr $expr) : Type { - return $this->getType($expr); - }); + return $this->initializerExprTypeResolver->getModType($node->left, $node->right, fn (Expr $expr): Type => $this->getType($expr)); } if ($node instanceof Expr\AssignOp\Mod) { - return $this->initializerExprTypeResolver->getModType($node->var, $node->expr, function (Expr $expr) : Type { - return $this->getType($expr); - }); + return $this->initializerExprTypeResolver->getModType($node->var, $node->expr, fn (Expr $expr): Type => $this->getType($expr)); } if ($node instanceof BinaryOp\Plus) { - return $this->initializerExprTypeResolver->getPlusType($node->left, $node->right, function (Expr $expr) : Type { - return $this->getType($expr); - }); + return $this->initializerExprTypeResolver->getPlusType($node->left, $node->right, fn (Expr $expr): Type => $this->getType($expr)); } if ($node instanceof Expr\AssignOp\Plus) { - return $this->initializerExprTypeResolver->getPlusType($node->var, $node->expr, function (Expr $expr) : Type { - return $this->getType($expr); - }); + return $this->initializerExprTypeResolver->getPlusType($node->var, $node->expr, fn (Expr $expr): Type => $this->getType($expr)); } if ($node instanceof BinaryOp\Minus) { - return $this->initializerExprTypeResolver->getMinusType($node->left, $node->right, function (Expr $expr) : Type { - return $this->getType($expr); - }); + return $this->initializerExprTypeResolver->getMinusType($node->left, $node->right, fn (Expr $expr): Type => $this->getType($expr)); } if ($node instanceof Expr\AssignOp\Minus) { - return $this->initializerExprTypeResolver->getMinusType($node->var, $node->expr, function (Expr $expr) : Type { - return $this->getType($expr); - }); + return $this->initializerExprTypeResolver->getMinusType($node->var, $node->expr, fn (Expr $expr): Type => $this->getType($expr)); } if ($node instanceof BinaryOp\Mul) { - return $this->initializerExprTypeResolver->getMulType($node->left, $node->right, function (Expr $expr) : Type { - return $this->getType($expr); - }); + return $this->initializerExprTypeResolver->getMulType($node->left, $node->right, fn (Expr $expr): Type => $this->getType($expr)); } if ($node instanceof Expr\AssignOp\Mul) { - return $this->initializerExprTypeResolver->getMulType($node->var, $node->expr, function (Expr $expr) : Type { - return $this->getType($expr); - }); + return $this->initializerExprTypeResolver->getMulType($node->var, $node->expr, fn (Expr $expr): Type => $this->getType($expr)); } if ($node instanceof BinaryOp\Pow) { - return $this->initializerExprTypeResolver->getPowType($node->left, $node->right, function (Expr $expr) : Type { - return $this->getType($expr); - }); + return $this->initializerExprTypeResolver->getPowType($node->left, $node->right, fn (Expr $expr): Type => $this->getType($expr)); } if ($node instanceof Expr\AssignOp\Pow) { - return $this->initializerExprTypeResolver->getPowType($node->var, $node->expr, function (Expr $expr) : Type { - return $this->getType($expr); - }); + return $this->initializerExprTypeResolver->getPowType($node->var, $node->expr, fn (Expr $expr): Type => $this->getType($expr)); } if ($node instanceof BinaryOp\ShiftLeft) { - return $this->initializerExprTypeResolver->getShiftLeftType($node->left, $node->right, function (Expr $expr) : Type { - return $this->getType($expr); - }); + return $this->initializerExprTypeResolver->getShiftLeftType($node->left, $node->right, fn (Expr $expr): Type => $this->getType($expr)); } if ($node instanceof Expr\AssignOp\ShiftLeft) { - return $this->initializerExprTypeResolver->getShiftLeftType($node->var, $node->expr, function (Expr $expr) : Type { - return $this->getType($expr); - }); + return $this->initializerExprTypeResolver->getShiftLeftType($node->var, $node->expr, fn (Expr $expr): Type => $this->getType($expr)); } if ($node instanceof BinaryOp\ShiftRight) { - return $this->initializerExprTypeResolver->getShiftRightType($node->left, $node->right, function (Expr $expr) : Type { - return $this->getType($expr); - }); + return $this->initializerExprTypeResolver->getShiftRightType($node->left, $node->right, fn (Expr $expr): Type => $this->getType($expr)); } if ($node instanceof Expr\AssignOp\ShiftRight) { - return $this->initializerExprTypeResolver->getShiftRightType($node->var, $node->expr, function (Expr $expr) : Type { - return $this->getType($expr); - }); + return $this->initializerExprTypeResolver->getShiftRightType($node->var, $node->expr, fn (Expr $expr): Type => $this->getType($expr)); } if ($node instanceof Expr\Clone_) { @@ -1223,7 +1116,9 @@ private function resolveType(string $exprString, Expr $node): Type if ($node instanceof FuncCall) { if ($node->name instanceof Name) { if ($this->reflectionProvider->hasFunction($node->name, $this)) { - return $this->createFirstClassCallable($this->reflectionProvider->getFunction($node->name, $this)->getVariants()); + return $this->createFirstClassCallable( + $this->reflectionProvider->getFunction($node->name, $this)->getVariants(), + ); } return new ObjectType(Closure::class); @@ -1234,7 +1129,9 @@ private function resolveType(string $exprString, Expr $node): Type return new ObjectType(Closure::class); } - return $this->createFirstClassCallable($callableType->getCallableParametersAcceptors($this)); + return $this->createFirstClassCallable( + $callableType->getCallableParametersAcceptors($this), + ); } if ($node instanceof MethodCall) { @@ -1297,9 +1194,16 @@ private function resolveType(string $exprString, Expr $node): Type if (!$param->var instanceof Variable || !is_string($param->var->name)) { throw new ShouldNotHappenException(); } - $parameters[] = new NativeParameterReflection($param->var->name, $firstOptionalParameterIndex !== null && $i >= $firstOptionalParameterIndex, $this->getFunctionType($param->type, $this->isParameterValueNullable($param), false), $param->byRef + $parameters[] = new NativeParameterReflection( + $param->var->name, + $firstOptionalParameterIndex !== null && $i >= $firstOptionalParameterIndex, + $this->getFunctionType($param->type, $this->isParameterValueNullable($param), false), + $param->byRef ? PassedByReference::createCreatesNewVariable() - : PassedByReference::createNo(), $param->variadic, $param->default !== null ? $this->getType($param->default) : null); + : PassedByReference::createNo(), + $param->variadic, + $param->default !== null ? $this->getType($param->default) : null, + ); } $callableParameters = null; @@ -1450,7 +1354,11 @@ private function resolveType(string $exprString, Expr $node): Type } } - return new ClosureType($parameters, $returnType, $isVariadic); + return new ClosureType( + $parameters, + $returnType, + $isVariadic, + ); } elseif ($node instanceof New_) { if ($node->class instanceof Name) { $type = $this->exactInstantiation($node, $node->class->toString()); @@ -1482,9 +1390,7 @@ private function resolveType(string $exprString, Expr $node): Type return $exprType->getObjectTypeOrClassStringObjectType(); } elseif ($node instanceof Array_) { - return $this->initializerExprTypeResolver->getArrayType($node, function (Expr $expr) : Type { - return $this->getType($expr); - }); + return $this->initializerExprTypeResolver->getArrayType($node, fn (Expr $expr): Type => $this->getType($expr)); } elseif ($node instanceof Int_) { return $this->getType($node->expr)->toInteger(); } elseif ($node instanceof Bool_) { @@ -1615,11 +1521,14 @@ private function resolveType(string $exprString, Expr $node): Type foreach ($arm->conds as $filteringExpr) { $items[] = new Expr\ArrayItem($filteringExpr); } - $filteringExpr = new FuncCall(new Name\FullyQualified('in_array'), [ + $filteringExpr = new FuncCall( + new Name\FullyQualified('in_array'), + [ new Arg($cond), new Arg(new Array_($items)), new Arg(new ConstFetch(new Name\FullyQualified('true'))), - ]); + ], + ); } $filteringExprType = $matchScope->getType($filteringExpr); @@ -1691,7 +1600,10 @@ private function resolveType(string $exprString, Expr $node): Type $rightType = $this->filterByFalseyValue($issetLeftExpr)->getType($node->right); if ($result === null) { - return TypeCombinator::union(TypeCombinator::removeNull($leftType), $rightType); + return TypeCombinator::union( + TypeCombinator::removeNull($leftType), + $rightType, + ); } return $rightType; @@ -1720,7 +1632,10 @@ private function resolveType(string $exprString, Expr $node): Type } $constFetch = new ConstFetch($name); if ($this->hasExpressionType($constFetch)->yes()) { - return $this->constantResolver->resolveConstantType($name->toString(), $this->expressionTypes[$this->getNodeKey($constFetch)]->getType()); + return $this->constantResolver->resolveConstantType( + $name->toString(), + $this->expressionTypes[$this->getNodeKey($constFetch)]->getType(), + ); } } @@ -1734,9 +1649,12 @@ private function resolveType(string $exprString, Expr $node): Type if ($this->hasExpressionType($node)->yes()) { return $this->expressionTypes[$exprString]->getType(); } - return $this->initializerExprTypeResolver->getClassConstFetchTypeByReflection($node->class, $node->name->name, $this->isInClass() ? $this->getClassReflection() : null, function (Expr $expr) : Type { - return $this->getType($expr); - }); + return $this->initializerExprTypeResolver->getClassConstFetchTypeByReflection( + $node->class, + $node->name->name, + $this->isInClass() ? $this->getClassReflection() : null, + fn (Expr $expr): Type => $this->getType($expr), + ); } if ($node instanceof Expr\Ternary) { @@ -1754,7 +1672,10 @@ private function resolveType(string $exprString, Expr $node): Type return $condResult->getFalseyScope()->getType($node->else); } - return TypeCombinator::union(TypeCombinator::removeFalsey($condResult->getTruthyScope()->getType($node->cond)), $condResult->getFalseyScope()->getType($node->else)); + return TypeCombinator::union( + TypeCombinator::removeFalsey($condResult->getTruthyScope()->getType($node->cond)), + $condResult->getFalseyScope()->getType($node->else), + ); } $booleanConditionType = $this->getType($node->cond)->toBoolean(); @@ -1766,7 +1687,10 @@ private function resolveType(string $exprString, Expr $node): Type return $condResult->getFalseyScope()->getType($node->else); } - return TypeCombinator::union($condResult->getTruthyScope()->getType($node->if), $condResult->getFalseyScope()->getType($node->else)); + return TypeCombinator::union( + $condResult->getTruthyScope()->getType($node->if), + $condResult->getFalseyScope()->getType($node->else), + ); } if ($node instanceof Variable && is_string($node->name)) { @@ -1778,13 +1702,23 @@ private function resolveType(string $exprString, Expr $node): Type } if ($node instanceof Expr\ArrayDimFetch && $node->dim !== null) { - return $this->getNullsafeShortCircuitingType($node->var, $this->getTypeFromArrayDimFetch($node, $this->getType($node->dim), $this->getType($node->var))); + return $this->getNullsafeShortCircuitingType( + $node->var, + $this->getTypeFromArrayDimFetch( + $node, + $this->getType($node->dim), + $this->getType($node->var), + ), + ); } if ($node instanceof MethodCall && $node->name instanceof Node\Identifier) { if ($this->nativeTypesPromoted) { $typeCallback = function () use ($node): Type { - $methodReflection = $this->getMethodReflection($this->getNativeType($node->var), $node->name->name); + $methodReflection = $this->getMethodReflection( + $this->getNativeType($node->var), + $node->name->name, + ); if ($methodReflection === null) { return new ErrorType(); } @@ -1796,7 +1730,11 @@ private function resolveType(string $exprString, Expr $node): Type } $typeCallback = function () use ($node): Type { - $returnType = $this->methodCallReturnType($this->getType($node->var), $node->name->name, $node); + $returnType = $this->methodCallReturnType( + $this->getType($node->var), + $node->name->name, + $node, + ); if ($returnType === null) { return new ErrorType(); } @@ -1815,8 +1753,11 @@ private function resolveType(string $exprString, Expr $node): Type return $this->getType(new MethodCall($node->var, $node->name, $node->args)); } - return TypeCombinator::union($this->filterByTruthyValue(new BinaryOp\NotIdentical($node->var, new ConstFetch(new Name('null')))) - ->getType(new MethodCall($node->var, $node->name, $node->args)), new NullType()); + return TypeCombinator::union( + $this->filterByTruthyValue(new BinaryOp\NotIdentical($node->var, new ConstFetch(new Name('null')))) + ->getType(new MethodCall($node->var, $node->name, $node->args)), + new NullType(), + ); } if ($node instanceof Expr\StaticCall && $node->name instanceof Node\Identifier) { @@ -1827,7 +1768,10 @@ private function resolveType(string $exprString, Expr $node): Type } else { $staticMethodCalledOnType = $this->getNativeType($node->class); } - $methodReflection = $this->getMethodReflection($staticMethodCalledOnType, $node->name->name); + $methodReflection = $this->getMethodReflection( + $staticMethodCalledOnType, + $node->name->name, + ); if ($methodReflection === null) { return new ErrorType(); } @@ -1850,7 +1794,11 @@ private function resolveType(string $exprString, Expr $node): Type $staticMethodCalledOnType = $this->getType($node->class)->getObjectTypeOrClassStringObjectType(); } - $returnType = $this->methodCallReturnType($staticMethodCalledOnType, $node->name->toString(), $node); + $returnType = $this->methodCallReturnType( + $staticMethodCalledOnType, + $node->name->toString(), + $node, + ); if ($returnType === null) { return new ErrorType(); } @@ -1880,7 +1828,11 @@ private function resolveType(string $exprString, Expr $node): Type } $typeCallback = function () use ($node): Type { - $returnType = $this->propertyFetchType($this->getType($node->var), $node->name->name, $node); + $returnType = $this->propertyFetchType( + $this->getType($node->var), + $node->name->name, + $node, + ); if ($returnType === null) { return new ErrorType(); } @@ -1899,8 +1851,11 @@ private function resolveType(string $exprString, Expr $node): Type return $this->getType(new PropertyFetch($node->var, $node->name)); } - return TypeCombinator::union($this->filterByTruthyValue(new BinaryOp\NotIdentical($node->var, new ConstFetch(new Name('null')))) - ->getType(new PropertyFetch($node->var, $node->name)), new NullType()); + return TypeCombinator::union( + $this->filterByTruthyValue(new BinaryOp\NotIdentical($node->var, new ConstFetch(new Name('null')))) + ->getType(new PropertyFetch($node->var, $node->name)), + new NullType(), + ); } if ( @@ -1931,7 +1886,11 @@ private function resolveType(string $exprString, Expr $node): Type $staticPropertyFetchedOnType = $this->getType($node->class)->getObjectTypeOrClassStringObjectType(); } - $returnType = $this->propertyFetchType($staticPropertyFetchedOnType, $node->name->toString(), $node); + $returnType = $this->propertyFetchType( + $staticPropertyFetchedOnType, + $node->name->toString(), + $node, + ); if ($returnType === null) { return new ErrorType(); } @@ -1953,7 +1912,12 @@ private function resolveType(string $exprString, Expr $node): Type return new ErrorType(); } - return ParametersAcceptorSelector::selectFromArgs($this, $node->getArgs(), $calledOnType->getCallableParametersAcceptors($this), null)->getReturnType(); + return ParametersAcceptorSelector::selectFromArgs( + $this, + $node->getArgs(), + $calledOnType->getCallableParametersAcceptors($this), + null, + )->getReturnType(); } if (!$this->reflectionProvider->hasFunction($node->name, $this)) { @@ -1974,7 +1938,12 @@ private function resolveType(string $exprString, Expr $node): Type } } - $parametersAcceptor = ParametersAcceptorSelector::selectFromArgs($this, $node->getArgs(), $functionReflection->getVariants(), $functionReflection->getNamedArgumentsVariants()); + $parametersAcceptor = ParametersAcceptorSelector::selectFromArgs( + $this, + $node->getArgs(), + $functionReflection->getVariants(), + $functionReflection->getNamedArgumentsVariants(), + ); $normalizedNode = ArgumentsNormalizer::reorderFuncArguments($parametersAcceptor, $node); if ($normalizedNode !== null) { foreach ($this->dynamicReturnTypeExtensionRegistry->getDynamicFunctionReturnTypeExtensions() as $dynamicFunctionReturnTypeExtension) { @@ -1982,7 +1951,11 @@ private function resolveType(string $exprString, Expr $node): Type continue; } - $resolvedType = $dynamicFunctionReturnTypeExtension->getTypeFromFunctionCall($functionReflection, $normalizedNode, $this); + $resolvedType = $dynamicFunctionReturnTypeExtension->getTypeFromFunctionCall( + $functionReflection, + $normalizedNode, + $this, + ); if ($resolvedType !== null) { return $resolvedType; } @@ -2049,9 +2022,9 @@ private function transformVoidToNull(Type $type, Node $node): Type } /** - * @param callable(Type): ?bool $typeCallback - */ - public function issetCheck(Expr $expr, callable $typeCallback, ?bool $result = null): ?bool + * @param callable(Type): ?bool $typeCallback + */ + public function issetCheck(Expr $expr, callable $typeCallback, ?bool $result = null): ?bool { // mirrored in PHPStan\Rules\IssetCheck if ($expr instanceof Node\Expr\Variable && is_string($expr->name)) { @@ -2205,9 +2178,9 @@ private function issetCheckUndefined(Expr $expr): ?bool } /** - * @param ParametersAcceptor[] $variants - */ - private function createFirstClassCallable(array $variants): Type + * @param ParametersAcceptor[] $variants + */ + private function createFirstClassCallable(array $variants): Type { $closureTypes = []; foreach ($variants as $variant) { @@ -2216,14 +2189,21 @@ private function createFirstClassCallable(array $variants): Type $returnType = $this->nativeTypesPromoted ? $variant->getNativeReturnType() : $returnType; } $parameters = $variant->getParameters(); - $closureTypes[] = new ClosureType($parameters, $returnType, $variant->isVariadic(), $variant->getTemplateTypeMap(), $variant->getResolvedTemplateTypeMap(), $variant instanceof ParametersAcceptorWithPhpDocs ? $variant->getCallSiteVarianceMap() : TemplateTypeVarianceMap::createEmpty()); + $closureTypes[] = new ClosureType( + $parameters, + $returnType, + $variant->isVariadic(), + $variant->getTemplateTypeMap(), + $variant->getResolvedTemplateTypeMap(), + $variant instanceof ParametersAcceptorWithPhpDocs ? $variant->getCallSiteVarianceMap() : TemplateTypeVarianceMap::createEmpty(), + ); } return TypeCombinator::union(...$closureTypes); } /** @api */ - public function getNativeType(Expr $expr): Type + public function getNativeType(Expr $expr): Type { return $this->promoteNativeTypes()->getType($expr); } @@ -2237,10 +2217,10 @@ public function getKeepVoidType(Expr $node): Type } /** - * @api - * @deprecated Use getNativeType() - */ - public function doNotTreatPhpDocTypesAsCertain(): Scope + * @api + * @deprecated Use getNativeType() + */ + public function doNotTreatPhpDocTypesAsCertain(): Scope { return $this->promoteNativeTypes(); } @@ -2255,13 +2235,30 @@ private function promoteNativeTypes(): self return $this->scopeWithPromotedNativeTypes; } - return $this->scopeWithPromotedNativeTypes = $this->scopeFactory->create($this->context, $this->declareStrictTypes, $this->function, $this->namespace, $this->nativeExpressionTypes, [], [], $this->inClosureBindScopeClasses, $this->anonymousFunctionReflection, $this->inFirstLevelStatement, $this->currentlyAssignedExpressions, $this->currentlyAllowedUndefinedExpressions, $this->inFunctionCallsStack, $this->afterExtractCall, $this->parentScope, true); + return $this->scopeWithPromotedNativeTypes = $this->scopeFactory->create( + $this->context, + $this->declareStrictTypes, + $this->function, + $this->namespace, + $this->nativeExpressionTypes, + [], + [], + $this->inClosureBindScopeClasses, + $this->anonymousFunctionReflection, + $this->inFirstLevelStatement, + $this->currentlyAssignedExpressions, + $this->currentlyAllowedUndefinedExpressions, + $this->inFunctionCallsStack, + $this->afterExtractCall, + $this->parentScope, + true, + ); } /** - * @param Node\Expr\PropertyFetch|Node\Expr\StaticPropertyFetch $propertyFetch - */ - private function hasPropertyNativeType($propertyFetch): bool + * @param Node\Expr\PropertyFetch|Node\Expr\StaticPropertyFetch $propertyFetch + */ + private function hasPropertyNativeType($propertyFetch): bool { $propertyReflection = $this->propertyReflectionFinder->findPropertyReflectionFromNode($propertyFetch, $this); if ($propertyReflection === null) { @@ -2276,18 +2273,30 @@ private function hasPropertyNativeType($propertyFetch): bool } /** @api */ - protected function getTypeFromArrayDimFetch(Expr\ArrayDimFetch $arrayDimFetch, Type $offsetType, Type $offsetAccessibleType) : Type - { - if ($arrayDimFetch->dim === null) { - throw new ShouldNotHappenException(); - } - if (!$offsetAccessibleType->isArray()->yes() && (new ObjectType(ArrayAccess::class))->isSuperTypeOf($offsetAccessibleType)->yes()) { - return $this->getType(new MethodCall($arrayDimFetch->var, new Node\Identifier('offsetGet'), [ + protected function getTypeFromArrayDimFetch( + Expr\ArrayDimFetch $arrayDimFetch, + Type $offsetType, + Type $offsetAccessibleType, + ): Type + { + if ($arrayDimFetch->dim === null) { + throw new ShouldNotHappenException(); + } + + if (!$offsetAccessibleType->isArray()->yes() && (new ObjectType(ArrayAccess::class))->isSuperTypeOf($offsetAccessibleType)->yes()) { + return $this->getType( + new MethodCall( + $arrayDimFetch->var, + new Node\Identifier('offsetGet'), + [ new Node\Arg($arrayDimFetch->dim), - ])); - } - return $offsetAccessibleType->getOffsetValueType($offsetType); - } + ], + ), + ); + } + + return $offsetAccessibleType->getOffsetValueType($offsetType); + } private function resolveExactName(Name $name): ?string { @@ -2316,7 +2325,7 @@ private function resolveExactName(Name $name): ?string } /** @api */ - public function resolveName(Name $name): string + public function resolveName(Name $name): string { $originalClass = (string) $name; if ($this->isInClass()) { @@ -2340,7 +2349,7 @@ public function resolveName(Name $name): string } /** @api */ - public function resolveTypeByName(Name $name): TypeWithClassName + public function resolveTypeByName(Name $name): TypeWithClassName { if ($name->toLowerString() === 'static' && $this->isInClass()) { if ($this->inClosureBindScopeClasses !== [] && $this->inClosureBindScopeClasses !== ['static']) { @@ -2372,25 +2381,25 @@ public function resolveTypeByName(Name $name): TypeWithClassName } /** - * @api - * @param mixed $value - */ - public function getTypeFromValue($value): Type + * @api + * @param mixed $value + */ + public function getTypeFromValue($value): Type { return ConstantTypeHelper::getTypeFromValue($value); } /** - * @api - * @deprecated use hasExpressionType instead - */ - public function isSpecified(Expr $node): bool + * @api + * @deprecated use hasExpressionType instead + */ + public function isSpecified(Expr $node): bool { return !$node instanceof Variable && $this->hasExpressionType($node)->yes(); } /** @api */ - public function hasExpressionType(Expr $node): TrinaryLogic + public function hasExpressionType(Expr $node): TrinaryLogic { if ($node instanceof Variable && is_string($node->name)) { return $this->hasVariableType($node->name); @@ -2404,14 +2413,31 @@ public function hasExpressionType(Expr $node): TrinaryLogic } /** - * @param MethodReflection|FunctionReflection $reflection - */ - public function pushInFunctionCall($reflection, ?ParameterReflection $parameter): self + * @param MethodReflection|FunctionReflection $reflection + */ + public function pushInFunctionCall($reflection, ?ParameterReflection $parameter): self { $stack = $this->inFunctionCallsStack; $stack[] = [$reflection, $parameter]; - $scope = $this->scopeFactory->create($this->context, $this->isDeclareStrictTypes(), $this->getFunction(), $this->getNamespace(), $this->expressionTypes, $this->nativeExpressionTypes, $this->conditionalExpressions, $this->inClosureBindScopeClasses, $this->anonymousFunctionReflection, $this->isInFirstLevelStatement(), $this->currentlyAssignedExpressions, $this->currentlyAllowedUndefinedExpressions, $stack, $this->afterExtractCall, $this->parentScope, $this->nativeTypesPromoted); + $scope = $this->scopeFactory->create( + $this->context, + $this->isDeclareStrictTypes(), + $this->getFunction(), + $this->getNamespace(), + $this->expressionTypes, + $this->nativeExpressionTypes, + $this->conditionalExpressions, + $this->inClosureBindScopeClasses, + $this->anonymousFunctionReflection, + $this->isInFirstLevelStatement(), + $this->currentlyAssignedExpressions, + $this->currentlyAllowedUndefinedExpressions, + $stack, + $this->afterExtractCall, + $this->parentScope, + $this->nativeTypesPromoted, + ); $scope->resolvedTypes = $this->resolvedTypes; $scope->truthyScopes = $this->truthyScopes; $scope->falseyScopes = $this->falseyScopes; @@ -2424,7 +2450,24 @@ public function popInFunctionCall(): self $stack = $this->inFunctionCallsStack; array_pop($stack); - $scope = $this->scopeFactory->create($this->context, $this->isDeclareStrictTypes(), $this->getFunction(), $this->getNamespace(), $this->expressionTypes, $this->nativeExpressionTypes, $this->conditionalExpressions, $this->inClosureBindScopeClasses, $this->anonymousFunctionReflection, $this->isInFirstLevelStatement(), $this->currentlyAssignedExpressions, $this->currentlyAllowedUndefinedExpressions, $stack, $this->afterExtractCall, $this->parentScope, $this->nativeTypesPromoted); + $scope = $this->scopeFactory->create( + $this->context, + $this->isDeclareStrictTypes(), + $this->getFunction(), + $this->getNamespace(), + $this->expressionTypes, + $this->nativeExpressionTypes, + $this->conditionalExpressions, + $this->inClosureBindScopeClasses, + $this->anonymousFunctionReflection, + $this->isInFirstLevelStatement(), + $this->currentlyAssignedExpressions, + $this->currentlyAllowedUndefinedExpressions, + $stack, + $this->afterExtractCall, + $this->parentScope, + $this->nativeTypesPromoted, + ); $scope->resolvedTypes = $this->resolvedTypes; $scope->truthyScopes = $this->truthyScopes; $scope->falseyScopes = $this->falseyScopes; @@ -2433,7 +2476,7 @@ public function popInFunctionCall(): self } /** @api */ - public function isInClassExists(string $className): bool + public function isInClassExists(string $className): bool { foreach ($this->inFunctionCallsStack as [$inFunctionCall]) { if (!$inFunctionCall instanceof FunctionReflection) { @@ -2457,9 +2500,7 @@ public function isInClassExists(string $className): bool public function getFunctionCallStack(): array { - return array_map(static function ($values) { - return $values[0]; - }, $this->inFunctionCallsStack); + return array_map(static fn ($values) => $values[0], $this->inFunctionCallsStack); } public function getFunctionCallStackWithParameters(): array @@ -2468,7 +2509,7 @@ public function getFunctionCallStackWithParameters(): array } /** @api */ - public function isInFunctionExists(string $functionName): bool + public function isInFunctionExists(string $functionName): bool { $expr = new FuncCall(new FullyQualified('function_exists'), [ new Arg(new String_(ltrim($functionName, '\\'))), @@ -2478,7 +2519,7 @@ public function isInFunctionExists(string $functionName): bool } /** @api */ - public function enterClass(ClassReflection $classReflection): self + public function enterClass(ClassReflection $classReflection): self { $thisHolder = ExpressionTypeHolder::createYes(new Variable('this'), new ThisType($classReflection)); $constantTypes = $this->getConstantTypes(); @@ -2486,7 +2527,23 @@ public function enterClass(ClassReflection $classReflection): self $nativeConstantTypes = $this->getNativeConstantTypes(); $nativeConstantTypes['$this'] = $thisHolder; - return $this->scopeFactory->create($this->context->enterClass($classReflection), $this->isDeclareStrictTypes(), null, $this->getNamespace(), $constantTypes, $nativeConstantTypes, [], [], null, true, [], [], [], false, $classReflection->isAnonymous() ? $this : null); + return $this->scopeFactory->create( + $this->context->enterClass($classReflection), + $this->isDeclareStrictTypes(), + null, + $this->getNamespace(), + $constantTypes, + $nativeConstantTypes, + [], + [], + null, + true, + [], + [], + [], + false, + $classReflection->isAnonymous() ? $this : null, + ); } public function enterTrait(ClassReflection $traitReflection): self @@ -2497,25 +2554,72 @@ public function enterTrait(ClassReflection $traitReflection): self if (count($traitNameParts) > 1) { $namespace = implode('\\', array_slice($traitNameParts, 0, -1)); } - return $this->scopeFactory->create($this->context->enterTrait($traitReflection), $this->isDeclareStrictTypes(), $this->getFunction(), $namespace, $this->expressionTypes, $this->nativeExpressionTypes, [], $this->inClosureBindScopeClasses, $this->anonymousFunctionReflection); + return $this->scopeFactory->create( + $this->context->enterTrait($traitReflection), + $this->isDeclareStrictTypes(), + $this->getFunction(), + $namespace, + $this->expressionTypes, + $this->nativeExpressionTypes, + [], + $this->inClosureBindScopeClasses, + $this->anonymousFunctionReflection, + ); } /** - * @api - * @param Type[] $phpDocParameterTypes - * @param Type[] $parameterOutTypes - */ - public function enterClassMethod(Node\Stmt\ClassMethod $classMethod, TemplateTypeMap $templateTypeMap, array $phpDocParameterTypes, ?Type $phpDocReturnType, ?Type $throwType, ?string $deprecatedDescription, bool $isDeprecated, bool $isInternal, bool $isFinal, ?bool $isPure = null, bool $acceptsNamedArguments = true, ?Assertions $asserts = null, ?Type $selfOutType = null, ?string $phpDocComment = null, array $parameterOutTypes = []) : self - { - if (!$this->isInClass()) { - throw new ShouldNotHappenException(); - } - return $this->enterFunctionLike(new PhpMethodFromParserNodeReflection($this->getClassReflection(), $classMethod, $this->getFile(), $templateTypeMap, $this->getRealParameterTypes($classMethod), array_map(static function (Type $type) : Type { - return TemplateTypeHelper::toArgument($type); - }, $phpDocParameterTypes), $this->getRealParameterDefaultValues($classMethod), $this->transformStaticType($this->getFunctionType($classMethod->returnType, false, false)), $phpDocReturnType !== null ? TemplateTypeHelper::toArgument($phpDocReturnType) : null, $throwType, $deprecatedDescription, $isDeprecated, $isInternal, $isFinal, $isPure, $acceptsNamedArguments, $asserts ?? Assertions::createEmpty(), $selfOutType, $phpDocComment, array_map(static function (Type $type) : Type { - return TemplateTypeHelper::toArgument($type); - }, $parameterOutTypes)), !$classMethod->isStatic()); - } + * @api + * @param Type[] $phpDocParameterTypes + * @param Type[] $parameterOutTypes + */ + public function enterClassMethod( + Node\Stmt\ClassMethod $classMethod, + TemplateTypeMap $templateTypeMap, + array $phpDocParameterTypes, + ?Type $phpDocReturnType, + ?Type $throwType, + ?string $deprecatedDescription, + bool $isDeprecated, + bool $isInternal, + bool $isFinal, + ?bool $isPure = null, + bool $acceptsNamedArguments = true, + ?Assertions $asserts = null, + ?Type $selfOutType = null, + ?string $phpDocComment = null, + array $parameterOutTypes = [], + ): self + { + if (!$this->isInClass()) { + throw new ShouldNotHappenException(); + } + + return $this->enterFunctionLike( + new PhpMethodFromParserNodeReflection( + $this->getClassReflection(), + $classMethod, + $this->getFile(), + $templateTypeMap, + $this->getRealParameterTypes($classMethod), + array_map(static fn (Type $type): Type => TemplateTypeHelper::toArgument($type), $phpDocParameterTypes), + $this->getRealParameterDefaultValues($classMethod), + $this->transformStaticType($this->getFunctionType($classMethod->returnType, false, false)), + $phpDocReturnType !== null ? TemplateTypeHelper::toArgument($phpDocReturnType) : null, + $throwType, + $deprecatedDescription, + $isDeprecated, + $isInternal, + $isFinal, + $isPure, + $acceptsNamedArguments, + $asserts ?? Assertions::createEmpty(), + $selfOutType, + $phpDocComment, + array_map(static fn (Type $type): Type => TemplateTypeHelper::toArgument($type), $parameterOutTypes), + ), + !$classMethod->isStatic(), + ); + } private function transformStaticType(Type $type): Type { @@ -2537,25 +2641,29 @@ private function transformStaticType(Type $type): Type } /** - * @return Type[] - */ - private function getRealParameterTypes(Node\FunctionLike $functionLike): array + * @return Type[] + */ + private function getRealParameterTypes(Node\FunctionLike $functionLike): array { $realParameterTypes = []; foreach ($functionLike->getParams() as $parameter) { if (!$parameter->var instanceof Variable || !is_string($parameter->var->name)) { throw new ShouldNotHappenException(); } - $realParameterTypes[$parameter->var->name] = $this->getFunctionType($parameter->type, $this->isParameterValueNullable($parameter), false); + $realParameterTypes[$parameter->var->name] = $this->getFunctionType( + $parameter->type, + $this->isParameterValueNullable($parameter), + false, + ); } return $realParameterTypes; } /** - * @return Type[] - */ - private function getRealParameterDefaultValues(Node\FunctionLike $functionLike): array + * @return Type[] + */ + private function getRealParameterDefaultValues(Node\FunctionLike $functionLike): array { $realParameterDefaultValues = []; foreach ($functionLike->getParams() as $parameter) { @@ -2572,92 +2680,145 @@ private function getRealParameterDefaultValues(Node\FunctionLike $functionLike): } /** - * @api - * @param Type[] $phpDocParameterTypes - * @param Type[] $parameterOutTypes - */ - public function enterFunction(Node\Stmt\Function_ $function, TemplateTypeMap $templateTypeMap, array $phpDocParameterTypes, ?Type $phpDocReturnType, ?Type $throwType, ?string $deprecatedDescription, bool $isDeprecated, bool $isInternal, bool $isFinal, ?bool $isPure = null, bool $acceptsNamedArguments = true, ?Assertions $asserts = null, ?string $phpDocComment = null, array $parameterOutTypes = []) : self - { - return $this->enterFunctionLike(new PhpFunctionFromParserNodeReflection($function, $this->getFile(), $templateTypeMap, $this->getRealParameterTypes($function), array_map(static function (Type $type) : Type { - return TemplateTypeHelper::toArgument($type); - }, $phpDocParameterTypes), $this->getRealParameterDefaultValues($function), $this->getFunctionType($function->returnType, $function->returnType === null, false), $phpDocReturnType !== null ? TemplateTypeHelper::toArgument($phpDocReturnType) : null, $throwType, $deprecatedDescription, $isDeprecated, $isInternal, $isFinal, $isPure, $acceptsNamedArguments, $asserts ?? Assertions::createEmpty(), $phpDocComment, array_map(static function (Type $type) : Type { - return TemplateTypeHelper::toArgument($type); - }, $parameterOutTypes)), false); - } - - private function enterFunctionLike(PhpFunctionFromParserNodeReflection $functionReflection, bool $preserveThis) : self - { - $acceptor = ParametersAcceptorSelector::selectSingle($functionReflection->getVariants()); - $parametersByName = []; - foreach ($acceptor->getParameters() as $parameter) { - $parametersByName[$parameter->getName()] = $parameter; - } - $expressionTypes = []; - $nativeExpressionTypes = []; - $conditionalTypes = []; - foreach ($acceptor->getParameters() as $parameter) { - $parameterType = $parameter->getType(); - - if ($parameterType instanceof ConditionalTypeForParameter) { - $targetParameterName = substr($parameterType->getParameterName(), 1); - if (array_key_exists($targetParameterName, $parametersByName)) { - $targetParameter = $parametersByName[$targetParameterName]; - - $ifType = $parameterType->isNegated() ? $parameterType->getElse() : $parameterType->getIf(); - $elseType = $parameterType->isNegated() ? $parameterType->getIf() : $parameterType->getElse(); - - $holder = new ConditionalExpressionHolder([ - $parameterType->getParameterName() => ExpressionTypeHolder::createYes(new Variable($targetParameterName), TypeCombinator::intersect($targetParameter->getType(), $parameterType->getTarget())), - ], new ExpressionTypeHolder(new Variable($parameter->getName()), $ifType, TrinaryLogic::createYes())); - $conditionalTypes['$' . $parameter->getName()][$holder->getKey()] = $holder; - - $holder = new ConditionalExpressionHolder([ - $parameterType->getParameterName() => ExpressionTypeHolder::createYes(new Variable($targetParameterName), TypeCombinator::remove($targetParameter->getType(), $parameterType->getTarget())), - ], new ExpressionTypeHolder(new Variable($parameter->getName()), $elseType, TrinaryLogic::createYes())); - $conditionalTypes['$' . $parameter->getName()][$holder->getKey()] = $holder; - } - } - - $paramExprString = '$' . $parameter->getName(); - if ($parameter->isVariadic()) { - if ($this->phpVersion->supportsNamedArguments() && $functionReflection->acceptsNamedArguments()) { - $parameterType = new ArrayType(new UnionType([new IntegerType(), new StringType()]), $parameterType); - } else { - $parameterType = AccessoryArrayListType::intersectWith(new ArrayType(new IntegerType(), $parameterType)); - } - } - $parameterNode = new Variable($parameter->getName()); - $expressionTypes[$paramExprString] = ExpressionTypeHolder::createYes($parameterNode, $parameterType); - - $nativeParameterType = $parameter->getNativeType(); - if ($parameter->isVariadic()) { - if ($this->phpVersion->supportsNamedArguments() && $functionReflection->acceptsNamedArguments()) { - $nativeParameterType = new ArrayType(new UnionType([new IntegerType(), new StringType()]), $nativeParameterType); - } else { - $nativeParameterType = AccessoryArrayListType::intersectWith(new ArrayType(new IntegerType(), $nativeParameterType)); - } - } - $nativeExpressionTypes[$paramExprString] = ExpressionTypeHolder::createYes($parameterNode, $nativeParameterType); - } - if ($preserveThis && array_key_exists('$this', $this->expressionTypes)) { - $expressionTypes['$this'] = $this->expressionTypes['$this']; - } - if ($preserveThis && array_key_exists('$this', $this->nativeExpressionTypes)) { - $nativeExpressionTypes['$this'] = $this->nativeExpressionTypes['$this']; - } - return $this->scopeFactory->create($this->context, $this->isDeclareStrictTypes(), $functionReflection, $this->getNamespace(), array_merge($this->getConstantTypes(), $expressionTypes), array_merge($this->getNativeConstantTypes(), $nativeExpressionTypes), $conditionalTypes); + * @api + * @param Type[] $phpDocParameterTypes + * @param Type[] $parameterOutTypes + */ + public function enterFunction( + Node\Stmt\Function_ $function, + TemplateTypeMap $templateTypeMap, + array $phpDocParameterTypes, + ?Type $phpDocReturnType, + ?Type $throwType, + ?string $deprecatedDescription, + bool $isDeprecated, + bool $isInternal, + bool $isFinal, + ?bool $isPure = null, + bool $acceptsNamedArguments = true, + ?Assertions $asserts = null, + ?string $phpDocComment = null, + array $parameterOutTypes = [], + ): self + { + return $this->enterFunctionLike( + new PhpFunctionFromParserNodeReflection( + $function, + $this->getFile(), + $templateTypeMap, + $this->getRealParameterTypes($function), + array_map(static fn (Type $type): Type => TemplateTypeHelper::toArgument($type), $phpDocParameterTypes), + $this->getRealParameterDefaultValues($function), + $this->getFunctionType($function->returnType, $function->returnType === null, false), + $phpDocReturnType !== null ? TemplateTypeHelper::toArgument($phpDocReturnType) : null, + $throwType, + $deprecatedDescription, + $isDeprecated, + $isInternal, + $isFinal, + $isPure, + $acceptsNamedArguments, + $asserts ?? Assertions::createEmpty(), + $phpDocComment, + array_map(static fn (Type $type): Type => TemplateTypeHelper::toArgument($type), $parameterOutTypes), + ), + false, + ); + } + + private function enterFunctionLike( + PhpFunctionFromParserNodeReflection $functionReflection, + bool $preserveThis, + ): self + { + $acceptor = ParametersAcceptorSelector::selectSingle($functionReflection->getVariants()); + $parametersByName = []; + + foreach ($acceptor->getParameters() as $parameter) { + $parametersByName[$parameter->getName()] = $parameter; + } + + $expressionTypes = []; + $nativeExpressionTypes = []; + $conditionalTypes = []; + foreach ($acceptor->getParameters() as $parameter) { + $parameterType = $parameter->getType(); + + if ($parameterType instanceof ConditionalTypeForParameter) { + $targetParameterName = substr($parameterType->getParameterName(), 1); + if (array_key_exists($targetParameterName, $parametersByName)) { + $targetParameter = $parametersByName[$targetParameterName]; + + $ifType = $parameterType->isNegated() ? $parameterType->getElse() : $parameterType->getIf(); + $elseType = $parameterType->isNegated() ? $parameterType->getIf() : $parameterType->getElse(); + + $holder = new ConditionalExpressionHolder([ + $parameterType->getParameterName() => ExpressionTypeHolder::createYes(new Variable($targetParameterName), TypeCombinator::intersect($targetParameter->getType(), $parameterType->getTarget())), + ], new ExpressionTypeHolder(new Variable($parameter->getName()), $ifType, TrinaryLogic::createYes())); + $conditionalTypes['$' . $parameter->getName()][$holder->getKey()] = $holder; + + $holder = new ConditionalExpressionHolder([ + $parameterType->getParameterName() => ExpressionTypeHolder::createYes(new Variable($targetParameterName), TypeCombinator::remove($targetParameter->getType(), $parameterType->getTarget())), + ], new ExpressionTypeHolder(new Variable($parameter->getName()), $elseType, TrinaryLogic::createYes())); + $conditionalTypes['$' . $parameter->getName()][$holder->getKey()] = $holder; + } } + $paramExprString = '$' . $parameter->getName(); + if ($parameter->isVariadic()) { + if ($this->phpVersion->supportsNamedArguments() && $functionReflection->acceptsNamedArguments()) { + $parameterType = new ArrayType(new UnionType([new IntegerType(), new StringType()]), $parameterType); + } else { + $parameterType = AccessoryArrayListType::intersectWith(new ArrayType(new IntegerType(), $parameterType)); + } + } + $parameterNode = new Variable($parameter->getName()); + $expressionTypes[$paramExprString] = ExpressionTypeHolder::createYes($parameterNode, $parameterType); + + $nativeParameterType = $parameter->getNativeType(); + if ($parameter->isVariadic()) { + if ($this->phpVersion->supportsNamedArguments() && $functionReflection->acceptsNamedArguments()) { + $nativeParameterType = new ArrayType(new UnionType([new IntegerType(), new StringType()]), $nativeParameterType); + } else { + $nativeParameterType = AccessoryArrayListType::intersectWith(new ArrayType(new IntegerType(), $nativeParameterType)); + } + } + $nativeExpressionTypes[$paramExprString] = ExpressionTypeHolder::createYes($parameterNode, $nativeParameterType); + } + + if ($preserveThis && array_key_exists('$this', $this->expressionTypes)) { + $expressionTypes['$this'] = $this->expressionTypes['$this']; + } + if ($preserveThis && array_key_exists('$this', $this->nativeExpressionTypes)) { + $nativeExpressionTypes['$this'] = $this->nativeExpressionTypes['$this']; + } + + return $this->scopeFactory->create( + $this->context, + $this->isDeclareStrictTypes(), + $functionReflection, + $this->getNamespace(), + array_merge($this->getConstantTypes(), $expressionTypes), + array_merge($this->getNativeConstantTypes(), $nativeExpressionTypes), + $conditionalTypes, + ); + } + /** @api */ - public function enterNamespace(string $namespaceName): self + public function enterNamespace(string $namespaceName): self { - return $this->scopeFactory->create($this->context->beginFile(), $this->isDeclareStrictTypes(), null, $namespaceName); + return $this->scopeFactory->create( + $this->context->beginFile(), + $this->isDeclareStrictTypes(), + null, + $namespaceName, + ); } /** - * @param list $scopeClasses - */ - public function enterClosureBind(?Type $thisType, ?Type $nativeThisType, array $scopeClasses): self + * @param list $scopeClasses + */ + public function enterClosureBind(?Type $thisType, ?Type $nativeThisType, array $scopeClasses): self { $expressionTypes = $this->expressionTypes; if ($thisType !== null) { @@ -2677,7 +2838,17 @@ public function enterClosureBind(?Type $thisType, ?Type $nativeThisType, array $ $scopeClasses = [$this->getClassReflection()->getName()]; } - return $this->scopeFactory->create($this->context, $this->isDeclareStrictTypes(), $this->getFunction(), $this->getNamespace(), $expressionTypes, $nativeExpressionTypes, $this->conditionalExpressions, $scopeClasses, $this->anonymousFunctionReflection); + return $this->scopeFactory->create( + $this->context, + $this->isDeclareStrictTypes(), + $this->getFunction(), + $this->getNamespace(), + $expressionTypes, + $nativeExpressionTypes, + $this->conditionalExpressions, + $scopeClasses, + $this->anonymousFunctionReflection, + ); } public function restoreOriginalScopeAfterClosureBind(self $originalScope): self @@ -2696,7 +2867,17 @@ public function restoreOriginalScopeAfterClosureBind(self $originalScope): self unset($nativeExpressionTypes['$this']); } - return $this->scopeFactory->create($this->context, $this->isDeclareStrictTypes(), $this->getFunction(), $this->getNamespace(), $expressionTypes, $nativeExpressionTypes, $this->conditionalExpressions, $originalScope->inClosureBindScopeClasses, $this->anonymousFunctionReflection); + return $this->scopeFactory->create( + $this->context, + $this->isDeclareStrictTypes(), + $this->getFunction(), + $this->getNamespace(), + $expressionTypes, + $nativeExpressionTypes, + $this->conditionalExpressions, + $originalScope->inClosureBindScopeClasses, + $this->anonymousFunctionReflection, + ); } public function enterClosureCall(Type $thisType, Type $nativeThisType): self @@ -2707,116 +2888,172 @@ public function enterClosureCall(Type $thisType, Type $nativeThisType): self $nativeExpressionTypes = $this->nativeExpressionTypes; $nativeExpressionTypes['$this'] = ExpressionTypeHolder::createYes(new Variable('this'), $nativeThisType); - return $this->scopeFactory->create($this->context, $this->isDeclareStrictTypes(), $this->getFunction(), $this->getNamespace(), $expressionTypes, $nativeExpressionTypes, $this->conditionalExpressions, $thisType->getObjectClassNames(), $this->anonymousFunctionReflection); + return $this->scopeFactory->create( + $this->context, + $this->isDeclareStrictTypes(), + $this->getFunction(), + $this->getNamespace(), + $expressionTypes, + $nativeExpressionTypes, + $this->conditionalExpressions, + $thisType->getObjectClassNames(), + $this->anonymousFunctionReflection, + ); } /** @api */ - public function isInClosureBind(): bool + public function isInClosureBind(): bool { return $this->inClosureBindScopeClasses !== []; } /** - * @api - * @param ParameterReflection[]|null $callableParameters - */ - public function enterAnonymousFunction(Expr\Closure $closure, ?array $callableParameters = null) : self - { - $anonymousFunctionReflection = $this->getType($closure); - if (!$anonymousFunctionReflection instanceof ClosureType) { - throw new ShouldNotHappenException(); - } - $scope = $this->enterAnonymousFunctionWithoutReflection($closure, $callableParameters); - return $this->scopeFactory->create($scope->context, $scope->isDeclareStrictTypes(), $scope->getFunction(), $scope->getNamespace(), $scope->expressionTypes, $scope->nativeExpressionTypes, [], $scope->inClosureBindScopeClasses, $anonymousFunctionReflection, true, [], [], $this->inFunctionCallsStack, false, $this, $this->nativeTypesPromoted); - } + * @api + * @param ParameterReflection[]|null $callableParameters + */ + public function enterAnonymousFunction( + Expr\Closure $closure, + ?array $callableParameters = null, + ): self + { + $anonymousFunctionReflection = $this->getType($closure); + if (!$anonymousFunctionReflection instanceof ClosureType) { + throw new ShouldNotHappenException(); + } + + $scope = $this->enterAnonymousFunctionWithoutReflection($closure, $callableParameters); + + return $this->scopeFactory->create( + $scope->context, + $scope->isDeclareStrictTypes(), + $scope->getFunction(), + $scope->getNamespace(), + $scope->expressionTypes, + $scope->nativeExpressionTypes, + [], + $scope->inClosureBindScopeClasses, + $anonymousFunctionReflection, + true, + [], + [], + $this->inFunctionCallsStack, + false, + $this, + $this->nativeTypesPromoted, + ); + } /** - * @param ParameterReflection[]|null $callableParameters - */ - private function enterAnonymousFunctionWithoutReflection(Expr\Closure $closure, ?array $callableParameters = null) : self - { - $expressionTypes = []; - $nativeTypes = []; - foreach ($closure->params as $i => $parameter) { - if (!$parameter->var instanceof Variable || !is_string($parameter->var->name)) { - throw new ShouldNotHappenException(); - } - $paramExprString = sprintf('$%s', $parameter->var->name); - $isNullable = $this->isParameterValueNullable($parameter); - $parameterType = $this->getFunctionType($parameter->type, $isNullable, $parameter->variadic); - if ($callableParameters !== null) { - if (isset($callableParameters[$i])) { - $parameterType = TypehintHelper::decideType($parameterType, $callableParameters[$i]->getType()); - } elseif (count($callableParameters) > 0) { - $lastParameter = $callableParameters[count($callableParameters) - 1]; - if ($lastParameter->isVariadic()) { - $parameterType = TypehintHelper::decideType($parameterType, $lastParameter->getType()); - } else { - $parameterType = TypehintHelper::decideType($parameterType, new MixedType()); - } - } else { - $parameterType = TypehintHelper::decideType($parameterType, new MixedType()); - } - } - $holder = ExpressionTypeHolder::createYes($parameter->var, $parameterType); - $expressionTypes[$paramExprString] = $holder; - $nativeTypes[$paramExprString] = $holder; - } - $nonRefVariableNames = []; - foreach ($closure->uses as $use) { - if (!is_string($use->var->name)) { - throw new ShouldNotHappenException(); - } - $variableName = $use->var->name; - $paramExprString = '$' . $use->var->name; - if ($use->byRef) { - $holder = ExpressionTypeHolder::createYes($use->var, new MixedType()); - $expressionTypes[$paramExprString] = $holder; - $nativeTypes[$paramExprString] = $holder; - continue; - } - $nonRefVariableNames[$variableName] = true; - if ($this->hasVariableType($variableName)->no()) { - $variableType = new ErrorType(); - $variableNativeType = new ErrorType(); - } else { - $variableType = $this->getVariableType($variableName); - $variableNativeType = $this->getNativeType($use->var); - } - $expressionTypes[$paramExprString] = ExpressionTypeHolder::createYes($use->var, $variableType); - $nativeTypes[$paramExprString] = ExpressionTypeHolder::createYes($use->var, $variableNativeType); - } - foreach ($this->invalidateStaticExpressions($this->expressionTypes) as $exprString => $typeHolder) { - $expr = $typeHolder->getExpr(); - if ($expr instanceof Variable) { - continue; - } - $variables = (new NodeFinder())->findInstanceOf([$expr], Variable::class); - if ($variables === [] && !$this->expressionTypeIsUnchangeable($typeHolder)) { - continue; - } - foreach ($variables as $variable) { - if (!$variable instanceof Variable) { - continue 2; - } - if (!is_string($variable->name)) { - continue 2; - } - if (!array_key_exists($variable->name, $nonRefVariableNames)) { - continue 2; - } - } - - $expressionTypes[$exprString] = $typeHolder; - } - if ($this->hasVariableType('this')->yes() && !$closure->static) { - $node = new Variable('this'); - $expressionTypes['$this'] = ExpressionTypeHolder::createYes($node, $this->getType($node)); - $nativeTypes['$this'] = ExpressionTypeHolder::createYes($node, $this->getNativeType($node)); - } - return $this->scopeFactory->create($this->context, $this->isDeclareStrictTypes(), $this->getFunction(), $this->getNamespace(), array_merge($this->getConstantTypes(), $expressionTypes), array_merge($this->getNativeConstantTypes(), $nativeTypes), [], $this->inClosureBindScopeClasses, new TrivialParametersAcceptor(), true, [], [], [], false, $this, $this->nativeTypesPromoted); + * @param ParameterReflection[]|null $callableParameters + */ + private function enterAnonymousFunctionWithoutReflection( + Expr\Closure $closure, + ?array $callableParameters = null, + ): self + { + $expressionTypes = []; + $nativeTypes = []; + foreach ($closure->params as $i => $parameter) { + if (!$parameter->var instanceof Variable || !is_string($parameter->var->name)) { + throw new ShouldNotHappenException(); + } + $paramExprString = sprintf('$%s', $parameter->var->name); + $isNullable = $this->isParameterValueNullable($parameter); + $parameterType = $this->getFunctionType($parameter->type, $isNullable, $parameter->variadic); + if ($callableParameters !== null) { + if (isset($callableParameters[$i])) { + $parameterType = TypehintHelper::decideType($parameterType, $callableParameters[$i]->getType()); + } elseif (count($callableParameters) > 0) { + $lastParameter = $callableParameters[count($callableParameters) - 1]; + if ($lastParameter->isVariadic()) { + $parameterType = TypehintHelper::decideType($parameterType, $lastParameter->getType()); + } else { + $parameterType = TypehintHelper::decideType($parameterType, new MixedType()); + } + } else { + $parameterType = TypehintHelper::decideType($parameterType, new MixedType()); + } + } + $holder = ExpressionTypeHolder::createYes($parameter->var, $parameterType); + $expressionTypes[$paramExprString] = $holder; + $nativeTypes[$paramExprString] = $holder; + } + + $nonRefVariableNames = []; + foreach ($closure->uses as $use) { + if (!is_string($use->var->name)) { + throw new ShouldNotHappenException(); + } + $variableName = $use->var->name; + $paramExprString = '$' . $use->var->name; + if ($use->byRef) { + $holder = ExpressionTypeHolder::createYes($use->var, new MixedType()); + $expressionTypes[$paramExprString] = $holder; + $nativeTypes[$paramExprString] = $holder; + continue; + } + $nonRefVariableNames[$variableName] = true; + if ($this->hasVariableType($variableName)->no()) { + $variableType = new ErrorType(); + $variableNativeType = new ErrorType(); + } else { + $variableType = $this->getVariableType($variableName); + $variableNativeType = $this->getNativeType($use->var); + } + $expressionTypes[$paramExprString] = ExpressionTypeHolder::createYes($use->var, $variableType); + $nativeTypes[$paramExprString] = ExpressionTypeHolder::createYes($use->var, $variableNativeType); + } + + foreach ($this->invalidateStaticExpressions($this->expressionTypes) as $exprString => $typeHolder) { + $expr = $typeHolder->getExpr(); + if ($expr instanceof Variable) { + continue; + } + $variables = (new NodeFinder())->findInstanceOf([$expr], Variable::class); + if ($variables === [] && !$this->expressionTypeIsUnchangeable($typeHolder)) { + continue; + } + foreach ($variables as $variable) { + if (!$variable instanceof Variable) { + continue 2; + } + if (!is_string($variable->name)) { + continue 2; + } + if (!array_key_exists($variable->name, $nonRefVariableNames)) { + continue 2; + } } + $expressionTypes[$exprString] = $typeHolder; + } + + if ($this->hasVariableType('this')->yes() && !$closure->static) { + $node = new Variable('this'); + $expressionTypes['$this'] = ExpressionTypeHolder::createYes($node, $this->getType($node)); + $nativeTypes['$this'] = ExpressionTypeHolder::createYes($node, $this->getNativeType($node)); + } + + return $this->scopeFactory->create( + $this->context, + $this->isDeclareStrictTypes(), + $this->getFunction(), + $this->getNamespace(), + array_merge($this->getConstantTypes(), $expressionTypes), + array_merge($this->getNativeConstantTypes(), $nativeTypes), + [], + $this->inClosureBindScopeClasses, + new TrivialParametersAcceptor(), + true, + [], + [], + [], + false, + $this, + $this->nativeTypesPromoted, + ); + } + private function expressionTypeIsUnchangeable(ExpressionTypeHolder $typeHolder): bool { $expr = $typeHolder->getExpr(); @@ -2832,17 +3069,18 @@ private function expressionTypeIsUnchangeable(ExpressionTypeHolder $typeHolder): } /** - * @param array $expressionTypes - * @return array - */ - private function invalidateStaticExpressions(array $expressionTypes): array + * @param array $expressionTypes + * @return array + */ + private function invalidateStaticExpressions(array $expressionTypes): array { $filteredExpressionTypes = []; $nodeFinder = new NodeFinder(); foreach ($expressionTypes as $exprString => $expressionType) { - $staticExpression = $nodeFinder->findFirst([$expressionType->getExpr()], static function ($node) { - return $node instanceof Expr\StaticCall || $node instanceof Expr\StaticPropertyFetch; - }); + $staticExpression = $nodeFinder->findFirst( + [$expressionType->getExpr()], + static fn ($node) => $node instanceof Expr\StaticCall || $node instanceof Expr\StaticPropertyFetch, + ); if ($staticExpression !== null) { continue; } @@ -2852,10 +3090,10 @@ private function invalidateStaticExpressions(array $expressionTypes): array } /** - * @api - * @param ParameterReflection[]|null $callableParameters - */ - public function enterArrowFunction(Expr\ArrowFunction $arrowFunction, ?array $callableParameters = null): self + * @api + * @param ParameterReflection[]|null $callableParameters + */ + public function enterArrowFunction(Expr\ArrowFunction $arrowFunction, ?array $callableParameters = null): self { $anonymousFunctionReflection = $this->getType($arrowFunction); if (!$anonymousFunctionReflection instanceof ClosureType) { @@ -2864,13 +3102,30 @@ public function enterArrowFunction(Expr\ArrowFunction $arrowFunction, ?array $ca $scope = $this->enterArrowFunctionWithoutReflection($arrowFunction, $callableParameters); - return $this->scopeFactory->create($scope->context, $scope->isDeclareStrictTypes(), $scope->getFunction(), $scope->getNamespace(), $scope->expressionTypes, $scope->nativeExpressionTypes, $scope->conditionalExpressions, $scope->inClosureBindScopeClasses, $anonymousFunctionReflection, true, [], [], $this->inFunctionCallsStack, $scope->afterExtractCall, $scope->parentScope, $this->nativeTypesPromoted); + return $this->scopeFactory->create( + $scope->context, + $scope->isDeclareStrictTypes(), + $scope->getFunction(), + $scope->getNamespace(), + $scope->expressionTypes, + $scope->nativeExpressionTypes, + $scope->conditionalExpressions, + $scope->inClosureBindScopeClasses, + $anonymousFunctionReflection, + true, + [], + [], + $this->inFunctionCallsStack, + $scope->afterExtractCall, + $scope->parentScope, + $this->nativeTypesPromoted, + ); } /** - * @param ParameterReflection[]|null $callableParameters - */ - private function enterArrowFunctionWithoutReflection(Expr\ArrowFunction $arrowFunction, ?array $callableParameters): self + * @param ParameterReflection[]|null $callableParameters + */ + private function enterArrowFunctionWithoutReflection(Expr\ArrowFunction $arrowFunction, ?array $callableParameters): self { $arrowFunctionScope = $this; foreach ($arrowFunction->params as $i => $parameter) { @@ -2906,7 +3161,24 @@ private function enterArrowFunctionWithoutReflection(Expr\ArrowFunction $arrowFu $arrowFunctionScope = $arrowFunctionScope->invalidateExpression(new Variable('this')); } - return $this->scopeFactory->create($arrowFunctionScope->context, $this->isDeclareStrictTypes(), $arrowFunctionScope->getFunction(), $arrowFunctionScope->getNamespace(), $this->invalidateStaticExpressions($arrowFunctionScope->expressionTypes), $arrowFunctionScope->nativeExpressionTypes, $arrowFunctionScope->conditionalExpressions, $arrowFunctionScope->inClosureBindScopeClasses, null, true, [], [], [], $arrowFunctionScope->afterExtractCall, $arrowFunctionScope->parentScope, $this->nativeTypesPromoted); + return $this->scopeFactory->create( + $arrowFunctionScope->context, + $this->isDeclareStrictTypes(), + $arrowFunctionScope->getFunction(), + $arrowFunctionScope->getNamespace(), + $this->invalidateStaticExpressions($arrowFunctionScope->expressionTypes), + $arrowFunctionScope->nativeExpressionTypes, + $arrowFunctionScope->conditionalExpressions, + $arrowFunctionScope->inClosureBindScopeClasses, + null, + true, + [], + [], + [], + $arrowFunctionScope->afterExtractCall, + $arrowFunctionScope->parentScope, + $this->nativeTypesPromoted, + ); } public function isParameterValueNullable(Node\Param $parameter): bool @@ -2919,20 +3191,30 @@ public function isParameterValueNullable(Node\Param $parameter): bool } /** - * @api - * @param Node\Name|Node\Identifier|Node\ComplexType|null $type - */ - public function getFunctionType($type, bool $isNullable, bool $isVariadic): Type + * @api + * @param Node\Name|Node\Identifier|Node\ComplexType|null $type + */ + public function getFunctionType($type, bool $isNullable, bool $isVariadic): Type { if ($isNullable) { - return TypeCombinator::addNull($this->getFunctionType($type, false, $isVariadic)); + return TypeCombinator::addNull( + $this->getFunctionType($type, false, $isVariadic), + ); } if ($isVariadic) { if ($this->phpVersion->supportsNamedArguments()) { - return new ArrayType(new UnionType([new IntegerType(), new StringType()]), $this->getFunctionType($type, false, false)); + return new ArrayType(new UnionType([new IntegerType(), new StringType()]), $this->getFunctionType( + $type, + false, + false, + )); } - return AccessoryArrayListType::intersectWith(new ArrayType(new IntegerType(), $this->getFunctionType($type, false, false))); + return AccessoryArrayListType::intersectWith(new ArrayType(new IntegerType(), $this->getFunctionType( + $type, + false, + false, + ))); } if ($type instanceof Name) { @@ -2971,7 +3253,11 @@ public function enterForeach(self $originalScope, Expr $iteratee, string $valueN { $iterateeType = $originalScope->getType($iteratee); $nativeIterateeType = $originalScope->getNativeType($iteratee); - $scope = $this->assignVariable($valueName, $originalScope->getIterableValueType($iterateeType), $originalScope->getIterableValueType($nativeIterateeType)); + $scope = $this->assignVariable( + $valueName, + $originalScope->getIterableValueType($iterateeType), + $originalScope->getIterableValueType($nativeIterateeType), + ); if ($keyName !== null) { $scope = $scope->enterForeachKey($originalScope, $iteratee, $keyName); } @@ -2983,24 +3269,30 @@ public function enterForeachKey(self $originalScope, Expr $iteratee, string $key { $iterateeType = $originalScope->getType($iteratee); $nativeIterateeType = $originalScope->getNativeType($iteratee); - $scope = $this->assignVariable($keyName, $originalScope->getIterableKeyType($iterateeType), $originalScope->getIterableKeyType($nativeIterateeType)); + $scope = $this->assignVariable( + $keyName, + $originalScope->getIterableKeyType($iterateeType), + $originalScope->getIterableKeyType($nativeIterateeType), + ); if ($iterateeType->isArray()->yes()) { - $scope = $scope->assignExpression(new Expr\ArrayDimFetch($iteratee, new Variable($keyName)), $originalScope->getIterableValueType($iterateeType), $originalScope->getIterableValueType($nativeIterateeType)); + $scope = $scope->assignExpression( + new Expr\ArrayDimFetch($iteratee, new Variable($keyName)), + $originalScope->getIterableValueType($iterateeType), + $originalScope->getIterableValueType($nativeIterateeType), + ); } return $scope; } /** - * @deprecated Use enterCatchType - * @param Node\Name[] $classes - */ - public function enterCatch(array $classes, ?string $variableName): self + * @deprecated Use enterCatchType + * @param Node\Name[] $classes + */ + public function enterCatch(array $classes, ?string $variableName): self { - $type = TypeCombinator::union(...array_map(static function (Node\Name $class) : ObjectType { - return new ObjectType((string) $class); - }, $classes)); + $type = TypeCombinator::union(...array_map(static fn (Node\Name $class): ObjectType => new ObjectType((string) $class), $classes)); return $this->enterCatchType($type, $variableName); } @@ -3011,7 +3303,11 @@ public function enterCatchType(Type $catchType, ?string $variableName): self return $this; } - return $this->assignVariable($variableName, TypeCombinator::intersect($catchType, new ObjectType(Throwable::class)), TypeCombinator::intersect($catchType, new ObjectType(Throwable::class))); + return $this->assignVariable( + $variableName, + TypeCombinator::intersect($catchType, new ObjectType(Throwable::class)), + TypeCombinator::intersect($catchType, new ObjectType(Throwable::class)), + ); } public function enterExpressionAssign(Expr $expr): self @@ -3020,7 +3316,24 @@ public function enterExpressionAssign(Expr $expr): self $currentlyAssignedExpressions = $this->currentlyAssignedExpressions; $currentlyAssignedExpressions[$exprString] = true; - $scope = $this->scopeFactory->create($this->context, $this->isDeclareStrictTypes(), $this->getFunction(), $this->getNamespace(), $this->expressionTypes, $this->nativeExpressionTypes, $this->conditionalExpressions, $this->inClosureBindScopeClasses, $this->anonymousFunctionReflection, $this->isInFirstLevelStatement(), $currentlyAssignedExpressions, $this->currentlyAllowedUndefinedExpressions, [], $this->afterExtractCall, $this->parentScope, $this->nativeTypesPromoted); + $scope = $this->scopeFactory->create( + $this->context, + $this->isDeclareStrictTypes(), + $this->getFunction(), + $this->getNamespace(), + $this->expressionTypes, + $this->nativeExpressionTypes, + $this->conditionalExpressions, + $this->inClosureBindScopeClasses, + $this->anonymousFunctionReflection, + $this->isInFirstLevelStatement(), + $currentlyAssignedExpressions, + $this->currentlyAllowedUndefinedExpressions, + [], + $this->afterExtractCall, + $this->parentScope, + $this->nativeTypesPromoted, + ); $scope->resolvedTypes = $this->resolvedTypes; $scope->truthyScopes = $this->truthyScopes; $scope->falseyScopes = $this->falseyScopes; @@ -3034,7 +3347,24 @@ public function exitExpressionAssign(Expr $expr): self $currentlyAssignedExpressions = $this->currentlyAssignedExpressions; unset($currentlyAssignedExpressions[$exprString]); - $scope = $this->scopeFactory->create($this->context, $this->isDeclareStrictTypes(), $this->getFunction(), $this->getNamespace(), $this->expressionTypes, $this->nativeExpressionTypes, $this->conditionalExpressions, $this->inClosureBindScopeClasses, $this->anonymousFunctionReflection, $this->isInFirstLevelStatement(), $currentlyAssignedExpressions, $this->currentlyAllowedUndefinedExpressions, [], $this->afterExtractCall, $this->parentScope, $this->nativeTypesPromoted); + $scope = $this->scopeFactory->create( + $this->context, + $this->isDeclareStrictTypes(), + $this->getFunction(), + $this->getNamespace(), + $this->expressionTypes, + $this->nativeExpressionTypes, + $this->conditionalExpressions, + $this->inClosureBindScopeClasses, + $this->anonymousFunctionReflection, + $this->isInFirstLevelStatement(), + $currentlyAssignedExpressions, + $this->currentlyAllowedUndefinedExpressions, + [], + $this->afterExtractCall, + $this->parentScope, + $this->nativeTypesPromoted, + ); $scope->resolvedTypes = $this->resolvedTypes; $scope->truthyScopes = $this->truthyScopes; $scope->falseyScopes = $this->falseyScopes; @@ -3043,7 +3373,7 @@ public function exitExpressionAssign(Expr $expr): self } /** @api */ - public function isInExpressionAssign(Expr $expr): bool + public function isInExpressionAssign(Expr $expr): bool { $exprString = $this->getNodeKey($expr); return array_key_exists($exprString, $this->currentlyAssignedExpressions); @@ -3059,7 +3389,24 @@ public function setAllowedUndefinedExpression(Expr $expr): self $currentlyAllowedUndefinedExpressions = $this->currentlyAllowedUndefinedExpressions; $currentlyAllowedUndefinedExpressions[$exprString] = true; - $scope = $this->scopeFactory->create($this->context, $this->isDeclareStrictTypes(), $this->getFunction(), $this->getNamespace(), $this->expressionTypes, $this->nativeExpressionTypes, $this->conditionalExpressions, $this->inClosureBindScopeClasses, $this->anonymousFunctionReflection, $this->isInFirstLevelStatement(), $this->currentlyAssignedExpressions, $currentlyAllowedUndefinedExpressions, [], $this->afterExtractCall, $this->parentScope, $this->nativeTypesPromoted); + $scope = $this->scopeFactory->create( + $this->context, + $this->isDeclareStrictTypes(), + $this->getFunction(), + $this->getNamespace(), + $this->expressionTypes, + $this->nativeExpressionTypes, + $this->conditionalExpressions, + $this->inClosureBindScopeClasses, + $this->anonymousFunctionReflection, + $this->isInFirstLevelStatement(), + $this->currentlyAssignedExpressions, + $currentlyAllowedUndefinedExpressions, + [], + $this->afterExtractCall, + $this->parentScope, + $this->nativeTypesPromoted, + ); $scope->resolvedTypes = $this->resolvedTypes; $scope->truthyScopes = $this->truthyScopes; $scope->falseyScopes = $this->falseyScopes; @@ -3073,7 +3420,24 @@ public function unsetAllowedUndefinedExpression(Expr $expr): self $currentlyAllowedUndefinedExpressions = $this->currentlyAllowedUndefinedExpressions; unset($currentlyAllowedUndefinedExpressions[$exprString]); - $scope = $this->scopeFactory->create($this->context, $this->isDeclareStrictTypes(), $this->getFunction(), $this->getNamespace(), $this->expressionTypes, $this->nativeExpressionTypes, $this->conditionalExpressions, $this->inClosureBindScopeClasses, $this->anonymousFunctionReflection, $this->isInFirstLevelStatement(), $this->currentlyAssignedExpressions, $currentlyAllowedUndefinedExpressions, [], $this->afterExtractCall, $this->parentScope, $this->nativeTypesPromoted); + $scope = $this->scopeFactory->create( + $this->context, + $this->isDeclareStrictTypes(), + $this->getFunction(), + $this->getNamespace(), + $this->expressionTypes, + $this->nativeExpressionTypes, + $this->conditionalExpressions, + $this->inClosureBindScopeClasses, + $this->anonymousFunctionReflection, + $this->isInFirstLevelStatement(), + $this->currentlyAssignedExpressions, + $currentlyAllowedUndefinedExpressions, + [], + $this->afterExtractCall, + $this->parentScope, + $this->nativeTypesPromoted, + ); $scope->resolvedTypes = $this->resolvedTypes; $scope->truthyScopes = $this->truthyScopes; $scope->falseyScopes = $this->falseyScopes; @@ -3082,7 +3446,7 @@ public function unsetAllowedUndefinedExpression(Expr $expr): self } /** @api */ - public function isUndefinedExpressionAllowed(Expr $expr): bool + public function isUndefinedExpressionAllowed(Expr $expr): bool { $exprString = $this->getNodeKey($expr); return array_key_exists($exprString, $this->currentlyAllowedUndefinedExpressions); @@ -3115,10 +3479,28 @@ public function unsetExpression(Expr $expr): self $exprVarNativeType = $scope->getNativeType($expr->var); $dimNativeType = $scope->getNativeType($expr->dim); $unsetNativeType = $exprVarNativeType->unsetOffset($dimNativeType); - $scope = $scope->assignExpression($expr->var, $unsetType, $unsetNativeType)->invalidateExpression(new FuncCall(new FullyQualified('count'), [new Arg($expr->var)]))->invalidateExpression(new FuncCall(new FullyQualified('sizeof'), [new Arg($expr->var)]))->invalidateExpression(new FuncCall(new Name('count'), [new Arg($expr->var)]))->invalidateExpression(new FuncCall(new Name('sizeof'), [new Arg($expr->var)])); + $scope = $scope->assignExpression($expr->var, $unsetType, $unsetNativeType)->invalidateExpression( + new FuncCall(new FullyQualified('count'), [new Arg($expr->var)]), + )->invalidateExpression( + new FuncCall(new FullyQualified('sizeof'), [new Arg($expr->var)]), + )->invalidateExpression( + new FuncCall(new Name('count'), [new Arg($expr->var)]), + )->invalidateExpression( + new FuncCall(new Name('sizeof'), [new Arg($expr->var)]), + ); if ($expr->var instanceof Expr\ArrayDimFetch && $expr->var->dim !== null) { - $scope = $scope->assignExpression($expr->var->var, $this->getType($expr->var->var)->setOffsetValueType($scope->getType($expr->var->dim), $scope->getType($expr->var)), $this->getNativeType($expr->var->var)->setOffsetValueType($scope->getNativeType($expr->var->dim), $scope->getNativeType($expr->var))); + $scope = $scope->assignExpression( + $expr->var->var, + $this->getType($expr->var->var)->setOffsetValueType( + $scope->getType($expr->var->dim), + $scope->getType($expr->var), + ), + $this->getNativeType($expr->var->var)->setOffsetValueType( + $scope->getNativeType($expr->var->dim), + $scope->getNativeType($expr->var), + ), + ); } } @@ -3160,7 +3542,15 @@ public function specifyExpressionType(Expr $expr, Type $type, Type $nativeType, $types[] = new StringType(); } - $scope = $scope->specifyExpressionType($expr->var, TypeCombinator::intersect(TypeCombinator::intersect($exprVarType, TypeCombinator::union(...$types)), new HasOffsetValueType($dimType, $type)), $scope->getNativeType($expr->var), $certainty); + $scope = $scope->specifyExpressionType( + $expr->var, + TypeCombinator::intersect( + TypeCombinator::intersect($exprVarType, TypeCombinator::union(...$types)), + new HasOffsetValueType($dimType, $type), + ), + $scope->getNativeType($expr->var), + $certainty, + ); } } } @@ -3177,7 +3567,24 @@ public function specifyExpressionType(Expr $expr, Type $type, Type $nativeType, $nativeTypes = $scope->nativeExpressionTypes; $nativeTypes[$exprString] = new ExpressionTypeHolder($expr, $nativeType, $certainty); - return $this->scopeFactory->create($this->context, $this->isDeclareStrictTypes(), $this->getFunction(), $this->getNamespace(), $expressionTypes, $nativeTypes, $this->conditionalExpressions, $this->inClosureBindScopeClasses, $this->anonymousFunctionReflection, $this->inFirstLevelStatement, $this->currentlyAssignedExpressions, $this->currentlyAllowedUndefinedExpressions, $this->inFunctionCallsStack, $this->afterExtractCall, $this->parentScope, $this->nativeTypesPromoted); + return $this->scopeFactory->create( + $this->context, + $this->isDeclareStrictTypes(), + $this->getFunction(), + $this->getNamespace(), + $expressionTypes, + $nativeTypes, + $this->conditionalExpressions, + $this->inClosureBindScopeClasses, + $this->anonymousFunctionReflection, + $this->inFirstLevelStatement, + $this->currentlyAssignedExpressions, + $this->currentlyAllowedUndefinedExpressions, + $this->inFunctionCallsStack, + $this->afterExtractCall, + $this->parentScope, + $this->nativeTypesPromoted, + ); } public function assignExpression(Expr $expr, Type $type, ?Type $nativeType = null): self @@ -3266,7 +3673,24 @@ public function invalidateExpression(Expr $expressionToInvalidate, bool $require return $this; } - return $this->scopeFactory->create($this->context, $this->isDeclareStrictTypes(), $this->getFunction(), $this->getNamespace(), $expressionTypes, $nativeExpressionTypes, $newConditionalExpressions, $this->inClosureBindScopeClasses, $this->anonymousFunctionReflection, $this->inFirstLevelStatement, $this->currentlyAssignedExpressions, $this->currentlyAllowedUndefinedExpressions, [], $this->afterExtractCall, $this->parentScope, $this->nativeTypesPromoted); + return $this->scopeFactory->create( + $this->context, + $this->isDeclareStrictTypes(), + $this->getFunction(), + $this->getNamespace(), + $expressionTypes, + $nativeExpressionTypes, + $newConditionalExpressions, + $this->inClosureBindScopeClasses, + $this->anonymousFunctionReflection, + $this->inFirstLevelStatement, + $this->currentlyAssignedExpressions, + $this->currentlyAllowedUndefinedExpressions, + [], + $this->afterExtractCall, + $this->parentScope, + $this->nativeTypesPromoted, + ); } private function shouldInvalidateExpression(string $exprStringToInvalidate, Expr $exprToInvalidate, Expr $expr, bool $requireMoreCharacters = false): bool @@ -3338,7 +3762,24 @@ private function invalidateMethodsOnExpression(Expr $expressionToInvalidate): se return $this; } - return $this->scopeFactory->create($this->context, $this->isDeclareStrictTypes(), $this->getFunction(), $this->getNamespace(), $expressionTypes, $nativeExpressionTypes, $this->conditionalExpressions, $this->inClosureBindScopeClasses, $this->anonymousFunctionReflection, $this->inFirstLevelStatement, $this->currentlyAssignedExpressions, $this->currentlyAllowedUndefinedExpressions, [], $this->afterExtractCall, $this->parentScope, $this->nativeTypesPromoted); + return $this->scopeFactory->create( + $this->context, + $this->isDeclareStrictTypes(), + $this->getFunction(), + $this->getNamespace(), + $expressionTypes, + $nativeExpressionTypes, + $this->conditionalExpressions, + $this->inClosureBindScopeClasses, + $this->anonymousFunctionReflection, + $this->inFirstLevelStatement, + $this->currentlyAssignedExpressions, + $this->currentlyAllowedUndefinedExpressions, + [], + $this->afterExtractCall, + $this->parentScope, + $this->nativeTypesPromoted, + ); } private function setExpressionCertainty(Expr $expr, TrinaryLogic $certainty): self @@ -3350,7 +3791,12 @@ private function setExpressionCertainty(Expr $expr, TrinaryLogic $certainty): se $originalExprType = $this->getType($expr); $nativeType = $this->getNativeType($expr); - return $this->specifyExpressionType($expr, $originalExprType, $nativeType, $certainty); + return $this->specifyExpressionType( + $expr, + $originalExprType, + $nativeType, + $certainty, + ); } private function addTypeToExpression(Expr $expr, Type $type): self @@ -3363,7 +3809,11 @@ private function addTypeToExpression(Expr $expr, Type $type): self return $this->specifyExpressionType($expr, $newType, $newType); } - return $this->specifyExpressionType($expr, TypeCombinator::intersect($type, $originalExprType), TypeCombinator::intersect($type, $nativeType)); + return $this->specifyExpressionType( + $expr, + TypeCombinator::intersect($type, $originalExprType), + TypeCombinator::intersect($type, $nativeType), + ); } public function removeTypeFromExpression(Expr $expr, Type $typeToRemove): self @@ -3375,14 +3825,18 @@ public function removeTypeFromExpression(Expr $expr, Type $typeToRemove): self ) { return $this; } - return $this->specifyExpressionType($expr, TypeCombinator::remove($exprType, $typeToRemove), TypeCombinator::remove($this->getNativeType($expr), $typeToRemove)); + return $this->specifyExpressionType( + $expr, + TypeCombinator::remove($exprType, $typeToRemove), + TypeCombinator::remove($this->getNativeType($expr), $typeToRemove), + ); } /** - * @api - * @return MutatingScope - */ - public function filterByTruthyValue(Expr $expr): Scope + * @api + * @return MutatingScope + */ + public function filterByTruthyValue(Expr $expr): Scope { $exprString = $this->getNodeKey($expr); if (array_key_exists($exprString, $this->truthyScopes)) { @@ -3397,10 +3851,10 @@ public function filterByTruthyValue(Expr $expr): Scope } /** - * @api - * @return MutatingScope - */ - public function filterByFalseyValue(Expr $expr): Scope + * @api + * @return MutatingScope + */ + public function filterByFalseyValue(Expr $expr): Scope { $exprString = $this->getNodeKey($expr); if (array_key_exists($exprString, $this->falseyScopes)) { @@ -3460,7 +3914,10 @@ public function filterBySpecifiedTypes(SpecifiedTypes $specifiedTypes): self $expr = $issetExpr->getExpr(); if ($typeSpecification['sure']) { - $scope = $scope->setExpressionCertainty($expr, TrinaryLogic::createMaybe()); + $scope = $scope->setExpressionCertainty( + $expr, + TrinaryLogic::createMaybe(), + ); } else { $scope = $scope->unsetExpression($expr); } @@ -3495,33 +3952,67 @@ public function filterBySpecifiedTypes(SpecifiedTypes $specifiedTypes): self } foreach ($conditions as $conditionalExprString => $expressions) { - $certainty = TrinaryLogic::lazyExtremeIdentity($expressions, static function (ConditionalExpressionHolder $holder) { - return $holder->getTypeHolder()->getCertainty(); - }); + $certainty = TrinaryLogic::lazyExtremeIdentity($expressions, static fn (ConditionalExpressionHolder $holder) => $holder->getTypeHolder()->getCertainty()); if ($certainty->no()) { unset($scope->expressionTypes[$conditionalExprString]); } else { - $type = TypeCombinator::intersect(...array_map(static function (ConditionalExpressionHolder $holder) { - return $holder->getTypeHolder()->getType(); - }, $expressions)); + $type = TypeCombinator::intersect(...array_map(static fn (ConditionalExpressionHolder $holder) => $holder->getTypeHolder()->getType(), $expressions)); $scope->expressionTypes[$conditionalExprString] = array_key_exists($conditionalExprString, $scope->expressionTypes) - ? new ExpressionTypeHolder($scope->expressionTypes[$conditionalExprString]->getExpr(), TypeCombinator::intersect($scope->expressionTypes[$conditionalExprString]->getType(), $type), TrinaryLogic::maxMin($scope->expressionTypes[$conditionalExprString]->getCertainty(), $certainty)) + ? new ExpressionTypeHolder( + $scope->expressionTypes[$conditionalExprString]->getExpr(), + TypeCombinator::intersect($scope->expressionTypes[$conditionalExprString]->getType(), $type), + TrinaryLogic::maxMin($scope->expressionTypes[$conditionalExprString]->getCertainty(), $certainty), + ) : $expressions[0]->getTypeHolder(); } } - return $scope->scopeFactory->create($scope->context, $scope->isDeclareStrictTypes(), $scope->getFunction(), $scope->getNamespace(), $scope->expressionTypes, $scope->nativeExpressionTypes, array_merge($specifiedTypes->getNewConditionalExpressionHolders(), $scope->conditionalExpressions), $scope->inClosureBindScopeClasses, $scope->anonymousFunctionReflection, $scope->inFirstLevelStatement, $scope->currentlyAssignedExpressions, $scope->currentlyAllowedUndefinedExpressions, $scope->inFunctionCallsStack, $scope->afterExtractCall, $scope->parentScope, $scope->nativeTypesPromoted); + return $scope->scopeFactory->create( + $scope->context, + $scope->isDeclareStrictTypes(), + $scope->getFunction(), + $scope->getNamespace(), + $scope->expressionTypes, + $scope->nativeExpressionTypes, + array_merge($specifiedTypes->getNewConditionalExpressionHolders(), $scope->conditionalExpressions), + $scope->inClosureBindScopeClasses, + $scope->anonymousFunctionReflection, + $scope->inFirstLevelStatement, + $scope->currentlyAssignedExpressions, + $scope->currentlyAllowedUndefinedExpressions, + $scope->inFunctionCallsStack, + $scope->afterExtractCall, + $scope->parentScope, + $scope->nativeTypesPromoted, + ); } /** - * @param ConditionalExpressionHolder[] $conditionalExpressionHolders - */ - public function addConditionalExpressions(string $exprString, array $conditionalExpressionHolders): self + * @param ConditionalExpressionHolder[] $conditionalExpressionHolders + */ + public function addConditionalExpressions(string $exprString, array $conditionalExpressionHolders): self { $conditionalExpressions = $this->conditionalExpressions; $conditionalExpressions[$exprString] = $conditionalExpressionHolders; - return $this->scopeFactory->create($this->context, $this->isDeclareStrictTypes(), $this->getFunction(), $this->getNamespace(), $this->expressionTypes, $this->nativeExpressionTypes, $conditionalExpressions, $this->inClosureBindScopeClasses, $this->anonymousFunctionReflection, $this->inFirstLevelStatement, $this->currentlyAssignedExpressions, $this->currentlyAllowedUndefinedExpressions, $this->inFunctionCallsStack, $this->afterExtractCall, $this->parentScope, $this->nativeTypesPromoted); + return $this->scopeFactory->create( + $this->context, + $this->isDeclareStrictTypes(), + $this->getFunction(), + $this->getNamespace(), + $this->expressionTypes, + $this->nativeExpressionTypes, + $conditionalExpressions, + $this->inClosureBindScopeClasses, + $this->anonymousFunctionReflection, + $this->inFirstLevelStatement, + $this->currentlyAssignedExpressions, + $this->currentlyAllowedUndefinedExpressions, + $this->inFunctionCallsStack, + $this->afterExtractCall, + $this->parentScope, + $this->nativeTypesPromoted, + ); } public function exitFirstLevelStatements(): self @@ -3534,7 +4025,24 @@ public function exitFirstLevelStatements(): self return $this->scopeOutOfFirstLevelStatement; } - $scope = $this->scopeFactory->create($this->context, $this->isDeclareStrictTypes(), $this->getFunction(), $this->getNamespace(), $this->expressionTypes, $this->nativeExpressionTypes, $this->conditionalExpressions, $this->inClosureBindScopeClasses, $this->anonymousFunctionReflection, false, $this->currentlyAssignedExpressions, $this->currentlyAllowedUndefinedExpressions, $this->inFunctionCallsStack, $this->afterExtractCall, $this->parentScope, $this->nativeTypesPromoted); + $scope = $this->scopeFactory->create( + $this->context, + $this->isDeclareStrictTypes(), + $this->getFunction(), + $this->getNamespace(), + $this->expressionTypes, + $this->nativeExpressionTypes, + $this->conditionalExpressions, + $this->inClosureBindScopeClasses, + $this->anonymousFunctionReflection, + false, + $this->currentlyAssignedExpressions, + $this->currentlyAllowedUndefinedExpressions, + $this->inFunctionCallsStack, + $this->afterExtractCall, + $this->parentScope, + $this->nativeTypesPromoted, + ); $scope->resolvedTypes = $this->resolvedTypes; $scope->truthyScopes = $this->truthyScopes; $scope->falseyScopes = $this->falseyScopes; @@ -3544,7 +4052,7 @@ public function exitFirstLevelStatements(): self } /** @api */ - public function isInFirstLevelStatement(): bool + public function isInFirstLevelStatement(): bool { return $this->inFirstLevelStatement; } @@ -3559,16 +4067,43 @@ public function mergeWith(?self $otherScope): self $mergedExpressionTypes = $this->mergeVariableHolders($ourExpressionTypes, $theirExpressionTypes); $conditionalExpressions = $this->intersectConditionalExpressions($otherScope->conditionalExpressions); - $conditionalExpressions = $this->createConditionalExpressions($conditionalExpressions, $ourExpressionTypes, $theirExpressionTypes, $mergedExpressionTypes); - $conditionalExpressions = $this->createConditionalExpressions($conditionalExpressions, $theirExpressionTypes, $ourExpressionTypes, $mergedExpressionTypes); - return $this->scopeFactory->create($this->context, $this->isDeclareStrictTypes(), $this->getFunction(), $this->getNamespace(), $mergedExpressionTypes, $this->mergeVariableHolders($this->nativeExpressionTypes, $otherScope->nativeExpressionTypes), $conditionalExpressions, $this->inClosureBindScopeClasses, $this->anonymousFunctionReflection, $this->inFirstLevelStatement, [], [], [], $this->afterExtractCall && $otherScope->afterExtractCall, $this->parentScope, $this->nativeTypesPromoted); + $conditionalExpressions = $this->createConditionalExpressions( + $conditionalExpressions, + $ourExpressionTypes, + $theirExpressionTypes, + $mergedExpressionTypes, + ); + $conditionalExpressions = $this->createConditionalExpressions( + $conditionalExpressions, + $theirExpressionTypes, + $ourExpressionTypes, + $mergedExpressionTypes, + ); + return $this->scopeFactory->create( + $this->context, + $this->isDeclareStrictTypes(), + $this->getFunction(), + $this->getNamespace(), + $mergedExpressionTypes, + $this->mergeVariableHolders($this->nativeExpressionTypes, $otherScope->nativeExpressionTypes), + $conditionalExpressions, + $this->inClosureBindScopeClasses, + $this->anonymousFunctionReflection, + $this->inFirstLevelStatement, + [], + [], + [], + $this->afterExtractCall && $otherScope->afterExtractCall, + $this->parentScope, + $this->nativeTypesPromoted, + ); } /** - * @param array $otherConditionalExpressions - * @return array - */ - private function intersectConditionalExpressions(array $otherConditionalExpressions): array + * @param array $otherConditionalExpressions + * @return array + */ + private function intersectConditionalExpressions(array $otherConditionalExpressions): array { $newConditionalExpressions = []; foreach ($this->conditionalExpressions as $exprString => $holders) { @@ -3590,78 +4125,88 @@ private function intersectConditionalExpressions(array $otherConditionalExpressi } /** - * @param array $conditionalExpressions - * @param array $ourExpressionTypes - * @param array $theirExpressionTypes - * @param array $mergedExpressionTypes - * @return array - */ - private function createConditionalExpressions(array $conditionalExpressions, array $ourExpressionTypes, array $theirExpressionTypes, array $mergedExpressionTypes) : array - { - $newVariableTypes = $ourExpressionTypes; - foreach ($theirExpressionTypes as $exprString => $holder) { - if (!array_key_exists($exprString, $mergedExpressionTypes)) { - continue; - } - - if (!$mergedExpressionTypes[$exprString]->getType()->equals($holder->getType())) { - continue; - } - - unset($newVariableTypes[$exprString]); - } - $typeGuards = []; - foreach ($newVariableTypes as $exprString => $holder) { - if (!$holder->getCertainty()->yes()) { - continue; - } - if (!array_key_exists($exprString, $mergedExpressionTypes)) { - continue; - } - if ($mergedExpressionTypes[$exprString]->getType()->equals($holder->getType())) { - continue; - } - - $typeGuards[$exprString] = $holder; - } - if (count($typeGuards) === 0) { - return $conditionalExpressions; - } - foreach ($newVariableTypes as $exprString => $holder) { - if ( - array_key_exists($exprString, $mergedExpressionTypes) - && $mergedExpressionTypes[$exprString]->equals($holder) - ) { - continue; - } - - $variableTypeGuards = $typeGuards; - unset($variableTypeGuards[$exprString]); - - if (count($variableTypeGuards) === 0) { - continue; - } - - $conditionalExpression = new ConditionalExpressionHolder($variableTypeGuards, $holder); - $conditionalExpressions[$exprString][$conditionalExpression->getKey()] = $conditionalExpression; - } - foreach ($mergedExpressionTypes as $exprString => $mergedExprTypeHolder) { - if (array_key_exists($exprString, $ourExpressionTypes)) { - continue; - } - - $conditionalExpression = new ConditionalExpressionHolder($typeGuards, new ExpressionTypeHolder($mergedExprTypeHolder->getExpr(), new ErrorType(), TrinaryLogic::createNo())); - $conditionalExpressions[$exprString][$conditionalExpression->getKey()] = $conditionalExpression; - } - return $conditionalExpressions; + * @param array $conditionalExpressions + * @param array $ourExpressionTypes + * @param array $theirExpressionTypes + * @param array $mergedExpressionTypes + * @return array + */ + private function createConditionalExpressions( + array $conditionalExpressions, + array $ourExpressionTypes, + array $theirExpressionTypes, + array $mergedExpressionTypes, + ): array + { + $newVariableTypes = $ourExpressionTypes; + foreach ($theirExpressionTypes as $exprString => $holder) { + if (!array_key_exists($exprString, $mergedExpressionTypes)) { + continue; + } + + if (!$mergedExpressionTypes[$exprString]->getType()->equals($holder->getType())) { + continue; + } + + unset($newVariableTypes[$exprString]); + } + + $typeGuards = []; + foreach ($newVariableTypes as $exprString => $holder) { + if (!$holder->getCertainty()->yes()) { + continue; + } + if (!array_key_exists($exprString, $mergedExpressionTypes)) { + continue; + } + if ($mergedExpressionTypes[$exprString]->getType()->equals($holder->getType())) { + continue; + } + + $typeGuards[$exprString] = $holder; + } + + if (count($typeGuards) === 0) { + return $conditionalExpressions; + } + + foreach ($newVariableTypes as $exprString => $holder) { + if ( + array_key_exists($exprString, $mergedExpressionTypes) + && $mergedExpressionTypes[$exprString]->equals($holder) + ) { + continue; + } + + $variableTypeGuards = $typeGuards; + unset($variableTypeGuards[$exprString]); + + if (count($variableTypeGuards) === 0) { + continue; } + $conditionalExpression = new ConditionalExpressionHolder($variableTypeGuards, $holder); + $conditionalExpressions[$exprString][$conditionalExpression->getKey()] = $conditionalExpression; + } + + foreach ($mergedExpressionTypes as $exprString => $mergedExprTypeHolder) { + if (array_key_exists($exprString, $ourExpressionTypes)) { + continue; + } + + $conditionalExpression = new ConditionalExpressionHolder($typeGuards, new ExpressionTypeHolder($mergedExprTypeHolder->getExpr(), new ErrorType(), TrinaryLogic::createNo())); + $conditionalExpressions[$exprString][$conditionalExpression->getKey()] = $conditionalExpression; + } + + return $conditionalExpressions; + } + /** - * @param array $ourVariableTypeHolders - * @param array $theirVariableTypeHolders - * @return array - */ - private function mergeVariableHolders(array $ourVariableTypeHolders, array $theirVariableTypeHolders): array + * @param array $ourVariableTypeHolders + * @param array $theirVariableTypeHolders + * @return array + */ + private function mergeVariableHolders(array $ourVariableTypeHolders, array $theirVariableTypeHolders): array { $intersectedVariableTypeHolders = []; foreach ($ourVariableTypeHolders as $exprString => $variableTypeHolder) { @@ -3701,7 +4246,11 @@ public function mergeInitializedProperties(self $calledMethodScope): self $certainty = $scope->expressionTypes[$exprString]->getCertainty(); $scope = $scope->assignExpression($propertyExpr, new MixedType(), new MixedType()); - $scope->expressionTypes[$exprString] = new ExpressionTypeHolder($typeHolder->getExpr(), $typeHolder->getType(), $typeHolder->getCertainty()->or($certainty)); + $scope->expressionTypes[$exprString] = new ExpressionTypeHolder( + $typeHolder->getExpr(), + $typeHolder->getType(), + $typeHolder->getCertainty()->or($certainty), + ); } return $scope; @@ -3709,76 +4258,129 @@ public function mergeInitializedProperties(self $calledMethodScope): self public function processFinallyScope(self $finallyScope, self $originalFinallyScope): self { - return $this->scopeFactory->create($this->context, $this->isDeclareStrictTypes(), $this->getFunction(), $this->getNamespace(), $this->processFinallyScopeVariableTypeHolders($this->expressionTypes, $finallyScope->expressionTypes, $originalFinallyScope->expressionTypes), $this->processFinallyScopeVariableTypeHolders($this->nativeExpressionTypes, $finallyScope->nativeExpressionTypes, $originalFinallyScope->nativeExpressionTypes), $this->conditionalExpressions, $this->inClosureBindScopeClasses, $this->anonymousFunctionReflection, $this->inFirstLevelStatement, [], [], [], $this->afterExtractCall, $this->parentScope, $this->nativeTypesPromoted); + return $this->scopeFactory->create( + $this->context, + $this->isDeclareStrictTypes(), + $this->getFunction(), + $this->getNamespace(), + $this->processFinallyScopeVariableTypeHolders( + $this->expressionTypes, + $finallyScope->expressionTypes, + $originalFinallyScope->expressionTypes, + ), + $this->processFinallyScopeVariableTypeHolders( + $this->nativeExpressionTypes, + $finallyScope->nativeExpressionTypes, + $originalFinallyScope->nativeExpressionTypes, + ), + $this->conditionalExpressions, + $this->inClosureBindScopeClasses, + $this->anonymousFunctionReflection, + $this->inFirstLevelStatement, + [], + [], + [], + $this->afterExtractCall, + $this->parentScope, + $this->nativeTypesPromoted, + ); } /** - * @param array $ourVariableTypeHolders - * @param array $finallyVariableTypeHolders - * @param array $originalVariableTypeHolders - * @return array - */ - private function processFinallyScopeVariableTypeHolders(array $ourVariableTypeHolders, array $finallyVariableTypeHolders, array $originalVariableTypeHolders) : array - { - foreach ($finallyVariableTypeHolders as $exprString => $variableTypeHolder) { - if ( - isset($originalVariableTypeHolders[$exprString]) - && !$originalVariableTypeHolders[$exprString]->getType()->equals($variableTypeHolder->getType()) - ) { - $ourVariableTypeHolders[$exprString] = $variableTypeHolder; - continue; - } - - if (isset($originalVariableTypeHolders[$exprString])) { - continue; - } - - $ourVariableTypeHolders[$exprString] = $variableTypeHolder; - } - return $ourVariableTypeHolders; + * @param array $ourVariableTypeHolders + * @param array $finallyVariableTypeHolders + * @param array $originalVariableTypeHolders + * @return array + */ + private function processFinallyScopeVariableTypeHolders( + array $ourVariableTypeHolders, + array $finallyVariableTypeHolders, + array $originalVariableTypeHolders, + ): array + { + foreach ($finallyVariableTypeHolders as $exprString => $variableTypeHolder) { + if ( + isset($originalVariableTypeHolders[$exprString]) + && !$originalVariableTypeHolders[$exprString]->getType()->equals($variableTypeHolder->getType()) + ) { + $ourVariableTypeHolders[$exprString] = $variableTypeHolder; + continue; + } + + if (isset($originalVariableTypeHolders[$exprString])) { + continue; } + $ourVariableTypeHolders[$exprString] = $variableTypeHolder; + } + + return $ourVariableTypeHolders; + } + /** - * @param Expr\ClosureUse[] $byRefUses - */ - public function processClosureScope(self $closureScope, ?self $prevScope, array $byRefUses) : self - { - $nativeExpressionTypes = $this->nativeExpressionTypes; - $expressionTypes = $this->expressionTypes; - if (count($byRefUses) === 0) { - return $this; - } - foreach ($byRefUses as $use) { - if (!is_string($use->var->name)) { - throw new ShouldNotHappenException(); - } - - $variableName = $use->var->name; - $variableExprString = '$' . $variableName; - - if (!$closureScope->hasVariableType($variableName)->yes()) { - $holder = ExpressionTypeHolder::createYes($use->var, new NullType()); - $expressionTypes[$variableExprString] = $holder; - $nativeExpressionTypes[$variableExprString] = $holder; - continue; - } - - $variableType = $closureScope->getVariableType($variableName); - - if ($prevScope !== null) { - $prevVariableType = $prevScope->getVariableType($variableName); - if (!$variableType->equals($prevVariableType)) { - $variableType = TypeCombinator::union($variableType, $prevVariableType); - $variableType = self::generalizeType($variableType, $prevVariableType, 0); - } - } - - $expressionTypes[$variableExprString] = ExpressionTypeHolder::createYes($use->var, $variableType); - $nativeExpressionTypes[$variableExprString] = ExpressionTypeHolder::createYes($use->var, $variableType); - } - return $this->scopeFactory->create($this->context, $this->isDeclareStrictTypes(), $this->getFunction(), $this->getNamespace(), $expressionTypes, $nativeExpressionTypes, $this->conditionalExpressions, $this->inClosureBindScopeClasses, $this->anonymousFunctionReflection, $this->inFirstLevelStatement, [], [], $this->inFunctionCallsStack, $this->afterExtractCall, $this->parentScope, $this->nativeTypesPromoted); + * @param Expr\ClosureUse[] $byRefUses + */ + public function processClosureScope( + self $closureScope, + ?self $prevScope, + array $byRefUses, + ): self + { + $nativeExpressionTypes = $this->nativeExpressionTypes; + $expressionTypes = $this->expressionTypes; + if (count($byRefUses) === 0) { + return $this; + } + + foreach ($byRefUses as $use) { + if (!is_string($use->var->name)) { + throw new ShouldNotHappenException(); } + $variableName = $use->var->name; + $variableExprString = '$' . $variableName; + + if (!$closureScope->hasVariableType($variableName)->yes()) { + $holder = ExpressionTypeHolder::createYes($use->var, new NullType()); + $expressionTypes[$variableExprString] = $holder; + $nativeExpressionTypes[$variableExprString] = $holder; + continue; + } + + $variableType = $closureScope->getVariableType($variableName); + + if ($prevScope !== null) { + $prevVariableType = $prevScope->getVariableType($variableName); + if (!$variableType->equals($prevVariableType)) { + $variableType = TypeCombinator::union($variableType, $prevVariableType); + $variableType = self::generalizeType($variableType, $prevVariableType, 0); + } + } + + $expressionTypes[$variableExprString] = ExpressionTypeHolder::createYes($use->var, $variableType); + $nativeExpressionTypes[$variableExprString] = ExpressionTypeHolder::createYes($use->var, $variableType); + } + + return $this->scopeFactory->create( + $this->context, + $this->isDeclareStrictTypes(), + $this->getFunction(), + $this->getNamespace(), + $expressionTypes, + $nativeExpressionTypes, + $this->conditionalExpressions, + $this->inClosureBindScopeClasses, + $this->anonymousFunctionReflection, + $this->inFirstLevelStatement, + [], + [], + $this->inFunctionCallsStack, + $this->afterExtractCall, + $this->parentScope, + $this->nativeTypesPromoted, + ); + } + public function processAlwaysIterableForeachScopeWithoutPollute(self $finalScope): self { $expressionTypes = $this->expressionTypes; @@ -3788,7 +4390,11 @@ public function processAlwaysIterableForeachScopeWithoutPollute(self $finalScope continue; } - $expressionTypes[$variableExprString] = new ExpressionTypeHolder($variableTypeHolder->getExpr(), $variableTypeHolder->getType(), $variableTypeHolder->getCertainty()->and($expressionTypes[$variableExprString]->getCertainty())); + $expressionTypes[$variableExprString] = new ExpressionTypeHolder( + $variableTypeHolder->getExpr(), + $variableTypeHolder->getType(), + $variableTypeHolder->getCertainty()->and($expressionTypes[$variableExprString]->getCertainty()), + ); } $nativeTypes = $this->nativeExpressionTypes; foreach ($finalScope->nativeExpressionTypes as $variableExprString => $variableTypeHolder) { @@ -3797,37 +4403,89 @@ public function processAlwaysIterableForeachScopeWithoutPollute(self $finalScope continue; } - $nativeTypes[$variableExprString] = new ExpressionTypeHolder($variableTypeHolder->getExpr(), $variableTypeHolder->getType(), $variableTypeHolder->getCertainty()->and($nativeTypes[$variableExprString]->getCertainty())); - } - - return $this->scopeFactory->create($this->context, $this->isDeclareStrictTypes(), $this->getFunction(), $this->getNamespace(), $expressionTypes, $nativeTypes, $this->conditionalExpressions, $this->inClosureBindScopeClasses, $this->anonymousFunctionReflection, $this->inFirstLevelStatement, [], [], [], $this->afterExtractCall, $this->parentScope, $this->nativeTypesPromoted); + $nativeTypes[$variableExprString] = new ExpressionTypeHolder( + $variableTypeHolder->getExpr(), + $variableTypeHolder->getType(), + $variableTypeHolder->getCertainty()->and($nativeTypes[$variableExprString]->getCertainty()), + ); + } + + return $this->scopeFactory->create( + $this->context, + $this->isDeclareStrictTypes(), + $this->getFunction(), + $this->getNamespace(), + $expressionTypes, + $nativeTypes, + $this->conditionalExpressions, + $this->inClosureBindScopeClasses, + $this->anonymousFunctionReflection, + $this->inFirstLevelStatement, + [], + [], + [], + $this->afterExtractCall, + $this->parentScope, + $this->nativeTypesPromoted, + ); } public function generalizeWith(self $otherScope): self { - $variableTypeHolders = $this->generalizeVariableTypeHolders($this->expressionTypes, $otherScope->expressionTypes); - $nativeTypes = $this->generalizeVariableTypeHolders($this->nativeExpressionTypes, $otherScope->nativeExpressionTypes); - - return $this->scopeFactory->create($this->context, $this->isDeclareStrictTypes(), $this->getFunction(), $this->getNamespace(), $variableTypeHolders, $nativeTypes, $this->conditionalExpressions, $this->inClosureBindScopeClasses, $this->anonymousFunctionReflection, $this->inFirstLevelStatement, [], [], [], $this->afterExtractCall, $this->parentScope, $this->nativeTypesPromoted); + $variableTypeHolders = $this->generalizeVariableTypeHolders( + $this->expressionTypes, + $otherScope->expressionTypes, + ); + $nativeTypes = $this->generalizeVariableTypeHolders( + $this->nativeExpressionTypes, + $otherScope->nativeExpressionTypes, + ); + + return $this->scopeFactory->create( + $this->context, + $this->isDeclareStrictTypes(), + $this->getFunction(), + $this->getNamespace(), + $variableTypeHolders, + $nativeTypes, + $this->conditionalExpressions, + $this->inClosureBindScopeClasses, + $this->anonymousFunctionReflection, + $this->inFirstLevelStatement, + [], + [], + [], + $this->afterExtractCall, + $this->parentScope, + $this->nativeTypesPromoted, + ); } /** - * @param array $variableTypeHolders - * @param array $otherVariableTypeHolders - * @return array - */ - private function generalizeVariableTypeHolders(array $variableTypeHolders, array $otherVariableTypeHolders) : array - { - foreach ($variableTypeHolders as $variableExprString => $variableTypeHolder) { - if (!isset($otherVariableTypeHolders[$variableExprString])) { - continue; - } - - $variableTypeHolders[$variableExprString] = new ExpressionTypeHolder($variableTypeHolder->getExpr(), self::generalizeType($variableTypeHolder->getType(), $otherVariableTypeHolders[$variableExprString]->getType(), 0), $variableTypeHolder->getCertainty()); - } - return $variableTypeHolders; + * @param array $variableTypeHolders + * @param array $otherVariableTypeHolders + * @return array + */ + private function generalizeVariableTypeHolders( + array $variableTypeHolders, + array $otherVariableTypeHolders, + ): array + { + foreach ($variableTypeHolders as $variableExprString => $variableTypeHolder) { + if (!isset($otherVariableTypeHolders[$variableExprString])) { + continue; } + $variableTypeHolders[$variableExprString] = new ExpressionTypeHolder( + $variableTypeHolder->getExpr(), + self::generalizeType($variableTypeHolder->getType(), $otherVariableTypeHolders[$variableExprString]->getType(), 0), + $variableTypeHolder->getCertainty(), + ); + } + + return $variableTypeHolders; + } + private static function generalizeType(Type $a, Type $b, int $depth): Type { if ($a->equals($b)) { @@ -3916,12 +4574,23 @@ private static function generalizeType(Type $a, Type $b, int $depth): Type if ($constantArraysA->getIterableKeyType()->equals($constantArraysB->getIterableKeyType())) { $resultArrayBuilder = ConstantArrayTypeBuilder::createEmpty(); foreach (TypeUtils::flattenTypes($constantArraysA->getIterableKeyType()) as $keyType) { - $resultArrayBuilder->setOffsetValueType($keyType, self::generalizeType($constantArraysA->getOffsetValueType($keyType), $constantArraysB->getOffsetValueType($keyType), $depth + 1), !$constantArraysA->hasOffsetValueType($keyType)->and($constantArraysB->hasOffsetValueType($keyType))->negate()->no()); + $resultArrayBuilder->setOffsetValueType( + $keyType, + self::generalizeType( + $constantArraysA->getOffsetValueType($keyType), + $constantArraysB->getOffsetValueType($keyType), + $depth + 1, + ), + !$constantArraysA->hasOffsetValueType($keyType)->and($constantArraysB->hasOffsetValueType($keyType))->negate()->no(), + ); } $resultTypes[] = $resultArrayBuilder->getArray(); } else { - $resultType = new ArrayType(TypeCombinator::union(self::generalizeType($constantArraysA->getIterableKeyType(), $constantArraysB->getIterableKeyType(), $depth + 1)), TypeCombinator::union(self::generalizeType($constantArraysA->getIterableValueType(), $constantArraysB->getIterableValueType(), $depth + 1))); + $resultType = new ArrayType( + TypeCombinator::union(self::generalizeType($constantArraysA->getIterableKeyType(), $constantArraysB->getIterableKeyType(), $depth + 1)), + TypeCombinator::union(self::generalizeType($constantArraysA->getIterableValueType(), $constantArraysB->getIterableValueType(), $depth + 1)), + ); if ($constantArraysA->isIterableAtLeastOnce()->yes() && $constantArraysB->isIterableAtLeastOnce()->yes()) { $resultType = TypeCombinator::intersect($resultType, new NonEmptyArrayType()); } @@ -3961,7 +4630,10 @@ private static function generalizeType(Type $a, Type $b, int $depth): Type } } - $resultType = new ArrayType(TypeCombinator::union(self::generalizeType($generalArraysA->getIterableKeyType(), $generalArraysB->getIterableKeyType(), $depth + 1)), TypeCombinator::union(self::generalizeType($aValueType, $bValueType, $depth + 1))); + $resultType = new ArrayType( + TypeCombinator::union(self::generalizeType($generalArraysA->getIterableKeyType(), $generalArraysB->getIterableKeyType(), $depth + 1)), + TypeCombinator::union(self::generalizeType($aValueType, $bValueType, $depth + 1)), + ); if ($generalArraysA->isIterableAtLeastOnce()->yes() && $generalArraysB->isIterableAtLeastOnce()->yes()) { $resultType = TypeCombinator::intersect($resultType, new NonEmptyArrayType()); } @@ -4108,11 +4780,15 @@ private static function generalizeType(Type $a, Type $b, int $depth): Type $resultTypes[] = TypeCombinator::union(...$integerRanges['b']); } - $accessoryTypes = array_map(static function (Type $type) : Type { - return $type->generalize(GeneralizePrecision::moreSpecific()); - }, TypeUtils::getAccessoryTypes($a)); + $accessoryTypes = array_map( + static fn (Type $type): Type => $type->generalize(GeneralizePrecision::moreSpecific()), + TypeUtils::getAccessoryTypes($a), + ); - return TypeCombinator::union(TypeCombinator::intersect(TypeCombinator::union(...$resultTypes, ...$otherTypes), ...$accessoryTypes), ...$otherTypes); + return TypeCombinator::union(TypeCombinator::intersect( + TypeCombinator::union(...$resultTypes, ...$otherTypes), + ...$accessoryTypes, + ), ...$otherTypes); } private static function getArrayDepth(Type $type): int @@ -4142,10 +4818,10 @@ public function equals(self $otherScope): bool } /** - * @param array $variableTypeHolders - * @param array $otherVariableTypeHolders - */ - private function compareVariableTypeHolders(array $variableTypeHolders, array $otherVariableTypeHolders): bool + * @param array $variableTypeHolders + * @param array $otherVariableTypeHolders + */ + private function compareVariableTypeHolders(array $variableTypeHolders, array $otherVariableTypeHolders): bool { if (count($variableTypeHolders) !== count($otherVariableTypeHolders)) { return false; @@ -4184,13 +4860,13 @@ private function getBooleanExpressionDepth(Expr $expr, int $depth = 0): int } /** @api */ - public function canAccessProperty(PropertyReflection $propertyReflection): bool + public function canAccessProperty(PropertyReflection $propertyReflection): bool { return $this->canAccessClassMember($propertyReflection); } /** @api */ - public function canCallMethod(MethodReflection $methodReflection): bool + public function canCallMethod(MethodReflection $methodReflection): bool { if ($this->canAccessClassMember($methodReflection)) { return true; @@ -4200,7 +4876,7 @@ public function canCallMethod(MethodReflection $methodReflection): bool } /** @api */ - public function canAccessConstant(ConstantReflection $constantReflection): bool + public function canAccessConstant(ConstantReflection $constantReflection): bool { return $this->canAccessClassMember($constantReflection); } @@ -4247,9 +4923,9 @@ private function canAccessClassMember(ClassMemberReflection $classMemberReflecti } /** - * @return string[] - */ - public function debug(): array + * @return string[] + */ + public function debug(): array { $descriptions = []; foreach ($this->expressionTypes as $name => $variableTypeHolder) { @@ -4269,7 +4945,13 @@ public function debug(): array $parts[] = $conditionalExprString . '=' . $expressionTypeHolder->getType()->describe(VerbosityLevel::precise()); } $condition = implode(' && ', $parts); - $descriptions[$key] = sprintf('if %s then %s is %s (%s)', $condition, $exprString, $holder->getTypeHolder()->getType()->describe(VerbosityLevel::precise()), $holder->getTypeHolder()->getCertainty()->describe()); + $descriptions[$key] = sprintf( + 'if %s then %s is %s (%s)', + $condition, + $exprString, + $holder->getTypeHolder()->getType()->describe(VerbosityLevel::precise()), + $holder->getTypeHolder()->getCertainty()->describe(), + ); } } @@ -4295,9 +4977,18 @@ private function exactInstantiation(New_ $node, string $className): ?Type } $resolvedTypes = []; - $methodCall = new Expr\StaticCall(new Name($resolvedClassName), new Node\Identifier($constructorMethod->getName()), $node->getArgs()); - - $parametersAcceptor = ParametersAcceptorSelector::selectFromArgs($this, $methodCall->getArgs(), $constructorMethod->getVariants(), $constructorMethod->getNamedArgumentsVariants()); + $methodCall = new Expr\StaticCall( + new Name($resolvedClassName), + new Node\Identifier($constructorMethod->getName()), + $node->getArgs(), + ); + + $parametersAcceptor = ParametersAcceptorSelector::selectFromArgs( + $this, + $methodCall->getArgs(), + $constructorMethod->getVariants(), + $constructorMethod->getNamedArgumentsVariants(), + ); $normalizedMethodCall = ArgumentsNormalizer::reorderStaticCallArguments($parametersAcceptor, $methodCall); if ($normalizedMethodCall !== null) { @@ -4306,7 +4997,11 @@ private function exactInstantiation(New_ $node, string $className): ?Type continue; } - $resolvedType = $dynamicStaticMethodReturnTypeExtension->getTypeFromStaticMethodCall($constructorMethod, $normalizedMethodCall, $this); + $resolvedType = $dynamicStaticMethodReturnTypeExtension->getTypeFromStaticMethodCall( + $constructorMethod, + $normalizedMethodCall, + $this, + ); if ($resolvedType === null) { continue; } @@ -4357,14 +5052,25 @@ private function exactInstantiation(New_ $node, string $className): ?Type } if ($constructorMethod instanceof DummyConstructorReflection || $constructorMethod->getDeclaringClass()->getName() !== $classReflection->getName()) { - return new GenericObjectType($resolvedClassName, $classReflection->typeMapToList($classReflection->getTemplateTypeMap()->resolveToBounds())); + return new GenericObjectType( + $resolvedClassName, + $classReflection->typeMapToList($classReflection->getTemplateTypeMap()->resolveToBounds()), + ); } - $parametersAcceptor = ParametersAcceptorSelector::selectFromArgs($this, $methodCall->getArgs(), $constructorMethod->getVariants(), $constructorMethod->getNamedArgumentsVariants()); + $parametersAcceptor = ParametersAcceptorSelector::selectFromArgs( + $this, + $methodCall->getArgs(), + $constructorMethod->getVariants(), + $constructorMethod->getNamedArgumentsVariants(), + ); if ($this->explicitMixedInUnknownGenericNew) { $resolvedTemplateTypeMap = $parametersAcceptor->getResolvedTemplateTypeMap(); - return TypeTraverser::map(new GenericObjectType($resolvedClassName, $classReflection->typeMapToList($classReflection->getTemplateTypeMap())), static function (Type $type, callable $traverse) use ($resolvedTemplateTypeMap): Type { + return TypeTraverser::map(new GenericObjectType( + $resolvedClassName, + $classReflection->typeMapToList($classReflection->getTemplateTypeMap()), + ), static function (Type $type, callable $traverse) use ($resolvedTemplateTypeMap): Type { if ($type instanceof TemplateType && !$type->isArgument()) { $newType = $resolvedTemplateTypeMap->getType($type->getName()); if ($newType === null || $newType instanceof ErrorType) { @@ -4398,7 +5104,10 @@ private function exactInstantiation(New_ $node, string $className): ?Type $list[] = $bound; } - return new GenericObjectType($resolvedClassName, $list); + return new GenericObjectType( + $resolvedClassName, + $list, + ); } private function filterTypeWithMethod(Type $typeWithMethod, string $methodName): ?Type @@ -4426,7 +5135,7 @@ private function filterTypeWithMethod(Type $typeWithMethod, string $methodName): } /** @api */ - public function getMethodReflection(Type $typeWithMethod, string $methodName): ?ExtendedMethodReflection + public function getMethodReflection(Type $typeWithMethod, string $methodName): ?ExtendedMethodReflection { $type = $this->filterTypeWithMethod($typeWithMethod, $methodName); if ($type === null) { @@ -4437,9 +5146,9 @@ public function getMethodReflection(Type $typeWithMethod, string $methodName): ? } /** - * @param MethodCall|Node\Expr\StaticCall $methodCall - */ - private function methodCallReturnType(Type $typeWithMethod, string $methodName, Expr $methodCall): ?Type + * @param MethodCall|Node\Expr\StaticCall $methodCall + */ + private function methodCallReturnType(Type $typeWithMethod, string $methodName, Expr $methodCall): ?Type { $typeWithMethod = $this->filterTypeWithMethod($typeWithMethod, $methodName); if ($typeWithMethod === null) { @@ -4447,7 +5156,12 @@ private function methodCallReturnType(Type $typeWithMethod, string $methodName, } $methodReflection = $typeWithMethod->getMethod($methodName, $this); - $parametersAcceptor = ParametersAcceptorSelector::selectFromArgs($this, $methodCall->getArgs(), $methodReflection->getVariants(), $methodReflection->getNamedArgumentsVariants()); + $parametersAcceptor = ParametersAcceptorSelector::selectFromArgs( + $this, + $methodCall->getArgs(), + $methodReflection->getVariants(), + $methodReflection->getNamedArgumentsVariants(), + ); if ($methodCall instanceof MethodCall) { $normalizedMethodCall = ArgumentsNormalizer::reorderMethodArguments($parametersAcceptor, $methodCall); } else { @@ -4478,7 +5192,11 @@ private function methodCallReturnType(Type $typeWithMethod, string $methodName, continue; } - $resolvedType = $dynamicStaticMethodReturnTypeExtension->getTypeFromStaticMethodCall($methodReflection, $normalizedMethodCall, $this); + $resolvedType = $dynamicStaticMethodReturnTypeExtension->getTypeFromStaticMethodCall( + $methodReflection, + $normalizedMethodCall, + $this, + ); if ($resolvedType === null) { continue; } @@ -4496,7 +5214,7 @@ private function methodCallReturnType(Type $typeWithMethod, string $methodName, } /** @api */ - public function getPropertyReflection(Type $typeWithProperty, string $propertyName): ?PropertyReflection + public function getPropertyReflection(Type $typeWithProperty, string $propertyName): ?PropertyReflection { if ($typeWithProperty instanceof UnionType) { $newTypes = []; @@ -4520,9 +5238,9 @@ public function getPropertyReflection(Type $typeWithProperty, string $propertyNa } /** - * @param PropertyFetch|Node\Expr\StaticPropertyFetch $propertyFetch - */ - private function propertyFetchType(Type $fetchedOnType, string $propertyName, Expr $propertyFetch): ?Type + * @param PropertyFetch|Node\Expr\StaticPropertyFetch $propertyFetch + */ + private function propertyFetchType(Type $fetchedOnType, string $propertyName, Expr $propertyFetch): ?Type { $propertyReflection = $this->getPropertyReflection($fetchedOnType, $propertyName); if ($propertyReflection === null) { @@ -4560,9 +5278,9 @@ public function getConstantReflection(Type $typeWithConstant, string $constantNa } /** - * @return array - */ - private function getConstantTypes(): array + * @return array + */ + private function getConstantTypes(): array { $constantTypes = []; foreach ($this->expressionTypes as $exprString => $typeHolder) { @@ -4576,9 +5294,9 @@ private function getConstantTypes(): array } /** - * @return array - */ - private function getNativeConstantTypes(): array + * @return array + */ + private function getNativeConstantTypes(): array { $constantTypes = []; foreach ($this->nativeExpressionTypes as $exprString => $typeHolder) { diff --git a/src/Analyser/NameScope.php b/src/Analyser/NameScope.php index 7131a6affa5..af3688e107e 100644 --- a/src/Analyser/NameScope.php +++ b/src/Analyser/NameScope.php @@ -20,42 +20,7 @@ class NameScope { - /** - * @var ?string - */ - private $namespace; - /** - * @var array - */ - private $uses; - /** - * @var ?string - */ - private $className; - /** - * @var ?string - */ - private $functionName; - /** - * @var array - */ - private $typeAliasesMap; - /** - * @var bool - */ - private $bypassTypeAliases; - /** - * @var array - */ - private $constUses; - /** - * @var ?string - */ - private $typeAliasClassName; - /** - * @var TemplateTypeMap - */ - private $templateTypeMap; + private TemplateTypeMap $templateTypeMap; /** * @api @@ -63,16 +28,8 @@ class NameScope * @param array $constUses alias(string) => fullName(string) * @param array $typeAliasesMap */ - public function __construct(?string $namespace, array $uses, ?string $className = null, ?string $functionName = null, ?TemplateTypeMap $templateTypeMap = null, array $typeAliasesMap = [], bool $bypassTypeAliases = false, array $constUses = [], ?string $typeAliasClassName = null) - { - $this->namespace = $namespace; - $this->uses = $uses; - $this->className = $className; - $this->functionName = $functionName; - $this->typeAliasesMap = $typeAliasesMap; - $this->bypassTypeAliases = $bypassTypeAliases; - $this->constUses = $constUses; - $this->typeAliasClassName = $typeAliasClassName; + 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) + { $this->templateTypeMap = $templateTypeMap ?? TemplateTypeMap::createEmpty(); } @@ -199,7 +156,19 @@ public function withTemplateTypeMap(TemplateTypeMap $map): self return $this; } - return new self($this->namespace, $this->uses, $this->className, $this->functionName, new TemplateTypeMap(array_merge($this->templateTypeMap->getTypes(), $map->getTypes())), $this->typeAliasesMap, $this->bypassTypeAliases, $this->constUses); + return new self( + $this->namespace, + $this->uses, + $this->className, + $this->functionName, + new TemplateTypeMap(array_merge( + $this->templateTypeMap->getTypes(), + $map->getTypes(), + )), + $this->typeAliasesMap, + $this->bypassTypeAliases, + $this->constUses, + ); } public function unsetTemplateType(string $name): self @@ -209,7 +178,16 @@ public function unsetTemplateType(string $name): self return $this; } - return new self($this->namespace, $this->uses, $this->className, $this->functionName, $this->templateTypeMap->unsetType($name), $this->typeAliasesMap, $this->bypassTypeAliases, $this->constUses); + return new self( + $this->namespace, + $this->uses, + $this->className, + $this->functionName, + $this->templateTypeMap->unsetType($name), + $this->typeAliasesMap, + $this->bypassTypeAliases, + $this->constUses, + ); } public function bypassTypeAliases(): self @@ -232,7 +210,16 @@ public function hasTypeAlias(string $alias): bool */ public static function __set_state(array $properties): self { - return new self($properties['namespace'], $properties['uses'], $properties['className'], $properties['functionName'], $properties['templateTypeMap'], $properties['typeAliasesMap'], $properties['bypassTypeAliases'], $properties['constUses']); + return new self( + $properties['namespace'], + $properties['uses'], + $properties['className'], + $properties['functionName'], + $properties['templateTypeMap'], + $properties['typeAliasesMap'], + $properties['bypassTypeAliases'], + $properties['constUses'], + ); } } diff --git a/src/Analyser/ResultCache/ResultCache.php b/src/Analyser/ResultCache/ResultCache.php index cd26a17be5f..409f1230073 100644 --- a/src/Analyser/ResultCache/ResultCache.php +++ b/src/Analyser/ResultCache/ResultCache.php @@ -9,42 +9,6 @@ class ResultCache { - /** - * @var string[] - */ - private $filesToAnalyse; - /** - * @var bool - */ - private $fullAnalysis; - /** - * @var int - */ - private $lastFullAnalysisTime; - /** - * @var mixed[] - */ - private $meta; - /** - * @var array> - */ - private $errors; - /** - * @var array> - */ - private $locallyIgnoredErrors; - /** - * @var array> - */ - private $collectedData; - /** - * @var array> - */ - private $dependencies; - /** - * @var array> - */ - private $exportedNodes; /** * @param string[] $filesToAnalyse * @param mixed[] $meta @@ -54,18 +18,20 @@ class ResultCache * @param array> $dependencies * @param array> $exportedNodes */ - public function __construct(array $filesToAnalyse, bool $fullAnalysis, int $lastFullAnalysisTime, array $meta, array $errors, array $locallyIgnoredErrors, array $collectedData, array $dependencies, array $exportedNodes) + public function __construct( + private array $filesToAnalyse, + private bool $fullAnalysis, + private int $lastFullAnalysisTime, + private array $meta, + private array $errors, + private array $locallyIgnoredErrors, + private array $collectedData, + private array $dependencies, + private array $exportedNodes, + ) { - $this->filesToAnalyse = $filesToAnalyse; - $this->fullAnalysis = $fullAnalysis; - $this->lastFullAnalysisTime = $lastFullAnalysisTime; - $this->meta = $meta; - $this->errors = $errors; - $this->locallyIgnoredErrors = $locallyIgnoredErrors; - $this->collectedData = $collectedData; - $this->dependencies = $dependencies; - $this->exportedNodes = $exportedNodes; } + /** * @return string[] */ diff --git a/src/Analyser/ResultCache/ResultCacheClearer.php b/src/Analyser/ResultCache/ResultCacheClearer.php index daac22d5f83..d9cbee81c6e 100644 --- a/src/Analyser/ResultCache/ResultCacheClearer.php +++ b/src/Analyser/ResultCache/ResultCacheClearer.php @@ -9,13 +9,8 @@ class ResultCacheClearer { - /** - * @var string - */ - private $cacheFilePath; - public function __construct(string $cacheFilePath) + public function __construct(private string $cacheFilePath) { - $this->cacheFilePath = $cacheFilePath; } public function clear(): string diff --git a/src/Analyser/ResultCache/ResultCacheManager.php b/src/Analyser/ResultCache/ResultCacheManager.php index 8cf85a21fb1..08af6df0d00 100644 --- a/src/Analyser/ResultCache/ResultCacheManager.php +++ b/src/Analyser/ResultCache/ResultCacheManager.php @@ -44,65 +44,13 @@ class ResultCacheManager { - /** - * @var ExportedNodeFetcher - */ - private $exportedNodeFetcher; - /** - * @var FileFinder - */ - private $scanFileFinder; - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - /** - * @var StubFilesProvider - */ - private $stubFilesProvider; - /** - * @var string - */ - private $cacheFilePath; - /** - * @var string[] - */ - private $analysedPaths; - /** - * @var string[] - */ - private $composerAutoloaderProjectPaths; - /** - * @var string - */ - private $usedLevel; - /** - * @var ?string - */ - private $cliAutoloadFile; - /** - * @var string[] - */ - private $bootstrapFiles; - /** - * @var string[] - */ - private $scanFiles; - /** - * @var string[] - */ - private $scanDirectories; - /** - * @var bool - */ - private $checkDependenciesOfProjectExtensionFiles; private const CACHE_VERSION = 'v11-locallyIgnoredErrors'; /** @var array */ - private $fileHashes = []; + private array $fileHashes = []; /** @var array */ - private $alreadyProcessed = []; + private array $alreadyProcessed = []; /** * @param string[] $analysedPaths @@ -111,21 +59,22 @@ class ResultCacheManager * @param string[] $scanFiles * @param string[] $scanDirectories */ - public function __construct(ExportedNodeFetcher $exportedNodeFetcher, FileFinder $scanFileFinder, ReflectionProvider $reflectionProvider, StubFilesProvider $stubFilesProvider, string $cacheFilePath, array $analysedPaths, array $composerAutoloaderProjectPaths, string $usedLevel, ?string $cliAutoloadFile, array $bootstrapFiles, array $scanFiles, array $scanDirectories, bool $checkDependenciesOfProjectExtensionFiles) + public function __construct( + private ExportedNodeFetcher $exportedNodeFetcher, + private FileFinder $scanFileFinder, + private ReflectionProvider $reflectionProvider, + private StubFilesProvider $stubFilesProvider, + private string $cacheFilePath, + private array $analysedPaths, + private array $composerAutoloaderProjectPaths, + private string $usedLevel, + private ?string $cliAutoloadFile, + private array $bootstrapFiles, + private array $scanFiles, + private array $scanDirectories, + private bool $checkDependenciesOfProjectExtensionFiles, + ) { - $this->exportedNodeFetcher = $exportedNodeFetcher; - $this->scanFileFinder = $scanFileFinder; - $this->reflectionProvider = $reflectionProvider; - $this->stubFilesProvider = $stubFilesProvider; - $this->cacheFilePath = $cacheFilePath; - $this->analysedPaths = $analysedPaths; - $this->composerAutoloaderProjectPaths = $composerAutoloaderProjectPaths; - $this->usedLevel = $usedLevel; - $this->cliAutoloadFile = $cliAutoloadFile; - $this->bootstrapFiles = $bootstrapFiles; - $this->scanFiles = $scanFiles; - $this->scanDirectories = $scanDirectories; - $this->checkDependenciesOfProjectExtensionFiles = $checkDependenciesOfProjectExtensionFiles; } /** @@ -504,7 +453,16 @@ public function process(AnalyserResult $analyserResult, ResultCache $resultCache } } - return new ResultCacheProcessResult(new AnalyserResult($flatErrors, $flatLocallyIgnoredErrors, $internalErrors, $flatCollectedData, $dependencies, $exportedNodes, $analyserResult->hasReachedInternalErrorsCountLimit(), $analyserResult->getPeakMemoryUsageBytes()), $saved); + return new ResultCacheProcessResult(new AnalyserResult( + $flatErrors, + $flatLocallyIgnoredErrors, + $internalErrors, + $flatCollectedData, + $dependencies, + $exportedNodes, + $analyserResult->hasReachedInternalErrorsCountLimit(), + $analyserResult->getPeakMemoryUsageBytes(), + ), $saved); } /** @@ -629,7 +587,15 @@ private function mergeExportedNodes(ResultCache $resultCache, array $freshExport * @param array> $exportedNodes * @param mixed[] $meta */ - private function save(int $lastFullAnalysisTime, array $errors, array $locallyIgnoredErrors, array $collectedData, array $dependencies, array $exportedNodes, array $meta) : void + private function save( + int $lastFullAnalysisTime, + array $errors, + array $locallyIgnoredErrors, + array $collectedData, + array $dependencies, + array $exportedNodes, + array $meta, + ): void { $invertedDependencies = []; $filesNoOneIsDependingOn = array_fill_keys(array_keys($dependencies), true); @@ -645,6 +611,7 @@ private function save(int $lastFullAnalysisTime, array $errors, array $locallyIg $invertedDependencies[$fileDep]['dependentFiles'][] = $file; } } + foreach (array_keys($filesNoOneIsDependingOn) as $file) { if (array_key_exists($file, $invertedDependencies)) { throw new ShouldNotHappenException(); @@ -659,22 +626,29 @@ private function save(int $lastFullAnalysisTime, array $errors, array $locallyIg 'dependentFiles' => [], ]; } + ksort($errors); ksort($locallyIgnoredErrors); ksort($collectedData); ksort($invertedDependencies); + foreach ($invertedDependencies as $file => $fileData) { $dependentFiles = $fileData['dependentFiles']; sort($dependentFiles); $invertedDependencies[$file]['dependentFiles'] = $dependentFiles; } + ksort($exportedNodes); + $file = $this->cacheFilePath; $projectConfigArray = $meta['projectConfig']; if ($projectConfigArray !== null) { $meta['projectConfig'] = Neon::encode($projectConfigArray); } - FileWriter::write($file, " " . var_export($lastFullAnalysisTime, true) . ", @@ -686,7 +660,8 @@ private function save(int $lastFullAnalysisTime, array $errors, array $locallyIg 'dependencies' => " . var_export($invertedDependencies, true) . ", 'exportedNodesCallback' => static function (): array { return " . var_export($exportedNodes, true) . '; }, ]; -'); +', + ); } /** @@ -699,7 +674,10 @@ private function getProjectExtensionFiles(?array $projectConfig, array $dependen $this->alreadyProcessed = []; $projectExtensionFiles = []; if ($projectConfig !== null) { - $services = array_merge($projectConfig['services'] ?? [], $projectConfig['rules'] ?? []); + $services = array_merge( + $projectConfig['services'] ?? [], + $projectConfig['rules'] ?? [], + ); foreach ($services as $service) { $classes = $this->getClassesFromConfigDefinition($service); if (is_array($service)) { @@ -796,9 +774,7 @@ private function getAllDependencies(string $fileName, array $dependencies): arra */ private function getMeta(array $allAnalysedFiles, ?array $projectConfigArray): array { - $extensions = array_values(array_filter(get_loaded_extensions(), static function (string $extension) : bool { - return $extension !== 'xdebug'; - })); + $extensions = array_values(array_filter(get_loaded_extensions(), static fn (string $extension): bool => $extension !== 'xdebug')); sort($extensions); if ($projectConfigArray !== null) { diff --git a/src/Analyser/ResultCache/ResultCacheProcessResult.php b/src/Analyser/ResultCache/ResultCacheProcessResult.php index b79c609c242..27326f33a07 100644 --- a/src/Analyser/ResultCache/ResultCacheProcessResult.php +++ b/src/Analyser/ResultCache/ResultCacheProcessResult.php @@ -7,18 +7,8 @@ class ResultCacheProcessResult { - /** - * @var AnalyserResult - */ - private $analyserResult; - /** - * @var bool - */ - private $saved; - public function __construct(AnalyserResult $analyserResult, bool $saved) + public function __construct(private AnalyserResult $analyserResult, private bool $saved) { - $this->analyserResult = $analyserResult; - $this->saved = $saved; } public function getAnalyserResult(): AnalyserResult diff --git a/src/Analyser/RuleErrorTransformer.php b/src/Analyser/RuleErrorTransformer.php index 9ef1a89c91c..464e8cd7763 100644 --- a/src/Analyser/RuleErrorTransformer.php +++ b/src/Analyser/RuleErrorTransformer.php @@ -17,9 +17,13 @@ class RuleErrorTransformer /** * @param class-string $nodeType - * @param string|RuleError $ruleError */ - public function transform($ruleError, Scope $scope, string $nodeType, int $nodeLine) : Error + public function transform( + string|RuleError $ruleError, + Scope $scope, + string $nodeType, + int $nodeLine, + ): Error { $line = $nodeLine; $canBeIgnored = true; @@ -70,7 +74,19 @@ public function transform($ruleError, Scope $scope, string $nodeType, int $nodeL $canBeIgnored = false; } } - return new Error($message, $fileName, $line, $canBeIgnored, $filePath, $traitFilePath, $tip, $nodeLine, $nodeType, $identifier, $metadata); + return new Error( + $message, + $fileName, + $line, + $canBeIgnored, + $filePath, + $traitFilePath, + $tip, + $nodeLine, + $nodeType, + $identifier, + $metadata, + ); } } diff --git a/src/Analyser/ScopeContext.php b/src/Analyser/ScopeContext.php index c7dd7730a69..4118909860e 100644 --- a/src/Analyser/ScopeContext.php +++ b/src/Analyser/ScopeContext.php @@ -8,24 +8,14 @@ class ScopeContext { - /** - * @var string - */ - private $file; - /** - * @var ?ClassReflection - */ - private $classReflection; - /** - * @var ?ClassReflection - */ - private $traitReflection; - private function __construct(string $file, ?ClassReflection $classReflection, ?ClassReflection $traitReflection) + private function __construct( + private string $file, + private ?ClassReflection $classReflection, + private ?ClassReflection $traitReflection, + ) { - $this->file = $file; - $this->classReflection = $classReflection; - $this->traitReflection = $traitReflection; } + /** @api */ public static function create(string $file): self { diff --git a/src/Analyser/ScopeFactory.php b/src/Analyser/ScopeFactory.php index c65bd2fe8af..c2401d375c2 100644 --- a/src/Analyser/ScopeFactory.php +++ b/src/Analyser/ScopeFactory.php @@ -6,13 +6,8 @@ class ScopeFactory { - /** - * @var InternalScopeFactory - */ - private $internalScopeFactory; - public function __construct(InternalScopeFactory $internalScopeFactory) + public function __construct(private InternalScopeFactory $internalScopeFactory) { - $this->internalScopeFactory = $internalScopeFactory; } public function create(ScopeContext $context): MutatingScope diff --git a/src/Analyser/SpecifiedTypes.php b/src/Analyser/SpecifiedTypes.php index 8599b72920a..578a34cdc22 100644 --- a/src/Analyser/SpecifiedTypes.php +++ b/src/Analyser/SpecifiedTypes.php @@ -9,40 +9,22 @@ class SpecifiedTypes { - /** - * @var array - */ - private $sureTypes; - /** - * @var array - */ - private $sureNotTypes; - /** - * @var bool - */ - private $overwrite; - /** - * @var array - */ - private $newConditionalExpressionHolders; - /** - * @var ?Expr - */ - private $rootExpr; /** * @api * @param array $sureTypes * @param array $sureNotTypes * @param array $newConditionalExpressionHolders */ - public function __construct(array $sureTypes = [], array $sureNotTypes = [], bool $overwrite = false, array $newConditionalExpressionHolders = [], ?Expr $rootExpr = null) + public function __construct( + private array $sureTypes = [], + private array $sureNotTypes = [], + private bool $overwrite = false, + private array $newConditionalExpressionHolders = [], + private ?Expr $rootExpr = null, + ) { - $this->sureTypes = $sureTypes; - $this->sureNotTypes = $sureNotTypes; - $this->overwrite = $overwrite; - $this->newConditionalExpressionHolders = $newConditionalExpressionHolders; - $this->rootExpr = $rootExpr; } + /** * @api * @return array diff --git a/src/Analyser/StatementContext.php b/src/Analyser/StatementContext.php index 8d32e439379..222d768b522 100644 --- a/src/Analyser/StatementContext.php +++ b/src/Analyser/StatementContext.php @@ -5,14 +5,12 @@ class StatementContext { - /** - * @var bool - */ - private $isTopLevel; - private function __construct(bool $isTopLevel) + private function __construct( + private bool $isTopLevel, + ) { - $this->isTopLevel = $isTopLevel; } + public static function createTopLevel(): self { return new self(true); diff --git a/src/Analyser/StatementExitPoint.php b/src/Analyser/StatementExitPoint.php index 7f64179c8fc..f7f46ca0916 100644 --- a/src/Analyser/StatementExitPoint.php +++ b/src/Analyser/StatementExitPoint.php @@ -8,18 +8,8 @@ class StatementExitPoint { - /** - * @var Stmt - */ - private $statement; - /** - * @var MutatingScope - */ - private $scope; - public function __construct(Stmt $statement, MutatingScope $scope) + public function __construct(private Stmt $statement, private MutatingScope $scope) { - $this->statement = $statement; - $this->scope = $scope; } public function getStatement(): Stmt diff --git a/src/Analyser/StatementResult.php b/src/Analyser/StatementResult.php index dae936e0333..be2e8aef4b8 100644 --- a/src/Analyser/StatementResult.php +++ b/src/Analyser/StatementResult.php @@ -9,38 +9,20 @@ class StatementResult { - /** - * @var MutatingScope - */ - private $scope; - /** - * @var bool - */ - private $hasYield; - /** - * @var bool - */ - private $isAlwaysTerminating; - /** - * @var StatementExitPoint[] - */ - private $exitPoints; - /** - * @var ThrowPoint[] - */ - private $throwPoints; /** * @param StatementExitPoint[] $exitPoints * @param ThrowPoint[] $throwPoints */ - public function __construct(MutatingScope $scope, bool $hasYield, bool $isAlwaysTerminating, array $exitPoints, array $throwPoints) + public function __construct( + private MutatingScope $scope, + private bool $hasYield, + private bool $isAlwaysTerminating, + private array $exitPoints, + private array $throwPoints, + ) { - $this->scope = $scope; - $this->hasYield = $hasYield; - $this->isAlwaysTerminating = $isAlwaysTerminating; - $this->exitPoints = $exitPoints; - $this->throwPoints = $throwPoints; } + public function getScope(): MutatingScope { return $this->scope; diff --git a/src/Analyser/ThrowPoint.php b/src/Analyser/ThrowPoint.php index 3db2e4fa56e..26ceec42604 100644 --- a/src/Analyser/ThrowPoint.php +++ b/src/Analyser/ThrowPoint.php @@ -12,37 +12,19 @@ class ThrowPoint { - /** - * @var MutatingScope - */ - private $scope; - /** - * @var Type - */ - private $type; - /** - * @var Node\Expr|Node\Stmt - */ - private $node; - /** - * @var bool - */ - private $explicit; - /** - * @var bool - */ - private $canContainAnyThrowable; /** * @param Node\Expr|Node\Stmt $node */ - private function __construct(MutatingScope $scope, Type $type, Node $node, bool $explicit, bool $canContainAnyThrowable) + private function __construct( + private MutatingScope $scope, + private Type $type, + private Node $node, + private bool $explicit, + private bool $canContainAnyThrowable, + ) { - $this->scope = $scope; - $this->type = $type; - $this->node = $node; - $this->explicit = $explicit; - $this->canContainAnyThrowable = $canContainAnyThrowable; } + /** * @param Node\Expr|Node\Stmt $node */ diff --git a/src/Analyser/TypeSpecifier.php b/src/Analyser/TypeSpecifier.php index 88e28152e98..4e7b61cc25e 100644 --- a/src/Analyser/TypeSpecifier.php +++ b/src/Analyser/TypeSpecifier.php @@ -83,788 +83,1020 @@ class TypeSpecifier { - /** - * @var ExprPrinter - */ - private $exprPrinter; - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - /** - * @var FunctionTypeSpecifyingExtension[] - */ - private $functionTypeSpecifyingExtensions; - /** - * @var MethodTypeSpecifyingExtension[] - */ - private $methodTypeSpecifyingExtensions; - /** - * @var StaticMethodTypeSpecifyingExtension[] - */ - private $staticMethodTypeSpecifyingExtensions; - /** - * @var bool - */ - private $rememberPossiblyImpureFunctionValues; - /** @var MethodTypeSpecifyingExtension[][]|null */ - private $methodTypeSpecifyingExtensionsByClass = null; + /** @var MethodTypeSpecifyingExtension[][]|null */ + private ?array $methodTypeSpecifyingExtensionsByClass = null; /** @var StaticMethodTypeSpecifyingExtension[][]|null */ - private $staticMethodTypeSpecifyingExtensionsByClass = null; + private ?array $staticMethodTypeSpecifyingExtensionsByClass = null; /** - * @param FunctionTypeSpecifyingExtension[] $functionTypeSpecifyingExtensions - * @param MethodTypeSpecifyingExtension[] $methodTypeSpecifyingExtensions - * @param StaticMethodTypeSpecifyingExtension[] $staticMethodTypeSpecifyingExtensions - */ - public function __construct(ExprPrinter $exprPrinter, ReflectionProvider $reflectionProvider, array $functionTypeSpecifyingExtensions, array $methodTypeSpecifyingExtensions, array $staticMethodTypeSpecifyingExtensions, bool $rememberPossiblyImpureFunctionValues) - { - $this->exprPrinter = $exprPrinter; - $this->reflectionProvider = $reflectionProvider; - $this->functionTypeSpecifyingExtensions = $functionTypeSpecifyingExtensions; - $this->methodTypeSpecifyingExtensions = $methodTypeSpecifyingExtensions; - $this->staticMethodTypeSpecifyingExtensions = $staticMethodTypeSpecifyingExtensions; - $this->rememberPossiblyImpureFunctionValues = $rememberPossiblyImpureFunctionValues; - foreach (array_merge($functionTypeSpecifyingExtensions, $methodTypeSpecifyingExtensions, $staticMethodTypeSpecifyingExtensions) as $extension) { - if (!($extension instanceof TypeSpecifierAwareExtension)) { - continue; - } - - $extension->setTypeSpecifier($this); - } + * @param FunctionTypeSpecifyingExtension[] $functionTypeSpecifyingExtensions + * @param MethodTypeSpecifyingExtension[] $methodTypeSpecifyingExtensions + * @param StaticMethodTypeSpecifyingExtension[] $staticMethodTypeSpecifyingExtensions + */ + public function __construct( + private ExprPrinter $exprPrinter, + private ReflectionProvider $reflectionProvider, + private array $functionTypeSpecifyingExtensions, + private array $methodTypeSpecifyingExtensions, + private array $staticMethodTypeSpecifyingExtensions, + private bool $rememberPossiblyImpureFunctionValues, + ) + { + foreach (array_merge($functionTypeSpecifyingExtensions, $methodTypeSpecifyingExtensions, $staticMethodTypeSpecifyingExtensions) as $extension) { + if (!($extension instanceof TypeSpecifierAwareExtension)) { + continue; } + $extension->setTypeSpecifier($this); + } + } + /** @api */ - public function specifyTypesInCondition(Scope $scope, Expr $expr, TypeSpecifierContext $context, ?Expr $rootExpr = null) : SpecifiedTypes - { - $rootExpr = $rootExpr ?? $expr; - if ($expr instanceof Expr\CallLike && $expr->isFirstClassCallable()) { - return new SpecifiedTypes([], [], false, [], $rootExpr); - } - if ($expr instanceof Instanceof_) { - $exprNode = $expr->expr; - if ($expr->class instanceof Name) { - $className = (string) $expr->class; - $lowercasedClassName = strtolower($className); - if ($lowercasedClassName === 'self' && $scope->isInClass()) { - $type = new ObjectType($scope->getClassReflection()->getName()); - } elseif ($lowercasedClassName === 'static' && $scope->isInClass()) { - $type = new StaticType($scope->getClassReflection()); - } elseif ($lowercasedClassName === 'parent') { - if ( - $scope->isInClass() - && $scope->getClassReflection()->getParentClass() !== null - ) { - $type = new ObjectType($scope->getClassReflection()->getParentClass()->getName()); - } else { - $type = new NonexistentParentClassType(); - } - } else { - $type = new ObjectType($className); - } - return $this->create($exprNode, $type, $context, false, $scope, $rootExpr); - } - - $classType = $scope->getType($expr->class); - $type = TypeTraverser::map($classType, static function (Type $type, callable $traverse): Type { - if ($type instanceof UnionType || $type instanceof IntersectionType) { - return $traverse($type); - } - if ($type->getObjectClassNames() !== []) { - return $type; - } - if ($type instanceof GenericClassStringType) { - return $type->getGenericType(); - } - if ($type instanceof ConstantStringType) { - return new ObjectType($type->getValue()); - } - return new MixedType(); - }); - - if (!$type->isSuperTypeOf(new MixedType())->yes()) { - if ($context->true()) { - $type = TypeCombinator::intersect($type, new ObjectWithoutClassType()); - return $this->create($exprNode, $type, $context, false, $scope, $rootExpr); - } elseif ($context->false()) { - $exprType = $scope->getType($expr->expr); - if (!$type->isSuperTypeOf($exprType)->yes()) { - return $this->create($exprNode, $type, $context, false, $scope, $rootExpr); - } - } - } - if ($context->true()) { - return $this->create($exprNode, new ObjectWithoutClassType(), $context, false, $scope, $rootExpr); - } - } elseif ($expr instanceof Node\Expr\BinaryOp\Identical) { - return $this->resolveIdentical($expr, $scope, $context, $rootExpr); - - } elseif ($expr instanceof Node\Expr\BinaryOp\NotIdentical) { - return $this->specifyTypesInCondition($scope, new Node\Expr\BooleanNot(new Node\Expr\BinaryOp\Identical($expr->left, $expr->right)), $context, $rootExpr); - } elseif ($expr instanceof Node\Expr\BinaryOp\Equal) { - return $this->resolveEqual($expr, $scope, $context, $rootExpr); - } elseif ($expr instanceof Node\Expr\BinaryOp\NotEqual) { - return $this->specifyTypesInCondition($scope, new Node\Expr\BooleanNot(new Node\Expr\BinaryOp\Equal($expr->left, $expr->right)), $context, $rootExpr); - - } elseif ($expr instanceof Node\Expr\BinaryOp\Smaller || $expr instanceof Node\Expr\BinaryOp\SmallerOrEqual) { - - if ( - $expr->left instanceof FuncCall - && count($expr->left->getArgs()) === 1 - && $expr->left->name instanceof Name - && in_array(strtolower((string) $expr->left->name), ['count', 'sizeof', 'strlen'], true) - && ( - !$expr->right instanceof FuncCall - || !$expr->right->name instanceof Name - || !in_array(strtolower((string) $expr->right->name), ['count', 'sizeof', 'strlen'], true) - ) - ) { - $inverseOperator = $expr instanceof Node\Expr\BinaryOp\Smaller - ? new Node\Expr\BinaryOp\SmallerOrEqual($expr->right, $expr->left) - : new Node\Expr\BinaryOp\Smaller($expr->right, $expr->left); - - return $this->specifyTypesInCondition($scope, new Node\Expr\BooleanNot($inverseOperator), $context, $rootExpr); - } - - $orEqual = $expr instanceof Node\Expr\BinaryOp\SmallerOrEqual; - $offset = $orEqual ? 0 : 1; - $leftType = $scope->getType($expr->left); - $result = new SpecifiedTypes([], [], false, [], $rootExpr); - - if ( - !$context->null() - && $expr->right instanceof FuncCall - && count($expr->right->getArgs()) === 1 - && $expr->right->name instanceof Name - && in_array(strtolower((string) $expr->right->name), ['count', 'sizeof'], true) - && $leftType->isInteger()->yes() - ) { - if ( - $context->truthy() && (IntegerRangeType::createAllGreaterThanOrEqualTo(1 - $offset)->isSuperTypeOf($leftType)->yes()) - || ($context->falsey() && (new ConstantIntegerType(1 - $offset))->isSuperTypeOf($leftType)->yes()) - ) { - $argType = $scope->getType($expr->right->getArgs()[0]->value); - if ($argType->isArray()->yes()) { - $newType = new NonEmptyArrayType(); - if ($context->truthy() && $argType->isList()->yes()) { - $newType = AccessoryArrayListType::intersectWith($newType); - } - - $result = $result->unionWith($this->create($expr->right->getArgs()[0]->value, $newType, $context, false, $scope, $rootExpr)); - } - } - } - - if ( - !$context->null() - && $expr->right instanceof FuncCall - && count($expr->right->getArgs()) === 1 - && $expr->right->name instanceof Name - && strtolower((string) $expr->right->name) === 'strlen' - && $leftType->isInteger()->yes() - ) { - if ( - $context->truthy() && (IntegerRangeType::createAllGreaterThanOrEqualTo(1 - $offset)->isSuperTypeOf($leftType)->yes()) - || ($context->falsey() && (new ConstantIntegerType(1 - $offset))->isSuperTypeOf($leftType)->yes()) - ) { - $argType = $scope->getType($expr->right->getArgs()[0]->value); - if ($argType->isString()->yes()) { - $accessory = new AccessoryNonEmptyStringType(); - if ($leftType instanceof ConstantIntegerType && $leftType->getValue() >= 2) { - $accessory = new AccessoryNonFalsyStringType(); - } - - $result = $result->unionWith($this->create($expr->right->getArgs()[0]->value, $accessory, $context, false, $scope, $rootExpr)); - } - } - } - - if ($leftType instanceof ConstantIntegerType) { - if ($expr->right instanceof Expr\PostInc) { - $result = $result->unionWith($this->createRangeTypes($rootExpr, $expr->right->var, IntegerRangeType::fromInterval($leftType->getValue(), null, $offset + 1), $context)); - } elseif ($expr->right instanceof Expr\PostDec) { - $result = $result->unionWith($this->createRangeTypes($rootExpr, $expr->right->var, IntegerRangeType::fromInterval($leftType->getValue(), null, $offset - 1), $context)); - } elseif ($expr->right instanceof Expr\PreInc || $expr->right instanceof Expr\PreDec) { - $result = $result->unionWith($this->createRangeTypes($rootExpr, $expr->right->var, IntegerRangeType::fromInterval($leftType->getValue(), null, $offset), $context)); - } - } - - $rightType = $scope->getType($expr->right); - if ($rightType instanceof ConstantIntegerType) { - if ($expr->left instanceof Expr\PostInc) { - $result = $result->unionWith($this->createRangeTypes($rootExpr, $expr->left->var, IntegerRangeType::fromInterval(null, $rightType->getValue(), -$offset + 1), $context)); - } elseif ($expr->left instanceof Expr\PostDec) { - $result = $result->unionWith($this->createRangeTypes($rootExpr, $expr->left->var, IntegerRangeType::fromInterval(null, $rightType->getValue(), -$offset - 1), $context)); - } elseif ($expr->left instanceof Expr\PreInc || $expr->left instanceof Expr\PreDec) { - $result = $result->unionWith($this->createRangeTypes($rootExpr, $expr->left->var, IntegerRangeType::fromInterval(null, $rightType->getValue(), -$offset), $context)); - } - } - - if ($context->true()) { - if (!$expr->left instanceof Node\Scalar) { - $result = $result->unionWith($this->create($expr->left, $orEqual ? $rightType->getSmallerOrEqualType() : $rightType->getSmallerType(), TypeSpecifierContext::createTruthy(), false, $scope, $rootExpr)); - } - if (!$expr->right instanceof Node\Scalar) { - $result = $result->unionWith($this->create($expr->right, $orEqual ? $leftType->getGreaterOrEqualType() : $leftType->getGreaterType(), TypeSpecifierContext::createTruthy(), false, $scope, $rootExpr)); - } - } elseif ($context->false()) { - if (!$expr->left instanceof Node\Scalar) { - $result = $result->unionWith($this->create($expr->left, $orEqual ? $rightType->getGreaterType() : $rightType->getGreaterOrEqualType(), TypeSpecifierContext::createTruthy(), false, $scope, $rootExpr)); - } - if (!$expr->right instanceof Node\Scalar) { - $result = $result->unionWith($this->create($expr->right, $orEqual ? $leftType->getSmallerType() : $leftType->getSmallerOrEqualType(), TypeSpecifierContext::createTruthy(), false, $scope, $rootExpr)); - } - } - - return $result; - - } elseif ($expr instanceof Node\Expr\BinaryOp\Greater) { - return $this->specifyTypesInCondition($scope, new Expr\BinaryOp\Smaller($expr->right, $expr->left), $context, $rootExpr); - - } elseif ($expr instanceof Node\Expr\BinaryOp\GreaterOrEqual) { - return $this->specifyTypesInCondition($scope, new Expr\BinaryOp\SmallerOrEqual($expr->right, $expr->left), $context, $rootExpr); - - } elseif ($expr instanceof FuncCall && $expr->name instanceof Name) { - if ($this->reflectionProvider->hasFunction($expr->name, $scope)) { - $functionReflection = $this->reflectionProvider->getFunction($expr->name, $scope); - foreach ($this->getFunctionTypeSpecifyingExtensions() as $extension) { - if (!$extension->isFunctionSupported($functionReflection, $expr, $context)) { - continue; - } - - return $extension->specifyTypes($functionReflection, $expr, $scope, $context); - } - - // lazy create parametersAcceptor, as creation can be expensive - $parametersAcceptor = null; - if (count($expr->getArgs()) > 0) { - $parametersAcceptor = ParametersAcceptorSelector::selectFromArgs($scope, $expr->getArgs(), $functionReflection->getVariants(), $functionReflection->getNamedArgumentsVariants()); - - $specifiedTypes = $this->specifyTypesFromConditionalReturnType($context, $expr, $parametersAcceptor, $scope); - if ($specifiedTypes !== null) { - return $specifiedTypes; - } - } - - $assertions = $functionReflection->getAsserts(); - if ($assertions->getAll() !== []) { - $parametersAcceptor = $parametersAcceptor ?? ParametersAcceptorSelector::selectFromArgs($scope, $expr->getArgs(), $functionReflection->getVariants(), $functionReflection->getNamedArgumentsVariants()); - - $asserts = $assertions->mapTypes(static function (Type $type) use($parametersAcceptor) { - return TemplateTypeHelper::resolveTemplateTypes($type, $parametersAcceptor->getResolvedTemplateTypeMap(), $parametersAcceptor instanceof ParametersAcceptorWithPhpDocs ? $parametersAcceptor->getCallSiteVarianceMap() : TemplateTypeVarianceMap::createEmpty(), TemplateTypeVariance::createInvariant()); - }); - $specifiedTypes = $this->specifyTypesFromAsserts($context, $expr, $asserts, $parametersAcceptor, $scope); - if ($specifiedTypes !== null) { - return $specifiedTypes; - } - } - } - - return $this->handleDefaultTruthyOrFalseyContext($context, $rootExpr, $expr, $scope); - } elseif ($expr instanceof MethodCall && $expr->name instanceof Node\Identifier) { - $methodCalledOnType = $scope->getType($expr->var); - $methodReflection = $scope->getMethodReflection($methodCalledOnType, $expr->name->name); - if ($methodReflection !== null) { - $referencedClasses = $methodCalledOnType->getObjectClassNames(); - if ( - count($referencedClasses) === 1 - && $this->reflectionProvider->hasClass($referencedClasses[0]) - ) { - $methodClassReflection = $this->reflectionProvider->getClass($referencedClasses[0]); - foreach ($this->getMethodTypeSpecifyingExtensionsForClass($methodClassReflection->getName()) as $extension) { - if (!$extension->isMethodSupported($methodReflection, $expr, $context)) { - continue; - } - - return $extension->specifyTypes($methodReflection, $expr, $scope, $context); - } - } - - // lazy create parametersAcceptor, as creation can be expensive - $parametersAcceptor = null; - if (count($expr->getArgs()) > 0) { - $parametersAcceptor = ParametersAcceptorSelector::selectFromArgs($scope, $expr->getArgs(), $methodReflection->getVariants(), $methodReflection->getNamedArgumentsVariants()); - - $specifiedTypes = $this->specifyTypesFromConditionalReturnType($context, $expr, $parametersAcceptor, $scope); - if ($specifiedTypes !== null) { - return $specifiedTypes; - } - } - - $assertions = $methodReflection->getAsserts(); - if ($assertions->getAll() !== []) { - $parametersAcceptor = $parametersAcceptor ?? ParametersAcceptorSelector::selectFromArgs($scope, $expr->getArgs(), $methodReflection->getVariants(), $methodReflection->getNamedArgumentsVariants()); - - $asserts = $assertions->mapTypes(static function (Type $type) use($parametersAcceptor) { - return TemplateTypeHelper::resolveTemplateTypes($type, $parametersAcceptor->getResolvedTemplateTypeMap(), $parametersAcceptor instanceof ParametersAcceptorWithPhpDocs ? $parametersAcceptor->getCallSiteVarianceMap() : TemplateTypeVarianceMap::createEmpty(), TemplateTypeVariance::createInvariant()); - }); - $specifiedTypes = $this->specifyTypesFromAsserts($context, $expr, $asserts, $parametersAcceptor, $scope); - if ($specifiedTypes !== null) { - return $specifiedTypes; - } - } - } - - return $this->handleDefaultTruthyOrFalseyContext($context, $rootExpr, $expr, $scope); - } elseif ($expr instanceof StaticCall && $expr->name instanceof Node\Identifier) { - if ($expr->class instanceof Name) { - $calleeType = $scope->resolveTypeByName($expr->class); - } else { - $calleeType = $scope->getType($expr->class); - } - - $staticMethodReflection = $scope->getMethodReflection($calleeType, $expr->name->name); - if ($staticMethodReflection !== null) { - $referencedClasses = $calleeType->getObjectClassNames(); - if ( - count($referencedClasses) === 1 - && $this->reflectionProvider->hasClass($referencedClasses[0]) - ) { - $staticMethodClassReflection = $this->reflectionProvider->getClass($referencedClasses[0]); - foreach ($this->getStaticMethodTypeSpecifyingExtensionsForClass($staticMethodClassReflection->getName()) as $extension) { - if (!$extension->isStaticMethodSupported($staticMethodReflection, $expr, $context)) { - continue; - } - - return $extension->specifyTypes($staticMethodReflection, $expr, $scope, $context); - } - } - - // lazy create parametersAcceptor, as creation can be expensive - $parametersAcceptor = null; - if (count($expr->getArgs()) > 0) { - $parametersAcceptor = ParametersAcceptorSelector::selectFromArgs($scope, $expr->getArgs(), $staticMethodReflection->getVariants(), $staticMethodReflection->getNamedArgumentsVariants()); - - $specifiedTypes = $this->specifyTypesFromConditionalReturnType($context, $expr, $parametersAcceptor, $scope); - if ($specifiedTypes !== null) { - return $specifiedTypes; - } - } - - $assertions = $staticMethodReflection->getAsserts(); - if ($assertions->getAll() !== []) { - $parametersAcceptor = $parametersAcceptor ?? ParametersAcceptorSelector::selectFromArgs($scope, $expr->getArgs(), $staticMethodReflection->getVariants(), $staticMethodReflection->getNamedArgumentsVariants()); - - $asserts = $assertions->mapTypes(static function (Type $type) use($parametersAcceptor) { - return TemplateTypeHelper::resolveTemplateTypes($type, $parametersAcceptor->getResolvedTemplateTypeMap(), $parametersAcceptor instanceof ParametersAcceptorWithPhpDocs ? $parametersAcceptor->getCallSiteVarianceMap() : TemplateTypeVarianceMap::createEmpty(), TemplateTypeVariance::createInvariant()); - }); - $specifiedTypes = $this->specifyTypesFromAsserts($context, $expr, $asserts, $parametersAcceptor, $scope); - if ($specifiedTypes !== null) { - return $specifiedTypes; - } - } - } - - return $this->handleDefaultTruthyOrFalseyContext($context, $rootExpr, $expr, $scope); - } elseif ($expr instanceof BooleanAnd || $expr instanceof LogicalAnd) { - if (!$scope instanceof MutatingScope) { - throw new ShouldNotHappenException(); - } - $leftTypes = $this->specifyTypesInCondition($scope, $expr->left, $context, $rootExpr); - $rightScope = $scope->filterByTruthyValue($expr->left); - $rightTypes = $this->specifyTypesInCondition($rightScope, $expr->right, $context, $rootExpr); - $types = $context->true() ? $leftTypes->unionWith($rightTypes) : $leftTypes->normalize($scope)->intersectWith($rightTypes->normalize($rightScope)); - if ($context->false()) { - return new SpecifiedTypes($types->getSureTypes(), $types->getSureNotTypes(), false, array_merge($this->processBooleanNotSureConditionalTypes($scope, $leftTypes, $rightTypes), $this->processBooleanNotSureConditionalTypes($scope, $rightTypes, $leftTypes), $this->processBooleanSureConditionalTypes($scope, $leftTypes, $rightTypes), $this->processBooleanSureConditionalTypes($scope, $rightTypes, $leftTypes)), $rootExpr); - } - - return $types; - } elseif ($expr instanceof BooleanOr || $expr instanceof LogicalOr) { - if (!$scope instanceof MutatingScope) { - throw new ShouldNotHappenException(); - } - $leftTypes = $this->specifyTypesInCondition($scope, $expr->left, $context, $rootExpr); - $rightScope = $scope->filterByFalseyValue($expr->left); - $rightTypes = $this->specifyTypesInCondition($rightScope, $expr->right, $context, $rootExpr); - $types = $context->true() ? $leftTypes->normalize($scope)->intersectWith($rightTypes->normalize($rightScope)) : $leftTypes->unionWith($rightTypes); - if ($context->true()) { - return new SpecifiedTypes($types->getSureTypes(), $types->getSureNotTypes(), false, array_merge($this->processBooleanNotSureConditionalTypes($scope, $leftTypes, $rightTypes), $this->processBooleanNotSureConditionalTypes($scope, $rightTypes, $leftTypes), $this->processBooleanSureConditionalTypes($scope, $leftTypes, $rightTypes), $this->processBooleanSureConditionalTypes($scope, $rightTypes, $leftTypes)), $rootExpr); - } - - return $types; - } elseif ($expr instanceof Node\Expr\BooleanNot && !$context->null()) { - return $this->specifyTypesInCondition($scope, $expr->expr, $context->negate(), $rootExpr); - } elseif ($expr instanceof Node\Expr\Assign) { - if (!$scope instanceof MutatingScope) { - throw new ShouldNotHappenException(); - } - if ($context->null()) { - return $this->specifyTypesInCondition($scope->exitFirstLevelStatements(), $expr->expr, $context, $rootExpr); - } - - return $this->specifyTypesInCondition($scope->exitFirstLevelStatements(), $expr->var, $context, $rootExpr); - } elseif ( - $expr instanceof Expr\Isset_ - && count($expr->vars) > 0 - && !$context->null() - ) { - // rewrite multi param isset() to and-chained single param isset() - if (count($expr->vars) > 1) { - $issets = []; - foreach ($expr->vars as $var) { - $issets[] = new Expr\Isset_([$var], $expr->getAttributes()); - } - - $first = array_shift($issets); - $andChain = null; - foreach ($issets as $isset) { - if ($andChain === null) { - $andChain = new BooleanAnd($first, $isset); - continue; - } - - $andChain = new BooleanAnd($andChain, $isset); - } - - if ($andChain === null) { - throw new ShouldNotHappenException(); - } - - return $this->specifyTypesInCondition($scope, $andChain, $context, $rootExpr); - } - - $issetExpr = $expr->vars[0]; - - if (!$context->true()) { - if (!$scope instanceof MutatingScope) { - throw new ShouldNotHappenException(); - } - - $isset = $scope->issetCheck($issetExpr, static function () { - return true; - }); - - if ($isset === false) { - return new SpecifiedTypes(); - } - - $type = $scope->getType($issetExpr); - $isNullable = !$type->isNull()->no(); - $exprType = $this->create($issetExpr, new NullType(), $context->negate(), false, $scope, $rootExpr); - - if ($issetExpr instanceof Expr\Variable && is_string($issetExpr->name)) { - if ($isset === true) { - if ($isNullable) { - return $exprType; - } - - // variable cannot exist in !isset() - return $exprType->unionWith($this->create(new IssetExpr($issetExpr), new NullType(), $context, false, $scope, $rootExpr)); - } - - if ($isNullable) { - // reduces variable certainty to maybe - return $exprType->unionWith($this->create(new IssetExpr($issetExpr), new NullType(), $context->negate(), false, $scope, $rootExpr)); - } - - // variable cannot exist in !isset() - return $this->create(new IssetExpr($issetExpr), new NullType(), $context, false, $scope, $rootExpr); - } - - if ($isNullable && $isset === true) { - return $exprType; - } - - return new SpecifiedTypes(); - } - - $tmpVars = [$issetExpr]; - while ( - $issetExpr instanceof ArrayDimFetch - || $issetExpr instanceof PropertyFetch - || ( - $issetExpr instanceof StaticPropertyFetch - && $issetExpr->class instanceof Expr - ) - ) { - if ($issetExpr instanceof StaticPropertyFetch) { - /** @var Expr $issetExpr */ - $issetExpr = $issetExpr->class; - } else { - $issetExpr = $issetExpr->var; - } - $tmpVars[] = $issetExpr; - } - $vars = array_reverse($tmpVars); - - $types = new SpecifiedTypes(); - foreach ($vars as $var) { - - if ($var instanceof Expr\Variable && is_string($var->name)) { - if ($scope->hasVariableType($var->name)->no()) { - return new SpecifiedTypes([], [], false, [], $rootExpr); - } - } - - if ( - $var instanceof ArrayDimFetch - && $var->dim !== null - && !$scope->getType($var->var) instanceof MixedType - ) { - $dimType = $scope->getType($var->dim); - - if ($dimType instanceof ConstantIntegerType || $dimType instanceof ConstantStringType) { - $types = $types->unionWith($this->create($var->var, new HasOffsetType($dimType), $context, false, $scope, $rootExpr)); - } - } - - if ( - $var instanceof PropertyFetch - && $var->name instanceof Node\Identifier - ) { - $types = $types->unionWith($this->create($var->var, new IntersectionType([ - new ObjectWithoutClassType(), - new HasPropertyType($var->name->toString()), - ]), TypeSpecifierContext::createTruthy(), false, $scope, $rootExpr)); - } elseif ( - $var instanceof StaticPropertyFetch - && $var->class instanceof Expr - && $var->name instanceof Node\VarLikeIdentifier - ) { - $types = $types->unionWith($this->create($var->class, new IntersectionType([ - new ObjectWithoutClassType(), - new HasPropertyType($var->name->toString()), - ]), TypeSpecifierContext::createTruthy(), false, $scope, $rootExpr)); - } - - $types = $types->unionWith($this->create($var, new NullType(), TypeSpecifierContext::createFalse(), false, $scope, $rootExpr)); - } - - return $types; - } elseif ( - $expr instanceof Expr\BinaryOp\Coalesce - && !$context->null() - ) { - if (!$context->true()) { - if (!$scope instanceof MutatingScope) { - throw new ShouldNotHappenException(); - } - - $isset = $scope->issetCheck($expr->left, static function () { - return true; - }); - - if ($isset !== true) { - return new SpecifiedTypes(); - } - - return $this->create($expr->left, new NullType(), $context->negate(), false, $scope, $rootExpr); - } - - if ((new ConstantBooleanType(false))->isSuperTypeOf($scope->getType($expr->right)->toBoolean())->yes()) { - return $this->create($expr->left, new NullType(), TypeSpecifierContext::createFalse(), false, $scope, $rootExpr); - } - - } elseif ( - $expr instanceof Expr\Empty_ - ) { - if (!$scope instanceof MutatingScope) { - throw new ShouldNotHappenException(); - } - - $isset = $scope->issetCheck($expr->expr, static function () { - return true; - }); - if ($isset === false) { - return new SpecifiedTypes(); - } - - return $this->specifyTypesInCondition($scope, new BooleanOr(new Expr\BooleanNot(new Expr\Isset_([$expr->expr])), new Expr\BooleanNot($expr->expr)), $context, $rootExpr); - } elseif ($expr instanceof Expr\ErrorSuppress) { - return $this->specifyTypesInCondition($scope, $expr->expr, $context, $rootExpr); - } elseif ( - $expr instanceof Expr\Ternary - && !$context->null() - && $scope->getType($expr->else)->isFalse()->yes() - ) { - $conditionExpr = $expr->cond; - if ($expr->if !== null) { - $conditionExpr = new BooleanAnd($conditionExpr, $expr->if); - } - - return $this->specifyTypesInCondition($scope, $conditionExpr, $context, $rootExpr); - - } elseif ($expr instanceof Expr\NullsafePropertyFetch && !$context->null()) { - $types = $this->specifyTypesInCondition($scope, new BooleanAnd(new Expr\BinaryOp\NotIdentical($expr->var, new ConstFetch(new Name('null'))), new PropertyFetch($expr->var, $expr->name)), $context, $rootExpr); - - $nullSafeTypes = $this->handleDefaultTruthyOrFalseyContext($context, $rootExpr, $expr, $scope); - return $context->true() ? $types->unionWith($nullSafeTypes) : $types->normalize($scope)->intersectWith($nullSafeTypes->normalize($scope)); - } elseif ($expr instanceof Expr\NullsafeMethodCall && !$context->null()) { - $types = $this->specifyTypesInCondition($scope, new BooleanAnd(new Expr\BinaryOp\NotIdentical($expr->var, new ConstFetch(new Name('null'))), new MethodCall($expr->var, $expr->name, $expr->args)), $context, $rootExpr); - - $nullSafeTypes = $this->handleDefaultTruthyOrFalseyContext($context, $rootExpr, $expr, $scope); - return $context->true() ? $types->unionWith($nullSafeTypes) : $types->normalize($scope)->intersectWith($nullSafeTypes->normalize($scope)); - } elseif (!$context->null()) { - return $this->handleDefaultTruthyOrFalseyContext($context, $rootExpr, $expr, $scope); - } - return new SpecifiedTypes([], [], false, [], $rootExpr); - } - - private function specifyTypesForConstantBinaryExpression(Expr $exprNode, ConstantScalarType $constantType, TypeSpecifierContext $context, Scope $scope, ?Expr $rootExpr) : ?SpecifiedTypes - { - if (!$context->null() && $constantType->getValue() === false) { - $types = $this->create($exprNode, $constantType, $context, false, $scope, $rootExpr); - if ($exprNode instanceof Expr\NullsafeMethodCall || $exprNode instanceof Expr\NullsafePropertyFetch) { - return $types; - } - - return $types->unionWith($this->specifyTypesInCondition($scope, $exprNode, $context->true() ? TypeSpecifierContext::createFalse() : TypeSpecifierContext::createFalse()->negate(), $rootExpr)); - } - if (!$context->null() && $constantType->getValue() === true) { - $types = $this->create($exprNode, $constantType, $context, false, $scope, $rootExpr); - if ($exprNode instanceof Expr\NullsafeMethodCall || $exprNode instanceof Expr\NullsafePropertyFetch) { - return $types; - } - - return $types->unionWith($this->specifyTypesInCondition($scope, $exprNode, $context->true() ? TypeSpecifierContext::createTrue() : TypeSpecifierContext::createTrue()->negate(), $rootExpr)); - } - if ($constantType->getValue() === null) { - return $this->create($exprNode, $constantType, $context, false, $scope, $rootExpr); - } - if ( - !$context->null() - && $exprNode instanceof FuncCall - && count($exprNode->getArgs()) === 1 - && $exprNode->name instanceof Name - && in_array(strtolower((string) $exprNode->name), ['count', 'sizeof'], true) - && $constantType instanceof ConstantIntegerType - ) { - if ($context->truthy() || $constantType->getValue() === 0) { - $newContext = $context; - if ($constantType->getValue() === 0) { - $newContext = $newContext->negate(); - } - $argType = $scope->getType($exprNode->getArgs()[0]->value); - if ($argType->isArray()->yes()) { - $funcTypes = $this->create($exprNode, $constantType, $context, false, $scope, $rootExpr); - if ($argType->isList()->yes() && $context->truthy() && $constantType->getValue() < ConstantArrayTypeBuilder::ARRAY_COUNT_LIMIT) { - $valueTypesBuilder = ConstantArrayTypeBuilder::createEmpty(); - $itemType = $argType->getIterableValueType(); - for ($i = 0; $i < $constantType->getValue(); $i++) { - $valueTypesBuilder->setOffsetValueType(new ConstantIntegerType($i), $itemType); - } - $valueTypes = $this->create($exprNode->getArgs()[0]->value, $valueTypesBuilder->getArray(), $context, false, $scope, $rootExpr); - } else { - $valueTypes = $this->create($exprNode->getArgs()[0]->value, new NonEmptyArrayType(), $newContext, false, $scope, $rootExpr); - } - return $funcTypes->unionWith($valueTypes); - } - } - } - if ( - !$context->null() - && $exprNode instanceof FuncCall - && count($exprNode->getArgs()) === 1 - && $exprNode->name instanceof Name - && strtolower((string) $exprNode->name) === 'strlen' - && $constantType instanceof ConstantIntegerType - ) { - if ($context->truthy() || $constantType->getValue() === 0) { - $newContext = $context; - if ($constantType->getValue() === 0) { - $newContext = $newContext->negate(); - } - $argType = $scope->getType($exprNode->getArgs()[0]->value); - if ($argType->isString()->yes()) { - $funcTypes = $this->create($exprNode, $constantType, $context, false, $scope, $rootExpr); - - $accessory = new AccessoryNonEmptyStringType(); - if ($constantType->getValue() >= 2) { - $accessory = new AccessoryNonFalsyStringType(); - } - $valueTypes = $this->create($exprNode->getArgs()[0]->value, $accessory, $newContext, false, $scope, $rootExpr); - - return $funcTypes->unionWith($valueTypes); - } - } - - } - return null; - } - - private function specifyTypesForConstantStringBinaryExpression(Expr $exprNode, ConstantStringType $constantType, TypeSpecifierContext $context, Scope $scope, ?Expr $rootExpr) : ?SpecifiedTypes - { - if ( - $context->truthy() - && $exprNode instanceof FuncCall - && $exprNode->name instanceof Name - && in_array(strtolower($exprNode->name->toString()), ['substr', 'strstr', 'stristr', 'strchr', 'strrchr', 'strtolower', 'strtoupper', 'mb_strtolower', 'mb_strtoupper', 'ucfirst', 'lcfirst', 'ucwords', 'mb_convert_case', 'mb_convert_kana'], true) - && isset($exprNode->getArgs()[0]) - && $constantType->getValue() !== '' - ) { - $argType = $scope->getType($exprNode->getArgs()[0]->value); - - if ($argType->isString()->yes()) { - if ($constantType->getValue() !== '0') { - return $this->create($exprNode->getArgs()[0]->value, TypeCombinator::intersect($argType, new AccessoryNonFalsyStringType()), $context, false, $scope); - } - - return $this->create($exprNode->getArgs()[0]->value, TypeCombinator::intersect($argType, new AccessoryNonEmptyStringType()), $context, false, $scope); - } - } - if ( - $exprNode instanceof FuncCall - && $exprNode->name instanceof Name - && strtolower($exprNode->name->toString()) === 'gettype' - && isset($exprNode->getArgs()[0]) - ) { - $type = null; - if ($constantType->getValue() === 'string') { - $type = new StringType(); - } - if ($constantType->getValue() === 'array') { - $type = new ArrayType(new MixedType(), new MixedType()); - } - if ($constantType->getValue() === 'boolean') { - $type = new BooleanType(); - } - if (in_array($constantType->getValue(), ['resource', 'resource (closed)'], true)) { - $type = new ResourceType(); - } - if ($constantType->getValue() === 'integer') { - $type = new IntegerType(); - } - if ($constantType->getValue() === 'double') { - $type = new FloatType(); - } - if ($constantType->getValue() === 'NULL') { - $type = new NullType(); - } - if ($constantType->getValue() === 'object') { - $type = new ObjectWithoutClassType(); - } - - if ($type !== null) { - $callType = $this->create($exprNode, $constantType, $context, false, $scope, $rootExpr); - $argType = $this->create($exprNode->getArgs()[0]->value, $type, $context, false, $scope, $rootExpr); - return $callType->unionWith($argType); - } - } - if ( - $context->true() - && $exprNode instanceof FuncCall - && $exprNode->name instanceof Name - && strtolower((string) $exprNode->name) === 'get_parent_class' - && isset($exprNode->getArgs()[0]) - ) { - $argType = $scope->getType($exprNode->getArgs()[0]->value); - $objectType = new ObjectType($constantType->getValue()); - $classStringType = new GenericClassStringType($objectType); - - if ($argType->isString()->yes()) { - return $this->create($exprNode->getArgs()[0]->value, $classStringType, $context, false, $scope); - } - - if ($argType->isObject()->yes()) { - return $this->create($exprNode->getArgs()[0]->value, $objectType, $context, false, $scope); - } - - return $this->create($exprNode->getArgs()[0]->value, TypeCombinator::union($objectType, $classStringType), $context, false, $scope); - } - return null; + public function specifyTypesInCondition( + Scope $scope, + Expr $expr, + TypeSpecifierContext $context, + ?Expr $rootExpr = null, + ): SpecifiedTypes + { + $rootExpr ??= $expr; + + if ($expr instanceof Expr\CallLike && $expr->isFirstClassCallable()) { + return new SpecifiedTypes([], [], false, [], $rootExpr); + } + + if ($expr instanceof Instanceof_) { + $exprNode = $expr->expr; + if ($expr->class instanceof Name) { + $className = (string) $expr->class; + $lowercasedClassName = strtolower($className); + if ($lowercasedClassName === 'self' && $scope->isInClass()) { + $type = new ObjectType($scope->getClassReflection()->getName()); + } elseif ($lowercasedClassName === 'static' && $scope->isInClass()) { + $type = new StaticType($scope->getClassReflection()); + } elseif ($lowercasedClassName === 'parent') { + if ( + $scope->isInClass() + && $scope->getClassReflection()->getParentClass() !== null + ) { + $type = new ObjectType($scope->getClassReflection()->getParentClass()->getName()); + } else { + $type = new NonexistentParentClassType(); + } + } else { + $type = new ObjectType($className); + } + return $this->create($exprNode, $type, $context, false, $scope, $rootExpr); + } + + $classType = $scope->getType($expr->class); + $type = TypeTraverser::map($classType, static function (Type $type, callable $traverse): Type { + if ($type instanceof UnionType || $type instanceof IntersectionType) { + return $traverse($type); + } + if ($type->getObjectClassNames() !== []) { + return $type; + } + if ($type instanceof GenericClassStringType) { + return $type->getGenericType(); + } + if ($type instanceof ConstantStringType) { + return new ObjectType($type->getValue()); + } + return new MixedType(); + }); + + if (!$type->isSuperTypeOf(new MixedType())->yes()) { + if ($context->true()) { + $type = TypeCombinator::intersect( + $type, + new ObjectWithoutClassType(), + ); + return $this->create($exprNode, $type, $context, false, $scope, $rootExpr); + } elseif ($context->false()) { + $exprType = $scope->getType($expr->expr); + if (!$type->isSuperTypeOf($exprType)->yes()) { + return $this->create($exprNode, $type, $context, false, $scope, $rootExpr); + } + } + } + if ($context->true()) { + return $this->create($exprNode, new ObjectWithoutClassType(), $context, false, $scope, $rootExpr); + } + } elseif ($expr instanceof Node\Expr\BinaryOp\Identical) { + return $this->resolveIdentical($expr, $scope, $context, $rootExpr); + + } elseif ($expr instanceof Node\Expr\BinaryOp\NotIdentical) { + return $this->specifyTypesInCondition( + $scope, + new Node\Expr\BooleanNot(new Node\Expr\BinaryOp\Identical($expr->left, $expr->right)), + $context, + $rootExpr, + ); + } elseif ($expr instanceof Node\Expr\BinaryOp\Equal) { + return $this->resolveEqual($expr, $scope, $context, $rootExpr); + } elseif ($expr instanceof Node\Expr\BinaryOp\NotEqual) { + return $this->specifyTypesInCondition( + $scope, + new Node\Expr\BooleanNot(new Node\Expr\BinaryOp\Equal($expr->left, $expr->right)), + $context, + $rootExpr, + ); + + } elseif ($expr instanceof Node\Expr\BinaryOp\Smaller || $expr instanceof Node\Expr\BinaryOp\SmallerOrEqual) { + + if ( + $expr->left instanceof FuncCall + && count($expr->left->getArgs()) === 1 + && $expr->left->name instanceof Name + && in_array(strtolower((string) $expr->left->name), ['count', 'sizeof', 'strlen'], true) + && ( + !$expr->right instanceof FuncCall + || !$expr->right->name instanceof Name + || !in_array(strtolower((string) $expr->right->name), ['count', 'sizeof', 'strlen'], true) + ) + ) { + $inverseOperator = $expr instanceof Node\Expr\BinaryOp\Smaller + ? new Node\Expr\BinaryOp\SmallerOrEqual($expr->right, $expr->left) + : new Node\Expr\BinaryOp\Smaller($expr->right, $expr->left); + + return $this->specifyTypesInCondition( + $scope, + new Node\Expr\BooleanNot($inverseOperator), + $context, + $rootExpr, + ); + } + + $orEqual = $expr instanceof Node\Expr\BinaryOp\SmallerOrEqual; + $offset = $orEqual ? 0 : 1; + $leftType = $scope->getType($expr->left); + $result = new SpecifiedTypes([], [], false, [], $rootExpr); + + if ( + !$context->null() + && $expr->right instanceof FuncCall + && count($expr->right->getArgs()) === 1 + && $expr->right->name instanceof Name + && in_array(strtolower((string) $expr->right->name), ['count', 'sizeof'], true) + && $leftType->isInteger()->yes() + ) { + if ( + $context->truthy() && (IntegerRangeType::createAllGreaterThanOrEqualTo(1 - $offset)->isSuperTypeOf($leftType)->yes()) + || ($context->falsey() && (new ConstantIntegerType(1 - $offset))->isSuperTypeOf($leftType)->yes()) + ) { + $argType = $scope->getType($expr->right->getArgs()[0]->value); + if ($argType->isArray()->yes()) { + $newType = new NonEmptyArrayType(); + if ($context->truthy() && $argType->isList()->yes()) { + $newType = AccessoryArrayListType::intersectWith($newType); + } + + $result = $result->unionWith( + $this->create($expr->right->getArgs()[0]->value, $newType, $context, false, $scope, $rootExpr), + ); + } + } + } + + if ( + !$context->null() + && $expr->right instanceof FuncCall + && count($expr->right->getArgs()) === 1 + && $expr->right->name instanceof Name + && strtolower((string) $expr->right->name) === 'strlen' + && $leftType->isInteger()->yes() + ) { + if ( + $context->truthy() && (IntegerRangeType::createAllGreaterThanOrEqualTo(1 - $offset)->isSuperTypeOf($leftType)->yes()) + || ($context->falsey() && (new ConstantIntegerType(1 - $offset))->isSuperTypeOf($leftType)->yes()) + ) { + $argType = $scope->getType($expr->right->getArgs()[0]->value); + if ($argType->isString()->yes()) { + $accessory = new AccessoryNonEmptyStringType(); + if ($leftType instanceof ConstantIntegerType && $leftType->getValue() >= 2) { + $accessory = new AccessoryNonFalsyStringType(); + } + + $result = $result->unionWith($this->create($expr->right->getArgs()[0]->value, $accessory, $context, false, $scope, $rootExpr)); + } + } + } + + if ($leftType instanceof ConstantIntegerType) { + if ($expr->right instanceof Expr\PostInc) { + $result = $result->unionWith($this->createRangeTypes( + $rootExpr, + $expr->right->var, + IntegerRangeType::fromInterval($leftType->getValue(), null, $offset + 1), + $context, + )); + } elseif ($expr->right instanceof Expr\PostDec) { + $result = $result->unionWith($this->createRangeTypes( + $rootExpr, + $expr->right->var, + IntegerRangeType::fromInterval($leftType->getValue(), null, $offset - 1), + $context, + )); + } elseif ($expr->right instanceof Expr\PreInc || $expr->right instanceof Expr\PreDec) { + $result = $result->unionWith($this->createRangeTypes( + $rootExpr, + $expr->right->var, + IntegerRangeType::fromInterval($leftType->getValue(), null, $offset), + $context, + )); + } + } + + $rightType = $scope->getType($expr->right); + if ($rightType instanceof ConstantIntegerType) { + if ($expr->left instanceof Expr\PostInc) { + $result = $result->unionWith($this->createRangeTypes( + $rootExpr, + $expr->left->var, + IntegerRangeType::fromInterval(null, $rightType->getValue(), -$offset + 1), + $context, + )); + } elseif ($expr->left instanceof Expr\PostDec) { + $result = $result->unionWith($this->createRangeTypes( + $rootExpr, + $expr->left->var, + IntegerRangeType::fromInterval(null, $rightType->getValue(), -$offset - 1), + $context, + )); + } elseif ($expr->left instanceof Expr\PreInc || $expr->left instanceof Expr\PreDec) { + $result = $result->unionWith($this->createRangeTypes( + $rootExpr, + $expr->left->var, + IntegerRangeType::fromInterval(null, $rightType->getValue(), -$offset), + $context, + )); + } + } + + if ($context->true()) { + if (!$expr->left instanceof Node\Scalar) { + $result = $result->unionWith( + $this->create( + $expr->left, + $orEqual ? $rightType->getSmallerOrEqualType() : $rightType->getSmallerType(), + TypeSpecifierContext::createTruthy(), + false, + $scope, + $rootExpr, + ), + ); + } + if (!$expr->right instanceof Node\Scalar) { + $result = $result->unionWith( + $this->create( + $expr->right, + $orEqual ? $leftType->getGreaterOrEqualType() : $leftType->getGreaterType(), + TypeSpecifierContext::createTruthy(), + false, + $scope, + $rootExpr, + ), + ); + } + } elseif ($context->false()) { + if (!$expr->left instanceof Node\Scalar) { + $result = $result->unionWith( + $this->create( + $expr->left, + $orEqual ? $rightType->getGreaterType() : $rightType->getGreaterOrEqualType(), + TypeSpecifierContext::createTruthy(), + false, + $scope, + $rootExpr, + ), + ); + } + if (!$expr->right instanceof Node\Scalar) { + $result = $result->unionWith( + $this->create( + $expr->right, + $orEqual ? $leftType->getSmallerType() : $leftType->getSmallerOrEqualType(), + TypeSpecifierContext::createTruthy(), + false, + $scope, + $rootExpr, + ), + ); + } + } + + return $result; + + } elseif ($expr instanceof Node\Expr\BinaryOp\Greater) { + return $this->specifyTypesInCondition($scope, new Expr\BinaryOp\Smaller($expr->right, $expr->left), $context, $rootExpr); + + } elseif ($expr instanceof Node\Expr\BinaryOp\GreaterOrEqual) { + return $this->specifyTypesInCondition($scope, new Expr\BinaryOp\SmallerOrEqual($expr->right, $expr->left), $context, $rootExpr); + + } elseif ($expr instanceof FuncCall && $expr->name instanceof Name) { + if ($this->reflectionProvider->hasFunction($expr->name, $scope)) { + $functionReflection = $this->reflectionProvider->getFunction($expr->name, $scope); + foreach ($this->getFunctionTypeSpecifyingExtensions() as $extension) { + if (!$extension->isFunctionSupported($functionReflection, $expr, $context)) { + continue; + } + + return $extension->specifyTypes($functionReflection, $expr, $scope, $context); + } + + // lazy create parametersAcceptor, as creation can be expensive + $parametersAcceptor = null; + if (count($expr->getArgs()) > 0) { + $parametersAcceptor = ParametersAcceptorSelector::selectFromArgs($scope, $expr->getArgs(), $functionReflection->getVariants(), $functionReflection->getNamedArgumentsVariants()); + + $specifiedTypes = $this->specifyTypesFromConditionalReturnType($context, $expr, $parametersAcceptor, $scope); + if ($specifiedTypes !== null) { + return $specifiedTypes; + } + } + + $assertions = $functionReflection->getAsserts(); + if ($assertions->getAll() !== []) { + $parametersAcceptor ??= ParametersAcceptorSelector::selectFromArgs($scope, $expr->getArgs(), $functionReflection->getVariants(), $functionReflection->getNamedArgumentsVariants()); + + $asserts = $assertions->mapTypes(static fn (Type $type) => TemplateTypeHelper::resolveTemplateTypes( + $type, + $parametersAcceptor->getResolvedTemplateTypeMap(), + $parametersAcceptor instanceof ParametersAcceptorWithPhpDocs ? $parametersAcceptor->getCallSiteVarianceMap() : TemplateTypeVarianceMap::createEmpty(), + TemplateTypeVariance::createInvariant(), + )); + $specifiedTypes = $this->specifyTypesFromAsserts($context, $expr, $asserts, $parametersAcceptor, $scope); + if ($specifiedTypes !== null) { + return $specifiedTypes; + } + } } + return $this->handleDefaultTruthyOrFalseyContext($context, $rootExpr, $expr, $scope); + } elseif ($expr instanceof MethodCall && $expr->name instanceof Node\Identifier) { + $methodCalledOnType = $scope->getType($expr->var); + $methodReflection = $scope->getMethodReflection($methodCalledOnType, $expr->name->name); + if ($methodReflection !== null) { + $referencedClasses = $methodCalledOnType->getObjectClassNames(); + if ( + count($referencedClasses) === 1 + && $this->reflectionProvider->hasClass($referencedClasses[0]) + ) { + $methodClassReflection = $this->reflectionProvider->getClass($referencedClasses[0]); + foreach ($this->getMethodTypeSpecifyingExtensionsForClass($methodClassReflection->getName()) as $extension) { + if (!$extension->isMethodSupported($methodReflection, $expr, $context)) { + continue; + } + + return $extension->specifyTypes($methodReflection, $expr, $scope, $context); + } + } + + // lazy create parametersAcceptor, as creation can be expensive + $parametersAcceptor = null; + if (count($expr->getArgs()) > 0) { + $parametersAcceptor = ParametersAcceptorSelector::selectFromArgs($scope, $expr->getArgs(), $methodReflection->getVariants(), $methodReflection->getNamedArgumentsVariants()); + + $specifiedTypes = $this->specifyTypesFromConditionalReturnType($context, $expr, $parametersAcceptor, $scope); + if ($specifiedTypes !== null) { + return $specifiedTypes; + } + } + + $assertions = $methodReflection->getAsserts(); + if ($assertions->getAll() !== []) { + $parametersAcceptor ??= ParametersAcceptorSelector::selectFromArgs($scope, $expr->getArgs(), $methodReflection->getVariants(), $methodReflection->getNamedArgumentsVariants()); + + $asserts = $assertions->mapTypes(static fn (Type $type) => TemplateTypeHelper::resolveTemplateTypes( + $type, + $parametersAcceptor->getResolvedTemplateTypeMap(), + $parametersAcceptor instanceof ParametersAcceptorWithPhpDocs ? $parametersAcceptor->getCallSiteVarianceMap() : TemplateTypeVarianceMap::createEmpty(), + TemplateTypeVariance::createInvariant(), + )); + $specifiedTypes = $this->specifyTypesFromAsserts($context, $expr, $asserts, $parametersAcceptor, $scope); + if ($specifiedTypes !== null) { + return $specifiedTypes; + } + } + } + + return $this->handleDefaultTruthyOrFalseyContext($context, $rootExpr, $expr, $scope); + } elseif ($expr instanceof StaticCall && $expr->name instanceof Node\Identifier) { + if ($expr->class instanceof Name) { + $calleeType = $scope->resolveTypeByName($expr->class); + } else { + $calleeType = $scope->getType($expr->class); + } + + $staticMethodReflection = $scope->getMethodReflection($calleeType, $expr->name->name); + if ($staticMethodReflection !== null) { + $referencedClasses = $calleeType->getObjectClassNames(); + if ( + count($referencedClasses) === 1 + && $this->reflectionProvider->hasClass($referencedClasses[0]) + ) { + $staticMethodClassReflection = $this->reflectionProvider->getClass($referencedClasses[0]); + foreach ($this->getStaticMethodTypeSpecifyingExtensionsForClass($staticMethodClassReflection->getName()) as $extension) { + if (!$extension->isStaticMethodSupported($staticMethodReflection, $expr, $context)) { + continue; + } + + return $extension->specifyTypes($staticMethodReflection, $expr, $scope, $context); + } + } + + // lazy create parametersAcceptor, as creation can be expensive + $parametersAcceptor = null; + if (count($expr->getArgs()) > 0) { + $parametersAcceptor = ParametersAcceptorSelector::selectFromArgs($scope, $expr->getArgs(), $staticMethodReflection->getVariants(), $staticMethodReflection->getNamedArgumentsVariants()); + + $specifiedTypes = $this->specifyTypesFromConditionalReturnType($context, $expr, $parametersAcceptor, $scope); + if ($specifiedTypes !== null) { + return $specifiedTypes; + } + } + + $assertions = $staticMethodReflection->getAsserts(); + if ($assertions->getAll() !== []) { + $parametersAcceptor ??= ParametersAcceptorSelector::selectFromArgs($scope, $expr->getArgs(), $staticMethodReflection->getVariants(), $staticMethodReflection->getNamedArgumentsVariants()); + + $asserts = $assertions->mapTypes(static fn (Type $type) => TemplateTypeHelper::resolveTemplateTypes( + $type, + $parametersAcceptor->getResolvedTemplateTypeMap(), + $parametersAcceptor instanceof ParametersAcceptorWithPhpDocs ? $parametersAcceptor->getCallSiteVarianceMap() : TemplateTypeVarianceMap::createEmpty(), + TemplateTypeVariance::createInvariant(), + )); + $specifiedTypes = $this->specifyTypesFromAsserts($context, $expr, $asserts, $parametersAcceptor, $scope); + if ($specifiedTypes !== null) { + return $specifiedTypes; + } + } + } + + return $this->handleDefaultTruthyOrFalseyContext($context, $rootExpr, $expr, $scope); + } elseif ($expr instanceof BooleanAnd || $expr instanceof LogicalAnd) { + if (!$scope instanceof MutatingScope) { + throw new ShouldNotHappenException(); + } + $leftTypes = $this->specifyTypesInCondition($scope, $expr->left, $context, $rootExpr); + $rightScope = $scope->filterByTruthyValue($expr->left); + $rightTypes = $this->specifyTypesInCondition($rightScope, $expr->right, $context, $rootExpr); + $types = $context->true() ? $leftTypes->unionWith($rightTypes) : $leftTypes->normalize($scope)->intersectWith($rightTypes->normalize($rightScope)); + if ($context->false()) { + return new SpecifiedTypes( + $types->getSureTypes(), + $types->getSureNotTypes(), + false, + array_merge( + $this->processBooleanNotSureConditionalTypes($scope, $leftTypes, $rightTypes), + $this->processBooleanNotSureConditionalTypes($scope, $rightTypes, $leftTypes), + $this->processBooleanSureConditionalTypes($scope, $leftTypes, $rightTypes), + $this->processBooleanSureConditionalTypes($scope, $rightTypes, $leftTypes), + ), + $rootExpr, + ); + } + + return $types; + } elseif ($expr instanceof BooleanOr || $expr instanceof LogicalOr) { + if (!$scope instanceof MutatingScope) { + throw new ShouldNotHappenException(); + } + $leftTypes = $this->specifyTypesInCondition($scope, $expr->left, $context, $rootExpr); + $rightScope = $scope->filterByFalseyValue($expr->left); + $rightTypes = $this->specifyTypesInCondition($rightScope, $expr->right, $context, $rootExpr); + $types = $context->true() ? $leftTypes->normalize($scope)->intersectWith($rightTypes->normalize($rightScope)) : $leftTypes->unionWith($rightTypes); + if ($context->true()) { + return new SpecifiedTypes( + $types->getSureTypes(), + $types->getSureNotTypes(), + false, + array_merge( + $this->processBooleanNotSureConditionalTypes($scope, $leftTypes, $rightTypes), + $this->processBooleanNotSureConditionalTypes($scope, $rightTypes, $leftTypes), + $this->processBooleanSureConditionalTypes($scope, $leftTypes, $rightTypes), + $this->processBooleanSureConditionalTypes($scope, $rightTypes, $leftTypes), + ), + $rootExpr, + ); + } + + return $types; + } elseif ($expr instanceof Node\Expr\BooleanNot && !$context->null()) { + return $this->specifyTypesInCondition($scope, $expr->expr, $context->negate(), $rootExpr); + } elseif ($expr instanceof Node\Expr\Assign) { + if (!$scope instanceof MutatingScope) { + throw new ShouldNotHappenException(); + } + if ($context->null()) { + return $this->specifyTypesInCondition($scope->exitFirstLevelStatements(), $expr->expr, $context, $rootExpr); + } + + return $this->specifyTypesInCondition($scope->exitFirstLevelStatements(), $expr->var, $context, $rootExpr); + } elseif ( + $expr instanceof Expr\Isset_ + && count($expr->vars) > 0 + && !$context->null() + ) { + // rewrite multi param isset() to and-chained single param isset() + if (count($expr->vars) > 1) { + $issets = []; + foreach ($expr->vars as $var) { + $issets[] = new Expr\Isset_([$var], $expr->getAttributes()); + } + + $first = array_shift($issets); + $andChain = null; + foreach ($issets as $isset) { + if ($andChain === null) { + $andChain = new BooleanAnd($first, $isset); + continue; + } + + $andChain = new BooleanAnd($andChain, $isset); + } + + if ($andChain === null) { + throw new ShouldNotHappenException(); + } + + return $this->specifyTypesInCondition($scope, $andChain, $context, $rootExpr); + } + + $issetExpr = $expr->vars[0]; + + if (!$context->true()) { + if (!$scope instanceof MutatingScope) { + throw new ShouldNotHappenException(); + } + + $isset = $scope->issetCheck($issetExpr, static fn () => true); + + if ($isset === false) { + return new SpecifiedTypes(); + } + + $type = $scope->getType($issetExpr); + $isNullable = !$type->isNull()->no(); + $exprType = $this->create( + $issetExpr, + new NullType(), + $context->negate(), + false, + $scope, + $rootExpr, + ); + + if ($issetExpr instanceof Expr\Variable && is_string($issetExpr->name)) { + if ($isset === true) { + if ($isNullable) { + return $exprType; + } + + // variable cannot exist in !isset() + return $exprType->unionWith($this->create( + new IssetExpr($issetExpr), + new NullType(), + $context, + false, + $scope, + $rootExpr, + )); + } + + if ($isNullable) { + // reduces variable certainty to maybe + return $exprType->unionWith($this->create( + new IssetExpr($issetExpr), + new NullType(), + $context->negate(), + false, + $scope, + $rootExpr, + )); + } + + // variable cannot exist in !isset() + return $this->create( + new IssetExpr($issetExpr), + new NullType(), + $context, + false, + $scope, + $rootExpr, + ); + } + + if ($isNullable && $isset === true) { + return $exprType; + } + + return new SpecifiedTypes(); + } + + $tmpVars = [$issetExpr]; + while ( + $issetExpr instanceof ArrayDimFetch + || $issetExpr instanceof PropertyFetch + || ( + $issetExpr instanceof StaticPropertyFetch + && $issetExpr->class instanceof Expr + ) + ) { + if ($issetExpr instanceof StaticPropertyFetch) { + /** @var Expr $issetExpr */ + $issetExpr = $issetExpr->class; + } else { + $issetExpr = $issetExpr->var; + } + $tmpVars[] = $issetExpr; + } + $vars = array_reverse($tmpVars); + + $types = new SpecifiedTypes(); + foreach ($vars as $var) { + + if ($var instanceof Expr\Variable && is_string($var->name)) { + if ($scope->hasVariableType($var->name)->no()) { + return new SpecifiedTypes([], [], false, [], $rootExpr); + } + } + + if ( + $var instanceof ArrayDimFetch + && $var->dim !== null + && !$scope->getType($var->var) instanceof MixedType + ) { + $dimType = $scope->getType($var->dim); + + if ($dimType instanceof ConstantIntegerType || $dimType instanceof ConstantStringType) { + $types = $types->unionWith( + $this->create( + $var->var, + new HasOffsetType($dimType), + $context, + false, + $scope, + $rootExpr, + ), + ); + } + } + + if ( + $var instanceof PropertyFetch + && $var->name instanceof Node\Identifier + ) { + $types = $types->unionWith( + $this->create($var->var, new IntersectionType([ + new ObjectWithoutClassType(), + new HasPropertyType($var->name->toString()), + ]), TypeSpecifierContext::createTruthy(), false, $scope, $rootExpr), + ); + } elseif ( + $var instanceof StaticPropertyFetch + && $var->class instanceof Expr + && $var->name instanceof Node\VarLikeIdentifier + ) { + $types = $types->unionWith( + $this->create($var->class, new IntersectionType([ + new ObjectWithoutClassType(), + new HasPropertyType($var->name->toString()), + ]), TypeSpecifierContext::createTruthy(), false, $scope, $rootExpr), + ); + } + + $types = $types->unionWith( + $this->create($var, new NullType(), TypeSpecifierContext::createFalse(), false, $scope, $rootExpr), + ); + } + + return $types; + } elseif ( + $expr instanceof Expr\BinaryOp\Coalesce + && !$context->null() + ) { + if (!$context->true()) { + if (!$scope instanceof MutatingScope) { + throw new ShouldNotHappenException(); + } + + $isset = $scope->issetCheck($expr->left, static fn () => true); + + if ($isset !== true) { + return new SpecifiedTypes(); + } + + return $this->create( + $expr->left, + new NullType(), + $context->negate(), + false, + $scope, + $rootExpr, + ); + } + + if ((new ConstantBooleanType(false))->isSuperTypeOf($scope->getType($expr->right)->toBoolean())->yes()) { + return $this->create( + $expr->left, + new NullType(), + TypeSpecifierContext::createFalse(), + false, + $scope, + $rootExpr, + ); + } + + } elseif ( + $expr instanceof Expr\Empty_ + ) { + if (!$scope instanceof MutatingScope) { + throw new ShouldNotHappenException(); + } + + $isset = $scope->issetCheck($expr->expr, static fn () => true); + if ($isset === false) { + return new SpecifiedTypes(); + } + + return $this->specifyTypesInCondition($scope, new BooleanOr( + new Expr\BooleanNot(new Expr\Isset_([$expr->expr])), + new Expr\BooleanNot($expr->expr), + ), $context, $rootExpr); + } elseif ($expr instanceof Expr\ErrorSuppress) { + return $this->specifyTypesInCondition($scope, $expr->expr, $context, $rootExpr); + } elseif ( + $expr instanceof Expr\Ternary + && !$context->null() + && $scope->getType($expr->else)->isFalse()->yes() + ) { + $conditionExpr = $expr->cond; + if ($expr->if !== null) { + $conditionExpr = new BooleanAnd($conditionExpr, $expr->if); + } + + return $this->specifyTypesInCondition($scope, $conditionExpr, $context, $rootExpr); + + } elseif ($expr instanceof Expr\NullsafePropertyFetch && !$context->null()) { + $types = $this->specifyTypesInCondition( + $scope, + new BooleanAnd( + new Expr\BinaryOp\NotIdentical($expr->var, new ConstFetch(new Name('null'))), + new PropertyFetch($expr->var, $expr->name), + ), + $context, + $rootExpr, + ); + + $nullSafeTypes = $this->handleDefaultTruthyOrFalseyContext($context, $rootExpr, $expr, $scope); + return $context->true() ? $types->unionWith($nullSafeTypes) : $types->normalize($scope)->intersectWith($nullSafeTypes->normalize($scope)); + } elseif ($expr instanceof Expr\NullsafeMethodCall && !$context->null()) { + $types = $this->specifyTypesInCondition( + $scope, + new BooleanAnd( + new Expr\BinaryOp\NotIdentical($expr->var, new ConstFetch(new Name('null'))), + new MethodCall($expr->var, $expr->name, $expr->args), + ), + $context, + $rootExpr, + ); + + $nullSafeTypes = $this->handleDefaultTruthyOrFalseyContext($context, $rootExpr, $expr, $scope); + return $context->true() ? $types->unionWith($nullSafeTypes) : $types->normalize($scope)->intersectWith($nullSafeTypes->normalize($scope)); + } elseif (!$context->null()) { + return $this->handleDefaultTruthyOrFalseyContext($context, $rootExpr, $expr, $scope); + } + + return new SpecifiedTypes([], [], false, [], $rootExpr); + } + + private function specifyTypesForConstantBinaryExpression( + Expr $exprNode, + ConstantScalarType $constantType, + TypeSpecifierContext $context, + Scope $scope, + ?Expr $rootExpr, + ): ?SpecifiedTypes + { + if (!$context->null() && $constantType->getValue() === false) { + $types = $this->create($exprNode, $constantType, $context, false, $scope, $rootExpr); + if ($exprNode instanceof Expr\NullsafeMethodCall || $exprNode instanceof Expr\NullsafePropertyFetch) { + return $types; + } + + return $types->unionWith($this->specifyTypesInCondition( + $scope, + $exprNode, + $context->true() ? TypeSpecifierContext::createFalse() : TypeSpecifierContext::createFalse()->negate(), + $rootExpr, + )); + } + + if (!$context->null() && $constantType->getValue() === true) { + $types = $this->create($exprNode, $constantType, $context, false, $scope, $rootExpr); + if ($exprNode instanceof Expr\NullsafeMethodCall || $exprNode instanceof Expr\NullsafePropertyFetch) { + return $types; + } + + return $types->unionWith($this->specifyTypesInCondition( + $scope, + $exprNode, + $context->true() ? TypeSpecifierContext::createTrue() : TypeSpecifierContext::createTrue()->negate(), + $rootExpr, + )); + } + + if ($constantType->getValue() === null) { + return $this->create($exprNode, $constantType, $context, false, $scope, $rootExpr); + } + + if ( + !$context->null() + && $exprNode instanceof FuncCall + && count($exprNode->getArgs()) === 1 + && $exprNode->name instanceof Name + && in_array(strtolower((string) $exprNode->name), ['count', 'sizeof'], true) + && $constantType instanceof ConstantIntegerType + ) { + if ($context->truthy() || $constantType->getValue() === 0) { + $newContext = $context; + if ($constantType->getValue() === 0) { + $newContext = $newContext->negate(); + } + $argType = $scope->getType($exprNode->getArgs()[0]->value); + if ($argType->isArray()->yes()) { + $funcTypes = $this->create($exprNode, $constantType, $context, false, $scope, $rootExpr); + if ($argType->isList()->yes() && $context->truthy() && $constantType->getValue() < ConstantArrayTypeBuilder::ARRAY_COUNT_LIMIT) { + $valueTypesBuilder = ConstantArrayTypeBuilder::createEmpty(); + $itemType = $argType->getIterableValueType(); + for ($i = 0; $i < $constantType->getValue(); $i++) { + $valueTypesBuilder->setOffsetValueType(new ConstantIntegerType($i), $itemType); + } + $valueTypes = $this->create($exprNode->getArgs()[0]->value, $valueTypesBuilder->getArray(), $context, false, $scope, $rootExpr); + } else { + $valueTypes = $this->create($exprNode->getArgs()[0]->value, new NonEmptyArrayType(), $newContext, false, $scope, $rootExpr); + } + return $funcTypes->unionWith($valueTypes); + } + } + } + + if ( + !$context->null() + && $exprNode instanceof FuncCall + && count($exprNode->getArgs()) === 1 + && $exprNode->name instanceof Name + && strtolower((string) $exprNode->name) === 'strlen' + && $constantType instanceof ConstantIntegerType + ) { + if ($context->truthy() || $constantType->getValue() === 0) { + $newContext = $context; + if ($constantType->getValue() === 0) { + $newContext = $newContext->negate(); + } + $argType = $scope->getType($exprNode->getArgs()[0]->value); + if ($argType->isString()->yes()) { + $funcTypes = $this->create($exprNode, $constantType, $context, false, $scope, $rootExpr); + + $accessory = new AccessoryNonEmptyStringType(); + if ($constantType->getValue() >= 2) { + $accessory = new AccessoryNonFalsyStringType(); + } + $valueTypes = $this->create($exprNode->getArgs()[0]->value, $accessory, $newContext, false, $scope, $rootExpr); + + return $funcTypes->unionWith($valueTypes); + } + } + + } + + return null; + } + + private function specifyTypesForConstantStringBinaryExpression( + Expr $exprNode, + ConstantStringType $constantType, + TypeSpecifierContext $context, + Scope $scope, + ?Expr $rootExpr, + ): ?SpecifiedTypes + { + if ( + $context->truthy() + && $exprNode instanceof FuncCall + && $exprNode->name instanceof Name + && in_array(strtolower($exprNode->name->toString()), ['substr', 'strstr', 'stristr', 'strchr', 'strrchr', 'strtolower', 'strtoupper', 'mb_strtolower', 'mb_strtoupper', 'ucfirst', 'lcfirst', 'ucwords', 'mb_convert_case', 'mb_convert_kana'], true) + && isset($exprNode->getArgs()[0]) + && $constantType->getValue() !== '' + ) { + $argType = $scope->getType($exprNode->getArgs()[0]->value); + + if ($argType->isString()->yes()) { + if ($constantType->getValue() !== '0') { + return $this->create( + $exprNode->getArgs()[0]->value, + TypeCombinator::intersect($argType, new AccessoryNonFalsyStringType()), + $context, + false, + $scope, + ); + } + + return $this->create( + $exprNode->getArgs()[0]->value, + TypeCombinator::intersect($argType, new AccessoryNonEmptyStringType()), + $context, + false, + $scope, + ); + } + } + + if ( + $exprNode instanceof FuncCall + && $exprNode->name instanceof Name + && strtolower($exprNode->name->toString()) === 'gettype' + && isset($exprNode->getArgs()[0]) + ) { + $type = null; + if ($constantType->getValue() === 'string') { + $type = new StringType(); + } + if ($constantType->getValue() === 'array') { + $type = new ArrayType(new MixedType(), new MixedType()); + } + if ($constantType->getValue() === 'boolean') { + $type = new BooleanType(); + } + if (in_array($constantType->getValue(), ['resource', 'resource (closed)'], true)) { + $type = new ResourceType(); + } + if ($constantType->getValue() === 'integer') { + $type = new IntegerType(); + } + if ($constantType->getValue() === 'double') { + $type = new FloatType(); + } + if ($constantType->getValue() === 'NULL') { + $type = new NullType(); + } + if ($constantType->getValue() === 'object') { + $type = new ObjectWithoutClassType(); + } + + if ($type !== null) { + $callType = $this->create($exprNode, $constantType, $context, false, $scope, $rootExpr); + $argType = $this->create($exprNode->getArgs()[0]->value, $type, $context, false, $scope, $rootExpr); + return $callType->unionWith($argType); + } + } + + if ( + $context->true() + && $exprNode instanceof FuncCall + && $exprNode->name instanceof Name + && strtolower((string) $exprNode->name) === 'get_parent_class' + && isset($exprNode->getArgs()[0]) + ) { + $argType = $scope->getType($exprNode->getArgs()[0]->value); + $objectType = new ObjectType($constantType->getValue()); + $classStringType = new GenericClassStringType($objectType); + + if ($argType->isString()->yes()) { + return $this->create( + $exprNode->getArgs()[0]->value, + $classStringType, + $context, + false, + $scope, + ); + } + + if ($argType->isObject()->yes()) { + return $this->create( + $exprNode->getArgs()[0]->value, + $objectType, + $context, + false, + $scope, + ); + } + + return $this->create( + $exprNode->getArgs()[0]->value, + TypeCombinator::union($objectType, $classStringType), + $context, + false, + $scope, + ); + } + + return null; + } + private function handleDefaultTruthyOrFalseyContext(TypeSpecifierContext $context, ?Expr $rootExpr, Expr $expr, Scope $scope): SpecifiedTypes { if ($context->null()) { @@ -881,77 +1113,103 @@ private function handleDefaultTruthyOrFalseyContext(TypeSpecifierContext $contex return new SpecifiedTypes([], [], false, [], $rootExpr); } - private function specifyTypesFromConditionalReturnType(TypeSpecifierContext $context, Expr\CallLike $call, ParametersAcceptor $parametersAcceptor, Scope $scope) : ?SpecifiedTypes - { - if (!$parametersAcceptor instanceof ResolvedFunctionVariant) { - return null; - } - $returnType = $parametersAcceptor->getOriginalParametersAcceptor()->getReturnType(); - if (!$returnType instanceof ConditionalTypeForParameter) { - return null; - } - if ($context->true()) { - $leftType = new ConstantBooleanType(true); - $rightType = new ConstantBooleanType(false); - } elseif ($context->false()) { - $leftType = new ConstantBooleanType(false); - $rightType = new ConstantBooleanType(true); - } elseif ($context->null()) { - $leftType = new MixedType(); - $rightType = new NeverType(); - } else { - return null; - } - $argsMap = []; - $parameters = $parametersAcceptor->getParameters(); - foreach ($call->getArgs() as $i => $arg) { - if ($arg->unpack) { - continue; - } - - if ($arg->name !== null) { - $paramName = $arg->name->toString(); - } elseif (isset($parameters[$i])) { - $paramName = $parameters[$i]->getName(); - } else { - continue; - } - - $argsMap['$' . $paramName] = $arg->value; - } - return $this->getConditionalSpecifiedTypes($returnType, $leftType, $rightType, $scope, $argsMap); + private function specifyTypesFromConditionalReturnType( + TypeSpecifierContext $context, + Expr\CallLike $call, + ParametersAcceptor $parametersAcceptor, + Scope $scope, + ): ?SpecifiedTypes + { + if (!$parametersAcceptor instanceof ResolvedFunctionVariant) { + return null; + } + + $returnType = $parametersAcceptor->getOriginalParametersAcceptor()->getReturnType(); + if (!$returnType instanceof ConditionalTypeForParameter) { + return null; + } + + if ($context->true()) { + $leftType = new ConstantBooleanType(true); + $rightType = new ConstantBooleanType(false); + } elseif ($context->false()) { + $leftType = new ConstantBooleanType(false); + $rightType = new ConstantBooleanType(true); + } elseif ($context->null()) { + $leftType = new MixedType(); + $rightType = new NeverType(); + } else { + return null; + } + + $argsMap = []; + $parameters = $parametersAcceptor->getParameters(); + foreach ($call->getArgs() as $i => $arg) { + if ($arg->unpack) { + continue; } + if ($arg->name !== null) { + $paramName = $arg->name->toString(); + } elseif (isset($parameters[$i])) { + $paramName = $parameters[$i]->getName(); + } else { + continue; + } + + $argsMap['$' . $paramName] = $arg->value; + } + + return $this->getConditionalSpecifiedTypes($returnType, $leftType, $rightType, $scope, $argsMap); + } + /** - * @param array $argsMap - */ - public function getConditionalSpecifiedTypes(ConditionalTypeForParameter $conditionalType, Type $leftType, Type $rightType, Scope $scope, array $argsMap) : ?SpecifiedTypes - { - $parameterName = $conditionalType->getParameterName(); - if (!array_key_exists($parameterName, $argsMap)) { - return null; - } - $targetType = $conditionalType->getTarget(); - $ifType = $conditionalType->getIf(); - $elseType = $conditionalType->getElse(); - if ($leftType->isSuperTypeOf($ifType)->yes() && $rightType->isSuperTypeOf($elseType)->yes()) { - $context = $conditionalType->isNegated() ? TypeSpecifierContext::createFalse() : TypeSpecifierContext::createTrue(); - } elseif ($leftType->isSuperTypeOf($elseType)->yes() && $rightType->isSuperTypeOf($ifType)->yes()) { - $context = $conditionalType->isNegated() ? TypeSpecifierContext::createTrue() : TypeSpecifierContext::createFalse(); - } else { - return null; - } - $specifiedTypes = $this->create($argsMap[$parameterName], $targetType, $context, false, $scope); - if ($targetType instanceof ConstantBooleanType) { - if (!$targetType->getValue()) { - $context = $context->negate(); - } - - $specifiedTypes = $specifiedTypes->unionWith($this->specifyTypesInCondition($scope, $argsMap[$parameterName], $context)); - } - return $specifiedTypes; + * @param array $argsMap + */ + public function getConditionalSpecifiedTypes( + ConditionalTypeForParameter $conditionalType, + Type $leftType, + Type $rightType, + Scope $scope, + array $argsMap, + ): ?SpecifiedTypes + { + $parameterName = $conditionalType->getParameterName(); + if (!array_key_exists($parameterName, $argsMap)) { + return null; + } + + $targetType = $conditionalType->getTarget(); + $ifType = $conditionalType->getIf(); + $elseType = $conditionalType->getElse(); + + if ($leftType->isSuperTypeOf($ifType)->yes() && $rightType->isSuperTypeOf($elseType)->yes()) { + $context = $conditionalType->isNegated() ? TypeSpecifierContext::createFalse() : TypeSpecifierContext::createTrue(); + } elseif ($leftType->isSuperTypeOf($elseType)->yes() && $rightType->isSuperTypeOf($ifType)->yes()) { + $context = $conditionalType->isNegated() ? TypeSpecifierContext::createTrue() : TypeSpecifierContext::createFalse(); + } else { + return null; + } + + $specifiedTypes = $this->create( + $argsMap[$parameterName], + $targetType, + $context, + false, + $scope, + ); + + if ($targetType instanceof ConstantBooleanType) { + if (!$targetType->getValue()) { + $context = $context->negate(); } + $specifiedTypes = $specifiedTypes->unionWith($this->specifyTypesInCondition($scope, $argsMap[$parameterName], $context)); + } + + return $specifiedTypes; + } + private function specifyTypesFromAsserts(TypeSpecifierContext $context, Expr\CallLike $call, Assertions $assertions, ParametersAcceptor $parametersAcceptor, Scope $scope): ?SpecifiedTypes { if ($context->null()) { @@ -1002,9 +1260,7 @@ private function specifyTypesFromAsserts(TypeSpecifierContext $context, Expr\Cal if ($type instanceof ConditionalTypeForParameter) { $parameterName = substr($type->getParameterName(), 1); if (array_key_exists($parameterName, $argsMap)) { - $argType = TypeCombinator::union(...array_map(static function (Expr $expr) use($scope) { - return $scope->getType($expr); - }, $argsMap[$parameterName])); + $argType = TypeCombinator::union(...array_map(static fn (Expr $expr) => $scope->getType($expr), $argsMap[$parameterName])); $type = $type->toConditional($argType); } } @@ -1016,7 +1272,9 @@ private function specifyTypesFromAsserts(TypeSpecifierContext $context, Expr\Cal $templateTypeMap = $parametersAcceptor->getResolvedTemplateTypeMap(); $containsUnresolvedTemplate = false; - TypeTraverser::map($assert->getOriginalType(), static function (Type $type, callable $traverse) use ($templateTypeMap, &$containsUnresolvedTemplate) { + TypeTraverser::map( + $assert->getOriginalType(), + static function (Type $type, callable $traverse) use ($templateTypeMap, &$containsUnresolvedTemplate) { if ($type instanceof TemplateType && $type->getScope()->getClassName() !== null) { $resolvedType = $templateTypeMap->getType($type->getName()); if ($resolvedType === null || $type->getBound()->equals($resolvedType)) { @@ -1026,9 +1284,17 @@ private function specifyTypesFromAsserts(TypeSpecifierContext $context, Expr\Cal } return $traverse($type); - }); - - $newTypes = $this->create($assertExpr, $assertedType, $assert->isNegated() ? TypeSpecifierContext::createFalse() : TypeSpecifierContext::createTrue(), false, $scope, $containsUnresolvedTemplate || $assert->isEquality() ? $call : null); + }, + ); + + $newTypes = $this->create( + $assertExpr, + $assertedType, + $assert->isNegated() ? TypeSpecifierContext::createFalse() : TypeSpecifierContext::createTrue(), + false, + $scope, + $containsUnresolvedTemplate || $assert->isEquality() ? $call : null, + ); $types = $types !== null ? $types->unionWith($newTypes) : $newTypes; if (!$context->null() || !$assertedType instanceof ConstantBooleanType) { @@ -1040,7 +1306,11 @@ private function specifyTypesFromAsserts(TypeSpecifierContext $context, Expr\Cal $subContext = $subContext->negate(); } - $types = $types->unionWith($this->specifyTypesInCondition($scope, $assertExpr, $subContext)); + $types = $types->unionWith($this->specifyTypesInCondition( + $scope, + $assertExpr, + $subContext, + )); } } @@ -1048,9 +1318,9 @@ private function specifyTypesFromAsserts(TypeSpecifierContext $context, Expr\Cal } /** - * @return array - */ - private function processBooleanSureConditionalTypes(Scope $scope, SpecifiedTypes $leftTypes, SpecifiedTypes $rightTypes): array + * @return array + */ + private function processBooleanSureConditionalTypes(Scope $scope, SpecifiedTypes $leftTypes, SpecifiedTypes $rightTypes): array { $conditionExpressionTypes = []; foreach ($leftTypes->getSureTypes() as $exprString => [$expr, $type]) { @@ -1061,7 +1331,10 @@ private function processBooleanSureConditionalTypes(Scope $scope, SpecifiedTypes continue; } - $conditionExpressionTypes[$exprString] = ExpressionTypeHolder::createYes($expr, TypeCombinator::remove($scope->getType($expr), $type)); + $conditionExpressionTypes[$exprString] = ExpressionTypeHolder::createYes( + $expr, + TypeCombinator::remove($scope->getType($expr), $type), + ); } if (count($conditionExpressionTypes) > 0) { @@ -1098,7 +1371,10 @@ private function processBooleanSureConditionalTypes(Scope $scope, SpecifiedTypes continue; } - $holder = new ConditionalExpressionHolder($conditions, new ExpressionTypeHolder($expr, TypeCombinator::intersect($scope->getType($expr), $type), TrinaryLogic::createYes())); + $holder = new ConditionalExpressionHolder( + $conditions, + new ExpressionTypeHolder($expr, TypeCombinator::intersect($scope->getType($expr), $type), TrinaryLogic::createYes()), + ); $holders[$exprString][$holder->getKey()] = $holder; } @@ -1109,9 +1385,9 @@ private function processBooleanSureConditionalTypes(Scope $scope, SpecifiedTypes } /** - * @return array - */ - private function processBooleanNotSureConditionalTypes(Scope $scope, SpecifiedTypes $leftTypes, SpecifiedTypes $rightTypes): array + * @return array + */ + private function processBooleanNotSureConditionalTypes(Scope $scope, SpecifiedTypes $leftTypes, SpecifiedTypes $rightTypes): array { $conditionExpressionTypes = []; foreach ($leftTypes->getSureNotTypes() as $exprString => [$expr, $type]) { @@ -1122,7 +1398,10 @@ private function processBooleanNotSureConditionalTypes(Scope $scope, SpecifiedTy continue; } - $conditionExpressionTypes[$exprString] = ExpressionTypeHolder::createYes($expr, TypeCombinator::intersect($scope->getType($expr), $type)); + $conditionExpressionTypes[$exprString] = ExpressionTypeHolder::createYes( + $expr, + TypeCombinator::intersect($scope->getType($expr), $type), + ); } if (count($conditionExpressionTypes) > 0) { @@ -1159,7 +1438,10 @@ private function processBooleanNotSureConditionalTypes(Scope $scope, SpecifiedTy continue; } - $holder = new ConditionalExpressionHolder($conditions, new ExpressionTypeHolder($expr, TypeCombinator::remove($scope->getType($expr), $type), TrinaryLogic::createYes())); + $holder = new ConditionalExpressionHolder( + $conditions, + new ExpressionTypeHolder($expr, TypeCombinator::remove($scope->getType($expr), $type), TrinaryLogic::createYes()), + ); $holders[$exprString][$holder->getKey()] = $holder; } @@ -1170,9 +1452,9 @@ private function processBooleanNotSureConditionalTypes(Scope $scope, SpecifiedTy } /** - * @return array{Expr, ConstantScalarType}|null - */ - private function findTypeExpressionsFromBinaryOperation(Scope $scope, Node\Expr\BinaryOp $binaryOperation): ?array + * @return array{Expr, ConstantScalarType}|null + */ + private function findTypeExpressionsFromBinaryOperation(Scope $scope, Node\Expr\BinaryOp $binaryOperation): ?array { $leftType = $scope->getType($binaryOperation->left); $rightType = $scope->getType($binaryOperation->right); @@ -1205,151 +1487,178 @@ private function findTypeExpressionsFromBinaryOperation(Scope $scope, Node\Expr\ } /** @api */ - public function create(Expr $expr, Type $type, TypeSpecifierContext $context, bool $overwrite = false, ?Scope $scope = null, ?Expr $rootExpr = null) : SpecifiedTypes - { - if ($expr instanceof Instanceof_ || $expr instanceof Expr\List_) { - return new SpecifiedTypes([], [], false, [], $rootExpr); - } - $specifiedExprs = []; - if ($expr instanceof AlwaysRememberedExpr) { - $specifiedExprs[] = $expr; - $expr = $expr->expr; - } - if ($expr instanceof Expr\Assign) { - $specifiedExprs[] = $expr->var; - $specifiedExprs[] = $expr->expr; - - while ($expr->expr instanceof Expr\Assign) { - $specifiedExprs[] = $expr->expr->var; - $expr = $expr->expr; - } - } elseif ($expr instanceof Expr\AssignOp\Coalesce) { - $specifiedExprs[] = $expr->var; - } else { - $specifiedExprs[] = $expr; - } - $types = null; - foreach ($specifiedExprs as $specifiedExpr) { - $newTypes = $this->createForExpr($specifiedExpr, $type, $context, $overwrite, $scope, $rootExpr); - - if ($types === null) { - $types = $newTypes; - } else { - $types = $types->unionWith($newTypes); - } - } - return $types; - } - - private function createForExpr(Expr $expr, Type $type, TypeSpecifierContext $context, bool $overwrite = false, ?Scope $scope = null, ?Expr $rootExpr = null) : SpecifiedTypes - { - if ($scope !== null) { - if ($context->true()) { - $containsNull = !$type->isNull()->no() && !$scope->getType($expr)->isNull()->no(); - } elseif ($context->false()) { - $containsNull = !TypeCombinator::containsNull($type) && !$scope->getType($expr)->isNull()->no(); - } - } - $originalExpr = $expr; - if (isset($containsNull) && !$containsNull) { - $expr = NullsafeOperatorHelper::getNullsafeShortcircuitedExpr($expr); - } - if ( - $scope !== null - && !$context->null() - && $expr instanceof Expr\BinaryOp\Coalesce - ) { - $rightIsSuperType = $type->isSuperTypeOf($scope->getType($expr->right)); - if (($context->true() && $rightIsSuperType->no()) || ($context->false() && $rightIsSuperType->yes())) { - $expr = $expr->left; - } - } - if ( - $expr instanceof FuncCall - && $expr->name instanceof Name - ) { - $has = $this->reflectionProvider->hasFunction($expr->name, $scope); - if (!$has) { - // backwards compatibility with previous behaviour - return new SpecifiedTypes([], [], false, [], $rootExpr); - } - - $functionReflection = $this->reflectionProvider->getFunction($expr->name, $scope); - $hasSideEffects = $functionReflection->hasSideEffects(); - if ($hasSideEffects->yes()) { - return new SpecifiedTypes([], [], false, [], $rootExpr); - } - - if (!$this->rememberPossiblyImpureFunctionValues && !$hasSideEffects->no()) { - return new SpecifiedTypes([], [], false, [], $rootExpr); - } - } - if ( - $expr instanceof MethodCall - && $expr->name instanceof Node\Identifier - && $scope !== null - ) { - $methodName = $expr->name->toString(); - $calledOnType = $scope->getType($expr->var); - $methodReflection = $scope->getMethodReflection($calledOnType, $methodName); - if ( - $methodReflection === null - || $methodReflection->hasSideEffects()->yes() - || (!$this->rememberPossiblyImpureFunctionValues && !$methodReflection->hasSideEffects()->no()) - ) { - if (isset($containsNull) && !$containsNull) { - return $this->createNullsafeTypes($rootExpr, $originalExpr, $scope, $context, $overwrite, $type); - } - - return new SpecifiedTypes([], [], false, [], $rootExpr); - } - } - if ( - $expr instanceof StaticCall - && $expr->name instanceof Node\Identifier - && $scope !== null - ) { - $methodName = $expr->name->toString(); - if ($expr->class instanceof Name) { - $calledOnType = $scope->resolveTypeByName($expr->class); - } else { - $calledOnType = $scope->getType($expr->class); - } - - $methodReflection = $scope->getMethodReflection($calledOnType, $methodName); - if ( - $methodReflection === null - || $methodReflection->hasSideEffects()->yes() - || (!$this->rememberPossiblyImpureFunctionValues && !$methodReflection->hasSideEffects()->no()) - ) { - if (isset($containsNull) && !$containsNull) { - return $this->createNullsafeTypes($rootExpr, $originalExpr, $scope, $context, $overwrite, $type); - } - - return new SpecifiedTypes([], [], false, [], $rootExpr); - } - } - $sureTypes = []; - $sureNotTypes = []; - $exprString = $this->exprPrinter->printExpr($expr); - $originalExprString = $this->exprPrinter->printExpr($originalExpr); - if ($context->false()) { - $sureNotTypes[$exprString] = [$expr, $type]; - if ($exprString !== $originalExprString) { - $sureNotTypes[$originalExprString] = [$originalExpr, $type]; - } - } elseif ($context->true()) { - $sureTypes[$exprString] = [$expr, $type]; - if ($exprString !== $originalExprString) { - $sureTypes[$originalExprString] = [$originalExpr, $type]; - } - } - $types = new SpecifiedTypes($sureTypes, $sureNotTypes, $overwrite, [], $rootExpr); - if ($scope !== null && isset($containsNull) && !$containsNull) { - return $this->createNullsafeTypes($rootExpr, $originalExpr, $scope, $context, $overwrite, $type)->unionWith($types); - } - return $types; + public function create( + Expr $expr, + Type $type, + TypeSpecifierContext $context, + bool $overwrite = false, + ?Scope $scope = null, + ?Expr $rootExpr = null, + ): SpecifiedTypes + { + if ($expr instanceof Instanceof_ || $expr instanceof Expr\List_) { + return new SpecifiedTypes([], [], false, [], $rootExpr); + } + + $specifiedExprs = []; + if ($expr instanceof AlwaysRememberedExpr) { + $specifiedExprs[] = $expr; + $expr = $expr->expr; + } + + if ($expr instanceof Expr\Assign) { + $specifiedExprs[] = $expr->var; + $specifiedExprs[] = $expr->expr; + + while ($expr->expr instanceof Expr\Assign) { + $specifiedExprs[] = $expr->expr->var; + $expr = $expr->expr; } + } elseif ($expr instanceof Expr\AssignOp\Coalesce) { + $specifiedExprs[] = $expr->var; + } else { + $specifiedExprs[] = $expr; + } + + $types = null; + + foreach ($specifiedExprs as $specifiedExpr) { + $newTypes = $this->createForExpr($specifiedExpr, $type, $context, $overwrite, $scope, $rootExpr); + + if ($types === null) { + $types = $newTypes; + } else { + $types = $types->unionWith($newTypes); + } + } + + return $types; + } + + private function createForExpr( + Expr $expr, + Type $type, + TypeSpecifierContext $context, + bool $overwrite = false, + ?Scope $scope = null, + ?Expr $rootExpr = null, + ): SpecifiedTypes + { + if ($scope !== null) { + if ($context->true()) { + $containsNull = !$type->isNull()->no() && !$scope->getType($expr)->isNull()->no(); + } elseif ($context->false()) { + $containsNull = !TypeCombinator::containsNull($type) && !$scope->getType($expr)->isNull()->no(); + } + } + + $originalExpr = $expr; + if (isset($containsNull) && !$containsNull) { + $expr = NullsafeOperatorHelper::getNullsafeShortcircuitedExpr($expr); + } + + if ( + $scope !== null + && !$context->null() + && $expr instanceof Expr\BinaryOp\Coalesce + ) { + $rightIsSuperType = $type->isSuperTypeOf($scope->getType($expr->right)); + if (($context->true() && $rightIsSuperType->no()) || ($context->false() && $rightIsSuperType->yes())) { + $expr = $expr->left; + } + } + + if ( + $expr instanceof FuncCall + && $expr->name instanceof Name + ) { + $has = $this->reflectionProvider->hasFunction($expr->name, $scope); + if (!$has) { + // backwards compatibility with previous behaviour + return new SpecifiedTypes([], [], false, [], $rootExpr); + } + + $functionReflection = $this->reflectionProvider->getFunction($expr->name, $scope); + $hasSideEffects = $functionReflection->hasSideEffects(); + if ($hasSideEffects->yes()) { + return new SpecifiedTypes([], [], false, [], $rootExpr); + } + + if (!$this->rememberPossiblyImpureFunctionValues && !$hasSideEffects->no()) { + return new SpecifiedTypes([], [], false, [], $rootExpr); + } + } + + if ( + $expr instanceof MethodCall + && $expr->name instanceof Node\Identifier + && $scope !== null + ) { + $methodName = $expr->name->toString(); + $calledOnType = $scope->getType($expr->var); + $methodReflection = $scope->getMethodReflection($calledOnType, $methodName); + if ( + $methodReflection === null + || $methodReflection->hasSideEffects()->yes() + || (!$this->rememberPossiblyImpureFunctionValues && !$methodReflection->hasSideEffects()->no()) + ) { + if (isset($containsNull) && !$containsNull) { + return $this->createNullsafeTypes($rootExpr, $originalExpr, $scope, $context, $overwrite, $type); + } + + return new SpecifiedTypes([], [], false, [], $rootExpr); + } + } + + if ( + $expr instanceof StaticCall + && $expr->name instanceof Node\Identifier + && $scope !== null + ) { + $methodName = $expr->name->toString(); + if ($expr->class instanceof Name) { + $calledOnType = $scope->resolveTypeByName($expr->class); + } else { + $calledOnType = $scope->getType($expr->class); + } + + $methodReflection = $scope->getMethodReflection($calledOnType, $methodName); + if ( + $methodReflection === null + || $methodReflection->hasSideEffects()->yes() + || (!$this->rememberPossiblyImpureFunctionValues && !$methodReflection->hasSideEffects()->no()) + ) { + if (isset($containsNull) && !$containsNull) { + return $this->createNullsafeTypes($rootExpr, $originalExpr, $scope, $context, $overwrite, $type); + } + + return new SpecifiedTypes([], [], false, [], $rootExpr); + } + } + + $sureTypes = []; + $sureNotTypes = []; + $exprString = $this->exprPrinter->printExpr($expr); + $originalExprString = $this->exprPrinter->printExpr($originalExpr); + if ($context->false()) { + $sureNotTypes[$exprString] = [$expr, $type]; + if ($exprString !== $originalExprString) { + $sureNotTypes[$originalExprString] = [$originalExpr, $type]; + } + } elseif ($context->true()) { + $sureTypes[$exprString] = [$expr, $type]; + if ($exprString !== $originalExprString) { + $sureTypes[$originalExprString] = [$originalExpr, $type]; + } + } + + $types = new SpecifiedTypes($sureTypes, $sureNotTypes, $overwrite, [], $rootExpr); + if ($scope !== null && isset($containsNull) && !$containsNull) { + return $this->createNullsafeTypes($rootExpr, $originalExpr, $scope, $context, $overwrite, $type)->unionWith($types); + } + + return $types; + } private function createNullsafeTypes(?Expr $rootExpr, Expr $expr, Scope $scope, TypeSpecifierContext $context, bool $overwrite, ?Type $type): SpecifiedTypes { @@ -1360,7 +1669,9 @@ private function createNullsafeTypes(?Expr $rootExpr, Expr $expr, Scope $scope, $propertyFetchTypes = $this->create(new PropertyFetch($expr->var, $expr->name), new NullType(), TypeSpecifierContext::createFalse(), false, $scope, $rootExpr); } - return $propertyFetchTypes->unionWith($this->create($expr->var, new NullType(), TypeSpecifierContext::createFalse(), $overwrite, $scope, $rootExpr)); + return $propertyFetchTypes->unionWith( + $this->create($expr->var, new NullType(), TypeSpecifierContext::createFalse(), $overwrite, $scope, $rootExpr), + ); } if ($expr instanceof Expr\NullsafeMethodCall) { @@ -1370,7 +1681,9 @@ private function createNullsafeTypes(?Expr $rootExpr, Expr $expr, Scope $scope, $methodCallTypes = $this->create(new MethodCall($expr->var, $expr->name, $expr->args), new NullType(), TypeSpecifierContext::createFalse(), $overwrite, $scope, $rootExpr); } - return $methodCallTypes->unionWith($this->create($expr->var, new NullType(), TypeSpecifierContext::createFalse(), $overwrite, $scope, $rootExpr)); + return $methodCallTypes->unionWith( + $this->create($expr->var, new NullType(), TypeSpecifierContext::createFalse(), $overwrite, $scope, $rootExpr), + ); } if ($expr instanceof Expr\PropertyFetch) { @@ -1414,17 +1727,17 @@ private function createRangeTypes(?Expr $rootExpr, Expr $expr, Type $type, TypeS } /** - * @return FunctionTypeSpecifyingExtension[] - */ - private function getFunctionTypeSpecifyingExtensions(): array + * @return FunctionTypeSpecifyingExtension[] + */ + private function getFunctionTypeSpecifyingExtensions(): array { return $this->functionTypeSpecifyingExtensions; } /** - * @return MethodTypeSpecifyingExtension[] - */ - private function getMethodTypeSpecifyingExtensionsForClass(string $className): array + * @return MethodTypeSpecifyingExtension[] + */ + private function getMethodTypeSpecifyingExtensionsForClass(string $className): array { if ($this->methodTypeSpecifyingExtensionsByClass === null) { $byClass = []; @@ -1438,9 +1751,9 @@ private function getMethodTypeSpecifyingExtensionsForClass(string $className): a } /** - * @return StaticMethodTypeSpecifyingExtension[] - */ - private function getStaticMethodTypeSpecifyingExtensionsForClass(string $className): array + * @return StaticMethodTypeSpecifyingExtension[] + */ + private function getStaticMethodTypeSpecifyingExtensionsForClass(string $className): array { if ($this->staticMethodTypeSpecifyingExtensionsByClass === null) { $byClass = []; @@ -1454,10 +1767,10 @@ private function getStaticMethodTypeSpecifyingExtensionsForClass(string $classNa } /** - * @param MethodTypeSpecifyingExtension[][]|StaticMethodTypeSpecifyingExtension[][] $extensions - * @return mixed[] - */ - private function getTypeSpecifyingExtensionsForType(array $extensions, string $className): array + * @param MethodTypeSpecifyingExtension[][]|StaticMethodTypeSpecifyingExtension[][] $extensions + * @return mixed[] + */ + private function getTypeSpecifyingExtensionsForType(array $extensions, string $className): array { $extensionsForClass = [[]]; $class = $this->reflectionProvider->getClass($className); @@ -1479,11 +1792,21 @@ public function resolveEqual(Expr\BinaryOp\Equal $expr, Scope $scope, TypeSpecif $exprNode = $expressions[0]; $constantType = $expressions[1]; if (!$context->null() && ($constantType->getValue() === false || $constantType->getValue() === null)) { - return $this->specifyTypesInCondition($scope, $exprNode, $context->true() ? TypeSpecifierContext::createFalsey() : TypeSpecifierContext::createFalsey()->negate(), $rootExpr); + return $this->specifyTypesInCondition( + $scope, + $exprNode, + $context->true() ? TypeSpecifierContext::createFalsey() : TypeSpecifierContext::createFalsey()->negate(), + $rootExpr, + ); } if (!$context->null() && $constantType->getValue() === true) { - return $this->specifyTypesInCondition($scope, $exprNode, $context->true() ? TypeSpecifierContext::createTruthy() : TypeSpecifierContext::createTruthy()->negate(), $rootExpr); + return $this->specifyTypesInCondition( + $scope, + $exprNode, + $context->true() ? TypeSpecifierContext::createTruthy() : TypeSpecifierContext::createTruthy()->negate(), + $rootExpr, + ); } if ( @@ -1512,12 +1835,28 @@ public function resolveEqual(Expr\BinaryOp\Equal $expr, Scope $scope, TypeSpecif $leftBooleanType = $leftType->toBoolean(); if ($leftBooleanType instanceof ConstantBooleanType && $rightType->isBoolean()->yes()) { - return $this->specifyTypesInCondition($scope, new Expr\BinaryOp\Identical(new ConstFetch(new Name($leftBooleanType->getValue() ? 'true' : 'false')), $expr->right), $context, $rootExpr); + return $this->specifyTypesInCondition( + $scope, + new Expr\BinaryOp\Identical( + new ConstFetch(new Name($leftBooleanType->getValue() ? 'true' : 'false')), + $expr->right, + ), + $context, + $rootExpr, + ); } $rightBooleanType = $rightType->toBoolean(); if ($rightBooleanType instanceof ConstantBooleanType && $leftType->isBoolean()->yes()) { - return $this->specifyTypesInCondition($scope, new Expr\BinaryOp\Identical($expr->left, new ConstFetch(new Name($rightBooleanType->getValue() ? 'true' : 'false'))), $context, $rootExpr); + return $this->specifyTypesInCondition( + $scope, + new Expr\BinaryOp\Identical( + $expr->left, + new ConstFetch(new Name($rightBooleanType->getValue() ? 'true' : 'false')), + ), + $context, + $rootExpr, + ); } if ( @@ -1585,7 +1924,14 @@ public function resolveIdentical(Expr\BinaryOp\Identical $expr, Scope $scope, Ty && isset($unwrappedLeftExpr->getArgs()[0]) ) { if ($rightType->getClassStringObjectType()->isObject()->yes()) { - return $this->create($unwrappedLeftExpr->getArgs()[0]->value, $rightType->getClassStringObjectType(), $context, false, $scope, $rootExpr)->unionWith($this->create($leftExpr, $rightType, $context, false, $scope, $rootExpr)); + return $this->create( + $unwrappedLeftExpr->getArgs()[0]->value, + $rightType->getClassStringObjectType(), + $context, + false, + $scope, + $rootExpr, + )->unionWith($this->create($leftExpr, $rightType, $context, false, $scope, $rootExpr)); } } @@ -1620,7 +1966,9 @@ public function resolveIdentical(Expr\BinaryOp\Identical $expr, Scope $scope, Ty $specifiedType = $this->specifyTypesForConstantBinaryExpression($exprNode, $constantType, $context, $scope, $rootExpr); if ($specifiedType !== null) { if ($exprNode instanceof AlwaysRememberedExpr) { - $specifiedType->unionWith($this->create($exprNode->getExpr(), $constantType, $context, false, $scope, $rootExpr)); + $specifiedType->unionWith( + $this->create($exprNode->getExpr(), $constantType, $context, false, $scope, $rootExpr), + ); } return $specifiedType; } @@ -1635,7 +1983,15 @@ public function resolveIdentical(Expr\BinaryOp\Identical $expr, Scope $scope, Ty $rightType instanceof ConstantStringType && strtolower($unwrappedLeftExpr->name->toString()) === 'class' ) { - return $this->specifyTypesInCondition($scope, new Instanceof_($unwrappedLeftExpr->class, new Name($rightType->getValue())), $context, $rootExpr)->unionWith($this->create($leftExpr, $rightType, $context, false, $scope, $rootExpr)); + return $this->specifyTypesInCondition( + $scope, + new Instanceof_( + $unwrappedLeftExpr->class, + new Name($rightType->getValue()), + ), + $context, + $rootExpr, + )->unionWith($this->create($leftExpr, $rightType, $context, false, $scope, $rootExpr)); } $leftType = $scope->getType($leftExpr); @@ -1648,7 +2004,15 @@ public function resolveIdentical(Expr\BinaryOp\Identical $expr, Scope $scope, Ty $leftType instanceof ConstantStringType && strtolower($unwrappedRightExpr->name->toString()) === 'class' ) { - return $this->specifyTypesInCondition($scope, new Instanceof_($unwrappedRightExpr->class, new Name($leftType->getValue())), $context, $rootExpr)->unionWith($this->create($rightExpr, $leftType, $context, false, $scope, $rootExpr)); + return $this->specifyTypesInCondition( + $scope, + new Instanceof_( + $unwrappedRightExpr->class, + new Name($leftType->getValue()), + ), + $context, + $rootExpr, + )->unionWith($this->create($rightExpr, $leftType, $context, false, $scope, $rootExpr)); } if ($context->false()) { @@ -1659,10 +2023,14 @@ public function resolveIdentical(Expr\BinaryOp\Identical $expr, Scope $scope, Ty $leftTypes = $this->create($leftExpr, $never, $contextForTypes, false, $scope, $rootExpr); $rightTypes = $this->create($rightExpr, $never, $contextForTypes, false, $scope, $rootExpr); if ($leftExpr instanceof AlwaysRememberedExpr) { - $leftTypes = $leftTypes->unionWith($this->create($unwrappedLeftExpr, $never, $contextForTypes, false, $scope, $rootExpr)); + $leftTypes = $leftTypes->unionWith( + $this->create($unwrappedLeftExpr, $never, $contextForTypes, false, $scope, $rootExpr), + ); } if ($rightExpr instanceof AlwaysRememberedExpr) { - $rightTypes = $rightTypes->unionWith($this->create($unwrappedRightExpr, $never, $contextForTypes, false, $scope, $rootExpr)); + $rightTypes = $rightTypes->unionWith( + $this->create($unwrappedRightExpr, $never, $contextForTypes, false, $scope, $rootExpr), + ); } return $leftTypes->unionWith($rightTypes); } @@ -1673,18 +2041,46 @@ public function resolveIdentical(Expr\BinaryOp\Identical $expr, Scope $scope, Ty count($leftType->getFiniteTypes()) === 1 || ($context->true() && $leftType->isConstantValue()->yes() && !$rightType->equals($leftType) && $rightType->isSuperTypeOf($leftType)->yes()) ) { - $types = $this->create($rightExpr, $leftType, $context, false, $scope, $rootExpr); + $types = $this->create( + $rightExpr, + $leftType, + $context, + false, + $scope, + $rootExpr, + ); if ($rightExpr instanceof AlwaysRememberedExpr) { - $types = $types->unionWith($this->create($unwrappedRightExpr, $leftType, $context, false, $scope, $rootExpr)); + $types = $types->unionWith($this->create( + $unwrappedRightExpr, + $leftType, + $context, + false, + $scope, + $rootExpr, + )); } } if ( count($rightType->getFiniteTypes()) === 1 || ($context->true() && $rightType->isConstantValue()->yes() && !$leftType->equals($rightType) && $leftType->isSuperTypeOf($rightType)->yes()) ) { - $leftTypes = $this->create($leftExpr, $rightType, $context, false, $scope, $rootExpr); + $leftTypes = $this->create( + $leftExpr, + $rightType, + $context, + false, + $scope, + $rootExpr, + ); if ($leftExpr instanceof AlwaysRememberedExpr) { - $leftTypes = $leftTypes->unionWith($this->create($unwrappedLeftExpr, $rightType, $context, false, $scope, $rootExpr)); + $leftTypes = $leftTypes->unionWith($this->create( + $unwrappedLeftExpr, + $rightType, + $context, + false, + $scope, + $rootExpr, + )); } if ($types !== null) { $types = $types->unionWith($leftTypes); @@ -1709,10 +2105,14 @@ public function resolveIdentical(Expr\BinaryOp\Identical $expr, Scope $scope, Ty $leftTypes = $this->create($leftExpr, $rightType, $context, false, $scope, $rootExpr); $rightTypes = $this->create($rightExpr, $leftType, $context, false, $scope, $rootExpr); if ($leftExpr instanceof AlwaysRememberedExpr) { - $leftTypes = $leftTypes->unionWith($this->create($unwrappedLeftExpr, $rightType, $context, false, $scope, $rootExpr)); + $leftTypes = $leftTypes->unionWith( + $this->create($unwrappedLeftExpr, $rightType, $context, false, $scope, $rootExpr), + ); } if ($rightExpr instanceof AlwaysRememberedExpr) { - $rightTypes = $rightTypes->unionWith($this->create($unwrappedRightExpr, $leftType, $context, false, $scope, $rootExpr)); + $rightTypes = $rightTypes->unionWith( + $this->create($unwrappedRightExpr, $leftType, $context, false, $scope, $rootExpr), + ); } return $leftTypes->unionWith($rightTypes); } elseif ($context->false()) { diff --git a/src/Analyser/TypeSpecifierContext.php b/src/Analyser/TypeSpecifierContext.php index e28e9f4c7ab..a14aba7112c 100644 --- a/src/Analyser/TypeSpecifierContext.php +++ b/src/Analyser/TypeSpecifierContext.php @@ -8,10 +8,6 @@ class TypeSpecifierContext { - /** - * @var ?int - */ - private $value; public const CONTEXT_TRUE = 0b0001; public const CONTEXT_TRUTHY_BUT_NOT_TRUE = 0b0010; public const CONTEXT_TRUTHY = self::CONTEXT_TRUE | self::CONTEXT_TRUTHY_BUT_NOT_TRUE; @@ -21,16 +17,15 @@ class TypeSpecifierContext public const CONTEXT_BITMASK = 0b1111; /** @var self[] */ - private static $registry; + private static array $registry; - private function __construct(?int $value) + private function __construct(private ?int $value) { - $this->value = $value; } private static function create(?int $value): self { - self::$registry[$value] = self::$registry[$value] ?? new self($value); + self::$registry[$value] ??= new self($value); return self::$registry[$value]; } diff --git a/src/Analyser/TypeSpecifierFactory.php b/src/Analyser/TypeSpecifierFactory.php index 782f7a53aac..eddf559900f 100644 --- a/src/Analyser/TypeSpecifierFactory.php +++ b/src/Analyser/TypeSpecifierFactory.php @@ -11,24 +11,32 @@ class TypeSpecifierFactory { - /** - * @var Container - */ - private $container; public const FUNCTION_TYPE_SPECIFYING_EXTENSION_TAG = 'phpstan.typeSpecifier.functionTypeSpecifyingExtension'; public const METHOD_TYPE_SPECIFYING_EXTENSION_TAG = 'phpstan.typeSpecifier.methodTypeSpecifyingExtension'; public const STATIC_METHOD_TYPE_SPECIFYING_EXTENSION_TAG = 'phpstan.typeSpecifier.staticMethodTypeSpecifyingExtension'; - public function __construct(Container $container) + public function __construct(private Container $container) { - $this->container = $container; } public function create(): TypeSpecifier { - $typeSpecifier = new TypeSpecifier($this->container->getByType(ExprPrinter::class), $this->container->getByType(ReflectionProvider::class), $this->container->getServicesByTag(self::FUNCTION_TYPE_SPECIFYING_EXTENSION_TAG), $this->container->getServicesByTag(self::METHOD_TYPE_SPECIFYING_EXTENSION_TAG), $this->container->getServicesByTag(self::STATIC_METHOD_TYPE_SPECIFYING_EXTENSION_TAG), $this->container->getParameter('rememberPossiblyImpureFunctionValues')); - - foreach (array_merge($this->container->getServicesByTag(BrokerFactory::PROPERTIES_CLASS_REFLECTION_EXTENSION_TAG), $this->container->getServicesByTag(BrokerFactory::METHODS_CLASS_REFLECTION_EXTENSION_TAG), $this->container->getServicesByTag(BrokerFactory::DYNAMIC_METHOD_RETURN_TYPE_EXTENSION_TAG), $this->container->getServicesByTag(BrokerFactory::DYNAMIC_STATIC_METHOD_RETURN_TYPE_EXTENSION_TAG), $this->container->getServicesByTag(BrokerFactory::DYNAMIC_FUNCTION_RETURN_TYPE_EXTENSION_TAG)) as $extension) { + $typeSpecifier = new TypeSpecifier( + $this->container->getByType(ExprPrinter::class), + $this->container->getByType(ReflectionProvider::class), + $this->container->getServicesByTag(self::FUNCTION_TYPE_SPECIFYING_EXTENSION_TAG), + $this->container->getServicesByTag(self::METHOD_TYPE_SPECIFYING_EXTENSION_TAG), + $this->container->getServicesByTag(self::STATIC_METHOD_TYPE_SPECIFYING_EXTENSION_TAG), + $this->container->getParameter('rememberPossiblyImpureFunctionValues'), + ); + + foreach (array_merge( + $this->container->getServicesByTag(BrokerFactory::PROPERTIES_CLASS_REFLECTION_EXTENSION_TAG), + $this->container->getServicesByTag(BrokerFactory::METHODS_CLASS_REFLECTION_EXTENSION_TAG), + $this->container->getServicesByTag(BrokerFactory::DYNAMIC_METHOD_RETURN_TYPE_EXTENSION_TAG), + $this->container->getServicesByTag(BrokerFactory::DYNAMIC_STATIC_METHOD_RETURN_TYPE_EXTENSION_TAG), + $this->container->getServicesByTag(BrokerFactory::DYNAMIC_FUNCTION_RETURN_TYPE_EXTENSION_TAG), + ) as $extension) { if (!($extension instanceof TypeSpecifierAwareExtension)) { continue; } diff --git a/src/Analyser/UndefinedVariableException.php b/src/Analyser/UndefinedVariableException.php index 5af3ce8212f..6719de349ce 100644 --- a/src/Analyser/UndefinedVariableException.php +++ b/src/Analyser/UndefinedVariableException.php @@ -8,18 +8,8 @@ class UndefinedVariableException extends AnalysedCodeException { - /** - * @var Scope - */ - private $scope; - /** - * @var string - */ - private $variableName; - public function __construct(Scope $scope, string $variableName) + public function __construct(private Scope $scope, private string $variableName) { - $this->scope = $scope; - $this->variableName = $variableName; parent::__construct(sprintf('Undefined variable: $%s', $variableName)); } diff --git a/src/Broker/AnonymousClassNameHelper.php b/src/Broker/AnonymousClassNameHelper.php index 20513576c44..20e3087b002 100644 --- a/src/Broker/AnonymousClassNameHelper.php +++ b/src/Broker/AnonymousClassNameHelper.php @@ -11,25 +11,31 @@ class AnonymousClassNameHelper { - /** - * @var FileHelper - */ - private $fileHelper; - /** - * @var RelativePathHelper - */ - private $relativePathHelper; - public function __construct(FileHelper $fileHelper, RelativePathHelper $relativePathHelper) - { - $this->fileHelper = $fileHelper; - $this->relativePathHelper = $relativePathHelper; - } - public function getAnonymousClassName(Node\Stmt\Class_ $classNode, string $filename) : string - { - if (isset($classNode->namespacedName)) { - throw new ShouldNotHappenException(); - } - $filename = $this->relativePathHelper->getRelativePath($this->fileHelper->normalizePath($filename, '/')); - return sprintf('AnonymousClass%s', md5(sprintf('%s:%s', $filename, $classNode->getStartLine()))); - } + + public function __construct( + private FileHelper $fileHelper, + private RelativePathHelper $relativePathHelper, + ) + { + } + + public function getAnonymousClassName( + Node\Stmt\Class_ $classNode, + string $filename, + ): string + { + if (isset($classNode->namespacedName)) { + throw new ShouldNotHappenException(); + } + + $filename = $this->relativePathHelper->getRelativePath( + $this->fileHelper->normalizePath($filename, '/'), + ); + + return sprintf( + 'AnonymousClass%s', + md5(sprintf('%s:%s', $filename, $classNode->getStartLine())), + ); + } + } diff --git a/src/Broker/Broker.php b/src/Broker/Broker.php index 02a1c2743a1..fee5eab88db 100644 --- a/src/Broker/Broker.php +++ b/src/Broker/Broker.php @@ -15,26 +15,16 @@ class Broker implements ReflectionProvider { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - /** - * @var string[] - */ - private $universalObjectCratesClasses; - /** - * @var ?Broker - */ - private static $instance = null; + private static ?Broker $instance = null; /** * @param string[] $universalObjectCratesClasses */ - public function __construct(ReflectionProvider $reflectionProvider, array $universalObjectCratesClasses) + public function __construct( + private ReflectionProvider $reflectionProvider, + private array $universalObjectCratesClasses, + ) { - $this->reflectionProvider = $reflectionProvider; - $this->universalObjectCratesClasses = $universalObjectCratesClasses; } public static function registerInstance(Broker $broker): void diff --git a/src/Broker/BrokerFactory.php b/src/Broker/BrokerFactory.php index 5556a5f3853..d35b68e30d4 100644 --- a/src/Broker/BrokerFactory.php +++ b/src/Broker/BrokerFactory.php @@ -8,10 +8,6 @@ class BrokerFactory { - /** - * @var Container - */ - private $container; public const PROPERTIES_CLASS_REFLECTION_EXTENSION_TAG = 'phpstan.broker.propertiesClassReflectionExtension'; public const METHODS_CLASS_REFLECTION_EXTENSION_TAG = 'phpstan.broker.methodsClassReflectionExtension'; public const ALLOWED_SUB_TYPES_CLASS_REFLECTION_EXTENSION_TAG = 'phpstan.broker.allowedSubTypesClassReflectionExtension'; @@ -21,14 +17,16 @@ class BrokerFactory public const OPERATOR_TYPE_SPECIFYING_EXTENSION_TAG = 'phpstan.broker.operatorTypeSpecifyingExtension'; public const EXPRESSION_TYPE_RESOLVER_EXTENSION_TAG = 'phpstan.broker.expressionTypeResolverExtension'; - public function __construct(Container $container) + public function __construct(private Container $container) { - $this->container = $container; } public function create(): Broker { - return new Broker($this->container->getByType(ReflectionProvider::class), $this->container->getParameter('universalObjectCratesClasses')); + return new Broker( + $this->container->getByType(ReflectionProvider::class), + $this->container->getParameter('universalObjectCratesClasses'), + ); } } diff --git a/src/Broker/ClassAutoloadingException.php b/src/Broker/ClassAutoloadingException.php index d4fcb9efba1..23e99fe5a54 100644 --- a/src/Broker/ClassAutoloadingException.php +++ b/src/Broker/ClassAutoloadingException.php @@ -10,18 +10,27 @@ class ClassAutoloadingException extends AnalysedCodeException { - /** - * @var string - */ - private $className; + private string $className; - public function __construct(string $functionName, ?Throwable $previous = null) + public function __construct( + string $functionName, + ?Throwable $previous = null, + ) { if ($previous !== null) { - parent::__construct(sprintf('%s (%s) thrown while looking for class %s.', get_class($previous), $previous->getMessage(), $functionName), 0, $previous); + parent::__construct(sprintf( + '%s (%s) thrown while looking for class %s.', + get_class($previous), + $previous->getMessage(), + $functionName, + ), 0, $previous); } else { - parent::__construct(sprintf('Class %s not found.', $functionName), 0); + parent::__construct(sprintf( + 'Class %s not found.', + $functionName, + ), 0); } + $this->className = $functionName; } diff --git a/src/Broker/ClassNotFoundException.php b/src/Broker/ClassNotFoundException.php index 28b3c71a4c3..d86a1bcb08b 100644 --- a/src/Broker/ClassNotFoundException.php +++ b/src/Broker/ClassNotFoundException.php @@ -8,13 +8,8 @@ class ClassNotFoundException extends AnalysedCodeException { - /** - * @var string - */ - private $className; - public function __construct(string $className) + public function __construct(private string $className) { - $this->className = $className; parent::__construct(sprintf('Class %s was not found while trying to analyse it - discovering symbols is probably not configured properly.', $className)); } diff --git a/src/Broker/ConstantNotFoundException.php b/src/Broker/ConstantNotFoundException.php index 933ab048bb1..2c490e36538 100644 --- a/src/Broker/ConstantNotFoundException.php +++ b/src/Broker/ConstantNotFoundException.php @@ -8,13 +8,8 @@ class ConstantNotFoundException extends AnalysedCodeException { - /** - * @var string - */ - private $constantName; - public function __construct(string $constantName) + public function __construct(private string $constantName) { - $this->constantName = $constantName; parent::__construct(sprintf('Constant %s not found.', $constantName)); } diff --git a/src/Broker/FunctionNotFoundException.php b/src/Broker/FunctionNotFoundException.php index 317a6d94cc8..de2728001f9 100644 --- a/src/Broker/FunctionNotFoundException.php +++ b/src/Broker/FunctionNotFoundException.php @@ -8,13 +8,8 @@ class FunctionNotFoundException extends AnalysedCodeException { - /** - * @var string - */ - private $functionName; - public function __construct(string $functionName) + public function __construct(private string $functionName) { - $this->functionName = $functionName; parent::__construct(sprintf('Function %s not found while trying to analyse it - discovering symbols is probably not configured properly.', $functionName)); } diff --git a/src/Cache/Cache.php b/src/Cache/Cache.php index 731f67b3ba6..0180ab6610f 100644 --- a/src/Cache/Cache.php +++ b/src/Cache/Cache.php @@ -5,13 +5,8 @@ class Cache { - /** - * @var CacheStorage - */ - private $storage; - public function __construct(CacheStorage $storage) + public function __construct(private CacheStorage $storage) { - $this->storage = $storage; } /** diff --git a/src/Cache/CacheItem.php b/src/Cache/CacheItem.php index 567f18fed4e..61d9946c901 100644 --- a/src/Cache/CacheItem.php +++ b/src/Cache/CacheItem.php @@ -5,21 +5,11 @@ class CacheItem { - /** - * @var string - */ - private $variableKey; - /** - * @var mixed - */ - private $data; /** * @param mixed $data */ - public function __construct(string $variableKey, $data) + public function __construct(private string $variableKey, private $data) { - $this->variableKey = $variableKey; - $this->data = $data; } public function isVariableKeyValid(string $variableKey): bool diff --git a/src/Cache/FileCacheStorage.php b/src/Cache/FileCacheStorage.php index 42b7f767ea2..38b36d25aa7 100644 --- a/src/Cache/FileCacheStorage.php +++ b/src/Cache/FileCacheStorage.php @@ -21,13 +21,8 @@ class FileCacheStorage implements CacheStorage { - /** - * @var string - */ - private $directory; - public function __construct(string $directory) + public function __construct(private string $directory) { - $this->directory = $directory; } /** @@ -68,7 +63,14 @@ public function save(string $key, string $variableKey, $data): void if ($errorAfter !== null && $errorBefore !== $errorAfter) { throw new ShouldNotHappenException(sprintf('Error occurred while saving item %s (%s) to cache: %s', $key, $variableKey, $errorAfter['message'])); } - FileWriter::write($tmpPath, sprintf(" */ - private $storage = []; + private array $storage = []; /** * @return mixed|null diff --git a/src/Collectors/CollectedData.php b/src/Collectors/CollectedData.php index 5451afb2b2e..76d7bb5fe4c 100644 --- a/src/Collectors/CollectedData.php +++ b/src/Collectors/CollectedData.php @@ -10,32 +10,19 @@ class CollectedData implements JsonSerializable { - /** - * @var mixed - */ - private $data; - /** - * @var string - */ - private $filePath; - /** - * @var class-string> - */ - private $collectorType; /** * @param mixed $data * @param class-string> $collectorType */ - public function __construct($data, string $filePath, string $collectorType) + public function __construct( + private $data, + private string $filePath, + private string $collectorType, + ) { - $this->data = $data; - $this->filePath = $filePath; - $this->collectorType = $collectorType; } - /** - * @return mixed - */ - public function getData() + + public function getData(): mixed { return $this->data; } @@ -76,7 +63,11 @@ public function jsonSerialize() */ public static function decode(array $json): self { - return new self($json['data'], $json['filePath'], $json['collectorType']); + return new self( + $json['data'], + $json['filePath'], + $json['collectorType'], + ); } /** @@ -84,7 +75,11 @@ public static function decode(array $json): self */ public static function __set_state(array $properties): self { - return new self($properties['data'], $properties['filePath'], $properties['collectorType']); + return new self( + $properties['data'], + $properties['filePath'], + $properties['collectorType'], + ); } } diff --git a/src/Collectors/Registry.php b/src/Collectors/Registry.php index bdff5703bde..65b80118b20 100644 --- a/src/Collectors/Registry.php +++ b/src/Collectors/Registry.php @@ -10,10 +10,10 @@ class Registry { /** @var Collector[][] */ - private $collectors = []; + private array $collectors = []; /** @var Collector[][] */ - private $cache = []; + private array $cache = []; /** * @param Collector[] $collectors diff --git a/src/Collectors/RegistryFactory.php b/src/Collectors/RegistryFactory.php index 52be5ac550a..0f852d32109 100644 --- a/src/Collectors/RegistryFactory.php +++ b/src/Collectors/RegistryFactory.php @@ -7,20 +7,17 @@ class RegistryFactory { - /** - * @var Container - */ - private $container; public const COLLECTOR_TAG = 'phpstan.collector'; - public function __construct(Container $container) + public function __construct(private Container $container) { - $this->container = $container; } public function create(): Registry { - return new Registry($this->container->getServicesByTag(self::COLLECTOR_TAG)); + return new Registry( + $this->container->getServicesByTag(self::COLLECTOR_TAG), + ); } } diff --git a/src/Command/AnalyseApplication.php b/src/Command/AnalyseApplication.php index 2518f7462f1..5a6209c9410 100644 --- a/src/Command/AnalyseApplication.php +++ b/src/Command/AnalyseApplication.php @@ -30,120 +30,127 @@ class AnalyseApplication { + public function __construct( + private AnalyserRunner $analyserRunner, + private StubValidator $stubValidator, + private ResultCacheManagerFactory $resultCacheManagerFactory, + private IgnoredErrorHelper $ignoredErrorHelper, + private int $internalErrorsCountLimit, + private StubFilesProvider $stubFilesProvider, + private RuleRegistry $ruleRegistry, + private ScopeFactory $scopeFactory, + private RuleErrorTransformer $ruleErrorTransformer, + ) + { + } + /** - * @var AnalyserRunner - */ - private $analyserRunner; - /** - * @var StubValidator - */ - private $stubValidator; - /** - * @var ResultCacheManagerFactory - */ - private $resultCacheManagerFactory; - /** - * @var IgnoredErrorHelper - */ - private $ignoredErrorHelper; - /** - * @var int - */ - private $internalErrorsCountLimit; - /** - * @var StubFilesProvider - */ - private $stubFilesProvider; - /** - * @var RuleRegistry - */ - private $ruleRegistry; - /** - * @var ScopeFactory - */ - private $scopeFactory; - /** - * @var RuleErrorTransformer - */ - private $ruleErrorTransformer; - public function __construct(AnalyserRunner $analyserRunner, StubValidator $stubValidator, ResultCacheManagerFactory $resultCacheManagerFactory, IgnoredErrorHelper $ignoredErrorHelper, int $internalErrorsCountLimit, StubFilesProvider $stubFilesProvider, RuleRegistry $ruleRegistry, ScopeFactory $scopeFactory, RuleErrorTransformer $ruleErrorTransformer) - { - $this->analyserRunner = $analyserRunner; - $this->stubValidator = $stubValidator; - $this->resultCacheManagerFactory = $resultCacheManagerFactory; - $this->ignoredErrorHelper = $ignoredErrorHelper; - $this->internalErrorsCountLimit = $internalErrorsCountLimit; - $this->stubFilesProvider = $stubFilesProvider; - $this->ruleRegistry = $ruleRegistry; - $this->scopeFactory = $scopeFactory; - $this->ruleErrorTransformer = $ruleErrorTransformer; - } - /** - * @param string[] $files - * @param mixed[]|null $projectConfigArray - */ - public function analyse(array $files, bool $onlyFiles, Output $stdOutput, Output $errorOutput, bool $defaultLevelUsed, bool $debug, ?string $projectConfigFile, ?array $projectConfigArray, InputInterface $input) : AnalysisResult - { - $isResultCacheUsed = false; - $resultCacheManager = $this->resultCacheManagerFactory->create(); - $ignoredErrorHelperResult = $this->ignoredErrorHelper->initialize(); - $fileSpecificErrors = []; - $notFileSpecificErrors = []; - if (count($ignoredErrorHelperResult->getErrors()) > 0) { - $notFileSpecificErrors = $ignoredErrorHelperResult->getErrors(); - $internalErrors = []; - $collectedData = []; - $savedResultCache = false; - $memoryUsageBytes = memory_get_peak_usage(true); - if ($errorOutput->isDebug()) { - $errorOutput->writeLineFormatted('Result cache was not saved because of ignoredErrorHelperResult errors.'); - } - } else { - $resultCache = $resultCacheManager->restore($files, $debug, $onlyFiles, $projectConfigArray, $errorOutput); - $intermediateAnalyserResult = $this->runAnalyser($resultCache->getFilesToAnalyse(), $files, $debug, $projectConfigFile, $stdOutput, $errorOutput, $input); - - $projectStubFiles = $this->stubFilesProvider->getProjectStubFiles(); - - $forceValidateStubFiles = (bool) ($_SERVER['__PHPSTAN_FORCE_VALIDATE_STUB_FILES'] ?? false); - if ( - $resultCache->isFullAnalysis() - && count($projectStubFiles) !== 0 - && (!$onlyFiles || $forceValidateStubFiles) - ) { - $stubErrors = $this->stubValidator->validate($projectStubFiles, $debug); - $intermediateAnalyserResult = new AnalyserResult(array_merge($intermediateAnalyserResult->getUnorderedErrors(), $stubErrors), $intermediateAnalyserResult->getLocallyIgnoredErrors(), $intermediateAnalyserResult->getInternalErrors(), $intermediateAnalyserResult->getCollectedData(), $intermediateAnalyserResult->getDependencies(), $intermediateAnalyserResult->getExportedNodes(), $intermediateAnalyserResult->hasReachedInternalErrorsCountLimit(), $intermediateAnalyserResult->getPeakMemoryUsageBytes()); - } - - $resultCacheResult = $resultCacheManager->process($intermediateAnalyserResult, $resultCache, $errorOutput, $onlyFiles, true); - $analyserResult = $resultCacheResult->getAnalyserResult(); - $internalErrors = $analyserResult->getInternalErrors(); - $errors = $analyserResult->getErrors(); - $hasInternalErrors = count($internalErrors) > 0 || $analyserResult->hasReachedInternalErrorsCountLimit(); - $memoryUsageBytes = $analyserResult->getPeakMemoryUsageBytes(); - $isResultCacheUsed = !$resultCache->isFullAnalysis(); - - if (!$hasInternalErrors) { - foreach ($this->getCollectedDataErrors($analyserResult->getCollectedData(), $onlyFiles) as $error) { - $errors[] = $error; - } - } - $ignoredErrorHelperProcessedResult = $ignoredErrorHelperResult->process($errors, $onlyFiles, $files, $hasInternalErrors); - $fileSpecificErrors = $ignoredErrorHelperProcessedResult->getNotIgnoredErrors(); - $notFileSpecificErrors = $ignoredErrorHelperProcessedResult->getOtherIgnoreMessages(); - $collectedData = $analyserResult->getCollectedData(); - $savedResultCache = $resultCacheResult->isSaved(); - if ($analyserResult->hasReachedInternalErrorsCountLimit()) { - $notFileSpecificErrors[] = sprintf('Reached internal errors count limit of %d, exiting...', $this->internalErrorsCountLimit); - } - $notFileSpecificErrors = array_merge($notFileSpecificErrors, $internalErrors); - } - return new AnalysisResult($fileSpecificErrors, $notFileSpecificErrors, $internalErrors, [], $collectedData, $defaultLevelUsed, $projectConfigFile, $savedResultCache, $memoryUsageBytes, $isResultCacheUsed); + * @param string[] $files + * @param mixed[]|null $projectConfigArray + */ + public function analyse( + array $files, + bool $onlyFiles, + Output $stdOutput, + Output $errorOutput, + bool $defaultLevelUsed, + bool $debug, + ?string $projectConfigFile, + ?array $projectConfigArray, + InputInterface $input, + ): AnalysisResult + { + $isResultCacheUsed = false; + $resultCacheManager = $this->resultCacheManagerFactory->create(); + + $ignoredErrorHelperResult = $this->ignoredErrorHelper->initialize(); + $fileSpecificErrors = []; + $notFileSpecificErrors = []; + if (count($ignoredErrorHelperResult->getErrors()) > 0) { + $notFileSpecificErrors = $ignoredErrorHelperResult->getErrors(); + $internalErrors = []; + $collectedData = []; + $savedResultCache = false; + $memoryUsageBytes = memory_get_peak_usage(true); + if ($errorOutput->isDebug()) { + $errorOutput->writeLineFormatted('Result cache was not saved because of ignoredErrorHelperResult errors.'); + } + } else { + $resultCache = $resultCacheManager->restore($files, $debug, $onlyFiles, $projectConfigArray, $errorOutput); + $intermediateAnalyserResult = $this->runAnalyser( + $resultCache->getFilesToAnalyse(), + $files, + $debug, + $projectConfigFile, + $stdOutput, + $errorOutput, + $input, + ); + + $projectStubFiles = $this->stubFilesProvider->getProjectStubFiles(); + + $forceValidateStubFiles = (bool) ($_SERVER['__PHPSTAN_FORCE_VALIDATE_STUB_FILES'] ?? false); + if ( + $resultCache->isFullAnalysis() + && count($projectStubFiles) !== 0 + && (!$onlyFiles || $forceValidateStubFiles) + ) { + $stubErrors = $this->stubValidator->validate($projectStubFiles, $debug); + $intermediateAnalyserResult = new AnalyserResult( + array_merge($intermediateAnalyserResult->getUnorderedErrors(), $stubErrors), + $intermediateAnalyserResult->getLocallyIgnoredErrors(), + $intermediateAnalyserResult->getInternalErrors(), + $intermediateAnalyserResult->getCollectedData(), + $intermediateAnalyserResult->getDependencies(), + $intermediateAnalyserResult->getExportedNodes(), + $intermediateAnalyserResult->hasReachedInternalErrorsCountLimit(), + $intermediateAnalyserResult->getPeakMemoryUsageBytes(), + ); + } + + $resultCacheResult = $resultCacheManager->process($intermediateAnalyserResult, $resultCache, $errorOutput, $onlyFiles, true); + $analyserResult = $resultCacheResult->getAnalyserResult(); + $internalErrors = $analyserResult->getInternalErrors(); + $errors = $analyserResult->getErrors(); + $hasInternalErrors = count($internalErrors) > 0 || $analyserResult->hasReachedInternalErrorsCountLimit(); + $memoryUsageBytes = $analyserResult->getPeakMemoryUsageBytes(); + $isResultCacheUsed = !$resultCache->isFullAnalysis(); + + if (!$hasInternalErrors) { + foreach ($this->getCollectedDataErrors($analyserResult->getCollectedData(), $onlyFiles) as $error) { + $errors[] = $error; + } + } + $ignoredErrorHelperProcessedResult = $ignoredErrorHelperResult->process($errors, $onlyFiles, $files, $hasInternalErrors); + $fileSpecificErrors = $ignoredErrorHelperProcessedResult->getNotIgnoredErrors(); + $notFileSpecificErrors = $ignoredErrorHelperProcessedResult->getOtherIgnoreMessages(); + $collectedData = $analyserResult->getCollectedData(); + $savedResultCache = $resultCacheResult->isSaved(); + if ($analyserResult->hasReachedInternalErrorsCountLimit()) { + $notFileSpecificErrors[] = sprintf('Reached internal errors count limit of %d, exiting...', $this->internalErrorsCountLimit); + } + $notFileSpecificErrors = array_merge($notFileSpecificErrors, $internalErrors); } - /** - * @param CollectedData[] $collectedData - * @return Error[] - */ - private function getCollectedDataErrors(array $collectedData, bool $onlyFiles): array + + return new AnalysisResult( + $fileSpecificErrors, + $notFileSpecificErrors, + $internalErrors, + [], + $collectedData, + $defaultLevelUsed, + $projectConfigFile, + $savedResultCache, + $memoryUsageBytes, + $isResultCacheUsed, + ); + } + + /** + * @param CollectedData[] $collectedData + * @return Error[] + */ + private function getCollectedDataErrors(array $collectedData, bool $onlyFiles): array { $nodeType = CollectedDataNode::class; $node = new CollectedDataNode($collectedData, $onlyFiles); @@ -173,52 +180,64 @@ private function getCollectedDataErrors(array $collectedData, bool $onlyFiles): } /** - * @param string[] $files - * @param string[] $allAnalysedFiles - */ - private function runAnalyser(array $files, array $allAnalysedFiles, bool $debug, ?string $projectConfigFile, Output $stdOutput, Output $errorOutput, InputInterface $input) : AnalyserResult - { - $filesCount = count($files); - $allAnalysedFilesCount = count($allAnalysedFiles); - if ($filesCount === 0) { - $errorOutput->getStyle()->progressStart($allAnalysedFilesCount); - $errorOutput->getStyle()->progressAdvance($allAnalysedFilesCount); - $errorOutput->getStyle()->progressFinish(); - return new AnalyserResult([], [], [], [], [], [], false, memory_get_peak_usage(true)); - } - if (!$debug) { - $preFileCallback = null; - $postFileCallback = static function (int $step) use ($errorOutput): void { - $errorOutput->getStyle()->progressAdvance($step); - }; - - $errorOutput->getStyle()->progressStart($allAnalysedFilesCount); - $errorOutput->getStyle()->progressAdvance($allAnalysedFilesCount - $filesCount); - } else { - $startTime = null; - $preFileCallback = static function (string $file) use ($stdOutput, &$startTime): void { - $stdOutput->writeLineFormatted($file); - $startTime = microtime(true); - }; - $postFileCallback = null; - if ($stdOutput->isDebug()) { - $previousMemory = memory_get_peak_usage(true); - $postFileCallback = static function () use ($stdOutput, &$previousMemory, &$startTime): void { - if ($startTime === null) { - throw new ShouldNotHappenException(); - } - $currentTotalMemory = memory_get_peak_usage(true); - $elapsedTime = microtime(true) - $startTime; - $stdOutput->writeLineFormatted(sprintf('--- consumed %s, total %s, took %.2f s', BytesHelper::bytes($currentTotalMemory - $previousMemory), BytesHelper::bytes($currentTotalMemory), $elapsedTime)); - $previousMemory = $currentTotalMemory; - }; - } - } - $analyserResult = $this->analyserRunner->runAnalyser($files, $allAnalysedFiles, $preFileCallback, $postFileCallback, $debug, true, $projectConfigFile, $input); - if (!$debug) { - $errorOutput->getStyle()->progressFinish(); - } - return $analyserResult; + * @param string[] $files + * @param string[] $allAnalysedFiles + */ + private function runAnalyser( + array $files, + array $allAnalysedFiles, + bool $debug, + ?string $projectConfigFile, + Output $stdOutput, + Output $errorOutput, + InputInterface $input, + ): AnalyserResult + { + $filesCount = count($files); + $allAnalysedFilesCount = count($allAnalysedFiles); + if ($filesCount === 0) { + $errorOutput->getStyle()->progressStart($allAnalysedFilesCount); + $errorOutput->getStyle()->progressAdvance($allAnalysedFilesCount); + $errorOutput->getStyle()->progressFinish(); + return new AnalyserResult([], [], [], [], [], [], false, memory_get_peak_usage(true)); + } + + if (!$debug) { + $preFileCallback = null; + $postFileCallback = static function (int $step) use ($errorOutput): void { + $errorOutput->getStyle()->progressAdvance($step); + }; + + $errorOutput->getStyle()->progressStart($allAnalysedFilesCount); + $errorOutput->getStyle()->progressAdvance($allAnalysedFilesCount - $filesCount); + } else { + $startTime = null; + $preFileCallback = static function (string $file) use ($stdOutput, &$startTime): void { + $stdOutput->writeLineFormatted($file); + $startTime = microtime(true); + }; + $postFileCallback = null; + if ($stdOutput->isDebug()) { + $previousMemory = memory_get_peak_usage(true); + $postFileCallback = static function () use ($stdOutput, &$previousMemory, &$startTime): void { + if ($startTime === null) { + throw new ShouldNotHappenException(); + } + $currentTotalMemory = memory_get_peak_usage(true); + $elapsedTime = microtime(true) - $startTime; + $stdOutput->writeLineFormatted(sprintf('--- consumed %s, total %s, took %.2f s', BytesHelper::bytes($currentTotalMemory - $previousMemory), BytesHelper::bytes($currentTotalMemory), $elapsedTime)); + $previousMemory = $currentTotalMemory; + }; + } } + $analyserResult = $this->analyserRunner->runAnalyser($files, $allAnalysedFiles, $preFileCallback, $postFileCallback, $debug, true, $projectConfigFile, $input); + + if (!$debug) { + $errorOutput->getStyle()->progressFinish(); + } + + return $analyserResult; + } + } diff --git a/src/Command/AnalyseCommand.php b/src/Command/AnalyseCommand.php index 5ca42151073..9c49194aab7 100644 --- a/src/Command/AnalyseCommand.php +++ b/src/Command/AnalyseCommand.php @@ -54,10 +54,6 @@ class AnalyseCommand extends Command { - /** - * @var string[] - */ - private $composerAutoloaderProjectPaths; private const NAME = 'analyse'; public const OPTION_LEVEL = 'level'; @@ -67,9 +63,10 @@ class AnalyseCommand extends Command /** * @param string[] $composerAutoloaderProjectPaths */ - public function __construct(array $composerAutoloaderProjectPaths) + public function __construct( + private array $composerAutoloaderProjectPaths, + ) { - $this->composerAutoloaderProjectPaths = $composerAutoloaderProjectPaths; parent::__construct(); } @@ -150,7 +147,19 @@ protected function execute(InputInterface $input, OutputInterface $output): int } try { - $inceptionResult = CommandHelper::begin($input, $output, $paths, $memoryLimit, $autoloadFile, $this->composerAutoloaderProjectPaths, $configuration, $generateBaselineFile, $level, $allowXdebug, $debugEnabled); + $inceptionResult = CommandHelper::begin( + $input, + $output, + $paths, + $memoryLimit, + $autoloadFile, + $this->composerAutoloaderProjectPaths, + $configuration, + $generateBaselineFile, + $level, + $allowXdebug, + $debugEnabled, + ); } catch (InceptionNotSuccessfulException $e) { return 1; } @@ -187,9 +196,11 @@ protected function execute(InputInterface $input, OutputInterface $output): int $container = $inceptionResult->getContainer(); $errorFormatterServiceName = sprintf('errorFormatter.%s', $errorFormat); if (!$container->hasService($errorFormatterServiceName)) { - $errorOutput->writeLineFormatted(sprintf('Error formatter "%s" not found. Available error formatters are: %s', $errorFormat, implode(', ', array_map(static function (string $name) : string { - return substr($name, strlen('errorFormatter.')); - }, $container->findServiceNamesByType(ErrorFormatter::class))))); + $errorOutput->writeLineFormatted(sprintf( + 'Error formatter "%s" not found. Available error formatters are: %s', + $errorFormat, + implode(', ', array_map(static fn (string $name): string => substr($name, strlen('errorFormatter.')), $container->findServiceNamesByType(ErrorFormatter::class))), + )); return 1; } @@ -213,7 +224,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int } catch (PathNotFoundException $e) { $inceptionResult->getErrorOutput()->writeLineFormatted(sprintf('%s', $e->getMessage())); return 1; - } catch (InceptionNotSuccessfulException $e) { + } catch (InceptionNotSuccessfulException) { return 1; } @@ -244,7 +255,11 @@ protected function execute(InputInterface $input, OutputInterface $output): int /** @var RelativePathHelper $relativePathHelper */ $relativePathHelper = $container->getService('relativePathHelper'); - $inceptionResult->getErrorOutput()->getStyle()->warning(sprintf('Configuration file %s (%s) is too big and might slow down PHPStan. Consider adding it to excludePaths.', $relativePathHelper->getRelativePath($analysedConfigFile), BytesHelper::bytes($fileSize))); + $inceptionResult->getErrorOutput()->getStyle()->warning(sprintf( + 'Configuration file %s (%s) is too big and might slow down PHPStan. Consider adding it to excludePaths.', + $relativePathHelper->getRelativePath($analysedConfigFile), + BytesHelper::bytes($fileSize), + )); } if ($fix) { @@ -259,11 +274,27 @@ protected function execute(InputInterface $input, OutputInterface $output): int } try { - $analysisResult = $application->analyse($files, $onlyFiles, $inceptionResult->getStdOutput(), $inceptionResult->getErrorOutput(), $inceptionResult->isDefaultLevelUsed(), $debug, $inceptionResult->getProjectConfigFile(), $inceptionResult->getProjectConfigArray(), $input); + $analysisResult = $application->analyse( + $files, + $onlyFiles, + $inceptionResult->getStdOutput(), + $inceptionResult->getErrorOutput(), + $inceptionResult->isDefaultLevelUsed(), + $debug, + $inceptionResult->getProjectConfigFile(), + $inceptionResult->getProjectConfigArray(), + $input, + ); } catch (Throwable $t) { if ($debug) { $stdOutput = $inceptionResult->getStdOutput(); - $stdOutput->writeRaw(sprintf('Uncaught %s: %s in %s:%d', get_class($t), $t->getMessage(), $t->getFile(), $t->getLine())); + $stdOutput->writeRaw(sprintf( + 'Uncaught %s: %s in %s:%d', + get_class($t), + $t->getMessage(), + $t->getFile(), + $t->getLine(), + )); $stdOutput->writeLineFormatted(''); $stdOutput->writeRaw($t->getTraceAsString()); $stdOutput->writeLineFormatted(''); @@ -272,7 +303,13 @@ protected function execute(InputInterface $input, OutputInterface $output): int while ($previous !== null) { $stdOutput->writeLineFormatted(''); $stdOutput->writeLineFormatted('Caused by:'); - $stdOutput->writeRaw(sprintf('Uncaught %s: %s in %s:%d', get_class($previous), $previous->getMessage(), $previous->getFile(), $previous->getLine())); + $stdOutput->writeRaw(sprintf( + 'Uncaught %s: %s in %s:%d', + get_class($previous), + $previous->getMessage(), + $previous->getFile(), + $previous->getLine(), + )); $stdOutput->writeRaw($previous->getTraceAsString()); $stdOutput->writeLineFormatted(''); $previous = $previous->getPrevious(); @@ -296,7 +333,10 @@ protected function execute(InputInterface $input, OutputInterface $output): int $exitCode = 2; } - return $inceptionResult->handleReturn($exitCode, $analysisResult->getPeakMemoryUsageBytes()); + return $inceptionResult->handleReturn( + $exitCode, + $analysisResult->getPeakMemoryUsageBytes(), + ); } private function createStreamOutput(): StreamOutput @@ -324,7 +364,10 @@ private function generateBaseline(string $generateBaselineFile, InceptionResult $inceptionResult->getStdOutput()->writeLineFormatted(''); } - $inceptionResult->getStdOutput()->getStyle()->error(sprintf('%s occurred. Baseline could not be generated.', count($internalErrors) === 1 ? 'An internal error' : 'Internal errors')); + $inceptionResult->getStdOutput()->getStyle()->error(sprintf( + '%s occurred. Baseline could not be generated.', + count($internalErrors) === 1 ? 'An internal error' : 'Internal errors', + )); return $inceptionResult->handleReturn(1, $analysisResult->getPeakMemoryUsageBytes()); } @@ -432,7 +475,13 @@ private function runFixer(InceptionResult $inceptionResult, Container $container /** @var FixerApplication $fixerApplication */ $fixerApplication = $container->getByType(FixerApplication::class); - return $fixerApplication->run($inceptionResult->getProjectConfigFile(), $input, $output, count($files), $_SERVER['argv'][0]); + return $fixerApplication->run( + $inceptionResult->getProjectConfigFile(), + $input, + $output, + count($files), + $_SERVER['argv'][0], + ); } } diff --git a/src/Command/AnalyserRunner.php b/src/Command/AnalyserRunner.php index 818f20a1839..6e5a92467d9 100644 --- a/src/Command/AnalyserRunner.php +++ b/src/Command/AnalyserRunner.php @@ -18,65 +18,71 @@ class AnalyserRunner { - /** - * @var Scheduler - */ - private $scheduler; - /** - * @var Analyser - */ - private $analyser; - /** - * @var ParallelAnalyser - */ - private $parallelAnalyser; - /** - * @var CpuCoreCounter - */ - private $cpuCoreCounter; - public function __construct(Scheduler $scheduler, Analyser $analyser, ParallelAnalyser $parallelAnalyser, CpuCoreCounter $cpuCoreCounter) - { - $this->scheduler = $scheduler; - $this->analyser = $analyser; - $this->parallelAnalyser = $parallelAnalyser; - $this->cpuCoreCounter = $cpuCoreCounter; - } - /** - * @param string[] $files - * @param string[] $allAnalysedFiles - * @param Closure(string $file): void|null $preFileCallback - * @param Closure(int ): void|null $postFileCallback - */ - public function runAnalyser(array $files, array $allAnalysedFiles, ?Closure $preFileCallback, ?Closure $postFileCallback, bool $debug, bool $allowParallel, ?string $projectConfigFile, InputInterface $input) : AnalyserResult - { - $filesCount = count($files); - if ($filesCount === 0) { - return new AnalyserResult([], [], [], [], [], [], false, memory_get_peak_usage(true)); - } - $schedule = $this->scheduler->scheduleWork($this->cpuCoreCounter->getNumberOfCpuCores(), $files); - $mainScript = null; - if (isset($_SERVER['argv'][0]) && is_file($_SERVER['argv'][0])) { - $mainScript = $_SERVER['argv'][0]; - } - if ( - !$debug - && $allowParallel - && function_exists('proc_open') - && $mainScript !== null - && $schedule->getNumberOfProcesses() > 0 - ) { - $loop = new StreamSelectLoop(); - $result = null; - $promise = $this->parallelAnalyser->analyse($loop, $schedule, $mainScript, $postFileCallback, $projectConfigFile, $input, null); - $promise->then(static function (AnalyserResult $tmp) use (&$result): void { - $result = $tmp; - }); - $loop->run(); - if ($result === null) { - throw new ShouldNotHappenException(); - } - return $result; - } - return $this->analyser->analyse($files, $preFileCallback, $postFileCallback, $debug, $allAnalysedFiles); - } + + public function __construct( + private Scheduler $scheduler, + private Analyser $analyser, + private ParallelAnalyser $parallelAnalyser, + private CpuCoreCounter $cpuCoreCounter, + ) + { + } + + /** + * @param string[] $files + * @param string[] $allAnalysedFiles + * @param Closure(string $file): void|null $preFileCallback + * @param Closure(int ): void|null $postFileCallback + */ + public function runAnalyser( + array $files, + array $allAnalysedFiles, + ?Closure $preFileCallback, + ?Closure $postFileCallback, + bool $debug, + bool $allowParallel, + ?string $projectConfigFile, + InputInterface $input, + ): AnalyserResult + { + $filesCount = count($files); + if ($filesCount === 0) { + return new AnalyserResult([], [], [], [], [], [], false, memory_get_peak_usage(true)); + } + + $schedule = $this->scheduler->scheduleWork($this->cpuCoreCounter->getNumberOfCpuCores(), $files); + $mainScript = null; + if (isset($_SERVER['argv'][0]) && is_file($_SERVER['argv'][0])) { + $mainScript = $_SERVER['argv'][0]; + } + + if ( + !$debug + && $allowParallel + && function_exists('proc_open') + && $mainScript !== null + && $schedule->getNumberOfProcesses() > 0 + ) { + $loop = new StreamSelectLoop(); + $result = null; + $promise = $this->parallelAnalyser->analyse($loop, $schedule, $mainScript, $postFileCallback, $projectConfigFile, $input, null); + $promise->then(static function (AnalyserResult $tmp) use (&$result): void { + $result = $tmp; + }); + $loop->run(); + if ($result === null) { + throw new ShouldNotHappenException(); + } + return $result; + } + + return $this->analyser->analyse( + $files, + $preFileCallback, + $postFileCallback, + $debug, + $allAnalysedFiles, + ); + } + } diff --git a/src/Command/AnalysisResult.php b/src/Command/AnalysisResult.php index 7a91e0b9782..b589665f8b1 100644 --- a/src/Command/AnalysisResult.php +++ b/src/Command/AnalysisResult.php @@ -11,44 +11,8 @@ class AnalysisResult { - /** - * @var list - */ - private $notFileSpecificErrors; - /** - * @var list - */ - private $internalErrors; - /** - * @var list - */ - private $warnings; - /** - * @var list - */ - private $collectedData; - /** - * @var bool - */ - private $defaultLevelUsed; - /** - * @var ?string - */ - private $projectConfigFile; - /** - * @var bool - */ - private $savedResultCache; - /** - * @var int - */ - private $peakMemoryUsageBytes; - /** - * @var bool - */ - private $isResultCacheUsed; /** @var list sorted by their file name, line number and message */ - private $fileSpecificErrors; + private array $fileSpecificErrors; /** * @param list $fileSpecificErrors @@ -57,19 +21,22 @@ class AnalysisResult * @param list $warnings * @param list $collectedData */ - public function __construct(array $fileSpecificErrors, array $notFileSpecificErrors, array $internalErrors, array $warnings, array $collectedData, bool $defaultLevelUsed, ?string $projectConfigFile, bool $savedResultCache, int $peakMemoryUsageBytes, bool $isResultCacheUsed) + public function __construct( + array $fileSpecificErrors, + private array $notFileSpecificErrors, + private array $internalErrors, + private array $warnings, + private array $collectedData, + private bool $defaultLevelUsed, + private ?string $projectConfigFile, + private bool $savedResultCache, + private int $peakMemoryUsageBytes, + private bool $isResultCacheUsed, + ) { - $this->notFileSpecificErrors = $notFileSpecificErrors; - $this->internalErrors = $internalErrors; - $this->warnings = $warnings; - $this->collectedData = $collectedData; - $this->defaultLevelUsed = $defaultLevelUsed; - $this->projectConfigFile = $projectConfigFile; - $this->savedResultCache = $savedResultCache; - $this->peakMemoryUsageBytes = $peakMemoryUsageBytes; - $this->isResultCacheUsed = $isResultCacheUsed; - usort($fileSpecificErrors, static function (Error $a, Error $b) : int { - return [ + usort( + $fileSpecificErrors, + static fn (Error $a, Error $b): int => [ $a->getFile(), $a->getLine(), $a->getMessage(), @@ -77,8 +44,9 @@ public function __construct(array $fileSpecificErrors, array $notFileSpecificErr $b->getFile(), $b->getLine(), $b->getMessage(), - ]; - }); + ], + ); + $this->fileSpecificErrors = $fileSpecificErrors; } diff --git a/src/Command/ClearResultCacheCommand.php b/src/Command/ClearResultCacheCommand.php index b6bf4d84f9e..30c59100ec7 100644 --- a/src/Command/ClearResultCacheCommand.php +++ b/src/Command/ClearResultCacheCommand.php @@ -14,18 +14,15 @@ class ClearResultCacheCommand extends Command { - /** - * @var string[] - */ - private $composerAutoloaderProjectPaths; private const NAME = 'clear-result-cache'; /** * @param string[] $composerAutoloaderProjectPaths */ - public function __construct(array $composerAutoloaderProjectPaths) + public function __construct( + private array $composerAutoloaderProjectPaths, + ) { - $this->composerAutoloaderProjectPaths = $composerAutoloaderProjectPaths; parent::__construct(); } @@ -72,8 +69,20 @@ protected function execute(InputInterface $input, OutputInterface $output): int } try { - $inceptionResult = CommandHelper::begin($input, $output, [], $memoryLimit, $autoloadFile, $this->composerAutoloaderProjectPaths, $configuration, null, '0', $allowXdebug, $debugEnabled); - } catch (InceptionNotSuccessfulException $e) { + $inceptionResult = CommandHelper::begin( + $input, + $output, + [], + $memoryLimit, + $autoloadFile, + $this->composerAutoloaderProjectPaths, + $configuration, + null, + '0', + $allowXdebug, + $debugEnabled, + ); + } catch (InceptionNotSuccessfulException) { return 1; } diff --git a/src/Command/CommandHelper.php b/src/Command/CommandHelper.php index 62929bdac3b..1261814cef1 100644 --- a/src/Command/CommandHelper.php +++ b/src/Command/CommandHelper.php @@ -66,10 +66,7 @@ class CommandHelper public const DEFAULT_LEVEL = '0'; - /** - * @var ?string - */ - private static $reservedMemory = null; + private static ?string $reservedMemory = null; /** * @param string[] $paths @@ -77,19 +74,35 @@ class CommandHelper * * @throws InceptionNotSuccessfulException */ - public static function begin(InputInterface $input, OutputInterface $output, array $paths, ?string $memoryLimit, ?string $autoloadFile, array $composerAutoloaderProjectPaths, ?string $projectConfigFile, ?string $generateBaselineFile, ?string $level, bool $allowXdebug, bool $debugEnabled = false, bool $cleanupContainerCache = true) : InceptionResult + public static function begin( + InputInterface $input, + OutputInterface $output, + array $paths, + ?string $memoryLimit, + ?string $autoloadFile, + array $composerAutoloaderProjectPaths, + ?string $projectConfigFile, + ?string $generateBaselineFile, + ?string $level, + bool $allowXdebug, + bool $debugEnabled = false, + bool $cleanupContainerCache = true, + ): InceptionResult { $stdOutput = new SymfonyOutput($output, new SymfonyStyle(new ErrorsConsoleStyle($input, $output))); + $errorOutput = (static function () use ($input, $output): Output { $symfonyErrorOutput = $output instanceof ConsoleOutputInterface ? $output->getErrorOutput() : $output; return new SymfonyOutput($symfonyErrorOutput, new SymfonyStyle(new ErrorsConsoleStyle($input, $symfonyErrorOutput))); })(); + if (!$allowXdebug) { $xdebug = new XdebugHandler('phpstan'); $xdebug->setPersistent(); $xdebug->check(); unset($xdebug); } + if ($allowXdebug) { if (!XdebugHandler::isXdebugActive()) { $errorOutput->getStyle()->note('You are running with "--xdebug" enabled, but the Xdebug PHP extension is not active. The process will not halt at breakpoints.'); @@ -101,11 +114,14 @@ public static function begin(InputInterface $input, OutputInterface $output, arr } elseif ($debugEnabled) { $v = XdebugHandler::getSkippedVersion(); if ($v !== '') { - $errorOutput->getStyle()->note("The Xdebug PHP extension is active, but \"--xdebug\" is not used.\n" . + $errorOutput->getStyle()->note( + "The Xdebug PHP extension is active, but \"--xdebug\" is not used.\n" . "The process was restarted and it will not halt at breakpoints.\n" . - 'Use "--xdebug" if you want to halt at breakpoints.'); + 'Use "--xdebug" if you want to halt at breakpoints.', + ); } } + if ($memoryLimit !== null) { if (Strings::match($memoryLimit, '#^-?\d+[kMG]?$#i') === null) { $errorOutput->writeLineFormatted(sprintf('Invalid memory limit format "%s".', $memoryLimit)); @@ -116,8 +132,8 @@ public static function begin(InputInterface $input, OutputInterface $output, arr throw new InceptionNotSuccessfulException(); } } - self::$reservedMemory = str_repeat('PHPStan', 1463); - // reserve 10 kB of space + + self::$reservedMemory = str_repeat('PHPStan', 1463); // reserve 10 kB of space register_shutdown_function(static function () use ($errorOutput): void { self::$reservedMemory = null; $error = error_get_last(); @@ -136,14 +152,17 @@ public static function begin(InputInterface $input, OutputInterface $output, arr $errorOutput->writeLineFormatted(sprintf('PHPStan process crashed because it reached configured PHP memory limit: %s', ini_get('memory_limit'))); $errorOutput->writeLineFormatted('Increase your memory limit in php.ini or run PHPStan with --memory-limit CLI option.'); }); + $currentWorkingDirectory = getcwd(); if ($currentWorkingDirectory === false) { throw new ShouldNotHappenException(); } $currentWorkingDirectoryFileHelper = new FileHelper($currentWorkingDirectory); $currentWorkingDirectory = $currentWorkingDirectoryFileHelper->getWorkingDirectory(); + /** @var array|false $autoloadFunctionsBefore */ $autoloadFunctionsBefore = spl_autoload_functions(); + if ($autoloadFile !== null) { $autoloadFile = $currentWorkingDirectoryFileHelper->absolutizePath($autoloadFile); if (!is_file($autoloadFile)) { @@ -167,17 +186,19 @@ public static function begin(InputInterface $input, OutputInterface $output, arr } else { $projectConfigFile = $currentWorkingDirectoryFileHelper->absolutizePath($projectConfigFile); } + if ($generateBaselineFile !== null) { $generateBaselineFile = $currentWorkingDirectoryFileHelper->normalizePath($currentWorkingDirectoryFileHelper->absolutizePath($generateBaselineFile)); } + $defaultLevelUsed = false; if ($projectConfigFile === null && $level === null) { $level = self::DEFAULT_LEVEL; $defaultLevelUsed = true; } - $paths = array_map(static function (string $path) use($currentWorkingDirectoryFileHelper) : string { - return $currentWorkingDirectoryFileHelper->normalizePath($currentWorkingDirectoryFileHelper->absolutizePath($path)); - }, $paths); + + $paths = array_map(static fn (string $path): string => $currentWorkingDirectoryFileHelper->normalizePath($currentWorkingDirectoryFileHelper->absolutizePath($path)), $paths); + $analysedPathsFromConfig = []; $containerFactory = new ContainerFactory($currentWorkingDirectory, true); $projectConfig = null; @@ -187,7 +208,12 @@ public static function begin(InputInterface $input, OutputInterface $output, arr throw new InceptionNotSuccessfulException(); } - $loader = (new LoaderFactory($currentWorkingDirectoryFileHelper, $containerFactory->getRootDirectory(), $containerFactory->getCurrentWorkingDirectory(), $generateBaselineFile))->createLoader(); + $loader = (new LoaderFactory( + $currentWorkingDirectoryFileHelper, + $containerFactory->getRootDirectory(), + $containerFactory->getCurrentWorkingDirectory(), + $generateBaselineFile, + ))->createLoader(); try { $projectConfig = $loader->load($projectConfigFile, null); @@ -214,6 +240,7 @@ public static function begin(InputInterface $input, OutputInterface $output, arr $paths = $analysedPathsFromConfig; } } + $additionalConfigFiles = []; if ($level !== null) { $levelConfigFile = sprintf('%s/config.level%s.neon', $containerFactory->getConfigDirectory(), $level); @@ -224,6 +251,7 @@ public static function begin(InputInterface $input, OutputInterface $output, arr $additionalConfigFiles[] = $levelConfigFile; } + if (class_exists('PHPStan\ExtensionInstaller\GeneratedConfig')) { $generatedConfigReflection = new ReflectionClass('PHPStan\ExtensionInstaller\GeneratedConfig'); $generatedConfigDirectory = dirname($generatedConfigReflection->getFileName()); @@ -252,12 +280,14 @@ public static function begin(InputInterface $input, OutputInterface $output, arr } } } + if ( $projectConfigFile !== null && $currentWorkingDirectoryFileHelper->normalizePath($projectConfigFile, '/') !== $currentWorkingDirectoryFileHelper->normalizePath(__DIR__ . '/../../conf/config.stubFiles.neon', '/') ) { $additionalConfigFiles[] = $projectConfigFile; } + $createDir = static function (string $path) use ($errorOutput): void { try { DirectoryCreator::ensureDirectoryExists($path, 0777); @@ -266,10 +296,12 @@ public static function begin(InputInterface $input, OutputInterface $output, arr throw new InceptionNotSuccessfulException(); } }; + if (!isset($tmpDir)) { $tmpDir = sys_get_temp_dir() . '/phpstan'; $createDir($tmpDir); } + try { $container = $containerFactory->create($tmpDir, $additionalConfigFiles, $paths, $composerAutoloaderProjectPaths, $analysedPathsFromConfig, $level ?? self::DEFAULT_LEVEL, $generateBaselineFile, $autoloadFile); } catch (InvalidConfigurationException | AssertionException $e) { @@ -334,9 +366,11 @@ public static function begin(InputInterface $input, OutputInterface $output, arr throw new InceptionNotSuccessfulException(); } + if ($cleanupContainerCache) { $containerFactory->clearOldContainers($tmpDir); } + /** @var bool|null $customRulesetUsed */ $customRulesetUsed = $container->getParameter('customRulesetUsed'); if ($customRulesetUsed === null) { @@ -354,11 +388,14 @@ public static function begin(InputInterface $input, OutputInterface $output, arr } elseif ($customRulesetUsed) { $defaultLevelUsed = false; } + foreach ($container->getParameter('bootstrapFiles') as $bootstrapFileFromArray) { self::executeBootstrapFile($bootstrapFileFromArray, $container, $errorOutput, $debugEnabled); } + /** @var array|false $autoloadFunctionsAfter */ $autoloadFunctionsAfter = spl_autoload_functions(); + if ($autoloadFunctionsBefore !== false && $autoloadFunctionsAfter !== false) { $newAutoloadFunctions = $GLOBALS['__phpstanAutoloadFunctions'] ?? []; foreach ($autoloadFunctionsAfter as $after) { @@ -373,6 +410,7 @@ public static function begin(InputInterface $input, OutputInterface $output, arr $GLOBALS['__phpstanAutoloadFunctions'] = $newAutoloadFunctions; } + if (PHP_VERSION_ID >= 80000) { require_once __DIR__ . '/../../stubs/runtime/Enum/UnitEnum.php'; require_once __DIR__ . '/../../stubs/runtime/Enum/BackedEnum.php'; @@ -380,6 +418,7 @@ public static function begin(InputInterface $input, OutputInterface $output, arr require_once __DIR__ . '/../../stubs/runtime/Enum/ReflectionEnumUnitCase.php'; require_once __DIR__ . '/../../stubs/runtime/Enum/ReflectionEnumBackedCase.php'; } + foreach ($container->getParameter('scanFiles') as $scannedFile) { if (is_file($scannedFile)) { continue; @@ -389,6 +428,7 @@ public static function begin(InputInterface $input, OutputInterface $output, arr throw new InceptionNotSuccessfulException(); } + foreach ($container->getParameter('scanDirectories') as $scannedDirectory) { if (is_dir($scannedDirectory)) { continue; @@ -398,6 +438,7 @@ public static function begin(InputInterface $input, OutputInterface $output, arr throw new InceptionNotSuccessfulException(); } + $alreadyAddedStubFiles = []; foreach ($container->getParameter('stubFiles') as $stubFile) { if (array_key_exists($stubFile, $alreadyAddedStubFiles)) { @@ -416,6 +457,7 @@ public static function begin(InputInterface $input, OutputInterface $output, arr throw new InceptionNotSuccessfulException(); } + $excludesAnalyse = $container->getParameter('excludes_analyse'); $excludePaths = $container->getParameter('excludePaths'); if (count($excludesAnalyse) > 0 && $excludePaths !== null) { @@ -430,17 +472,23 @@ public static function begin(InputInterface $input, OutputInterface $output, arr $errorOutput->writeLineFormatted(''); $errorOutput->writeLineFormatted(sprintf('Parameter excludes_analyse has been deprecated so use excludePaths only from now on.')); } + if ($container->hasParameter('scopeClass') && $container->getParameter('scopeClass') !== MutatingScope::class) { $errorOutput->writeLineFormatted('⚠️ You\'re using a deprecated config option scopeClass. ⚠️️'); $errorOutput->writeLineFormatted(''); $errorOutput->writeLineFormatted(sprintf('Please implement PHPStan\Type\ExpressionTypeResolverExtension interface instead and register it as a service.')); } + $tempResultCachePath = $container->getParameter('tempResultCachePath'); $createDir($tempResultCachePath); + /** @var FileFinder $fileFinder */ $fileFinder = $container->getService('fileFinderAnalyse'); + $pathRoutingParser = $container->getService('pathRoutingParser'); + $stubFilesProvider = $container->getByType(StubFilesProvider::class); + $filesCallback = static function () use ($currentWorkingDirectoryFileHelper, $stubFilesProvider, $fileFinder, $pathRoutingParser, $paths, $errorOutput): array { if (count($paths) === 0) { $errorOutput->writeLineFormatted('At least one path must be specified to analyse.'); @@ -453,19 +501,32 @@ public static function begin(InputInterface $input, OutputInterface $output, arr $stubFilesExcluder = new FileExcluder($currentWorkingDirectoryFileHelper, $stubFilesProvider->getProjectStubFiles()); - $files = array_values(array_filter($files, static function (string $file) use($stubFilesExcluder) { - return !$stubFilesExcluder->isExcludedFromAnalysing($file); - })); + $files = array_values(array_filter($files, static fn (string $file) => !$stubFilesExcluder->isExcludedFromAnalysing($file))); return [$files, $fileFinderResult->isOnlyFiles()]; }; - return new InceptionResult($filesCallback, $stdOutput, $errorOutput, $container, $defaultLevelUsed, $projectConfigFile, $projectConfig, $generateBaselineFile); + + return new InceptionResult( + $filesCallback, + $stdOutput, + $errorOutput, + $container, + $defaultLevelUsed, + $projectConfigFile, + $projectConfig, + $generateBaselineFile, + ); } /** * @throws InceptionNotSuccessfulException */ - private static function executeBootstrapFile(string $file, Container $container, Output $errorOutput, bool $debugEnabled) : void + private static function executeBootstrapFile( + string $file, + Container $container, + Output $errorOutput, + bool $debugEnabled, + ): void { if (!is_file($file)) { $errorOutput->writeLineFormatted(sprintf('Bootstrap file %s does not exist.', $file)); diff --git a/src/Command/DumpParametersCommand.php b/src/Command/DumpParametersCommand.php index 8341407e001..50e6e57b4bc 100644 --- a/src/Command/DumpParametersCommand.php +++ b/src/Command/DumpParametersCommand.php @@ -14,18 +14,15 @@ class DumpParametersCommand extends Command { - /** - * @var string[] - */ - private $composerAutoloaderProjectPaths; private const NAME = 'dump-parameters'; /** * @param string[] $composerAutoloaderProjectPaths */ - public function __construct(array $composerAutoloaderProjectPaths) + public function __construct( + private array $composerAutoloaderProjectPaths, + ) { - $this->composerAutoloaderProjectPaths = $composerAutoloaderProjectPaths; parent::__construct(); } @@ -73,8 +70,19 @@ protected function execute(InputInterface $input, OutputInterface $output): int } try { - $inceptionResult = CommandHelper::begin($input, $output, [], $memoryLimit, $autoloadFile, $this->composerAutoloaderProjectPaths, $configuration, null, $level, false); - } catch (InceptionNotSuccessfulException $e) { + $inceptionResult = CommandHelper::begin( + $input, + $output, + [], + $memoryLimit, + $autoloadFile, + $this->composerAutoloaderProjectPaths, + $configuration, + null, + $level, + false, + ); + } catch (InceptionNotSuccessfulException) { return 1; } diff --git a/src/Command/ErrorFormatter/BaselineNeonErrorFormatter.php b/src/Command/ErrorFormatter/BaselineNeonErrorFormatter.php index 309db28b0c2..545eeed111c 100644 --- a/src/Command/ErrorFormatter/BaselineNeonErrorFormatter.php +++ b/src/Command/ErrorFormatter/BaselineNeonErrorFormatter.php @@ -17,58 +17,61 @@ class BaselineNeonErrorFormatter { - /** - * @var RelativePathHelper - */ - private $relativePathHelper; - public function __construct(RelativePathHelper $relativePathHelper) - { - $this->relativePathHelper = $relativePathHelper; + public function __construct(private RelativePathHelper $relativePathHelper) + { + } + + public function formatErrors( + AnalysisResult $analysisResult, + Output $output, + string $existingBaselineContent, + ): int + { + if (!$analysisResult->hasErrors()) { + $output->writeRaw($this->getNeon([], $existingBaselineContent)); + return 0; + } + + $fileErrors = []; + foreach ($analysisResult->getFileSpecificErrors() as $fileSpecificError) { + if (!$fileSpecificError->canBeIgnored()) { + continue; + } + $fileErrors[$this->relativePathHelper->getRelativePath($fileSpecificError->getFilePath())][] = $fileSpecificError->getMessage(); } + ksort($fileErrors, SORT_STRING); + + $errorsToOutput = []; + foreach ($fileErrors as $file => $errorMessages) { + $fileErrorsCounts = []; + foreach ($errorMessages as $errorMessage) { + if (!isset($fileErrorsCounts[$errorMessage])) { + $fileErrorsCounts[$errorMessage] = 1; + continue; + } + + $fileErrorsCounts[$errorMessage]++; + } + ksort($fileErrorsCounts, SORT_STRING); - public function formatErrors(AnalysisResult $analysisResult, Output $output, string $existingBaselineContent) : int - { - if (!$analysisResult->hasErrors()) { - $output->writeRaw($this->getNeon([], $existingBaselineContent)); - return 0; - } - $fileErrors = []; - foreach ($analysisResult->getFileSpecificErrors() as $fileSpecificError) { - if (!$fileSpecificError->canBeIgnored()) { - continue; - } - $fileErrors[$this->relativePathHelper->getRelativePath($fileSpecificError->getFilePath())][] = $fileSpecificError->getMessage(); - } - ksort($fileErrors, SORT_STRING); - $errorsToOutput = []; - foreach ($fileErrors as $file => $errorMessages) { - $fileErrorsCounts = []; - foreach ($errorMessages as $errorMessage) { - if (!isset($fileErrorsCounts[$errorMessage])) { - $fileErrorsCounts[$errorMessage] = 1; - continue; - } - - $fileErrorsCounts[$errorMessage]++; - } - ksort($fileErrorsCounts, SORT_STRING); - - foreach ($fileErrorsCounts as $message => $count) { - $errorsToOutput[] = [ - 'message' => Helpers::escape('#^' . preg_quote($message, '#') . '$#'), - 'count' => $count, - 'path' => Helpers::escape($file), - ]; - } - } - $output->writeRaw($this->getNeon($errorsToOutput, $existingBaselineContent)); - return 1; + foreach ($fileErrorsCounts as $message => $count) { + $errorsToOutput[] = [ + 'message' => Helpers::escape('#^' . preg_quote($message, '#') . '$#'), + 'count' => $count, + 'path' => Helpers::escape($file), + ]; + } } + $output->writeRaw($this->getNeon($errorsToOutput, $existingBaselineContent)); + + return 1; + } + /** - * @param array $ignoreErrors - */ - private function getNeon(array $ignoreErrors, string $existingBaselineContent): string + * @param array $ignoreErrors + */ + private function getNeon(array $ignoreErrors, string $existingBaselineContent): string { $neon = Neon::encode([ 'parameters' => [ diff --git a/src/Command/ErrorFormatter/BaselinePhpErrorFormatter.php b/src/Command/ErrorFormatter/BaselinePhpErrorFormatter.php index b4adbab90ec..0af50dba479 100644 --- a/src/Command/ErrorFormatter/BaselinePhpErrorFormatter.php +++ b/src/Command/ErrorFormatter/BaselinePhpErrorFormatter.php @@ -19,78 +19,87 @@ class BaselinePhpErrorFormatter { - /** - * @var RelativePathHelper - */ - private $relativePathHelper; - public function __construct(RelativePathHelper $relativePathHelper) - { - $this->relativePathHelper = $relativePathHelper; + public function __construct(private RelativePathHelper $relativePathHelper) + { + } + + public function formatErrors( + AnalysisResult $analysisResult, + Output $output, + ): int + { + if (!$analysisResult->hasErrors()) { + $php = 'writeRaw($php); + return 0; + } + + $fileErrors = []; + foreach ($analysisResult->getFileSpecificErrors() as $fileSpecificError) { + if (!$fileSpecificError->canBeIgnored()) { + continue; + } + $fileErrors['/' . $this->relativePathHelper->getRelativePath($fileSpecificError->getFilePath())][] = $fileSpecificError; } + ksort($fileErrors, SORT_STRING); + + $php = ' $errors) { + $fileErrorsByMessage = []; + foreach ($errors as $error) { + $errorMessage = $error->getMessage(); + if (!isset($fileErrorsByMessage[$errorMessage])) { + $fileErrorsByMessage[$errorMessage] = [ + 1, + $error->getIdentifier() !== null ? [$error->getIdentifier() => true] : [], + ]; + continue; + } + + $fileErrorsByMessage[$errorMessage][0]++; - public function formatErrors(AnalysisResult $analysisResult, Output $output) : int - { - if (!$analysisResult->hasErrors()) { - $php = 'writeRaw($php); - return 0; - } - $fileErrors = []; - foreach ($analysisResult->getFileSpecificErrors() as $fileSpecificError) { - if (!$fileSpecificError->canBeIgnored()) { - continue; - } - $fileErrors['/' . $this->relativePathHelper->getRelativePath($fileSpecificError->getFilePath())][] = $fileSpecificError; - } - ksort($fileErrors, SORT_STRING); - $php = ' $errors) { - $fileErrorsByMessage = []; - foreach ($errors as $error) { - $errorMessage = $error->getMessage(); - if (!isset($fileErrorsByMessage[$errorMessage])) { - $fileErrorsByMessage[$errorMessage] = [ - 1, - $error->getIdentifier() !== null ? [$error->getIdentifier() => true] : [], - ]; - continue; - } - - $fileErrorsByMessage[$errorMessage][0]++; - - if ($error->getIdentifier() === null) { - continue; - } - $fileErrorsByMessage[$errorMessage][1][$error->getIdentifier()] = true; - } - ksort($fileErrorsByMessage, SORT_STRING); - - foreach ($fileErrorsByMessage as $message => [$count, $identifiersInKeys]) { - $identifiers = array_keys($identifiersInKeys); - sort($identifiers); - $identifiersComment = ''; - if (count($identifiers) > 0) { - if (count($identifiers) === 1) { - $identifiersComment = "\n\t// identifier: " . $identifiers[0]; - } else { - $identifiersComment = "\n\t// identifiers: " . implode(', ', $identifiers); - } - } - - $php .= sprintf("\$ignoreErrors[] = [%s\n\t'message' => %s,\n\t'count' => %d,\n\t'path' => __DIR__ . %s,\n];\n", $identifiersComment, var_export(Helpers::escape('#^' . preg_quote($message, '#') . '$#'), true), var_export($count, true), var_export(Helpers::escape($file), true)); - } - } - $php .= "\n"; - $php .= 'return [\'parameters\' => [\'ignoreErrors\' => $ignoreErrors]];'; - $php .= "\n"; - $output->writeRaw($php); - return 1; + if ($error->getIdentifier() === null) { + continue; + } + $fileErrorsByMessage[$errorMessage][1][$error->getIdentifier()] = true; + } + ksort($fileErrorsByMessage, SORT_STRING); + + foreach ($fileErrorsByMessage as $message => [$count, $identifiersInKeys]) { + $identifiers = array_keys($identifiersInKeys); + sort($identifiers); + $identifiersComment = ''; + if (count($identifiers) > 0) { + if (count($identifiers) === 1) { + $identifiersComment = "\n\t// identifier: " . $identifiers[0]; + } else { + $identifiersComment = "\n\t// identifiers: " . implode(', ', $identifiers); + } + } + + $php .= sprintf( + "\$ignoreErrors[] = [%s\n\t'message' => %s,\n\t'count' => %d,\n\t'path' => __DIR__ . %s,\n];\n", + $identifiersComment, + var_export(Helpers::escape('#^' . preg_quote($message, '#') . '$#'), true), + var_export($count, true), + var_export(Helpers::escape($file), true), + ); + } } + $php .= "\n"; + $php .= 'return [\'parameters\' => [\'ignoreErrors\' => $ignoreErrors]];'; + $php .= "\n"; + + $output->writeRaw($php); + + return 1; + } + } diff --git a/src/Command/ErrorFormatter/CheckstyleErrorFormatter.php b/src/Command/ErrorFormatter/CheckstyleErrorFormatter.php index c4878711c65..cfb2ddc5593 100644 --- a/src/Command/ErrorFormatter/CheckstyleErrorFormatter.php +++ b/src/Command/ErrorFormatter/CheckstyleErrorFormatter.php @@ -15,78 +15,90 @@ class CheckstyleErrorFormatter implements ErrorFormatter { - /** - * @var RelativePathHelper - */ - private $relativePathHelper; - public function __construct(RelativePathHelper $relativePathHelper) - { - $this->relativePathHelper = $relativePathHelper; + public function __construct(private RelativePathHelper $relativePathHelper) + { + } + + public function formatErrors( + AnalysisResult $analysisResult, + Output $output, + ): int + { + $output->writeRaw(''); + $output->writeLineFormatted(''); + $output->writeRaw(''); + $output->writeLineFormatted(''); + + foreach ($this->groupByFile($analysisResult) as $relativeFilePath => $errors) { + $output->writeRaw(sprintf( + '', + $this->escape($relativeFilePath), + )); + $output->writeLineFormatted(''); + + foreach ($errors as $error) { + $output->writeRaw(sprintf( + ' ', + $this->escape((string) $error->getLine()), + $this->escape($error->getMessage()), + $error->getIdentifier() !== null ? sprintf(' source="%s"', $this->escape($error->getIdentifier())) : '', + )); + $output->writeLineFormatted(''); + } + $output->writeRaw(''); + $output->writeLineFormatted(''); + } + + $notFileSpecificErrors = $analysisResult->getNotFileSpecificErrors(); + + if (count($notFileSpecificErrors) > 0) { + $output->writeRaw(''); + $output->writeLineFormatted(''); + + foreach ($notFileSpecificErrors as $error) { + $output->writeRaw(sprintf(' ', $this->escape($error))); + $output->writeLineFormatted(''); + } + + $output->writeRaw(''); + $output->writeLineFormatted(''); } - public function formatErrors(AnalysisResult $analysisResult, Output $output) : int - { - $output->writeRaw(''); - $output->writeLineFormatted(''); - $output->writeRaw(''); - $output->writeLineFormatted(''); - foreach ($this->groupByFile($analysisResult) as $relativeFilePath => $errors) { - $output->writeRaw(sprintf('', $this->escape($relativeFilePath))); - $output->writeLineFormatted(''); - - foreach ($errors as $error) { - $output->writeRaw(sprintf(' ', $this->escape((string) $error->getLine()), $this->escape($error->getMessage()), $error->getIdentifier() !== null ? sprintf(' source="%s"', $this->escape($error->getIdentifier())) : '')); - $output->writeLineFormatted(''); - } - $output->writeRaw(''); - $output->writeLineFormatted(''); - } - $notFileSpecificErrors = $analysisResult->getNotFileSpecificErrors(); - if (count($notFileSpecificErrors) > 0) { - $output->writeRaw(''); - $output->writeLineFormatted(''); - - foreach ($notFileSpecificErrors as $error) { - $output->writeRaw(sprintf(' ', $this->escape($error))); - $output->writeLineFormatted(''); - } - - $output->writeRaw(''); - $output->writeLineFormatted(''); - } - if ($analysisResult->hasWarnings()) { - $output->writeRaw(''); - $output->writeLineFormatted(''); - - foreach ($analysisResult->getWarnings() as $warning) { - $output->writeRaw(sprintf(' ', $this->escape($warning))); - $output->writeLineFormatted(''); - } - - $output->writeRaw(''); - $output->writeLineFormatted(''); - } - $output->writeRaw(''); - $output->writeLineFormatted(''); - return $analysisResult->hasErrors() ? 1 : 0; + if ($analysisResult->hasWarnings()) { + $output->writeRaw(''); + $output->writeLineFormatted(''); + + foreach ($analysisResult->getWarnings() as $warning) { + $output->writeRaw(sprintf(' ', $this->escape($warning))); + $output->writeLineFormatted(''); + } + + $output->writeRaw(''); + $output->writeLineFormatted(''); } + $output->writeRaw(''); + $output->writeLineFormatted(''); + + return $analysisResult->hasErrors() ? 1 : 0; + } + /** - * Escapes values for using in XML - * - */ - private function escape(string $string): string + * Escapes values for using in XML + * + */ + private function escape(string $string): string { return htmlspecialchars($string, ENT_XML1 | ENT_COMPAT, 'UTF-8'); } /** - * Group errors by file - * - * @return array> Array that have as key the relative path of file - * and as value an array with occurred errors. - */ - private function groupByFile(AnalysisResult $analysisResult): array + * Group errors by file + * + * @return array> Array that have as key the relative path of file + * and as value an array with occurred errors. + */ + private function groupByFile(AnalysisResult $analysisResult): array { $files = []; @@ -96,7 +108,9 @@ private function groupByFile(AnalysisResult $analysisResult): array if ($fileSpecificError->getTraitFilePath() !== null) { $absolutePath = $fileSpecificError->getTraitFilePath(); } - $relativeFilePath = $this->relativePathHelper->getRelativePath($absolutePath); + $relativeFilePath = $this->relativePathHelper->getRelativePath( + $absolutePath, + ); $files[$relativeFilePath][] = $fileSpecificError; } diff --git a/src/Command/ErrorFormatter/CiDetectedErrorFormatter.php b/src/Command/ErrorFormatter/CiDetectedErrorFormatter.php index 5858fc00eac..541dfd77e31 100644 --- a/src/Command/ErrorFormatter/CiDetectedErrorFormatter.php +++ b/src/Command/ErrorFormatter/CiDetectedErrorFormatter.php @@ -11,19 +11,13 @@ class CiDetectedErrorFormatter implements ErrorFormatter { - /** - * @var GithubErrorFormatter - */ - private $githubErrorFormatter; - /** - * @var TeamcityErrorFormatter - */ - private $teamcityErrorFormatter; - public function __construct(GithubErrorFormatter $githubErrorFormatter, TeamcityErrorFormatter $teamcityErrorFormatter) + public function __construct( + private GithubErrorFormatter $githubErrorFormatter, + private TeamcityErrorFormatter $teamcityErrorFormatter, + ) { - $this->githubErrorFormatter = $githubErrorFormatter; - $this->teamcityErrorFormatter = $teamcityErrorFormatter; } + public function formatErrors(AnalysisResult $analysisResult, Output $output): int { $ciDetector = new CiDetector(); @@ -35,7 +29,7 @@ public function formatErrors(AnalysisResult $analysisResult, Output $output): in } elseif ($ci->getCiName() === CiDetector::CI_TEAMCITY) { return $this->teamcityErrorFormatter->formatErrors($analysisResult, $output); } - } catch (CiNotDetectedException $e) { + } catch (CiNotDetectedException) { // pass } diff --git a/src/Command/ErrorFormatter/ErrorFormatter.php b/src/Command/ErrorFormatter/ErrorFormatter.php index 9f877a36d50..2d4e17ee311 100644 --- a/src/Command/ErrorFormatter/ErrorFormatter.php +++ b/src/Command/ErrorFormatter/ErrorFormatter.php @@ -27,6 +27,9 @@ interface ErrorFormatter * * @return int Error code. */ - public function formatErrors(AnalysisResult $analysisResult, Output $output) : int; + public function formatErrors( + AnalysisResult $analysisResult, + Output $output, + ): int; } diff --git a/src/Command/ErrorFormatter/GithubErrorFormatter.php b/src/Command/ErrorFormatter/GithubErrorFormatter.php index 898ddc1fc75..03dc1aa8d00 100644 --- a/src/Command/ErrorFormatter/GithubErrorFormatter.php +++ b/src/Command/ErrorFormatter/GithubErrorFormatter.php @@ -17,14 +17,12 @@ class GithubErrorFormatter implements ErrorFormatter { - /** - * @var RelativePathHelper - */ - private $relativePathHelper; - public function __construct(RelativePathHelper $relativePathHelper) + public function __construct( + private RelativePathHelper $relativePathHelper, + ) { - $this->relativePathHelper = $relativePathHelper; } + public function formatErrors(AnalysisResult $analysisResult, Output $output): int { foreach ($analysisResult->getFileSpecificErrors() as $fileSpecificError) { diff --git a/src/Command/ErrorFormatter/GitlabErrorFormatter.php b/src/Command/ErrorFormatter/GitlabErrorFormatter.php index 92cee8d5c03..6aa4b61befc 100644 --- a/src/Command/ErrorFormatter/GitlabErrorFormatter.php +++ b/src/Command/ErrorFormatter/GitlabErrorFormatter.php @@ -15,13 +15,8 @@ class GitlabErrorFormatter implements ErrorFormatter { - /** - * @var RelativePathHelper - */ - private $relativePathHelper; - public function __construct(RelativePathHelper $relativePathHelper) + public function __construct(private RelativePathHelper $relativePathHelper) { - $this->relativePathHelper = $relativePathHelper; } public function formatErrors(AnalysisResult $analysisResult, Output $output): int @@ -31,11 +26,16 @@ public function formatErrors(AnalysisResult $analysisResult, Output $output): in foreach ($analysisResult->getFileSpecificErrors() as $fileSpecificError) { $error = [ 'description' => $fileSpecificError->getMessage(), - 'fingerprint' => hash('sha256', implode([ + 'fingerprint' => hash( + 'sha256', + implode( + [ $fileSpecificError->getFile(), $fileSpecificError->getLine(), $fileSpecificError->getMessage(), - ])), + ], + ), + ), 'severity' => $fileSpecificError->canBeIgnored() ? 'major' : 'blocker', 'location' => [ 'path' => $this->relativePathHelper->getRelativePath($fileSpecificError->getFile()), diff --git a/src/Command/ErrorFormatter/JsonErrorFormatter.php b/src/Command/ErrorFormatter/JsonErrorFormatter.php index 78e309b08e6..9f9f1edcfbb 100644 --- a/src/Command/ErrorFormatter/JsonErrorFormatter.php +++ b/src/Command/ErrorFormatter/JsonErrorFormatter.php @@ -12,13 +12,8 @@ class JsonErrorFormatter implements ErrorFormatter { - /** - * @var bool - */ - private $pretty; - public function __construct(bool $pretty) + public function __construct(private bool $pretty) { - $this->pretty = $pretty; } public function formatErrors(AnalysisResult $analysisResult, Output $output): int diff --git a/src/Command/ErrorFormatter/JunitErrorFormatter.php b/src/Command/ErrorFormatter/JunitErrorFormatter.php index 3131a5713f7..6e684ad9424 100644 --- a/src/Command/ErrorFormatter/JunitErrorFormatter.php +++ b/src/Command/ErrorFormatter/JunitErrorFormatter.php @@ -13,45 +13,59 @@ class JunitErrorFormatter implements ErrorFormatter { - /** - * @var RelativePathHelper - */ - private $relativePathHelper; - public function __construct(RelativePathHelper $relativePathHelper) - { - $this->relativePathHelper = $relativePathHelper; + public function __construct(private RelativePathHelper $relativePathHelper) + { + } + + public function formatErrors( + AnalysisResult $analysisResult, + Output $output, + ): int + { + $totalFailuresCount = $analysisResult->getTotalErrorsCount(); + $totalTestsCount = $analysisResult->hasErrors() ? $totalFailuresCount : 1; + + $result = ''; + $result .= sprintf( + '', + $totalFailuresCount, + $totalTestsCount, + ); + + foreach ($analysisResult->getFileSpecificErrors() as $fileSpecificError) { + $fileName = $this->relativePathHelper->getRelativePath($fileSpecificError->getFile()); + $result .= $this->createTestCase( + sprintf('%s:%s', $fileName, (string) $fileSpecificError->getLine()), + 'ERROR', + $this->escape($fileSpecificError->getMessage()), + ); } - public function formatErrors(AnalysisResult $analysisResult, Output $output) : int - { - $totalFailuresCount = $analysisResult->getTotalErrorsCount(); - $totalTestsCount = $analysisResult->hasErrors() ? $totalFailuresCount : 1; - $result = ''; - $result .= sprintf('', $totalFailuresCount, $totalTestsCount); - foreach ($analysisResult->getFileSpecificErrors() as $fileSpecificError) { - $fileName = $this->relativePathHelper->getRelativePath($fileSpecificError->getFile()); - $result .= $this->createTestCase(sprintf('%s:%s', $fileName, (string) $fileSpecificError->getLine()), 'ERROR', $this->escape($fileSpecificError->getMessage())); - } - foreach ($analysisResult->getNotFileSpecificErrors() as $notFileSpecificError) { - $result .= $this->createTestCase('General error', 'ERROR', $this->escape($notFileSpecificError)); - } - foreach ($analysisResult->getWarnings() as $warning) { - $result .= $this->createTestCase('Warning', 'WARNING', $this->escape($warning)); - } - if (!$analysisResult->hasErrors()) { - $result .= $this->createTestCase('phpstan', ''); - } - $result .= ''; - $output->writeRaw($result); - return $analysisResult->hasErrors() ? 1 : 0; + foreach ($analysisResult->getNotFileSpecificErrors() as $notFileSpecificError) { + $result .= $this->createTestCase('General error', 'ERROR', $this->escape($notFileSpecificError)); } + foreach ($analysisResult->getWarnings() as $warning) { + $result .= $this->createTestCase('Warning', 'WARNING', $this->escape($warning)); + } + + if (!$analysisResult->hasErrors()) { + $result .= $this->createTestCase('phpstan', ''); + } + + $result .= ''; + + $output->writeRaw($result); + + return $analysisResult->hasErrors() ? 1 : 0; + } + /** - * Format a single test case - * - * - */ - private function createTestCase(string $reference, string $type, ?string $message = null): string + * Format a single test case + * + * + */ + private function createTestCase(string $reference, string $type, ?string $message = null): string { $result = sprintf('', $this->escape($reference)); @@ -65,10 +79,10 @@ private function createTestCase(string $reference, string $type, ?string $messag } /** - * Escapes values for using in XML - * - */ - private function escape(string $string): string + * Escapes values for using in XML + * + */ + private function escape(string $string): string { return htmlspecialchars($string, ENT_XML1 | ENT_COMPAT, 'UTF-8'); } diff --git a/src/Command/ErrorFormatter/RawErrorFormatter.php b/src/Command/ErrorFormatter/RawErrorFormatter.php index 42d082db7ec..4625983275d 100644 --- a/src/Command/ErrorFormatter/RawErrorFormatter.php +++ b/src/Command/ErrorFormatter/RawErrorFormatter.php @@ -9,20 +9,33 @@ class RawErrorFormatter implements ErrorFormatter { - public function formatErrors(AnalysisResult $analysisResult, Output $output) : int + public function formatErrors( + AnalysisResult $analysisResult, + Output $output, + ): int { foreach ($analysisResult->getNotFileSpecificErrors() as $notFileSpecificError) { $output->writeRaw(sprintf('?:?:%s', $notFileSpecificError)); $output->writeLineFormatted(''); } + foreach ($analysisResult->getFileSpecificErrors() as $fileSpecificError) { - $output->writeRaw(sprintf('%s:%d:%s', $fileSpecificError->getFile(), $fileSpecificError->getLine() ?? '?', $fileSpecificError->getMessage())); + $output->writeRaw( + sprintf( + '%s:%d:%s', + $fileSpecificError->getFile(), + $fileSpecificError->getLine() ?? '?', + $fileSpecificError->getMessage(), + ), + ); $output->writeLineFormatted(''); } + foreach ($analysisResult->getWarnings() as $warning) { $output->writeRaw(sprintf('?:?:%s', $warning)); $output->writeLineFormatted(''); } + return $analysisResult->hasErrors() ? 1 : 0; } diff --git a/src/Command/ErrorFormatter/TableErrorFormatter.php b/src/Command/ErrorFormatter/TableErrorFormatter.php index a2307a0ce35..16d10956d37 100644 --- a/src/Command/ErrorFormatter/TableErrorFormatter.php +++ b/src/Command/ErrorFormatter/TableErrorFormatter.php @@ -24,159 +24,158 @@ class TableErrorFormatter implements ErrorFormatter { - /** - * @var RelativePathHelper - */ - private $relativePathHelper; - /** - * @var SimpleRelativePathHelper - */ - private $simpleRelativePathHelper; - /** - * @var CiDetectedErrorFormatter - */ - private $ciDetectedErrorFormatter; - /** - * @var bool - */ - private $showTipsOfTheDay; - /** - * @var ?string - */ - private $editorUrl; - /** - * @var ?string - */ - private $editorUrlTitle; - public function __construct(RelativePathHelper $relativePathHelper, SimpleRelativePathHelper $simpleRelativePathHelper, CiDetectedErrorFormatter $ciDetectedErrorFormatter, bool $showTipsOfTheDay, ?string $editorUrl, ?string $editorUrlTitle) - { - $this->relativePathHelper = $relativePathHelper; - $this->simpleRelativePathHelper = $simpleRelativePathHelper; - $this->ciDetectedErrorFormatter = $ciDetectedErrorFormatter; - $this->showTipsOfTheDay = $showTipsOfTheDay; - $this->editorUrl = $editorUrl; - $this->editorUrlTitle = $editorUrlTitle; + public function __construct( + private RelativePathHelper $relativePathHelper, + private SimpleRelativePathHelper $simpleRelativePathHelper, + private CiDetectedErrorFormatter $ciDetectedErrorFormatter, + private bool $showTipsOfTheDay, + private ?string $editorUrl, + private ?string $editorUrlTitle, + ) + { + } + + /** @api */ + public function formatErrors( + AnalysisResult $analysisResult, + Output $output, + ): int + { + $this->ciDetectedErrorFormatter->formatErrors($analysisResult, $output); + $projectConfigFile = 'phpstan.neon'; + if ($analysisResult->getProjectConfigFile() !== null) { + $projectConfigFile = $this->relativePathHelper->getRelativePath($analysisResult->getProjectConfigFile()); + } + + $style = $output->getStyle(); + + if (!$analysisResult->hasErrors() && !$analysisResult->hasWarnings()) { + $style->success('No errors'); + + if ($this->showTipsOfTheDay) { + if ($analysisResult->isDefaultLevelUsed()) { + $output->writeLineFormatted('💡 Tip of the Day:'); + $output->writeLineFormatted(sprintf( + "PHPStan is performing only the most basic checks.\nYou can pass a higher rule level through the --%s option\n(the default and current level is %d) to analyse code more thoroughly.", + AnalyseCommand::OPTION_LEVEL, + AnalyseCommand::DEFAULT_LEVEL, + )); + $output->writeLineFormatted(''); + } + } + + return 0; + } + + /** @var array $fileErrors */ + $fileErrors = []; + $outputIdentifiers = $output->isVerbose(); + $outputIdentifiersInFile = []; + foreach ($analysisResult->getFileSpecificErrors() as $fileSpecificError) { + if (!isset($fileErrors[$fileSpecificError->getFile()])) { + $fileErrors[$fileSpecificError->getFile()] = []; + } + + $fileErrors[$fileSpecificError->getFile()][] = $fileSpecificError; + if ($outputIdentifiers) { + continue; + } + + $filePath = $fileSpecificError->getTraitFilePath() ?? $fileSpecificError->getFilePath(); + if (array_key_exists($filePath, $outputIdentifiersInFile)) { + continue; + } + + if ($fileSpecificError->getIdentifier() === null) { + continue; + } + + if (!in_array($fileSpecificError->getIdentifier(), [ + 'ignore.unmatchedIdentifier', + 'ignore.parseError', + 'ignore.unmatched', + ], true)) { + continue; + } + + $outputIdentifiersInFile[$filePath] = true; } - /** @api */ - public function formatErrors(AnalysisResult $analysisResult, Output $output) : int - { - $this->ciDetectedErrorFormatter->formatErrors($analysisResult, $output); - $projectConfigFile = 'phpstan.neon'; - if ($analysisResult->getProjectConfigFile() !== null) { - $projectConfigFile = $this->relativePathHelper->getRelativePath($analysisResult->getProjectConfigFile()); - } - $style = $output->getStyle(); - if (!$analysisResult->hasErrors() && !$analysisResult->hasWarnings()) { - $style->success('No errors'); - - if ($this->showTipsOfTheDay) { - if ($analysisResult->isDefaultLevelUsed()) { - $output->writeLineFormatted('💡 Tip of the Day:'); - $output->writeLineFormatted(sprintf("PHPStan is performing only the most basic checks.\nYou can pass a higher rule level through the --%s option\n(the default and current level is %d) to analyse code more thoroughly.", AnalyseCommand::OPTION_LEVEL, AnalyseCommand::DEFAULT_LEVEL)); - $output->writeLineFormatted(''); - } - } - - return 0; - } - /** @var array $fileErrors */ - $fileErrors = []; - $outputIdentifiers = $output->isVerbose(); - $outputIdentifiersInFile = []; - foreach ($analysisResult->getFileSpecificErrors() as $fileSpecificError) { - if (!isset($fileErrors[$fileSpecificError->getFile()])) { - $fileErrors[$fileSpecificError->getFile()] = []; - } - - $fileErrors[$fileSpecificError->getFile()][] = $fileSpecificError; - if ($outputIdentifiers) { - continue; - } - - $filePath = $fileSpecificError->getTraitFilePath() ?? $fileSpecificError->getFilePath(); - if (array_key_exists($filePath, $outputIdentifiersInFile)) { - continue; - } - - if ($fileSpecificError->getIdentifier() === null) { - continue; - } - - if (!in_array($fileSpecificError->getIdentifier(), [ - 'ignore.unmatchedIdentifier', - 'ignore.parseError', - 'ignore.unmatched', - ], true)) { - continue; - } - - $outputIdentifiersInFile[$filePath] = true; - } - foreach ($fileErrors as $file => $errors) { - $rows = []; - foreach ($errors as $error) { - $message = $error->getMessage(); - $filePath = $error->getTraitFilePath() ?? $error->getFilePath(); - if (($outputIdentifiers || array_key_exists($filePath, $outputIdentifiersInFile)) && $error->getIdentifier() !== null && $error->canBeIgnored()) { - $message .= "\n"; - $message .= '🪪 ' . $error->getIdentifier(); - } - if ($error->getTip() !== null) { - $tip = $error->getTip(); - $tip = str_replace('%configurationFile%', $projectConfigFile, $tip); - - $message .= "\n"; - if (str_contains($tip, "\n")) { - $lines = explode("\n", $tip); - foreach ($lines as $line) { - $message .= '💡 ' . ltrim($line, ' •') . "\n"; - } - } else { - $message .= '💡 ' . $tip; - } - } - if (is_string($this->editorUrl)) { - $url = str_replace(['%file%', '%relFile%', '%line%'], [$filePath, $this->simpleRelativePathHelper->getRelativePath($filePath), (string) $error->getLine()], $this->editorUrl); - - if (is_string($this->editorUrlTitle)) { - $title = str_replace(['%file%', '%relFile%', '%line%'], [$filePath, $this->simpleRelativePathHelper->getRelativePath($filePath), (string) $error->getLine()], $this->editorUrlTitle); - } else { - $title = $this->relativePathHelper->getRelativePath($filePath); - } - - $message .= "\n✏️ ' . $title . ''; - } - $rows[] = [ - $this->formatLineNumber($error->getLine()), - $message, - ]; - } - - $style->table(['Line', $this->relativePathHelper->getRelativePath($file)], $rows); - } - if (count($analysisResult->getNotFileSpecificErrors()) > 0) { - $style->table(['', 'Error'], array_map(static function (string $error) : array { - return ['', $error]; - }, $analysisResult->getNotFileSpecificErrors())); - } - $warningsCount = count($analysisResult->getWarnings()); - if ($warningsCount > 0) { - $style->table(['', 'Warning'], array_map(static function (string $warning) : array { - return ['', $warning]; - }, $analysisResult->getWarnings())); - } - $finalMessage = sprintf($analysisResult->getTotalErrorsCount() === 1 ? 'Found %d error' : 'Found %d errors', $analysisResult->getTotalErrorsCount()); - if ($warningsCount > 0) { - $finalMessage .= sprintf($warningsCount === 1 ? ' and %d warning' : ' and %d warnings', $warningsCount); - } - if ($analysisResult->getTotalErrorsCount() > 0) { - $style->error($finalMessage); - } else { - $style->warning($finalMessage); - } - return $analysisResult->getTotalErrorsCount() > 0 ? 1 : 0; + + foreach ($fileErrors as $file => $errors) { + $rows = []; + foreach ($errors as $error) { + $message = $error->getMessage(); + $filePath = $error->getTraitFilePath() ?? $error->getFilePath(); + if (($outputIdentifiers || array_key_exists($filePath, $outputIdentifiersInFile)) && $error->getIdentifier() !== null && $error->canBeIgnored()) { + $message .= "\n"; + $message .= '🪪 ' . $error->getIdentifier(); + } + if ($error->getTip() !== null) { + $tip = $error->getTip(); + $tip = str_replace('%configurationFile%', $projectConfigFile, $tip); + + $message .= "\n"; + if (str_contains($tip, "\n")) { + $lines = explode("\n", $tip); + foreach ($lines as $line) { + $message .= '💡 ' . ltrim($line, ' •') . "\n"; + } + } else { + $message .= '💡 ' . $tip; + } + } + if (is_string($this->editorUrl)) { + $url = str_replace( + ['%file%', '%relFile%', '%line%'], + [$filePath, $this->simpleRelativePathHelper->getRelativePath($filePath), (string) $error->getLine()], + $this->editorUrl, + ); + + if (is_string($this->editorUrlTitle)) { + $title = str_replace( + ['%file%', '%relFile%', '%line%'], + [$filePath, $this->simpleRelativePathHelper->getRelativePath($filePath), (string) $error->getLine()], + $this->editorUrlTitle, + ); + } else { + $title = $this->relativePathHelper->getRelativePath($filePath); + } + + $message .= "\n✏️ ' . $title . ''; + } + $rows[] = [ + $this->formatLineNumber($error->getLine()), + $message, + ]; + } + + $style->table(['Line', $this->relativePathHelper->getRelativePath($file)], $rows); + } + + if (count($analysisResult->getNotFileSpecificErrors()) > 0) { + $style->table(['', 'Error'], array_map(static fn (string $error): array => ['', $error], $analysisResult->getNotFileSpecificErrors())); + } + + $warningsCount = count($analysisResult->getWarnings()); + if ($warningsCount > 0) { + $style->table(['', 'Warning'], array_map(static fn (string $warning): array => ['', $warning], $analysisResult->getWarnings())); + } + + $finalMessage = sprintf($analysisResult->getTotalErrorsCount() === 1 ? 'Found %d error' : 'Found %d errors', $analysisResult->getTotalErrorsCount()); + if ($warningsCount > 0) { + $finalMessage .= sprintf($warningsCount === 1 ? ' and %d warning' : ' and %d warnings', $warningsCount); + } + + if ($analysisResult->getTotalErrorsCount() > 0) { + $style->error($finalMessage); + } else { + $style->warning($finalMessage); } - private function formatLineNumber(?int $lineNumber): string + + return $analysisResult->getTotalErrorsCount() > 0 ? 1 : 0; + } + + private function formatLineNumber(?int $lineNumber): string { if ($lineNumber === null) { return ''; diff --git a/src/Command/ErrorFormatter/TeamcityErrorFormatter.php b/src/Command/ErrorFormatter/TeamcityErrorFormatter.php index 63ff6b54b30..a6e6e2cf32b 100644 --- a/src/Command/ErrorFormatter/TeamcityErrorFormatter.php +++ b/src/Command/ErrorFormatter/TeamcityErrorFormatter.php @@ -18,13 +18,8 @@ class TeamcityErrorFormatter implements ErrorFormatter { - /** - * @var RelativePathHelper - */ - private $relativePathHelper; - public function __construct(RelativePathHelper $relativePathHelper) + public function __construct(private RelativePathHelper $relativePathHelper) { - $this->relativePathHelper = $relativePathHelper; } public function formatErrors(AnalysisResult $analysisResult, Output $output): int diff --git a/src/Command/ErrorsConsoleStyle.php b/src/Command/ErrorsConsoleStyle.php index aef749e4ec7..520ce7add31 100644 --- a/src/Command/ErrorsConsoleStyle.php +++ b/src/Command/ErrorsConsoleStyle.php @@ -23,20 +23,11 @@ class ErrorsConsoleStyle extends SymfonyStyle public const OPTION_NO_PROGRESS = 'no-progress'; - /** - * @var bool - */ - private $showProgress; + private bool $showProgress; - /** - * @var ProgressBar - */ - private $progressBar; + private ProgressBar $progressBar; - /** - * @var ?bool - */ - private $isCiDetected = null; + private ?bool $isCiDetected = null; public function __construct(InputInterface $input, OutputInterface $output) { @@ -110,7 +101,10 @@ private function wrap(array $rows, int $terminalWidth, int $maxHeaderWidth): arr if (str_starts_with($columnRow, '✏️')) { continue; } - $wrapped = wordwrap($columnRow, $terminalWidth - $maxHeaderWidth - 5); + $wrapped = wordwrap( + $columnRow, + $terminalWidth - $maxHeaderWidth - 5, + ); if (str_starts_with($columnRow, '💡 ')) { $wrappedLines = explode("\n", $wrapped); $newWrappedLines = []; diff --git a/src/Command/FixerApplication.php b/src/Command/FixerApplication.php index 740d49511c8..c3be97c7eda 100644 --- a/src/Command/FixerApplication.php +++ b/src/Command/FixerApplication.php @@ -64,148 +64,140 @@ class FixerApplication { - /** - * @var FileMonitor - */ - private $fileMonitor; - /** - * @var IgnoredErrorHelper - */ - private $ignoredErrorHelper; - /** - * @var StubFilesProvider - */ - private $stubFilesProvider; - /** - * @var string[] - */ - private $analysedPaths; - /** - * @var string - */ - private $currentWorkingDirectory; - /** - * @var string - */ - private $proTmpDir; - /** - * @var list - */ - private $dnsServers; - /** - * @var string[] - */ - private $composerAutoloaderProjectPaths; - /** - * @var string[] - */ - private $allConfigFiles; - /** - * @var ?string - */ - private $cliAutoloadFile; - /** - * @var string[] - */ - private $bootstrapFiles; - /** @var (ExtendedPromiseInterface&CancellablePromiseInterface)|null */ + /** @var (ExtendedPromiseInterface&CancellablePromiseInterface)|null */ private $processInProgress; /** - * @param string[] $analysedPaths - * @param list $dnsServers - * @param string[] $composerAutoloaderProjectPaths - * @param string[] $allConfigFiles - * @param string[] $bootstrapFiles - */ - public function __construct(FileMonitor $fileMonitor, IgnoredErrorHelper $ignoredErrorHelper, StubFilesProvider $stubFilesProvider, array $analysedPaths, string $currentWorkingDirectory, string $proTmpDir, array $dnsServers, array $composerAutoloaderProjectPaths, array $allConfigFiles, ?string $cliAutoloadFile, array $bootstrapFiles) - { - $this->fileMonitor = $fileMonitor; - $this->ignoredErrorHelper = $ignoredErrorHelper; - $this->stubFilesProvider = $stubFilesProvider; - $this->analysedPaths = $analysedPaths; - $this->currentWorkingDirectory = $currentWorkingDirectory; - $this->proTmpDir = $proTmpDir; - $this->dnsServers = $dnsServers; - $this->composerAutoloaderProjectPaths = $composerAutoloaderProjectPaths; - $this->allConfigFiles = $allConfigFiles; - $this->cliAutoloadFile = $cliAutoloadFile; - $this->bootstrapFiles = $bootstrapFiles; - } + * @param string[] $analysedPaths + * @param list $dnsServers + * @param string[] $composerAutoloaderProjectPaths + * @param string[] $allConfigFiles + * @param string[] $bootstrapFiles + */ + public function __construct( + private FileMonitor $fileMonitor, + private IgnoredErrorHelper $ignoredErrorHelper, + private StubFilesProvider $stubFilesProvider, + private array $analysedPaths, + private string $currentWorkingDirectory, + private string $proTmpDir, + private array $dnsServers, + private array $composerAutoloaderProjectPaths, + private array $allConfigFiles, + private ?string $cliAutoloadFile, + private array $bootstrapFiles, + ) + { + } - public function run(?string $projectConfigFile, InputInterface $input, OutputInterface $output, int $filesCount, string $mainScript) : int - { - $loop = new StreamSelectLoop(); - $server = new TcpServer('127.0.0.1:0', $loop); - /** @var string $serverAddress */ - $serverAddress = $server->getAddress(); - /** @var int<0, 65535> $serverPort */ - $serverPort = parse_url($serverAddress, PHP_URL_PORT); - $server->on('connection', function (ConnectionInterface $connection) use ($loop, $projectConfigFile, $input, $output, $mainScript, $filesCount): void { - // phpcs:disable SlevomatCodingStandard.Namespaces.ReferenceUsedNamesOnly - $jsonInvalidUtf8Ignore = defined('JSON_INVALID_UTF8_IGNORE') ? JSON_INVALID_UTF8_IGNORE : 0; - // phpcs:enable - $decoder = new Decoder($connection, true, 512, $jsonInvalidUtf8Ignore, 128 * 1024 * 1024); - $encoder = new Encoder($connection, $jsonInvalidUtf8Ignore); - $encoder->write(['action' => 'initialData', 'data' => [ - 'currentWorkingDirectory' => $this->currentWorkingDirectory, - 'analysedPaths' => $this->analysedPaths, - 'projectConfigFile' => $projectConfigFile, - 'filesCount' => $filesCount, - 'phpstanVersion' => ComposerHelper::getPhpStanVersion(), - ]]); - $decoder->on('data', static function (array $data) use($output) : void { - if ($data['action'] === 'webPort') { - $output->writeln(sprintf('Open your web browser at: http://127.0.0.1:%d', $data['data']['port'])); - $output->writeln('Press [Ctrl-C] to quit.'); - return; - } - }); - - $this->fileMonitor->initialize(array_merge($this->analysedPaths, $this->getComposerLocks(), $this->getComposerInstalled(), $this->getExecutedFiles(), $this->getStubFiles(), $this->allConfigFiles)); - - $this->analyse($loop, $mainScript, $projectConfigFile, $input, $output, $encoder); - - $this->monitorFileChanges($loop, function (FileMonitorResult $changes) use ($loop, $mainScript, $projectConfigFile, $input, $encoder, $output): void { - if ($this->processInProgress !== null) { - $this->processInProgress->cancel(); - $this->processInProgress = null; - } - - if (count($changes->getChangedFiles()) > 0) { - $encoder->write(['action' => 'changedFiles', 'data' => [ - 'paths' => $changes->getChangedFiles(), - ]]); - } - - $this->analyse($loop, $mainScript, $projectConfigFile, $input, $output, $encoder); - }); - }); - try { - $fixerProcess = $this->getFixerProcess($output, $serverPort); - } catch (FixerProcessException $e) { - return 1; - } - $fixerProcess->start($loop); - $fixerProcess->on('exit', function ($exitCode) use ($output, $loop): void { - $loop->stop(); - if ($exitCode === null) { - return; - } - if ($exitCode === 0) { - return; - } - $output->writeln(sprintf('PHPStan Pro process exited with code %d.', $exitCode)); - @unlink($this->proTmpDir . '/phar-info.json'); - }); - $loop->run(); - return 0; + public function run( + ?string $projectConfigFile, + InputInterface $input, + OutputInterface $output, + int $filesCount, + string $mainScript, + ): int + { + $loop = new StreamSelectLoop(); + $server = new TcpServer('127.0.0.1:0', $loop); + /** @var string $serverAddress */ + $serverAddress = $server->getAddress(); + + /** @var int<0, 65535> $serverPort */ + $serverPort = parse_url($serverAddress, PHP_URL_PORT); + + $server->on('connection', function (ConnectionInterface $connection) use ($loop, $projectConfigFile, $input, $output, $mainScript, $filesCount): void { + // phpcs:disable SlevomatCodingStandard.Namespaces.ReferenceUsedNamesOnly + $jsonInvalidUtf8Ignore = defined('JSON_INVALID_UTF8_IGNORE') ? JSON_INVALID_UTF8_IGNORE : 0; + // phpcs:enable + $decoder = new Decoder($connection, true, 512, $jsonInvalidUtf8Ignore, 128 * 1024 * 1024); + $encoder = new Encoder($connection, $jsonInvalidUtf8Ignore); + $encoder->write(['action' => 'initialData', 'data' => [ + 'currentWorkingDirectory' => $this->currentWorkingDirectory, + 'analysedPaths' => $this->analysedPaths, + 'projectConfigFile' => $projectConfigFile, + 'filesCount' => $filesCount, + 'phpstanVersion' => ComposerHelper::getPhpStanVersion(), + ]]); + $decoder->on('data', static function (array $data) use ( + $output, + ): void { + if ($data['action'] === 'webPort') { + $output->writeln(sprintf('Open your web browser at: http://127.0.0.1:%d', $data['data']['port'])); + $output->writeln('Press [Ctrl-C] to quit.'); + return; + } + }); + + $this->fileMonitor->initialize(array_merge( + $this->analysedPaths, + $this->getComposerLocks(), + $this->getComposerInstalled(), + $this->getExecutedFiles(), + $this->getStubFiles(), + $this->allConfigFiles, + )); + + $this->analyse( + $loop, + $mainScript, + $projectConfigFile, + $input, + $output, + $encoder, + ); + + $this->monitorFileChanges($loop, function (FileMonitorResult $changes) use ($loop, $mainScript, $projectConfigFile, $input, $encoder, $output): void { + if ($this->processInProgress !== null) { + $this->processInProgress->cancel(); + $this->processInProgress = null; + } + + if (count($changes->getChangedFiles()) > 0) { + $encoder->write(['action' => 'changedFiles', 'data' => [ + 'paths' => $changes->getChangedFiles(), + ]]); + } + + $this->analyse( + $loop, + $mainScript, + $projectConfigFile, + $input, + $output, + $encoder, + ); + }); + }); + + try { + $fixerProcess = $this->getFixerProcess($output, $serverPort); + } catch (FixerProcessException) { + return 1; } + $fixerProcess->start($loop); + $fixerProcess->on('exit', function ($exitCode) use ($output, $loop): void { + $loop->stop(); + if ($exitCode === null) { + return; + } + if ($exitCode === 0) { + return; + } + $output->writeln(sprintf('PHPStan Pro process exited with code %d.', $exitCode)); + @unlink($this->proTmpDir . '/phar-info.json'); + }); + + $loop->run(); + + return 0; + } + /** - * @throws FixerProcessException - */ - private function getFixerProcess(OutputInterface $output, int $serverPort): Process + * @throws FixerProcessException + */ + private function getFixerProcess(OutputInterface $output, int $serverPort): Process { try { DirectoryCreator::ensureDirectoryExists($this->proTmpDir, 0777); @@ -232,7 +224,7 @@ private function getFixerProcess(OutputInterface $output, int $serverPort): Proc try { $phar = new Phar($pharPath); - } catch (Throwable $e) { + } catch (Throwable) { @unlink($pharPath); @unlink($infoPath); $output->writeln('PHPStan Pro PHAR signature is corrupted.'); @@ -285,79 +277,96 @@ private function getFixerProcess(OutputInterface $output, int $serverPort): Proc return new Process(sprintf('%s -d memory_limit=%s %s --port %d', escapeshellarg(PHP_BINARY), escapeshellarg(ini_get('memory_limit')), escapeshellarg($pharPath), $serverPort), null, $env, []); } - private function downloadPhar(OutputInterface $output, string $pharPath, string $infoPath) : void - { - $currentVersion = null; - $branch = 'main'; - if (is_file($pharPath) && is_file($infoPath)) { - /** @var array{version: string, date: string, branch?: string} $currentInfo */ - $currentInfo = Json::decode(FileReader::read($infoPath), Json::FORCE_ARRAY); - $currentVersion = $currentInfo['version']; - $currentBranch = $currentInfo['branch'] ?? 'master'; - $currentDate = DateTime::createFromFormat(DateTime::ATOM, $currentInfo['date']); - if ($currentDate === false) { - throw new ShouldNotHappenException(); - } - if ( - $currentBranch === $branch - && (new DateTimeImmutable('', new DateTimeZone('UTC'))) <= $currentDate->modify('+24 hours') - ) { - return; - } - - $output->writeln('Checking if there\'s a new PHPStan Pro release...'); - } - $dnsConfig = new Config(); - $dnsConfig->nameservers = $this->dnsServers; - $client = new Browser(new Connector([ + private function downloadPhar( + OutputInterface $output, + string $pharPath, + string $infoPath, + ): void + { + $currentVersion = null; + $branch = 'main'; + if (is_file($pharPath) && is_file($infoPath)) { + /** @var array{version: string, date: string, branch?: string} $currentInfo */ + $currentInfo = Json::decode(FileReader::read($infoPath), Json::FORCE_ARRAY); + $currentVersion = $currentInfo['version']; + $currentBranch = $currentInfo['branch'] ?? 'master'; + $currentDate = DateTime::createFromFormat(DateTime::ATOM, $currentInfo['date']); + if ($currentDate === false) { + throw new ShouldNotHappenException(); + } + if ( + $currentBranch === $branch + && (new DateTimeImmutable('', new DateTimeZone('UTC'))) <= $currentDate->modify('+24 hours') + ) { + return; + } + + $output->writeln('Checking if there\'s a new PHPStan Pro release...'); + } + + $dnsConfig = new Config(); + $dnsConfig->nameservers = $this->dnsServers; + + $client = new Browser( + new Connector( + [ 'timeout' => 5, 'tls' => [ 'cafile' => CaBundle::getBundledCaBundlePath(), ], 'dns' => $dnsConfig, - ])); - /** - * @var array{url: string, version: string} $latestInfo - */ - $latestInfo = Json::decode((string) await($client->get(sprintf('https://fixer-download-api.phpstan.com/latest?%s', http_build_query(['phpVersion' => PHP_VERSION_ID, 'branch' => $branch]))))->getBody(), Json::FORCE_ARRAY); - if ($currentVersion !== null && $latestInfo['version'] === $currentVersion) { - $this->writeInfoFile($infoPath, $latestInfo['version'], $branch); - $output->writeln('You\'re running the latest PHPStan Pro!'); - return; - } - $output->writeln('Downloading the latest PHPStan Pro...'); - $pharPathResource = fopen($pharPath, 'w'); - if ($pharPathResource === false) { - throw new ShouldNotHappenException(sprintf('Could not open file %s for writing.', $pharPath)); - } - $progressBar = new ProgressBar($output); - $client->requestStreaming('GET', $latestInfo['url'])->done(static function (ResponseInterface $response) use ($progressBar, $pharPathResource): void { - $body = $response->getBody(); - if (!$body instanceof ReadableStreamInterface) { - throw new ShouldNotHappenException(); - } - - $totalSize = (int) $response->getHeaderLine('Content-Length'); - $progressBar->setFormat('file_download'); - $progressBar->setMessage(sprintf('%.2f MB', $totalSize / 1000000), 'fileSize'); - $progressBar->start($totalSize); - - $bytes = 0; - $body->on('data', static function ($chunk) use ($pharPathResource, $progressBar, &$bytes): void { - $bytes += strlen($chunk); - fwrite($pharPathResource, $chunk); - $progressBar->setProgress($bytes); - }); - }, function (Throwable $e) use ($output): void { - $this->printDownloadError($output, $e); - }); - Loop::run(); - fclose($pharPathResource); - $progressBar->finish(); - $output->writeln(''); - $output->writeln(''); - $this->writeInfoFile($infoPath, $latestInfo['version'], $branch); + ], + ), + ); + + /** + * @var array{url: string, version: string} $latestInfo + */ + $latestInfo = Json::decode((string) await($client->get(sprintf('https://fixer-download-api.phpstan.com/latest?%s', http_build_query(['phpVersion' => PHP_VERSION_ID, 'branch' => $branch]))))->getBody(), Json::FORCE_ARRAY); + if ($currentVersion !== null && $latestInfo['version'] === $currentVersion) { + $this->writeInfoFile($infoPath, $latestInfo['version'], $branch); + $output->writeln('You\'re running the latest PHPStan Pro!'); + return; + } + + $output->writeln('Downloading the latest PHPStan Pro...'); + + $pharPathResource = fopen($pharPath, 'w'); + if ($pharPathResource === false) { + throw new ShouldNotHappenException(sprintf('Could not open file %s for writing.', $pharPath)); } + $progressBar = new ProgressBar($output); + $client->requestStreaming('GET', $latestInfo['url'])->done(static function (ResponseInterface $response) use ($progressBar, $pharPathResource): void { + $body = $response->getBody(); + if (!$body instanceof ReadableStreamInterface) { + throw new ShouldNotHappenException(); + } + + $totalSize = (int) $response->getHeaderLine('Content-Length'); + $progressBar->setFormat('file_download'); + $progressBar->setMessage(sprintf('%.2f MB', $totalSize / 1000000), 'fileSize'); + $progressBar->start($totalSize); + + $bytes = 0; + $body->on('data', static function ($chunk) use ($pharPathResource, $progressBar, &$bytes): void { + $bytes += strlen($chunk); + fwrite($pharPathResource, $chunk); + $progressBar->setProgress($bytes); + }); + }, function (Throwable $e) use ($output): void { + $this->printDownloadError($output, $e); + }); + + Loop::run(); + + fclose($pharPathResource); + + $progressBar->finish(); + $output->writeln(''); + $output->writeln(''); + + $this->writeInfoFile($infoPath, $latestInfo['version'], $branch); + } private function printDownloadError(OutputInterface $output, Throwable $e): void { @@ -382,9 +391,9 @@ private function writeInfoFile(string $infoPath, string $version, string $branch } /** - * @param callable(FileMonitorResult): void $hasChangesCallback - */ - private function monitorFileChanges(LoopInterface $loop, callable $hasChangesCallback): void + * @param callable(FileMonitorResult): void $hasChangesCallback + */ + private function monitorFileChanges(LoopInterface $loop, callable $hasChangesCallback): void { $callback = function () use (&$callback, $loop, $hasChangesCallback): void { $changes = $this->fileMonitor->getChanges(); @@ -398,45 +407,62 @@ private function monitorFileChanges(LoopInterface $loop, callable $hasChangesCal $loop->addTimer(1.0, $callback); } - private function analyse(LoopInterface $loop, string $mainScript, ?string $projectConfigFile, InputInterface $input, OutputInterface $output, Encoder $phpstanFixerEncoder) : void - { - $ignoredErrorHelperResult = $this->ignoredErrorHelper->initialize(); - if (count($ignoredErrorHelperResult->getErrors()) > 0) { - throw new ShouldNotHappenException(); - } - // TCP server for fixer:worker (TCP client) - $server = new TcpServer('127.0.0.1:0', $loop); - /** @var string $serverAddress */ - $serverAddress = $server->getAddress(); - /** @var int<0, 65535> $serverPort */ - $serverPort = parse_url($serverAddress, PHP_URL_PORT); - $server->on('connection', static function (ConnectionInterface $connection) use ($phpstanFixerEncoder): void { - // phpcs:disable SlevomatCodingStandard.Namespaces.ReferenceUsedNamesOnly - $jsonInvalidUtf8Ignore = defined('JSON_INVALID_UTF8_IGNORE') ? JSON_INVALID_UTF8_IGNORE : 0; - // phpcs:enable - $decoder = new Decoder($connection, true, 512, $jsonInvalidUtf8Ignore, 128 * 1024 * 1024); - $decoder->on('data', static function (array $data) use ($phpstanFixerEncoder): void { - $phpstanFixerEncoder->write($data); - }); - }); - $process = new ProcessPromise($loop, 'changedFileAnalysis', ProcessHelper::getWorkerCommand($mainScript, 'fixer:worker', $projectConfigFile, [ + private function analyse( + LoopInterface $loop, + string $mainScript, + ?string $projectConfigFile, + InputInterface $input, + OutputInterface $output, + Encoder $phpstanFixerEncoder, + ): void + { + $ignoredErrorHelperResult = $this->ignoredErrorHelper->initialize(); + if (count($ignoredErrorHelperResult->getErrors()) > 0) { + throw new ShouldNotHappenException(); + } + + // TCP server for fixer:worker (TCP client) + $server = new TcpServer('127.0.0.1:0', $loop); + /** @var string $serverAddress */ + $serverAddress = $server->getAddress(); + /** @var int<0, 65535> $serverPort */ + $serverPort = parse_url($serverAddress, PHP_URL_PORT); + + $server->on('connection', static function (ConnectionInterface $connection) use ($phpstanFixerEncoder): void { + // phpcs:disable SlevomatCodingStandard.Namespaces.ReferenceUsedNamesOnly + $jsonInvalidUtf8Ignore = defined('JSON_INVALID_UTF8_IGNORE') ? JSON_INVALID_UTF8_IGNORE : 0; + // phpcs:enable + $decoder = new Decoder($connection, true, 512, $jsonInvalidUtf8Ignore, 128 * 1024 * 1024); + $decoder->on('data', static function (array $data) use ($phpstanFixerEncoder): void { + $phpstanFixerEncoder->write($data); + }); + }); + + $process = new ProcessPromise($loop, 'changedFileAnalysis', ProcessHelper::getWorkerCommand( + $mainScript, + 'fixer:worker', + $projectConfigFile, + [ '--server-port', (string) $serverPort, - ], $input)); - $this->processInProgress = $process->run(); - $this->processInProgress->done(function () use ($server): void { - $this->processInProgress = null; - $server->close(); - }, function (Throwable $e) use ($server, $output, $phpstanFixerEncoder): void { - $this->processInProgress = null; - $server->close(); - $output->writeln('Worker process exited: ' . $e->getMessage() . ''); - $phpstanFixerEncoder->write(['action' => 'analysisCrash', 'data' => [ - 'errors' => [$e->getMessage()], - ]]); - throw $e; - }); - } + ], + $input, + )); + $this->processInProgress = $process->run(); + + $this->processInProgress->done(function () use ($server): void { + $this->processInProgress = null; + $server->close(); + }, function (Throwable $e) use ($server, $output, $phpstanFixerEncoder): void { + $this->processInProgress = null; + $server->close(); + $output->writeln('Worker process exited: ' . $e->getMessage() . ''); + $phpstanFixerEncoder->write(['action' => 'analysisCrash', 'data' => [ + 'errors' => [$e->getMessage()], + ]]); + throw $e; + }); + } private function isDockerRunning(): bool { @@ -444,9 +470,9 @@ private function isDockerRunning(): bool } /** - * @return list - */ - private function getComposerLocks(): array + * @return list + */ + private function getComposerLocks(): array { $locks = []; foreach ($this->composerAutoloaderProjectPaths as $autoloadPath) { @@ -462,9 +488,9 @@ private function getComposerLocks(): array } /** - * @return list - */ - private function getComposerInstalled(): array + * @return list + */ + private function getComposerInstalled(): array { $files = []; foreach ($this->composerAutoloaderProjectPaths as $autoloadPath) { @@ -485,9 +511,9 @@ private function getComposerInstalled(): array } /** - * @return list - */ - private function getExecutedFiles(): array + * @return list + */ + private function getExecutedFiles(): array { $files = []; if ($this->cliAutoloadFile !== null) { @@ -502,9 +528,9 @@ private function getExecutedFiles(): array } /** - * @return list - */ - private function getStubFiles(): array + * @return list + */ + private function getStubFiles(): array { $stubFiles = []; foreach ($this->stubFilesProvider->getProjectStubFiles() as $stubFile) { diff --git a/src/Command/FixerWorkerCommand.php b/src/Command/FixerWorkerCommand.php index 1ddb28d0094..5dfd361c58e 100644 --- a/src/Command/FixerWorkerCommand.php +++ b/src/Command/FixerWorkerCommand.php @@ -52,18 +52,15 @@ class FixerWorkerCommand extends Command { - /** - * @var string[] - */ - private $composerAutoloaderProjectPaths; private const NAME = 'fixer:worker'; /** * @param string[] $composerAutoloaderProjectPaths */ - public function __construct(array $composerAutoloaderProjectPaths) + public function __construct( + private array $composerAutoloaderProjectPaths, + ) { - $this->composerAutoloaderProjectPaths = $composerAutoloaderProjectPaths; parent::__construct(); } @@ -106,8 +103,21 @@ protected function execute(InputInterface $input, OutputInterface $output): int } try { - $inceptionResult = CommandHelper::begin($input, $output, $paths, $memoryLimit, $autoloadFile, $this->composerAutoloaderProjectPaths, $configuration, null, $level, $allowXdebug, false, false); - } catch (InceptionNotSuccessfulException $e) { + $inceptionResult = CommandHelper::begin( + $input, + $output, + $paths, + $memoryLimit, + $autoloadFile, + $this->composerAutoloaderProjectPaths, + $configuration, + null, + $level, + $allowXdebug, + false, + false, + ); + } catch (InceptionNotSuccessfulException) { return 1; } @@ -135,7 +145,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int try { [$inceptionFiles, $isOnlyFiles] = $inceptionResult->getFiles(); - } catch (PathNotFoundException | InceptionNotSuccessfulException $e) { + } catch (PathNotFoundException | InceptionNotSuccessfulException) { throw new ShouldNotHappenException(); } @@ -197,7 +207,13 @@ protected function execute(InputInterface $input, OutputInterface $output): int return $aTime <=> $bTime; }); - $this->runAnalyser($loop, $container, $filesToAnalyse, $configuration, $input, function (array $errors, array $locallyIgnoredErrors, array $analysedFiles) use ($out, $ignoredErrorHelperResult, $isOnlyFiles, $inceptionFiles): void { + $this->runAnalyser( + $loop, + $container, + $filesToAnalyse, + $configuration, + $input, + function (array $errors, array $locallyIgnoredErrors, array $analysedFiles) use ($out, $ignoredErrorHelperResult, $isOnlyFiles, $inceptionFiles): void { [$errors, $ignoredErrors] = $this->filterErrors($errors, $ignoredErrorHelperResult, $isOnlyFiles, $inceptionFiles, false); foreach ($locallyIgnoredErrors as $locallyIgnoredError) { $ignoredErrors[] = [$locallyIgnoredError, null]; @@ -210,8 +226,15 @@ protected function execute(InputInterface $input, OutputInterface $output): int 'analysedFiles' => $analysedFiles, ], ]); - })->then(function (AnalyserResult $intermediateAnalyserResult) use ($resultCacheManager, $resultCache, $inceptionResult, $container, $isOnlyFiles, $ignoredErrorHelperResult, $inceptionFiles, $out): void { - $result = $resultCacheManager->process($intermediateAnalyserResult, $resultCache, $inceptionResult->getErrorOutput(), false, true)->getAnalyserResult(); + }, + )->then(function (AnalyserResult $intermediateAnalyserResult) use ($resultCacheManager, $resultCache, $inceptionResult, $container, $isOnlyFiles, $ignoredErrorHelperResult, $inceptionFiles, $out): void { + $result = $resultCacheManager->process( + $intermediateAnalyserResult, + $resultCache, + $inceptionResult->getErrorOutput(), + false, + true, + )->getAnalyserResult(); $hasInternalErrors = count($result->getInternalErrors()) > 0 || $result->hasReachedInternalErrorsCountLimit(); @@ -240,7 +263,12 @@ protected function execute(InputInterface $input, OutputInterface $output): int ], ]); - $ignoredErrorHelperProcessedResult = $ignoredErrorHelperResult->process($intermediateErrors, $isOnlyFiles, $inceptionFiles, $hasInternalErrors); + $ignoredErrorHelperProcessedResult = $ignoredErrorHelperResult->process( + $intermediateErrors, + $isOnlyFiles, + $inceptionFiles, + $hasInternalErrors, + ); $intermediateErrors = $ignoredErrorHelperProcessedResult->getNotIgnoredErrors(); $ignoreNotFileErrors = $ignoredErrorHelperProcessedResult->getOtherIgnoreMessages(); @@ -356,7 +384,15 @@ private function runAnalyser(LoopInterface $loop, Container $container, array $f $mainScript = $_SERVER['argv'][0]; } - return $parallelAnalyser->analyse($loop, $schedule, $mainScript, null, $configuration, $input, $onFileAnalysisHandler); + return $parallelAnalyser->analyse( + $loop, + $schedule, + $mainScript, + null, + $configuration, + $input, + $onFileAnalysisHandler, + ); } } diff --git a/src/Command/IgnoredRegexValidator.php b/src/Command/IgnoredRegexValidator.php index df20a258b85..e7a90c5bd24 100644 --- a/src/Command/IgnoredRegexValidator.php +++ b/src/Command/IgnoredRegexValidator.php @@ -20,19 +20,13 @@ class IgnoredRegexValidator { - /** - * @var Parser - */ - private $parser; - /** - * @var TypeStringResolver - */ - private $typeStringResolver; - public function __construct(Parser $parser, TypeStringResolver $typeStringResolver) + public function __construct( + private Parser $parser, + private TypeStringResolver $typeStringResolver, + ) { - $this->parser = $parser; - $this->typeStringResolver = $typeStringResolver; } + public function validate(string $regex): IgnoredRegexValidatorResult { $regex = $this->removeDelimiters($regex); @@ -53,7 +47,11 @@ public function validate(string $regex): IgnoredRegexValidatorResult return new IgnoredRegexValidatorResult([], false, false); } - return new IgnoredRegexValidatorResult($this->getIgnoredTypes($ast), $this->hasAnchorsInTheMiddle($ast), false); + return new IgnoredRegexValidatorResult( + $this->getIgnoredTypes($ast), + $this->hasAnchorsInTheMiddle($ast), + false, + ); } /** @@ -85,7 +83,7 @@ private function getIgnoredTypes(TreeNode $ast): array try { $type = $this->typeStringResolver->resolve($matches[1], null); - } catch (ParserException $e) { + } catch (ParserException) { continue; } diff --git a/src/Command/IgnoredRegexValidatorResult.php b/src/Command/IgnoredRegexValidatorResult.php index 361aff8a597..fcda6a015bf 100644 --- a/src/Command/IgnoredRegexValidatorResult.php +++ b/src/Command/IgnoredRegexValidatorResult.php @@ -5,37 +5,19 @@ class IgnoredRegexValidatorResult { - /** - * @var array - */ - private $ignoredTypes; - /** - * @var bool - */ - private $anchorsInTheMiddle; - /** - * @var bool - */ - private $allErrorsIgnored; - /** - * @var ?string - */ - private $wrongSequence; - /** - * @var ?string - */ - private $escapedWrongSequence; /** * @param array $ignoredTypes */ - public function __construct(array $ignoredTypes, bool $anchorsInTheMiddle, bool $allErrorsIgnored, ?string $wrongSequence = null, ?string $escapedWrongSequence = null) + public function __construct( + private array $ignoredTypes, + private bool $anchorsInTheMiddle, + private bool $allErrorsIgnored, + private ?string $wrongSequence = null, + private ?string $escapedWrongSequence = null, + ) { - $this->ignoredTypes = $ignoredTypes; - $this->anchorsInTheMiddle = $anchorsInTheMiddle; - $this->allErrorsIgnored = $allErrorsIgnored; - $this->wrongSequence = $wrongSequence; - $this->escapedWrongSequence = $escapedWrongSequence; } + /** * @return array */ diff --git a/src/Command/InceptionResult.php b/src/Command/InceptionResult.php index d96d39227d4..308935fb9de 100644 --- a/src/Command/InceptionResult.php +++ b/src/Command/InceptionResult.php @@ -12,34 +12,6 @@ class InceptionResult { - /** - * @var Output - */ - private $stdOutput; - /** - * @var Output - */ - private $errorOutput; - /** - * @var Container - */ - private $container; - /** - * @var bool - */ - private $isDefaultLevelUsed; - /** - * @var ?string - */ - private $projectConfigFile; - /** - * @var mixed[]|null - */ - private $projectConfigArray; - /** - * @var ?string - */ - private $generateBaselineFile; /** @var callable(): (array{string[], bool}) */ private $filesCallback; @@ -47,15 +19,17 @@ class InceptionResult * @param callable(): (array{string[], bool}) $filesCallback * @param mixed[]|null $projectConfigArray */ - public function __construct(callable $filesCallback, Output $stdOutput, Output $errorOutput, Container $container, bool $isDefaultLevelUsed, ?string $projectConfigFile, ?array $projectConfigArray, ?string $generateBaselineFile) + public function __construct( + callable $filesCallback, + private Output $stdOutput, + private Output $errorOutput, + private Container $container, + private bool $isDefaultLevelUsed, + private ?string $projectConfigFile, + private ?array $projectConfigArray, + private ?string $generateBaselineFile, + ) { - $this->stdOutput = $stdOutput; - $this->errorOutput = $errorOutput; - $this->container = $container; - $this->isDefaultLevelUsed = $isDefaultLevelUsed; - $this->projectConfigFile = $projectConfigFile; - $this->projectConfigArray = $projectConfigArray; - $this->generateBaselineFile = $generateBaselineFile; $this->filesCallback = $filesCallback; } @@ -113,7 +87,10 @@ public function getGenerateBaselineFile(): ?string public function handleReturn(int $exitCode, ?int $peakMemoryUsageBytes): int { if ($peakMemoryUsageBytes !== null && $this->getErrorOutput()->isVerbose()) { - $this->getErrorOutput()->writeLineFormatted(sprintf('Used memory: %s', BytesHelper::bytes(max(memory_get_peak_usage(true), $peakMemoryUsageBytes)))); + $this->getErrorOutput()->writeLineFormatted(sprintf( + 'Used memory: %s', + BytesHelper::bytes(max(memory_get_peak_usage(true), $peakMemoryUsageBytes)), + )); } return $exitCode; diff --git a/src/Command/Symfony/SymfonyOutput.php b/src/Command/Symfony/SymfonyOutput.php index 4de81ce2708..5e1a46273ae 100644 --- a/src/Command/Symfony/SymfonyOutput.php +++ b/src/Command/Symfony/SymfonyOutput.php @@ -12,19 +12,13 @@ class SymfonyOutput implements Output { - /** - * @var OutputInterface - */ - private $symfonyOutput; - /** - * @var OutputStyle - */ - private $style; - public function __construct(OutputInterface $symfonyOutput, OutputStyle $style) + public function __construct( + private OutputInterface $symfonyOutput, + private OutputStyle $style, + ) { - $this->symfonyOutput = $symfonyOutput; - $this->style = $style; } + public function writeFormatted(string $message): void { $this->symfonyOutput->write($message, false, OutputInterface::OUTPUT_NORMAL); diff --git a/src/Command/Symfony/SymfonyStyle.php b/src/Command/Symfony/SymfonyStyle.php index edb918b49c7..99ed87ec330 100644 --- a/src/Command/Symfony/SymfonyStyle.php +++ b/src/Command/Symfony/SymfonyStyle.php @@ -11,13 +11,8 @@ class SymfonyStyle implements OutputStyle { - /** - * @var StyleInterface - */ - private $symfonyStyle; - public function __construct(StyleInterface $symfonyStyle) + public function __construct(private StyleInterface $symfonyStyle) { - $this->symfonyStyle = $symfonyStyle; } public function getSymfonyStyle(): StyleInterface diff --git a/src/Command/WorkerCommand.php b/src/Command/WorkerCommand.php index fa75f238bf4..c9d648bed6a 100644 --- a/src/Command/WorkerCommand.php +++ b/src/Command/WorkerCommand.php @@ -33,23 +33,17 @@ class WorkerCommand extends Command { - /** - * @var string[] - */ - private $composerAutoloaderProjectPaths; private const NAME = 'worker'; - /** - * @var int - */ - private $errorCount = 0; + private int $errorCount = 0; /** * @param string[] $composerAutoloaderProjectPaths */ - public function __construct(array $composerAutoloaderProjectPaths) + public function __construct( + private array $composerAutoloaderProjectPaths, + ) { - $this->composerAutoloaderProjectPaths = $composerAutoloaderProjectPaths; parent::__construct(); } @@ -95,7 +89,20 @@ protected function execute(InputInterface $input, OutputInterface $output): int } try { - $inceptionResult = CommandHelper::begin($input, $output, $paths, $memoryLimit, $autoloadFile, $this->composerAutoloaderProjectPaths, $configuration, null, $level, $allowXdebug, false, false); + $inceptionResult = CommandHelper::begin( + $input, + $output, + $paths, + $memoryLimit, + $autoloadFile, + $this->composerAutoloaderProjectPaths, + $configuration, + null, + $level, + $allowXdebug, + false, + false, + ); } catch (InceptionNotSuccessfulException $e) { return 1; } @@ -108,7 +115,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int } catch (PathNotFoundException $e) { $inceptionResult->getErrorOutput()->writeLineFormatted(sprintf('%s', $e->getMessage())); return 1; - } catch (InceptionNotSuccessfulException $e) { + } catch (InceptionNotSuccessfulException) { return 1; } @@ -140,7 +147,13 @@ protected function execute(InputInterface $input, OutputInterface $output): int /** * @param array $analysedFiles */ - private function runWorker(Container $container, WritableStreamInterface $out, ReadableStreamInterface $in, OutputInterface $output, array $analysedFiles) : void + private function runWorker( + Container $container, + WritableStreamInterface $out, + ReadableStreamInterface $in, + OutputInterface $output, + array $analysedFiles, + ): void { $handleError = function (Throwable $error) use ($out, $output): void { $this->errorCount++; diff --git a/src/Dependency/DependencyResolver.php b/src/Dependency/DependencyResolver.php index 8f6b07e01f3..5c4af0aff19 100644 --- a/src/Dependency/DependencyResolver.php +++ b/src/Dependency/DependencyResolver.php @@ -31,29 +31,15 @@ class DependencyResolver { - /** - * @var FileHelper - */ - private $fileHelper; - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - /** - * @var ExportedNodeResolver - */ - private $exportedNodeResolver; - /** - * @var FileTypeMapper - */ - private $fileTypeMapper; - public function __construct(FileHelper $fileHelper, ReflectionProvider $reflectionProvider, ExportedNodeResolver $exportedNodeResolver, FileTypeMapper $fileTypeMapper) + public function __construct( + private FileHelper $fileHelper, + private ReflectionProvider $reflectionProvider, + private ExportedNodeResolver $exportedNodeResolver, + private FileTypeMapper $fileTypeMapper, + ) { - $this->fileHelper = $fileHelper; - $this->reflectionProvider = $reflectionProvider; - $this->exportedNodeResolver = $exportedNodeResolver; - $this->fileTypeMapper = $fileTypeMapper; } + public function resolveDependencies(Node $node, Scope $scope): NodeDependencies { $dependenciesReflections = []; @@ -169,7 +155,7 @@ public function resolveDependencies(Node $node, Scope $scope): NodeDependencies $this->addClassToDependencies($referencedClass, $dependenciesReflections); } } - } catch (FunctionNotFoundException $e) { + } catch (FunctionNotFoundException) { // pass } } else { @@ -393,7 +379,7 @@ public function resolveDependencies(Node $node, Scope $scope): NodeDependencies $this->addClassToDependencies($referencedClass, $dependenciesReflections); } } - } catch (ClassNotFoundException $e) { + } catch (ClassNotFoundException) { // pass } } elseif ($node instanceof Node\Stmt\TraitUse) { @@ -403,7 +389,13 @@ public function resolveDependencies(Node $node, Scope $scope): NodeDependencies $docComment = $node->getDocComment(); if ($docComment !== null) { - $usesTags = $this->fileTypeMapper->getResolvedPhpDoc($scope->getFile(), $scope->isInClass() ? $scope->getClassReflection()->getName() : null, $scope->isInTrait() ? $scope->getTraitReflection()->getName() : null, null, $docComment->getText())->getUsesTags(); + $usesTags = $this->fileTypeMapper->getResolvedPhpDoc( + $scope->getFile(), + $scope->isInClass() ? $scope->getClassReflection()->getName() : null, + $scope->isInTrait() ? $scope->getTraitReflection()->getName() : null, + null, + $docComment->getText(), + )->getUsesTags(); foreach ($usesTags as $usesTag) { foreach ($usesTag->getType()->getReferencedClasses() as $referencedClass) { $this->addClassToDependencies($referencedClass, $dependenciesReflections); @@ -477,7 +469,7 @@ private function addClassToDependencies(string $className, array &$dependenciesR { try { $classReflection = $this->reflectionProvider->getClass($className); - } catch (ClassNotFoundException $e) { + } catch (ClassNotFoundException) { return; } @@ -604,10 +596,16 @@ private function getFunctionReflection(Node\Name $nameNode, ?Scope $scope): Func /** * @param array $dependenciesReflections */ - private function extractFromParametersAcceptor(ParametersAcceptorWithPhpDocs $parametersAcceptor, array &$dependenciesReflections) : void + private function extractFromParametersAcceptor( + ParametersAcceptorWithPhpDocs $parametersAcceptor, + array &$dependenciesReflections, + ): void { foreach ($parametersAcceptor->getParameters() as $parameter) { - $referencedClasses = array_merge($parameter->getNativeType()->getReferencedClasses(), $parameter->getPhpDocType()->getReferencedClasses()); + $referencedClasses = array_merge( + $parameter->getNativeType()->getReferencedClasses(), + $parameter->getPhpDocType()->getReferencedClasses(), + ); foreach ($referencedClasses as $referencedClass) { $this->addClassToDependencies($referencedClass, $dependenciesReflections); @@ -621,7 +619,11 @@ private function extractFromParametersAcceptor(ParametersAcceptorWithPhpDocs $pa $this->addClassToDependencies($referencedClass, $dependenciesReflections); } } - $returnTypeReferencedClasses = array_merge($parametersAcceptor->getNativeReturnType()->getReferencedClasses(), $parametersAcceptor->getPhpDocReturnType()->getReferencedClasses()); + + $returnTypeReferencedClasses = array_merge( + $parametersAcceptor->getNativeReturnType()->getReferencedClasses(), + $parametersAcceptor->getPhpDocReturnType()->getReferencedClasses(), + ); foreach ($returnTypeReferencedClasses as $referencedClass) { $this->addClassToDependencies($referencedClass, $dependenciesReflections); } @@ -630,11 +632,15 @@ private function extractFromParametersAcceptor(ParametersAcceptorWithPhpDocs $pa /** * @param array $dependenciesReflections */ - private function extractThrowType(?Type $throwType, array &$dependenciesReflections) : void + private function extractThrowType( + ?Type $throwType, + array &$dependenciesReflections, + ): void { if ($throwType === null) { return; } + foreach ($throwType->getReferencedClasses() as $referencedClass) { $this->addClassToDependencies($referencedClass, $dependenciesReflections); } diff --git a/src/Dependency/ExportedNode/ExportedAttributeNode.php b/src/Dependency/ExportedNode/ExportedAttributeNode.php index 46add2ecc18..02714f2f592 100644 --- a/src/Dependency/ExportedNode/ExportedAttributeNode.php +++ b/src/Dependency/ExportedNode/ExportedAttributeNode.php @@ -10,22 +10,16 @@ class ExportedAttributeNode implements ExportedNode, JsonSerializable { - /** - * @var string - */ - private $name; - /** - * @var array - */ - private $args; /** * @param array $args argument name or index(string|int) => value expression (string) */ - public function __construct(string $name, array $args) + public function __construct( + private string $name, + private array $args, + ) { - $this->name = $name; - $this->args = $args; } + public function equals(ExportedNode $node): bool { if (!$node instanceof self) { @@ -55,7 +49,10 @@ public function equals(ExportedNode $node): bool */ public static function __set_state(array $properties): ExportedNode { - return new self($properties['name'], $properties['args']); + return new self( + $properties['name'], + $properties['args'], + ); } /** @@ -79,7 +76,10 @@ public function jsonSerialize() */ public static function decode(array $data): ExportedNode { - return new self($data['name'], $data['args']); + return new self( + $data['name'], + $data['args'], + ); } } diff --git a/src/Dependency/ExportedNode/ExportedClassConstantNode.php b/src/Dependency/ExportedNode/ExportedClassConstantNode.php index 13b32b360fc..aab53925f16 100644 --- a/src/Dependency/ExportedNode/ExportedClassConstantNode.php +++ b/src/Dependency/ExportedNode/ExportedClassConstantNode.php @@ -12,27 +12,17 @@ class ExportedClassConstantNode implements ExportedNode, JsonSerializable { - /** - * @var string - */ - private $name; - /** - * @var string - */ - private $value; - /** - * @var ExportedAttributeNode[] - */ - private $attributes; /** * @param ExportedAttributeNode[] $attributes */ - public function __construct(string $name, string $value, array $attributes) + public function __construct( + private string $name, + private string $value, + private array $attributes, + ) { - $this->name = $name; - $this->value = $value; - $this->attributes = $attributes; } + public function equals(ExportedNode $node): bool { if (!$node instanceof self) { @@ -59,7 +49,11 @@ public function equals(ExportedNode $node): bool */ public static function __set_state(array $properties): ExportedNode { - return new self($properties['name'], $properties['value'], $properties['attributes']); + return new self( + $properties['name'], + $properties['value'], + $properties['attributes'], + ); } /** @@ -68,12 +62,16 @@ public static function __set_state(array $properties): ExportedNode */ public static function decode(array $data): ExportedNode { - return new self($data['name'], $data['value'], array_map(static function (array $attributeData): ExportedAttributeNode { + return new self( + $data['name'], + $data['value'], + array_map(static function (array $attributeData): ExportedAttributeNode { if ($attributeData['type'] !== ExportedAttributeNode::class) { throw new ShouldNotHappenException(); } return ExportedAttributeNode::decode($attributeData['data']); - }, $data['attributes'])); + }, $data['attributes']), + ); } /** diff --git a/src/Dependency/ExportedNode/ExportedClassConstantsNode.php b/src/Dependency/ExportedNode/ExportedClassConstantsNode.php index b06eb159571..04bace72824 100644 --- a/src/Dependency/ExportedNode/ExportedClassConstantsNode.php +++ b/src/Dependency/ExportedNode/ExportedClassConstantsNode.php @@ -12,36 +12,11 @@ class ExportedClassConstantsNode implements ExportedNode, JsonSerializable { - /** - * @var ExportedClassConstantNode[] - */ - private $constants; - /** - * @var bool - */ - private $public; - /** - * @var bool - */ - private $private; - /** - * @var bool - */ - private $final; - /** - * @var ?ExportedPhpDocNode - */ - private $phpDoc; /** * @param ExportedClassConstantNode[] $constants */ - public function __construct(array $constants, bool $public, bool $private, bool $final, ?ExportedPhpDocNode $phpDoc) + public function __construct(private array $constants, private bool $public, private bool $private, private bool $final, private ?ExportedPhpDocNode $phpDoc) { - $this->constants = $constants; - $this->public = $public; - $this->private = $private; - $this->final = $final; - $this->phpDoc = $phpDoc; } public function equals(ExportedNode $node): bool @@ -83,7 +58,13 @@ public function equals(ExportedNode $node): bool */ public static function __set_state(array $properties): ExportedNode { - return new self($properties['constants'], $properties['public'], $properties['private'], $properties['final'], $properties['phpDoc']); + return new self( + $properties['constants'], + $properties['public'], + $properties['private'], + $properties['final'], + $properties['phpDoc'], + ); } /** @@ -92,12 +73,18 @@ public static function __set_state(array $properties): ExportedNode */ public static function decode(array $data): ExportedNode { - return new self(array_map(static function (array $constantData): ExportedClassConstantNode { + return new self( + array_map(static function (array $constantData): ExportedClassConstantNode { if ($constantData['type'] !== ExportedClassConstantNode::class) { throw new ShouldNotHappenException(); } return ExportedClassConstantNode::decode($constantData['data']); - }, $data['constants']), $data['public'], $data['private'], $data['final'], $data['phpDoc'] !== null ? ExportedPhpDocNode::decode($data['phpDoc']['data']) : null); + }, $data['constants']), + $data['public'], + $data['private'], + $data['final'], + $data['phpDoc'] !== null ? ExportedPhpDocNode::decode($data['phpDoc']['data']) : null, + ); } /** diff --git a/src/Dependency/ExportedNode/ExportedClassNode.php b/src/Dependency/ExportedNode/ExportedClassNode.php index 39cc501538e..b96096cff25 100644 --- a/src/Dependency/ExportedNode/ExportedClassNode.php +++ b/src/Dependency/ExportedNode/ExportedClassNode.php @@ -13,46 +13,6 @@ class ExportedClassNode implements RootExportedNode, JsonSerializable { - /** - * @var string - */ - private $name; - /** - * @var ?ExportedPhpDocNode - */ - private $phpDoc; - /** - * @var bool - */ - private $abstract; - /** - * @var bool - */ - private $final; - /** - * @var ?string - */ - private $extends; - /** - * @var string[] - */ - private $implements; - /** - * @var string[] - */ - private $usedTraits; - /** - * @var ExportedTraitUseAdaptation[] - */ - private $traitUseAdaptations; - /** - * @var ExportedNode[] - */ - private $statements; - /** - * @var ExportedAttributeNode[] - */ - private $attributes; /** * @param string[] $implements * @param string[] $usedTraits @@ -60,19 +20,21 @@ class ExportedClassNode implements RootExportedNode, JsonSerializable * @param ExportedNode[] $statements * @param ExportedAttributeNode[] $attributes */ - public function __construct(string $name, ?ExportedPhpDocNode $phpDoc, bool $abstract, bool $final, ?string $extends, array $implements, array $usedTraits, array $traitUseAdaptations, array $statements, array $attributes) + public function __construct( + private string $name, + private ?ExportedPhpDocNode $phpDoc, + private bool $abstract, + private bool $final, + private ?string $extends, + private array $implements, + private array $usedTraits, + private array $traitUseAdaptations, + private array $statements, + private array $attributes, + ) { - $this->name = $name; - $this->phpDoc = $phpDoc; - $this->abstract = $abstract; - $this->final = $final; - $this->extends = $extends; - $this->implements = $implements; - $this->usedTraits = $usedTraits; - $this->traitUseAdaptations = $traitUseAdaptations; - $this->statements = $statements; - $this->attributes = $attributes; } + public function equals(ExportedNode $node): bool { if (!$node instanceof self) { @@ -138,7 +100,18 @@ public function equals(ExportedNode $node): bool */ public static function __set_state(array $properties): ExportedNode { - return new self($properties['name'], $properties['phpDoc'], $properties['abstract'], $properties['final'], $properties['extends'], $properties['implements'], $properties['usedTraits'], $properties['traitUseAdaptations'], $properties['statements'], $properties['attributes']); + return new self( + $properties['name'], + $properties['phpDoc'], + $properties['abstract'], + $properties['final'], + $properties['extends'], + $properties['implements'], + $properties['usedTraits'], + $properties['traitUseAdaptations'], + $properties['statements'], + $properties['attributes'], + ); } /** @@ -170,21 +143,32 @@ public function jsonSerialize() */ public static function decode(array $data): ExportedNode { - return new self($data['name'], $data['phpDoc'] !== null ? ExportedPhpDocNode::decode($data['phpDoc']['data']) : null, $data['abstract'], $data['final'], $data['extends'], $data['implements'], $data['usedTraits'], array_map(static function (array $traitUseAdaptationData): ExportedTraitUseAdaptation { + return new self( + $data['name'], + $data['phpDoc'] !== null ? ExportedPhpDocNode::decode($data['phpDoc']['data']) : null, + $data['abstract'], + $data['final'], + $data['extends'], + $data['implements'], + $data['usedTraits'], + array_map(static function (array $traitUseAdaptationData): ExportedTraitUseAdaptation { if ($traitUseAdaptationData['type'] !== ExportedTraitUseAdaptation::class) { throw new ShouldNotHappenException(); } return ExportedTraitUseAdaptation::decode($traitUseAdaptationData['data']); - }, $data['traitUseAdaptations']), array_map(static function (array $node): ExportedNode { + }, $data['traitUseAdaptations']), + array_map(static function (array $node): ExportedNode { $nodeType = $node['type']; return $nodeType::decode($node['data']); - }, $data['statements']), array_map(static function (array $attributeData): ExportedAttributeNode { + }, $data['statements']), + array_map(static function (array $attributeData): ExportedAttributeNode { if ($attributeData['type'] !== ExportedAttributeNode::class) { throw new ShouldNotHappenException(); } return ExportedAttributeNode::decode($attributeData['data']); - }, $data['attributes'])); + }, $data['attributes']), + ); } public function getType(): string diff --git a/src/Dependency/ExportedNode/ExportedEnumCaseNode.php b/src/Dependency/ExportedNode/ExportedEnumCaseNode.php index 82032038933..da304b58937 100644 --- a/src/Dependency/ExportedNode/ExportedEnumCaseNode.php +++ b/src/Dependency/ExportedNode/ExportedEnumCaseNode.php @@ -9,23 +9,8 @@ class ExportedEnumCaseNode implements ExportedNode, JsonSerializable { - /** - * @var string - */ - private $name; - /** - * @var ?string - */ - private $value; - /** - * @var ?ExportedPhpDocNode - */ - private $phpDoc; - public function __construct(string $name, ?string $value, ?ExportedPhpDocNode $phpDoc) + public function __construct(private string $name, private ?string $value, private ?ExportedPhpDocNode $phpDoc) { - $this->name = $name; - $this->value = $value; - $this->phpDoc = $phpDoc; } public function equals(ExportedNode $node): bool @@ -56,7 +41,11 @@ public function equals(ExportedNode $node): bool */ public static function __set_state(array $properties): ExportedNode { - return new self($properties['name'], $properties['value'], $properties['phpDoc']); + return new self( + $properties['name'], + $properties['value'], + $properties['phpDoc'], + ); } /** @@ -65,7 +54,11 @@ public static function __set_state(array $properties): ExportedNode */ public static function decode(array $data): ExportedNode { - return new self($data['name'], $data['value'], $data['phpDoc'] !== null ? ExportedPhpDocNode::decode($data['phpDoc']['data']) : null); + return new self( + $data['name'], + $data['value'], + $data['phpDoc'] !== null ? ExportedPhpDocNode::decode($data['phpDoc']['data']) : null, + ); } /** diff --git a/src/Dependency/ExportedNode/ExportedEnumNode.php b/src/Dependency/ExportedNode/ExportedEnumNode.php index 6467c3b3e5b..3d75abd6277 100644 --- a/src/Dependency/ExportedNode/ExportedEnumNode.php +++ b/src/Dependency/ExportedNode/ExportedEnumNode.php @@ -13,44 +13,22 @@ class ExportedEnumNode implements RootExportedNode, JsonSerializable { - /** - * @var string - */ - private $name; - /** - * @var ?string - */ - private $scalarType; - /** - * @var ?ExportedPhpDocNode - */ - private $phpDoc; - /** - * @var string[] - */ - private $implements; - /** - * @var ExportedNode[] - */ - private $statements; - /** - * @var ExportedAttributeNode[] - */ - private $attributes; /** * @param string[] $implements * @param ExportedNode[] $statements * @param ExportedAttributeNode[] $attributes */ - public function __construct(string $name, ?string $scalarType, ?ExportedPhpDocNode $phpDoc, array $implements, array $statements, array $attributes) + public function __construct( + private string $name, + private ?string $scalarType, + private ?ExportedPhpDocNode $phpDoc, + private array $implements, + private array $statements, + private array $attributes, + ) { - $this->name = $name; - $this->scalarType = $scalarType; - $this->phpDoc = $phpDoc; - $this->implements = $implements; - $this->statements = $statements; - $this->attributes = $attributes; } + public function equals(ExportedNode $node): bool { if (!$node instanceof self) { @@ -102,7 +80,14 @@ public function equals(ExportedNode $node): bool */ public static function __set_state(array $properties): ExportedNode { - return new self($properties['name'], $properties['scalarType'], $properties['phpDoc'], $properties['implements'], $properties['statements'], $properties['attributes']); + return new self( + $properties['name'], + $properties['scalarType'], + $properties['phpDoc'], + $properties['implements'], + $properties['statements'], + $properties['attributes'], + ); } /** @@ -130,16 +115,23 @@ public function jsonSerialize() */ public static function decode(array $data): ExportedNode { - return new self($data['name'], $data['scalarType'], $data['phpDoc'] !== null ? ExportedPhpDocNode::decode($data['phpDoc']['data']) : null, $data['implements'], array_map(static function (array $node): ExportedNode { + return new self( + $data['name'], + $data['scalarType'], + $data['phpDoc'] !== null ? ExportedPhpDocNode::decode($data['phpDoc']['data']) : null, + $data['implements'], + array_map(static function (array $node): ExportedNode { $nodeType = $node['type']; return $nodeType::decode($node['data']); - }, $data['statements']), array_map(static function (array $attributeData): ExportedAttributeNode { + }, $data['statements']), + array_map(static function (array $attributeData): ExportedAttributeNode { if ($attributeData['type'] !== ExportedAttributeNode::class) { throw new ShouldNotHappenException(); } return ExportedAttributeNode::decode($attributeData['data']); - }, $data['attributes'])); + }, $data['attributes']), + ); } public function getType(): string diff --git a/src/Dependency/ExportedNode/ExportedFunctionNode.php b/src/Dependency/ExportedNode/ExportedFunctionNode.php index f9fe9f541dc..fcc0f51ad55 100644 --- a/src/Dependency/ExportedNode/ExportedFunctionNode.php +++ b/src/Dependency/ExportedNode/ExportedFunctionNode.php @@ -13,43 +13,21 @@ class ExportedFunctionNode implements RootExportedNode, JsonSerializable { - /** - * @var string - */ - private $name; - /** - * @var ?ExportedPhpDocNode - */ - private $phpDoc; - /** - * @var bool - */ - private $byRef; - /** - * @var ?string - */ - private $returnType; - /** - * @var ExportedParameterNode[] - */ - private $parameters; - /** - * @var ExportedAttributeNode[] - */ - private $attributes; /** * @param ExportedParameterNode[] $parameters * @param ExportedAttributeNode[] $attributes */ - public function __construct(string $name, ?ExportedPhpDocNode $phpDoc, bool $byRef, ?string $returnType, array $parameters, array $attributes) + public function __construct( + private string $name, + private ?ExportedPhpDocNode $phpDoc, + private bool $byRef, + private ?string $returnType, + private array $parameters, + private array $attributes, + ) { - $this->name = $name; - $this->phpDoc = $phpDoc; - $this->byRef = $byRef; - $this->returnType = $returnType; - $this->parameters = $parameters; - $this->attributes = $attributes; } + public function equals(ExportedNode $node): bool { if (!$node instanceof self) { @@ -100,7 +78,14 @@ public function equals(ExportedNode $node): bool */ public static function __set_state(array $properties): ExportedNode { - return new self($properties['name'], $properties['phpDoc'], $properties['byRef'], $properties['returnType'], $properties['parameters'], $properties['attributes']); + return new self( + $properties['name'], + $properties['phpDoc'], + $properties['byRef'], + $properties['returnType'], + $properties['parameters'], + $properties['attributes'], + ); } /** @@ -128,17 +113,24 @@ public function jsonSerialize() */ public static function decode(array $data): ExportedNode { - return new self($data['name'], $data['phpDoc'] !== null ? ExportedPhpDocNode::decode($data['phpDoc']['data']) : null, $data['byRef'], $data['returnType'], array_map(static function (array $parameterData): ExportedParameterNode { + return new self( + $data['name'], + $data['phpDoc'] !== null ? ExportedPhpDocNode::decode($data['phpDoc']['data']) : null, + $data['byRef'], + $data['returnType'], + array_map(static function (array $parameterData): ExportedParameterNode { if ($parameterData['type'] !== ExportedParameterNode::class) { throw new ShouldNotHappenException(); } return ExportedParameterNode::decode($parameterData['data']); - }, $data['parameters']), array_map(static function (array $attributeData): ExportedAttributeNode { + }, $data['parameters']), + array_map(static function (array $attributeData): ExportedAttributeNode { if ($attributeData['type'] !== ExportedAttributeNode::class) { throw new ShouldNotHappenException(); } return ExportedAttributeNode::decode($attributeData['data']); - }, $data['attributes'])); + }, $data['attributes']), + ); } public function getType(): string diff --git a/src/Dependency/ExportedNode/ExportedInterfaceNode.php b/src/Dependency/ExportedNode/ExportedInterfaceNode.php index 89a3c803482..394eef707d2 100644 --- a/src/Dependency/ExportedNode/ExportedInterfaceNode.php +++ b/src/Dependency/ExportedNode/ExportedInterfaceNode.php @@ -12,32 +12,12 @@ class ExportedInterfaceNode implements RootExportedNode, JsonSerializable { - /** - * @var string - */ - private $name; - /** - * @var ?ExportedPhpDocNode - */ - private $phpDoc; - /** - * @var string[] - */ - private $extends; - /** - * @var ExportedNode[] - */ - private $statements; /** * @param string[] $extends * @param ExportedNode[] $statements */ - public function __construct(string $name, ?ExportedPhpDocNode $phpDoc, array $extends, array $statements) + public function __construct(private string $name, private ?ExportedPhpDocNode $phpDoc, private array $extends, private array $statements) { - $this->name = $name; - $this->phpDoc = $phpDoc; - $this->extends = $extends; - $this->statements = $statements; } public function equals(ExportedNode $node): bool @@ -80,7 +60,12 @@ public function equals(ExportedNode $node): bool */ public static function __set_state(array $properties): ExportedNode { - return new self($properties['name'], $properties['phpDoc'], $properties['extends'], $properties['statements']); + return new self( + $properties['name'], + $properties['phpDoc'], + $properties['extends'], + $properties['statements'], + ); } /** @@ -106,11 +91,16 @@ public function jsonSerialize() */ public static function decode(array $data): ExportedNode { - return new self($data['name'], $data['phpDoc'] !== null ? ExportedPhpDocNode::decode($data['phpDoc']['data']) : null, $data['extends'], array_map(static function (array $node): ExportedNode { + return new self( + $data['name'], + $data['phpDoc'] !== null ? ExportedPhpDocNode::decode($data['phpDoc']['data']) : null, + $data['extends'], + array_map(static function (array $node): ExportedNode { $nodeType = $node['type']; return $nodeType::decode($node['data']); - }, $data['statements'])); + }, $data['statements']), + ); } public function getType(): string diff --git a/src/Dependency/ExportedNode/ExportedMethodNode.php b/src/Dependency/ExportedNode/ExportedMethodNode.php index 499a3fe4d57..a60a6d205ee 100644 --- a/src/Dependency/ExportedNode/ExportedMethodNode.php +++ b/src/Dependency/ExportedNode/ExportedMethodNode.php @@ -12,68 +12,26 @@ class ExportedMethodNode implements ExportedNode, JsonSerializable { - /** - * @var string - */ - private $name; - /** - * @var ?ExportedPhpDocNode - */ - private $phpDoc; - /** - * @var bool - */ - private $byRef; - /** - * @var bool - */ - private $public; - /** - * @var bool - */ - private $private; - /** - * @var bool - */ - private $abstract; - /** - * @var bool - */ - private $final; - /** - * @var bool - */ - private $static; - /** - * @var ?string - */ - private $returnType; - /** - * @var ExportedParameterNode[] - */ - private $parameters; - /** - * @var ExportedAttributeNode[] - */ - private $attributes; /** * @param ExportedParameterNode[] $parameters * @param ExportedAttributeNode[] $attributes */ - public function __construct(string $name, ?ExportedPhpDocNode $phpDoc, bool $byRef, bool $public, bool $private, bool $abstract, bool $final, bool $static, ?string $returnType, array $parameters, array $attributes) + public function __construct( + private string $name, + private ?ExportedPhpDocNode $phpDoc, + private bool $byRef, + private bool $public, + private bool $private, + private bool $abstract, + private bool $final, + private bool $static, + private ?string $returnType, + private array $parameters, + private array $attributes, + ) { - $this->name = $name; - $this->phpDoc = $phpDoc; - $this->byRef = $byRef; - $this->public = $public; - $this->private = $private; - $this->abstract = $abstract; - $this->final = $final; - $this->static = $static; - $this->returnType = $returnType; - $this->parameters = $parameters; - $this->attributes = $attributes; } + public function equals(ExportedNode $node): bool { if (!$node instanceof self) { @@ -129,7 +87,19 @@ public function equals(ExportedNode $node): bool */ public static function __set_state(array $properties): ExportedNode { - return new self($properties['name'], $properties['phpDoc'], $properties['byRef'], $properties['public'], $properties['private'], $properties['abstract'], $properties['final'], $properties['static'], $properties['returnType'], $properties['parameters'], $properties['attributes']); + return new self( + $properties['name'], + $properties['phpDoc'], + $properties['byRef'], + $properties['public'], + $properties['private'], + $properties['abstract'], + $properties['final'], + $properties['static'], + $properties['returnType'], + $properties['parameters'], + $properties['attributes'], + ); } /** @@ -162,17 +132,29 @@ public function jsonSerialize() */ public static function decode(array $data): ExportedNode { - return new self($data['name'], $data['phpDoc'] !== null ? ExportedPhpDocNode::decode($data['phpDoc']['data']) : null, $data['byRef'], $data['public'], $data['private'], $data['abstract'], $data['final'], $data['static'], $data['returnType'], array_map(static function (array $parameterData): ExportedParameterNode { + return new self( + $data['name'], + $data['phpDoc'] !== null ? ExportedPhpDocNode::decode($data['phpDoc']['data']) : null, + $data['byRef'], + $data['public'], + $data['private'], + $data['abstract'], + $data['final'], + $data['static'], + $data['returnType'], + array_map(static function (array $parameterData): ExportedParameterNode { if ($parameterData['type'] !== ExportedParameterNode::class) { throw new ShouldNotHappenException(); } return ExportedParameterNode::decode($parameterData['data']); - }, $data['parameters']), array_map(static function (array $attributeData): ExportedAttributeNode { + }, $data['parameters']), + array_map(static function (array $attributeData): ExportedAttributeNode { if ($attributeData['type'] !== ExportedAttributeNode::class) { throw new ShouldNotHappenException(); } return ExportedAttributeNode::decode($attributeData['data']); - }, $data['attributes'])); + }, $data['attributes']), + ); } } diff --git a/src/Dependency/ExportedNode/ExportedParameterNode.php b/src/Dependency/ExportedNode/ExportedParameterNode.php index 427b0f8da66..d205afafdbc 100644 --- a/src/Dependency/ExportedNode/ExportedParameterNode.php +++ b/src/Dependency/ExportedNode/ExportedParameterNode.php @@ -12,42 +12,20 @@ class ExportedParameterNode implements ExportedNode, JsonSerializable { - /** - * @var string - */ - private $name; - /** - * @var ?string - */ - private $type; - /** - * @var bool - */ - private $byRef; - /** - * @var bool - */ - private $variadic; - /** - * @var bool - */ - private $hasDefault; - /** - * @var ExportedAttributeNode[] - */ - private $attributes; /** * @param ExportedAttributeNode[] $attributes */ - public function __construct(string $name, ?string $type, bool $byRef, bool $variadic, bool $hasDefault, array $attributes) + public function __construct( + private string $name, + private ?string $type, + private bool $byRef, + private bool $variadic, + private bool $hasDefault, + private array $attributes, + ) { - $this->name = $name; - $this->type = $type; - $this->byRef = $byRef; - $this->variadic = $variadic; - $this->hasDefault = $hasDefault; - $this->attributes = $attributes; } + public function equals(ExportedNode $node): bool { if (!$node instanceof self) { @@ -77,7 +55,14 @@ public function equals(ExportedNode $node): bool */ public static function __set_state(array $properties): ExportedNode { - return new self($properties['name'], $properties['type'], $properties['byRef'], $properties['variadic'], $properties['hasDefault'], $properties['attributes']); + return new self( + $properties['name'], + $properties['type'], + $properties['byRef'], + $properties['variadic'], + $properties['hasDefault'], + $properties['attributes'], + ); } /** @@ -105,12 +90,19 @@ public function jsonSerialize() */ public static function decode(array $data): ExportedNode { - return new self($data['name'], $data['type'], $data['byRef'], $data['variadic'], $data['hasDefault'], array_map(static function (array $attributeData): ExportedAttributeNode { + return new self( + $data['name'], + $data['type'], + $data['byRef'], + $data['variadic'], + $data['hasDefault'], + array_map(static function (array $attributeData): ExportedAttributeNode { if ($attributeData['type'] !== ExportedAttributeNode::class) { throw new ShouldNotHappenException(); } return ExportedAttributeNode::decode($attributeData['data']); - }, $data['attributes'])); + }, $data['attributes']), + ); } } diff --git a/src/Dependency/ExportedNode/ExportedPhpDocNode.php b/src/Dependency/ExportedNode/ExportedPhpDocNode.php index 5bebd2ea36c..64a37c96a46 100644 --- a/src/Dependency/ExportedNode/ExportedPhpDocNode.php +++ b/src/Dependency/ExportedNode/ExportedPhpDocNode.php @@ -9,32 +9,12 @@ class ExportedPhpDocNode implements ExportedNode, JsonSerializable { - /** - * @var string - */ - private $phpDocString; - /** - * @var ?string - */ - private $namespace; - /** - * @var array - */ - private $uses; - /** - * @var array - */ - private $constUses; /** * @param array $uses alias(string) => fullName(string) * @param array $constUses alias(string) => fullName(string) */ - public function __construct(string $phpDocString, ?string $namespace, array $uses, array $constUses) + public function __construct(private string $phpDocString, private ?string $namespace, private array $uses, private array $constUses) { - $this->phpDocString = $phpDocString; - $this->namespace = $namespace; - $this->uses = $uses; - $this->constUses = $constUses; } public function equals(ExportedNode $node): bool diff --git a/src/Dependency/ExportedNode/ExportedPropertiesNode.php b/src/Dependency/ExportedNode/ExportedPropertiesNode.php index 79b70856b5e..c801f256428 100644 --- a/src/Dependency/ExportedNode/ExportedPropertiesNode.php +++ b/src/Dependency/ExportedNode/ExportedPropertiesNode.php @@ -12,53 +12,23 @@ class ExportedPropertiesNode implements JsonSerializable, ExportedNode { - /** - * @var string[] - */ - private $names; - /** - * @var ?ExportedPhpDocNode - */ - private $phpDoc; - /** - * @var ?string - */ - private $type; - /** - * @var bool - */ - private $public; - /** - * @var bool - */ - private $private; - /** - * @var bool - */ - private $static; - /** - * @var bool - */ - private $readonly; - /** - * @var ExportedAttributeNode[] - */ - private $attributes; /** * @param string[] $names * @param ExportedAttributeNode[] $attributes */ - public function __construct(array $names, ?ExportedPhpDocNode $phpDoc, ?string $type, bool $public, bool $private, bool $static, bool $readonly, array $attributes) + public function __construct( + private array $names, + private ?ExportedPhpDocNode $phpDoc, + private ?string $type, + private bool $public, + private bool $private, + private bool $static, + private bool $readonly, + private array $attributes, + ) { - $this->names = $names; - $this->phpDoc = $phpDoc; - $this->type = $type; - $this->public = $public; - $this->private = $private; - $this->static = $static; - $this->readonly = $readonly; - $this->attributes = $attributes; } + public function equals(ExportedNode $node): bool { if (!$node instanceof self) { @@ -110,7 +80,16 @@ public function equals(ExportedNode $node): bool */ public static function __set_state(array $properties): ExportedNode { - return new self($properties['names'], $properties['phpDoc'], $properties['type'], $properties['public'], $properties['private'], $properties['static'], $properties['readonly'], $properties['attributes']); + return new self( + $properties['names'], + $properties['phpDoc'], + $properties['type'], + $properties['public'], + $properties['private'], + $properties['static'], + $properties['readonly'], + $properties['attributes'], + ); } /** @@ -119,12 +98,21 @@ public static function __set_state(array $properties): ExportedNode */ public static function decode(array $data): ExportedNode { - return new self($data['names'], $data['phpDoc'] !== null ? ExportedPhpDocNode::decode($data['phpDoc']['data']) : null, $data['type'], $data['public'], $data['private'], $data['static'], $data['readonly'], array_map(static function (array $attributeData): ExportedAttributeNode { + return new self( + $data['names'], + $data['phpDoc'] !== null ? ExportedPhpDocNode::decode($data['phpDoc']['data']) : null, + $data['type'], + $data['public'], + $data['private'], + $data['static'], + $data['readonly'], + array_map(static function (array $attributeData): ExportedAttributeNode { if ($attributeData['type'] !== ExportedAttributeNode::class) { throw new ShouldNotHappenException(); } return ExportedAttributeNode::decode($attributeData['data']); - }, $data['attributes'])); + }, $data['attributes']), + ); } /** diff --git a/src/Dependency/ExportedNode/ExportedTraitNode.php b/src/Dependency/ExportedNode/ExportedTraitNode.php index f45e3efaea4..f90246ad154 100644 --- a/src/Dependency/ExportedNode/ExportedTraitNode.php +++ b/src/Dependency/ExportedNode/ExportedTraitNode.php @@ -10,13 +10,8 @@ class ExportedTraitNode implements RootExportedNode, JsonSerializable { - /** - * @var string - */ - private $traitName; - public function __construct(string $traitName) + public function __construct(private string $traitName) { - $this->traitName = $traitName; } public function equals(ExportedNode $node): bool diff --git a/src/Dependency/ExportedNode/ExportedTraitUseAdaptation.php b/src/Dependency/ExportedNode/ExportedTraitUseAdaptation.php index 786bf4e0289..57f3491010b 100644 --- a/src/Dependency/ExportedNode/ExportedTraitUseAdaptation.php +++ b/src/Dependency/ExportedNode/ExportedTraitUseAdaptation.php @@ -10,48 +10,41 @@ class ExportedTraitUseAdaptation implements ExportedNode, JsonSerializable { /** - * @var ?string - */ - private $traitName; - /** - * @var string - */ - private $method; - /** - * @var ?int - */ - private $newModifier; - /** - * @var ?string - */ - private $newName; - /** - * @var string[]|null - */ - private $insteadOfs; - /** - * @param string[]|null $insteadOfs - */ - private function __construct(?string $traitName, string $method, ?int $newModifier, ?string $newName, ?array $insteadOfs) - { - $this->traitName = $traitName; - $this->method = $method; - $this->newModifier = $newModifier; - $this->newName = $newName; - $this->insteadOfs = $insteadOfs; - } - public static function createAlias(?string $traitName, string $method, ?int $newModifier, ?string $newName) : self - { - return new self($traitName, $method, $newModifier, $newName, null); - } - /** - * @param string[] $insteadOfs - */ - public static function createPrecedence(?string $traitName, string $method, array $insteadOfs) : self - { - return new self($traitName, $method, null, null, $insteadOfs); - } - public function equals(ExportedNode $node): bool + * @param string[]|null $insteadOfs + */ + private function __construct( + private ?string $traitName, + private string $method, + private ?int $newModifier, + private ?string $newName, + private ?array $insteadOfs, + ) + { + } + + public static function createAlias( + ?string $traitName, + string $method, + ?int $newModifier, + ?string $newName, + ): self + { + return new self($traitName, $method, $newModifier, $newName, null); + } + + /** + * @param string[] $insteadOfs + */ + public static function createPrecedence( + ?string $traitName, + string $method, + array $insteadOfs, + ): self + { + return new self($traitName, $method, null, null, $insteadOfs); + } + + public function equals(ExportedNode $node): bool { if (!$node instanceof self) { return false; @@ -65,21 +58,33 @@ public function equals(ExportedNode $node): bool } /** - * @param mixed[] $properties - * @return self - */ - public static function __set_state(array $properties): ExportedNode + * @param mixed[] $properties + * @return self + */ + public static function __set_state(array $properties): ExportedNode { - return new self($properties['traitName'], $properties['method'], $properties['newModifier'], $properties['newName'], $properties['insteadOfs']); + return new self( + $properties['traitName'], + $properties['method'], + $properties['newModifier'], + $properties['newName'], + $properties['insteadOfs'], + ); } /** - * @param mixed[] $data - * @return self - */ - public static function decode(array $data): ExportedNode + * @param mixed[] $data + * @return self + */ + public static function decode(array $data): ExportedNode { - return new self($data['traitName'], $data['method'], $data['newModifier'], $data['newName'], $data['insteadOfs']); + return new self( + $data['traitName'], + $data['method'], + $data['newModifier'], + $data['newName'], + $data['insteadOfs'], + ); } /** diff --git a/src/Dependency/ExportedNodeFetcher.php b/src/Dependency/ExportedNodeFetcher.php index 453f19f5d35..4d562f1275f 100644 --- a/src/Dependency/ExportedNodeFetcher.php +++ b/src/Dependency/ExportedNodeFetcher.php @@ -9,19 +9,13 @@ class ExportedNodeFetcher { - /** - * @var Parser - */ - private $parser; - /** - * @var ExportedNodeVisitor - */ - private $visitor; - public function __construct(Parser $parser, ExportedNodeVisitor $visitor) + public function __construct( + private Parser $parser, + private ExportedNodeVisitor $visitor, + ) { - $this->parser = $parser; - $this->visitor = $visitor; } + /** * @return RootExportedNode[] */ @@ -32,7 +26,7 @@ public function fetchNodes(string $fileName): array try { $ast = $this->parser->parseFile($fileName); - } catch (ParserErrorsException $e) { + } catch (ParserErrorsException) { return []; } $this->visitor->reset($fileName); diff --git a/src/Dependency/ExportedNodeResolver.php b/src/Dependency/ExportedNodeResolver.php index 326207d3e4e..89d532512cb 100644 --- a/src/Dependency/ExportedNodeResolver.php +++ b/src/Dependency/ExportedNodeResolver.php @@ -31,18 +31,8 @@ class ExportedNodeResolver { - /** - * @var FileTypeMapper - */ - private $fileTypeMapper; - /** - * @var ExprPrinter - */ - private $exprPrinter; - public function __construct(FileTypeMapper $fileTypeMapper, ExprPrinter $exprPrinter) + public function __construct(private FileTypeMapper $fileTypeMapper, private ExprPrinter $exprPrinter) { - $this->fileTypeMapper = $fileTypeMapper; - $this->exprPrinter = $exprPrinter; } public function resolve(string $fileName, Node $node): ?RootExportedNode @@ -72,36 +62,65 @@ public function resolve(string $fileName, Node $node): ?RootExportedNode $className = $node->namespacedName->toString(); - return new ExportedClassNode($className, $this->exportPhpDocNode($fileName, $className, null, $docComment !== null ? $docComment->getText() : null), $node->isAbstract(), $node->isFinal(), $extendsName, $implementsNames, $usedTraits, array_map(static function (Node\Stmt\TraitUseAdaptation $adaptation): ExportedTraitUseAdaptation { + return new ExportedClassNode( + $className, + $this->exportPhpDocNode( + $fileName, + $className, + null, + $docComment !== null ? $docComment->getText() : null, + ), + $node->isAbstract(), + $node->isFinal(), + $extendsName, + $implementsNames, + $usedTraits, + array_map(static function (Node\Stmt\TraitUseAdaptation $adaptation): ExportedTraitUseAdaptation { if ($adaptation instanceof Node\Stmt\TraitUseAdaptation\Alias) { - return ExportedTraitUseAdaptation::createAlias($adaptation->trait !== null ? $adaptation->trait->toString() : null, $adaptation->method->toString(), $adaptation->newModifier, $adaptation->newName !== null ? $adaptation->newName->toString() : null); + return ExportedTraitUseAdaptation::createAlias( + $adaptation->trait !== null ? $adaptation->trait->toString() : null, + $adaptation->method->toString(), + $adaptation->newModifier, + $adaptation->newName !== null ? $adaptation->newName->toString() : null, + ); } if ($adaptation instanceof Node\Stmt\TraitUseAdaptation\Precedence) { - return ExportedTraitUseAdaptation::createPrecedence($adaptation->trait !== null ? $adaptation->trait->toString() : null, $adaptation->method->toString(), array_map(static function (Name $name) : string { - return $name->toString(); - }, $adaptation->insteadof)); + return ExportedTraitUseAdaptation::createPrecedence( + $adaptation->trait !== null ? $adaptation->trait->toString() : null, + $adaptation->method->toString(), + array_map(static fn (Name $name): string => $name->toString(), $adaptation->insteadof), + ); } throw new ShouldNotHappenException(); - }, $adaptations), $this->exportClassStatements($node->stmts, $fileName, $className), $this->exportAttributeNodes($node->attrGroups)); + }, $adaptations), + $this->exportClassStatements($node->stmts, $fileName, $className), + $this->exportAttributeNodes($node->attrGroups), + ); } if ($node instanceof Node\Stmt\Interface_ && isset($node->namespacedName)) { - $extendsNames = array_map(static function (Name $name) : string { - return (string) $name; - }, $node->extends); + $extendsNames = array_map(static fn (Name $name): string => (string) $name, $node->extends); $docComment = $node->getDocComment(); $interfaceName = $node->namespacedName->toString(); - return new ExportedInterfaceNode($interfaceName, $this->exportPhpDocNode($fileName, $interfaceName, null, $docComment !== null ? $docComment->getText() : null), $extendsNames, $this->exportClassStatements($node->stmts, $fileName, $interfaceName)); + return new ExportedInterfaceNode( + $interfaceName, + $this->exportPhpDocNode( + $fileName, + $interfaceName, + null, + $docComment !== null ? $docComment->getText() : null, + ), + $extendsNames, + $this->exportClassStatements($node->stmts, $fileName, $interfaceName), + ); } if ($node instanceof Node\Stmt\Enum_ && $node->namespacedName !== null) { - $implementsNames = array_map(static function (Name $name) : string { - return (string) $name; - }, $node->implements); + $implementsNames = array_map(static fn (Name $name): string => (string) $name, $node->implements); $docComment = $node->getDocComment(); $enumName = $node->namespacedName->toString(); @@ -110,7 +129,19 @@ public function resolve(string $fileName, Node $node): ?RootExportedNode $scalarType = $node->scalarType->toString(); } - return new ExportedEnumNode($enumName, $scalarType, $this->exportPhpDocNode($fileName, $enumName, null, $docComment !== null ? $docComment->getText() : null), $implementsNames, $this->exportClassStatements($node->stmts, $fileName, $enumName), $this->exportAttributeNodes($node->attrGroups)); + return new ExportedEnumNode( + $enumName, + $scalarType, + $this->exportPhpDocNode( + $fileName, + $enumName, + null, + $docComment !== null ? $docComment->getText() : null, + ), + $implementsNames, + $this->exportClassStatements($node->stmts, $fileName, $enumName), + $this->exportAttributeNodes($node->attrGroups), + ); } if ($node instanceof Node\Stmt\Trait_ && isset($node->namespacedName)) { @@ -125,7 +156,19 @@ public function resolve(string $fileName, Node $node): ?RootExportedNode $docComment = $node->getDocComment(); - return new ExportedFunctionNode($functionName, $this->exportPhpDocNode($fileName, null, $functionName, $docComment !== null ? $docComment->getText() : null), $node->byRef, $this->printType($node->returnType), $this->exportParameterNodes($node->params), $this->exportAttributeNodes($node->attrGroups)); + return new ExportedFunctionNode( + $functionName, + $this->exportPhpDocNode( + $fileName, + null, + $functionName, + $docComment !== null ? $docComment->getText() : null, + ), + $node->byRef, + $this->printType($node->returnType), + $this->exportParameterNodes($node->params), + $this->exportAttributeNodes($node->attrGroups), + ); } return null; @@ -198,22 +241,43 @@ private function exportParameterNodes(array $params): array $type = new Node\NullableType($type); } } - $nodes[] = new ExportedParameterNode($param->var->name, $this->printType($type), $param->byRef, $param->variadic, $param->default !== null, $this->exportAttributeNodes($param->attrGroups)); + $nodes[] = new ExportedParameterNode( + $param->var->name, + $this->printType($type), + $param->byRef, + $param->variadic, + $param->default !== null, + $this->exportAttributeNodes($param->attrGroups), + ); } return $nodes; } - private function exportPhpDocNode(string $file, ?string $className, ?string $functionName, ?string $text) : ?ExportedPhpDocNode + private function exportPhpDocNode( + string $file, + ?string $className, + ?string $functionName, + ?string $text, + ): ?ExportedPhpDocNode { if ($text === null) { return null; } - $resolvedPhpDocBlock = $this->fileTypeMapper->getResolvedPhpDoc($file, $className, null, $functionName, $text); + + $resolvedPhpDocBlock = $this->fileTypeMapper->getResolvedPhpDoc( + $file, + $className, + null, + $functionName, + $text, + ); + $nameScope = $resolvedPhpDocBlock->getNullableNameScope(); if ($nameScope === null) { return null; } + return new ExportedPhpDocNode($text, $nameScope->getNamespace(), $nameScope->getUses(), $nameScope->getConstUses()); } @@ -243,7 +307,24 @@ private function exportClassStatement(Node\Stmt $node, string $fileName, string $methodName = $node->name->toString(); $docComment = $node->getDocComment(); - return new ExportedMethodNode($methodName, $this->exportPhpDocNode($fileName, $namespacedName, $methodName, $docComment !== null ? $docComment->getText() : null), $node->byRef, $node->isPublic(), $node->isPrivate(), $node->isAbstract(), $node->isFinal(), $node->isStatic(), $this->printType($node->returnType), $this->exportParameterNodes($node->params), $this->exportAttributeNodes($node->attrGroups)); + return new ExportedMethodNode( + $methodName, + $this->exportPhpDocNode( + $fileName, + $namespacedName, + $methodName, + $docComment !== null ? $docComment->getText() : null, + ), + $node->byRef, + $node->isPublic(), + $node->isPrivate(), + $node->isAbstract(), + $node->isFinal(), + $node->isStatic(), + $this->printType($node->returnType), + $this->exportParameterNodes($node->params), + $this->exportAttributeNodes($node->attrGroups), + ); } } @@ -254,9 +335,21 @@ private function exportClassStatement(Node\Stmt $node, string $fileName, string $docComment = $node->getDocComment(); - return new ExportedPropertiesNode(array_map(static function (Node\Stmt\PropertyProperty $prop) : string { - return $prop->name->toString(); - }, $node->props), $this->exportPhpDocNode($fileName, $namespacedName, null, $docComment !== null ? $docComment->getText() : null), $this->printType($node->type), $node->isPublic(), $node->isPrivate(), $node->isStatic(), $node->isReadonly(), $this->exportAttributeNodes($node->attrGroups)); + return new ExportedPropertiesNode( + array_map(static fn (Node\Stmt\PropertyProperty $prop): string => $prop->name->toString(), $node->props), + $this->exportPhpDocNode( + $fileName, + $namespacedName, + null, + $docComment !== null ? $docComment->getText() : null, + ), + $this->printType($node->type), + $node->isPublic(), + $node->isPrivate(), + $node->isStatic(), + $node->isReadonly(), + $this->exportAttributeNodes($node->attrGroups), + ); } if ($node instanceof Node\Stmt\ClassConst) { @@ -268,16 +361,40 @@ private function exportClassStatement(Node\Stmt $node, string $fileName, string $constants = []; foreach ($node->consts as $const) { - $constants[] = new ExportedClassConstantNode($const->name->toString(), $this->exprPrinter->printExpr($const->value), $this->exportAttributeNodes($node->attrGroups)); + $constants[] = new ExportedClassConstantNode( + $const->name->toString(), + $this->exprPrinter->printExpr($const->value), + $this->exportAttributeNodes($node->attrGroups), + ); } - return new ExportedClassConstantsNode($constants, $node->isPublic(), $node->isPrivate(), $node->isFinal(), $this->exportPhpDocNode($fileName, $namespacedName, null, $docComment !== null ? $docComment->getText() : null)); + return new ExportedClassConstantsNode( + $constants, + $node->isPublic(), + $node->isPrivate(), + $node->isFinal(), + $this->exportPhpDocNode( + $fileName, + $namespacedName, + null, + $docComment !== null ? $docComment->getText() : null, + ), + ); } if ($node instanceof Node\Stmt\EnumCase) { $docComment = $node->getDocComment(); - return new ExportedEnumCaseNode($node->name->toString(), $node->expr !== null ? $this->exprPrinter->printExpr($node->expr) : null, $this->exportPhpDocNode($fileName, $namespacedName, null, $docComment !== null ? $docComment->getText() : null)); + return new ExportedEnumCaseNode( + $node->name->toString(), + $node->expr !== null ? $this->exprPrinter->printExpr($node->expr) : null, + $this->exportPhpDocNode( + $fileName, + $namespacedName, + null, + $docComment !== null ? $docComment->getText() : null, + ), + ); } return null; @@ -297,7 +414,10 @@ private function exportAttributeNodes(array $attributeGroups): array $args[$arg->name->name ?? $i] = $this->exprPrinter->printExpr($arg->value); } - $nodes[] = new ExportedAttributeNode($attribute->name->toString(), $args); + $nodes[] = new ExportedAttributeNode( + $attribute->name->toString(), + $args, + ); } } diff --git a/src/Dependency/ExportedNodeVisitor.php b/src/Dependency/ExportedNodeVisitor.php index 200161d0dec..902ca005d63 100644 --- a/src/Dependency/ExportedNodeVisitor.php +++ b/src/Dependency/ExportedNodeVisitor.php @@ -10,25 +10,17 @@ class ExportedNodeVisitor extends NodeVisitorAbstract { - /** - * @var ExportedNodeResolver - */ - private $exportedNodeResolver; - /** - * @var ?string - */ - private $fileName = null; + private ?string $fileName = null; /** @var RootExportedNode[] */ - private $currentNodes = []; + private array $currentNodes = []; /** * ExportedNodeVisitor constructor. * */ - public function __construct(ExportedNodeResolver $exportedNodeResolver) + public function __construct(private ExportedNodeResolver $exportedNodeResolver) { - $this->exportedNodeResolver = $exportedNodeResolver; } public function reset(string $fileName): void diff --git a/src/Dependency/NodeDependencies.php b/src/Dependency/NodeDependencies.php index c58906e98bb..a31a6eeadd5 100644 --- a/src/Dependency/NodeDependencies.php +++ b/src/Dependency/NodeDependencies.php @@ -10,27 +10,17 @@ class NodeDependencies { - /** - * @var FileHelper - */ - private $fileHelper; - /** - * @var array - */ - private $reflections; - /** - * @var ?RootExportedNode - */ - private $exportedNode; /** * @param array $reflections */ - public function __construct(FileHelper $fileHelper, array $reflections, ?RootExportedNode $exportedNode) + public function __construct( + private FileHelper $fileHelper, + private array $reflections, + private ?RootExportedNode $exportedNode, + ) { - $this->fileHelper = $fileHelper; - $this->reflections = $reflections; - $this->exportedNode = $exportedNode; } + /** * @param array $analysedFiles * @return string[] diff --git a/src/DependencyInjection/BleedingEdgeToggle.php b/src/DependencyInjection/BleedingEdgeToggle.php index e143548edfb..f510a64c8d7 100644 --- a/src/DependencyInjection/BleedingEdgeToggle.php +++ b/src/DependencyInjection/BleedingEdgeToggle.php @@ -5,10 +5,7 @@ class BleedingEdgeToggle { - /** - * @var bool - */ - private static $bleedingEdge = false; + private static bool $bleedingEdge = false; public static function isBleedingEdge(): bool { diff --git a/src/DependencyInjection/ConditionalTagsExtension.php b/src/DependencyInjection/ConditionalTagsExtension.php index 0e08c5c59c2..358e673e10f 100644 --- a/src/DependencyInjection/ConditionalTagsExtension.php +++ b/src/DependencyInjection/ConditionalTagsExtension.php @@ -66,9 +66,7 @@ public function beforeCompile(): void foreach ($services as $service) { foreach ($tags as $tag => $parameter) { if (is_array($parameter)) { - $parameter = array_reduce($parameter, static function ($carry, $item) { - return $carry && (bool) $item; - }, true); + $parameter = array_reduce($parameter, static fn ($carry, $item) => $carry && (bool) $item, true); } if ((bool) $parameter) { $service->addTag($tag); diff --git a/src/DependencyInjection/Configurator.php b/src/DependencyInjection/Configurator.php index 03ab000b251..1c8b1e7bc6a 100644 --- a/src/DependencyInjection/Configurator.php +++ b/src/DependencyInjection/Configurator.php @@ -18,16 +18,11 @@ class Configurator extends \Nette\Bootstrap\Configurator { - /** - * @var LoaderFactory - */ - private $loaderFactory; /** @var string[] */ - private $allConfigFiles = []; + private array $allConfigFiles = []; - public function __construct(LoaderFactory $loaderFactory) + public function __construct(private LoaderFactory $loaderFactory) { - $this->loaderFactory = $loaderFactory; parent::__construct(); } @@ -59,9 +54,15 @@ public function getContainerCacheDirectory(): string public function loadContainer(): string { - $loader = new ContainerLoader($this->getContainerCacheDirectory(), $this->staticParameters['debugMode']); - - return $loader->load([$this, 'generateContainer'], [$this->staticParameters, array_keys($this->dynamicParameters), $this->configs, PHP_VERSION_ID - PHP_RELEASE_VERSION, NeonAdapter::CACHE_KEY, $this->getAllConfigFilesHashes()]); + $loader = new ContainerLoader( + $this->getContainerCacheDirectory(), + $this->staticParameters['debugMode'], + ); + + return $loader->load( + [$this, 'generateContainer'], + [$this->staticParameters, array_keys($this->dynamicParameters), $this->configs, PHP_VERSION_ID - PHP_RELEASE_VERSION, NeonAdapter::CACHE_KEY, $this->getAllConfigFilesHashes()], + ); } public function createContainer(bool $initialize = true): OriginalNetteContainer diff --git a/src/DependencyInjection/ContainerFactory.php b/src/DependencyInjection/ContainerFactory.php index a6fad78c805..cb3bf3006a0 100644 --- a/src/DependencyInjection/ContainerFactory.php +++ b/src/DependencyInjection/ContainerFactory.php @@ -59,40 +59,18 @@ class ContainerFactory { - /** - * @var string - */ - private $currentWorkingDirectory; - /** - * @var bool - */ - private $checkDuplicateFiles; - /** - * @var FileHelper - */ - private $fileHelper; + private FileHelper $fileHelper; - /** - * @var string - */ - private $rootDirectory; + private string $rootDirectory; - /** - * @var string - */ - private $configDirectory; + private string $configDirectory; - /** - * @var ?int - */ - private static $lastInitializedContainerId = null; + private static ?int $lastInitializedContainerId = null; /** @api */ - public function __construct(string $currentWorkingDirectory, bool $checkDuplicateFiles = false) + public function __construct(private string $currentWorkingDirectory, private bool $checkDuplicateFiles = false) { - $this->currentWorkingDirectory = $currentWorkingDirectory; - $this->checkDuplicateFiles = $checkDuplicateFiles; - $this->fileHelper = new FileHelper($currentWorkingDirectory); + $this->fileHelper = new FileHelper($currentWorkingDirectory); $rootDir = __DIR__ . '/../..'; $originalRootDir = $this->fileHelper->normalizePath($rootDir); @@ -107,55 +85,76 @@ public function __construct(string $currentWorkingDirectory, bool $checkDuplicat } /** - * @param string[] $additionalConfigFiles - * @param string[] $analysedPaths - * @param string[] $composerAutoloaderProjectPaths - * @param string[] $analysedPathsFromConfig - */ - public function create(string $tempDirectory, array $additionalConfigFiles, array $analysedPaths, array $composerAutoloaderProjectPaths = [], array $analysedPathsFromConfig = [], string $usedLevel = CommandHelper::DEFAULT_LEVEL, ?string $generateBaselineFile = null, ?string $cliAutoloadFile = null) : Container - { - [$allConfigFiles, $projectConfig] = $this->detectDuplicateIncludedFiles(array_merge([__DIR__ . '/../../conf/parametersSchema.neon'], $additionalConfigFiles), [ - 'rootDir' => $this->rootDirectory, - 'currentWorkingDirectory' => $this->currentWorkingDirectory, - 'env' => getenv(), - ]); - $configurator = new Configurator(new LoaderFactory($this->fileHelper, $this->rootDirectory, $this->currentWorkingDirectory, $generateBaselineFile)); - $configurator->defaultExtensions = [ - 'php' => PhpExtension::class, - 'extensions' => ExtensionsExtension::class, - ]; - $configurator->setDebugMode(true); - $configurator->setTempDirectory($tempDirectory); - $configurator->addParameters([ - 'rootDir' => $this->rootDirectory, - 'currentWorkingDirectory' => $this->currentWorkingDirectory, - 'cliArgumentsVariablesRegistered' => ini_get('register_argc_argv') === '1', - 'tmpDir' => $tempDirectory, - 'additionalConfigFiles' => $additionalConfigFiles, - 'allConfigFiles' => $allConfigFiles, - 'composerAutoloaderProjectPaths' => $composerAutoloaderProjectPaths, - 'generateBaselineFile' => $generateBaselineFile, - 'usedLevel' => $usedLevel, - 'cliAutoloadFile' => $cliAutoloadFile, - ]); - $configurator->addDynamicParameters([ - 'analysedPaths' => $analysedPaths, - 'analysedPathsFromConfig' => $analysedPathsFromConfig, - 'env' => getenv(), - ]); - $configurator->addConfig($this->configDirectory . '/config.neon'); - foreach ($additionalConfigFiles as $additionalConfigFile) { - $configurator->addConfig($additionalConfigFile); - } - $configurator->setAllConfigFiles($allConfigFiles); - $container = $configurator->createContainer()->getByType(Container::class); - $this->validateParameters($container->getParameters(), $projectConfig['parametersSchema']); - self::postInitializeContainer($container); - return $container; - } + * @param string[] $additionalConfigFiles + * @param string[] $analysedPaths + * @param string[] $composerAutoloaderProjectPaths + * @param string[] $analysedPathsFromConfig + */ + public function create( + string $tempDirectory, + array $additionalConfigFiles, + array $analysedPaths, + array $composerAutoloaderProjectPaths = [], + array $analysedPathsFromConfig = [], + string $usedLevel = CommandHelper::DEFAULT_LEVEL, + ?string $generateBaselineFile = null, + ?string $cliAutoloadFile = null, + ): Container + { + [$allConfigFiles, $projectConfig] = $this->detectDuplicateIncludedFiles( + array_merge([__DIR__ . '/../../conf/parametersSchema.neon'], $additionalConfigFiles), + [ + 'rootDir' => $this->rootDirectory, + 'currentWorkingDirectory' => $this->currentWorkingDirectory, + 'env' => getenv(), + ], + ); + + $configurator = new Configurator(new LoaderFactory( + $this->fileHelper, + $this->rootDirectory, + $this->currentWorkingDirectory, + $generateBaselineFile, + )); + $configurator->defaultExtensions = [ + 'php' => PhpExtension::class, + 'extensions' => ExtensionsExtension::class, + ]; + $configurator->setDebugMode(true); + $configurator->setTempDirectory($tempDirectory); + $configurator->addParameters([ + 'rootDir' => $this->rootDirectory, + 'currentWorkingDirectory' => $this->currentWorkingDirectory, + 'cliArgumentsVariablesRegistered' => ini_get('register_argc_argv') === '1', + 'tmpDir' => $tempDirectory, + 'additionalConfigFiles' => $additionalConfigFiles, + 'allConfigFiles' => $allConfigFiles, + 'composerAutoloaderProjectPaths' => $composerAutoloaderProjectPaths, + 'generateBaselineFile' => $generateBaselineFile, + 'usedLevel' => $usedLevel, + 'cliAutoloadFile' => $cliAutoloadFile, + ]); + $configurator->addDynamicParameters([ + 'analysedPaths' => $analysedPaths, + 'analysedPathsFromConfig' => $analysedPathsFromConfig, + 'env' => getenv(), + ]); + $configurator->addConfig($this->configDirectory . '/config.neon'); + foreach ($additionalConfigFiles as $additionalConfigFile) { + $configurator->addConfig($additionalConfigFile); + } + + $configurator->setAllConfigFiles($allConfigFiles); + + $container = $configurator->createContainer()->getByType(Container::class); + $this->validateParameters($container->getParameters(), $projectConfig['parametersSchema']); + self::postInitializeContainer($container); + + return $container; + } /** @internal */ - public static function postInitializeContainer(Container $container): void + public static function postInitializeContainer(Container $container): void { $containerId = spl_object_id($container); if ($containerId === self::$lastInitializedContainerId) { @@ -173,7 +172,14 @@ public static function postInitializeContainer(Container $container): void /** @var Parser $phpParser */ $phpParser = $container->getService('phpParserDecorator'); - BetterReflection::populate($container->getByType(PhpVersion::class)->getVersionId(), $sourceLocator, $reflector, $phpParser, $container->getByType(PhpStormStubsSourceStubber::class), $container->getByType(Printer::class)); + BetterReflection::populate( + $container->getByType(PhpVersion::class)->getVersionId(), + $sourceLocator, + $reflector, + $phpParser, + $container->getByType(PhpStormStubsSourceStubber::class), + $container->getByType(Printer::class), + ); $broker = $container->getByType(Broker::class); Broker::registerInstance($broker); @@ -189,7 +195,12 @@ public static function postInitializeContainer(Container $container): void public function clearOldContainers(string $tempDirectory): void { - $configurator = new Configurator(new LoaderFactory($this->fileHelper, $this->rootDirectory, $this->currentWorkingDirectory, null)); + $configurator = new Configurator(new LoaderFactory( + $this->fileHelper, + $this->rootDirectory, + $this->currentWorkingDirectory, + null, + )); $configurator->setDebugMode(true); $configurator->setTempDirectory($tempDirectory); @@ -234,70 +245,85 @@ public function getConfigDirectory(): string } /** - * @param string[] $configFiles - * @param array $loaderParameters - * @return array{list, array} - * @throws DuplicateIncludedFilesException - */ - private function detectDuplicateIncludedFiles(array $configFiles, array $loaderParameters) : array - { - $neonAdapter = new NeonAdapter(); - $phpAdapter = new PhpAdapter(); - $allConfigFiles = []; - $configArray = []; - foreach ($configFiles as $configFile) { - [$tmpConfigFiles, $tmpConfigArray] = self::getConfigFiles($this->fileHelper, $neonAdapter, $phpAdapter, $configFile, $loaderParameters, null); - $allConfigFiles = array_merge($allConfigFiles, $tmpConfigFiles); - - /** @var array $configArray */ - $configArray = \Nette\Schema\Helpers::merge($tmpConfigArray, $configArray); - } - $normalized = array_map(function (string $file) : string { - return $this->fileHelper->normalizePath($file); - }, $allConfigFiles); - $deduplicated = array_unique($normalized); - if (count($normalized) <= count($deduplicated)) { - return [$normalized, $configArray]; - } - if (!$this->checkDuplicateFiles) { - return [$normalized, $configArray]; - } - $duplicateFiles = array_unique(array_diff_key($normalized, $deduplicated)); - throw new DuplicateIncludedFilesException($duplicateFiles); - } + * @param string[] $configFiles + * @param array $loaderParameters + * @return array{list, array} + * @throws DuplicateIncludedFilesException + */ + private function detectDuplicateIncludedFiles( + array $configFiles, + array $loaderParameters, + ): array + { + $neonAdapter = new NeonAdapter(); + $phpAdapter = new PhpAdapter(); + $allConfigFiles = []; + $configArray = []; + foreach ($configFiles as $configFile) { + [$tmpConfigFiles, $tmpConfigArray] = self::getConfigFiles($this->fileHelper, $neonAdapter, $phpAdapter, $configFile, $loaderParameters, null); + $allConfigFiles = array_merge($allConfigFiles, $tmpConfigFiles); + + /** @var array $configArray */ + $configArray = \Nette\Schema\Helpers::merge($tmpConfigArray, $configArray); + } + + $normalized = array_map(fn (string $file): string => $this->fileHelper->normalizePath($file), $allConfigFiles); + + $deduplicated = array_unique($normalized); + if (count($normalized) <= count($deduplicated)) { + return [$normalized, $configArray]; + } + + if (!$this->checkDuplicateFiles) { + return [$normalized, $configArray]; + } + + $duplicateFiles = array_unique(array_diff_key($normalized, $deduplicated)); + + throw new DuplicateIncludedFilesException($duplicateFiles); + } /** - * @param array $loaderParameters - * @return array{list, array} - */ - private static function getConfigFiles(FileHelper $fileHelper, NeonAdapter $neonAdapter, PhpAdapter $phpAdapter, string $configFile, array $loaderParameters, ?string $generateBaselineFile) : array - { - if ($generateBaselineFile === $fileHelper->normalizePath($configFile)) { - return [[], []]; - } - if (!is_file($configFile) || !is_readable($configFile)) { - return [[], []]; - } - if (str_ends_with($configFile, '.php')) { - $data = $phpAdapter->load($configFile); - } else { - $data = $neonAdapter->load($configFile); - } - $allConfigFiles = [$configFile]; - if (isset($data['includes'])) { - Validators::assert($data['includes'], 'list', sprintf("section 'includes' in file '%s'", $configFile)); - $includes = Helpers::expand($data['includes'], $loaderParameters); - foreach ($includes as $include) { - $include = self::expandIncludedFile($include, $configFile); - [$tmpConfigFiles, $tmpConfigArray] = self::getConfigFiles($fileHelper, $neonAdapter, $phpAdapter, $include, $loaderParameters, $generateBaselineFile); - $allConfigFiles = array_merge($allConfigFiles, $tmpConfigFiles); - - /** @var array $data */ - $data = \Nette\Schema\Helpers::merge($tmpConfigArray, $data); - } - } - return [$allConfigFiles, $data]; + * @param array $loaderParameters + * @return array{list, array} + */ + private static function getConfigFiles( + FileHelper $fileHelper, + NeonAdapter $neonAdapter, + PhpAdapter $phpAdapter, + string $configFile, + array $loaderParameters, + ?string $generateBaselineFile, + ): array + { + if ($generateBaselineFile === $fileHelper->normalizePath($configFile)) { + return [[], []]; + } + if (!is_file($configFile) || !is_readable($configFile)) { + return [[], []]; + } + + if (str_ends_with($configFile, '.php')) { + $data = $phpAdapter->load($configFile); + } else { + $data = $neonAdapter->load($configFile); + } + $allConfigFiles = [$configFile]; + if (isset($data['includes'])) { + Validators::assert($data['includes'], 'list', sprintf("section 'includes' in file '%s'", $configFile)); + $includes = Helpers::expand($data['includes'], $loaderParameters); + foreach ($includes as $include) { + $include = self::expandIncludedFile($include, $configFile); + [$tmpConfigFiles, $tmpConfigArray] = self::getConfigFiles($fileHelper, $neonAdapter, $phpAdapter, $include, $loaderParameters, $generateBaselineFile); + $allConfigFiles = array_merge($allConfigFiles, $tmpConfigFiles); + + /** @var array $data */ + $data = \Nette\Schema\Helpers::merge($tmpConfigArray, $data); } + } + + return [$allConfigFiles, $data]; + } private static function expandIncludedFile(string $includedFile, string $mainFile): string { @@ -307,18 +333,20 @@ private static function expandIncludedFile(string $includedFile, string $mainFil } /** - * @param array $parameters - * @param array $parametersSchema - */ - private function validateParameters(array $parameters, array $parametersSchema): void + * @param array $parameters + * @param array $parametersSchema + */ + private function validateParameters(array $parameters, array $parametersSchema): void { if (!(bool) $parameters['__validate']) { return; } - $schema = $this->processArgument(new Statement('schema', [ + $schema = $this->processArgument( + new Statement('schema', [ new Statement('structure', [$parametersSchema]), - ])); + ]), + ); $processor = new Processor(); $processor->onNewContext[] = static function (SchemaContext $context): void { $context->path = ['parameters']; @@ -327,9 +355,9 @@ private function validateParameters(array $parameters, array $parametersSchema): } /** - * @param Statement[] $statements - */ - private function processSchema(array $statements, bool $required = true): Schema + * @param Statement[] $statements + */ + private function processSchema(array $statements, bool $required = true): Schema { if (count($statements) === 0) { throw new ShouldNotHappenException(); @@ -337,9 +365,7 @@ private function processSchema(array $statements, bool $required = true): Schema $parameterSchema = null; foreach ($statements as $statement) { - $processedArguments = array_map(function ($argument) { - return $this->processArgument($argument); - }, $statement->arguments); + $processedArguments = array_map(fn ($argument) => $this->processArgument($argument), $statement->arguments); if ($parameterSchema === null) { /** @var Type|AnyOf|Structure $parameterSchema */ $parameterSchema = Expect::{$statement->getEntity()}(...$processedArguments); @@ -356,10 +382,10 @@ private function processSchema(array $statements, bool $required = true): Schema } /** - * @param mixed $argument - * @return mixed - */ - private function processArgument($argument, bool $required = true) + * @param mixed $argument + * @return mixed + */ + private function processArgument($argument, bool $required = true) { if ($argument instanceof Statement) { if ($argument->entity === 'schema') { diff --git a/src/DependencyInjection/DerivativeContainerFactory.php b/src/DependencyInjection/DerivativeContainerFactory.php index ebcfdf54ea2..48270f714d1 100644 --- a/src/DependencyInjection/DerivativeContainerFactory.php +++ b/src/DependencyInjection/DerivativeContainerFactory.php @@ -7,68 +7,45 @@ class DerivativeContainerFactory { - /** - * @var string - */ - private $currentWorkingDirectory; - /** - * @var string - */ - private $tempDirectory; - /** - * @var string[] - */ - private $additionalConfigFiles; - /** - * @var string[] - */ - private $analysedPaths; - /** - * @var string[] - */ - private $composerAutoloaderProjectPaths; - /** - * @var string[] - */ - private $analysedPathsFromConfig; - /** - * @var string - */ - private $usedLevel; - /** - * @var ?string - */ - private $generateBaselineFile; - /** - * @var ?string - */ - private $cliAutoloadFile; /** * @param string[] $additionalConfigFiles * @param string[] $analysedPaths * @param string[] $composerAutoloaderProjectPaths * @param string[] $analysedPathsFromConfig */ - public function __construct(string $currentWorkingDirectory, string $tempDirectory, array $additionalConfigFiles, array $analysedPaths, array $composerAutoloaderProjectPaths, array $analysedPathsFromConfig, string $usedLevel, ?string $generateBaselineFile, ?string $cliAutoloadFile) + public function __construct( + private string $currentWorkingDirectory, + private string $tempDirectory, + private array $additionalConfigFiles, + private array $analysedPaths, + private array $composerAutoloaderProjectPaths, + private array $analysedPathsFromConfig, + private string $usedLevel, + private ?string $generateBaselineFile, + private ?string $cliAutoloadFile, + ) { - $this->currentWorkingDirectory = $currentWorkingDirectory; - $this->tempDirectory = $tempDirectory; - $this->additionalConfigFiles = $additionalConfigFiles; - $this->analysedPaths = $analysedPaths; - $this->composerAutoloaderProjectPaths = $composerAutoloaderProjectPaths; - $this->analysedPathsFromConfig = $analysedPathsFromConfig; - $this->usedLevel = $usedLevel; - $this->generateBaselineFile = $generateBaselineFile; - $this->cliAutoloadFile = $cliAutoloadFile; } + /** * @param string[] $additionalConfigFiles */ public function create(array $additionalConfigFiles): Container { - $containerFactory = new ContainerFactory($this->currentWorkingDirectory); + $containerFactory = new ContainerFactory( + $this->currentWorkingDirectory, + ); - return $containerFactory->create($this->tempDirectory, array_merge($this->additionalConfigFiles, $additionalConfigFiles), $this->analysedPaths, $this->composerAutoloaderProjectPaths, $this->analysedPathsFromConfig, $this->usedLevel, $this->generateBaselineFile, $this->cliAutoloadFile); + return $containerFactory->create( + $this->tempDirectory, + array_merge($this->additionalConfigFiles, $additionalConfigFiles), + $this->analysedPaths, + $this->composerAutoloaderProjectPaths, + $this->analysedPathsFromConfig, + $this->usedLevel, + $this->generateBaselineFile, + $this->cliAutoloadFile, + ); } } diff --git a/src/DependencyInjection/DuplicateIncludedFilesException.php b/src/DependencyInjection/DuplicateIncludedFilesException.php index 8115ac5757d..13ea681636c 100644 --- a/src/DependencyInjection/DuplicateIncludedFilesException.php +++ b/src/DependencyInjection/DuplicateIncludedFilesException.php @@ -9,16 +9,11 @@ class DuplicateIncludedFilesException extends Exception { - /** - * @var string[] - */ - private $files; /** * @param string[] $files */ - public function __construct(array $files) + public function __construct(private array $files) { - $this->files = $files; parent::__construct(sprintf('These files are included multiple times: %s', implode(', ', $this->files))); } diff --git a/src/DependencyInjection/InvalidIgnoredErrorPatternsException.php b/src/DependencyInjection/InvalidIgnoredErrorPatternsException.php index c0e8dacd1e2..dd9258c64d8 100644 --- a/src/DependencyInjection/InvalidIgnoredErrorPatternsException.php +++ b/src/DependencyInjection/InvalidIgnoredErrorPatternsException.php @@ -8,16 +8,11 @@ class InvalidIgnoredErrorPatternsException extends Exception { - /** - * @var string[] - */ - private $errors; /** * @param string[] $errors */ - public function __construct(array $errors) + public function __construct(private array $errors) { - $this->errors = $errors; parent::__construct(implode("\n", $this->errors)); } diff --git a/src/DependencyInjection/LoaderFactory.php b/src/DependencyInjection/LoaderFactory.php index 80c26333c47..600fede4351 100644 --- a/src/DependencyInjection/LoaderFactory.php +++ b/src/DependencyInjection/LoaderFactory.php @@ -9,29 +9,15 @@ class LoaderFactory { - /** - * @var FileHelper - */ - private $fileHelper; - /** - * @var string - */ - private $rootDir; - /** - * @var string - */ - private $currentWorkingDirectory; - /** - * @var ?string - */ - private $generateBaselineFile; - public function __construct(FileHelper $fileHelper, string $rootDir, string $currentWorkingDirectory, ?string $generateBaselineFile) + public function __construct( + private FileHelper $fileHelper, + private string $rootDir, + private string $currentWorkingDirectory, + private ?string $generateBaselineFile, + ) { - $this->fileHelper = $fileHelper; - $this->rootDir = $rootDir; - $this->currentWorkingDirectory = $currentWorkingDirectory; - $this->generateBaselineFile = $generateBaselineFile; } + public function createLoader(): Loader { $loader = new NeonLoader($this->fileHelper, $this->generateBaselineFile); diff --git a/src/DependencyInjection/MemoizingContainer.php b/src/DependencyInjection/MemoizingContainer.php index 4db3a5c6a0c..07e92fbac52 100644 --- a/src/DependencyInjection/MemoizingContainer.php +++ b/src/DependencyInjection/MemoizingContainer.php @@ -7,16 +7,11 @@ class MemoizingContainer implements Container { - /** - * @var Container - */ - private $originalContainer; /** @var array */ - private $servicesByType = []; + private array $servicesByType = []; - public function __construct(Container $originalContainer) + public function __construct(private Container $originalContainer) { - $this->originalContainer = $originalContainer; } public function hasService(string $serviceName): bool diff --git a/src/DependencyInjection/NeonAdapter.php b/src/DependencyInjection/NeonAdapter.php index 47df973bd7a..a0aac143fd6 100644 --- a/src/DependencyInjection/NeonAdapter.php +++ b/src/DependencyInjection/NeonAdapter.php @@ -34,7 +34,7 @@ class NeonAdapter implements Adapter private const PREVENT_MERGING_SUFFIX = '!'; /** @var FileHelper[] */ - private $fileHelpers = []; + private array $fileHelpers = []; /** * @return mixed[] @@ -82,7 +82,10 @@ public function process(array $arr, string $fileKey, string $file): array if ($val->value === Neon::CHAIN) { $tmp = null; foreach ($this->process($val->attributes, $fileKeyToPass, $file) as $st) { - $tmp = new Statement($tmp === null ? $st->getEntity() : [$tmp, ltrim(implode('::', (array) $st->getEntity()), ':')], $st->arguments); + $tmp = new Statement( + $tmp === null ? $st->getEntity() : [$tmp, ltrim(implode('::', (array) $st->getEntity()), ':')], + $st->arguments, + ); } $val = $tmp; } else { @@ -142,35 +145,44 @@ public function process(array $arr, string $fileKey, string $file): array */ public function dump(array $data): string { - array_walk_recursive($data, static function (&$val): void { + array_walk_recursive( + $data, + static function (&$val): void { if (!($val instanceof Statement)) { return; } $val = self::statementToEntity($val); - }); + }, + ); return "# generated by Nette\n\n" . Neon::encode($data, Neon::BLOCK); } private static function statementToEntity(Statement $val): Entity { - array_walk_recursive($val->arguments, static function (&$val): void { + array_walk_recursive( + $val->arguments, + static function (&$val): void { if ($val instanceof Statement) { $val = self::statementToEntity($val); } elseif ($val instanceof Reference) { $val = '@' . $val->getValue(); } - }); + }, + ); $entity = $val->getEntity(); if ($entity instanceof Reference) { $entity = '@' . $entity->getValue(); } elseif (is_array($entity)) { if ($entity[0] instanceof Statement) { - return new Entity(Neon::CHAIN, [ + return new Entity( + Neon::CHAIN, + [ self::statementToEntity($entity[0]), new Entity('::' . $entity[1], $val->arguments), - ]); + ], + ); } elseif ($entity[0] instanceof Reference) { $entity = '@' . $entity[0]->getValue() . '::' . $entity[1]; } elseif (is_string($entity[0])) { diff --git a/src/DependencyInjection/NeonLoader.php b/src/DependencyInjection/NeonLoader.php index 33d0833738a..4f797d1af76 100644 --- a/src/DependencyInjection/NeonLoader.php +++ b/src/DependencyInjection/NeonLoader.php @@ -8,19 +8,13 @@ class NeonLoader extends Loader { - /** - * @var FileHelper - */ - private $fileHelper; - /** - * @var ?string - */ - private $generateBaselineFile; - public function __construct(FileHelper $fileHelper, ?string $generateBaselineFile) + public function __construct( + private FileHelper $fileHelper, + private ?string $generateBaselineFile, + ) { - $this->fileHelper = $fileHelper; - $this->generateBaselineFile = $generateBaselineFile; } + /** * @return mixed[] */ diff --git a/src/DependencyInjection/Nette/NetteContainer.php b/src/DependencyInjection/Nette/NetteContainer.php index f36714c92a1..b5e488ca323 100644 --- a/src/DependencyInjection/Nette/NetteContainer.php +++ b/src/DependencyInjection/Nette/NetteContainer.php @@ -14,13 +14,8 @@ class NetteContainer implements Container { - /** - * @var \Nette\DI\Container - */ - private $container; - public function __construct(\Nette\DI\Container $container) + public function __construct(private \Nette\DI\Container $container) { - $this->container = $container; } public function hasService(string $serviceName): bool @@ -95,9 +90,7 @@ public function getParameter(string $parameterName) */ private function tagsToServices(array $tags): array { - return array_map(function (string $serviceName) { - return $this->getService($serviceName); - }, array_keys($tags)); + return array_map(fn (string $serviceName) => $this->getService($serviceName), array_keys($tags)); } } diff --git a/src/DependencyInjection/Reflection/LazyClassReflectionExtensionRegistryProvider.php b/src/DependencyInjection/Reflection/LazyClassReflectionExtensionRegistryProvider.php index a2aa79ab479..899b9153d40 100644 --- a/src/DependencyInjection/Reflection/LazyClassReflectionExtensionRegistryProvider.php +++ b/src/DependencyInjection/Reflection/LazyClassReflectionExtensionRegistryProvider.php @@ -16,18 +16,10 @@ class LazyClassReflectionExtensionRegistryProvider implements ClassReflectionExtensionRegistryProvider { - /** - * @var Container - */ - private $container; - /** - * @var ?ClassReflectionExtensionRegistry - */ - private $registry = null; - - public function __construct(Container $container) + private ?ClassReflectionExtensionRegistry $registry = null; + + public function __construct(private Container $container) { - $this->container = $container; } public function getRegistry(): ClassReflectionExtensionRegistry @@ -37,7 +29,14 @@ public function getRegistry(): ClassReflectionExtensionRegistry $annotationsMethodsClassReflectionExtension = $this->container->getByType(AnnotationsMethodsClassReflectionExtension::class); $annotationsPropertiesClassReflectionExtension = $this->container->getByType(AnnotationsPropertiesClassReflectionExtension::class); - $this->registry = new ClassReflectionExtensionRegistry($this->container->getByType(Broker::class), array_merge([$phpClassReflectionExtension], $this->container->getServicesByTag(BrokerFactory::PROPERTIES_CLASS_REFLECTION_EXTENSION_TAG), [$annotationsPropertiesClassReflectionExtension]), array_merge([$phpClassReflectionExtension], $this->container->getServicesByTag(BrokerFactory::METHODS_CLASS_REFLECTION_EXTENSION_TAG), [$annotationsMethodsClassReflectionExtension]), $this->container->getServicesByTag(BrokerFactory::ALLOWED_SUB_TYPES_CLASS_REFLECTION_EXTENSION_TAG), $this->container->getByType(RequireExtendsPropertiesClassReflectionExtension::class), $this->container->getByType(RequireExtendsMethodsClassReflectionExtension::class)); + $this->registry = new ClassReflectionExtensionRegistry( + $this->container->getByType(Broker::class), + array_merge([$phpClassReflectionExtension], $this->container->getServicesByTag(BrokerFactory::PROPERTIES_CLASS_REFLECTION_EXTENSION_TAG), [$annotationsPropertiesClassReflectionExtension]), + array_merge([$phpClassReflectionExtension], $this->container->getServicesByTag(BrokerFactory::METHODS_CLASS_REFLECTION_EXTENSION_TAG), [$annotationsMethodsClassReflectionExtension]), + $this->container->getServicesByTag(BrokerFactory::ALLOWED_SUB_TYPES_CLASS_REFLECTION_EXTENSION_TAG), + $this->container->getByType(RequireExtendsPropertiesClassReflectionExtension::class), + $this->container->getByType(RequireExtendsMethodsClassReflectionExtension::class), + ); } return $this->registry; diff --git a/src/DependencyInjection/Type/LazyDynamicReturnTypeExtensionRegistryProvider.php b/src/DependencyInjection/Type/LazyDynamicReturnTypeExtensionRegistryProvider.php index c3416a4c048..f992ad9ddf5 100644 --- a/src/DependencyInjection/Type/LazyDynamicReturnTypeExtensionRegistryProvider.php +++ b/src/DependencyInjection/Type/LazyDynamicReturnTypeExtensionRegistryProvider.php @@ -11,24 +11,22 @@ class LazyDynamicReturnTypeExtensionRegistryProvider implements DynamicReturnTypeExtensionRegistryProvider { - /** - * @var Container - */ - private $container; - /** - * @var ?DynamicReturnTypeExtensionRegistry - */ - private $registry = null; - - public function __construct(Container $container) + private ?DynamicReturnTypeExtensionRegistry $registry = null; + + public function __construct(private Container $container) { - $this->container = $container; } public function getRegistry(): DynamicReturnTypeExtensionRegistry { if ($this->registry === null) { - $this->registry = new DynamicReturnTypeExtensionRegistry($this->container->getByType(Broker::class), $this->container->getByType(ReflectionProvider::class), $this->container->getServicesByTag(BrokerFactory::DYNAMIC_METHOD_RETURN_TYPE_EXTENSION_TAG), $this->container->getServicesByTag(BrokerFactory::DYNAMIC_STATIC_METHOD_RETURN_TYPE_EXTENSION_TAG), $this->container->getServicesByTag(BrokerFactory::DYNAMIC_FUNCTION_RETURN_TYPE_EXTENSION_TAG)); + $this->registry = new DynamicReturnTypeExtensionRegistry( + $this->container->getByType(Broker::class), + $this->container->getByType(ReflectionProvider::class), + $this->container->getServicesByTag(BrokerFactory::DYNAMIC_METHOD_RETURN_TYPE_EXTENSION_TAG), + $this->container->getServicesByTag(BrokerFactory::DYNAMIC_STATIC_METHOD_RETURN_TYPE_EXTENSION_TAG), + $this->container->getServicesByTag(BrokerFactory::DYNAMIC_FUNCTION_RETURN_TYPE_EXTENSION_TAG), + ); } return $this->registry; diff --git a/src/DependencyInjection/Type/LazyDynamicThrowTypeExtensionProvider.php b/src/DependencyInjection/Type/LazyDynamicThrowTypeExtensionProvider.php index b913d1b6502..4696fb8b217 100644 --- a/src/DependencyInjection/Type/LazyDynamicThrowTypeExtensionProvider.php +++ b/src/DependencyInjection/Type/LazyDynamicThrowTypeExtensionProvider.php @@ -7,17 +7,12 @@ class LazyDynamicThrowTypeExtensionProvider implements DynamicThrowTypeExtensionProvider { - /** - * @var Container - */ - private $container; public const FUNCTION_TAG = 'phpstan.dynamicFunctionThrowTypeExtension'; public const METHOD_TAG = 'phpstan.dynamicMethodThrowTypeExtension'; public const STATIC_METHOD_TAG = 'phpstan.dynamicStaticMethodThrowTypeExtension'; - public function __construct(Container $container) + public function __construct(private Container $container) { - $this->container = $container; } public function getDynamicFunctionThrowTypeExtensions(): array diff --git a/src/DependencyInjection/Type/LazyExpressionTypeResolverExtensionRegistryProvider.php b/src/DependencyInjection/Type/LazyExpressionTypeResolverExtensionRegistryProvider.php index 96e65c1c77a..43910f86688 100644 --- a/src/DependencyInjection/Type/LazyExpressionTypeResolverExtensionRegistryProvider.php +++ b/src/DependencyInjection/Type/LazyExpressionTypeResolverExtensionRegistryProvider.php @@ -9,24 +9,18 @@ class LazyExpressionTypeResolverExtensionRegistryProvider implements ExpressionTypeResolverExtensionRegistryProvider { - /** - * @var Container - */ - private $container; - /** - * @var ?ExpressionTypeResolverExtensionRegistry - */ - private $registry = null; - - public function __construct(Container $container) + private ?ExpressionTypeResolverExtensionRegistry $registry = null; + + public function __construct(private Container $container) { - $this->container = $container; } public function getRegistry(): ExpressionTypeResolverExtensionRegistry { if ($this->registry === null) { - $this->registry = new ExpressionTypeResolverExtensionRegistry($this->container->getServicesByTag(BrokerFactory::EXPRESSION_TYPE_RESOLVER_EXTENSION_TAG)); + $this->registry = new ExpressionTypeResolverExtensionRegistry( + $this->container->getServicesByTag(BrokerFactory::EXPRESSION_TYPE_RESOLVER_EXTENSION_TAG), + ); } return $this->registry; diff --git a/src/DependencyInjection/Type/LazyOperatorTypeSpecifyingExtensionRegistryProvider.php b/src/DependencyInjection/Type/LazyOperatorTypeSpecifyingExtensionRegistryProvider.php index 3aed0af464d..22e356fe70f 100644 --- a/src/DependencyInjection/Type/LazyOperatorTypeSpecifyingExtensionRegistryProvider.php +++ b/src/DependencyInjection/Type/LazyOperatorTypeSpecifyingExtensionRegistryProvider.php @@ -10,24 +10,19 @@ class LazyOperatorTypeSpecifyingExtensionRegistryProvider implements OperatorTypeSpecifyingExtensionRegistryProvider { - /** - * @var Container - */ - private $container; - /** - * @var ?OperatorTypeSpecifyingExtensionRegistry - */ - private $registry = null; - - public function __construct(Container $container) + private ?OperatorTypeSpecifyingExtensionRegistry $registry = null; + + public function __construct(private Container $container) { - $this->container = $container; } public function getRegistry(): OperatorTypeSpecifyingExtensionRegistry { if ($this->registry === null) { - $this->registry = new OperatorTypeSpecifyingExtensionRegistry($this->container->getByType(Broker::class), $this->container->getServicesByTag(BrokerFactory::OPERATOR_TYPE_SPECIFYING_EXTENSION_TAG)); + $this->registry = new OperatorTypeSpecifyingExtensionRegistry( + $this->container->getByType(Broker::class), + $this->container->getServicesByTag(BrokerFactory::OPERATOR_TYPE_SPECIFYING_EXTENSION_TAG), + ); } return $this->registry; diff --git a/src/DependencyInjection/ValidateIgnoredErrorsExtension.php b/src/DependencyInjection/ValidateIgnoredErrorsExtension.php index 5705cc3f190..5432fc0eecf 100644 --- a/src/DependencyInjection/ValidateIgnoredErrorsExtension.php +++ b/src/DependencyInjection/ValidateIgnoredErrorsExtension.php @@ -62,14 +62,24 @@ public function loadConfiguration(): void ReflectionProviderStaticAccessor::registerInstance($reflectionProvider); PhpVersionStaticAccessor::registerInstance(new PhpVersion(PHP_VERSION_ID)); $constantResolver = new ConstantResolver($reflectionProviderProvider, []); - $ignoredRegexValidator = new IgnoredRegexValidator($parser, new TypeStringResolver(new Lexer(), new TypeParser(new ConstExprParser($builder->parameters['featureToggles']['unescapeStrings'])), new TypeNodeResolver(new DirectTypeNodeResolverExtensionRegistryProvider(new class implements TypeNodeResolverExtensionRegistry { + $ignoredRegexValidator = new IgnoredRegexValidator( + $parser, + new TypeStringResolver( + new Lexer(), + new TypeParser(new ConstExprParser($builder->parameters['featureToggles']['unescapeStrings'])), + new TypeNodeResolver( + new DirectTypeNodeResolverExtensionRegistryProvider( + new class implements TypeNodeResolverExtensionRegistry { public function getExtensions(): array { return []; } - }), $reflectionProviderProvider, new DirectTypeAliasResolverProvider(new class implements TypeAliasResolver { + }, + ), + $reflectionProviderProvider, + new DirectTypeAliasResolverProvider(new class implements TypeAliasResolver { public function hasTypeAlias(string $aliasName, ?string $classNameScope): bool { @@ -81,14 +91,19 @@ public function resolveTypeAlias(string $aliasName, NameScope $nameScope): ?Type return null; } - }), $constantResolver, new InitializerExprTypeResolver($constantResolver, $reflectionProviderProvider, new PhpVersion(PHP_VERSION_ID), new class implements OperatorTypeSpecifyingExtensionRegistryProvider { + }), + $constantResolver, + new InitializerExprTypeResolver($constantResolver, $reflectionProviderProvider, new PhpVersion(PHP_VERSION_ID), new class implements OperatorTypeSpecifyingExtensionRegistryProvider { public function getRegistry(): OperatorTypeSpecifyingExtensionRegistry { return new OperatorTypeSpecifyingExtensionRegistry(null, []); } - }, new OversizedArrayBuilder())))); + }, new OversizedArrayBuilder()), + ), + ), + ); $errors = []; foreach ($ignoreErrors as $ignoreError) { @@ -151,9 +166,14 @@ private function validateMessage(IgnoredRegexValidator $ignoredRegexValidator, s */ private function createIgnoredTypesError(string $regex, array $ignoredTypes): string { - return sprintf("Ignored error %s has an unescaped '|' which leads to ignoring more errors than intended. Use '\\|' instead.\n%s", $regex, sprintf("It ignores all errors containing the following types:\n%s", implode("\n", array_map(static function (string $typeDescription) : string { - return sprintf('* %s', $typeDescription); - }, array_keys($ignoredTypes))))); + return sprintf( + "Ignored error %s has an unescaped '|' which leads to ignoring more errors than intended. Use '\\|' instead.\n%s", + $regex, + sprintf( + "It ignores all errors containing the following types:\n%s", + implode("\n", array_map(static fn (string $typeDescription): string => sprintf('* %s', $typeDescription), array_keys($ignoredTypes))), + ), + ); } private function createAnchorInTheMiddleError(string $regex): string diff --git a/src/File/FileExcluder.php b/src/File/FileExcluder.php index 1ef979a9cf8..2ea5271d5dd 100644 --- a/src/File/FileExcluder.php +++ b/src/File/FileExcluder.php @@ -19,23 +19,23 @@ class FileExcluder * * @var string[] */ - private $literalAnalyseExcludes = []; + private array $literalAnalyseExcludes = []; /** * fnmatch() patterns to use for excluding files and directories from analysing * @var string[] */ - private $fnmatchAnalyseExcludes = []; + private array $fnmatchAnalyseExcludes = []; - /** - * @var int - */ - private $fnmatchFlags; + private int $fnmatchFlags; /** * @param string[] $analyseExcludes */ - public function __construct(FileHelper $fileHelper, array $analyseExcludes) + public function __construct( + FileHelper $fileHelper, + array $analyseExcludes, + ) { foreach ($analyseExcludes as $exclude) { $len = strlen($exclude); @@ -53,6 +53,7 @@ public function __construct(FileHelper $fileHelper, array $analyseExcludes) $this->literalAnalyseExcludes[] = $fileHelper->absolutizePath($normalized); } } + $isWindows = DIRECTORY_SEPARATOR === '\\'; if ($isWindows) { $this->fnmatchFlags = FNM_NOESCAPE | FNM_CASEFOLD; diff --git a/src/File/FileExcluderFactory.php b/src/File/FileExcluderFactory.php index 25b91fb0420..26976a3dfbd 100644 --- a/src/File/FileExcluderFactory.php +++ b/src/File/FileExcluderFactory.php @@ -10,28 +10,18 @@ class FileExcluderFactory { - /** - * @var FileExcluderRawFactory - */ - private $fileExcluderRawFactory; - /** - * @var string[] - */ - private $obsoleteExcludesAnalyse; - /** - * @var array{analyse?: array, analyseAndScan?: array}|null - */ - private $excludePaths; /** * @param string[] $obsoleteExcludesAnalyse * @param array{analyse?: array, analyseAndScan?: array}|null $excludePaths */ - public function __construct(FileExcluderRawFactory $fileExcluderRawFactory, array $obsoleteExcludesAnalyse, ?array $excludePaths) + public function __construct( + private FileExcluderRawFactory $fileExcluderRawFactory, + private array $obsoleteExcludesAnalyse, + private ?array $excludePaths, + ) { - $this->fileExcluderRawFactory = $fileExcluderRawFactory; - $this->obsoleteExcludesAnalyse = $obsoleteExcludesAnalyse; - $this->excludePaths = $excludePaths; } + public function createAnalyseFileExcluder(): FileExcluder { if ($this->excludePaths === null) { diff --git a/src/File/FileExcluderRawFactory.php b/src/File/FileExcluderRawFactory.php index 0e4245891a5..0e3550cb3a2 100644 --- a/src/File/FileExcluderRawFactory.php +++ b/src/File/FileExcluderRawFactory.php @@ -8,6 +8,8 @@ interface FileExcluderRawFactory /** * @param string[] $analyseExcludes */ - public function create(array $analyseExcludes) : FileExcluder; + public function create( + array $analyseExcludes, + ): FileExcluder; } diff --git a/src/File/FileFinder.php b/src/File/FileFinder.php index c822d535133..6ca9db6dddc 100644 --- a/src/File/FileFinder.php +++ b/src/File/FileFinder.php @@ -13,27 +13,17 @@ class FileFinder { - /** - * @var FileExcluder - */ - private $fileExcluder; - /** - * @var FileHelper - */ - private $fileHelper; - /** - * @var string[] - */ - private $fileExtensions; /** * @param string[] $fileExtensions */ - public function __construct(FileExcluder $fileExcluder, FileHelper $fileHelper, array $fileExtensions) + public function __construct( + private FileExcluder $fileExcluder, + private FileHelper $fileHelper, + private array $fileExtensions, + ) { - $this->fileExcluder = $fileExcluder; - $this->fileHelper = $fileHelper; - $this->fileExtensions = $fileExtensions; } + /** * @param string[] $paths */ @@ -56,9 +46,7 @@ public function findFiles(array $paths): FileFinderResult } } - $files = array_values(array_unique(array_filter($files, function (string $file) : bool { - return !$this->fileExcluder->isExcludedFromAnalysing($file); - }))); + $files = array_values(array_unique(array_filter($files, fn (string $file): bool => !$this->fileExcluder->isExcludedFromAnalysing($file)))); return new FileFinderResult($files, $onlyFiles); } diff --git a/src/File/FileFinderResult.php b/src/File/FileFinderResult.php index e7d15ccc168..d88bcbb84ce 100644 --- a/src/File/FileFinderResult.php +++ b/src/File/FileFinderResult.php @@ -5,21 +5,11 @@ class FileFinderResult { - /** - * @var string[] - */ - private $files; - /** - * @var bool - */ - private $onlyFiles; /** * @param string[] $files */ - public function __construct(array $files, bool $onlyFiles) + public function __construct(private array $files, private bool $onlyFiles) { - $this->files = $files; - $this->onlyFiles = $onlyFiles; } /** diff --git a/src/File/FileHelper.php b/src/File/FileHelper.php index 620dbb730b0..33f4878cb41 100644 --- a/src/File/FileHelper.php +++ b/src/File/FileHelper.php @@ -20,10 +20,7 @@ class FileHelper { - /** - * @var string - */ - private $workingDirectory; + private string $workingDirectory; public function __construct(string $workingDirectory) { diff --git a/src/File/FileMonitor.php b/src/File/FileMonitor.php index 03684fd721f..26e27454ff7 100644 --- a/src/File/FileMonitor.php +++ b/src/File/FileMonitor.php @@ -11,19 +11,14 @@ class FileMonitor { - /** - * @var FileFinder - */ - private $fileFinder; /** @var array|null */ - private $fileHashes = null; + private ?array $fileHashes = null; /** @var array|null */ - private $paths = null; + private ?array $paths = null; - public function __construct(FileFinder $fileFinder) + public function __construct(private FileFinder $fileFinder) { - $this->fileFinder = $fileFinder; } /** @@ -76,7 +71,12 @@ public function getChanges(): FileMonitorResult $deletedFiles[] = $file; } - return new FileMonitorResult($newFiles, $changedFiles, $deletedFiles, count($fileHashes)); + return new FileMonitorResult( + $newFiles, + $changedFiles, + $deletedFiles, + count($fileHashes), + ); } private function getFileHash(string $filePath): string diff --git a/src/File/FileMonitorResult.php b/src/File/FileMonitorResult.php index fdbf93587a7..940c21e965e 100644 --- a/src/File/FileMonitorResult.php +++ b/src/File/FileMonitorResult.php @@ -7,34 +7,20 @@ class FileMonitorResult { - /** - * @var string[] - */ - private $newFiles; - /** - * @var string[] - */ - private $changedFiles; - /** - * @var string[] - */ - private $deletedFiles; - /** - * @var int - */ - private $totalFilesCount; /** * @param string[] $newFiles * @param string[] $changedFiles * @param string[] $deletedFiles */ - public function __construct(array $newFiles, array $changedFiles, array $deletedFiles, int $totalFilesCount) + public function __construct( + private array $newFiles, + private array $changedFiles, + private array $deletedFiles, + private int $totalFilesCount, + ) { - $this->newFiles = $newFiles; - $this->changedFiles = $changedFiles; - $this->deletedFiles = $deletedFiles; - $this->totalFilesCount = $totalFilesCount; } + /** * @return string[] */ diff --git a/src/File/FileWriter.php b/src/File/FileWriter.php index 1f8041f049e..2a40c35bb1c 100644 --- a/src/File/FileWriter.php +++ b/src/File/FileWriter.php @@ -14,7 +14,10 @@ public static function write(string $fileName, string $contents): void if ($success === false) { $error = error_get_last(); - throw new CouldNotWriteFileException($fileName, $error !== null ? $error['message'] : 'unknown cause'); + throw new CouldNotWriteFileException( + $fileName, + $error !== null ? $error['message'] : 'unknown cause', + ); } } diff --git a/src/File/FuzzyRelativePathHelper.php b/src/File/FuzzyRelativePathHelper.php index 8a6f578e54a..3654c10c081 100644 --- a/src/File/FuzzyRelativePathHelper.php +++ b/src/File/FuzzyRelativePathHelper.php @@ -17,93 +17,92 @@ class FuzzyRelativePathHelper implements RelativePathHelper { - /** - * @var RelativePathHelper - */ - private $fallbackRelativePathHelper; - /** - * @var string - */ - private $directorySeparator; + private string $directorySeparator; - /** - * @var ?string - */ - private $pathToTrim = null; + private ?string $pathToTrim = null; /** - * @param string[] $analysedPaths - * @param non-empty-string|null $directorySeparator - */ - public function __construct(RelativePathHelper $fallbackRelativePathHelper, string $currentWorkingDirectory, array $analysedPaths, ?string $directorySeparator = null) - { - $this->fallbackRelativePathHelper = $fallbackRelativePathHelper; - if ($directorySeparator === null) { - $directorySeparator = DIRECTORY_SEPARATOR; - } - $this->directorySeparator = $directorySeparator; - $pathBeginning = null; - $pathToTrimArray = null; - $trimBeginning = static function (string $path): array { - if (substr($path, 0, 1) === '/') { - return [ - '/', - substr($path, 1), - ]; - } elseif (substr($path, 1, 1) === ':') { - return [ - substr($path, 0, 3), - substr($path, 3), - ]; - } - - return ['', $path]; - }; - if ( - !in_array($currentWorkingDirectory, ['', '/'], true) - && !(strlen($currentWorkingDirectory) === 3 && substr($currentWorkingDirectory, 1, 1) === ':') - ) { - [$pathBeginning, $currentWorkingDirectory] = $trimBeginning($currentWorkingDirectory); - - $pathToTrimArray = explode($directorySeparator, $currentWorkingDirectory); - } - foreach ($analysedPaths as $pathNumber => $path) { - [$tempPathBeginning, $path] = $trimBeginning($path); - - $pathArray = explode($directorySeparator, $path); - $pathTempParts = []; - $pathArraySize = count($pathArray); - foreach ($pathArray as $i => $pathPart) { - if ($i === $pathArraySize - 1 && str_ends_with($pathPart, '.php')) { - continue; - } - if (!isset($pathToTrimArray[$i])) { - if ($pathNumber !== 0) { - $pathToTrimArray = $pathTempParts; - continue 2; - } - } elseif ($pathToTrimArray[$i] !== $pathPart) { - $pathToTrimArray = $pathTempParts; - continue 2; - } - - $pathTempParts[] = $pathPart; - } - - $pathBeginning = $tempPathBeginning; - $pathToTrimArray = $pathTempParts; - } - if ($pathToTrimArray === null || count($pathToTrimArray) === 0) { - return; - } - $pathToTrim = $pathBeginning . implode($directorySeparator, $pathToTrimArray); - $realPathToTrim = realpath($pathToTrim); - if ($realPathToTrim !== false) { - $pathToTrim = $realPathToTrim; - } - $this->pathToTrim = $pathToTrim; + * @param string[] $analysedPaths + * @param non-empty-string|null $directorySeparator + */ + public function __construct( + private RelativePathHelper $fallbackRelativePathHelper, + string $currentWorkingDirectory, + array $analysedPaths, + ?string $directorySeparator = null, + ) + { + if ($directorySeparator === null) { + $directorySeparator = DIRECTORY_SEPARATOR; + } + + $this->directorySeparator = $directorySeparator; + $pathBeginning = null; + $pathToTrimArray = null; + $trimBeginning = static function (string $path): array { + if (substr($path, 0, 1) === '/') { + return [ + '/', + substr($path, 1), + ]; + } elseif (substr($path, 1, 1) === ':') { + return [ + substr($path, 0, 3), + substr($path, 3), + ]; + } + + return ['', $path]; + }; + + if ( + !in_array($currentWorkingDirectory, ['', '/'], true) + && !(strlen($currentWorkingDirectory) === 3 && substr($currentWorkingDirectory, 1, 1) === ':') + ) { + [$pathBeginning, $currentWorkingDirectory] = $trimBeginning($currentWorkingDirectory); + + $pathToTrimArray = explode($directorySeparator, $currentWorkingDirectory); + } + foreach ($analysedPaths as $pathNumber => $path) { + [$tempPathBeginning, $path] = $trimBeginning($path); + + $pathArray = explode($directorySeparator, $path); + $pathTempParts = []; + $pathArraySize = count($pathArray); + foreach ($pathArray as $i => $pathPart) { + if ($i === $pathArraySize - 1 && str_ends_with($pathPart, '.php')) { + continue; + } + if (!isset($pathToTrimArray[$i])) { + if ($pathNumber !== 0) { + $pathToTrimArray = $pathTempParts; + continue 2; + } + } elseif ($pathToTrimArray[$i] !== $pathPart) { + $pathToTrimArray = $pathTempParts; + continue 2; + } + + $pathTempParts[] = $pathPart; } + $pathBeginning = $tempPathBeginning; + $pathToTrimArray = $pathTempParts; + } + + if ($pathToTrimArray === null || count($pathToTrimArray) === 0) { + return; + } + + $pathToTrim = $pathBeginning . implode($directorySeparator, $pathToTrimArray); + $realPathToTrim = realpath($pathToTrim); + if ($realPathToTrim !== false) { + $pathToTrim = $realPathToTrim; + } + + $this->pathToTrim = $pathToTrim; + } + public function getRelativePath(string $filename): string { if ( diff --git a/src/File/ParentDirectoryRelativePathHelper.php b/src/File/ParentDirectoryRelativePathHelper.php index e688629fb04..218d4597fca 100644 --- a/src/File/ParentDirectoryRelativePathHelper.php +++ b/src/File/ParentDirectoryRelativePathHelper.php @@ -17,13 +17,8 @@ class ParentDirectoryRelativePathHelper implements RelativePathHelper { - /** - * @var string - */ - private $parentDirectory; - public function __construct(string $parentDirectory) + public function __construct(private string $parentDirectory) { - $this->parentDirectory = $parentDirectory; } public function getRelativePath(string $filename): string diff --git a/src/File/PathNotFoundException.php b/src/File/PathNotFoundException.php index 87becc49bd7..fb8f4dd1911 100644 --- a/src/File/PathNotFoundException.php +++ b/src/File/PathNotFoundException.php @@ -8,13 +8,8 @@ class PathNotFoundException extends Exception { - /** - * @var string - */ - private $path; - public function __construct(string $path) + public function __construct(private string $path) { - $this->path = $path; parent::__construct(sprintf('Path %s does not exist', $path)); } diff --git a/src/File/SimpleRelativePathHelper.php b/src/File/SimpleRelativePathHelper.php index 50f4ae5e904..854f584b478 100644 --- a/src/File/SimpleRelativePathHelper.php +++ b/src/File/SimpleRelativePathHelper.php @@ -10,13 +10,8 @@ class SimpleRelativePathHelper implements RelativePathHelper { - /** - * @var string - */ - private $currentWorkingDirectory; - public function __construct(string $currentWorkingDirectory) + public function __construct(private string $currentWorkingDirectory) { - $this->currentWorkingDirectory = $currentWorkingDirectory; } public function getRelativePath(string $filename): string diff --git a/src/Internal/ComposerHelper.php b/src/Internal/ComposerHelper.php index 91e2bf8c210..322d7f10488 100644 --- a/src/Internal/ComposerHelper.php +++ b/src/Internal/ComposerHelper.php @@ -17,10 +17,7 @@ final class ComposerHelper { - /** - * @var ?string - */ - private static $phpstanVersion = null; + private static ?string $phpstanVersion = null; /** @return array|null */ public static function getComposerConfig(string $root): ?array @@ -35,7 +32,7 @@ public static function getComposerConfig(string $root): ?array $composerJsonContents = FileReader::read($composerJsonPath); return Json::decode($composerJsonContents, Json::FORCE_ARRAY); - } catch (CouldNotReadFileException | JsonException $e) { + } catch (CouldNotReadFileException | JsonException) { return null; } } diff --git a/src/Internal/DirectoryCreator.php b/src/Internal/DirectoryCreator.php index 59c6654d123..3ed7c2ff117 100644 --- a/src/Internal/DirectoryCreator.php +++ b/src/Internal/DirectoryCreator.php @@ -12,15 +12,22 @@ final class DirectoryCreator /** * @throws DirectoryCreatorException if unable to create directory. */ - public static function ensureDirectoryExists(string $directory, int $mode = 0755, bool $recursive = true) : void + public static function ensureDirectoryExists( + string $directory, + int $mode = 0755, + bool $recursive = true, + ): void { if (is_dir($directory)) { return; } + if (@mkdir($directory, $mode, $recursive)) { return; } + clearstatcache(); + if (!is_dir($directory)) { throw new DirectoryCreatorException($directory); } diff --git a/src/Internal/DirectoryCreatorException.php b/src/Internal/DirectoryCreatorException.php index 4c85b68991e..bafff9ab7ef 100644 --- a/src/Internal/DirectoryCreatorException.php +++ b/src/Internal/DirectoryCreatorException.php @@ -10,17 +10,15 @@ final class DirectoryCreatorException extends Exception { - /** - * @readonly - * @var string - */ - public $directory; - public function __construct(string $directory) + public function __construct(public readonly string $directory) { - $this->directory = $directory; - $error = error_get_last(); + $error = error_get_last(); - parent::__construct(sprintf('Failed to create directory "%s" (%s).', $directory, is_null($error) ? 'unknown cause' : $error['message'])); + parent::__construct(sprintf( + 'Failed to create directory "%s" (%s).', + $directory, + is_null($error) ? 'unknown cause' : $error['message'], + )); } } diff --git a/src/Node/BooleanAndNode.php b/src/Node/BooleanAndNode.php index 48ebe583e0f..55573e7eb8b 100644 --- a/src/Node/BooleanAndNode.php +++ b/src/Node/BooleanAndNode.php @@ -11,21 +11,8 @@ class BooleanAndNode extends Expr implements VirtualNode { - /** - * @var BooleanAnd|LogicalAnd - */ - private $originalNode; - /** - * @var Scope - */ - private $rightScope; - /** - * @param BooleanAnd|LogicalAnd $originalNode - */ - public function __construct($originalNode, Scope $rightScope) + public function __construct(private BooleanAnd|LogicalAnd $originalNode, private Scope $rightScope) { - $this->originalNode = $originalNode; - $this->rightScope = $rightScope; parent::__construct($originalNode->getAttributes()); } diff --git a/src/Node/BooleanOrNode.php b/src/Node/BooleanOrNode.php index 4586ece286c..0c1523e60b5 100644 --- a/src/Node/BooleanOrNode.php +++ b/src/Node/BooleanOrNode.php @@ -11,21 +11,8 @@ class BooleanOrNode extends Expr implements VirtualNode { - /** - * @var BooleanOr|LogicalOr - */ - private $originalNode; - /** - * @var Scope - */ - private $rightScope; - /** - * @param BooleanOr|LogicalOr $originalNode - */ - public function __construct($originalNode, Scope $rightScope) + public function __construct(private BooleanOr|LogicalOr $originalNode, private Scope $rightScope) { - $this->originalNode = $originalNode; - $this->rightScope = $rightScope; parent::__construct($originalNode->getAttributes()); } diff --git a/src/Node/BreaklessWhileLoopNode.php b/src/Node/BreaklessWhileLoopNode.php index f65ad8a70e3..8a824778bca 100644 --- a/src/Node/BreaklessWhileLoopNode.php +++ b/src/Node/BreaklessWhileLoopNode.php @@ -10,21 +10,11 @@ class BreaklessWhileLoopNode extends NodeAbstract implements VirtualNode { - /** - * @var While_ - */ - private $originalNode; - /** - * @var StatementExitPoint[] - */ - private $exitPoints; /** * @param StatementExitPoint[] $exitPoints */ - public function __construct(While_ $originalNode, array $exitPoints) + public function __construct(private While_ $originalNode, private array $exitPoints) { - $this->originalNode = $originalNode; - $this->exitPoints = $exitPoints; parent::__construct($originalNode->getAttributes()); } diff --git a/src/Node/CatchWithUnthrownExceptionNode.php b/src/Node/CatchWithUnthrownExceptionNode.php index 3bb4f867ad8..007fa832189 100644 --- a/src/Node/CatchWithUnthrownExceptionNode.php +++ b/src/Node/CatchWithUnthrownExceptionNode.php @@ -10,23 +10,8 @@ class CatchWithUnthrownExceptionNode extends NodeAbstract implements VirtualNode { - /** - * @var Catch_ - */ - private $originalNode; - /** - * @var Type - */ - private $caughtType; - /** - * @var Type - */ - private $originalCaughtType; - public function __construct(Catch_ $originalNode, Type $caughtType, Type $originalCaughtType) + public function __construct(private Catch_ $originalNode, private Type $caughtType, private Type $originalCaughtType) { - $this->originalNode = $originalNode; - $this->caughtType = $caughtType; - $this->originalCaughtType = $originalCaughtType; parent::__construct($originalNode->getAttributes()); } diff --git a/src/Node/ClassConstantsNode.php b/src/Node/ClassConstantsNode.php index 554401c3fe1..dee7d0019a8 100644 --- a/src/Node/ClassConstantsNode.php +++ b/src/Node/ClassConstantsNode.php @@ -12,32 +12,12 @@ class ClassConstantsNode extends NodeAbstract implements VirtualNode { - /** - * @var ClassLike - */ - private $class; - /** - * @var ClassConst[] - */ - private $constants; - /** - * @var ClassConstantFetch[] - */ - private $fetches; - /** - * @var ClassReflection - */ - private $classReflection; /** * @param ClassConst[] $constants * @param ClassConstantFetch[] $fetches */ - public function __construct(ClassLike $class, array $constants, array $fetches, ClassReflection $classReflection) + public function __construct(private ClassLike $class, private array $constants, private array $fetches, private ClassReflection $classReflection) { - $this->class = $class; - $this->constants = $constants; - $this->fetches = $fetches; - $this->classReflection = $classReflection; parent::__construct($class->getAttributes()); } diff --git a/src/Node/ClassMethod.php b/src/Node/ClassMethod.php index 03b239c1d4f..6ecfaeead8f 100644 --- a/src/Node/ClassMethod.php +++ b/src/Node/ClassMethod.php @@ -8,13 +8,11 @@ class ClassMethod extends PhpParserClassMethod { - /** - * @var bool - */ - private $isDeclaredInTrait; - public function __construct(\PhpParser\Node\Stmt\ClassMethod $node, bool $isDeclaredInTrait) + public function __construct( + \PhpParser\Node\Stmt\ClassMethod $node, + private bool $isDeclaredInTrait, + ) { - $this->isDeclaredInTrait = $isDeclaredInTrait; parent::__construct($node->name, [ 'flags' => $node->flags, 'byRef' => $node->byRef, @@ -24,6 +22,7 @@ public function __construct(\PhpParser\Node\Stmt\ClassMethod $node, bool $isDecl 'attrGroups' => $node->attrGroups, ], $node->attributes); } + public function getNode(): PhpParserClassMethod { return $this; diff --git a/src/Node/ClassMethodsNode.php b/src/Node/ClassMethodsNode.php index 1f65f6d8ca3..e02620532bd 100644 --- a/src/Node/ClassMethodsNode.php +++ b/src/Node/ClassMethodsNode.php @@ -11,32 +11,12 @@ class ClassMethodsNode extends NodeAbstract implements VirtualNode { - /** - * @var ClassLike - */ - private $class; - /** - * @var ClassMethod[] - */ - private $methods; - /** - * @var array - */ - private $methodCalls; - /** - * @var ClassReflection - */ - private $classReflection; /** * @param ClassMethod[] $methods * @param array $methodCalls */ - public function __construct(ClassLike $class, array $methods, array $methodCalls, ClassReflection $classReflection) + public function __construct(private ClassLike $class, private array $methods, private array $methodCalls, private ClassReflection $classReflection) { - $this->class = $class; - $this->methods = $methods; - $this->methodCalls = $methodCalls; - $this->classReflection = $classReflection; parent::__construct($class->getAttributes()); } diff --git a/src/Node/ClassPropertiesNode.php b/src/Node/ClassPropertiesNode.php index 757ee08088b..406d49c47c6 100644 --- a/src/Node/ClassPropertiesNode.php +++ b/src/Node/ClassPropertiesNode.php @@ -32,51 +32,25 @@ class ClassPropertiesNode extends NodeAbstract implements VirtualNode { - /** - * @var ClassLike - */ - private $class; - /** - * @var ReadWritePropertiesExtensionProvider - */ - private $readWritePropertiesExtensionProvider; - /** - * @var ClassPropertyNode[] - */ - private $properties; - /** - * @var array - */ - private $propertyUsages; - /** - * @var array - */ - private $methodCalls; - /** - * @var array - */ - private $returnStatementNodes; - /** - * @var ClassReflection - */ - private $classReflection; /** * @param ClassPropertyNode[] $properties * @param array $propertyUsages * @param array $methodCalls * @param array $returnStatementNodes */ - public function __construct(ClassLike $class, ReadWritePropertiesExtensionProvider $readWritePropertiesExtensionProvider, array $properties, array $propertyUsages, array $methodCalls, array $returnStatementNodes, ClassReflection $classReflection) + public function __construct( + private ClassLike $class, + private ReadWritePropertiesExtensionProvider $readWritePropertiesExtensionProvider, + private array $properties, + private array $propertyUsages, + private array $methodCalls, + private array $returnStatementNodes, + private ClassReflection $classReflection, + ) { - $this->class = $class; - $this->readWritePropertiesExtensionProvider = $readWritePropertiesExtensionProvider; - $this->properties = $properties; - $this->propertyUsages = $propertyUsages; - $this->methodCalls = $methodCalls; - $this->returnStatementNodes = $returnStatementNodes; - $this->classReflection = $classReflection; parent::__construct($class->getAttributes()); } + public function getClass(): ClassLike { return $this->class; @@ -121,12 +95,17 @@ public function getClassReflection(): ClassReflection * @param ReadWritePropertiesExtension[]|null $extensions * @return array{array, array, array} */ - public function getUninitializedProperties(Scope $scope, array $constructors, ?array $extensions = null) : array + public function getUninitializedProperties( + Scope $scope, + array $constructors, + ?array $extensions = null, + ): array { if (!$this->getClass() instanceof Class_) { return [[], [], []]; } $classReflection = $this->getClassReflection(); + $uninitializedProperties = []; $originalProperties = []; $initialInitializedProperties = []; @@ -168,16 +147,20 @@ public function getUninitializedProperties(Scope $scope, array $constructors, ?a } $uninitializedProperties[$property->getName()] = $property; } + if ($constructors === []) { return [$uninitializedProperties, [], []]; } + $methodsCalledFromConstructor = $this->getMethodsCalledFromConstructor($classReflection, $initialInitializedProperties, $initializedProperties, $constructors); $prematureAccess = []; $additionalAssigns = []; + $initializedInConstructor = []; if ($classReflection->hasConstructor()) { $initializedInConstructor = array_diff_key($uninitializedProperties, $this->collectUninitializedProperties([$classReflection->getConstructor()->getName()], $uninitializedProperties)); } + foreach ($this->getPropertyUsages() as $usage) { $fetch = $usage->getFetch(); if (!$fetch instanceof PropertyFetch) { @@ -255,6 +238,7 @@ public function getUninitializedProperties(Scope $scope, array $constructors, ?a } } } + return [ $this->collectUninitializedProperties(array_keys($methodsCalledFromConstructor), $uninitializedProperties), $prematureAccess, @@ -329,7 +313,12 @@ private function collectUninitializedProperties(array $constructors, array $unin * @param array> $initializedProperties * @return array> */ - private function getMethodsCalledFromConstructor(ClassReflection $classReflection, array $initialInitializedProperties, array $initializedProperties, array $methods) : array + private function getMethodsCalledFromConstructor( + ClassReflection $classReflection, + array $initialInitializedProperties, + array $initializedProperties, + array $methods, + ): array { $originalMap = $initializedProperties; $originalMethods = $methods; @@ -381,9 +370,11 @@ private function getMethodsCalledFromConstructor(ClassReflection $classReflectio $initializedProperties[$methodName] = $this->getInitializedProperties($callScope, $initializedProperties[$inMethod->getName()] ?? $initialInitializedProperties); $methods[] = $methodName; } + if ($originalMap === $initializedProperties && $originalMethods === $methods) { return $initializedProperties; } + return $this->getMethodsCalledFromConstructor($classReflection, $initialInitializedProperties, $initializedProperties, $methods); } diff --git a/src/Node/ClassPropertyNode.php b/src/Node/ClassPropertyNode.php index 18d1e61c284..a7c81ff9d40 100644 --- a/src/Node/ClassPropertyNode.php +++ b/src/Node/ClassPropertyNode.php @@ -15,78 +15,26 @@ class ClassPropertyNode extends NodeAbstract implements VirtualNode { - /** - * @var string - */ - private $name; - /** - * @var int - */ - private $flags; - /** - * @var Identifier|Name|Node\ComplexType|null - */ - private $type; - /** - * @var ?Expr - */ - private $default; - /** - * @var ?string - */ - private $phpDoc; - /** - * @var ?Type - */ - private $phpDocType; - /** - * @var bool - */ - private $isPromoted; - /** - * @var bool - */ - private $isPromotedFromTrait; - /** - * @var bool - */ - private $isReadonlyByPhpDoc; - /** - * @var bool - */ - private $isDeclaredInTrait; - /** - * @var bool - */ - private $isReadonlyClass; - /** - * @var bool - */ - private $isAllowedPrivateMutation; - /** - * @var ClassReflection - */ - private $classReflection; - /** - * @param Identifier|Name|Node\ComplexType|null $type - */ - public function __construct(string $name, int $flags, $type, ?Expr $default, ?string $phpDoc, ?Type $phpDocType, bool $isPromoted, bool $isPromotedFromTrait, Node $originalNode, bool $isReadonlyByPhpDoc, bool $isDeclaredInTrait, bool $isReadonlyClass, bool $isAllowedPrivateMutation, ClassReflection $classReflection) - { - $this->name = $name; - $this->flags = $flags; - $this->type = $type; - $this->default = $default; - $this->phpDoc = $phpDoc; - $this->phpDocType = $phpDocType; - $this->isPromoted = $isPromoted; - $this->isPromotedFromTrait = $isPromotedFromTrait; - $this->isReadonlyByPhpDoc = $isReadonlyByPhpDoc; - $this->isDeclaredInTrait = $isDeclaredInTrait; - $this->isReadonlyClass = $isReadonlyClass; - $this->isAllowedPrivateMutation = $isAllowedPrivateMutation; - $this->classReflection = $classReflection; + public function __construct( + private string $name, + private int $flags, + private Identifier|Name|Node\ComplexType|null $type, + private ?Expr $default, + private ?string $phpDoc, + private ?Type $phpDocType, + private bool $isPromoted, + private bool $isPromotedFromTrait, + Node $originalNode, + private bool $isReadonlyByPhpDoc, + private bool $isDeclaredInTrait, + private bool $isReadonlyClass, + private bool $isAllowedPrivateMutation, + private ClassReflection $classReflection, + ) + { parent::__construct($originalNode->getAttributes()); } + public function getName(): string { return $this->name; diff --git a/src/Node/ClassStatementsGatherer.php b/src/Node/ClassStatementsGatherer.php index e05dba422d2..904186224f0 100644 --- a/src/Node/ClassStatementsGatherer.php +++ b/src/Node/ClassStatementsGatherer.php @@ -25,10 +25,6 @@ class ClassStatementsGatherer { - /** - * @var ClassReflection - */ - private $classReflection; private const PROPERTY_ENUMERATING_FUNCTIONS = [ 'get_object_vars', 'array_walk', @@ -38,32 +34,34 @@ class ClassStatementsGatherer private $nodeCallback; /** @var ClassPropertyNode[] */ - private $properties = []; + private array $properties = []; /** @var ClassMethod[] */ - private $methods = []; + private array $methods = []; /** @var \PHPStan\Node\Method\MethodCall[] */ - private $methodCalls = []; + private array $methodCalls = []; /** @var array */ - private $propertyUsages = []; + private array $propertyUsages = []; /** @var Node\Stmt\ClassConst[] */ - private $constants = []; + private array $constants = []; /** @var ClassConstantFetch[] */ - private $constantFetches = []; + private array $constantFetches = []; /** @var array */ - private $returnStatementNodes = []; + private array $returnStatementNodes = []; /** * @param callable(Node $node, Scope $scope): void $nodeCallback */ - public function __construct(ClassReflection $classReflection, callable $nodeCallback) + public function __construct( + private ClassReflection $classReflection, + callable $nodeCallback, + ) { - $this->classReflection = $classReflection; $this->nodeCallback = $nodeCallback; } @@ -141,7 +139,11 @@ private function gatherNodes(Node $node, Scope $scope): void if ($node instanceof ClassPropertyNode) { $this->properties[] = $node; if ($node->isPromoted()) { - $this->propertyUsages[] = new PropertyWrite(new PropertyFetch(new Expr\Variable('this'), new Identifier($node->getName())), $scope, true); + $this->propertyUsages[] = new PropertyWrite( + new PropertyFetch(new Expr\Variable('this'), new Identifier($node->getName())), + $scope, + true, + ); } return; } @@ -243,7 +245,10 @@ private function tryToApplyPropertyReads(Expr\FuncCall $node, Scope $scope): voi if ($property->isStatic()) { continue; } - $this->propertyUsages[] = new PropertyRead(new PropertyFetch(new Expr\Variable('this'), new Identifier($property->getName())), $scope); + $this->propertyUsages[] = new PropertyRead( + new PropertyFetch(new Expr\Variable('this'), new Identifier($property->getName())), + $scope, + ); } } diff --git a/src/Node/ClosureReturnStatementsNode.php b/src/Node/ClosureReturnStatementsNode.php index 244d1b60884..07eb1b9f95b 100644 --- a/src/Node/ClosureReturnStatementsNode.php +++ b/src/Node/ClosureReturnStatementsNode.php @@ -14,38 +14,21 @@ class ClosureReturnStatementsNode extends NodeAbstract implements ReturnStatementsNode { - /** - * @var list - */ - private $returnStatements; - /** - * @var list - */ - private $yieldStatements; - /** - * @var StatementResult - */ - private $statementResult; - /** - * @var list - */ - private $executionEnds; - /** - * @var Node\Expr\Closure - */ - private $closureExpr; + private Node\Expr\Closure $closureExpr; /** * @param list $returnStatements * @param list $yieldStatements * @param list $executionEnds */ - public function __construct(Closure $closureExpr, array $returnStatements, array $yieldStatements, StatementResult $statementResult, array $executionEnds) + public function __construct( + Closure $closureExpr, + private array $returnStatements, + private array $yieldStatements, + private StatementResult $statementResult, + private array $executionEnds, + ) { - $this->returnStatements = $returnStatements; - $this->yieldStatements = $yieldStatements; - $this->statementResult = $statementResult; - $this->executionEnds = $executionEnds; parent::__construct($closureExpr->getAttributes()); $this->closureExpr = $closureExpr; } diff --git a/src/Node/CollectedDataNode.php b/src/Node/CollectedDataNode.php index 72b3ae2641c..8f7684e1ec5 100644 --- a/src/Node/CollectedDataNode.php +++ b/src/Node/CollectedDataNode.php @@ -12,21 +12,11 @@ class CollectedDataNode extends NodeAbstract { - /** - * @var CollectedData[] - */ - private $collectedData; - /** - * @var bool - */ - private $onlyFiles; /** * @param CollectedData[] $collectedData */ - public function __construct(array $collectedData, bool $onlyFiles) + public function __construct(private array $collectedData, private bool $onlyFiles) { - $this->collectedData = $collectedData; - $this->onlyFiles = $onlyFiles; parent::__construct([]); } diff --git a/src/Node/Constant/ClassConstantFetch.php b/src/Node/Constant/ClassConstantFetch.php index be0c0be3613..30129007d01 100644 --- a/src/Node/Constant/ClassConstantFetch.php +++ b/src/Node/Constant/ClassConstantFetch.php @@ -9,18 +9,8 @@ class ClassConstantFetch { - /** - * @var ClassConstFetch - */ - private $node; - /** - * @var Scope - */ - private $scope; - public function __construct(ClassConstFetch $node, Scope $scope) + public function __construct(private ClassConstFetch $node, private Scope $scope) { - $this->node = $node; - $this->scope = $scope; } public function getNode(): ClassConstFetch diff --git a/src/Node/DoWhileLoopConditionNode.php b/src/Node/DoWhileLoopConditionNode.php index 9e1d85c319e..c6cbc865728 100644 --- a/src/Node/DoWhileLoopConditionNode.php +++ b/src/Node/DoWhileLoopConditionNode.php @@ -9,21 +9,11 @@ class DoWhileLoopConditionNode extends NodeAbstract implements VirtualNode { - /** - * @var Expr - */ - private $cond; - /** - * @var StatementExitPoint[] - */ - private $exitPoints; /** * @param StatementExitPoint[] $exitPoints */ - public function __construct(Expr $cond, array $exitPoints) + public function __construct(private Expr $cond, private array $exitPoints) { - $this->cond = $cond; - $this->exitPoints = $exitPoints; parent::__construct($cond->getAttributes()); } diff --git a/src/Node/ExecutionEndNode.php b/src/Node/ExecutionEndNode.php index 9e8ed7b92ef..225036a5ba9 100644 --- a/src/Node/ExecutionEndNode.php +++ b/src/Node/ExecutionEndNode.php @@ -10,25 +10,15 @@ class ExecutionEndNode extends NodeAbstract implements VirtualNode { - /** - * @var Node - */ - private $node; - /** - * @var StatementResult - */ - private $statementResult; - /** - * @var bool - */ - private $hasNativeReturnTypehint; - public function __construct(Node $node, StatementResult $statementResult, bool $hasNativeReturnTypehint) + public function __construct( + private Node $node, + private StatementResult $statementResult, + private bool $hasNativeReturnTypehint, + ) { - $this->node = $node; - $this->statementResult = $statementResult; - $this->hasNativeReturnTypehint = $hasNativeReturnTypehint; parent::__construct($node->getAttributes()); } + public function getNode(): Node { return $this->node; diff --git a/src/Node/Expr/AlwaysRememberedExpr.php b/src/Node/Expr/AlwaysRememberedExpr.php index c0bf662d743..049ad46a6b4 100644 --- a/src/Node/Expr/AlwaysRememberedExpr.php +++ b/src/Node/Expr/AlwaysRememberedExpr.php @@ -9,23 +9,8 @@ class AlwaysRememberedExpr extends Expr implements VirtualNode { - /** - * @var Expr - */ - public $expr; - /** - * @var Type - */ - private $type; - /** - * @var Type - */ - private $nativeType; - public function __construct(Expr $expr, Type $type, Type $nativeType) + public function __construct(public Expr $expr, private Type $type, private Type $nativeType) { - $this->expr = $expr; - $this->type = $type; - $this->nativeType = $nativeType; parent::__construct([]); } diff --git a/src/Node/Expr/GetIterableKeyTypeExpr.php b/src/Node/Expr/GetIterableKeyTypeExpr.php index a0e5ba1a475..40301cc29f1 100644 --- a/src/Node/Expr/GetIterableKeyTypeExpr.php +++ b/src/Node/Expr/GetIterableKeyTypeExpr.php @@ -8,13 +8,8 @@ class GetIterableKeyTypeExpr extends Expr implements VirtualNode { - /** - * @var Expr - */ - private $expr; - public function __construct(Expr $expr) + public function __construct(private Expr $expr) { - $this->expr = $expr; parent::__construct([]); } diff --git a/src/Node/Expr/GetIterableValueTypeExpr.php b/src/Node/Expr/GetIterableValueTypeExpr.php index e6deaede78c..2fd920f21a8 100644 --- a/src/Node/Expr/GetIterableValueTypeExpr.php +++ b/src/Node/Expr/GetIterableValueTypeExpr.php @@ -8,13 +8,8 @@ class GetIterableValueTypeExpr extends Expr implements VirtualNode { - /** - * @var Expr - */ - private $expr; - public function __construct(Expr $expr) + public function __construct(private Expr $expr) { - $this->expr = $expr; parent::__construct([]); } diff --git a/src/Node/Expr/GetOffsetValueTypeExpr.php b/src/Node/Expr/GetOffsetValueTypeExpr.php index f82e78c930b..ed7b33a1249 100644 --- a/src/Node/Expr/GetOffsetValueTypeExpr.php +++ b/src/Node/Expr/GetOffsetValueTypeExpr.php @@ -8,18 +8,8 @@ class GetOffsetValueTypeExpr extends Expr implements VirtualNode { - /** - * @var Expr - */ - private $var; - /** - * @var Expr - */ - private $dim; - public function __construct(Expr $var, Expr $dim) + public function __construct(private Expr $var, private Expr $dim) { - $this->var = $var; - $this->dim = $dim; parent::__construct([]); } diff --git a/src/Node/Expr/OriginalPropertyTypeExpr.php b/src/Node/Expr/OriginalPropertyTypeExpr.php index c5e45c28440..2250a8158b4 100644 --- a/src/Node/Expr/OriginalPropertyTypeExpr.php +++ b/src/Node/Expr/OriginalPropertyTypeExpr.php @@ -8,23 +8,12 @@ class OriginalPropertyTypeExpr extends Expr implements VirtualNode { - /** - * @var Expr\PropertyFetch|Expr\StaticPropertyFetch - */ - private $propertyFetch; - /** - * @param Expr\PropertyFetch|Expr\StaticPropertyFetch $propertyFetch - */ - public function __construct($propertyFetch) + public function __construct(private Expr\PropertyFetch|Expr\StaticPropertyFetch $propertyFetch) { - $this->propertyFetch = $propertyFetch; parent::__construct([]); } - /** - * @return Expr\PropertyFetch|Expr\StaticPropertyFetch - */ - public function getPropertyFetch() + public function getPropertyFetch(): Expr\PropertyFetch|Expr\StaticPropertyFetch { return $this->propertyFetch; } diff --git a/src/Node/Expr/PropertyInitializationExpr.php b/src/Node/Expr/PropertyInitializationExpr.php index 3bea48ec4a3..942fa08d5c0 100644 --- a/src/Node/Expr/PropertyInitializationExpr.php +++ b/src/Node/Expr/PropertyInitializationExpr.php @@ -8,13 +8,8 @@ class PropertyInitializationExpr extends Expr implements VirtualNode { - /** - * @var string - */ - private $propertyName; - public function __construct(string $propertyName) + public function __construct(private string $propertyName) { - $this->propertyName = $propertyName; parent::__construct([]); } diff --git a/src/Node/Expr/SetOffsetValueTypeExpr.php b/src/Node/Expr/SetOffsetValueTypeExpr.php index 6d8e411bda8..3e42e13b0c3 100644 --- a/src/Node/Expr/SetOffsetValueTypeExpr.php +++ b/src/Node/Expr/SetOffsetValueTypeExpr.php @@ -8,23 +8,8 @@ class SetOffsetValueTypeExpr extends Expr implements VirtualNode { - /** - * @var Expr - */ - private $var; - /** - * @var ?Expr - */ - private $dim; - /** - * @var Expr - */ - private $value; - public function __construct(Expr $var, ?Expr $dim, Expr $value) + public function __construct(private Expr $var, private ?Expr $dim, private Expr $value) { - $this->var = $var; - $this->dim = $dim; - $this->value = $value; parent::__construct([]); } diff --git a/src/Node/Expr/TypeExpr.php b/src/Node/Expr/TypeExpr.php index 3318fd19323..4adc5be0e33 100644 --- a/src/Node/Expr/TypeExpr.php +++ b/src/Node/Expr/TypeExpr.php @@ -9,13 +9,8 @@ class TypeExpr extends Expr implements VirtualNode { - /** - * @var Type - */ - private $exprType; - public function __construct(Type $exprType) + public function __construct(private Type $exprType) { - $this->exprType = $exprType; parent::__construct(); } diff --git a/src/Node/FileNode.php b/src/Node/FileNode.php index 379724baf50..13a6596ced3 100644 --- a/src/Node/FileNode.php +++ b/src/Node/FileNode.php @@ -9,16 +9,11 @@ class FileNode extends NodeAbstract implements VirtualNode { - /** - * @var Node[] - */ - private $nodes; /** * @param Node[] $nodes */ - public function __construct(array $nodes) + public function __construct(private array $nodes) { - $this->nodes = $nodes; $firstNode = $nodes[0] ?? null; parent::__construct($firstNode !== null ? $firstNode->getAttributes() : []); } diff --git a/src/Node/FinallyExitPointsNode.php b/src/Node/FinallyExitPointsNode.php index 0a7c82b4929..a87bdc516cc 100644 --- a/src/Node/FinallyExitPointsNode.php +++ b/src/Node/FinallyExitPointsNode.php @@ -9,22 +9,12 @@ class FinallyExitPointsNode extends NodeAbstract implements VirtualNode { - /** - * @var StatementExitPoint[] - */ - private $finallyExitPoints; - /** - * @var StatementExitPoint[] - */ - private $tryCatchExitPoints; /** * @param StatementExitPoint[] $finallyExitPoints * @param StatementExitPoint[] $tryCatchExitPoints */ - public function __construct(array $finallyExitPoints, array $tryCatchExitPoints) + public function __construct(private array $finallyExitPoints, private array $tryCatchExitPoints) { - $this->finallyExitPoints = $finallyExitPoints; - $this->tryCatchExitPoints = $tryCatchExitPoints; parent::__construct([]); } diff --git a/src/Node/FunctionCallableNode.php b/src/Node/FunctionCallableNode.php index 4a1e48ae15e..d43e0228ce2 100644 --- a/src/Node/FunctionCallableNode.php +++ b/src/Node/FunctionCallableNode.php @@ -9,21 +9,8 @@ class FunctionCallableNode extends Expr implements VirtualNode { - /** - * @var Name|Expr - */ - private $name; - /** - * @var Expr\FuncCall - */ - private $originalNode; - /** - * @param Name|Expr $name - */ - public function __construct($name, Expr\FuncCall $originalNode) + public function __construct(private Name|Expr $name, private Expr\FuncCall $originalNode) { - $this->name = $name; - $this->originalNode = $originalNode; parent::__construct($this->originalNode->getAttributes()); } diff --git a/src/Node/FunctionReturnStatementsNode.php b/src/Node/FunctionReturnStatementsNode.php index dbd5afeaed3..0b8f4b4494b 100644 --- a/src/Node/FunctionReturnStatementsNode.php +++ b/src/Node/FunctionReturnStatementsNode.php @@ -14,45 +14,23 @@ class FunctionReturnStatementsNode extends NodeAbstract implements ReturnStatementsNode { - /** - * @var Function_ - */ - private $function; - /** - * @var list - */ - private $returnStatements; - /** - * @var list - */ - private $yieldStatements; - /** - * @var StatementResult - */ - private $statementResult; - /** - * @var list - */ - private $executionEnds; - /** - * @var FunctionReflection - */ - private $functionReflection; /** * @param list $returnStatements * @param list $yieldStatements * @param list $executionEnds */ - public function __construct(Function_ $function, array $returnStatements, array $yieldStatements, StatementResult $statementResult, array $executionEnds, FunctionReflection $functionReflection) + public function __construct( + private Function_ $function, + private array $returnStatements, + private array $yieldStatements, + private StatementResult $statementResult, + private array $executionEnds, + private FunctionReflection $functionReflection, + ) { - $this->function = $function; - $this->returnStatements = $returnStatements; - $this->yieldStatements = $yieldStatements; - $this->statementResult = $statementResult; - $this->executionEnds = $executionEnds; - $this->functionReflection = $functionReflection; parent::__construct($function->getAttributes()); } + public function getReturnStatements(): array { return $this->returnStatements; diff --git a/src/Node/InArrowFunctionNode.php b/src/Node/InArrowFunctionNode.php index f8e82ac9711..7716f332b4a 100644 --- a/src/Node/InArrowFunctionNode.php +++ b/src/Node/InArrowFunctionNode.php @@ -11,18 +11,10 @@ class InArrowFunctionNode extends NodeAbstract implements VirtualNode { - /** - * @var ClosureType - */ - private $closureType; - /** - * @var Node\Expr\ArrowFunction - */ - private $originalNode; + private Node\Expr\ArrowFunction $originalNode; - public function __construct(ClosureType $closureType, ArrowFunction $originalNode) + public function __construct(private ClosureType $closureType, ArrowFunction $originalNode) { - $this->closureType = $closureType; parent::__construct($originalNode->getAttributes()); $this->originalNode = $originalNode; } diff --git a/src/Node/InClassMethodNode.php b/src/Node/InClassMethodNode.php index a135771eccf..da1d8a09b7b 100644 --- a/src/Node/InClassMethodNode.php +++ b/src/Node/InClassMethodNode.php @@ -10,25 +10,15 @@ class InClassMethodNode extends Node\Stmt implements VirtualNode { - /** - * @var ClassReflection - */ - private $classReflection; - /** - * @var PhpMethodFromParserNodeReflection - */ - private $methodReflection; - /** - * @var Node\Stmt\ClassMethod - */ - private $originalNode; - public function __construct(ClassReflection $classReflection, PhpMethodFromParserNodeReflection $methodReflection, Node\Stmt\ClassMethod $originalNode) + public function __construct( + private ClassReflection $classReflection, + private PhpMethodFromParserNodeReflection $methodReflection, + private Node\Stmt\ClassMethod $originalNode, + ) { - $this->classReflection = $classReflection; - $this->methodReflection = $methodReflection; - $this->originalNode = $originalNode; parent::__construct($originalNode->getAttributes()); } + public function getClassReflection(): ClassReflection { return $this->classReflection; diff --git a/src/Node/InClassNode.php b/src/Node/InClassNode.php index 0e2caed8fbf..23310aaec0d 100644 --- a/src/Node/InClassNode.php +++ b/src/Node/InClassNode.php @@ -10,18 +10,8 @@ class InClassNode extends Node\Stmt implements VirtualNode { - /** - * @var ClassLike - */ - private $originalNode; - /** - * @var ClassReflection - */ - private $classReflection; - public function __construct(ClassLike $originalNode, ClassReflection $classReflection) + public function __construct(private ClassLike $originalNode, private ClassReflection $classReflection) { - $this->originalNode = $originalNode; - $this->classReflection = $classReflection; parent::__construct($originalNode->getAttributes()); } diff --git a/src/Node/InClosureNode.php b/src/Node/InClosureNode.php index 4df77af30aa..8882ebd0e3d 100644 --- a/src/Node/InClosureNode.php +++ b/src/Node/InClosureNode.php @@ -11,18 +11,10 @@ class InClosureNode extends NodeAbstract implements VirtualNode { - /** - * @var ClosureType - */ - private $closureType; - /** - * @var Node\Expr\Closure - */ - private $originalNode; + private Node\Expr\Closure $originalNode; - public function __construct(ClosureType $closureType, Closure $originalNode) + public function __construct(private ClosureType $closureType, Closure $originalNode) { - $this->closureType = $closureType; parent::__construct($originalNode->getAttributes()); $this->originalNode = $originalNode; } diff --git a/src/Node/InForeachNode.php b/src/Node/InForeachNode.php index 07e879ed027..b39026a9c95 100644 --- a/src/Node/InForeachNode.php +++ b/src/Node/InForeachNode.php @@ -8,13 +8,8 @@ class InForeachNode extends NodeAbstract implements VirtualNode { - /** - * @var Foreach_ - */ - private $originalNode; - public function __construct(Foreach_ $originalNode) + public function __construct(private Foreach_ $originalNode) { - $this->originalNode = $originalNode; parent::__construct($originalNode->getAttributes()); } diff --git a/src/Node/InFunctionNode.php b/src/Node/InFunctionNode.php index e4479e50f24..548c2ac4224 100644 --- a/src/Node/InFunctionNode.php +++ b/src/Node/InFunctionNode.php @@ -9,20 +9,14 @@ class InFunctionNode extends Node\Stmt implements VirtualNode { - /** - * @var PhpFunctionFromParserNodeReflection - */ - private $functionReflection; - /** - * @var Node\Stmt\Function_ - */ - private $originalNode; - public function __construct(PhpFunctionFromParserNodeReflection $functionReflection, Node\Stmt\Function_ $originalNode) + public function __construct( + private PhpFunctionFromParserNodeReflection $functionReflection, + private Node\Stmt\Function_ $originalNode, + ) { - $this->functionReflection = $functionReflection; - $this->originalNode = $originalNode; parent::__construct($originalNode->getAttributes()); } + public function getFunctionReflection(): PhpFunctionFromParserNodeReflection { return $this->functionReflection; diff --git a/src/Node/InTraitNode.php b/src/Node/InTraitNode.php index f59c5361b47..688c04499bd 100644 --- a/src/Node/InTraitNode.php +++ b/src/Node/InTraitNode.php @@ -9,18 +9,8 @@ class InTraitNode extends Node\Stmt implements VirtualNode { - /** - * @var Node\Stmt\Trait_ - */ - private $originalNode; - /** - * @var ClassReflection - */ - private $traitReflection; - public function __construct(Node\Stmt\Trait_ $originalNode, ClassReflection $traitReflection) + public function __construct(private Node\Stmt\Trait_ $originalNode, private ClassReflection $traitReflection) { - $this->originalNode = $originalNode; - $this->traitReflection = $traitReflection; parent::__construct($originalNode->getAttributes()); } diff --git a/src/Node/InstantiationCallableNode.php b/src/Node/InstantiationCallableNode.php index 0c5ba8d49cf..382431f70ad 100644 --- a/src/Node/InstantiationCallableNode.php +++ b/src/Node/InstantiationCallableNode.php @@ -9,21 +9,8 @@ class InstantiationCallableNode extends Expr implements VirtualNode { - /** - * @var Name|Expr - */ - private $class; - /** - * @var Expr\New_ - */ - private $originalNode; - /** - * @param Name|Expr $class - */ - public function __construct($class, Expr\New_ $originalNode) + public function __construct(private Name|Expr $class, private Expr\New_ $originalNode) { - $this->class = $class; - $this->originalNode = $originalNode; parent::__construct($this->originalNode->getAttributes()); } diff --git a/src/Node/IssetExpr.php b/src/Node/IssetExpr.php index 088812b967b..5c45df0ebc2 100644 --- a/src/Node/IssetExpr.php +++ b/src/Node/IssetExpr.php @@ -7,15 +7,13 @@ class IssetExpr extends Expr implements VirtualNode { - /** - * @var Expr - */ - private $expr; - public function __construct(Expr $expr) + public function __construct( + private Expr $expr, + ) { - $this->expr = $expr; parent::__construct([]); } + public function getExpr(): Expr { return $this->expr; diff --git a/src/Node/LiteralArrayItem.php b/src/Node/LiteralArrayItem.php index 34f48396dae..48dd0e3705d 100644 --- a/src/Node/LiteralArrayItem.php +++ b/src/Node/LiteralArrayItem.php @@ -9,18 +9,8 @@ class LiteralArrayItem { - /** - * @var Scope - */ - private $scope; - /** - * @var ?ArrayItem - */ - private $arrayItem; - public function __construct(Scope $scope, ?ArrayItem $arrayItem) + public function __construct(private Scope $scope, private ?ArrayItem $arrayItem) { - $this->scope = $scope; - $this->arrayItem = $arrayItem; } public function getScope(): Scope diff --git a/src/Node/LiteralArrayNode.php b/src/Node/LiteralArrayNode.php index fc0c6466d19..bcbd3f0a937 100644 --- a/src/Node/LiteralArrayNode.php +++ b/src/Node/LiteralArrayNode.php @@ -9,16 +9,11 @@ class LiteralArrayNode extends NodeAbstract implements VirtualNode { - /** - * @var LiteralArrayItem[] - */ - private $itemNodes; /** * @param LiteralArrayItem[] $itemNodes */ - public function __construct(Array_ $originalNode, array $itemNodes) + public function __construct(Array_ $originalNode, private array $itemNodes) { - $this->itemNodes = $itemNodes; parent::__construct($originalNode->getAttributes()); } diff --git a/src/Node/MatchExpressionArm.php b/src/Node/MatchExpressionArm.php index 15ef1d12941..bc8643af458 100644 --- a/src/Node/MatchExpressionArm.php +++ b/src/Node/MatchExpressionArm.php @@ -6,26 +6,11 @@ class MatchExpressionArm { - /** - * @var MatchExpressionArmBody - */ - private $body; - /** - * @var MatchExpressionArmCondition[] - */ - private $conditions; - /** - * @var int - */ - private $line; /** * @param MatchExpressionArmCondition[] $conditions */ - public function __construct(MatchExpressionArmBody $body, array $conditions, int $line) + public function __construct(private MatchExpressionArmBody $body, private array $conditions, private int $line) { - $this->body = $body; - $this->conditions = $conditions; - $this->line = $line; } public function getBody(): MatchExpressionArmBody diff --git a/src/Node/MatchExpressionArmBody.php b/src/Node/MatchExpressionArmBody.php index bec3393a757..544d6237dea 100644 --- a/src/Node/MatchExpressionArmBody.php +++ b/src/Node/MatchExpressionArmBody.php @@ -9,18 +9,8 @@ class MatchExpressionArmBody { - /** - * @var Scope - */ - private $scope; - /** - * @var Expr - */ - private $body; - public function __construct(Scope $scope, Expr $body) + public function __construct(private Scope $scope, private Expr $body) { - $this->scope = $scope; - $this->body = $body; } public function getScope(): Scope diff --git a/src/Node/MatchExpressionArmCondition.php b/src/Node/MatchExpressionArmCondition.php index 157ac546acd..2928175be79 100644 --- a/src/Node/MatchExpressionArmCondition.php +++ b/src/Node/MatchExpressionArmCondition.php @@ -9,23 +9,8 @@ class MatchExpressionArmCondition { - /** - * @var Expr - */ - private $condition; - /** - * @var Scope - */ - private $scope; - /** - * @var int - */ - private $line; - public function __construct(Expr $condition, Scope $scope, int $line) + public function __construct(private Expr $condition, private Scope $scope, private int $line) { - $this->condition = $condition; - $this->scope = $scope; - $this->line = $line; } public function getCondition(): Expr diff --git a/src/Node/MatchExpressionNode.php b/src/Node/MatchExpressionNode.php index 7a9e32d7d49..00ec3bcf8c7 100644 --- a/src/Node/MatchExpressionNode.php +++ b/src/Node/MatchExpressionNode.php @@ -10,28 +10,19 @@ class MatchExpressionNode extends NodeAbstract implements VirtualNode { - /** - * @var Expr - */ - private $condition; - /** - * @var MatchExpressionArm[] - */ - private $arms; - /** - * @var Scope - */ - private $endScope; /** * @param MatchExpressionArm[] $arms */ - public function __construct(Expr $condition, array $arms, Expr\Match_ $originalNode, Scope $endScope) + public function __construct( + private Expr $condition, + private array $arms, + Expr\Match_ $originalNode, + private Scope $endScope, + ) { - $this->condition = $condition; - $this->arms = $arms; - $this->endScope = $endScope; parent::__construct($originalNode->getAttributes()); } + public function getCondition(): Expr { return $this->condition; diff --git a/src/Node/Method/MethodCall.php b/src/Node/Method/MethodCall.php index 64ffff408e5..19c77316fb7 100644 --- a/src/Node/Method/MethodCall.php +++ b/src/Node/Method/MethodCall.php @@ -11,22 +11,13 @@ class MethodCall { - /** - * @var Node\Expr\MethodCall|StaticCall|Array_ - */ - private $node; - /** - * @var Scope - */ - private $scope; - /** - * @param Node\Expr\MethodCall|StaticCall|Array_ $node - */ - public function __construct($node, Scope $scope) + public function __construct( + private Node\Expr\MethodCall|StaticCall|Array_ $node, + private Scope $scope, + ) { - $this->node = $node; - $this->scope = $scope; } + /** * @return Node\Expr\MethodCall|StaticCall|Array_ */ diff --git a/src/Node/MethodCallableNode.php b/src/Node/MethodCallableNode.php index 75b642518b8..aff7b5cefc8 100644 --- a/src/Node/MethodCallableNode.php +++ b/src/Node/MethodCallableNode.php @@ -9,28 +9,15 @@ class MethodCallableNode extends Expr implements VirtualNode { - /** - * @var Expr - */ - private $var; - /** - * @var Identifier|Expr - */ - private $name; - /** - * @var Expr\MethodCall - */ - private $originalNode; - /** - * @param Identifier|Expr $name - */ - public function __construct(Expr $var, $name, Expr\MethodCall $originalNode) + public function __construct( + private Expr $var, + private Identifier|Expr $name, + private Expr\MethodCall $originalNode, + ) { - $this->var = $var; - $this->name = $name; - $this->originalNode = $originalNode; parent::__construct($originalNode->getAttributes()); } + public function getVar(): Expr { return $this->var; diff --git a/src/Node/MethodReturnStatementsNode.php b/src/Node/MethodReturnStatementsNode.php index cc100089d0c..fe7aa691fbb 100644 --- a/src/Node/MethodReturnStatementsNode.php +++ b/src/Node/MethodReturnStatementsNode.php @@ -15,48 +15,23 @@ class MethodReturnStatementsNode extends NodeAbstract implements ReturnStatementsNode { - /** - * @var list - */ - private $returnStatements; - /** - * @var list - */ - private $yieldStatements; - /** - * @var StatementResult - */ - private $statementResult; - /** - * @var list - */ - private $executionEnds; - /** - * @var ClassReflection - */ - private $classReflection; - /** - * @var MethodReflection - */ - private $methodReflection; - /** - * @var ClassMethod - */ - private $classMethod; + private ClassMethod $classMethod; /** * @param list $returnStatements * @param list $yieldStatements * @param list $executionEnds */ - public function __construct(ClassMethod $method, array $returnStatements, array $yieldStatements, StatementResult $statementResult, array $executionEnds, ClassReflection $classReflection, MethodReflection $methodReflection) + public function __construct( + ClassMethod $method, + private array $returnStatements, + private array $yieldStatements, + private StatementResult $statementResult, + private array $executionEnds, + private ClassReflection $classReflection, + private MethodReflection $methodReflection, + ) { - $this->returnStatements = $returnStatements; - $this->yieldStatements = $yieldStatements; - $this->statementResult = $statementResult; - $this->executionEnds = $executionEnds; - $this->classReflection = $classReflection; - $this->methodReflection = $methodReflection; parent::__construct($method->getAttributes()); $this->classMethod = $method; } diff --git a/src/Node/Printer/ExprPrinter.php b/src/Node/Printer/ExprPrinter.php index b76415c3a13..3763201b5ff 100644 --- a/src/Node/Printer/ExprPrinter.php +++ b/src/Node/Printer/ExprPrinter.php @@ -8,13 +8,8 @@ class ExprPrinter { - /** - * @var Printer - */ - private $printer; - public function __construct(Printer $printer) + public function __construct(private Printer $printer) { - $this->printer = $printer; } public function printExpr(Expr $expr): string diff --git a/src/Node/Property/PropertyRead.php b/src/Node/Property/PropertyRead.php index c5c1fd1ac3a..27bc3ba5c47 100644 --- a/src/Node/Property/PropertyRead.php +++ b/src/Node/Property/PropertyRead.php @@ -10,22 +10,13 @@ class PropertyRead { - /** - * @var PropertyFetch|StaticPropertyFetch - */ - private $fetch; - /** - * @var Scope - */ - private $scope; - /** - * @param PropertyFetch|StaticPropertyFetch $fetch - */ - public function __construct($fetch, Scope $scope) + public function __construct( + private PropertyFetch|StaticPropertyFetch $fetch, + private Scope $scope, + ) { - $this->fetch = $fetch; - $this->scope = $scope; } + /** * @return PropertyFetch|StaticPropertyFetch */ diff --git a/src/Node/Property/PropertyWrite.php b/src/Node/Property/PropertyWrite.php index bea00cdc4a6..9577dc7fa85 100644 --- a/src/Node/Property/PropertyWrite.php +++ b/src/Node/Property/PropertyWrite.php @@ -10,26 +10,8 @@ class PropertyWrite { - /** - * @var PropertyFetch|StaticPropertyFetch - */ - private $fetch; - /** - * @var Scope - */ - private $scope; - /** - * @var bool - */ - private $promotedPropertyWrite; - /** - * @param PropertyFetch|StaticPropertyFetch $fetch - */ - public function __construct($fetch, Scope $scope, bool $promotedPropertyWrite) + public function __construct(private PropertyFetch|StaticPropertyFetch $fetch, private Scope $scope, private bool $promotedPropertyWrite) { - $this->fetch = $fetch; - $this->scope = $scope; - $this->promotedPropertyWrite = $promotedPropertyWrite; } /** diff --git a/src/Node/PropertyAssignNode.php b/src/Node/PropertyAssignNode.php index b79b8f60587..62a5d7ac1e3 100644 --- a/src/Node/PropertyAssignNode.php +++ b/src/Node/PropertyAssignNode.php @@ -8,32 +8,16 @@ class PropertyAssignNode extends NodeAbstract implements VirtualNode { - /** - * @var Expr\PropertyFetch|Expr\StaticPropertyFetch - */ - private $propertyFetch; - /** - * @var Expr - */ - private $assignedExpr; - /** - * @var bool - */ - private $assignOp; - /** - * @param Expr\PropertyFetch|Expr\StaticPropertyFetch $propertyFetch - */ - public function __construct($propertyFetch, Expr $assignedExpr, bool $assignOp) + public function __construct( + private Expr\PropertyFetch|Expr\StaticPropertyFetch $propertyFetch, + private Expr $assignedExpr, + private bool $assignOp, + ) { - $this->propertyFetch = $propertyFetch; - $this->assignedExpr = $assignedExpr; - $this->assignOp = $assignOp; parent::__construct($propertyFetch->getAttributes()); } - /** - * @return Expr\PropertyFetch|Expr\StaticPropertyFetch - */ - public function getPropertyFetch() + + public function getPropertyFetch(): Expr\PropertyFetch|Expr\StaticPropertyFetch { return $this->propertyFetch; } diff --git a/src/Node/ReturnStatement.php b/src/Node/ReturnStatement.php index 0bafc2d133b..99767fba7b4 100644 --- a/src/Node/ReturnStatement.php +++ b/src/Node/ReturnStatement.php @@ -10,18 +10,10 @@ class ReturnStatement { - /** - * @var Scope - */ - private $scope; - /** - * @var Node\Stmt\Return_ - */ - private $returnNode; - - public function __construct(Scope $scope, Return_ $returnNode) + private Node\Stmt\Return_ $returnNode; + + public function __construct(private Scope $scope, Return_ $returnNode) { - $this->scope = $scope; $this->returnNode = $returnNode; } diff --git a/src/Node/StaticMethodCallableNode.php b/src/Node/StaticMethodCallableNode.php index 9b4e2d1dc2e..a4c6e675ef2 100644 --- a/src/Node/StaticMethodCallableNode.php +++ b/src/Node/StaticMethodCallableNode.php @@ -10,29 +10,15 @@ class StaticMethodCallableNode extends Expr implements VirtualNode { - /** - * @var Name|Expr - */ - private $class; - /** - * @var Identifier|Expr - */ - private $name; - /** - * @var Expr\StaticCall - */ - private $originalNode; - /** - * @param Name|Expr $class - * @param Identifier|Expr $name - */ - public function __construct($class, $name, Expr\StaticCall $originalNode) + public function __construct( + private Name|Expr $class, + private Identifier|Expr $name, + private Expr\StaticCall $originalNode, + ) { - $this->class = $class; - $this->name = $name; - $this->originalNode = $originalNode; parent::__construct($originalNode->getAttributes()); } + /** * @return Expr|Name */ diff --git a/src/Node/UnreachableStatementNode.php b/src/Node/UnreachableStatementNode.php index b2802d13b38..fb05c30a509 100644 --- a/src/Node/UnreachableStatementNode.php +++ b/src/Node/UnreachableStatementNode.php @@ -8,13 +8,8 @@ class UnreachableStatementNode extends Stmt implements VirtualNode { - /** - * @var Stmt - */ - private $originalStatement; - public function __construct(Stmt $originalStatement) + public function __construct(private Stmt $originalStatement) { - $this->originalStatement = $originalStatement; parent::__construct($originalStatement->getAttributes()); } diff --git a/src/Node/VarTagChangedExpressionTypeNode.php b/src/Node/VarTagChangedExpressionTypeNode.php index 182b30c3722..6689aa7a0dc 100644 --- a/src/Node/VarTagChangedExpressionTypeNode.php +++ b/src/Node/VarTagChangedExpressionTypeNode.php @@ -9,18 +9,8 @@ class VarTagChangedExpressionTypeNode extends NodeAbstract implements VirtualNode { - /** - * @var VarTag - */ - private $varTag; - /** - * @var Expr - */ - private $expr; - public function __construct(VarTag $varTag, Expr $expr) + public function __construct(private VarTag $varTag, private Expr $expr) { - $this->varTag = $varTag; - $this->expr = $expr; parent::__construct($expr->getAttributes()); } diff --git a/src/Parallel/ParallelAnalyser.php b/src/Parallel/ParallelAnalyser.php index 1728d6b8cdc..682331f8872 100644 --- a/src/Parallel/ParallelAnalyser.php +++ b/src/Parallel/ParallelAnalyser.php @@ -36,218 +36,241 @@ class ParallelAnalyser { - /** - * @var int - */ - private $internalErrorsCountLimit; - /** - * @var int - */ - private $decoderBufferSize; - private const DEFAULT_TIMEOUT = 600.0; + private const DEFAULT_TIMEOUT = 600.0; - /** - * @var float - */ - private $processTimeout; + private float $processTimeout; - /** - * @var ProcessPool - */ - private $processPool; - - public function __construct(int $internalErrorsCountLimit, float $processTimeout, int $decoderBufferSize) - { - $this->internalErrorsCountLimit = $internalErrorsCountLimit; - $this->decoderBufferSize = $decoderBufferSize; - $this->processTimeout = max($processTimeout, self::DEFAULT_TIMEOUT); - } + private ProcessPool $processPool; + + public function __construct( + private int $internalErrorsCountLimit, + float $processTimeout, + private int $decoderBufferSize, + ) + { + $this->processTimeout = max($processTimeout, self::DEFAULT_TIMEOUT); + } /** - * @param Closure(int ): void|null $postFileCallback - * @param (callable(list, list, string[]): void)|null $onFileAnalysisHandler - */ - public function analyse(LoopInterface $loop, Schedule $schedule, string $mainScript, ?Closure $postFileCallback, ?string $projectConfigFile, InputInterface $input, ?callable $onFileAnalysisHandler) : PromiseInterface - { - $jobs = array_reverse($schedule->getJobs()); - $numberOfProcesses = $schedule->getNumberOfProcesses(); - $someChildEnded = false; - $errors = []; - $locallyIgnoredErrors = []; - $peakMemoryUsages = []; - $internalErrors = []; - $internalErrorsCount = 0; - $collectedData = []; - $dependencies = []; - $reachedInternalErrorsCountLimit = false; - $exportedNodes = []; - $deferred = new Deferred(); - $server = new TcpServer('127.0.0.1:0', $loop); - $this->processPool = new ProcessPool($server, static function () use ($deferred, &$jobs, &$internalErrors, &$internalErrorsCount, &$reachedInternalErrorsCountLimit, &$errors, &$locallyIgnoredErrors, &$collectedData, &$dependencies, &$exportedNodes, &$peakMemoryUsages): void { - if (count($jobs) > 0 && $internalErrorsCount === 0) { - $internalErrors[] = 'Some parallel worker jobs have not finished.'; - $internalErrorsCount++; - } - - $deferred->resolve(new AnalyserResult($errors, $locallyIgnoredErrors, $internalErrors, $collectedData, $internalErrorsCount === 0 ? $dependencies : null, $exportedNodes, $reachedInternalErrorsCountLimit, array_sum($peakMemoryUsages))); - }); - $server->on('connection', function (ConnectionInterface $connection) use (&$jobs): void { - // phpcs:disable SlevomatCodingStandard.Namespaces.ReferenceUsedNamesOnly - $jsonInvalidUtf8Ignore = defined('JSON_INVALID_UTF8_IGNORE') ? JSON_INVALID_UTF8_IGNORE : 0; - // phpcs:enable - $decoder = new Decoder($connection, true, 512, $jsonInvalidUtf8Ignore, $this->decoderBufferSize); - $encoder = new Encoder($connection, $jsonInvalidUtf8Ignore); - $decoder->on('data', function (array $data) use (&$jobs, $decoder, $encoder): void { - if ($data['action'] !== 'hello') { - return; - } - - $identifier = $data['identifier']; - $process = $this->processPool->getProcess($identifier); - $process->bindConnection($decoder, $encoder); - if (count($jobs) === 0) { - $this->processPool->tryQuitProcess($identifier); - return; - } - - $job = array_pop($jobs); - $process->request(['action' => 'analyse', 'files' => $job]); - }); - }); - /** @var string $serverAddress */ - $serverAddress = $server->getAddress(); - /** @var int<0, 65535> $serverPort */ - $serverPort = parse_url($serverAddress, PHP_URL_PORT); - $handleError = function (Throwable $error) use (&$internalErrors, &$internalErrorsCount, &$reachedInternalErrorsCountLimit): void { - $internalErrors[] = sprintf('Internal error: ' . $error->getMessage()); - $internalErrorsCount++; - $reachedInternalErrorsCountLimit = true; - $this->processPool->quitAll(); - }; - for ($i = 0; $i < $numberOfProcesses; $i++) { - if (count($jobs) === 0) { - break; - } - - $processIdentifier = Random::generate(); - $commandOptions = [ - '--port', - (string) $serverPort, - '--identifier', - $processIdentifier, - ]; - - $process = new Process(ProcessHelper::getWorkerCommand($mainScript, 'worker', $projectConfigFile, $commandOptions, $input), $loop, $this->processTimeout); - $process->start(function (array $json) use ($process, &$internalErrors, &$errors, &$locallyIgnoredErrors, &$collectedData, &$dependencies, &$exportedNodes, &$peakMemoryUsages, &$jobs, $postFileCallback, &$internalErrorsCount, &$reachedInternalErrorsCountLimit, $processIdentifier, $onFileAnalysisHandler): void { - $fileErrors = []; - foreach ($json['errors'] as $jsonError) { - if (is_string($jsonError)) { - $internalErrors[] = sprintf('Internal error: %s', $jsonError); - continue; - } - - $fileErrors[] = Error::decode($jsonError); - } - - $locallyIgnoredFileErrors = []; - foreach ($json['locallyIgnoredErrors'] as $locallyIgnoredJsonError) { - $locallyIgnoredFileErrors[] = Error::decode($locallyIgnoredJsonError); - } - - if ($onFileAnalysisHandler !== null) { - $onFileAnalysisHandler($fileErrors, $locallyIgnoredFileErrors, $json['files']); - } - - foreach ($fileErrors as $fileError) { - $errors[] = $fileError; - } - - foreach ($locallyIgnoredFileErrors as $locallyIgnoredFileError) { - $locallyIgnoredErrors[] = $locallyIgnoredFileError; - } - - foreach ($json['collectedData'] as $jsonData) { - $collectedData[] = CollectedData::decode($jsonData); - } - - /** - * @var string $file - * @var array $fileDependencies - */ - foreach ($json['dependencies'] as $file => $fileDependencies) { - $dependencies[$file] = $fileDependencies; - } - - /** - * @var string $file - * @var array $fileExportedNodes - */ - foreach ($json['exportedNodes'] as $file => $fileExportedNodes) { - if (count($fileExportedNodes) === 0) { - continue; - } - $exportedNodes[$file] = array_map(static function (array $node): RootExportedNode { - $class = $node['type']; - - return $class::decode($node['data']); - }, $fileExportedNodes); - } - - if ($postFileCallback !== null) { - $postFileCallback(count($json['files'])); - } - - if (!isset($peakMemoryUsages[$processIdentifier]) || $peakMemoryUsages[$processIdentifier] < $json['memoryUsage']) { - $peakMemoryUsages[$processIdentifier] = $json['memoryUsage']; - } - - $internalErrorsCount += $json['internalErrorsCount']; - if ($internalErrorsCount >= $this->internalErrorsCountLimit) { - $reachedInternalErrorsCountLimit = true; - $this->processPool->quitAll(); - } - - if (count($jobs) === 0) { - $this->processPool->tryQuitProcess($processIdentifier); - return; - } - - $job = array_pop($jobs); - $process->request(['action' => 'analyse', 'files' => $job]); - }, $handleError, function ($exitCode, string $output) use (&$someChildEnded, &$peakMemoryUsages, &$internalErrors, &$internalErrorsCount, $processIdentifier): void { - if ($someChildEnded === false) { - $peakMemoryUsages['main'] = memory_get_usage(true); - } - $someChildEnded = true; - - $this->processPool->tryQuitProcess($processIdentifier); - if ($exitCode === 0) { - return; - } - if ($exitCode === null) { - return; - } - - $memoryLimitMessage = 'PHPStan process crashed because it reached configured PHP memory limit'; - if (str_contains($output, $memoryLimitMessage)) { - foreach ($internalErrors as $internalError) { - if (!str_contains($internalError, $memoryLimitMessage)) { - continue; - } - - return; - } - $internalErrors[] = sprintf(sprintf("Child process error: %s: %s\n%s\n", $memoryLimitMessage, ini_get('memory_limit'), 'Increase your memory limit in php.ini or run PHPStan with --memory-limit CLI option.')); - $internalErrorsCount++; - return; - } - - $internalErrors[] = sprintf('Child process error (exit code %d): %s', $exitCode, $output); - $internalErrorsCount++; - }); - $this->processPool->attachProcess($processIdentifier, $process); - } - return $deferred->promise(); + * @param Closure(int ): void|null $postFileCallback + * @param (callable(list, list, string[]): void)|null $onFileAnalysisHandler + */ + public function analyse( + LoopInterface $loop, + Schedule $schedule, + string $mainScript, + ?Closure $postFileCallback, + ?string $projectConfigFile, + InputInterface $input, + ?callable $onFileAnalysisHandler, + ): PromiseInterface + { + $jobs = array_reverse($schedule->getJobs()); + + $numberOfProcesses = $schedule->getNumberOfProcesses(); + $someChildEnded = false; + $errors = []; + $locallyIgnoredErrors = []; + $peakMemoryUsages = []; + $internalErrors = []; + $internalErrorsCount = 0; + $collectedData = []; + $dependencies = []; + $reachedInternalErrorsCountLimit = false; + $exportedNodes = []; + + $deferred = new Deferred(); + + $server = new TcpServer('127.0.0.1:0', $loop); + $this->processPool = new ProcessPool($server, static function () use ($deferred, &$jobs, &$internalErrors, &$internalErrorsCount, &$reachedInternalErrorsCountLimit, &$errors, &$locallyIgnoredErrors, &$collectedData, &$dependencies, &$exportedNodes, &$peakMemoryUsages): void { + if (count($jobs) > 0 && $internalErrorsCount === 0) { + $internalErrors[] = 'Some parallel worker jobs have not finished.'; + $internalErrorsCount++; + } + + $deferred->resolve(new AnalyserResult( + $errors, + $locallyIgnoredErrors, + $internalErrors, + $collectedData, + $internalErrorsCount === 0 ? $dependencies : null, + $exportedNodes, + $reachedInternalErrorsCountLimit, + array_sum($peakMemoryUsages), // not 100% correct as the peak usages of workers might not have met + )); + }); + $server->on('connection', function (ConnectionInterface $connection) use (&$jobs): void { + // phpcs:disable SlevomatCodingStandard.Namespaces.ReferenceUsedNamesOnly + $jsonInvalidUtf8Ignore = defined('JSON_INVALID_UTF8_IGNORE') ? JSON_INVALID_UTF8_IGNORE : 0; + // phpcs:enable + $decoder = new Decoder($connection, true, 512, $jsonInvalidUtf8Ignore, $this->decoderBufferSize); + $encoder = new Encoder($connection, $jsonInvalidUtf8Ignore); + $decoder->on('data', function (array $data) use (&$jobs, $decoder, $encoder): void { + if ($data['action'] !== 'hello') { + return; + } + + $identifier = $data['identifier']; + $process = $this->processPool->getProcess($identifier); + $process->bindConnection($decoder, $encoder); + if (count($jobs) === 0) { + $this->processPool->tryQuitProcess($identifier); + return; + } + + $job = array_pop($jobs); + $process->request(['action' => 'analyse', 'files' => $job]); + }); + }); + /** @var string $serverAddress */ + $serverAddress = $server->getAddress(); + + /** @var int<0, 65535> $serverPort */ + $serverPort = parse_url($serverAddress, PHP_URL_PORT); + + $handleError = function (Throwable $error) use (&$internalErrors, &$internalErrorsCount, &$reachedInternalErrorsCountLimit): void { + $internalErrors[] = sprintf('Internal error: ' . $error->getMessage()); + $internalErrorsCount++; + $reachedInternalErrorsCountLimit = true; + $this->processPool->quitAll(); + }; + + for ($i = 0; $i < $numberOfProcesses; $i++) { + if (count($jobs) === 0) { + break; + } + + $processIdentifier = Random::generate(); + $commandOptions = [ + '--port', + (string) $serverPort, + '--identifier', + $processIdentifier, + ]; + + $process = new Process(ProcessHelper::getWorkerCommand( + $mainScript, + 'worker', + $projectConfigFile, + $commandOptions, + $input, + ), $loop, $this->processTimeout); + $process->start(function (array $json) use ($process, &$internalErrors, &$errors, &$locallyIgnoredErrors, &$collectedData, &$dependencies, &$exportedNodes, &$peakMemoryUsages, &$jobs, $postFileCallback, &$internalErrorsCount, &$reachedInternalErrorsCountLimit, $processIdentifier, $onFileAnalysisHandler): void { + $fileErrors = []; + foreach ($json['errors'] as $jsonError) { + if (is_string($jsonError)) { + $internalErrors[] = sprintf('Internal error: %s', $jsonError); + continue; + } + + $fileErrors[] = Error::decode($jsonError); + } + + $locallyIgnoredFileErrors = []; + foreach ($json['locallyIgnoredErrors'] as $locallyIgnoredJsonError) { + $locallyIgnoredFileErrors[] = Error::decode($locallyIgnoredJsonError); + } + + if ($onFileAnalysisHandler !== null) { + $onFileAnalysisHandler($fileErrors, $locallyIgnoredFileErrors, $json['files']); + } + + foreach ($fileErrors as $fileError) { + $errors[] = $fileError; + } + + foreach ($locallyIgnoredFileErrors as $locallyIgnoredFileError) { + $locallyIgnoredErrors[] = $locallyIgnoredFileError; + } + + foreach ($json['collectedData'] as $jsonData) { + $collectedData[] = CollectedData::decode($jsonData); + } + + /** + * @var string $file + * @var array $fileDependencies + */ + foreach ($json['dependencies'] as $file => $fileDependencies) { + $dependencies[$file] = $fileDependencies; + } + + /** + * @var string $file + * @var array $fileExportedNodes + */ + foreach ($json['exportedNodes'] as $file => $fileExportedNodes) { + if (count($fileExportedNodes) === 0) { + continue; + } + $exportedNodes[$file] = array_map(static function (array $node): RootExportedNode { + $class = $node['type']; + + return $class::decode($node['data']); + }, $fileExportedNodes); + } + + if ($postFileCallback !== null) { + $postFileCallback(count($json['files'])); + } + + if (!isset($peakMemoryUsages[$processIdentifier]) || $peakMemoryUsages[$processIdentifier] < $json['memoryUsage']) { + $peakMemoryUsages[$processIdentifier] = $json['memoryUsage']; + } + + $internalErrorsCount += $json['internalErrorsCount']; + if ($internalErrorsCount >= $this->internalErrorsCountLimit) { + $reachedInternalErrorsCountLimit = true; + $this->processPool->quitAll(); + } + + if (count($jobs) === 0) { + $this->processPool->tryQuitProcess($processIdentifier); + return; + } + + $job = array_pop($jobs); + $process->request(['action' => 'analyse', 'files' => $job]); + }, $handleError, function ($exitCode, string $output) use (&$someChildEnded, &$peakMemoryUsages, &$internalErrors, &$internalErrorsCount, $processIdentifier): void { + if ($someChildEnded === false) { + $peakMemoryUsages['main'] = memory_get_usage(true); + } + $someChildEnded = true; + + $this->processPool->tryQuitProcess($processIdentifier); + if ($exitCode === 0) { + return; + } + if ($exitCode === null) { + return; + } + + $memoryLimitMessage = 'PHPStan process crashed because it reached configured PHP memory limit'; + if (str_contains($output, $memoryLimitMessage)) { + foreach ($internalErrors as $internalError) { + if (!str_contains($internalError, $memoryLimitMessage)) { + continue; + } + + return; + } + $internalErrors[] = sprintf(sprintf( + "Child process error: %s: %s\n%s\n", + $memoryLimitMessage, + ini_get('memory_limit'), + 'Increase your memory limit in php.ini or run PHPStan with --memory-limit CLI option.', + )); + $internalErrorsCount++; + return; + } + + $internalErrors[] = sprintf('Child process error (exit code %d): %s', $exitCode, $output); + $internalErrorsCount++; + }); + $this->processPool->attachProcess($processIdentifier, $process); } + return $deferred->promise(); + } + } diff --git a/src/Parallel/Process.php b/src/Parallel/Process.php index c6a2286a66f..34fc0dcc5c5 100644 --- a/src/Parallel/Process.php +++ b/src/Parallel/Process.php @@ -19,27 +19,9 @@ class Process { - /** - * @var string - */ - private $command; - /** - * @var LoopInterface - */ - private $loop; - /** - * @var float - */ - private $timeoutSeconds; - /** - * @var \React\ChildProcess\Process - */ - public $process; + public \React\ChildProcess\Process $process; - /** - * @var ?WritableStreamInterface - */ - private $in = null; + private ?WritableStreamInterface $in = null; /** @var resource */ private $stdOut; @@ -53,16 +35,14 @@ class Process /** @var callable(Throwable $exception): void */ private $onError; - /** - * @var ?TimerInterface - */ - private $timer = null; + private ?TimerInterface $timer = null; - public function __construct(string $command, LoopInterface $loop, float $timeoutSeconds) + public function __construct( + private string $command, + private LoopInterface $loop, + private float $timeoutSeconds, + ) { - $this->command = $command; - $this->loop = $loop; - $this->timeoutSeconds = $timeoutSeconds; } /** diff --git a/src/Parallel/ProcessPool.php b/src/Parallel/ProcessPool.php index d1414e6c074..ac0569c5091 100644 --- a/src/Parallel/ProcessPool.php +++ b/src/Parallel/ProcessPool.php @@ -12,12 +12,8 @@ class ProcessPool { - /** - * @var TcpServer - */ - private $server; /** @var array */ - private $processes = []; + private array $processes = []; /** @var callable(): void */ private $onServerClose; @@ -25,9 +21,8 @@ class ProcessPool /** * @param callable(): void $onServerClose */ - public function __construct(TcpServer $server, callable $onServerClose) + public function __construct(private TcpServer $server, callable $onServerClose) { - $this->server = $server; $this->onServerClose = $onServerClose; } diff --git a/src/Parallel/Schedule.php b/src/Parallel/Schedule.php index 0bb562a80d4..42935bd6c58 100644 --- a/src/Parallel/Schedule.php +++ b/src/Parallel/Schedule.php @@ -5,21 +5,11 @@ class Schedule { - /** - * @var int - */ - private $numberOfProcesses; - /** - * @var array> - */ - private $jobs; /** * @param array> $jobs */ - public function __construct(int $numberOfProcesses, array $jobs) + public function __construct(private int $numberOfProcesses, private array $jobs) { - $this->numberOfProcesses = $numberOfProcesses; - $this->jobs = $jobs; } public function getNumberOfProcesses(): int diff --git a/src/Parallel/Scheduler.php b/src/Parallel/Scheduler.php index 02732911e3e..1a3bd38ac4c 100644 --- a/src/Parallel/Scheduler.php +++ b/src/Parallel/Scheduler.php @@ -10,36 +10,35 @@ class Scheduler { - /** - * @var positive-int - */ - private $jobSize; - /** - * @var positive-int - */ - private $maximumNumberOfProcesses; - /** - * @var positive-int - */ - private $minimumNumberOfJobsPerProcess; - /** - * @param positive-int $jobSize - * @param positive-int $maximumNumberOfProcesses - * @param positive-int $minimumNumberOfJobsPerProcess - */ - public function __construct(int $jobSize, int $maximumNumberOfProcesses, int $minimumNumberOfJobsPerProcess) - { - $this->jobSize = $jobSize; - $this->maximumNumberOfProcesses = $maximumNumberOfProcesses; - $this->minimumNumberOfJobsPerProcess = $minimumNumberOfJobsPerProcess; - } - /** - * @param array $files - */ - public function scheduleWork(int $cpuCores, array $files) : Schedule - { - $jobs = array_chunk($files, $this->jobSize); - $numberOfProcesses = min(max((int) floor(count($jobs) / $this->minimumNumberOfJobsPerProcess), 1), $cpuCores); - return new Schedule(min($numberOfProcesses, $this->maximumNumberOfProcesses), $jobs); - } + + /** + * @param positive-int $jobSize + * @param positive-int $maximumNumberOfProcesses + * @param positive-int $minimumNumberOfJobsPerProcess + */ + public function __construct( + private int $jobSize, + private int $maximumNumberOfProcesses, + private int $minimumNumberOfJobsPerProcess, + ) + { + } + + /** + * @param array $files + */ + public function scheduleWork( + int $cpuCores, + array $files, + ): Schedule + { + $jobs = array_chunk($files, $this->jobSize); + $numberOfProcesses = min( + max((int) floor(count($jobs) / $this->minimumNumberOfJobsPerProcess), 1), + $cpuCores, + ); + + return new Schedule(min($numberOfProcesses, $this->maximumNumberOfProcesses), $jobs); + } + } diff --git a/src/Parser/CachedParser.php b/src/Parser/CachedParser.php index 52359942b26..225375678cb 100644 --- a/src/Parser/CachedParser.php +++ b/src/Parser/CachedParser.php @@ -9,29 +9,19 @@ class CachedParser implements Parser { - /** - * @var Parser - */ - private $originalParser; - /** - * @var int - */ - private $cachedNodesByStringCountMax; /** @var array*/ - private $cachedNodesByString = []; + private array $cachedNodesByString = []; - /** - * @var int - */ - private $cachedNodesByStringCount = 0; + private int $cachedNodesByStringCount = 0; /** @var array */ - private $parsedByString = []; + private array $parsedByString = []; - public function __construct(Parser $originalParser, int $cachedNodesByStringCountMax) + public function __construct( + private Parser $originalParser, + private int $cachedNodesByStringCountMax, + ) { - $this->originalParser = $originalParser; - $this->cachedNodesByStringCountMax = $cachedNodesByStringCountMax; } /** @@ -41,7 +31,12 @@ public function __construct(Parser $originalParser, int $cachedNodesByStringCoun public function parseFile(string $file): array { if ($this->cachedNodesByStringCountMax !== 0 && $this->cachedNodesByStringCount >= $this->cachedNodesByStringCountMax) { - $this->cachedNodesByString = array_slice($this->cachedNodesByString, 1, null, true); + $this->cachedNodesByString = array_slice( + $this->cachedNodesByString, + 1, + null, + true, + ); --$this->cachedNodesByStringCount; } @@ -62,7 +57,12 @@ public function parseFile(string $file): array public function parseString(string $sourceCode): array { if ($this->cachedNodesByStringCountMax !== 0 && $this->cachedNodesByStringCount >= $this->cachedNodesByStringCountMax) { - $this->cachedNodesByString = array_slice($this->cachedNodesByString, 1, null, true); + $this->cachedNodesByString = array_slice( + $this->cachedNodesByString, + 1, + null, + true, + ); --$this->cachedNodesByStringCount; } diff --git a/src/Parser/CleaningParser.php b/src/Parser/CleaningParser.php index 12def4d9d45..98db0e64ef8 100644 --- a/src/Parser/CleaningParser.php +++ b/src/Parser/CleaningParser.php @@ -9,18 +9,10 @@ class CleaningParser implements Parser { - /** - * @var Parser - */ - private $wrappedParser; - /** - * @var NodeTraverser - */ - private $traverser; + private NodeTraverser $traverser; - public function __construct(Parser $wrappedParser, PhpVersion $phpVersion) + public function __construct(private Parser $wrappedParser, PhpVersion $phpVersion) { - $this->wrappedParser = $wrappedParser; $this->traverser = new NodeTraverser(); $this->traverser->addVisitor(new CleaningVisitor()); $this->traverser->addVisitor(new RemoveUnusedCodeByPhpVersionIdVisitor($phpVersion->getVersionString())); diff --git a/src/Parser/CleaningVisitor.php b/src/Parser/CleaningVisitor.php index d4f08a5d598..0a2c9aecff2 100644 --- a/src/Parser/CleaningVisitor.php +++ b/src/Parser/CleaningVisitor.php @@ -11,10 +11,7 @@ class CleaningVisitor extends NodeVisitorAbstract { - /** - * @var NodeFinder - */ - private $nodeFinder; + private NodeFinder $nodeFinder; public function __construct() { diff --git a/src/Parser/DeclarePositionVisitor.php b/src/Parser/DeclarePositionVisitor.php index 6247ba4b114..08818c16522 100644 --- a/src/Parser/DeclarePositionVisitor.php +++ b/src/Parser/DeclarePositionVisitor.php @@ -9,10 +9,7 @@ class DeclarePositionVisitor extends NodeVisitorAbstract { - /** - * @var bool - */ - private $isFirstStatement = true; + private bool $isFirstStatement = true; public const ATTRIBUTE_NAME = 'isFirstStatement'; diff --git a/src/Parser/LexerFactory.php b/src/Parser/LexerFactory.php index ec27842cb03..624eb251bfd 100644 --- a/src/Parser/LexerFactory.php +++ b/src/Parser/LexerFactory.php @@ -9,15 +9,10 @@ class LexerFactory { - /** - * @var PhpVersion - */ - private $phpVersion; private const OPTIONS = ['usedAttributes' => ['comments', 'startLine', 'endLine', 'startTokenPos', 'endTokenPos', 'startFilePos', 'endFilePos']]; - public function __construct(PhpVersion $phpVersion) + public function __construct(private PhpVersion $phpVersion) { - $this->phpVersion = $phpVersion; } public function create(): Lexer diff --git a/src/Parser/ParentStmtTypesVisitor.php b/src/Parser/ParentStmtTypesVisitor.php index e84696848a3..a7da560658e 100644 --- a/src/Parser/ParentStmtTypesVisitor.php +++ b/src/Parser/ParentStmtTypesVisitor.php @@ -14,7 +14,7 @@ final class ParentStmtTypesVisitor extends NodeVisitorAbstract public const ATTRIBUTE_NAME = 'parentStmtTypes'; /** @var array> */ - private $typeStack = []; + private array $typeStack = []; public function beforeTraverse(array $nodes): ?array { diff --git a/src/Parser/ParserErrorsException.php b/src/Parser/ParserErrorsException.php index 91b44ba0f1f..dbae41eacc1 100644 --- a/src/Parser/ParserErrorsException.php +++ b/src/Parser/ParserErrorsException.php @@ -11,38 +11,29 @@ class ParserErrorsException extends Exception { - /** - * @var Error[] - */ - private $errors; - /** - * @var ?string - */ - private $parsedFile; - /** @var mixed[] */ - private $attributes; + /** @var mixed[] */ + private array $attributes; /** - * @param Error[] $errors - */ - public function __construct(array $errors, ?string $parsedFile) - { - $this->errors = $errors; - $this->parsedFile = $parsedFile; - parent::__construct(implode(', ', array_map(static function (Error $error) : string { - return $error->getMessage(); - }, $errors))); - if (count($errors) > 0) { - $this->attributes = $errors[0]->getAttributes(); - } else { - $this->attributes = []; - } - } + * @param Error[] $errors + */ + public function __construct( + private array $errors, + private ?string $parsedFile, + ) + { + parent::__construct(implode(', ', array_map(static fn (Error $error): string => $error->getMessage(), $errors))); + if (count($errors) > 0) { + $this->attributes = $errors[0]->getAttributes(); + } else { + $this->attributes = []; + } + } /** - * @return Error[] - */ - public function getErrors(): array + * @return Error[] + */ + public function getErrors(): array { return $this->errors; } @@ -53,9 +44,9 @@ public function getParsedFile(): ?string } /** - * @return mixed[] - */ - public function getAttributes(): array + * @return mixed[] + */ + public function getAttributes(): array { return $this->attributes; } diff --git a/src/Parser/PathRoutingParser.php b/src/Parser/PathRoutingParser.php index e3ef6ff68f8..436416bcf95 100644 --- a/src/Parser/PathRoutingParser.php +++ b/src/Parser/PathRoutingParser.php @@ -9,31 +9,16 @@ class PathRoutingParser implements Parser { - /** - * @var FileHelper - */ - private $fileHelper; - /** - * @var Parser - */ - private $currentPhpVersionRichParser; - /** - * @var Parser - */ - private $currentPhpVersionSimpleParser; - /** - * @var Parser - */ - private $php8Parser; /** @var bool[] filePath(string) => bool(true) */ - private $analysedFiles = []; - - public function __construct(FileHelper $fileHelper, Parser $currentPhpVersionRichParser, Parser $currentPhpVersionSimpleParser, Parser $php8Parser) + private array $analysedFiles = []; + + public function __construct( + private FileHelper $fileHelper, + private Parser $currentPhpVersionRichParser, + private Parser $currentPhpVersionSimpleParser, + private Parser $php8Parser, + ) { - $this->fileHelper = $fileHelper; - $this->currentPhpVersionRichParser = $currentPhpVersionRichParser; - $this->currentPhpVersionSimpleParser = $currentPhpVersionSimpleParser; - $this->php8Parser = $php8Parser; } /** diff --git a/src/Parser/PhpParserDecorator.php b/src/Parser/PhpParserDecorator.php index abccd4ce0ae..5626f20b1ab 100644 --- a/src/Parser/PhpParserDecorator.php +++ b/src/Parser/PhpParserDecorator.php @@ -11,13 +11,8 @@ class PhpParserDecorator implements Parser { - /** - * @var \PHPStan\Parser\Parser - */ - private $wrappedParser; - public function __construct(\PHPStan\Parser\Parser $wrappedParser) + public function __construct(private \PHPStan\Parser\Parser $wrappedParser) { - $this->wrappedParser = $wrappedParser; } /** diff --git a/src/Parser/RemoveUnusedCodeByPhpVersionIdVisitor.php b/src/Parser/RemoveUnusedCodeByPhpVersionIdVisitor.php index a07c9aef182..eed9b93bf7c 100644 --- a/src/Parser/RemoveUnusedCodeByPhpVersionIdVisitor.php +++ b/src/Parser/RemoveUnusedCodeByPhpVersionIdVisitor.php @@ -11,19 +11,11 @@ class RemoveUnusedCodeByPhpVersionIdVisitor extends NodeVisitorAbstract { - /** - * @var string - */ - private $phpVersionString; - public function __construct(string $phpVersionString) + public function __construct(private string $phpVersionString) { - $this->phpVersionString = $phpVersionString; } - /** - * @return Node|int|null - */ - public function enterNode(Node $node) + public function enterNode(Node $node): Node|int|null { if (!$node instanceof Node\Stmt\If_) { return null; diff --git a/src/Parser/RichParser.php b/src/Parser/RichParser.php index 65394809fa3..b21729086dc 100644 --- a/src/Parser/RichParser.php +++ b/src/Parser/RichParser.php @@ -35,44 +35,21 @@ class RichParser implements Parser { - /** - * @var \PhpParser\Parser - */ - private $parser; - /** - * @var Lexer - */ - private $lexer; - /** - * @var NameResolver - */ - private $nameResolver; - /** - * @var Container - */ - private $container; - /** - * @var IgnoreLexer - */ - private $ignoreLexer; - /** - * @var bool - */ - private $enableIgnoreErrorsWithinPhpDocs; public const VISITOR_SERVICE_TAG = 'phpstan.parser.richParserNodeVisitor'; private const PHPDOC_TAG_REGEX = '(@(?:[a-z][a-z0-9-\\\\]+:)?[a-z][a-z0-9-\\\\]*+)'; private const PHPDOC_DOCTRINE_TAG_REGEX = '(@[a-z_\\\\][a-z0-9_\:\\\\]*[a-z_][a-z0-9_]*)'; - public function __construct(\PhpParser\Parser $parser, Lexer $lexer, NameResolver $nameResolver, Container $container, IgnoreLexer $ignoreLexer, bool $enableIgnoreErrorsWithinPhpDocs = false) + public function __construct( + private \PhpParser\Parser $parser, + private Lexer $lexer, + private NameResolver $nameResolver, + private Container $container, + private IgnoreLexer $ignoreLexer, + private bool $enableIgnoreErrorsWithinPhpDocs = false, + ) { - $this->parser = $parser; - $this->lexer = $lexer; - $this->nameResolver = $nameResolver; - $this->container = $container; - $this->ignoreLexer = $ignoreLexer; - $this->enableIgnoreErrorsWithinPhpDocs = $enableIgnoreErrorsWithinPhpDocs; } /** @@ -126,9 +103,7 @@ public function parseString(string $sourceCode): array } foreach ($traitCollectingVisitor->traits as $trait) { - $trait->setAttribute('linesToIgnore', array_filter($linesToIgnore, static function (int $line) use($trait) : bool { - return $line >= $trait->getStartLine() && $line <= $trait->getEndLine(); - }, ARRAY_FILTER_USE_KEY)); + $trait->setAttribute('linesToIgnore', array_filter($linesToIgnore, static fn (int $line): bool => $line >= $trait->getStartLine() && $line <= $trait->getEndLine(), ARRAY_FILTER_USE_KEY)); } return $nodes; @@ -272,19 +247,27 @@ private function getLinesToIgnore(array $tokens): array /** * @return array */ - private function getLinesToIgnoreForTokenByIgnoreComment(string $tokenText, int $tokenLine, string $ignoreComment, bool $ignoreNextLine = false) : array + private function getLinesToIgnoreForTokenByIgnoreComment( + string $tokenText, + int $tokenLine, + string $ignoreComment, + bool $ignoreNextLine = false, + ): array { $lines = []; $positionsOfIgnoreComment = []; $offset = 0; + while (($pos = strpos($tokenText, $ignoreComment, $offset)) !== false) { $positionsOfIgnoreComment[] = $pos; $offset = $pos + 1; } + foreach ($positionsOfIgnoreComment as $pos) { $line = $tokenLine + substr_count(substr($tokenText, 0, $pos), "\n") + ($ignoreNextLine ? 1 : 0); $lines[$line] = null; } + return $lines; } @@ -296,9 +279,7 @@ private function parseIdentifiers(string $text, int $ignorePos): array { $text = substr($text, $ignorePos + strlen('@phpstan-ignore')); $tokens = $this->ignoreLexer->tokenize($text); - $tokens = array_values(array_filter($tokens, static function (array $token) { - return !in_array($token[IgnoreLexer::TYPE_OFFSET], [IgnoreLexer::TOKEN_WHITESPACE, IgnoreLexer::TOKEN_EOL], true); - })); + $tokens = array_values(array_filter($tokens, static fn (array $token) => !in_array($token[IgnoreLexer::TYPE_OFFSET], [IgnoreLexer::TOKEN_WHITESPACE, IgnoreLexer::TOKEN_EOL], true))); $c = count($tokens); $identifiers = []; diff --git a/src/Parser/SimpleParser.php b/src/Parser/SimpleParser.php index 9d8c867d78a..efcf47d786a 100644 --- a/src/Parser/SimpleParser.php +++ b/src/Parser/SimpleParser.php @@ -12,19 +12,13 @@ class SimpleParser implements Parser { - /** - * @var \PhpParser\Parser - */ - private $parser; - /** - * @var NameResolver - */ - private $nameResolver; - public function __construct(\PhpParser\Parser $parser, NameResolver $nameResolver) + public function __construct( + private \PhpParser\Parser $parser, + private NameResolver $nameResolver, + ) { - $this->parser = $parser; - $this->nameResolver = $nameResolver; } + /** * @param string $file path to a file to parse * @return Node\Stmt[] diff --git a/src/Parser/TraitCollectingVisitor.php b/src/Parser/TraitCollectingVisitor.php index d2927875b3d..e6341a9de63 100644 --- a/src/Parser/TraitCollectingVisitor.php +++ b/src/Parser/TraitCollectingVisitor.php @@ -9,7 +9,7 @@ final class TraitCollectingVisitor extends NodeVisitorAbstract { /** @var list */ - public $traits = []; + public array $traits = []; public function enterNode(Node $node): ?Node { diff --git a/src/Parser/TryCatchTypeVisitor.php b/src/Parser/TryCatchTypeVisitor.php index 7689e2fb45b..cca8bf4e3a3 100644 --- a/src/Parser/TryCatchTypeVisitor.php +++ b/src/Parser/TryCatchTypeVisitor.php @@ -14,7 +14,7 @@ final class TryCatchTypeVisitor extends NodeVisitorAbstract public const ATTRIBUTE_NAME = 'tryCatchTypes'; /** @var array|null> */ - private $typeStack = []; + private array $typeStack = []; public function beforeTraverse(array $nodes): ?array { diff --git a/src/Parser/TypeTraverserInstanceofVisitor.php b/src/Parser/TypeTraverserInstanceofVisitor.php index d8613dc5799..a39226bbb25 100644 --- a/src/Parser/TypeTraverserInstanceofVisitor.php +++ b/src/Parser/TypeTraverserInstanceofVisitor.php @@ -10,10 +10,7 @@ class TypeTraverserInstanceofVisitor extends NodeVisitorAbstract public const ATTRIBUTE_NAME = 'insideTypeTraverserMap'; - /** - * @var int - */ - private $depth = 0; + private int $depth = 0; public function beforeTraverse(array $nodes): ?array { diff --git a/src/Php/PhpVersion.php b/src/Php/PhpVersion.php index 79263f3d11f..2ca9954a25a 100644 --- a/src/Php/PhpVersion.php +++ b/src/Php/PhpVersion.php @@ -8,13 +8,8 @@ class PhpVersion { - /** - * @var int - */ - private $versionId; - public function __construct(int $versionId) + public function __construct(private int $versionId) { - $this->versionId = $versionId; } public function getVersionId(): int @@ -226,6 +221,7 @@ public function arrayFunctionsReturnNullWithNonArray(): bool return $this->versionId < 80000; } + // see https://www.php.net/manual/en/migration80.incompatible.php#migration80.incompatible.core.string-number-comparision public function castsNumbersToStringsOnLooseComparison(): bool { return $this->versionId >= 80000; diff --git a/src/Php/PhpVersionFactory.php b/src/Php/PhpVersionFactory.php index 8047e48fc03..2ed8fe67810 100644 --- a/src/Php/PhpVersionFactory.php +++ b/src/Php/PhpVersionFactory.php @@ -10,19 +10,13 @@ class PhpVersionFactory { - /** - * @var ?int - */ - private $versionId; - /** - * @var ?string - */ - private $composerPhpVersion; - public function __construct(?int $versionId, ?string $composerPhpVersion) + public function __construct( + private ?int $versionId, + private ?string $composerPhpVersion, + ) { - $this->versionId = $versionId; - $this->composerPhpVersion = $composerPhpVersion; } + public function create(): PhpVersion { $versionId = $this->versionId; diff --git a/src/Php/PhpVersionFactoryFactory.php b/src/Php/PhpVersionFactoryFactory.php index eb36448cf1e..870d1ff276d 100644 --- a/src/Php/PhpVersionFactoryFactory.php +++ b/src/Php/PhpVersionFactoryFactory.php @@ -14,22 +14,16 @@ class PhpVersionFactoryFactory { - /** - * @var ?int - */ - private $versionId; - /** - * @var string[] - */ - private $composerAutoloaderProjectPaths; /** * @param string[] $composerAutoloaderProjectPaths */ - public function __construct(?int $versionId, array $composerAutoloaderProjectPaths) + public function __construct( + private ?int $versionId, + private array $composerAutoloaderProjectPaths, + ) { - $this->versionId = $versionId; - $this->composerAutoloaderProjectPaths = $composerAutoloaderProjectPaths; } + public function create(): PhpVersionFactory { $composerPhpVersion = null; @@ -43,7 +37,7 @@ public function create(): PhpVersionFactory if (is_string($platformVersion)) { $composerPhpVersion = $platformVersion; } - } catch (CouldNotReadFileException | JsonException $e) { + } catch (CouldNotReadFileException | JsonException) { // pass } } diff --git a/src/PhpDoc/ConstExprParserFactory.php b/src/PhpDoc/ConstExprParserFactory.php index ee274ac5268..aa2ca2657de 100644 --- a/src/PhpDoc/ConstExprParserFactory.php +++ b/src/PhpDoc/ConstExprParserFactory.php @@ -7,13 +7,8 @@ class ConstExprParserFactory { - /** - * @var bool - */ - private $unescapeStrings; - public function __construct(bool $unescapeStrings) + public function __construct(private bool $unescapeStrings) { - $this->unescapeStrings = $unescapeStrings; } public function create(): ConstExprParser diff --git a/src/PhpDoc/CountableStubFilesExtension.php b/src/PhpDoc/CountableStubFilesExtension.php index 7d4bd4a2329..af7761e6256 100644 --- a/src/PhpDoc/CountableStubFilesExtension.php +++ b/src/PhpDoc/CountableStubFilesExtension.php @@ -5,13 +5,8 @@ class CountableStubFilesExtension implements StubFilesExtension { - /** - * @var bool - */ - private $bleedingEdge; - public function __construct(bool $bleedingEdge) + public function __construct(private bool $bleedingEdge) { - $this->bleedingEdge = $bleedingEdge; } public function getFiles(): array diff --git a/src/PhpDoc/DefaultStubFilesProvider.php b/src/PhpDoc/DefaultStubFilesProvider.php index 28a9eb76af9..da52332a1f3 100644 --- a/src/PhpDoc/DefaultStubFilesProvider.php +++ b/src/PhpDoc/DefaultStubFilesProvider.php @@ -12,32 +12,21 @@ class DefaultStubFilesProvider implements StubFilesProvider { - /** - * @var Container - */ - private $container; - /** - * @var string[] - */ - private $stubFiles; - /** - * @var string - */ - private $currentWorkingDirectory; /** @var string[]|null */ - private $cachedFiles = null; + private ?array $cachedFiles = null; /** @var string[]|null */ - private $cachedProjectFiles = null; + private ?array $cachedProjectFiles = null; /** * @param string[] $stubFiles */ - public function __construct(Container $container, array $stubFiles, string $currentWorkingDirectory) + public function __construct( + private Container $container, + private array $stubFiles, + private string $currentWorkingDirectory, + ) { - $this->container = $container; - $this->stubFiles = $stubFiles; - $this->currentWorkingDirectory = $currentWorkingDirectory; } public function getStubFiles(): array @@ -74,9 +63,7 @@ public function getProjectStubFiles(): array return $this->cachedProjectFiles = array_values(array_filter( $this->getStubFiles(), - static function (string $file) use($vendorDir) : bool { - return !str_contains(strtr($file, '\\', '/'), $vendorDir); - } + static fn (string $file): bool => !str_contains(strtr($file, '\\', '/'), $vendorDir) )); } diff --git a/src/PhpDoc/DirectTypeNodeResolverExtensionRegistryProvider.php b/src/PhpDoc/DirectTypeNodeResolverExtensionRegistryProvider.php index e7c0803e90b..cd912d76bb9 100644 --- a/src/PhpDoc/DirectTypeNodeResolverExtensionRegistryProvider.php +++ b/src/PhpDoc/DirectTypeNodeResolverExtensionRegistryProvider.php @@ -5,13 +5,8 @@ class DirectTypeNodeResolverExtensionRegistryProvider implements TypeNodeResolverExtensionRegistryProvider { - /** - * @var TypeNodeResolverExtensionRegistry - */ - private $registry; - public function __construct(TypeNodeResolverExtensionRegistry $registry) + public function __construct(private TypeNodeResolverExtensionRegistry $registry) { - $this->registry = $registry; } public function getRegistry(): TypeNodeResolverExtensionRegistry diff --git a/src/PhpDoc/JsonValidateStubFilesExtension.php b/src/PhpDoc/JsonValidateStubFilesExtension.php index cba13dc40e9..19c1f824d02 100644 --- a/src/PhpDoc/JsonValidateStubFilesExtension.php +++ b/src/PhpDoc/JsonValidateStubFilesExtension.php @@ -7,13 +7,8 @@ class JsonValidateStubFilesExtension implements StubFilesExtension { - /** - * @var PhpVersion - */ - private $phpVersion; - public function __construct(PhpVersion $phpVersion) + public function __construct(private PhpVersion $phpVersion) { - $this->phpVersion = $phpVersion; } public function getFiles(): array diff --git a/src/PhpDoc/LazyTypeNodeResolverExtensionRegistryProvider.php b/src/PhpDoc/LazyTypeNodeResolverExtensionRegistryProvider.php index 24032a971c0..4a041e369e3 100644 --- a/src/PhpDoc/LazyTypeNodeResolverExtensionRegistryProvider.php +++ b/src/PhpDoc/LazyTypeNodeResolverExtensionRegistryProvider.php @@ -7,24 +7,19 @@ class LazyTypeNodeResolverExtensionRegistryProvider implements TypeNodeResolverExtensionRegistryProvider { - /** - * @var Container - */ - private $container; - /** - * @var ?TypeNodeResolverExtensionRegistry - */ - private $registry = null; - - public function __construct(Container $container) + private ?TypeNodeResolverExtensionRegistry $registry = null; + + public function __construct(private Container $container) { - $this->container = $container; } public function getRegistry(): TypeNodeResolverExtensionRegistry { if ($this->registry === null) { - $this->registry = new TypeNodeResolverExtensionAwareRegistry($this->container->getByType(TypeNodeResolver::class), $this->container->getServicesByTag(TypeNodeResolverExtension::EXTENSION_TAG)); + $this->registry = new TypeNodeResolverExtensionAwareRegistry( + $this->container->getByType(TypeNodeResolver::class), + $this->container->getServicesByTag(TypeNodeResolverExtension::EXTENSION_TAG), + ); } return $this->registry; diff --git a/src/PhpDoc/PhpDocBlock.php b/src/PhpDoc/PhpDocBlock.php index 8323cad58d9..c4a6f6ce435 100644 --- a/src/PhpDoc/PhpDocBlock.php +++ b/src/PhpDoc/PhpDocBlock.php @@ -22,48 +22,22 @@ class PhpDocBlock { - /** - * @var string - */ - private $docComment; - /** - * @var ?string - */ - private $file; - /** - * @var ClassReflection - */ - private $classReflection; - /** - * @var ?string - */ - private $trait; - /** - * @var bool - */ - private $explicit; - /** - * @var array - */ - private $parameterNameMapping; - /** - * @var array - */ - private $parents; /** * @param array $parameterNameMapping * @param array $parents */ - private function __construct(string $docComment, ?string $file, ClassReflection $classReflection, ?string $trait, bool $explicit, array $parameterNameMapping, array $parents) + private function __construct( + private string $docComment, + private ?string $file, + private ClassReflection $classReflection, + private ?string $trait, + private bool $explicit, + private array $parameterNameMapping, + private array $parents, + ) { - $this->docComment = $docComment; - $this->file = $file; - $this->classReflection = $classReflection; - $this->trait = $trait; - $this->explicit = $explicit; - $this->parameterNameMapping = $parameterNameMapping; - $this->parents = $parents; } + public function getDocComment(): string { return $this->docComment; @@ -150,12 +124,23 @@ public static function resolvePhpDocBlockForProperty( string $propertyName, ?string $file, ?bool $explicit, - array $originalPositionalParameterNames, - // unused - array $newPositionalParameterNames - ) : self + array $originalPositionalParameterNames, // unused + array $newPositionalParameterNames, // unused + ): self { - return self::resolvePhpDocBlockTree($docComment, $classReflection, $trait, $propertyName, $file, 'hasNativeProperty', 'getNativeProperty', __FUNCTION__, $explicit, [], []); + return self::resolvePhpDocBlockTree( + $docComment, + $classReflection, + $trait, + $propertyName, + $file, + 'hasNativeProperty', + 'getNativeProperty', + __FUNCTION__, + $explicit, + [], + [], + ); } /** @@ -165,36 +150,96 @@ public static function resolvePhpDocBlockForProperty( public static function resolvePhpDocBlockForConstant( ?string $docComment, ClassReflection $classReflection, - ?string $trait, - // unused + ?string $trait, // unused string $constantName, ?string $file, ?bool $explicit, - array $originalPositionalParameterNames, - // unused - array $newPositionalParameterNames - ) : self + array $originalPositionalParameterNames, // unused + array $newPositionalParameterNames, // unused + ): self { - return self::resolvePhpDocBlockTree($docComment, $classReflection, null, $constantName, $file, 'hasConstant', 'getConstant', __FUNCTION__, $explicit, [], []); + return self::resolvePhpDocBlockTree( + $docComment, + $classReflection, + null, + $constantName, + $file, + 'hasConstant', + 'getConstant', + __FUNCTION__, + $explicit, + [], + [], + ); } /** * @param array $originalPositionalParameterNames * @param array $newPositionalParameterNames */ - public static function resolvePhpDocBlockForMethod(?string $docComment, ClassReflection $classReflection, ?string $trait, string $methodName, ?string $file, ?bool $explicit, array $originalPositionalParameterNames, array $newPositionalParameterNames) : self + public static function resolvePhpDocBlockForMethod( + ?string $docComment, + ClassReflection $classReflection, + ?string $trait, + string $methodName, + ?string $file, + ?bool $explicit, + array $originalPositionalParameterNames, + array $newPositionalParameterNames, + ): self { - return self::resolvePhpDocBlockTree($docComment, $classReflection, $trait, $methodName, $file, 'hasNativeMethod', 'getNativeMethod', __FUNCTION__, $explicit, $originalPositionalParameterNames, $newPositionalParameterNames); + return self::resolvePhpDocBlockTree( + $docComment, + $classReflection, + $trait, + $methodName, + $file, + 'hasNativeMethod', + 'getNativeMethod', + __FUNCTION__, + $explicit, + $originalPositionalParameterNames, + $newPositionalParameterNames, + ); } /** * @param array $originalPositionalParameterNames * @param array $newPositionalParameterNames */ - private static function resolvePhpDocBlockTree(?string $docComment, ClassReflection $classReflection, ?string $trait, string $name, ?string $file, string $hasMethodName, string $getMethodName, string $resolveMethodName, ?bool $explicit, array $originalPositionalParameterNames, array $newPositionalParameterNames) : self + private static function resolvePhpDocBlockTree( + ?string $docComment, + ClassReflection $classReflection, + ?string $trait, + string $name, + ?string $file, + string $hasMethodName, + string $getMethodName, + string $resolveMethodName, + ?bool $explicit, + array $originalPositionalParameterNames, + array $newPositionalParameterNames, + ): self { - $docBlocksFromParents = self::resolveParentPhpDocBlocks($classReflection, $name, $hasMethodName, $getMethodName, $resolveMethodName, $explicit ?? $docComment !== null, $newPositionalParameterNames); - return new self($docComment ?? ResolvedPhpDocBlock::EMPTY_DOC_STRING, $file, $classReflection, $trait, $explicit ?? true, self::remapParameterNames($originalPositionalParameterNames, $newPositionalParameterNames), $docBlocksFromParents); + $docBlocksFromParents = self::resolveParentPhpDocBlocks( + $classReflection, + $name, + $hasMethodName, + $getMethodName, + $resolveMethodName, + $explicit ?? $docComment !== null, + $newPositionalParameterNames, + ); + + return new self( + $docComment ?? ResolvedPhpDocBlock::EMPTY_DOC_STRING, + $file, + $classReflection, + $trait, + $explicit ?? true, + self::remapParameterNames($originalPositionalParameterNames, $newPositionalParameterNames), + $docBlocksFromParents, + ); } /** @@ -202,7 +247,10 @@ private static function resolvePhpDocBlockTree(?string $docComment, ClassReflect * @param array $newPositionalParameterNames * @return array */ - private static function remapParameterNames(array $originalPositionalParameterNames, array $newPositionalParameterNames) : array + private static function remapParameterNames( + array $originalPositionalParameterNames, + array $newPositionalParameterNames, + ): array { $parameterNameMapping = []; foreach ($originalPositionalParameterNames as $i => $parameterName) { @@ -211,6 +259,7 @@ private static function remapParameterNames(array $originalPositionalParameterNa } $parameterNameMapping[$newPositionalParameterNames[$i]] = $parameterName; } + return $parameterNameMapping; } @@ -218,12 +267,29 @@ private static function remapParameterNames(array $originalPositionalParameterNa * @param array $positionalParameterNames * @return array */ - private static function resolveParentPhpDocBlocks(ClassReflection $classReflection, string $name, string $hasMethodName, string $getMethodName, string $resolveMethodName, bool $explicit, array $positionalParameterNames) : array + private static function resolveParentPhpDocBlocks( + ClassReflection $classReflection, + string $name, + string $hasMethodName, + string $getMethodName, + string $resolveMethodName, + bool $explicit, + array $positionalParameterNames, + ): array { $result = []; $parentReflections = self::getParentReflections($classReflection); + foreach ($parentReflections as $parentReflection) { - $oneResult = self::resolvePhpDocBlockFromClass($parentReflection, $name, $hasMethodName, $getMethodName, $resolveMethodName, $explicit, $positionalParameterNames); + $oneResult = self::resolvePhpDocBlockFromClass( + $parentReflection, + $name, + $hasMethodName, + $getMethodName, + $resolveMethodName, + $explicit, + $positionalParameterNames, + ); if ($oneResult === null) { // Null if it is private or from a wrong trait. continue; @@ -231,6 +297,7 @@ private static function resolveParentPhpDocBlocks(ClassReflection $classReflecti $result[] = $oneResult; } + return $result; } @@ -256,7 +323,15 @@ private static function getParentReflections(ClassReflection $classReflection): /** * @param array $positionalParameterNames */ - private static function resolvePhpDocBlockFromClass(ClassReflection $classReflection, string $name, string $hasMethodName, string $getMethodName, string $resolveMethodName, bool $explicit, array $positionalParameterNames) : ?self + private static function resolvePhpDocBlockFromClass( + ClassReflection $classReflection, + string $name, + string $hasMethodName, + string $getMethodName, + string $resolveMethodName, + bool $explicit, + array $positionalParameterNames, + ): ?self { if ($classReflection->$hasMethodName($name)) { /** @var PropertyReflection|MethodReflection|ConstantReflection $parentReflection */ @@ -299,8 +374,18 @@ private static function resolvePhpDocBlockFromClass(ClassReflection $classReflec ? $traitReflection->getName() : null; - return self::$resolveMethodName($parentReflection->getDocComment() ?? ResolvedPhpDocBlock::EMPTY_DOC_STRING, $classReflection, $trait, $name, $classReflection->getFileName(), $explicit, $positionalParameterNames, $positionalMethodParameterNames); + return self::$resolveMethodName( + $parentReflection->getDocComment() ?? ResolvedPhpDocBlock::EMPTY_DOC_STRING, + $classReflection, + $trait, + $name, + $classReflection->getFileName(), + $explicit, + $positionalParameterNames, + $positionalMethodParameterNames, + ); } + return null; } diff --git a/src/PhpDoc/PhpDocInheritanceResolver.php b/src/PhpDoc/PhpDocInheritanceResolver.php index 1be53bdfc97..a0b34db3e0f 100644 --- a/src/PhpDoc/PhpDocInheritanceResolver.php +++ b/src/PhpDoc/PhpDocInheritanceResolver.php @@ -11,38 +11,83 @@ class PhpDocInheritanceResolver { + public function __construct( + private FileTypeMapper $fileTypeMapper, + private StubPhpDocProvider $stubPhpDocProvider, + ) + { + } + + public function resolvePhpDocForProperty( + ?string $docComment, + ClassReflection $classReflection, + ?string $classReflectionFileName, + ?string $declaringTraitName, + string $propertyName, + ): ResolvedPhpDocBlock + { + $phpDocBlock = PhpDocBlock::resolvePhpDocBlockForProperty( + $docComment, + $classReflection, + null, + $propertyName, + $classReflectionFileName, + null, + [], + [], + ); + + return $this->docBlockTreeToResolvedDocBlock($phpDocBlock, $declaringTraitName, null, $propertyName, null); + } + + public function resolvePhpDocForConstant( + ?string $docComment, + ClassReflection $classReflection, + ?string $classReflectionFileName, + string $constantName, + ): ResolvedPhpDocBlock + { + $phpDocBlock = PhpDocBlock::resolvePhpDocBlockForConstant( + $docComment, + $classReflection, + null, + $constantName, + $classReflectionFileName, + null, + [], + [], + ); + + return $this->docBlockTreeToResolvedDocBlock($phpDocBlock, null, null, null, $constantName); + } + /** - * @var FileTypeMapper - */ - private $fileTypeMapper; - /** - * @var StubPhpDocProvider - */ - private $stubPhpDocProvider; - public function __construct(FileTypeMapper $fileTypeMapper, StubPhpDocProvider $stubPhpDocProvider) - { - $this->fileTypeMapper = $fileTypeMapper; - $this->stubPhpDocProvider = $stubPhpDocProvider; - } - public function resolvePhpDocForProperty(?string $docComment, ClassReflection $classReflection, ?string $classReflectionFileName, ?string $declaringTraitName, string $propertyName) : ResolvedPhpDocBlock - { - $phpDocBlock = PhpDocBlock::resolvePhpDocBlockForProperty($docComment, $classReflection, null, $propertyName, $classReflectionFileName, null, [], []); - return $this->docBlockTreeToResolvedDocBlock($phpDocBlock, $declaringTraitName, null, $propertyName, null); - } - public function resolvePhpDocForConstant(?string $docComment, ClassReflection $classReflection, ?string $classReflectionFileName, string $constantName) : ResolvedPhpDocBlock - { - $phpDocBlock = PhpDocBlock::resolvePhpDocBlockForConstant($docComment, $classReflection, null, $constantName, $classReflectionFileName, null, [], []); - return $this->docBlockTreeToResolvedDocBlock($phpDocBlock, null, null, null, $constantName); - } - /** - * @param array $positionalParameterNames - */ - public function resolvePhpDocForMethod(?string $docComment, ?string $fileName, ClassReflection $classReflection, ?string $declaringTraitName, string $methodName, array $positionalParameterNames) : ResolvedPhpDocBlock - { - $phpDocBlock = PhpDocBlock::resolvePhpDocBlockForMethod($docComment, $classReflection, $declaringTraitName, $methodName, $fileName, null, $positionalParameterNames, $positionalParameterNames); - return $this->docBlockTreeToResolvedDocBlock($phpDocBlock, $phpDocBlock->getTrait(), $methodName, null, null); - } - private function docBlockTreeToResolvedDocBlock(PhpDocBlock $phpDocBlock, ?string $traitName, ?string $functionName, ?string $propertyName, ?string $constantName): ResolvedPhpDocBlock + * @param array $positionalParameterNames + */ + public function resolvePhpDocForMethod( + ?string $docComment, + ?string $fileName, + ClassReflection $classReflection, + ?string $declaringTraitName, + string $methodName, + array $positionalParameterNames, + ): ResolvedPhpDocBlock + { + $phpDocBlock = PhpDocBlock::resolvePhpDocBlockForMethod( + $docComment, + $classReflection, + $declaringTraitName, + $methodName, + $fileName, + null, + $positionalParameterNames, + $positionalParameterNames, + ); + + return $this->docBlockTreeToResolvedDocBlock($phpDocBlock, $phpDocBlock->getTrait(), $methodName, null, null); + } + + private function docBlockTreeToResolvedDocBlock(PhpDocBlock $phpDocBlock, ?string $traitName, ?string $functionName, ?string $propertyName, ?string $constantName): ResolvedPhpDocBlock { $parents = []; $parentPhpDocBlocks = []; @@ -55,7 +100,13 @@ private function docBlockTreeToResolvedDocBlock(PhpDocBlock $phpDocBlock, ?strin ) { continue; } - $parents[] = $this->docBlockTreeToResolvedDocBlock($parentPhpDocBlock, $parentPhpDocBlock->getTrait(), $functionName, $propertyName, $constantName); + $parents[] = $this->docBlockTreeToResolvedDocBlock( + $parentPhpDocBlock, + $parentPhpDocBlock->getTrait(), + $functionName, + $propertyName, + $constantName, + ); $parentPhpDocBlocks[] = $parentPhpDocBlock; } @@ -68,9 +119,7 @@ private function docBlockToResolvedDocBlock(PhpDocBlock $phpDocBlock, ?string $t $classReflection = $phpDocBlock->getClassReflection(); if ($functionName !== null && $classReflection->getNativeReflection()->hasMethod($functionName)) { $methodReflection = $classReflection->getNativeReflection()->getMethod($functionName); - $stub = $this->stubPhpDocProvider->findMethodPhpDoc($classReflection->getName(), $functionName, array_map(static function (ReflectionParameter $parameter) : string { - return $parameter->getName(); - }, $methodReflection->getParameters())); + $stub = $this->stubPhpDocProvider->findMethodPhpDoc($classReflection->getName(), $functionName, array_map(static fn (ReflectionParameter $parameter): string => $parameter->getName(), $methodReflection->getParameters())); if ($stub !== null) { return $stub; } @@ -100,7 +149,13 @@ private function docBlockToResolvedDocBlock(PhpDocBlock $phpDocBlock, ?string $t } } - return $this->fileTypeMapper->getResolvedPhpDoc($phpDocBlock->getFile(), $classReflection->getName(), $traitName, $functionName, $phpDocBlock->getDocComment()); + return $this->fileTypeMapper->getResolvedPhpDoc( + $phpDocBlock->getFile(), + $classReflection->getName(), + $traitName, + $functionName, + $phpDocBlock->getDocComment(), + ); } } diff --git a/src/PhpDoc/PhpDocNodeResolver.php b/src/PhpDoc/PhpDocNodeResolver.php index eac0651ed55..57eaa652792 100644 --- a/src/PhpDoc/PhpDocNodeResolver.php +++ b/src/PhpDoc/PhpDocNodeResolver.php @@ -47,24 +47,14 @@ class PhpDocNodeResolver { - /** - * @var TypeNodeResolver - */ - private $typeNodeResolver; - /** - * @var ConstExprNodeResolver - */ - private $constExprNodeResolver; - /** - * @var UnresolvableTypeHelper - */ - private $unresolvableTypeHelper; - public function __construct(TypeNodeResolver $typeNodeResolver, ConstExprNodeResolver $constExprNodeResolver, UnresolvableTypeHelper $unresolvableTypeHelper) + public function __construct( + private TypeNodeResolver $typeNodeResolver, + private ConstExprNodeResolver $constExprNodeResolver, + private UnresolvableTypeHelper $unresolvableTypeHelper, + ) { - $this->typeNodeResolver = $typeNodeResolver; - $this->constExprNodeResolver = $constExprNodeResolver; - $this->unresolvableTypeHelper = $unresolvableTypeHelper; } + /** * @return array<(string|int), VarTag> */ @@ -114,7 +104,11 @@ public function resolvePropertyTags(PhpDocNode $phpDocNode, NameScope $nameScope $propertyName = substr($tagValue->propertyName, 1); $propertyType = $this->typeNodeResolver->resolve($tagValue->type, $nameScope); - $resolved[$propertyName] = new PropertyTag($propertyType, $propertyType, $propertyType); + $resolved[$propertyName] = new PropertyTag( + $propertyType, + $propertyType, + $propertyType, + ); } } @@ -128,7 +122,11 @@ public function resolvePropertyTags(PhpDocNode $phpDocNode, NameScope $nameScope $writableType = $resolved[$propertyName]->getWritableType(); } - $resolved[$propertyName] = new PropertyTag($propertyType, $propertyType, $writableType); + $resolved[$propertyName] = new PropertyTag( + $propertyType, + $propertyType, + $writableType, + ); } } @@ -142,7 +140,11 @@ public function resolvePropertyTags(PhpDocNode $phpDocNode, NameScope $nameScope $readableType = $resolved[$propertyName]->getReadableType(); } - $resolved[$propertyName] = new PropertyTag($readableType ?? $propertyType, $readableType, $propertyType); + $resolved[$propertyName] = new PropertyTag( + $readableType ?? $propertyType, + $readableType, + $propertyType, + ); } } @@ -172,14 +174,24 @@ public function resolveMethodTags(PhpDocNode $phpDocNode, NameScope $nameScope): $defaultValue = $this->constExprNodeResolver->resolve($parameterNode->defaultValue); } - $parameters[$parameterName] = new MethodTagParameter($type, $parameterNode->isReference + $parameters[$parameterName] = new MethodTagParameter( + $type, + $parameterNode->isReference ? PassedByReference::createCreatesNewVariable() - : PassedByReference::createNo(), $parameterNode->isVariadic || $parameterNode->defaultValue !== null, $parameterNode->isVariadic, $defaultValue); + : PassedByReference::createNo(), + $parameterNode->isVariadic || $parameterNode->defaultValue !== null, + $parameterNode->isVariadic, + $defaultValue, + ); } - $resolved[$tagValue->methodName] = new MethodTag($tagValue->returnType !== null + $resolved[$tagValue->methodName] = new MethodTag( + $tagValue->returnType !== null ? $this->typeNodeResolver->resolve($tagValue->returnType, $nameScope) - : new MixedType(), $tagValue->isStatic, $parameters); + : new MixedType(), + $tagValue->isStatic, + $parameters, + ); } } @@ -195,7 +207,9 @@ public function resolveExtendsTags(PhpDocNode $phpDocNode, NameScope $nameScope) foreach (['@extends', '@template-extends', '@phpstan-extends'] as $tagName) { foreach ($phpDocNode->getExtendsTagValues($tagName) as $tagValue) { - $resolved[$nameScope->resolveStringName($tagValue->type->type->name)] = new ExtendsTag($this->typeNodeResolver->resolve($tagValue->type, $nameScope)); + $resolved[$nameScope->resolveStringName($tagValue->type->type->name)] = new ExtendsTag( + $this->typeNodeResolver->resolve($tagValue->type, $nameScope), + ); } } @@ -211,7 +225,9 @@ public function resolveImplementsTags(PhpDocNode $phpDocNode, NameScope $nameSco foreach (['@implements', '@template-implements', '@phpstan-implements'] as $tagName) { foreach ($phpDocNode->getImplementsTagValues($tagName) as $tagValue) { - $resolved[$nameScope->resolveStringName($tagValue->type->type->name)] = new ImplementsTag($this->typeNodeResolver->resolve($tagValue->type, $nameScope)); + $resolved[$nameScope->resolveStringName($tagValue->type->type->name)] = new ImplementsTag( + $this->typeNodeResolver->resolve($tagValue->type, $nameScope), + ); } } @@ -227,7 +243,9 @@ public function resolveUsesTags(PhpDocNode $phpDocNode, NameScope $nameScope): a foreach (['@use', '@template-use', '@phpstan-use'] as $tagName) { foreach ($phpDocNode->getUsesTagValues($tagName) as $tagValue) { - $resolved[$nameScope->resolveStringName($tagValue->type->type->name)] = new UsesTag($this->typeNodeResolver->resolve($tagValue->type, $nameScope)); + $resolved[$nameScope->resolveStringName($tagValue->type->type->name)] = new UsesTag( + $this->typeNodeResolver->resolve($tagValue->type, $nameScope), + ); } } @@ -280,7 +298,11 @@ public function resolveTemplateTags(PhpDocNode $phpDocNode, NameScope $nameScope } } - $resolved[$valueNode->name] = new TemplateTag($valueNode->name, $valueNode->bound !== null ? $this->typeNodeResolver->resolve($valueNode->bound, $nameScope->unsetTemplateType($valueNode->name)) : new MixedType(true), $variance); + $resolved[$valueNode->name] = new TemplateTag( + $valueNode->name, + $valueNode->bound !== null ? $this->typeNodeResolver->resolve($valueNode->bound, $nameScope->unsetTemplateType($valueNode->name)) : new MixedType(true), + $variance, + ); $resolvedPrefix[$valueNode->name] = $prefix; } @@ -302,7 +324,10 @@ public function resolveParamTags(PhpDocNode $phpDocNode, NameScope $nameScope): continue; } - $resolved[$parameterName] = new ParamTag($parameterType, $tagValue->isVariadic); + $resolved[$parameterName] = new ParamTag( + $parameterType, + $tagValue->isVariadic, + ); } } @@ -328,7 +353,9 @@ public function resolveParamOutTags(PhpDocNode $phpDocNode, NameScope $nameScope continue; } - $resolved[$parameterName] = new ParamOutTag($parameterType); + $resolved[$parameterName] = new ParamOutTag( + $parameterType, + ); } } @@ -379,9 +406,9 @@ public function resolveThrowsTags(PhpDocNode $phpDocNode, NameScope $nameScope): */ public function resolveMixinTags(PhpDocNode $phpDocNode, NameScope $nameScope): array { - return array_map(function (MixinTagValueNode $mixinTagValueNode) use($nameScope) : MixinTag { - return new MixinTag($this->typeNodeResolver->resolve($mixinTagValueNode->type, $nameScope)); - }, $phpDocNode->getMixinTagValues()); + return array_map(fn (MixinTagValueNode $mixinTagValueNode): MixinTag => new MixinTag( + $this->typeNodeResolver->resolve($mixinTagValueNode->type, $nameScope), + ), $phpDocNode->getMixinTagValues()); } /** @@ -393,7 +420,9 @@ public function resolveRequireExtendsTags(PhpDocNode $phpDocNode, NameScope $nam foreach (['@psalm-require-extends', '@phpstan-require-extends'] as $tagName) { foreach ($phpDocNode->getRequireExtendsTagValues($tagName) as $tagValue) { - $resolved[] = new RequireExtendsTag($this->typeNodeResolver->resolve($tagValue->type, $nameScope)); + $resolved[] = new RequireExtendsTag( + $this->typeNodeResolver->resolve($tagValue->type, $nameScope), + ); } } @@ -409,7 +438,9 @@ public function resolveRequireImplementsTags(PhpDocNode $phpDocNode, NameScope $ foreach (['@psalm-require-implements', '@phpstan-require-implements'] as $tagName) { foreach ($phpDocNode->getRequireImplementsTagValues($tagName) as $tagValue) { - $resolved[] = new RequireImplementsTag($this->typeNodeResolver->resolve($tagValue->type, $nameScope)); + $resolved[] = new RequireImplementsTag( + $this->typeNodeResolver->resolve($tagValue->type, $nameScope), + ); } } @@ -459,7 +490,11 @@ public function resolveTypeAliasImportTags(PhpDocNode $phpDocNode, NameScope $na public function resolveAssertTags(PhpDocNode $phpDocNode, NameScope $nameScope): array { foreach (['@phpstan', '@psalm'] as $prefix) { - $resolved = array_merge($this->resolveAssertTagsFor($phpDocNode, $nameScope, $prefix . '-assert', AssertTag::NULL), $this->resolveAssertTagsFor($phpDocNode, $nameScope, $prefix . '-assert-if-true', AssertTag::IF_TRUE), $this->resolveAssertTagsFor($phpDocNode, $nameScope, $prefix . '-assert-if-false', AssertTag::IF_FALSE)); + $resolved = array_merge( + $this->resolveAssertTagsFor($phpDocNode, $nameScope, $prefix . '-assert', AssertTag::NULL), + $this->resolveAssertTagsFor($phpDocNode, $nameScope, $prefix . '-assert-if-true', AssertTag::IF_TRUE), + $this->resolveAssertTagsFor($phpDocNode, $nameScope, $prefix . '-assert-if-false', AssertTag::IF_FALSE), + ); if (count($resolved) > 0) { return $resolved; diff --git a/src/PhpDoc/PhpDocStringResolver.php b/src/PhpDoc/PhpDocStringResolver.php index 789141e272d..d9d6203e5b1 100644 --- a/src/PhpDoc/PhpDocStringResolver.php +++ b/src/PhpDoc/PhpDocStringResolver.php @@ -10,18 +10,8 @@ class PhpDocStringResolver { - /** - * @var Lexer - */ - private $phpDocLexer; - /** - * @var PhpDocParser - */ - private $phpDocParser; - public function __construct(Lexer $phpDocLexer, PhpDocParser $phpDocParser) + public function __construct(private Lexer $phpDocLexer, private PhpDocParser $phpDocParser) { - $this->phpDocLexer = $phpDocLexer; - $this->phpDocParser = $phpDocParser; } public function resolve(string $phpDocString): PhpDocNode diff --git a/src/PhpDoc/ReflectionEnumStubFilesExtension.php b/src/PhpDoc/ReflectionEnumStubFilesExtension.php index d5b000797b1..0fe8fbb5b29 100644 --- a/src/PhpDoc/ReflectionEnumStubFilesExtension.php +++ b/src/PhpDoc/ReflectionEnumStubFilesExtension.php @@ -7,13 +7,8 @@ class ReflectionEnumStubFilesExtension implements StubFilesExtension { - /** - * @var PhpVersion - */ - private $phpVersion; - public function __construct(PhpVersion $phpVersion) + public function __construct(private PhpVersion $phpVersion) { - $this->phpVersion = $phpVersion; } public function getFiles(): array diff --git a/src/PhpDoc/ResolvedPhpDocBlock.php b/src/PhpDoc/ResolvedPhpDocBlock.php index 9d10273cc7f..1dc8b5d13e2 100644 --- a/src/PhpDoc/ResolvedPhpDocBlock.php +++ b/src/PhpDoc/ResolvedPhpDocBlock.php @@ -45,156 +45,96 @@ class ResolvedPhpDocBlock public const EMPTY_DOC_STRING = '/** */'; - /** - * @var PhpDocNode - */ - private $phpDocNode; + private PhpDocNode $phpDocNode; /** @var PhpDocNode[] */ - private $phpDocNodes; + private array $phpDocNodes; - /** - * @var string - */ - private $phpDocString; + private string $phpDocString; - /** - * @var ?string - */ - private $filename; + private ?string $filename; - /** - * @var ?NameScope - */ - private $nameScope = null; + private ?NameScope $nameScope = null; - /** - * @var TemplateTypeMap - */ - private $templateTypeMap; + private TemplateTypeMap $templateTypeMap; /** @var array */ - private $templateTags; + private array $templateTags; - /** - * @var PhpDocNodeResolver - */ - private $phpDocNodeResolver; + private PhpDocNodeResolver $phpDocNodeResolver; - /** - * @var ReflectionProvider - */ - private $reflectionProvider; + private ReflectionProvider $reflectionProvider; /** @var array<(string|int), VarTag>|false */ - private $varTags = false; + private array|false $varTags = false; /** @var array|false */ - private $methodTags = false; + private array|false $methodTags = false; /** @var array|false */ - private $propertyTags = false; + private array|false $propertyTags = false; /** @var array|false */ - private $extendsTags = false; + private array|false $extendsTags = false; /** @var array|false */ - private $implementsTags = false; + private array|false $implementsTags = false; /** @var array|false */ - private $usesTags = false; + private array|false $usesTags = false; /** @var array|false */ - private $paramTags = false; + private array|false $paramTags = false; /** @var array|false */ - private $paramOutTags = false; + private array|false $paramOutTags = false; - /** - * @var ReturnTag|false|null - */ - private $returnTag = false; + private ReturnTag|false|null $returnTag = false; - /** - * @var ThrowsTag|false|null - */ - private $throwsTag = false; + private ThrowsTag|false|null $throwsTag = false; /** @var array|false */ - private $mixinTags = false; + private array|false $mixinTags = false; /** @var array|false */ - private $requireExtendsTags = false; + private array|false $requireExtendsTags = false; /** @var array|false */ - private $requireImplementsTags = false; + private array|false $requireImplementsTags = false; /** @var array|false */ - private $typeAliasTags = false; + private array|false $typeAliasTags = false; /** @var array|false */ - private $typeAliasImportTags = false; + private array|false $typeAliasImportTags = false; /** @var array|false */ - private $assertTags = false; + private array|false $assertTags = false; - /** - * @var SelfOutTypeTag|false|null - */ - private $selfOutTypeTag = false; + private SelfOutTypeTag|false|null $selfOutTypeTag = false; - /** - * @var DeprecatedTag|false|null - */ - private $deprecatedTag = false; + private DeprecatedTag|false|null $deprecatedTag = false; - /** - * @var ?bool - */ - private $isDeprecated = null; + private ?bool $isDeprecated = null; - /** - * @var ?bool - */ - private $isNotDeprecated = null; + private ?bool $isNotDeprecated = null; - /** - * @var ?bool - */ - private $isInternal = null; + private ?bool $isInternal = null; - /** - * @var ?bool - */ - private $isFinal = null; + private ?bool $isFinal = null; /** @var bool|'notLoaded'|null */ - private $isPure = 'notLoaded'; + private bool|string|null $isPure = 'notLoaded'; - /** - * @var ?bool - */ - private $isReadOnly = null; + private ?bool $isReadOnly = null; - /** - * @var ?bool - */ - private $isImmutable = null; + private ?bool $isImmutable = null; - /** - * @var ?bool - */ - private $isAllowedPrivateMutation = null; + private ?bool $isAllowedPrivateMutation = null; - /** - * @var ?bool - */ - private $hasConsistentConstructor = null; + private ?bool $hasConsistentConstructor = null; - /** - * @var ?bool - */ - private $acceptsNamedArguments = null; + private ?bool $acceptsNamedArguments = null; private function __construct() { @@ -203,7 +143,16 @@ private function __construct() /** * @param TemplateTag[] $templateTags */ - public static function create(PhpDocNode $phpDocNode, string $phpDocString, ?string $filename, NameScope $nameScope, TemplateTypeMap $templateTypeMap, array $templateTags, PhpDocNodeResolver $phpDocNodeResolver, ReflectionProvider $reflectionProvider) : self + public static function create( + PhpDocNode $phpDocNode, + string $phpDocString, + ?string $filename, + NameScope $nameScope, + TemplateTypeMap $templateTypeMap, + array $templateTags, + PhpDocNodeResolver $phpDocNodeResolver, + ReflectionProvider $reflectionProvider, + ): self { // new property also needs to be added to createEmpty() and merge() $self = new self(); @@ -216,6 +165,7 @@ public static function create(PhpDocNode $phpDocNode, string $phpDocString, ?str $self->templateTags = $templateTags; $self->phpDocNodeResolver = $phpDocNodeResolver; $self->reflectionProvider = $reflectionProvider; + return $self; } @@ -453,7 +403,10 @@ public function getNullableNameScope(): ?NameScope public function getVarTags(): array { if ($this->varTags === false) { - $this->varTags = $this->phpDocNodeResolver->resolveVarTags($this->phpDocNode, $this->getNameScope()); + $this->varTags = $this->phpDocNodeResolver->resolveVarTags( + $this->phpDocNode, + $this->getNameScope(), + ); } return $this->varTags; } @@ -464,7 +417,10 @@ public function getVarTags(): array public function getMethodTags(): array { if ($this->methodTags === false) { - $this->methodTags = $this->phpDocNodeResolver->resolveMethodTags($this->phpDocNode, $this->getNameScope()); + $this->methodTags = $this->phpDocNodeResolver->resolveMethodTags( + $this->phpDocNode, + $this->getNameScope(), + ); } return $this->methodTags; } @@ -475,7 +431,10 @@ public function getMethodTags(): array public function getPropertyTags(): array { if ($this->propertyTags === false) { - $this->propertyTags = $this->phpDocNodeResolver->resolvePropertyTags($this->phpDocNode, $this->getNameScope()); + $this->propertyTags = $this->phpDocNodeResolver->resolvePropertyTags( + $this->phpDocNode, + $this->getNameScope(), + ); } return $this->propertyTags; } @@ -494,7 +453,10 @@ public function getTemplateTags(): array public function getExtendsTags(): array { if ($this->extendsTags === false) { - $this->extendsTags = $this->phpDocNodeResolver->resolveExtendsTags($this->phpDocNode, $this->getNameScope()); + $this->extendsTags = $this->phpDocNodeResolver->resolveExtendsTags( + $this->phpDocNode, + $this->getNameScope(), + ); } return $this->extendsTags; } @@ -505,7 +467,10 @@ public function getExtendsTags(): array public function getImplementsTags(): array { if ($this->implementsTags === false) { - $this->implementsTags = $this->phpDocNodeResolver->resolveImplementsTags($this->phpDocNode, $this->getNameScope()); + $this->implementsTags = $this->phpDocNodeResolver->resolveImplementsTags( + $this->phpDocNode, + $this->getNameScope(), + ); } return $this->implementsTags; } @@ -516,7 +481,10 @@ public function getImplementsTags(): array public function getUsesTags(): array { if ($this->usesTags === false) { - $this->usesTags = $this->phpDocNodeResolver->resolveUsesTags($this->phpDocNode, $this->getNameScope()); + $this->usesTags = $this->phpDocNodeResolver->resolveUsesTags( + $this->phpDocNode, + $this->getNameScope(), + ); } return $this->usesTags; } @@ -527,7 +495,10 @@ public function getUsesTags(): array public function getParamTags(): array { if ($this->paramTags === false) { - $this->paramTags = $this->phpDocNodeResolver->resolveParamTags($this->phpDocNode, $this->getNameScope()); + $this->paramTags = $this->phpDocNodeResolver->resolveParamTags( + $this->phpDocNode, + $this->getNameScope(), + ); } return $this->paramTags; } @@ -538,7 +509,10 @@ public function getParamTags(): array public function getParamOutTags(): array { if ($this->paramOutTags === false) { - $this->paramOutTags = $this->phpDocNodeResolver->resolveParamOutTags($this->phpDocNode, $this->getNameScope()); + $this->paramOutTags = $this->phpDocNodeResolver->resolveParamOutTags( + $this->phpDocNode, + $this->getNameScope(), + ); } return $this->paramOutTags; } @@ -546,7 +520,10 @@ public function getParamOutTags(): array public function getReturnTag(): ?ReturnTag { if (is_bool($this->returnTag)) { - $this->returnTag = $this->phpDocNodeResolver->resolveReturnTag($this->phpDocNode, $this->getNameScope()); + $this->returnTag = $this->phpDocNodeResolver->resolveReturnTag( + $this->phpDocNode, + $this->getNameScope(), + ); } return $this->returnTag; } @@ -554,7 +531,10 @@ public function getReturnTag(): ?ReturnTag public function getThrowsTag(): ?ThrowsTag { if (is_bool($this->throwsTag)) { - $this->throwsTag = $this->phpDocNodeResolver->resolveThrowsTags($this->phpDocNode, $this->getNameScope()); + $this->throwsTag = $this->phpDocNodeResolver->resolveThrowsTags( + $this->phpDocNode, + $this->getNameScope(), + ); } return $this->throwsTag; } @@ -565,7 +545,10 @@ public function getThrowsTag(): ?ThrowsTag public function getMixinTags(): array { if ($this->mixinTags === false) { - $this->mixinTags = $this->phpDocNodeResolver->resolveMixinTags($this->phpDocNode, $this->getNameScope()); + $this->mixinTags = $this->phpDocNodeResolver->resolveMixinTags( + $this->phpDocNode, + $this->getNameScope(), + ); } return $this->mixinTags; @@ -577,7 +560,10 @@ public function getMixinTags(): array public function getRequireExtendsTags(): array { if ($this->requireExtendsTags === false) { - $this->requireExtendsTags = $this->phpDocNodeResolver->resolveRequireExtendsTags($this->phpDocNode, $this->getNameScope()); + $this->requireExtendsTags = $this->phpDocNodeResolver->resolveRequireExtendsTags( + $this->phpDocNode, + $this->getNameScope(), + ); } return $this->requireExtendsTags; @@ -589,7 +575,10 @@ public function getRequireExtendsTags(): array public function getRequireImplementsTags(): array { if ($this->requireImplementsTags === false) { - $this->requireImplementsTags = $this->phpDocNodeResolver->resolveRequireImplementsTags($this->phpDocNode, $this->getNameScope()); + $this->requireImplementsTags = $this->phpDocNodeResolver->resolveRequireImplementsTags( + $this->phpDocNode, + $this->getNameScope(), + ); } return $this->requireImplementsTags; @@ -601,7 +590,10 @@ public function getRequireImplementsTags(): array public function getTypeAliasTags(): array { if ($this->typeAliasTags === false) { - $this->typeAliasTags = $this->phpDocNodeResolver->resolveTypeAliasTags($this->phpDocNode, $this->getNameScope()); + $this->typeAliasTags = $this->phpDocNodeResolver->resolveTypeAliasTags( + $this->phpDocNode, + $this->getNameScope(), + ); } return $this->typeAliasTags; @@ -613,7 +605,10 @@ public function getTypeAliasTags(): array public function getTypeAliasImportTags(): array { if ($this->typeAliasImportTags === false) { - $this->typeAliasImportTags = $this->phpDocNodeResolver->resolveTypeAliasImportTags($this->phpDocNode, $this->getNameScope()); + $this->typeAliasImportTags = $this->phpDocNodeResolver->resolveTypeAliasImportTags( + $this->phpDocNode, + $this->getNameScope(), + ); } return $this->typeAliasImportTags; @@ -625,7 +620,10 @@ public function getTypeAliasImportTags(): array public function getAssertTags(): array { if ($this->assertTags === false) { - $this->assertTags = $this->phpDocNodeResolver->resolveAssertTags($this->phpDocNode, $this->getNameScope()); + $this->assertTags = $this->phpDocNodeResolver->resolveAssertTags( + $this->phpDocNode, + $this->getNameScope(), + ); } return $this->assertTags; @@ -634,7 +632,10 @@ public function getAssertTags(): array public function getSelfOutTag(): ?SelfOutTypeTag { if ($this->selfOutTypeTag === false) { - $this->selfOutTypeTag = $this->phpDocNodeResolver->resolveSelfOutTypeTag($this->phpDocNode, $this->getNameScope()); + $this->selfOutTypeTag = $this->phpDocNodeResolver->resolveSelfOutTypeTag( + $this->phpDocNode, + $this->getNameScope(), + ); } return $this->selfOutTypeTag; @@ -643,7 +644,10 @@ public function getSelfOutTag(): ?SelfOutTypeTag public function getDeprecatedTag(): ?DeprecatedTag { if (is_bool($this->deprecatedTag)) { - $this->deprecatedTag = $this->phpDocNodeResolver->resolveDeprecatedTag($this->phpDocNode, $this->getNameScope()); + $this->deprecatedTag = $this->phpDocNodeResolver->resolveDeprecatedTag( + $this->phpDocNode, + $this->getNameScope(), + ); } return $this->deprecatedTag; } @@ -651,7 +655,9 @@ public function getDeprecatedTag(): ?DeprecatedTag public function isDeprecated(): bool { if ($this->isDeprecated === null) { - $this->isDeprecated = $this->phpDocNodeResolver->resolveIsDeprecated($this->phpDocNode); + $this->isDeprecated = $this->phpDocNodeResolver->resolveIsDeprecated( + $this->phpDocNode, + ); } return $this->isDeprecated; } @@ -662,7 +668,9 @@ public function isDeprecated(): bool public function isNotDeprecated(): bool { if ($this->isNotDeprecated === null) { - $this->isNotDeprecated = $this->phpDocNodeResolver->resolveIsNotDeprecated($this->phpDocNode); + $this->isNotDeprecated = $this->phpDocNodeResolver->resolveIsNotDeprecated( + $this->phpDocNode, + ); } return $this->isNotDeprecated; } @@ -670,7 +678,9 @@ public function isNotDeprecated(): bool public function isInternal(): bool { if ($this->isInternal === null) { - $this->isInternal = $this->phpDocNodeResolver->resolveIsInternal($this->phpDocNode); + $this->isInternal = $this->phpDocNodeResolver->resolveIsInternal( + $this->phpDocNode, + ); } return $this->isInternal; } @@ -678,7 +688,9 @@ public function isInternal(): bool public function isFinal(): bool { if ($this->isFinal === null) { - $this->isFinal = $this->phpDocNodeResolver->resolveIsFinal($this->phpDocNode); + $this->isFinal = $this->phpDocNodeResolver->resolveIsFinal( + $this->phpDocNode, + ); } return $this->isFinal; } @@ -686,7 +698,9 @@ public function isFinal(): bool public function hasConsistentConstructor(): bool { if ($this->hasConsistentConstructor === null) { - $this->hasConsistentConstructor = $this->phpDocNodeResolver->resolveHasConsistentConstructor($this->phpDocNode); + $this->hasConsistentConstructor = $this->phpDocNodeResolver->resolveHasConsistentConstructor( + $this->phpDocNode, + ); } return $this->hasConsistentConstructor; } @@ -694,7 +708,9 @@ public function hasConsistentConstructor(): bool public function acceptsNamedArguments(): bool { if ($this->acceptsNamedArguments === null) { - $this->acceptsNamedArguments = $this->phpDocNodeResolver->resolveAcceptsNamedArguments($this->phpDocNode); + $this->acceptsNamedArguments = $this->phpDocNodeResolver->resolveAcceptsNamedArguments( + $this->phpDocNode, + ); } return $this->acceptsNamedArguments; } @@ -707,13 +723,17 @@ public function getTemplateTypeMap(): TemplateTypeMap public function isPure(): ?bool { if ($this->isPure === 'notLoaded') { - $pure = $this->phpDocNodeResolver->resolveIsPure($this->phpDocNode); + $pure = $this->phpDocNodeResolver->resolveIsPure( + $this->phpDocNode, + ); if ($pure) { $this->isPure = true; return $this->isPure; } - $impure = $this->phpDocNodeResolver->resolveIsImpure($this->phpDocNode); + $impure = $this->phpDocNodeResolver->resolveIsImpure( + $this->phpDocNode, + ); if ($impure) { $this->isPure = false; return $this->isPure; @@ -728,7 +748,9 @@ public function isPure(): ?bool public function isReadOnly(): bool { if ($this->isReadOnly === null) { - $this->isReadOnly = $this->phpDocNodeResolver->resolveIsReadOnly($this->phpDocNode); + $this->isReadOnly = $this->phpDocNodeResolver->resolveIsReadOnly( + $this->phpDocNode, + ); } return $this->isReadOnly; } @@ -736,7 +758,9 @@ public function isReadOnly(): bool public function isImmutable(): bool { if ($this->isImmutable === null) { - $this->isImmutable = $this->phpDocNodeResolver->resolveIsImmutable($this->phpDocNode); + $this->isImmutable = $this->phpDocNodeResolver->resolveIsImmutable( + $this->phpDocNode, + ); } return $this->isImmutable; } @@ -744,7 +768,9 @@ public function isImmutable(): bool public function isAllowedPrivateMutation(): bool { if ($this->isAllowedPrivateMutation === null) { - $this->isAllowedPrivateMutation = $this->phpDocNodeResolver->resolveAllowPrivateMutation($this->phpDocNode); + $this->isAllowedPrivateMutation = $this->phpDocNodeResolver->resolveAllowPrivateMutation( + $this->phpDocNode, + ); } return $this->isAllowedPrivateMutation; @@ -856,13 +882,16 @@ private static function mergeOneParentReturnTag(?ReturnTag $returnTag, ?ClassRef $parentType = $parentReturnTag->getType(); if ($classReflection !== null) { - $parentType = TypeTraverser::map($parentType, static function (Type $type, callable $traverse) use ($classReflection): Type { + $parentType = TypeTraverser::map( + $parentType, + static function (Type $type, callable $traverse) use ($classReflection): Type { if ($type instanceof StaticType) { return $type->changeBaseClass($classReflection); } return $traverse($type); - }); + }, + ); $parentReturnTag = $parentReturnTag->withType($parentType); } @@ -873,7 +902,13 @@ private static function mergeOneParentReturnTag(?ReturnTag $returnTag, ?ClassRef return null; } - return self::resolveTemplateTypeInTag($parentReturnTag->withType($phpDocBlock->transformConditionalReturnTypeWithParameterNameMapping($parentReturnTag->getType()))->toImplicit(), $phpDocBlock, TemplateTypeVariance::createCovariant()); + return self::resolveTemplateTypeInTag( + $parentReturnTag->withType( + $phpDocBlock->transformConditionalReturnTypeWithParameterNameMapping($parentReturnTag->getType()), + )->toImplicit(), + $phpDocBlock, + TemplateTypeVariance::createCovariant(), + ); } /** @@ -895,9 +930,12 @@ private static function mergeAssertTags(array $assertTags, array $parents, array $phpDocBlock = $parentPhpDocBlocks[$i]; - return array_map(static function (AssertTag $assertTag) use($phpDocBlock) { - return $assertTag->withParameter($phpDocBlock->transformAssertTagParameterWithParameterNameMapping($assertTag->getParameter())); - }, $result); + return array_map( + static fn (AssertTag $assertTag) => $assertTag->withParameter( + $phpDocBlock->transformAssertTagParameterWithParameterNameMapping($assertTag->getParameter()), + ), + $result, + ); } return $assertTags; @@ -1006,9 +1044,18 @@ private static function mergeOneParentParamOutTags(array $paramOutTags, self $pa * @param T $tag * @return T */ - private static function resolveTemplateTypeInTag(TypedTag $tag, PhpDocBlock $phpDocBlock, TemplateTypeVariance $positionVariance) : TypedTag + private static function resolveTemplateTypeInTag( + TypedTag $tag, + PhpDocBlock $phpDocBlock, + TemplateTypeVariance $positionVariance, + ): TypedTag { - $type = TemplateTypeHelper::resolveTemplateTypes($tag->getType(), $phpDocBlock->getClassReflection()->getActiveTemplateTypeMap(), $phpDocBlock->getClassReflection()->getCallSiteVarianceMap(), $positionVariance); + $type = TemplateTypeHelper::resolveTemplateTypes( + $tag->getType(), + $phpDocBlock->getClassReflection()->getActiveTemplateTypeMap(), + $phpDocBlock->getClassReflection()->getCallSiteVarianceMap(), + $positionVariance, + ); return $tag->withType($type); } diff --git a/src/PhpDoc/StubPhpDocProvider.php b/src/PhpDoc/StubPhpDocProvider.php index 0b37340984a..b42350184a2 100644 --- a/src/PhpDoc/StubPhpDocProvider.php +++ b/src/PhpDoc/StubPhpDocProvider.php @@ -17,69 +17,52 @@ class StubPhpDocProvider { - /** - * @var Parser - */ - private $parser; - /** - * @var FileTypeMapper - */ - private $fileTypeMapper; - /** - * @var StubFilesProvider - */ - private $stubFilesProvider; /** @var array */ - private $classMap = []; + private array $classMap = []; /** @var array> */ - private $propertyMap = []; + private array $propertyMap = []; /** @var array> */ - private $constantMap = []; + private array $constantMap = []; /** @var array> */ - private $methodMap = []; + private array $methodMap = []; /** @var array */ - private $functionMap = []; + private array $functionMap = []; - /** - * @var bool - */ - private $initialized = false; + private bool $initialized = false; - /** - * @var bool - */ - private $initializing = false; + private bool $initializing = false; /** @var array */ - private $knownClassesDocComments = []; + private array $knownClassesDocComments = []; /** @var array */ - private $knownFunctionsDocComments = []; + private array $knownFunctionsDocComments = []; /** @var array> */ - private $knownPropertiesDocComments = []; + private array $knownPropertiesDocComments = []; /** @var array> */ - private $knownConstantsDocComments = []; + private array $knownConstantsDocComments = []; /** @var array> */ - private $knownMethodsDocComments = []; + private array $knownMethodsDocComments = []; /** @var array>> */ - private $knownMethodsParameterNames = []; + private array $knownMethodsParameterNames = []; /** @var array> */ - private $knownFunctionParameterNames = []; + private array $knownFunctionParameterNames = []; - public function __construct(Parser $parser, FileTypeMapper $fileTypeMapper, StubFilesProvider $stubFilesProvider) + public function __construct( + private Parser $parser, + private FileTypeMapper $fileTypeMapper, + private StubFilesProvider $stubFilesProvider, + ) { - $this->parser = $parser; - $this->fileTypeMapper = $fileTypeMapper; - $this->stubFilesProvider = $stubFilesProvider; } public function findClassPhpDoc(string $className): ?ResolvedPhpDocBlock @@ -94,7 +77,13 @@ public function findClassPhpDoc(string $className): ?ResolvedPhpDocBlock if (array_key_exists($className, $this->knownClassesDocComments)) { [$file, $docComment] = $this->knownClassesDocComments[$className]; - $this->classMap[$className] = $this->fileTypeMapper->getResolvedPhpDoc($file, $className, null, null, $docComment); + $this->classMap[$className] = $this->fileTypeMapper->getResolvedPhpDoc( + $file, + $className, + null, + null, + $docComment, + ); return $this->classMap[$className]; } @@ -114,7 +103,13 @@ public function findPropertyPhpDoc(string $className, string $propertyName): ?Re if (array_key_exists($propertyName, $this->knownPropertiesDocComments[$className])) { [$file, $docComment] = $this->knownPropertiesDocComments[$className][$propertyName]; - $this->propertyMap[$className][$propertyName] = $this->fileTypeMapper->getResolvedPhpDoc($file, $className, null, null, $docComment); + $this->propertyMap[$className][$propertyName] = $this->fileTypeMapper->getResolvedPhpDoc( + $file, + $className, + null, + null, + $docComment, + ); return $this->propertyMap[$className][$propertyName]; } @@ -134,7 +129,13 @@ public function findClassConstantPhpDoc(string $className, string $constantName) if (array_key_exists($constantName, $this->knownConstantsDocComments[$className])) { [$file, $docComment] = $this->knownConstantsDocComments[$className][$constantName]; - $this->constantMap[$className][$constantName] = $this->fileTypeMapper->getResolvedPhpDoc($file, $className, null, null, $docComment); + $this->constantMap[$className][$constantName] = $this->fileTypeMapper->getResolvedPhpDoc( + $file, + $className, + null, + null, + $docComment, + ); return $this->constantMap[$className][$constantName]; } @@ -157,7 +158,13 @@ public function findMethodPhpDoc(string $className, string $methodName, array $p if (array_key_exists($methodName, $this->knownMethodsDocComments[$className])) { [$file, $docComment] = $this->knownMethodsDocComments[$className][$methodName]; - $resolvedPhpDoc = $this->fileTypeMapper->getResolvedPhpDoc($file, $className, null, $methodName, $docComment); + $resolvedPhpDoc = $this->fileTypeMapper->getResolvedPhpDoc( + $file, + $className, + null, + $methodName, + $docComment, + ); if (!isset($this->knownMethodsParameterNames[$className][$methodName])) { throw new ShouldNotHappenException(); @@ -194,7 +201,13 @@ public function findFunctionPhpDoc(string $functionName, array $positionalParame if (array_key_exists($functionName, $this->knownFunctionsDocComments)) { [$file, $docComment] = $this->knownFunctionsDocComments[$functionName]; - $resolvedPhpDoc = $this->fileTypeMapper->getResolvedPhpDoc($file, null, null, $functionName, $docComment); + $resolvedPhpDoc = $this->fileTypeMapper->getResolvedPhpDoc( + $file, + null, + null, + $functionName, + $docComment, + ); if (!isset($this->knownFunctionParameterNames[$functionName])) { throw new ShouldNotHappenException(); diff --git a/src/PhpDoc/StubSourceLocatorFactory.php b/src/PhpDoc/StubSourceLocatorFactory.php index 0456667f054..27384f41b17 100644 --- a/src/PhpDoc/StubSourceLocatorFactory.php +++ b/src/PhpDoc/StubSourceLocatorFactory.php @@ -17,34 +17,16 @@ class StubSourceLocatorFactory { - /** - * @var Parser - */ - private $php8Parser; - /** - * @var PhpStormStubsSourceStubber - */ - private $phpStormStubsSourceStubber; - /** - * @var OptimizedSingleFileSourceLocatorRepository - */ - private $optimizedSingleFileSourceLocatorRepository; - /** - * @var OptimizedPsrAutoloaderLocatorFactory - */ - private $optimizedPsrAutoloaderLocatorFactory; - /** - * @var StubFilesProvider - */ - private $stubFilesProvider; - public function __construct(Parser $php8Parser, PhpStormStubsSourceStubber $phpStormStubsSourceStubber, OptimizedSingleFileSourceLocatorRepository $optimizedSingleFileSourceLocatorRepository, OptimizedPsrAutoloaderLocatorFactory $optimizedPsrAutoloaderLocatorFactory, StubFilesProvider $stubFilesProvider) + public function __construct( + private Parser $php8Parser, + private PhpStormStubsSourceStubber $phpStormStubsSourceStubber, + private OptimizedSingleFileSourceLocatorRepository $optimizedSingleFileSourceLocatorRepository, + private OptimizedPsrAutoloaderLocatorFactory $optimizedPsrAutoloaderLocatorFactory, + private StubFilesProvider $stubFilesProvider, + ) { - $this->php8Parser = $php8Parser; - $this->phpStormStubsSourceStubber = $phpStormStubsSourceStubber; - $this->optimizedSingleFileSourceLocatorRepository = $optimizedSingleFileSourceLocatorRepository; - $this->optimizedPsrAutoloaderLocatorFactory = $optimizedPsrAutoloaderLocatorFactory; - $this->stubFilesProvider = $stubFilesProvider; } + public function create(): SourceLocator { $locators = []; @@ -53,12 +35,16 @@ public function create(): SourceLocator $locators[] = $this->optimizedSingleFileSourceLocatorRepository->getOrCreate($stubFile); } - $locators[] = $this->optimizedPsrAutoloaderLocatorFactory->create(Psr4Mapping::fromArrayMappings([ + $locators[] = $this->optimizedPsrAutoloaderLocatorFactory->create( + Psr4Mapping::fromArrayMappings([ 'PHPStan\\' => [dirname(__DIR__) . '/'], - ])); - $locators[] = $this->optimizedPsrAutoloaderLocatorFactory->create(Psr4Mapping::fromArrayMappings([ + ]), + ); + $locators[] = $this->optimizedPsrAutoloaderLocatorFactory->create( + Psr4Mapping::fromArrayMappings([ 'PhpParser\\' => [dirname(__DIR__, 2) . '/vendor/nikic/php-parser/lib/PhpParser/'], - ])); + ]), + ); $locators[] = new PhpInternalSourceLocator($astPhp8Locator, $this->phpStormStubsSourceStubber); diff --git a/src/PhpDoc/StubValidator.php b/src/PhpDoc/StubValidator.php index 0e9416003a1..6eb52f2e56d 100644 --- a/src/PhpDoc/StubValidator.php +++ b/src/PhpDoc/StubValidator.php @@ -71,19 +71,13 @@ class StubValidator { - /** - * @var DerivativeContainerFactory - */ - private $derivativeContainerFactory; - /** - * @var bool - */ - private $duplicateStubs; - public function __construct(DerivativeContainerFactory $derivativeContainerFactory, bool $duplicateStubs) + public function __construct( + private DerivativeContainerFactory $derivativeContainerFactory, + private bool $duplicateStubs, + ) { - $this->derivativeContainerFactory = $derivativeContainerFactory; - $this->duplicateStubs = $duplicateStubs; } + /** * @param string[] $stubFiles * @return list @@ -117,8 +111,14 @@ public function validate(array $stubFiles, bool $debug): array $errors = []; foreach ($stubFiles as $stubFile) { try { - $tmpErrors = $fileAnalyser->analyseFile($stubFile, $analysedFiles, $ruleRegistry, $collectorRegistry, static function (): void { - })->getErrors(); + $tmpErrors = $fileAnalyser->analyseFile( + $stubFile, + $analysedFiles, + $ruleRegistry, + $collectorRegistry, + static function (): void { + }, + )->getErrors(); foreach ($tmpErrors as $tmpError) { $errors[] = $tmpError->withoutTip()->doNotIgnore(); } @@ -181,9 +181,18 @@ private function getRuleRegistry(Container $container): RuleRegistry new MethodTemplateTypeRule($fileTypeMapper, $templateTypeCheck), new MethodSignatureVarianceRule($varianceCheck), new TraitTemplateTypeRule($fileTypeMapper, $templateTypeCheck), - new IncompatiblePhpDocTypeRule($fileTypeMapper, $genericObjectTypeCheck, $unresolvableTypeHelper), + new IncompatiblePhpDocTypeRule( + $fileTypeMapper, + $genericObjectTypeCheck, + $unresolvableTypeHelper, + ), new IncompatiblePropertyPhpDocTypeRule($genericObjectTypeCheck, $unresolvableTypeHelper), - new InvalidPhpDocTagValueRule($container->getByType(Lexer::class), $container->getByType(PhpDocParser::class), $container->getParameter('featureToggles')['allInvalidPhpDocs'], $container->getParameter('featureToggles')['invalidPhpDocTagLine']), + new InvalidPhpDocTagValueRule( + $container->getByType(Lexer::class), + $container->getByType(PhpDocParser::class), + $container->getParameter('featureToggles')['allInvalidPhpDocs'], + $container->getParameter('featureToggles')['invalidPhpDocTagLine'], + ), new InvalidThrowsPhpDocValueRule($fileTypeMapper), // level 6 @@ -202,7 +211,11 @@ private function getRuleRegistry(Container $container): RuleRegistry } if ((bool) $container->getParameter('featureToggles')['allInvalidPhpDocs']) { - $rules[] = new InvalidPHPStanDocTagRule($container->getByType(Lexer::class), $container->getByType(PhpDocParser::class), true); + $rules[] = new InvalidPHPStanDocTagRule( + $container->getByType(Lexer::class), + $container->getByType(PhpDocParser::class), + true, + ); } return new DirectRuleRegistry($rules); diff --git a/src/PhpDoc/Tag/AssertTag.php b/src/PhpDoc/Tag/AssertTag.php index f4899ad63b4..4e436873a2e 100644 --- a/src/PhpDoc/Tag/AssertTag.php +++ b/src/PhpDoc/Tag/AssertTag.php @@ -9,45 +9,17 @@ final class AssertTag implements TypedTag { - /** - * @var self::NULL|self::IF_TRUE|self::IF_FALSE - */ - private $if; - /** - * @var Type - */ - private $type; - /** - * @var AssertTagParameter - */ - private $parameter; - /** - * @var bool - */ - private $negated; - /** - * @var bool - */ - private $equality; public const NULL = ''; public const IF_TRUE = 'true'; public const IF_FALSE = 'false'; - /** - * @var ?Type - */ - private $originalType = null; + private ?Type $originalType = null; /** * @param self::NULL|self::IF_TRUE|self::IF_FALSE $if */ - public function __construct(string $if, Type $type, AssertTagParameter $parameter, bool $negated, bool $equality) + public function __construct(private string $if, private Type $type, private AssertTagParameter $parameter, private bool $negated, private bool $equality) { - $this->if = $if; - $this->type = $type; - $this->parameter = $parameter; - $this->negated = $negated; - $this->equality = $equality; } /** @@ -65,7 +37,7 @@ public function getType(): Type public function getOriginalType(): Type { - return $this->originalType = $this->originalType ?? $this->type; + return $this->originalType ??= $this->type; } public function getParameter(): AssertTagParameter diff --git a/src/PhpDoc/Tag/AssertTagParameter.php b/src/PhpDoc/Tag/AssertTagParameter.php index 75bbfb2d7a1..18717b34941 100644 --- a/src/PhpDoc/Tag/AssertTagParameter.php +++ b/src/PhpDoc/Tag/AssertTagParameter.php @@ -8,24 +8,14 @@ class AssertTagParameter { - /** - * @var string - */ - private $parameterName; - /** - * @var ?string - */ - private $property; - /** - * @var ?string - */ - private $method; - public function __construct(string $parameterName, ?string $property, ?string $method) + public function __construct( + private string $parameterName, + private ?string $property, + private ?string $method, + ) { - $this->parameterName = $parameterName; - $this->property = $property; - $this->method = $method; } + public function getParameterName(): string { return $this->parameterName; @@ -33,7 +23,11 @@ public function getParameterName(): string public function changeParameterName(string $parameterName): self { - return new self($parameterName, $this->property, $this->method); + return new self( + $parameterName, + $this->property, + $this->method, + ); } public function describe(): string diff --git a/src/PhpDoc/Tag/DeprecatedTag.php b/src/PhpDoc/Tag/DeprecatedTag.php index a98b710186d..ea798c2aab4 100644 --- a/src/PhpDoc/Tag/DeprecatedTag.php +++ b/src/PhpDoc/Tag/DeprecatedTag.php @@ -6,13 +6,8 @@ class DeprecatedTag { - /** - * @var ?string - */ - private $message; - public function __construct(?string $message) + public function __construct(private ?string $message) { - $this->message = $message; } public function getMessage(): ?string diff --git a/src/PhpDoc/Tag/ExtendsTag.php b/src/PhpDoc/Tag/ExtendsTag.php index c03bb71be43..74ed32b7a2a 100644 --- a/src/PhpDoc/Tag/ExtendsTag.php +++ b/src/PhpDoc/Tag/ExtendsTag.php @@ -8,13 +8,8 @@ class ExtendsTag { - /** - * @var Type - */ - private $type; - public function __construct(Type $type) + public function __construct(private Type $type) { - $this->type = $type; } public function getType(): Type diff --git a/src/PhpDoc/Tag/ImplementsTag.php b/src/PhpDoc/Tag/ImplementsTag.php index b7ce8a72547..cc9376b47ae 100644 --- a/src/PhpDoc/Tag/ImplementsTag.php +++ b/src/PhpDoc/Tag/ImplementsTag.php @@ -8,13 +8,8 @@ class ImplementsTag { - /** - * @var Type - */ - private $type; - public function __construct(Type $type) + public function __construct(private Type $type) { - $this->type = $type; } public function getType(): Type diff --git a/src/PhpDoc/Tag/MethodTag.php b/src/PhpDoc/Tag/MethodTag.php index f180b17e7c5..e640418ea80 100644 --- a/src/PhpDoc/Tag/MethodTag.php +++ b/src/PhpDoc/Tag/MethodTag.php @@ -8,27 +8,17 @@ class MethodTag { - /** - * @var Type - */ - private $returnType; - /** - * @var bool - */ - private $isStatic; - /** - * @var array - */ - private $parameters; /** * @param array $parameters */ - public function __construct(Type $returnType, bool $isStatic, array $parameters) + public function __construct( + private Type $returnType, + private bool $isStatic, + private array $parameters, + ) { - $this->returnType = $returnType; - $this->isStatic = $isStatic; - $this->parameters = $parameters; } + public function getReturnType(): Type { return $this->returnType; diff --git a/src/PhpDoc/Tag/MethodTagParameter.php b/src/PhpDoc/Tag/MethodTagParameter.php index 25410ee0e34..1326c4cbc9a 100644 --- a/src/PhpDoc/Tag/MethodTagParameter.php +++ b/src/PhpDoc/Tag/MethodTagParameter.php @@ -9,34 +9,16 @@ class MethodTagParameter { - /** - * @var Type - */ - private $type; - /** - * @var PassedByReference - */ - private $passedByReference; - /** - * @var bool - */ - private $isOptional; - /** - * @var bool - */ - private $isVariadic; - /** - * @var ?Type - */ - private $defaultValue; - public function __construct(Type $type, PassedByReference $passedByReference, bool $isOptional, bool $isVariadic, ?Type $defaultValue) + public function __construct( + private Type $type, + private PassedByReference $passedByReference, + private bool $isOptional, + private bool $isVariadic, + private ?Type $defaultValue, + ) { - $this->type = $type; - $this->passedByReference = $passedByReference; - $this->isOptional = $isOptional; - $this->isVariadic = $isVariadic; - $this->defaultValue = $defaultValue; } + public function getType(): Type { return $this->type; diff --git a/src/PhpDoc/Tag/MixinTag.php b/src/PhpDoc/Tag/MixinTag.php index 050ecac5340..2a97b732645 100644 --- a/src/PhpDoc/Tag/MixinTag.php +++ b/src/PhpDoc/Tag/MixinTag.php @@ -8,13 +8,8 @@ class MixinTag { - /** - * @var Type - */ - private $type; - public function __construct(Type $type) + public function __construct(private Type $type) { - $this->type = $type; } public function getType(): Type diff --git a/src/PhpDoc/Tag/ParamOutTag.php b/src/PhpDoc/Tag/ParamOutTag.php index 2f95dfe9d6a..c40018cb453 100644 --- a/src/PhpDoc/Tag/ParamOutTag.php +++ b/src/PhpDoc/Tag/ParamOutTag.php @@ -8,13 +8,8 @@ class ParamOutTag implements TypedTag { - /** - * @var Type - */ - private $type; - public function __construct(Type $type) + public function __construct(private Type $type) { - $this->type = $type; } public function getType(): Type diff --git a/src/PhpDoc/Tag/ParamTag.php b/src/PhpDoc/Tag/ParamTag.php index c482bad83b6..651064cec1a 100644 --- a/src/PhpDoc/Tag/ParamTag.php +++ b/src/PhpDoc/Tag/ParamTag.php @@ -8,18 +8,8 @@ class ParamTag implements TypedTag { - /** - * @var Type - */ - private $type; - /** - * @var bool - */ - private $isVariadic; - public function __construct(Type $type, bool $isVariadic) + public function __construct(private Type $type, private bool $isVariadic) { - $this->type = $type; - $this->isVariadic = $isVariadic; } public function getType(): Type diff --git a/src/PhpDoc/Tag/PropertyTag.php b/src/PhpDoc/Tag/PropertyTag.php index 16f122015ff..f2e42c14b38 100644 --- a/src/PhpDoc/Tag/PropertyTag.php +++ b/src/PhpDoc/Tag/PropertyTag.php @@ -8,24 +8,14 @@ class PropertyTag { - /** - * @var Type - */ - private $type; - /** - * @var ?Type - */ - private $readableType; - /** - * @var ?Type - */ - private $writableType; - public function __construct(Type $type, ?Type $readableType, ?Type $writableType) + public function __construct( + private Type $type, + private ?Type $readableType, + private ?Type $writableType, + ) { - $this->type = $type; - $this->readableType = $readableType; - $this->writableType = $writableType; } + /** * @deprecated Use getReadableType() / getWritableType() */ diff --git a/src/PhpDoc/Tag/RequireExtendsTag.php b/src/PhpDoc/Tag/RequireExtendsTag.php index ac1fa843ef8..a1e60d45a63 100644 --- a/src/PhpDoc/Tag/RequireExtendsTag.php +++ b/src/PhpDoc/Tag/RequireExtendsTag.php @@ -8,13 +8,8 @@ class RequireExtendsTag { - /** - * @var Type - */ - private $type; - public function __construct(Type $type) + public function __construct(private Type $type) { - $this->type = $type; } public function getType(): Type diff --git a/src/PhpDoc/Tag/RequireImplementsTag.php b/src/PhpDoc/Tag/RequireImplementsTag.php index e14fd4e039e..2a0f42303fb 100644 --- a/src/PhpDoc/Tag/RequireImplementsTag.php +++ b/src/PhpDoc/Tag/RequireImplementsTag.php @@ -8,13 +8,8 @@ class RequireImplementsTag { - /** - * @var Type - */ - private $type; - public function __construct(Type $type) + public function __construct(private Type $type) { - $this->type = $type; } public function getType(): Type diff --git a/src/PhpDoc/Tag/ReturnTag.php b/src/PhpDoc/Tag/ReturnTag.php index 4282cd8e225..683b0cb2590 100644 --- a/src/PhpDoc/Tag/ReturnTag.php +++ b/src/PhpDoc/Tag/ReturnTag.php @@ -8,18 +8,8 @@ class ReturnTag implements TypedTag { - /** - * @var Type - */ - private $type; - /** - * @var bool - */ - private $isExplicit; - public function __construct(Type $type, bool $isExplicit) + public function __construct(private Type $type, private bool $isExplicit) { - $this->type = $type; - $this->isExplicit = $isExplicit; } public function getType(): Type diff --git a/src/PhpDoc/Tag/SelfOutTypeTag.php b/src/PhpDoc/Tag/SelfOutTypeTag.php index 975fd1a9efc..bbd5a2ca090 100644 --- a/src/PhpDoc/Tag/SelfOutTypeTag.php +++ b/src/PhpDoc/Tag/SelfOutTypeTag.php @@ -7,13 +7,8 @@ class SelfOutTypeTag implements TypedTag { - /** - * @var Type - */ - private $type; - public function __construct(Type $type) + public function __construct(private Type $type) { - $this->type = $type; } public function getType(): Type diff --git a/src/PhpDoc/Tag/TemplateTag.php b/src/PhpDoc/Tag/TemplateTag.php index 113765734a1..4a2180c0529 100644 --- a/src/PhpDoc/Tag/TemplateTag.php +++ b/src/PhpDoc/Tag/TemplateTag.php @@ -9,23 +9,8 @@ class TemplateTag { - /** - * @var string - */ - private $name; - /** - * @var Type - */ - private $bound; - /** - * @var TemplateTypeVariance - */ - private $variance; - public function __construct(string $name, Type $bound, TemplateTypeVariance $variance) + public function __construct(private string $name, private Type $bound, private TemplateTypeVariance $variance) { - $this->name = $name; - $this->bound = $bound; - $this->variance = $variance; } public function getName(): string diff --git a/src/PhpDoc/Tag/ThrowsTag.php b/src/PhpDoc/Tag/ThrowsTag.php index bf2665da012..15c1ac94d9e 100644 --- a/src/PhpDoc/Tag/ThrowsTag.php +++ b/src/PhpDoc/Tag/ThrowsTag.php @@ -8,13 +8,8 @@ class ThrowsTag { - /** - * @var Type - */ - private $type; - public function __construct(Type $type) + public function __construct(private Type $type) { - $this->type = $type; } public function getType(): Type diff --git a/src/PhpDoc/Tag/TypeAliasImportTag.php b/src/PhpDoc/Tag/TypeAliasImportTag.php index 717369c0519..ab074d6775d 100644 --- a/src/PhpDoc/Tag/TypeAliasImportTag.php +++ b/src/PhpDoc/Tag/TypeAliasImportTag.php @@ -6,23 +6,8 @@ final class TypeAliasImportTag { - /** - * @var string - */ - private $importedAlias; - /** - * @var string - */ - private $importedFrom; - /** - * @var ?string - */ - private $importedAs; - public function __construct(string $importedAlias, string $importedFrom, ?string $importedAs) + public function __construct(private string $importedAlias, private string $importedFrom, private ?string $importedAs) { - $this->importedAlias = $importedAlias; - $this->importedFrom = $importedFrom; - $this->importedAs = $importedAs; } public function getImportedAlias(): string diff --git a/src/PhpDoc/Tag/TypeAliasTag.php b/src/PhpDoc/Tag/TypeAliasTag.php index 54a55f13d7d..35b613417a0 100644 --- a/src/PhpDoc/Tag/TypeAliasTag.php +++ b/src/PhpDoc/Tag/TypeAliasTag.php @@ -10,24 +10,14 @@ class TypeAliasTag { - /** - * @var string - */ - private $aliasName; - /** - * @var TypeNode - */ - private $typeNode; - /** - * @var NameScope - */ - private $nameScope; - public function __construct(string $aliasName, TypeNode $typeNode, NameScope $nameScope) + public function __construct( + private string $aliasName, + private TypeNode $typeNode, + private NameScope $nameScope, + ) { - $this->aliasName = $aliasName; - $this->typeNode = $typeNode; - $this->nameScope = $nameScope; } + public function getAliasName(): string { return $this->aliasName; @@ -35,7 +25,10 @@ public function getAliasName(): string public function getTypeAlias(): TypeAlias { - return new TypeAlias($this->typeNode, $this->nameScope); + return new TypeAlias( + $this->typeNode, + $this->nameScope, + ); } } diff --git a/src/PhpDoc/Tag/UsesTag.php b/src/PhpDoc/Tag/UsesTag.php index 996ca5b6bff..453eb5b2502 100644 --- a/src/PhpDoc/Tag/UsesTag.php +++ b/src/PhpDoc/Tag/UsesTag.php @@ -8,13 +8,8 @@ class UsesTag { - /** - * @var Type - */ - private $type; - public function __construct(Type $type) + public function __construct(private Type $type) { - $this->type = $type; } public function getType(): Type diff --git a/src/PhpDoc/Tag/VarTag.php b/src/PhpDoc/Tag/VarTag.php index 708e82eb1ac..672cb81d43f 100644 --- a/src/PhpDoc/Tag/VarTag.php +++ b/src/PhpDoc/Tag/VarTag.php @@ -8,13 +8,8 @@ class VarTag implements TypedTag { - /** - * @var Type - */ - private $type; - public function __construct(Type $type) + public function __construct(private Type $type) { - $this->type = $type; } public function getType(): Type diff --git a/src/PhpDoc/TypeNodeResolver.php b/src/PhpDoc/TypeNodeResolver.php index 44041052f6f..c43095a82fb 100644 --- a/src/PhpDoc/TypeNodeResolver.php +++ b/src/PhpDoc/TypeNodeResolver.php @@ -115,36 +115,17 @@ class TypeNodeResolver { - /** - * @var TypeNodeResolverExtensionRegistryProvider - */ - private $extensionRegistryProvider; - /** - * @var ReflectionProvider\ReflectionProviderProvider - */ - private $reflectionProviderProvider; - /** - * @var TypeAliasResolverProvider - */ - private $typeAliasResolverProvider; - /** - * @var ConstantResolver - */ - private $constantResolver; - /** - * @var InitializerExprTypeResolver - */ - private $initializerExprTypeResolver; /** @var array */ - private $genericTypeResolvingStack = []; - - public function __construct(TypeNodeResolverExtensionRegistryProvider $extensionRegistryProvider, ReflectionProvider\ReflectionProviderProvider $reflectionProviderProvider, TypeAliasResolverProvider $typeAliasResolverProvider, ConstantResolver $constantResolver, InitializerExprTypeResolver $initializerExprTypeResolver) + private array $genericTypeResolvingStack = []; + + public function __construct( + private TypeNodeResolverExtensionRegistryProvider $extensionRegistryProvider, + private ReflectionProvider\ReflectionProviderProvider $reflectionProviderProvider, + private TypeAliasResolverProvider $typeAliasResolverProvider, + private ConstantResolver $constantResolver, + private InitializerExprTypeResolver $initializerExprTypeResolver, + ) { - $this->extensionRegistryProvider = $extensionRegistryProvider; - $this->reflectionProviderProvider = $reflectionProviderProvider; - $this->typeAliasResolverProvider = $typeAliasResolverProvider; - $this->constantResolver = $constantResolver; - $this->initializerExprTypeResolver = $initializerExprTypeResolver; } /** @api */ @@ -256,10 +237,16 @@ private function resolveIdentifierTypeNode(IdentifierTypeNode $typeNode, NameSco return new UnionType([new IntegerType(), new FloatType(), new StringType(), new BooleanType()]); case 'empty-scalar': - return TypeCombinator::intersect(new UnionType([new IntegerType(), new FloatType(), new StringType(), new BooleanType()]), StaticTypeFactory::falsey()); + return TypeCombinator::intersect( + new UnionType([new IntegerType(), new FloatType(), new StringType(), new BooleanType()]), + StaticTypeFactory::falsey(), + ); case 'non-empty-scalar': - return TypeCombinator::remove(new UnionType([new IntegerType(), new FloatType(), new StringType(), new BooleanType()]), StaticTypeFactory::falsey()); + return TypeCombinator::remove( + new UnionType([new IntegerType(), new FloatType(), new StringType(), new BooleanType()]), + StaticTypeFactory::falsey(), + ); case 'number': $type = $this->tryResolvePseudoTypeClassType($typeNode, $nameScope); @@ -351,7 +338,10 @@ private function resolveIdentifierTypeNode(IdentifierTypeNode $typeNode, NameSco return new ArrayType(new MixedType(), new MixedType()); case 'non-empty-array': - return TypeCombinator::intersect(new ArrayType(new MixedType(), new MixedType()), new NonEmptyArrayType()); + return TypeCombinator::intersect( + new ArrayType(new MixedType(), new MixedType()), + new NonEmptyArrayType(), + ); case 'iterable': return new IterableType(new MixedType(), new MixedType()); @@ -409,9 +399,15 @@ private function resolveIdentifierTypeNode(IdentifierTypeNode $typeNode, NameSco case 'list': return AccessoryArrayListType::intersectWith(new ArrayType(new IntegerType(), new MixedType())); case 'non-empty-list': - return AccessoryArrayListType::intersectWith(TypeCombinator::intersect(new ArrayType(new IntegerType(), new MixedType()), new NonEmptyArrayType())); + return AccessoryArrayListType::intersectWith(TypeCombinator::intersect( + new ArrayType(new IntegerType(), new MixedType()), + new NonEmptyArrayType(), + )); case '__always-list': - return TypeCombinator::intersect(new ArrayType(new IntegerType(), new MixedType()), new AccessoryArrayListType()); + return TypeCombinator::intersect( + new ArrayType(new IntegerType(), new MixedType()), + new AccessoryArrayListType(), + ); case 'empty': $type = $this->tryResolvePseudoTypeClassType($typeNode, $nameScope); @@ -583,12 +579,24 @@ private function resolveIntersectionTypeNode(IntersectionTypeNode $typeNode, Nam private function resolveConditionalTypeNode(ConditionalTypeNode $typeNode, NameScope $nameScope): Type { - return new ConditionalType($this->resolve($typeNode->subjectType, $nameScope), $this->resolve($typeNode->targetType, $nameScope), $this->resolve($typeNode->if, $nameScope), $this->resolve($typeNode->else, $nameScope), $typeNode->negated); + return new ConditionalType( + $this->resolve($typeNode->subjectType, $nameScope), + $this->resolve($typeNode->targetType, $nameScope), + $this->resolve($typeNode->if, $nameScope), + $this->resolve($typeNode->else, $nameScope), + $typeNode->negated, + ); } private function resolveConditionalTypeForParameterNode(ConditionalTypeForParameterNode $typeNode, NameScope $nameScope): Type { - return new ConditionalTypeForParameter($typeNode->parameterName, $this->resolve($typeNode->targetType, $nameScope), $this->resolve($typeNode->if, $nameScope), $this->resolve($typeNode->else, $nameScope), $typeNode->negated); + return new ConditionalTypeForParameter( + $typeNode->parameterName, + $this->resolve($typeNode->targetType, $nameScope), + $this->resolve($typeNode->if, $nameScope), + $this->resolve($typeNode->else, $nameScope), + $typeNode->negated, + ); } private function resolveArrayTypeNode(ArrayTypeNode $typeNode, NameScope $nameScope): Type @@ -601,7 +609,8 @@ private function resolveGenericTypeNode(GenericTypeNode $typeNode, NameScope $na { $mainTypeName = strtolower($typeNode->type->name); $genericTypes = $this->resolveMultiple($typeNode->genericTypes, $nameScope); - $variances = array_map(static function (string $variance): TemplateTypeVariance { + $variances = array_map( + static function (string $variance): TemplateTypeVariance { switch ($variance) { case GenericTypeNode::VARIANCE_INVARIANT: return TemplateTypeVariance::createInvariant(); @@ -612,7 +621,9 @@ private function resolveGenericTypeNode(GenericTypeNode $typeNode, NameScope $na case GenericTypeNode::VARIANCE_BIVARIANT: return TemplateTypeVariance::createBivariant(); } - }, $typeNode->variances); + }, + $typeNode->variances, + ); if (in_array($mainTypeName, ['array', 'non-empty-array'], true)) { if (count($genericTypes) === 1) { // array @@ -834,11 +845,17 @@ private function resolveGenericTypeNode(GenericTypeNode $typeNode, NameScope $na try { if (count($genericTypes) === 1) { // Foo - return TypeCombinator::intersect($mainType, new IterableType(new MixedType(true), $genericTypes[0])); + return TypeCombinator::intersect( + $mainType, + new IterableType(new MixedType(true), $genericTypes[0]), + ); } if (count($genericTypes) === 2) { // Foo - return TypeCombinator::intersect($mainType, new IterableType($genericTypes[0], $genericTypes[1])); + return TypeCombinator::intersect( + $mainType, + new IterableType($genericTypes[0], $genericTypes[1]), + ); } } finally { if ($mainTypeClassName !== null) { @@ -858,14 +875,24 @@ private function resolveCallableTypeNode(CallableTypeNode $typeNode, NameScope $ { $mainType = $this->resolve($typeNode->identifier, $nameScope); $isVariadic = false; - $parameters = array_map(function (CallableTypeParameterNode $parameterNode) use ($nameScope, &$isVariadic): NativeParameterReflection { + $parameters = array_map( + function (CallableTypeParameterNode $parameterNode) use ($nameScope, &$isVariadic): NativeParameterReflection { $isVariadic = $isVariadic || $parameterNode->isVariadic; $parameterName = $parameterNode->parameterName; if (str_starts_with($parameterName, '$')) { $parameterName = substr($parameterName, 1); } - return new NativeParameterReflection($parameterName, $parameterNode->isOptional || $parameterNode->isVariadic, $this->resolve($parameterNode->type, $nameScope), $parameterNode->isReference ? PassedByReference::createCreatesNewVariable() : PassedByReference::createNo(), $parameterNode->isVariadic, null); - }, $typeNode->parameters); + return new NativeParameterReflection( + $parameterName, + $parameterNode->isOptional || $parameterNode->isVariadic, + $this->resolve($parameterNode->type, $nameScope), + $parameterNode->isReference ? PassedByReference::createCreatesNewVariable() : PassedByReference::createNo(), + $parameterNode->isVariadic, + null, + ); + }, + $typeNode->parameters, + ); $returnType = $this->resolve($typeNode->returnType, $nameScope); if ($mainType instanceof CallableType) { @@ -1002,7 +1029,12 @@ private function resolveConstTypeNode(ConstTypeNode $typeNode, NameScope $nameSc continue; } - $constantTypes[] = $this->initializerExprTypeResolver->getType($reflectionConstant->getValueExpression(), InitializerExprContext::fromClassReflection($this->getReflectionProvider()->getClass($declaringClassName))); + $constantTypes[] = $this->initializerExprTypeResolver->getType( + $reflectionConstant->getValueExpression(), + InitializerExprContext::fromClassReflection( + $this->getReflectionProvider()->getClass($declaringClassName), + ), + ); } if (count($constantTypes) === 0) { @@ -1058,9 +1090,7 @@ private function resolveOffsetAccessNode(OffsetAccessTypeNode $typeNode, NameSco private function expandIntMaskToType(Type $type): ?Type { - $ints = array_map(static function (ConstantIntegerType $type) { - return $type->getValue(); - }, TypeUtils::getConstantIntegers($type)); + $ints = array_map(static fn (ConstantIntegerType $type) => $type->getValue(), TypeUtils::getConstantIntegers($type)); if (count($ints) === 0) { return null; } @@ -1087,9 +1117,7 @@ private function expandIntMaskToType(Type $type): ?Type return IntegerRangeType::fromInterval($min, $max); } - return TypeCombinator::union(...array_map(static function ($value) { - return new ConstantIntegerType($value); - }, $values)); + return TypeCombinator::union(...array_map(static fn ($value) => new ConstantIntegerType($value), $values)); } /** diff --git a/src/PhpDoc/TypeNodeResolverExtensionAwareRegistry.php b/src/PhpDoc/TypeNodeResolverExtensionAwareRegistry.php index 8951029aa3f..a41b9c631cc 100644 --- a/src/PhpDoc/TypeNodeResolverExtensionAwareRegistry.php +++ b/src/PhpDoc/TypeNodeResolverExtensionAwareRegistry.php @@ -6,27 +6,26 @@ class TypeNodeResolverExtensionAwareRegistry implements TypeNodeResolverExtensio { /** - * @var TypeNodeResolverExtension[] - */ - private $extensions; - /** - * @param TypeNodeResolverExtension[] $extensions - */ - public function __construct(TypeNodeResolver $typeNodeResolver, array $extensions) - { - $this->extensions = $extensions; - foreach ($extensions as $extension) { - if (!$extension instanceof TypeNodeResolverAwareExtension) { - continue; - } - - $extension->setTypeNodeResolver($typeNodeResolver); - } + * @param TypeNodeResolverExtension[] $extensions + */ + public function __construct( + TypeNodeResolver $typeNodeResolver, + private array $extensions, + ) + { + foreach ($extensions as $extension) { + if (!$extension instanceof TypeNodeResolverAwareExtension) { + continue; } - /** - * @return TypeNodeResolverExtension[] - */ - public function getExtensions(): array + + $extension->setTypeNodeResolver($typeNodeResolver); + } + } + + /** + * @return TypeNodeResolverExtension[] + */ + public function getExtensions(): array { return $this->extensions; } diff --git a/src/PhpDoc/TypeStringResolver.php b/src/PhpDoc/TypeStringResolver.php index ce3b906f52b..91333363ed2 100644 --- a/src/PhpDoc/TypeStringResolver.php +++ b/src/PhpDoc/TypeStringResolver.php @@ -11,23 +11,8 @@ class TypeStringResolver { - /** - * @var Lexer - */ - private $typeLexer; - /** - * @var TypeParser - */ - private $typeParser; - /** - * @var TypeNodeResolver - */ - private $typeNodeResolver; - public function __construct(Lexer $typeLexer, TypeParser $typeParser, TypeNodeResolver $typeNodeResolver) + public function __construct(private Lexer $typeLexer, private TypeParser $typeParser, private TypeNodeResolver $typeNodeResolver) { - $this->typeLexer = $typeLexer; - $this->typeParser = $typeParser; - $this->typeNodeResolver = $typeNodeResolver; } /** @api */ diff --git a/src/Process/CpuCoreCounter.php b/src/Process/CpuCoreCounter.php index 01e52f19468..cff6084b875 100644 --- a/src/Process/CpuCoreCounter.php +++ b/src/Process/CpuCoreCounter.php @@ -8,10 +8,7 @@ class CpuCoreCounter { - /** - * @var ?int - */ - private $count = null; + private ?int $count = null; public function getNumberOfCpuCores(): int { @@ -21,7 +18,7 @@ public function getNumberOfCpuCores(): int try { $this->count = (new FidryCpuCoreCounter())->getCount(); - } catch (NumberOfCpuCoreNotFound $e) { + } catch (NumberOfCpuCoreNotFound) { $this->count = 1; } diff --git a/src/Process/ProcessHelper.php b/src/Process/ProcessHelper.php index 631619030a0..2597e771a89 100644 --- a/src/Process/ProcessHelper.php +++ b/src/Process/ProcessHelper.php @@ -19,24 +19,35 @@ class ProcessHelper /** * @param string[] $additionalItems */ - public static function getWorkerCommand(string $mainScript, string $commandName, ?string $projectConfigFile, array $additionalItems, InputInterface $input) : string + public static function getWorkerCommand( + string $mainScript, + string $commandName, + ?string $projectConfigFile, + array $additionalItems, + InputInterface $input, + ): string { $phpIni = php_ini_loaded_file(); $phpCmd = $phpIni === false ? escapeshellarg(PHP_BINARY) : sprintf('%s -c %s', escapeshellarg(PHP_BINARY), escapeshellarg($phpIni)); + $processCommandArray = [ $phpCmd, ]; + if ($input->getOption('memory-limit') === null) { $processCommandArray[] = '-d'; $processCommandArray[] = 'memory_limit=' . ini_get('memory_limit'); } + foreach ([$mainScript, $commandName] as $arg) { $processCommandArray[] = escapeshellarg($arg); } + if ($projectConfigFile !== null) { $processCommandArray[] = '--configuration'; $processCommandArray[] = escapeshellarg($projectConfigFile); } + $options = [ AnalyseCommand::OPTION_LEVEL, 'autoload-file', @@ -59,13 +70,17 @@ public static function getWorkerCommand(string $mainScript, string $commandName, $processCommandArray[] = sprintf('--%s=%s', $optionName, escapeshellarg($optionValue)); } + $processCommandArray = array_merge($processCommandArray, $additionalItems); + $processCommandArray[] = '--'; + /** @var string[] $paths */ $paths = $input->getArgument('paths'); foreach ($paths as $path) { $processCommandArray[] = escapeshellarg($path); } + return implode(' ', $processCommandArray); } diff --git a/src/Process/ProcessPromise.php b/src/Process/ProcessPromise.php index 2a8fea6ed3c..91362ace740 100644 --- a/src/Process/ProcessPromise.php +++ b/src/Process/ProcessPromise.php @@ -16,38 +16,14 @@ class ProcessPromise { - /** - * @var LoopInterface - */ - private $loop; - /** - * @var string - */ - private $name; - /** - * @var string - */ - private $command; - /** - * @var Deferred - */ - private $deferred; + private Deferred $deferred; - /** - * @var ?Process - */ - private $process = null; + private ?Process $process = null; - /** - * @var bool - */ - private $canceled = false; + private bool $canceled = false; - public function __construct(LoopInterface $loop, string $name, string $command) + public function __construct(private LoopInterface $loop, private string $name, private string $command) { - $this->loop = $loop; - $this->name = $name; - $this->command = $command; $this->deferred = new Deferred(); } diff --git a/src/Reflection/Annotations/AnnotationMethodReflection.php b/src/Reflection/Annotations/AnnotationMethodReflection.php index ea41730f6f0..6a50a0ce9c0 100644 --- a/src/Reflection/Annotations/AnnotationMethodReflection.php +++ b/src/Reflection/Annotations/AnnotationMethodReflection.php @@ -15,49 +15,22 @@ class AnnotationMethodReflection implements ExtendedMethodReflection { - /** - * @var string - */ - private $name; - /** - * @var ClassReflection - */ - private $declaringClass; - /** - * @var Type - */ - private $returnType; - /** - * @var AnnotationsMethodParameterReflection[] - */ - private $parameters; - /** - * @var bool - */ - private $isStatic; - /** - * @var bool - */ - private $isVariadic; - /** - * @var ?Type - */ - private $throwType; /** @var FunctionVariantWithPhpDocs[]|null */ - private $variants = null; + private ?array $variants = null; /** * @param AnnotationsMethodParameterReflection[] $parameters */ - public function __construct(string $name, ClassReflection $declaringClass, Type $returnType, array $parameters, bool $isStatic, bool $isVariadic, ?Type $throwType) + public function __construct( + private string $name, + private ClassReflection $declaringClass, + private Type $returnType, + private array $parameters, + private bool $isStatic, + private bool $isVariadic, + private ?Type $throwType, + ) { - $this->name = $name; - $this->declaringClass = $declaringClass; - $this->returnType = $returnType; - $this->parameters = $parameters; - $this->isStatic = $isStatic; - $this->isVariadic = $isVariadic; - $this->throwType = $throwType; } public function getDeclaringClass(): ClassReflection @@ -94,7 +67,15 @@ public function getVariants(): array { if ($this->variants === null) { $this->variants = [ - new FunctionVariantWithPhpDocs(TemplateTypeMap::createEmpty(), null, $this->parameters, $this->isVariadic, $this->returnType, $this->returnType, new MixedType()), + new FunctionVariantWithPhpDocs( + TemplateTypeMap::createEmpty(), + null, + $this->parameters, + $this->isVariadic, + $this->returnType, + $this->returnType, + new MixedType(), + ), ]; } return $this->variants; diff --git a/src/Reflection/Annotations/AnnotationPropertyReflection.php b/src/Reflection/Annotations/AnnotationPropertyReflection.php index f419560b75c..6fe9b9d1256 100644 --- a/src/Reflection/Annotations/AnnotationPropertyReflection.php +++ b/src/Reflection/Annotations/AnnotationPropertyReflection.php @@ -10,34 +10,16 @@ class AnnotationPropertyReflection implements PropertyReflection { - /** - * @var ClassReflection - */ - private $declaringClass; - /** - * @var Type - */ - private $readableType; - /** - * @var Type - */ - private $writableType; - /** - * @var bool - */ - private $readable; - /** - * @var bool - */ - private $writable; - public function __construct(ClassReflection $declaringClass, Type $readableType, Type $writableType, bool $readable, bool $writable) + public function __construct( + private ClassReflection $declaringClass, + private Type $readableType, + private Type $writableType, + private bool $readable, + private bool $writable, + ) { - $this->declaringClass = $declaringClass; - $this->readableType = $readableType; - $this->writableType = $writableType; - $this->readable = $readable; - $this->writable = $writable; } + public function getDeclaringClass(): ClassReflection { return $this->declaringClass; diff --git a/src/Reflection/Annotations/AnnotationsMethodParameterReflection.php b/src/Reflection/Annotations/AnnotationsMethodParameterReflection.php index 75731cfa158..555a77e2555 100644 --- a/src/Reflection/Annotations/AnnotationsMethodParameterReflection.php +++ b/src/Reflection/Annotations/AnnotationsMethodParameterReflection.php @@ -10,38 +10,8 @@ class AnnotationsMethodParameterReflection implements ParameterReflectionWithPhpDocs { - /** - * @var string - */ - private $name; - /** - * @var Type - */ - private $type; - /** - * @var PassedByReference - */ - private $passedByReference; - /** - * @var bool - */ - private $isOptional; - /** - * @var bool - */ - private $isVariadic; - /** - * @var ?Type - */ - private $defaultValue; - public function __construct(string $name, Type $type, PassedByReference $passedByReference, bool $isOptional, bool $isVariadic, ?Type $defaultValue) + public function __construct(private string $name, private Type $type, private PassedByReference $passedByReference, private bool $isOptional, private bool $isVariadic, private ?Type $defaultValue) { - $this->name = $name; - $this->type = $type; - $this->passedByReference = $passedByReference; - $this->isOptional = $isOptional; - $this->isVariadic = $isVariadic; - $this->defaultValue = $defaultValue; } public function getName(): string diff --git a/src/Reflection/Annotations/AnnotationsMethodsClassReflectionExtension.php b/src/Reflection/Annotations/AnnotationsMethodsClassReflectionExtension.php index 2f60db1d021..e1cee2da24f 100644 --- a/src/Reflection/Annotations/AnnotationsMethodsClassReflectionExtension.php +++ b/src/Reflection/Annotations/AnnotationsMethodsClassReflectionExtension.php @@ -14,7 +14,7 @@ class AnnotationsMethodsClassReflectionExtension implements MethodsClassReflecti { /** @var ExtendedMethodReflection[][] */ - private $methods = []; + private array $methods = []; public function hasMethod(ClassReflection $classReflection, string $methodName): bool { @@ -37,22 +37,47 @@ public function getMethod(ClassReflection $classReflection, string $methodName): return $this->methods[$classReflection->getCacheKey()][$methodName]; } - private function findClassReflectionWithMethod(ClassReflection $classReflection, ClassReflection $declaringClass, string $methodName) : ?ExtendedMethodReflection + private function findClassReflectionWithMethod( + ClassReflection $classReflection, + ClassReflection $declaringClass, + string $methodName, + ): ?ExtendedMethodReflection { $methodTags = $classReflection->getMethodTags(); if (isset($methodTags[$methodName])) { $parameters = []; foreach ($methodTags[$methodName]->getParameters() as $parameterName => $parameterTag) { - $parameters[] = new AnnotationsMethodParameterReflection($parameterName, $parameterTag->getType(), $parameterTag->passedByReference(), $parameterTag->isOptional(), $parameterTag->isVariadic(), $parameterTag->getDefaultValue()); + $parameters[] = new AnnotationsMethodParameterReflection( + $parameterName, + $parameterTag->getType(), + $parameterTag->passedByReference(), + $parameterTag->isOptional(), + $parameterTag->isVariadic(), + $parameterTag->getDefaultValue(), + ); } $isStatic = $methodTags[$methodName]->isStatic(); $nativeCallMethodName = $isStatic ? '__callStatic' : '__call'; - return new AnnotationMethodReflection($methodName, $declaringClass, TemplateTypeHelper::resolveTemplateTypes($methodTags[$methodName]->getReturnType(), $classReflection->getActiveTemplateTypeMap(), $classReflection->getCallSiteVarianceMap(), TemplateTypeVariance::createCovariant()), $parameters, $isStatic, $this->detectMethodVariadic($parameters), $classReflection->hasNativeMethod($nativeCallMethodName) + return new AnnotationMethodReflection( + $methodName, + $declaringClass, + TemplateTypeHelper::resolveTemplateTypes( + $methodTags[$methodName]->getReturnType(), + $classReflection->getActiveTemplateTypeMap(), + $classReflection->getCallSiteVarianceMap(), + TemplateTypeVariance::createCovariant(), + ), + $parameters, + $isStatic, + $this->detectMethodVariadic($parameters), + $classReflection->hasNativeMethod($nativeCallMethodName) ? $classReflection->getNativeMethod($nativeCallMethodName)->getThrowType() - : null); + : null, + ); } + foreach ($classReflection->getTraits() as $traitClass) { $methodWithDeclaringClass = $this->findClassReflectionWithMethod($traitClass, $classReflection, $methodName); if ($methodWithDeclaringClass === null) { @@ -61,6 +86,7 @@ private function findClassReflectionWithMethod(ClassReflection $classReflection, return $methodWithDeclaringClass; } + $parentClass = $classReflection->getParentClass(); while ($parentClass !== null) { $methodWithDeclaringClass = $this->findClassReflectionWithMethod($parentClass, $parentClass, $methodName); @@ -79,6 +105,7 @@ private function findClassReflectionWithMethod(ClassReflection $classReflection, $parentClass = $parentClass->getParentClass(); } + foreach ($classReflection->getInterfaces() as $interfaceClass) { $methodWithDeclaringClass = $this->findClassReflectionWithMethod($interfaceClass, $interfaceClass, $methodName); if ($methodWithDeclaringClass === null) { @@ -87,6 +114,7 @@ private function findClassReflectionWithMethod(ClassReflection $classReflection, return $methodWithDeclaringClass; } + return null; } diff --git a/src/Reflection/Annotations/AnnotationsPropertiesClassReflectionExtension.php b/src/Reflection/Annotations/AnnotationsPropertiesClassReflectionExtension.php index 413b00ec438..3ef4959ab8b 100644 --- a/src/Reflection/Annotations/AnnotationsPropertiesClassReflectionExtension.php +++ b/src/Reflection/Annotations/AnnotationsPropertiesClassReflectionExtension.php @@ -13,7 +13,7 @@ class AnnotationsPropertiesClassReflectionExtension implements PropertiesClassRe { /** @var PropertyReflection[][] */ - private $properties = []; + private array $properties = []; public function hasProperty(ClassReflection $classReflection, string $propertyName): bool { @@ -33,7 +33,11 @@ public function getProperty(ClassReflection $classReflection, string $propertyNa return $this->properties[$classReflection->getCacheKey()][$propertyName]; } - private function findClassReflectionWithProperty(ClassReflection $classReflection, ClassReflection $declaringClass, string $propertyName) : ?PropertyReflection + private function findClassReflectionWithProperty( + ClassReflection $classReflection, + ClassReflection $declaringClass, + string $propertyName, + ): ?PropertyReflection { $propertyTags = $classReflection->getPropertyTags(); if (isset($propertyTags[$propertyName])) { @@ -47,8 +51,25 @@ private function findClassReflectionWithProperty(ClassReflection $classReflectio $isWritable = $isWritable || $nativeProperty->isWritable(); } - return new AnnotationPropertyReflection($declaringClass, TemplateTypeHelper::resolveTemplateTypes($propertyTag->getReadableType() ?? new NeverType(), $classReflection->getActiveTemplateTypeMap(), $classReflection->getCallSiteVarianceMap(), TemplateTypeVariance::createCovariant()), TemplateTypeHelper::resolveTemplateTypes($propertyTag->getWritableType() ?? new NeverType(), $classReflection->getActiveTemplateTypeMap(), $classReflection->getCallSiteVarianceMap(), TemplateTypeVariance::createContravariant()), $isReadable, $isWritable); + return new AnnotationPropertyReflection( + $declaringClass, + TemplateTypeHelper::resolveTemplateTypes( + $propertyTag->getReadableType() ?? new NeverType(), + $classReflection->getActiveTemplateTypeMap(), + $classReflection->getCallSiteVarianceMap(), + TemplateTypeVariance::createCovariant(), + ), + TemplateTypeHelper::resolveTemplateTypes( + $propertyTag->getWritableType() ?? new NeverType(), + $classReflection->getActiveTemplateTypeMap(), + $classReflection->getCallSiteVarianceMap(), + TemplateTypeVariance::createContravariant(), + ), + $isReadable, + $isWritable, + ); } + foreach ($classReflection->getTraits() as $traitClass) { $methodWithDeclaringClass = $this->findClassReflectionWithProperty($traitClass, $classReflection, $propertyName); if ($methodWithDeclaringClass === null) { @@ -57,6 +78,7 @@ private function findClassReflectionWithProperty(ClassReflection $classReflectio return $methodWithDeclaringClass; } + $parentClass = $classReflection->getParentClass(); while ($parentClass !== null) { $methodWithDeclaringClass = $this->findClassReflectionWithProperty($parentClass, $parentClass, $propertyName); @@ -75,6 +97,7 @@ private function findClassReflectionWithProperty(ClassReflection $classReflectio $parentClass = $parentClass->getParentClass(); } + foreach ($classReflection->getInterfaces() as $interfaceClass) { $methodWithDeclaringClass = $this->findClassReflectionWithProperty($interfaceClass, $interfaceClass, $propertyName); if ($methodWithDeclaringClass === null) { @@ -83,6 +106,7 @@ private function findClassReflectionWithProperty(ClassReflection $classReflectio return $methodWithDeclaringClass; } + return null; } diff --git a/src/Reflection/Assertions.php b/src/Reflection/Assertions.php index 78fbd8708ad..6adb97136c4 100644 --- a/src/Reflection/Assertions.php +++ b/src/Reflection/Assertions.php @@ -16,21 +16,13 @@ class Assertions { - /** - * @var AssertTag[] - */ - private $asserts; - /** - * @var ?self - */ - private static $empty = null; + private static ?self $empty = null; /** * @param AssertTag[] $asserts */ - private function __construct(array $asserts) + private function __construct(private array $asserts) { - $this->asserts = $asserts; } /** @@ -46,9 +38,7 @@ public function getAll(): array */ public function getAsserts(): array { - return array_filter($this->asserts, static function (AssertTag $assert) { - return $assert->getIf() === AssertTag::NULL; - }); + return array_filter($this->asserts, static fn (AssertTag $assert) => $assert->getIf() === AssertTag::NULL); } /** @@ -56,13 +46,13 @@ public function getAsserts(): array */ public function getAssertsIfTrue(): array { - return array_merge(array_filter($this->asserts, static function (AssertTag $assert) { - return $assert->getIf() === AssertTag::IF_TRUE; - }), array_map(static function (AssertTag $assert) { - return $assert->negate(); - }, array_filter($this->asserts, static function (AssertTag $assert) { - return $assert->getIf() === AssertTag::IF_FALSE && !$assert->isEquality(); - }))); + return array_merge( + array_filter($this->asserts, static fn (AssertTag $assert) => $assert->getIf() === AssertTag::IF_TRUE), + array_map( + static fn (AssertTag $assert) => $assert->negate(), + array_filter($this->asserts, static fn (AssertTag $assert) => $assert->getIf() === AssertTag::IF_FALSE && !$assert->isEquality()), + ), + ); } /** @@ -70,13 +60,13 @@ public function getAssertsIfTrue(): array */ public function getAssertsIfFalse(): array { - return array_merge(array_filter($this->asserts, static function (AssertTag $assert) { - return $assert->getIf() === AssertTag::IF_FALSE; - }), array_map(static function (AssertTag $assert) { - return $assert->negate(); - }, array_filter($this->asserts, static function (AssertTag $assert) { - return $assert->getIf() === AssertTag::IF_TRUE && !$assert->isEquality(); - }))); + return array_merge( + array_filter($this->asserts, static fn (AssertTag $assert) => $assert->getIf() === AssertTag::IF_FALSE), + array_map( + static fn (AssertTag $assert) => $assert->negate(), + array_filter($this->asserts, static fn (AssertTag $assert) => $assert->getIf() === AssertTag::IF_TRUE && !$assert->isEquality()), + ), + ); } /** @@ -84,9 +74,7 @@ public function getAssertsIfFalse(): array */ public function mapTypes(callable $callable): self { - $assertTagsCallback = static function (AssertTag $tag) use($callable) : AssertTag { - return $tag->withType($callable($tag->getType())); - }; + $assertTagsCallback = static fn (AssertTag $tag): AssertTag => $tag->withType($callable($tag->getType())); return new self(array_map($assertTagsCallback, $this->asserts)); } diff --git a/src/Reflection/BetterReflection/BetterReflectionProvider.php b/src/Reflection/BetterReflection/BetterReflectionProvider.php index 01169312e0b..d7bf76a56de 100644 --- a/src/Reflection/BetterReflection/BetterReflectionProvider.php +++ b/src/Reflection/BetterReflection/BetterReflectionProvider.php @@ -56,103 +56,40 @@ class BetterReflectionProvider implements ReflectionProvider { - /** - * @var ReflectionProvider\ReflectionProviderProvider - */ - private $reflectionProviderProvider; - /** - * @var InitializerExprTypeResolver - */ - private $initializerExprTypeResolver; - /** - * @var ClassReflectionExtensionRegistryProvider - */ - private $classReflectionExtensionRegistryProvider; - /** - * @var Reflector - */ - private $reflector; - /** - * @var FileTypeMapper - */ - private $fileTypeMapper; - /** - * @var PhpDocInheritanceResolver - */ - private $phpDocInheritanceResolver; - /** - * @var PhpVersion - */ - private $phpVersion; - /** - * @var NativeFunctionReflectionProvider - */ - private $nativeFunctionReflectionProvider; - /** - * @var StubPhpDocProvider - */ - private $stubPhpDocProvider; - /** - * @var FunctionReflectionFactory - */ - private $functionReflectionFactory; - /** - * @var RelativePathHelper - */ - private $relativePathHelper; - /** - * @var AnonymousClassNameHelper - */ - private $anonymousClassNameHelper; - /** - * @var FileHelper - */ - private $fileHelper; - /** - * @var PhpStormStubsSourceStubber - */ - private $phpstormStubsSourceStubber; - /** - * @var SignatureMapProvider - */ - private $signatureMapProvider; - /** - * @var string[] - */ - private $universalObjectCratesClasses; /** @var FunctionReflection[] */ - private $functionReflections = []; + private array $functionReflections = []; /** @var ClassReflection[] */ - private $classReflections = []; + private array $classReflections = []; /** @var ClassReflection[] */ - private static $anonymousClasses = []; + private static array $anonymousClasses = []; /** @var array */ - private $cachedConstants = []; + private array $cachedConstants = []; /** * @param string[] $universalObjectCratesClasses */ - public function __construct(ReflectionProvider\ReflectionProviderProvider $reflectionProviderProvider, InitializerExprTypeResolver $initializerExprTypeResolver, ClassReflectionExtensionRegistryProvider $classReflectionExtensionRegistryProvider, Reflector $reflector, FileTypeMapper $fileTypeMapper, PhpDocInheritanceResolver $phpDocInheritanceResolver, PhpVersion $phpVersion, NativeFunctionReflectionProvider $nativeFunctionReflectionProvider, StubPhpDocProvider $stubPhpDocProvider, FunctionReflectionFactory $functionReflectionFactory, RelativePathHelper $relativePathHelper, AnonymousClassNameHelper $anonymousClassNameHelper, FileHelper $fileHelper, PhpStormStubsSourceStubber $phpstormStubsSourceStubber, SignatureMapProvider $signatureMapProvider, array $universalObjectCratesClasses) + public function __construct( + private ReflectionProvider\ReflectionProviderProvider $reflectionProviderProvider, + private InitializerExprTypeResolver $initializerExprTypeResolver, + private ClassReflectionExtensionRegistryProvider $classReflectionExtensionRegistryProvider, + private Reflector $reflector, + private FileTypeMapper $fileTypeMapper, + private PhpDocInheritanceResolver $phpDocInheritanceResolver, + private PhpVersion $phpVersion, + private NativeFunctionReflectionProvider $nativeFunctionReflectionProvider, + private StubPhpDocProvider $stubPhpDocProvider, + private FunctionReflectionFactory $functionReflectionFactory, + private RelativePathHelper $relativePathHelper, + private AnonymousClassNameHelper $anonymousClassNameHelper, + private FileHelper $fileHelper, + private PhpStormStubsSourceStubber $phpstormStubsSourceStubber, + private SignatureMapProvider $signatureMapProvider, + private array $universalObjectCratesClasses, + ) { - $this->reflectionProviderProvider = $reflectionProviderProvider; - $this->initializerExprTypeResolver = $initializerExprTypeResolver; - $this->classReflectionExtensionRegistryProvider = $classReflectionExtensionRegistryProvider; - $this->reflector = $reflector; - $this->fileTypeMapper = $fileTypeMapper; - $this->phpDocInheritanceResolver = $phpDocInheritanceResolver; - $this->phpVersion = $phpVersion; - $this->nativeFunctionReflectionProvider = $nativeFunctionReflectionProvider; - $this->stubPhpDocProvider = $stubPhpDocProvider; - $this->functionReflectionFactory = $functionReflectionFactory; - $this->relativePathHelper = $relativePathHelper; - $this->anonymousClassNameHelper = $anonymousClassNameHelper; - $this->fileHelper = $fileHelper; - $this->phpstormStubsSourceStubber = $phpstormStubsSourceStubber; - $this->signatureMapProvider = $signatureMapProvider; - $this->universalObjectCratesClasses = $universalObjectCratesClasses; } public function hasClass(string $className): bool @@ -168,9 +105,9 @@ public function hasClass(string $className): bool try { $this->reflector->reflectClass($className); return true; - } catch (IdentifierNotFound $e) { + } catch (IdentifierNotFound) { return false; - } catch (InvalidIdentifierName $e) { + } catch (InvalidIdentifierName) { return false; } } @@ -183,7 +120,7 @@ public function getClass(string $className): ClassReflection try { $reflectionClass = $this->reflector->reflectClass($className); - } catch (IdentifierNotFound | InvalidIdentifierName $e) { + } catch (IdentifierNotFound | InvalidIdentifierName) { throw new ClassNotFoundException($className); } @@ -195,7 +132,26 @@ public function getClass(string $className): ClassReflection $enumAdapter = base64_decode('UEhQU3RhblxCZXR0ZXJSZWZsZWN0aW9uXFJlZmxlY3Rpb25cQWRhcHRlclxSZWZsZWN0aW9uRW51bQ==', true); - $classReflection = new ClassReflection($this->reflectionProviderProvider->getReflectionProvider(), $this->initializerExprTypeResolver, $this->fileTypeMapper, $this->stubPhpDocProvider, $this->phpDocInheritanceResolver, $this->phpVersion, $this->signatureMapProvider, $this->classReflectionExtensionRegistryProvider->getRegistry()->getPropertiesClassReflectionExtensions(), $this->classReflectionExtensionRegistryProvider->getRegistry()->getMethodsClassReflectionExtensions(), $this->classReflectionExtensionRegistryProvider->getRegistry()->getAllowedSubTypesClassReflectionExtensions(), $this->classReflectionExtensionRegistryProvider->getRegistry()->getRequireExtendsPropertyClassReflectionExtension(), $this->classReflectionExtensionRegistryProvider->getRegistry()->getRequireExtendsMethodsClassReflectionExtension(), $reflectionClass->getName(), $reflectionClass instanceof ReflectionEnum && PHP_VERSION_ID >= 80000 ? new $enumAdapter($reflectionClass) : new ReflectionClass($reflectionClass), null, null, $this->stubPhpDocProvider->findClassPhpDoc($reflectionClass->getName()), $this->universalObjectCratesClasses); + $classReflection = new ClassReflection( + $this->reflectionProviderProvider->getReflectionProvider(), + $this->initializerExprTypeResolver, + $this->fileTypeMapper, + $this->stubPhpDocProvider, + $this->phpDocInheritanceResolver, + $this->phpVersion, + $this->signatureMapProvider, + $this->classReflectionExtensionRegistryProvider->getRegistry()->getPropertiesClassReflectionExtensions(), + $this->classReflectionExtensionRegistryProvider->getRegistry()->getMethodsClassReflectionExtensions(), + $this->classReflectionExtensionRegistryProvider->getRegistry()->getAllowedSubTypesClassReflectionExtensions(), + $this->classReflectionExtensionRegistryProvider->getRegistry()->getRequireExtendsPropertyClassReflectionExtension(), + $this->classReflectionExtensionRegistryProvider->getRegistry()->getRequireExtendsMethodsClassReflectionExtension(), + $reflectionClass->getName(), + $reflectionClass instanceof ReflectionEnum && PHP_VERSION_ID >= 80000 ? new $enumAdapter($reflectionClass) : new ReflectionClass($reflectionClass), + null, + null, + $this->stubPhpDocProvider->findClassPhpDoc($reflectionClass->getName()), + $this->universalObjectCratesClasses, + ); $this->classReflections[$reflectionClassName] = $classReflection; @@ -238,7 +194,10 @@ public function getAnonymousClassReflection(Node\Stmt\Class_ $classNode, Scope $ } $filename = $this->fileHelper->normalizePath($this->relativePathHelper->getRelativePath($scopeFile), '/'); - $className = $this->anonymousClassNameHelper->getAnonymousClassName($classNode, $scopeFile); + $className = $this->anonymousClassNameHelper->getAnonymousClassName( + $classNode, + $scopeFile, + ); $classNode->name = new Node\Identifier($className); $classNode->setAttribute('anonymousClass', true); @@ -246,9 +205,33 @@ public function getAnonymousClassReflection(Node\Stmt\Class_ $classNode, Scope $ return self::$anonymousClasses[$className]; } - $reflectionClass = \PHPStan\BetterReflection\Reflection\ReflectionClass::createFromNode($this->reflector, $classNode, new LocatedSource(FileReader::read($scopeFile), $className, $scopeFile), null); - - self::$anonymousClasses[$className] = new ClassReflection($this->reflectionProviderProvider->getReflectionProvider(), $this->initializerExprTypeResolver, $this->fileTypeMapper, $this->stubPhpDocProvider, $this->phpDocInheritanceResolver, $this->phpVersion, $this->signatureMapProvider, $this->classReflectionExtensionRegistryProvider->getRegistry()->getPropertiesClassReflectionExtensions(), $this->classReflectionExtensionRegistryProvider->getRegistry()->getMethodsClassReflectionExtensions(), $this->classReflectionExtensionRegistryProvider->getRegistry()->getAllowedSubTypesClassReflectionExtensions(), $this->classReflectionExtensionRegistryProvider->getRegistry()->getRequireExtendsPropertyClassReflectionExtension(), $this->classReflectionExtensionRegistryProvider->getRegistry()->getRequireExtendsMethodsClassReflectionExtension(), sprintf('class@anonymous/%s:%s', $filename, $classNode->getStartLine()), new ReflectionClass($reflectionClass), $scopeFile, null, $this->stubPhpDocProvider->findClassPhpDoc($className), $this->universalObjectCratesClasses); + $reflectionClass = \PHPStan\BetterReflection\Reflection\ReflectionClass::createFromNode( + $this->reflector, + $classNode, + new LocatedSource(FileReader::read($scopeFile), $className, $scopeFile), + null, + ); + + self::$anonymousClasses[$className] = new ClassReflection( + $this->reflectionProviderProvider->getReflectionProvider(), + $this->initializerExprTypeResolver, + $this->fileTypeMapper, + $this->stubPhpDocProvider, + $this->phpDocInheritanceResolver, + $this->phpVersion, + $this->signatureMapProvider, + $this->classReflectionExtensionRegistryProvider->getRegistry()->getPropertiesClassReflectionExtensions(), + $this->classReflectionExtensionRegistryProvider->getRegistry()->getMethodsClassReflectionExtensions(), + $this->classReflectionExtensionRegistryProvider->getRegistry()->getAllowedSubTypesClassReflectionExtensions(), + $this->classReflectionExtensionRegistryProvider->getRegistry()->getRequireExtendsPropertyClassReflectionExtension(), + $this->classReflectionExtensionRegistryProvider->getRegistry()->getRequireExtendsMethodsClassReflectionExtension(), + sprintf('class@anonymous/%s:%s', $filename, $classNode->getStartLine()), + new ReflectionClass($reflectionClass), + $scopeFile, + null, + $this->stubPhpDocProvider->findClassPhpDoc($className), + $this->universalObjectCratesClasses, + ); $this->classReflections[$className] = self::$anonymousClasses[$className]; return self::$anonymousClasses[$className]; @@ -298,9 +281,7 @@ private function getCustomFunction(string $functionName): PhpFunctionReflection $phpDocComment = null; $phpDocParameterOutTags = []; - $resolvedPhpDoc = $this->stubPhpDocProvider->findFunctionPhpDoc($reflectionFunction->getName(), array_map(static function (ReflectionParameter $parameter) : string { - return $parameter->getName(); - }, $reflectionFunction->getParameters())); + $resolvedPhpDoc = $this->stubPhpDocProvider->findFunctionPhpDoc($reflectionFunction->getName(), array_map(static fn (ReflectionParameter $parameter): string => $parameter->getName(), $reflectionFunction->getParameters())); if ($resolvedPhpDoc === null && $reflectionFunction->getFileName() !== false && $reflectionFunction->getDocComment() !== false) { $docComment = $reflectionFunction->getDocComment(); $resolvedPhpDoc = $this->fileTypeMapper->getResolvedPhpDoc($reflectionFunction->getFileName(), null, null, $reflectionFunction->getName(), $docComment); @@ -323,11 +304,22 @@ private function getCustomFunction(string $functionName): PhpFunctionReflection $phpDocParameterOutTags = $resolvedPhpDoc->getParamOutTags(); } - return $this->functionReflectionFactory->create($reflectionFunction, $templateTypeMap, array_map(static function (ParamTag $paramTag) : Type { - return $paramTag->getType(); - }, $phpDocParameterTags), $phpDocReturnTag !== null ? $phpDocReturnTag->getType() : null, $phpDocThrowsTag !== null ? $phpDocThrowsTag->getType() : null, $deprecatedTag !== null ? $deprecatedTag->getMessage() : null, $isDeprecated, $isInternal, $isFinal, $reflectionFunction->getFileName() !== false ? $reflectionFunction->getFileName() : null, $isPure, $asserts, $phpDocComment, array_map(static function (ParamOutTag $paramOutTag) : Type { - return $paramOutTag->getType(); - }, $phpDocParameterOutTags)); + return $this->functionReflectionFactory->create( + $reflectionFunction, + $templateTypeMap, + array_map(static fn (ParamTag $paramTag): Type => $paramTag->getType(), $phpDocParameterTags), + $phpDocReturnTag !== null ? $phpDocReturnTag->getType() : null, + $phpDocThrowsTag !== null ? $phpDocThrowsTag->getType() : null, + $deprecatedTag !== null ? $deprecatedTag->getMessage() : null, + $isDeprecated, + $isInternal, + $isFinal, + $reflectionFunction->getFileName() !== false ? $reflectionFunction->getFileName() : null, + $isPure, + $asserts, + $phpDocComment, + array_map(static fn (ParamOutTag $paramOutTag): Type => $paramOutTag->getType(), $phpDocParameterOutTags), + ); } public function resolveFunctionName(Node\Name $nameNode, ?NamespaceAnswerer $namespaceAnswerer): ?string @@ -336,9 +328,9 @@ public function resolveFunctionName(Node\Name $nameNode, ?NamespaceAnswerer $nam try { $this->reflector->reflectFunction($name); return true; - } catch (IdentifierNotFound $e) { + } catch (IdentifierNotFound) { // pass - } catch (InvalidIdentifierName $e) { + } catch (InvalidIdentifierName) { // pass } @@ -369,7 +361,11 @@ public function getConstant(Node\Name $nameNode, ?NamespaceAnswerer $namespaceAn $fileName = $constantReflection->getFileName(); $constantValueType = $this->initializerExprTypeResolver->getType($constantReflection->getValueExpression(), InitializerExprContext::fromGlobalConstant($constantReflection)); - return $this->cachedConstants[$constantName] = new RuntimeConstantReflection($constantName, $constantValueType, $fileName); + return $this->cachedConstants[$constantName] = new RuntimeConstantReflection( + $constantName, + $constantValueType, + $fileName, + ); } public function resolveConstantName(Node\Name $nameNode, ?NamespaceAnswerer $namespaceAnswerer): ?string @@ -378,9 +374,9 @@ public function resolveConstantName(Node\Name $nameNode, ?NamespaceAnswerer $nam try { $this->reflector->reflectConstant($name); return true; - } catch (IdentifierNotFound $e) { + } catch (IdentifierNotFound) { // pass - } catch (UnableToCompileNode $e) { + } catch (UnableToCompileNode) { // pass } return false; @@ -390,7 +386,11 @@ public function resolveConstantName(Node\Name $nameNode, ?NamespaceAnswerer $nam /** * @param Closure(string $name): bool $existsCallback */ - private function resolveName(Node\Name $nameNode, Closure $existsCallback, ?NamespaceAnswerer $namespaceAnswerer) : ?string + private function resolveName( + Node\Name $nameNode, + Closure $existsCallback, + ?NamespaceAnswerer $namespaceAnswerer, + ): ?string { $name = (string) $nameNode; if ($namespaceAnswerer !== null && $namespaceAnswerer->getNamespace() !== null && !$nameNode->isFullyQualified()) { @@ -399,9 +399,11 @@ private function resolveName(Node\Name $nameNode, Closure $existsCallback, ?Name return $namespacedName; } } + if ($existsCallback($name)) { return $name; } + return null; } diff --git a/src/Reflection/BetterReflection/BetterReflectionProviderFactory.php b/src/Reflection/BetterReflection/BetterReflectionProviderFactory.php index d50bef895a9..b6fa9c03094 100644 --- a/src/Reflection/BetterReflection/BetterReflectionProviderFactory.php +++ b/src/Reflection/BetterReflection/BetterReflectionProviderFactory.php @@ -7,6 +7,8 @@ interface BetterReflectionProviderFactory { - public function create(Reflector $reflector) : BetterReflectionProvider; + public function create( + Reflector $reflector, + ): BetterReflectionProvider; } diff --git a/src/Reflection/BetterReflection/BetterReflectionSourceLocatorFactory.php b/src/Reflection/BetterReflection/BetterReflectionSourceLocatorFactory.php index 6e49a66e726..5a207d0476a 100644 --- a/src/Reflection/BetterReflection/BetterReflectionSourceLocatorFactory.php +++ b/src/Reflection/BetterReflection/BetterReflectionSourceLocatorFactory.php @@ -33,62 +33,6 @@ class BetterReflectionSourceLocatorFactory { - /** - * @var Parser - */ - private $parser; - /** - * @var Parser - */ - private $php8Parser; - /** - * @var PhpStormStubsSourceStubber - */ - private $phpstormStubsSourceStubber; - /** - * @var ReflectionSourceStubber - */ - private $reflectionSourceStubber; - /** - * @var OptimizedSingleFileSourceLocatorRepository - */ - private $optimizedSingleFileSourceLocatorRepository; - /** - * @var OptimizedDirectorySourceLocatorRepository - */ - private $optimizedDirectorySourceLocatorRepository; - /** - * @var ComposerJsonAndInstalledJsonSourceLocatorMaker - */ - private $composerJsonAndInstalledJsonSourceLocatorMaker; - /** - * @var OptimizedPsrAutoloaderLocatorFactory - */ - private $optimizedPsrAutoloaderLocatorFactory; - /** - * @var FileNodesFetcher - */ - private $fileNodesFetcher; - /** - * @var string[] - */ - private $scanFiles; - /** - * @var string[] - */ - private $scanDirectories; - /** - * @var string[] - */ - private $analysedPaths; - /** - * @var string[] - */ - private $composerAutoloaderProjectPaths; - /** - * @var string[] - */ - private $analysedPathsFromConfig; /** * @param string[] $scanFiles * @param string[] $scanDirectories @@ -96,29 +40,37 @@ class BetterReflectionSourceLocatorFactory * @param string[] $composerAutoloaderProjectPaths * @param string[] $analysedPathsFromConfig */ - public function __construct(Parser $parser, Parser $php8Parser, PhpStormStubsSourceStubber $phpstormStubsSourceStubber, ReflectionSourceStubber $reflectionSourceStubber, OptimizedSingleFileSourceLocatorRepository $optimizedSingleFileSourceLocatorRepository, OptimizedDirectorySourceLocatorRepository $optimizedDirectorySourceLocatorRepository, ComposerJsonAndInstalledJsonSourceLocatorMaker $composerJsonAndInstalledJsonSourceLocatorMaker, OptimizedPsrAutoloaderLocatorFactory $optimizedPsrAutoloaderLocatorFactory, FileNodesFetcher $fileNodesFetcher, array $scanFiles, array $scanDirectories, array $analysedPaths, array $composerAutoloaderProjectPaths, array $analysedPathsFromConfig) + public function __construct( + private Parser $parser, + private Parser $php8Parser, + private PhpStormStubsSourceStubber $phpstormStubsSourceStubber, + private ReflectionSourceStubber $reflectionSourceStubber, + private OptimizedSingleFileSourceLocatorRepository $optimizedSingleFileSourceLocatorRepository, + private OptimizedDirectorySourceLocatorRepository $optimizedDirectorySourceLocatorRepository, + private ComposerJsonAndInstalledJsonSourceLocatorMaker $composerJsonAndInstalledJsonSourceLocatorMaker, + private OptimizedPsrAutoloaderLocatorFactory $optimizedPsrAutoloaderLocatorFactory, + private FileNodesFetcher $fileNodesFetcher, + private array $scanFiles, + private array $scanDirectories, + private array $analysedPaths, + private array $composerAutoloaderProjectPaths, + private array $analysedPathsFromConfig, + ) { - $this->parser = $parser; - $this->php8Parser = $php8Parser; - $this->phpstormStubsSourceStubber = $phpstormStubsSourceStubber; - $this->reflectionSourceStubber = $reflectionSourceStubber; - $this->optimizedSingleFileSourceLocatorRepository = $optimizedSingleFileSourceLocatorRepository; - $this->optimizedDirectorySourceLocatorRepository = $optimizedDirectorySourceLocatorRepository; - $this->composerJsonAndInstalledJsonSourceLocatorMaker = $composerJsonAndInstalledJsonSourceLocatorMaker; - $this->optimizedPsrAutoloaderLocatorFactory = $optimizedPsrAutoloaderLocatorFactory; - $this->fileNodesFetcher = $fileNodesFetcher; - $this->scanFiles = $scanFiles; - $this->scanDirectories = $scanDirectories; - $this->analysedPaths = $analysedPaths; - $this->composerAutoloaderProjectPaths = $composerAutoloaderProjectPaths; - $this->analysedPathsFromConfig = $analysedPathsFromConfig; } + public function create(): SourceLocator { $locators = []; $astLocator = new Locator($this->parser); - $locators[] = new AutoloadFunctionsSourceLocator(new AutoloadSourceLocator($this->fileNodesFetcher, false), new ReflectionClassSourceLocator($astLocator, $this->reflectionSourceStubber)); + $locators[] = new AutoloadFunctionsSourceLocator( + new AutoloadSourceLocator($this->fileNodesFetcher, false), + new ReflectionClassSourceLocator( + $astLocator, + $this->reflectionSourceStubber, + ), + ); $analysedDirectories = []; $analysedFiles = []; @@ -160,10 +112,12 @@ public function create(): SourceLocator if (extension_loaded('phar')) { $pharProtocolPath = Phar::running(); if ($pharProtocolPath !== '') { - $fileLocators[] = $this->optimizedPsrAutoloaderLocatorFactory->create(Psr4Mapping::fromArrayMappings([ + $fileLocators[] = $this->optimizedPsrAutoloaderLocatorFactory->create( + Psr4Mapping::fromArrayMappings([ 'PHPStan\\Testing\\' => [$pharProtocolPath . '/src/Testing/'], 'PHPStan\\BetterReflection\\' => [$pharProtocolPath . '/vendor/ondrejmirtes/better-reflection/src/'], - ])); + ]), + ); } } diff --git a/src/Reflection/BetterReflection/Reflector/MemoizingReflector.php b/src/Reflection/BetterReflection/Reflector/MemoizingReflector.php index b25b44357cb..486ad45c201 100644 --- a/src/Reflection/BetterReflection/Reflector/MemoizingReflector.php +++ b/src/Reflection/BetterReflection/Reflector/MemoizingReflector.php @@ -15,22 +15,17 @@ final class MemoizingReflector implements Reflector { - /** - * @var Reflector - */ - private $reflector; /** @var array */ - private $classReflections = []; + private array $classReflections = []; /** @var array */ - private $constantReflections = []; + private array $constantReflections = []; /** @var array */ - private $functionReflections = []; + private array $functionReflections = []; - public function __construct(Reflector $reflector) + public function __construct(private Reflector $reflector) { - $this->reflector = $reflector; } public function reflectClass(string $className): ReflectionClass diff --git a/src/Reflection/BetterReflection/SourceLocator/AutoloadFunctionsSourceLocator.php b/src/Reflection/BetterReflection/SourceLocator/AutoloadFunctionsSourceLocator.php index 9f000d21a6c..2acb010ad72 100644 --- a/src/Reflection/BetterReflection/SourceLocator/AutoloadFunctionsSourceLocator.php +++ b/src/Reflection/BetterReflection/SourceLocator/AutoloadFunctionsSourceLocator.php @@ -15,19 +15,13 @@ class AutoloadFunctionsSourceLocator implements SourceLocator { - /** - * @var AutoloadSourceLocator - */ - private $autoloadSourceLocator; - /** - * @var ReflectionClassSourceLocator - */ - private $reflectionClassSourceLocator; - public function __construct(AutoloadSourceLocator $autoloadSourceLocator, ReflectionClassSourceLocator $reflectionClassSourceLocator) + public function __construct( + private AutoloadSourceLocator $autoloadSourceLocator, + private ReflectionClassSourceLocator $reflectionClassSourceLocator, + ) { - $this->autoloadSourceLocator = $autoloadSourceLocator; - $this->reflectionClassSourceLocator = $reflectionClassSourceLocator; } + public function locateIdentifier(Reflector $reflector, Identifier $identifier): ?Reflection { if (!$identifier->isClass()) { diff --git a/src/Reflection/BetterReflection/SourceLocator/AutoloadSourceLocator.php b/src/Reflection/BetterReflection/SourceLocator/AutoloadSourceLocator.php index 962205b9c59..969d9783334 100644 --- a/src/Reflection/BetterReflection/SourceLocator/AutoloadSourceLocator.php +++ b/src/Reflection/BetterReflection/SourceLocator/AutoloadSourceLocator.php @@ -50,31 +50,21 @@ class AutoloadSourceLocator implements SourceLocator { - /** - * @var FileNodesFetcher - */ - private $fileNodesFetcher; - /** - * @var bool - */ - private $executeAutoloadersInFileReadTrap; /** @var array{classes: array, functions: array, constants: array} */ - private $presentSymbols = [ + private array $presentSymbols = [ 'classes' => [], 'functions' => [], 'constants' => [], ]; /** @var array */ - private $scannedFiles = []; + private array $scannedFiles = []; /** @var array */ - private $startLineByClass = []; + private array $startLineByClass = []; - public function __construct(FileNodesFetcher $fileNodesFetcher, bool $executeAutoloadersInFileReadTrap) + public function __construct(private FileNodesFetcher $fileNodesFetcher, private bool $executeAutoloadersInFileReadTrap) { - $this->fileNodesFetcher = $fileNodesFetcher; - $this->executeAutoloadersInFileReadTrap = $executeAutoloadersInFileReadTrap; } public function locateIdentifier(Reflector $reflector, Identifier $identifier): ?Reflection @@ -113,7 +103,9 @@ public function locateIdentifier(Reflector $reflector, Identifier $identifier): } $constantValue = @constant($constantName); - return ReflectionConstant::createFromNode($reflector, new FuncCall(new Name('define'), [ + return ReflectionConstant::createFromNode( + $reflector, + new FuncCall(new Name('define'), [ new Arg(new String_($constantName)), new Arg(new TypeExpr(ConstantTypeHelper::getTypeFromValue($constantValue))), ], [ @@ -121,7 +113,11 @@ public function locateIdentifier(Reflector $reflector, Identifier $identifier): 'endLine' => 1, 'startFilePos' => 1, 'endFilePos' => 4, - ]), new LocatedSource('isClass()) { @@ -213,7 +209,12 @@ private function findReflection(Reflector $reflector, string $file, Identifier $ } } - return $nodeToReflection->__invoke($reflector, $classNode->getNode(), $classNode->getLocatedSource(), $classNode->getNamespace()); + return $nodeToReflection->__invoke( + $reflector, + $classNode->getNode(), + $classNode->getLocatedSource(), + $classNode->getNamespace(), + ); } return null; @@ -225,7 +226,12 @@ private function findReflection(Reflector $reflector, string $file, Identifier $ } foreach ($result->getFunctionNodes()[$identifierName] as $functionNode) { - return $nodeToReflection->__invoke($reflector, $functionNode->getNode(), $functionNode->getLocatedSource(), $functionNode->getNamespace()); + return $nodeToReflection->__invoke( + $reflector, + $functionNode->getNode(), + $functionNode->getLocatedSource(), + $functionNode->getNamespace(), + ); } } @@ -259,7 +265,13 @@ private function findReflection(Reflector $reflector, string $file, Identifier $ } } - return $nodeToReflection->__invoke($reflector, $constantNode, $fetchedConstantNode->getLocatedSource(), $fetchedConstantNode->getNamespace(), $positionInNode); + return $nodeToReflection->__invoke( + $reflector, + $constantNode, + $fetchedConstantNode->getLocatedSource(), + $fetchedConstantNode->getNamespace(), + $positionInNode, + ); } } @@ -320,7 +332,8 @@ private function locateClassByName(string $className): ?array $this->silenceErrors(); try { - $result = FileReadTrapStreamWrapper::withStreamWrapperOverride(static function () use ($className): ?array { + $result = FileReadTrapStreamWrapper::withStreamWrapperOverride( + static function () use ($className): ?array { $functions = spl_autoload_functions(); if ($functions === false) { return null; @@ -341,7 +354,8 @@ private function locateClassByName(string $className): ?array } return null; - }); + }, + ); if ($result === null) { return null; } @@ -362,9 +376,7 @@ private function locateClassByName(string $className): ?array private function silenceErrors(): void { - set_error_handler(static function () : bool { - return true; - }); + set_error_handler(static fn (): bool => true); } } diff --git a/src/Reflection/BetterReflection/SourceLocator/CachingVisitor.php b/src/Reflection/BetterReflection/SourceLocator/CachingVisitor.php index fa036c361e5..7e8367df3ca 100644 --- a/src/Reflection/BetterReflection/SourceLocator/CachingVisitor.php +++ b/src/Reflection/BetterReflection/SourceLocator/CachingVisitor.php @@ -15,29 +15,20 @@ class CachingVisitor extends NodeVisitorAbstract { - /** - * @var string - */ - private $fileName; + private string $fileName; - /** - * @var string - */ - private $contents; + private string $contents; /** @var array>> */ - private $classNodes; + private array $classNodes; /** @var array>> */ - private $functionNodes; + private array $functionNodes; /** @var array>> */ - private $constantNodes; + private array $constantNodes; - /** - * @var ?Node\Stmt\Namespace_ - */ - private $currentNamespaceNode = null; + private ?Node\Stmt\Namespace_ $currentNamespaceNode = null; public function enterNode(Node $node): ?int { @@ -53,7 +44,11 @@ public function enterNode(Node $node): ?int if ($this->currentNamespaceNode !== null && $this->currentNamespaceNode->name !== null) { $fullClassName = $this->currentNamespaceNode->name . '\\' . $fullClassName; } - $this->classNodes[strtolower($fullClassName)][] = new FetchedNode($node, $this->currentNamespaceNode, new LocatedSource($this->contents, $fullClassName, $this->fileName)); + $this->classNodes[strtolower($fullClassName)][] = new FetchedNode( + $node, + $this->currentNamespaceNode, + new LocatedSource($this->contents, $fullClassName, $this->fileName), + ); } return NodeTraverser::DONT_TRAVERSE_CHILDREN; @@ -62,7 +57,11 @@ public function enterNode(Node $node): ?int if ($node instanceof Node\Stmt\Function_) { if ($node->namespacedName !== null) { $functionName = $node->namespacedName->toString(); - $this->functionNodes[strtolower($functionName)][] = new FetchedNode($node, $this->currentNamespaceNode, new LocatedSource($this->contents, $functionName, $this->fileName)); + $this->functionNodes[strtolower($functionName)][] = new FetchedNode( + $node, + $this->currentNamespaceNode, + new LocatedSource($this->contents, $functionName, $this->fileName), + ); } return NodeTraverser::DONT_TRAVERSE_CHILDREN; @@ -74,7 +73,11 @@ public function enterNode(Node $node): ?int continue; } - $this->constantNodes[ConstantNameHelper::normalize($const->namespacedName->toString())][] = new FetchedNode($node, $this->currentNamespaceNode, new LocatedSource($this->contents, null, $this->fileName)); + $this->constantNodes[ConstantNameHelper::normalize($const->namespacedName->toString())][] = new FetchedNode( + $node, + $this->currentNamespaceNode, + new LocatedSource($this->contents, null, $this->fileName), + ); } return NodeTraverser::DONT_TRAVERSE_CHILDREN; @@ -83,7 +86,7 @@ public function enterNode(Node $node): ?int if ($node instanceof Node\Expr\FuncCall) { try { ConstantNodeChecker::assertValidDefineFunctionCall($node); - } catch (InvalidConstantNode $e) { + } catch (InvalidConstantNode) { return null; } @@ -91,7 +94,11 @@ public function enterNode(Node $node): ?int $nameNode = $node->getArgs()[0]->value; $constantName = $nameNode->value; - $constantNode = new FetchedNode($node, $this->currentNamespaceNode, new LocatedSource($this->contents, $constantName, $this->fileName)); + $constantNode = new FetchedNode( + $node, + $this->currentNamespaceNode, + new LocatedSource($this->contents, $constantName, $this->fileName), + ); $this->constantNodes[ConstantNameHelper::normalize($constantName)][] = $constantNode; return NodeTraverser::DONT_TRAVERSE_CHILDREN; diff --git a/src/Reflection/BetterReflection/SourceLocator/ComposerJsonAndInstalledJsonSourceLocatorMaker.php b/src/Reflection/BetterReflection/SourceLocator/ComposerJsonAndInstalledJsonSourceLocatorMaker.php index 0d1c88d7cce..ff9068d8354 100644 --- a/src/Reflection/BetterReflection/SourceLocator/ComposerJsonAndInstalledJsonSourceLocatorMaker.php +++ b/src/Reflection/BetterReflection/SourceLocator/ComposerJsonAndInstalledJsonSourceLocatorMaker.php @@ -28,29 +28,15 @@ class ComposerJsonAndInstalledJsonSourceLocatorMaker { - /** - * @var OptimizedDirectorySourceLocatorRepository - */ - private $optimizedDirectorySourceLocatorRepository; - /** - * @var OptimizedPsrAutoloaderLocatorFactory - */ - private $optimizedPsrAutoloaderLocatorFactory; - /** - * @var OptimizedDirectorySourceLocatorFactory - */ - private $optimizedDirectorySourceLocatorFactory; - /** - * @var PhpVersion - */ - private $phpVersion; - public function __construct(OptimizedDirectorySourceLocatorRepository $optimizedDirectorySourceLocatorRepository, OptimizedPsrAutoloaderLocatorFactory $optimizedPsrAutoloaderLocatorFactory, OptimizedDirectorySourceLocatorFactory $optimizedDirectorySourceLocatorFactory, PhpVersion $phpVersion) + public function __construct( + private OptimizedDirectorySourceLocatorRepository $optimizedDirectorySourceLocatorRepository, + private OptimizedPsrAutoloaderLocatorFactory $optimizedPsrAutoloaderLocatorFactory, + private OptimizedDirectorySourceLocatorFactory $optimizedDirectorySourceLocatorFactory, + private PhpVersion $phpVersion, + ) { - $this->optimizedDirectorySourceLocatorRepository = $optimizedDirectorySourceLocatorRepository; - $this->optimizedPsrAutoloaderLocatorFactory = $optimizedPsrAutoloaderLocatorFactory; - $this->optimizedDirectorySourceLocatorFactory = $optimizedDirectorySourceLocatorFactory; - $this->phpVersion = $phpVersion; } + public function create(string $projectInstallationPath): ?SourceLocator { $composer = ComposerHelper::getComposerConfig($projectInstallationPath); @@ -71,28 +57,56 @@ public function create(string $projectInstallationPath): ?SourceLocator try { $installedJsonContents = FileReader::read($installedJsonPath); $installedJson = Json::decode($installedJsonContents, Json::FORCE_ARRAY); - } catch (CouldNotReadFileException | JsonException $e) { + } catch (CouldNotReadFileException | JsonException) { return null; } $installed = $installedJson['packages'] ?? $installedJson; $dev = (bool) ($installedJson['dev'] ?? true); - $classMapPaths = array_merge($this->prefixPaths($this->packageToClassMapPaths($composer), $projectInstallationPath . '/'), $dev ? $this->prefixPaths($this->packageToClassMapPaths($composer, 'autoload-dev'), $projectInstallationPath . '/') : [], ...array_map(function (array $package) use($installedJsonDirectoryPath, $vendorDirectory) : array { - return $this->prefixPaths($this->packageToClassMapPaths($package), $this->packagePrefixPath($installedJsonDirectoryPath, $package, $vendorDirectory)); - }, $installed)); - $filePaths = array_merge($this->prefixPaths($this->packageToFilePaths($composer), $projectInstallationPath . '/'), $dev ? $this->prefixPaths($this->packageToFilePaths($composer, 'autoload-dev'), $projectInstallationPath . '/') : [], ...array_map(function (array $package) use($installedJsonDirectoryPath, $vendorDirectory) : array { - return $this->prefixPaths($this->packageToFilePaths($package), $this->packagePrefixPath($installedJsonDirectoryPath, $package, $vendorDirectory)); - }, $installed)); + $classMapPaths = array_merge( + $this->prefixPaths($this->packageToClassMapPaths($composer), $projectInstallationPath . '/'), + $dev ? $this->prefixPaths($this->packageToClassMapPaths($composer, 'autoload-dev'), $projectInstallationPath . '/') : [], + ...array_map(fn (array $package): array => $this->prefixPaths( + $this->packageToClassMapPaths($package), + $this->packagePrefixPath($installedJsonDirectoryPath, $package, $vendorDirectory), + ), $installed), + ); + $filePaths = array_merge( + $this->prefixPaths($this->packageToFilePaths($composer), $projectInstallationPath . '/'), + $dev ? $this->prefixPaths($this->packageToFilePaths($composer, 'autoload-dev'), $projectInstallationPath . '/') : [], + ...array_map(fn (array $package): array => $this->prefixPaths( + $this->packageToFilePaths($package), + $this->packagePrefixPath($installedJsonDirectoryPath, $package, $vendorDirectory), + ), $installed), + ); $locators = []; - $locators[] = $this->optimizedPsrAutoloaderLocatorFactory->create(Psr4Mapping::fromArrayMappings(array_merge_recursive($this->prefixWithInstallationPath($this->packageToPsr4AutoloadNamespaces($composer), $projectInstallationPath), $dev ? $this->prefixWithInstallationPath($this->packageToPsr4AutoloadNamespaces($composer, 'autoload-dev'), $projectInstallationPath) : [], ...array_map(function (array $package) use($installedJsonDirectoryPath, $vendorDirectory) : array { - return $this->prefixWithPackagePath($this->packageToPsr4AutoloadNamespaces($package), $installedJsonDirectoryPath, $package, $vendorDirectory); - }, $installed)))); + $locators[] = $this->optimizedPsrAutoloaderLocatorFactory->create( + Psr4Mapping::fromArrayMappings(array_merge_recursive( + $this->prefixWithInstallationPath($this->packageToPsr4AutoloadNamespaces($composer), $projectInstallationPath), + $dev ? $this->prefixWithInstallationPath($this->packageToPsr4AutoloadNamespaces($composer, 'autoload-dev'), $projectInstallationPath) : [], + ...array_map(fn (array $package): array => $this->prefixWithPackagePath( + $this->packageToPsr4AutoloadNamespaces($package), + $installedJsonDirectoryPath, + $package, + $vendorDirectory, + ), $installed), + )), + ); - $locators[] = $this->optimizedPsrAutoloaderLocatorFactory->create(Psr0Mapping::fromArrayMappings(array_merge_recursive($this->prefixWithInstallationPath($this->packageToPsr0AutoloadNamespaces($composer), $projectInstallationPath), $dev ? $this->prefixWithInstallationPath($this->packageToPsr0AutoloadNamespaces($composer, 'autoload-dev'), $projectInstallationPath) : [], ...array_map(function (array $package) use($installedJsonDirectoryPath, $vendorDirectory) : array { - return $this->prefixWithPackagePath($this->packageToPsr0AutoloadNamespaces($package), $installedJsonDirectoryPath, $package, $vendorDirectory); - }, $installed)))); + $locators[] = $this->optimizedPsrAutoloaderLocatorFactory->create( + Psr0Mapping::fromArrayMappings(array_merge_recursive( + $this->prefixWithInstallationPath($this->packageToPsr0AutoloadNamespaces($composer), $projectInstallationPath), + $dev ? $this->prefixWithInstallationPath($this->packageToPsr0AutoloadNamespaces($composer, 'autoload-dev'), $projectInstallationPath) : [], + ...array_map(fn (array $package): array => $this->prefixWithPackagePath( + $this->packageToPsr0AutoloadNamespaces($package), + $installedJsonDirectoryPath, + $package, + $vendorDirectory, + ), $installed), + )), + ); $files = []; foreach ($classMapPaths as $classMapPath) { @@ -158,9 +172,7 @@ public function create(string $projectInstallationPath): ?SourceLocator */ private function packageToPsr4AutoloadNamespaces(array $package, string $autoloadSection = 'autoload'): array { - return array_map(static function ($namespacePaths) : array { - return (array) $namespacePaths; - }, $package[$autoloadSection]['psr-4'] ?? []); + return array_map(static fn ($namespacePaths): array => (array) $namespacePaths, $package[$autoloadSection]['psr-4'] ?? []); } /** @@ -170,9 +182,7 @@ private function packageToPsr4AutoloadNamespaces(array $package, string $autoloa */ private function packageToPsr0AutoloadNamespaces(array $package, string $autoloadSection = 'autoload'): array { - return array_map(static function ($namespacePaths) : array { - return (array) $namespacePaths; - }, $package[$autoloadSection]['psr-0'] ?? []); + return array_map(static fn ($namespacePaths): array => (array) $namespacePaths, $package[$autoloadSection]['psr-0'] ?? []); } /** @@ -198,11 +208,16 @@ private function packageToFilePaths(array $package, string $autoloadSection = 'a /** * @param mixed[] $package */ - private function packagePrefixPath(string $installedJsonDirectoryPath, array $package, string $vendorDirectory) : string + private function packagePrefixPath( + string $installedJsonDirectoryPath, + array $package, + string $vendorDirectory, + ): string { if (array_key_exists('install-path', $package)) { return $installedJsonDirectoryPath . '/' . $package['install-path'] . '/'; } + return $vendorDirectory . '/' . $package['name'] . '/'; } @@ -216,9 +231,7 @@ private function prefixWithPackagePath(array $paths, string $installedJsonDirect { $prefix = $this->packagePrefixPath($installedJsonDirectoryPath, $package, $vendorDirectory); - return array_map(function (array $paths) use($prefix) : array { - return $this->prefixPaths($paths, $prefix); - }, $paths); + return array_map(fn (array $paths): array => $this->prefixPaths($paths, $prefix), $paths); } /** @@ -228,9 +241,7 @@ private function prefixWithPackagePath(array $paths, string $installedJsonDirect */ private function prefixWithInstallationPath(array $paths, string $trimmedInstallationPath): array { - return array_map(function (array $paths) use($trimmedInstallationPath) : array { - return $this->prefixPaths($paths, $trimmedInstallationPath . '/'); - }, $paths); + return array_map(fn (array $paths): array => $this->prefixPaths($paths, $trimmedInstallationPath . '/'), $paths); } /** @@ -240,9 +251,7 @@ private function prefixWithInstallationPath(array $paths, string $trimmedInstall */ private function prefixPaths(array $paths, string $prefix): array { - return array_map(static function (string $path) use($prefix) : string { - return $prefix . $path; - }, $paths); + return array_map(static fn (string $path): string => $prefix . $path, $paths); } } diff --git a/src/Reflection/BetterReflection/SourceLocator/FetchedNode.php b/src/Reflection/BetterReflection/SourceLocator/FetchedNode.php index 7807eeaa3d3..89e33adb3db 100644 --- a/src/Reflection/BetterReflection/SourceLocator/FetchedNode.php +++ b/src/Reflection/BetterReflection/SourceLocator/FetchedNode.php @@ -11,27 +11,17 @@ class FetchedNode { - /** - * @var T - */ - private $node; - /** - * @var ?Node\Stmt\Namespace_ - */ - private $namespace; - /** - * @var LocatedSource - */ - private $locatedSource; /** * @param T $node */ - public function __construct(Node $node, ?Node\Stmt\Namespace_ $namespace, LocatedSource $locatedSource) + public function __construct( + private Node $node, + private ?Node\Stmt\Namespace_ $namespace, + private LocatedSource $locatedSource, + ) { - $this->node = $node; - $this->namespace = $namespace; - $this->locatedSource = $locatedSource; } + /** * @return T */ diff --git a/src/Reflection/BetterReflection/SourceLocator/FetchedNodesResult.php b/src/Reflection/BetterReflection/SourceLocator/FetchedNodesResult.php index 584c348dcbd..aa98107ae34 100644 --- a/src/Reflection/BetterReflection/SourceLocator/FetchedNodesResult.php +++ b/src/Reflection/BetterReflection/SourceLocator/FetchedNodesResult.php @@ -7,29 +7,19 @@ class FetchedNodesResult { - /** - * @var array>> - */ - private $classNodes; - /** - * @var array>> - */ - private $functionNodes; - /** - * @var array>> - */ - private $constantNodes; /** * @param array>> $classNodes * @param array>> $functionNodes * @param array>> $constantNodes */ - public function __construct(array $classNodes, array $functionNodes, array $constantNodes) + public function __construct( + private array $classNodes, + private array $functionNodes, + private array $constantNodes, + ) { - $this->classNodes = $classNodes; - $this->functionNodes = $functionNodes; - $this->constantNodes = $constantNodes; } + /** * @return array>> */ diff --git a/src/Reflection/BetterReflection/SourceLocator/FileNodesFetcher.php b/src/Reflection/BetterReflection/SourceLocator/FileNodesFetcher.php index 1c5adbf2921..0fa3440e29b 100644 --- a/src/Reflection/BetterReflection/SourceLocator/FileNodesFetcher.php +++ b/src/Reflection/BetterReflection/SourceLocator/FileNodesFetcher.php @@ -10,19 +10,13 @@ class FileNodesFetcher { - /** - * @var CachingVisitor - */ - private $cachingVisitor; - /** - * @var Parser - */ - private $parser; - public function __construct(CachingVisitor $cachingVisitor, Parser $parser) + public function __construct( + private CachingVisitor $cachingVisitor, + private Parser $parser, + ) { - $this->cachingVisitor = $cachingVisitor; - $this->parser = $parser; } + public function fetchNodes(string $fileName): FetchedNodesResult { $nodeTraverser = new NodeTraverser(); @@ -32,13 +26,17 @@ public function fetchNodes(string $fileName): FetchedNodesResult try { $ast = $this->parser->parseFile($fileName); - } catch (ParserErrorsException $e) { + } catch (ParserErrorsException) { return new FetchedNodesResult([], [], []); } $this->cachingVisitor->reset($fileName, $contents); $nodeTraverser->traverse($ast); - $result = new FetchedNodesResult($this->cachingVisitor->getClassNodes(), $this->cachingVisitor->getFunctionNodes(), $this->cachingVisitor->getConstantNodes()); + $result = new FetchedNodesResult( + $this->cachingVisitor->getClassNodes(), + $this->cachingVisitor->getFunctionNodes(), + $this->cachingVisitor->getConstantNodes(), + ); $this->cachingVisitor->reset($fileName, $contents); diff --git a/src/Reflection/BetterReflection/SourceLocator/FileReadTrapStreamWrapper.php b/src/Reflection/BetterReflection/SourceLocator/FileReadTrapStreamWrapper.php index 13b721a6910..4a35d07ca26 100644 --- a/src/Reflection/BetterReflection/SourceLocator/FileReadTrapStreamWrapper.php +++ b/src/Reflection/BetterReflection/SourceLocator/FileReadTrapStreamWrapper.php @@ -35,20 +35,14 @@ final class FileReadTrapStreamWrapper ]; /** @var string[]|null */ - private static $registeredStreamWrapperProtocols; + private static ?array $registeredStreamWrapperProtocols; /** @var string[] */ - public static $autoloadLocatedFiles = []; + public static array $autoloadLocatedFiles = []; - /** - * @var bool - */ - private $readFromFile = false; + private bool $readFromFile = false; - /** - * @var int - */ - private $seekPosition = 0; + private int $seekPosition = 0; /** * @param string[] $streamWrapperProtocols @@ -59,10 +53,14 @@ final class FileReadTrapStreamWrapper * @psalm-param callable() : ExecutedMethodReturnType $executeMeWithinStreamWrapperOverride * @psalm-return ExecutedMethodReturnType */ - public static function withStreamWrapperOverride(callable $executeMeWithinStreamWrapperOverride, array $streamWrapperProtocols = self::DEFAULT_STREAM_WRAPPER_PROTOCOLS) + public static function withStreamWrapperOverride( + callable $executeMeWithinStreamWrapperOverride, + array $streamWrapperProtocols = self::DEFAULT_STREAM_WRAPPER_PROTOCOLS, + ) { self::$registeredStreamWrapperProtocols = $streamWrapperProtocols; self::$autoloadLocatedFiles = []; + try { foreach ($streamWrapperProtocols as $protocol) { stream_wrapper_unregister($protocol); @@ -75,8 +73,10 @@ public static function withStreamWrapperOverride(callable $executeMeWithinStream stream_wrapper_restore($protocol); } } + self::$registeredStreamWrapperProtocols = null; self::$autoloadLocatedFiles = []; + return $result; } diff --git a/src/Reflection/BetterReflection/SourceLocator/NewOptimizedDirectorySourceLocator.php b/src/Reflection/BetterReflection/SourceLocator/NewOptimizedDirectorySourceLocator.php index 61ebd767903..557ac4848c2 100644 --- a/src/Reflection/BetterReflection/SourceLocator/NewOptimizedDirectorySourceLocator.php +++ b/src/Reflection/BetterReflection/SourceLocator/NewOptimizedDirectorySourceLocator.php @@ -19,34 +19,20 @@ class NewOptimizedDirectorySourceLocator implements SourceLocator { - /** - * @var FileNodesFetcher - */ - private $fileNodesFetcher; - /** - * @var array - */ - private $classToFile; - /** - * @var array> - */ - private $functionToFiles; - /** - * @var array - */ - private $constantToFile; /** * @param array $classToFile * @param array> $functionToFiles * @param array $constantToFile */ - public function __construct(FileNodesFetcher $fileNodesFetcher, array $classToFile, array $functionToFiles, array $constantToFile) + public function __construct( + private FileNodesFetcher $fileNodesFetcher, + private array $classToFile, + private array $functionToFiles, + private array $constantToFile, + ) { - $this->fileNodesFetcher = $fileNodesFetcher; - $this->classToFile = $classToFile; - $this->functionToFiles = $functionToFiles; - $this->constantToFile = $constantToFile; } + public function locateIdentifier(Reflector $reflector, Identifier $identifier): ?Reflection { if ($identifier->isClass()) { @@ -108,7 +94,11 @@ public function locateIdentifier(Reflector $reflector, Identifier $identifier): /** @var FetchedNode $fetchedConstantNode */ $fetchedConstantNode = current($fetchedConstantNodes[$constantName]); - return $this->nodeToReflection($reflector, $fetchedConstantNode, $this->findConstantPositionInConstNode($fetchedConstantNode->getNode(), $constantName)); + return $this->nodeToReflection( + $reflector, + $fetchedConstantNode, + $this->findConstantPositionInConstNode($fetchedConstantNode->getNode(), $constantName), + ); } return null; @@ -120,7 +110,13 @@ public function locateIdentifier(Reflector $reflector, Identifier $identifier): private function nodeToReflection(Reflector $reflector, FetchedNode $fetchedNode, ?int $positionInNode = null): Reflection { $nodeToReflection = new NodeToReflection(); - return $nodeToReflection->__invoke($reflector, $fetchedNode->getNode(), $fetchedNode->getLocatedSource(), $fetchedNode->getNamespace(), $positionInNode); + return $nodeToReflection->__invoke( + $reflector, + $fetchedNode->getNode(), + $fetchedNode->getLocatedSource(), + $fetchedNode->getNamespace(), + $positionInNode, + ); } private function findFileByClass(string $className): ?string @@ -185,7 +181,11 @@ public function locateIdentifiersByType(Reflector $reflector, IdentifierType $id $fetchedNodesResult = $this->fileNodesFetcher->fetchNodes($file); foreach ($fetchedNodesResult->getConstantNodes() as $identifierName => $fetchedConstantNodes) { foreach ($fetchedConstantNodes as $fetchedConstantNode) { - $reflections[$identifierName] = $this->nodeToReflection($reflector, $fetchedConstantNode, $this->findConstantPositionInConstNode($fetchedConstantNode->getNode(), $identifierName)); + $reflections[$identifierName] = $this->nodeToReflection( + $reflector, + $fetchedConstantNode, + $this->findConstantPositionInConstNode($fetchedConstantNode->getNode(), $identifierName), + ); } } } @@ -194,10 +194,7 @@ public function locateIdentifiersByType(Reflector $reflector, IdentifierType $id return array_values($reflections); } - /** - * @param Node\Stmt\Const_|Node\Expr\FuncCall $constantNode - */ - private function findConstantPositionInConstNode($constantNode, string $constantName): ?int + private function findConstantPositionInConstNode(Node\Stmt\Const_|Node\Expr\FuncCall $constantNode, string $constantName): ?int { if ($constantNode instanceof Node\Expr\FuncCall) { return null; diff --git a/src/Reflection/BetterReflection/SourceLocator/OptimizedDirectorySourceLocator.php b/src/Reflection/BetterReflection/SourceLocator/OptimizedDirectorySourceLocator.php index e92def4529c..b6fc6e471cf 100644 --- a/src/Reflection/BetterReflection/SourceLocator/OptimizedDirectorySourceLocator.php +++ b/src/Reflection/BetterReflection/SourceLocator/OptimizedDirectorySourceLocator.php @@ -30,46 +30,30 @@ class OptimizedDirectorySourceLocator implements SourceLocator { - /** - * @var FileNodesFetcher - */ - private $fileNodesFetcher; - /** - * @var PhpVersion - */ - private $phpVersion; - /** - * @var string[] - */ - private $files; - /** - * @var PhpFileCleaner - */ - private $cleaner; + private PhpFileCleaner $cleaner; - /** - * @var string - */ - private $extraTypes; + private string $extraTypes; /** @var array|null */ - private $classToFile = null; + private ?array $classToFile = null; /** @var array|null */ - private $constantToFile = null; + private ?array $constantToFile = null; /** @var array>|null */ - private $functionToFiles = null; + private ?array $functionToFiles = null; /** * @param string[] $files */ - public function __construct(FileNodesFetcher $fileNodesFetcher, PhpVersion $phpVersion, array $files) + public function __construct( + private FileNodesFetcher $fileNodesFetcher, + private PhpVersion $phpVersion, + private array $files, + ) { - $this->fileNodesFetcher = $fileNodesFetcher; - $this->phpVersion = $phpVersion; - $this->files = $files; $this->extraTypes = $this->phpVersion->supportsEnums() ? '|enum' : ''; + $this->cleaner = new PhpFileCleaner(); } @@ -134,7 +118,11 @@ public function locateIdentifier(Reflector $reflector, Identifier $identifier): /** @var FetchedNode $fetchedConstantNode */ $fetchedConstantNode = current($fetchedConstantNodes[$constantName]); - return $this->nodeToReflection($reflector, $fetchedConstantNode, $this->findConstantPositionInConstNode($fetchedConstantNode->getNode(), $constantName)); + return $this->nodeToReflection( + $reflector, + $fetchedConstantNode, + $this->findConstantPositionInConstNode($fetchedConstantNode->getNode(), $constantName), + ); } return null; @@ -146,7 +134,13 @@ public function locateIdentifier(Reflector $reflector, Identifier $identifier): private function nodeToReflection(Reflector $reflector, FetchedNode $fetchedNode, ?int $positionInNode = null): Reflection { $nodeToReflection = new NodeToReflection(); - return $nodeToReflection->__invoke($reflector, $fetchedNode->getNode(), $fetchedNode->getLocatedSource(), $fetchedNode->getNamespace(), $positionInNode); + return $nodeToReflection->__invoke( + $reflector, + $fetchedNode->getNode(), + $fetchedNode->getLocatedSource(), + $fetchedNode->getNamespace(), + $positionInNode, + ); } private function findFileByClass(string $className): ?string @@ -339,7 +333,11 @@ public function locateIdentifiersByType(Reflector $reflector, IdentifierType $id $fetchedNodesResult = $this->fileNodesFetcher->fetchNodes($file); foreach ($fetchedNodesResult->getConstantNodes() as $identifierName => $fetchedConstantNodes) { foreach ($fetchedConstantNodes as $fetchedConstantNode) { - $reflections[$identifierName] = $this->nodeToReflection($reflector, $fetchedConstantNode, $this->findConstantPositionInConstNode($fetchedConstantNode->getNode(), $identifierName)); + $reflections[$identifierName] = $this->nodeToReflection( + $reflector, + $fetchedConstantNode, + $this->findConstantPositionInConstNode($fetchedConstantNode->getNode(), $identifierName), + ); } } } @@ -348,10 +346,7 @@ public function locateIdentifiersByType(Reflector $reflector, IdentifierType $id return array_values($reflections); } - /** - * @param Node\Stmt\Const_|Node\Expr\FuncCall $constantNode - */ - private function findConstantPositionInConstNode($constantNode, string $constantName): ?int + private function findConstantPositionInConstNode(Node\Stmt\Const_|Node\Expr\FuncCall $constantNode, string $constantName): ?int { if ($constantNode instanceof Node\Expr\FuncCall) { return null; diff --git a/src/Reflection/BetterReflection/SourceLocator/OptimizedDirectorySourceLocatorFactory.php b/src/Reflection/BetterReflection/SourceLocator/OptimizedDirectorySourceLocatorFactory.php index fdeaf75b6e2..a147d1872ee 100644 --- a/src/Reflection/BetterReflection/SourceLocator/OptimizedDirectorySourceLocatorFactory.php +++ b/src/Reflection/BetterReflection/SourceLocator/OptimizedDirectorySourceLocatorFactory.php @@ -20,38 +20,17 @@ class OptimizedDirectorySourceLocatorFactory { - /** - * @var FileNodesFetcher - */ - private $fileNodesFetcher; - /** - * @var FileFinder - */ - private $fileFinder; - /** - * @var PhpVersion - */ - private $phpVersion; - /** - * @var Cache - */ - private $cache; - /** - * @var PhpFileCleaner - */ - private $cleaner; + private PhpFileCleaner $cleaner; - /** - * @var string - */ - private $extraTypes; + private string $extraTypes; - public function __construct(FileNodesFetcher $fileNodesFetcher, FileFinder $fileFinder, PhpVersion $phpVersion, Cache $cache) + public function __construct( + private FileNodesFetcher $fileNodesFetcher, + private FileFinder $fileFinder, + private PhpVersion $phpVersion, + private Cache $cache, + ) { - $this->fileNodesFetcher = $fileNodesFetcher; - $this->fileFinder = $fileFinder; - $this->phpVersion = $phpVersion; - $this->cache = $cache; $this->extraTypes = $this->phpVersion->supportsEnums() ? '|enum' : ''; $this->cleaner = new PhpFileCleaner(); } @@ -100,7 +79,12 @@ public function createByDirectory(string $directory): NewOptimizedDirectorySourc [$classToFile, $functionToFiles, $constantToFile] = $this->changeStructure($cached); - return new NewOptimizedDirectorySourceLocator($this->fileNodesFetcher, $classToFile, $functionToFiles, $constantToFile); + return new NewOptimizedDirectorySourceLocator( + $this->fileNodesFetcher, + $classToFile, + $functionToFiles, + $constantToFile, + ); } /** @@ -116,7 +100,12 @@ public function createByFiles(array $files): NewOptimizedDirectorySourceLocator [$classToFile, $functionToFiles, $constantToFile] = $this->changeStructure($symbols); - return new NewOptimizedDirectorySourceLocator($this->fileNodesFetcher, $classToFile, $functionToFiles, $constantToFile); + return new NewOptimizedDirectorySourceLocator( + $this->fileNodesFetcher, + $classToFile, + $functionToFiles, + $constantToFile, + ); } /** diff --git a/src/Reflection/BetterReflection/SourceLocator/OptimizedDirectorySourceLocatorRepository.php b/src/Reflection/BetterReflection/SourceLocator/OptimizedDirectorySourceLocatorRepository.php index e2d1b376687..c636424c2fe 100644 --- a/src/Reflection/BetterReflection/SourceLocator/OptimizedDirectorySourceLocatorRepository.php +++ b/src/Reflection/BetterReflection/SourceLocator/OptimizedDirectorySourceLocatorRepository.php @@ -7,16 +7,11 @@ class OptimizedDirectorySourceLocatorRepository { - /** - * @var OptimizedDirectorySourceLocatorFactory - */ - private $factory; /** @var array */ - private $locators = []; + private array $locators = []; - public function __construct(OptimizedDirectorySourceLocatorFactory $factory) + public function __construct(private OptimizedDirectorySourceLocatorFactory $factory) { - $this->factory = $factory; } public function getOrCreate(string $directory): NewOptimizedDirectorySourceLocator diff --git a/src/Reflection/BetterReflection/SourceLocator/OptimizedPsrAutoloaderLocator.php b/src/Reflection/BetterReflection/SourceLocator/OptimizedPsrAutoloaderLocator.php index 63d5e44f68d..7abfec64dac 100644 --- a/src/Reflection/BetterReflection/SourceLocator/OptimizedPsrAutoloaderLocator.php +++ b/src/Reflection/BetterReflection/SourceLocator/OptimizedPsrAutoloaderLocator.php @@ -13,21 +13,14 @@ class OptimizedPsrAutoloaderLocator implements SourceLocator { - /** - * @var PsrAutoloaderMapping - */ - private $mapping; - /** - * @var OptimizedSingleFileSourceLocatorRepository - */ - private $optimizedSingleFileSourceLocatorRepository; /** @var array */ - private $locators = []; + private array $locators = []; - public function __construct(PsrAutoloaderMapping $mapping, OptimizedSingleFileSourceLocatorRepository $optimizedSingleFileSourceLocatorRepository) + public function __construct( + private PsrAutoloaderMapping $mapping, + private OptimizedSingleFileSourceLocatorRepository $optimizedSingleFileSourceLocatorRepository, + ) { - $this->mapping = $mapping; - $this->optimizedSingleFileSourceLocatorRepository = $optimizedSingleFileSourceLocatorRepository; } public function locateIdentifier(Reflector $reflector, Identifier $identifier): ?Reflection diff --git a/src/Reflection/BetterReflection/SourceLocator/OptimizedSingleFileSourceLocator.php b/src/Reflection/BetterReflection/SourceLocator/OptimizedSingleFileSourceLocator.php index 97cac1d4293..982a372d4a9 100644 --- a/src/Reflection/BetterReflection/SourceLocator/OptimizedSingleFileSourceLocator.php +++ b/src/Reflection/BetterReflection/SourceLocator/OptimizedSingleFileSourceLocator.php @@ -21,21 +21,14 @@ class OptimizedSingleFileSourceLocator implements SourceLocator { - /** - * @var FileNodesFetcher - */ - private $fileNodesFetcher; - /** - * @var string - */ - private $fileName; /** @var array{classes: array, functions: array, constants: array}|null */ - private $presentSymbols = null; + private ?array $presentSymbols = null; - public function __construct(FileNodesFetcher $fileNodesFetcher, string $fileName) + public function __construct( + private FileNodesFetcher $fileNodesFetcher, + private string $fileName, + ) { - $this->fileNodesFetcher = $fileNodesFetcher; - $this->fileName = $fileName; } public function locateIdentifier(Reflector $reflector, Identifier $identifier): ?Reflection @@ -88,7 +81,12 @@ public function locateIdentifier(Reflector $reflector, Identifier $identifier): } foreach ($classNodes[$className] as $classNode) { - $classReflection = $nodeToReflection->__invoke($reflector, $classNode->getNode(), $classNode->getLocatedSource(), $classNode->getNamespace()); + $classReflection = $nodeToReflection->__invoke( + $reflector, + $classNode->getNode(), + $classNode->getLocatedSource(), + $classNode->getNamespace(), + ); if (!$classReflection instanceof ReflectionClass) { throw new ShouldNotHappenException(); } @@ -105,7 +103,12 @@ public function locateIdentifier(Reflector $reflector, Identifier $identifier): } foreach ($functionNodes[$functionName] as $functionNode) { - $functionReflection = $nodeToReflection->__invoke($reflector, $functionNode->getNode(), $functionNode->getLocatedSource(), $functionNode->getNamespace()); + $functionReflection = $nodeToReflection->__invoke( + $reflector, + $functionNode->getNode(), + $functionNode->getLocatedSource(), + $functionNode->getNamespace(), + ); if (!$functionReflection instanceof ReflectionFunction) { throw new ShouldNotHappenException(); } @@ -144,7 +147,13 @@ public function locateIdentifier(Reflector $reflector, Identifier $identifier): } } - $constantReflection = $nodeToReflection->__invoke($reflector, $fetchedConstantNode->getNode(), $fetchedConstantNode->getLocatedSource(), $fetchedConstantNode->getNamespace(), $positionInNode); + $constantReflection = $nodeToReflection->__invoke( + $reflector, + $fetchedConstantNode->getNode(), + $fetchedConstantNode->getLocatedSource(), + $fetchedConstantNode->getNamespace(), + $positionInNode, + ); if (!$constantReflection instanceof ReflectionConstant) { throw new ShouldNotHappenException(); } @@ -168,7 +177,12 @@ public function locateIdentifiersByType(Reflector $reflector, IdentifierType $id foreach ($classNodes as $classNodesArray) { foreach ($classNodesArray as $classNode) { - $classReflection = $nodeToReflection->__invoke($reflector, $classNode->getNode(), $classNode->getLocatedSource(), $classNode->getNamespace()); + $classReflection = $nodeToReflection->__invoke( + $reflector, + $classNode->getNode(), + $classNode->getLocatedSource(), + $classNode->getNamespace(), + ); if (!$classReflection instanceof ReflectionClass) { throw new ShouldNotHappenException(); @@ -184,7 +198,12 @@ public function locateIdentifiersByType(Reflector $reflector, IdentifierType $id foreach ($functionNodes as $functionNodesArray) { foreach ($functionNodesArray as $functionNode) { - $functionReflection = $nodeToReflection->__invoke($reflector, $functionNode->getNode(), $functionNode->getLocatedSource(), $functionNode->getNamespace()); + $functionReflection = $nodeToReflection->__invoke( + $reflector, + $functionNode->getNode(), + $functionNode->getLocatedSource(), + $functionNode->getNamespace(), + ); $reflections[] = $functionReflection; } @@ -203,7 +222,13 @@ public function locateIdentifiersByType(Reflector $reflector, IdentifierType $id throw new ShouldNotHappenException(); } - $constantReflection = $nodeToReflection->__invoke($reflector, $constantNode, $fetchedConstantNode->getLocatedSource(), $fetchedConstantNode->getNamespace(), $constPosition); + $constantReflection = $nodeToReflection->__invoke( + $reflector, + $constantNode, + $fetchedConstantNode->getLocatedSource(), + $fetchedConstantNode->getNamespace(), + $constPosition, + ); if (!$constantReflection instanceof ReflectionConstant) { throw new ShouldNotHappenException(); } @@ -214,7 +239,12 @@ public function locateIdentifiersByType(Reflector $reflector, IdentifierType $id continue; } - $constantReflection = $nodeToReflection->__invoke($reflector, $constantNode, $fetchedConstantNode->getLocatedSource(), $fetchedConstantNode->getNamespace()); + $constantReflection = $nodeToReflection->__invoke( + $reflector, + $constantNode, + $fetchedConstantNode->getLocatedSource(), + $fetchedConstantNode->getNamespace(), + ); if (!$constantReflection instanceof ReflectionConstant) { throw new ShouldNotHappenException(); } diff --git a/src/Reflection/BetterReflection/SourceLocator/OptimizedSingleFileSourceLocatorRepository.php b/src/Reflection/BetterReflection/SourceLocator/OptimizedSingleFileSourceLocatorRepository.php index 551feb76236..59e26df1269 100644 --- a/src/Reflection/BetterReflection/SourceLocator/OptimizedSingleFileSourceLocatorRepository.php +++ b/src/Reflection/BetterReflection/SourceLocator/OptimizedSingleFileSourceLocatorRepository.php @@ -7,16 +7,11 @@ class OptimizedSingleFileSourceLocatorRepository { - /** - * @var OptimizedSingleFileSourceLocatorFactory - */ - private $factory; /** @var array */ - private $locators = []; + private array $locators = []; - public function __construct(OptimizedSingleFileSourceLocatorFactory $factory) + public function __construct(private OptimizedSingleFileSourceLocatorFactory $factory) { - $this->factory = $factory; } public function getOrCreate(string $fileName): OptimizedSingleFileSourceLocator diff --git a/src/Reflection/BetterReflection/SourceLocator/PhpFileCleaner.php b/src/Reflection/BetterReflection/SourceLocator/PhpFileCleaner.php index e98ca7e5f89..d9d45cd3e50 100644 --- a/src/Reflection/BetterReflection/SourceLocator/PhpFileCleaner.php +++ b/src/Reflection/BetterReflection/SourceLocator/PhpFileCleaner.php @@ -18,27 +18,15 @@ class PhpFileCleaner { /** @var array */ - private $typeConfig = []; + private array $typeConfig = []; - /** - * @var string - */ - private $restPattern; + private string $restPattern; - /** - * @var string - */ - private $contents = ''; + private string $contents = ''; - /** - * @var int - */ - private $len = 0; + private int $len = 0; - /** - * @var int - */ - private $index = 0; + private int $index = 0; public function __construct() { diff --git a/src/Reflection/BetterReflection/SourceLocator/PhpVersionBlacklistSourceLocator.php b/src/Reflection/BetterReflection/SourceLocator/PhpVersionBlacklistSourceLocator.php index ce8816f1441..0731d733b0b 100644 --- a/src/Reflection/BetterReflection/SourceLocator/PhpVersionBlacklistSourceLocator.php +++ b/src/Reflection/BetterReflection/SourceLocator/PhpVersionBlacklistSourceLocator.php @@ -12,19 +12,13 @@ class PhpVersionBlacklistSourceLocator implements SourceLocator { - /** - * @var SourceLocator - */ - private $sourceLocator; - /** - * @var PhpStormStubsSourceStubber - */ - private $phpStormStubsSourceStubber; - public function __construct(SourceLocator $sourceLocator, PhpStormStubsSourceStubber $phpStormStubsSourceStubber) + public function __construct( + private SourceLocator $sourceLocator, + private PhpStormStubsSourceStubber $phpStormStubsSourceStubber, + ) { - $this->sourceLocator = $sourceLocator; - $this->phpStormStubsSourceStubber = $phpStormStubsSourceStubber; } + public function locateIdentifier(Reflector $reflector, Identifier $identifier): ?Reflection { if ($identifier->isClass()) { diff --git a/src/Reflection/BetterReflection/SourceLocator/ReflectionClassSourceLocator.php b/src/Reflection/BetterReflection/SourceLocator/ReflectionClassSourceLocator.php index 072b6e36d5e..1e204254516 100644 --- a/src/Reflection/BetterReflection/SourceLocator/ReflectionClassSourceLocator.php +++ b/src/Reflection/BetterReflection/SourceLocator/ReflectionClassSourceLocator.php @@ -15,19 +15,13 @@ class ReflectionClassSourceLocator implements SourceLocator { - /** - * @var Locator - */ - private $astLocator; - /** - * @var ReflectionSourceStubber - */ - private $reflectionSourceStubber; - public function __construct(Locator $astLocator, ReflectionSourceStubber $reflectionSourceStubber) + public function __construct( + private Locator $astLocator, + private ReflectionSourceStubber $reflectionSourceStubber, + ) { - $this->astLocator = $astLocator; - $this->reflectionSourceStubber = $reflectionSourceStubber; } + public function locateIdentifier(Reflector $reflector, Identifier $identifier): ?Reflection { if (!$identifier->isClass()) { @@ -44,7 +38,11 @@ public function locateIdentifier(Reflector $reflector, Identifier $identifier): $reflection = new ReflectionClass($className); - return $this->astLocator->findReflection($reflector, new LocatedSource($stub->getStub(), $reflection->getName(), null), new Identifier($reflection->getName(), new IdentifierType(IdentifierType::IDENTIFIER_CLASS))); + return $this->astLocator->findReflection( + $reflector, + new LocatedSource($stub->getStub(), $reflection->getName(), null), + new Identifier($reflection->getName(), new IdentifierType(IdentifierType::IDENTIFIER_CLASS)), + ); } public function locateIdentifiersByType(Reflector $reflector, IdentifierType $identifierType): array diff --git a/src/Reflection/BetterReflection/SourceLocator/RewriteClassAliasSourceLocator.php b/src/Reflection/BetterReflection/SourceLocator/RewriteClassAliasSourceLocator.php index 7b459bfbbb1..3993684ddde 100644 --- a/src/Reflection/BetterReflection/SourceLocator/RewriteClassAliasSourceLocator.php +++ b/src/Reflection/BetterReflection/SourceLocator/RewriteClassAliasSourceLocator.php @@ -15,13 +15,8 @@ class RewriteClassAliasSourceLocator implements SourceLocator { - /** - * @var SourceLocator - */ - private $originalSourceLocator; - public function __construct(SourceLocator $originalSourceLocator) + public function __construct(private SourceLocator $originalSourceLocator) { - $this->originalSourceLocator = $originalSourceLocator; } public function locateIdentifier(Reflector $reflector, Identifier $identifier): ?Reflection diff --git a/src/Reflection/BetterReflection/SourceLocator/SkipClassAliasSourceLocator.php b/src/Reflection/BetterReflection/SourceLocator/SkipClassAliasSourceLocator.php index 2705b941052..fc8e931ffe1 100644 --- a/src/Reflection/BetterReflection/SourceLocator/SkipClassAliasSourceLocator.php +++ b/src/Reflection/BetterReflection/SourceLocator/SkipClassAliasSourceLocator.php @@ -13,13 +13,8 @@ class SkipClassAliasSourceLocator implements SourceLocator { - /** - * @var SourceLocator - */ - private $sourceLocator; - public function __construct(SourceLocator $sourceLocator) + public function __construct(private SourceLocator $sourceLocator) { - $this->sourceLocator = $sourceLocator; } public function locateIdentifier(Reflector $reflector, Identifier $identifier): ?Reflection diff --git a/src/Reflection/BetterReflection/SourceStubber/PhpStormStubsSourceStubberFactory.php b/src/Reflection/BetterReflection/SourceStubber/PhpStormStubsSourceStubberFactory.php index ee2260244ac..3d5615b24f8 100644 --- a/src/Reflection/BetterReflection/SourceStubber/PhpStormStubsSourceStubberFactory.php +++ b/src/Reflection/BetterReflection/SourceStubber/PhpStormStubsSourceStubberFactory.php @@ -10,23 +10,8 @@ class PhpStormStubsSourceStubberFactory { - /** - * @var Parser - */ - private $phpParser; - /** - * @var Printer - */ - private $printer; - /** - * @var PhpVersion - */ - private $phpVersion; - public function __construct(Parser $phpParser, Printer $printer, PhpVersion $phpVersion) + public function __construct(private Parser $phpParser, private Printer $printer, private PhpVersion $phpVersion) { - $this->phpParser = $phpParser; - $this->printer = $printer; - $this->phpVersion = $phpVersion; } public function create(): PhpStormStubsSourceStubber diff --git a/src/Reflection/ClassConstantReflection.php b/src/Reflection/ClassConstantReflection.php index cc9657115fc..fd69ce81297 100644 --- a/src/Reflection/ClassConstantReflection.php +++ b/src/Reflection/ClassConstantReflection.php @@ -14,53 +14,19 @@ class ClassConstantReflection implements ConstantReflection { - /** - * @var InitializerExprTypeResolver - */ - private $initializerExprTypeResolver; - /** - * @var ClassReflection - */ - private $declaringClass; - /** - * @var ReflectionClassConstant - */ - private $reflection; - /** - * @var ?Type - */ - private $nativeType; - /** - * @var ?Type - */ - private $phpDocType; - /** - * @var ?string - */ - private $deprecatedDescription; - /** - * @var bool - */ - private $isDeprecated; - /** - * @var bool - */ - private $isInternal; - /** - * @var ?Type - */ - private $valueType = null; + private ?Type $valueType = null; - public function __construct(InitializerExprTypeResolver $initializerExprTypeResolver, ClassReflection $declaringClass, ReflectionClassConstant $reflection, ?Type $nativeType, ?Type $phpDocType, ?string $deprecatedDescription, bool $isDeprecated, bool $isInternal) + public function __construct( + private InitializerExprTypeResolver $initializerExprTypeResolver, + private ClassReflection $declaringClass, + private ReflectionClassConstant $reflection, + private ?Type $nativeType, + private ?Type $phpDocType, + private ?string $deprecatedDescription, + private bool $isDeprecated, + private bool $isInternal, + ) { - $this->initializerExprTypeResolver = $initializerExprTypeResolver; - $this->declaringClass = $declaringClass; - $this->reflection = $reflection; - $this->nativeType = $nativeType; - $this->phpDocType = $phpDocType; - $this->deprecatedDescription = $deprecatedDescription; - $this->isDeprecated = $isDeprecated; - $this->isInternal = $isInternal; } public function getName(): string @@ -81,7 +47,7 @@ public function getValue() { try { return $this->reflection->getValue(); - } catch (UnableToCompileNode $e) { + } catch (UnableToCompileNode) { return NAN; } } @@ -116,7 +82,10 @@ public function getValueType(): Type if ($this->valueType === null) { if ($this->phpDocType !== null) { if ($this->nativeType !== null) { - return $this->valueType = TypehintHelper::decideType($this->nativeType, $this->phpDocType); + return $this->valueType = TypehintHelper::decideType( + $this->nativeType, + $this->phpDocType, + ); } return $this->phpDocType; diff --git a/src/Reflection/ClassReflection.php b/src/Reflection/ClassReflection.php index c55597a95bc..4921f4a1530 100644 --- a/src/Reflection/ClassReflection.php +++ b/src/Reflection/ClassReflection.php @@ -73,228 +73,97 @@ class ClassReflection { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - /** - * @var InitializerExprTypeResolver - */ - private $initializerExprTypeResolver; - /** - * @var FileTypeMapper - */ - private $fileTypeMapper; - /** - * @var StubPhpDocProvider - */ - private $stubPhpDocProvider; - /** - * @var PhpDocInheritanceResolver - */ - private $phpDocInheritanceResolver; - /** - * @var PhpVersion - */ - private $phpVersion; - /** - * @var SignatureMapProvider - */ - private $signatureMapProvider; - /** - * @var PropertiesClassReflectionExtension[] - */ - private $propertiesClassReflectionExtensions; - /** - * @var MethodsClassReflectionExtension[] - */ - private $methodsClassReflectionExtensions; - /** - * @var AllowedSubTypesClassReflectionExtension[] - */ - private $allowedSubTypesClassReflectionExtensions; - /** - * @var RequireExtendsPropertiesClassReflectionExtension - */ - private $requireExtendsPropertiesClassReflectionExtension; - /** - * @var RequireExtendsMethodsClassReflectionExtension - */ - private $requireExtendsMethodsClassReflectionExtension; - /** - * @var string - */ - private $displayName; - /** - * @var ReflectionClass|ReflectionEnum - */ - private $reflection; - /** - * @var ?string - */ - private $anonymousFilename; - /** - * @var ?TemplateTypeMap - */ - private $resolvedTemplateTypeMap; - /** - * @var ?ResolvedPhpDocBlock - */ - private $stubPhpDocBlock; - /** - * @var string[] - */ - private $universalObjectCratesClasses; - /** - * @var ?string - */ - private $extraCacheKey; - /** - * @var ?TemplateTypeVarianceMap - */ - private $resolvedCallSiteVarianceMap; /** @var ExtendedMethodReflection[] */ - private $methods = []; + private array $methods = []; /** @var PropertyReflection[] */ - private $properties = []; + private array $properties = []; /** @var ClassConstantReflection[] */ - private $constants = []; + private array $constants = []; /** @var int[]|null */ - private $classHierarchyDistances = null; + private ?array $classHierarchyDistances = null; - /** - * @var ?string - */ - private $deprecatedDescription = null; + private ?string $deprecatedDescription = null; - /** - * @var ?bool - */ - private $isDeprecated = null; + private ?bool $isDeprecated = null; - /** - * @var ?bool - */ - private $isGeneric = null; + private ?bool $isGeneric = null; - /** - * @var ?bool - */ - private $isInternal = null; + private ?bool $isInternal = null; - /** - * @var ?bool - */ - private $isFinal = null; + private ?bool $isFinal = null; - /** - * @var ?bool - */ - private $isImmutable = null; + private ?bool $isImmutable = null; - /** - * @var ?bool - */ - private $hasConsistentConstructor = null; + private ?bool $hasConsistentConstructor = null; - /** - * @var ?TemplateTypeMap - */ - private $templateTypeMap = null; + private ?TemplateTypeMap $templateTypeMap = null; - /** - * @var ?TemplateTypeMap - */ - private $activeTemplateTypeMap = null; + private ?TemplateTypeMap $activeTemplateTypeMap = null; - /** - * @var ?TemplateTypeVarianceMap - */ - private $defaultCallSiteVarianceMap = null; + private ?TemplateTypeVarianceMap $defaultCallSiteVarianceMap = null; - /** - * @var ?TemplateTypeVarianceMap - */ - private $callSiteVarianceMap = null; + private ?TemplateTypeVarianceMap $callSiteVarianceMap = null; /** @var array|null */ - private $ancestors = null; + private ?array $ancestors = null; - /** - * @var ?string - */ - private $cacheKey = null; + private ?string $cacheKey = null; /** @var array */ - private $subclasses = []; + private array $subclasses = []; - /** - * @var string|false|null - */ - private $filename = false; + private string|false|null $filename = false; - /** - * @var string|false|null - */ - private $reflectionDocComment = false; + private string|false|null $reflectionDocComment = false; - /** - * @var false|ResolvedPhpDocBlock - */ - private $resolvedPhpDocBlock = false; + private false|ResolvedPhpDocBlock $resolvedPhpDocBlock = false; /** @var ClassReflection[]|null */ - private $cachedInterfaces = null; + private ?array $cachedInterfaces = null; - /** - * @var ClassReflection|false|null - */ - private $cachedParentClass = false; + private ClassReflection|false|null $cachedParentClass = false; /** @var array|null */ - private $typeAliases = null; + private ?array $typeAliases = null; /** @var array */ - private static $resolvingTypeAliasImports = []; + private static array $resolvingTypeAliasImports = []; /** * @param PropertiesClassReflectionExtension[] $propertiesClassReflectionExtensions * @param MethodsClassReflectionExtension[] $methodsClassReflectionExtensions * @param AllowedSubTypesClassReflectionExtension[] $allowedSubTypesClassReflectionExtensions * @param string[] $universalObjectCratesClasses - * @param ReflectionClass|ReflectionEnum $reflection */ - public function __construct(ReflectionProvider $reflectionProvider, InitializerExprTypeResolver $initializerExprTypeResolver, FileTypeMapper $fileTypeMapper, StubPhpDocProvider $stubPhpDocProvider, PhpDocInheritanceResolver $phpDocInheritanceResolver, PhpVersion $phpVersion, SignatureMapProvider $signatureMapProvider, array $propertiesClassReflectionExtensions, array $methodsClassReflectionExtensions, array $allowedSubTypesClassReflectionExtensions, RequireExtendsPropertiesClassReflectionExtension $requireExtendsPropertiesClassReflectionExtension, RequireExtendsMethodsClassReflectionExtension $requireExtendsMethodsClassReflectionExtension, string $displayName, $reflection, ?string $anonymousFilename, ?TemplateTypeMap $resolvedTemplateTypeMap, ?ResolvedPhpDocBlock $stubPhpDocBlock, array $universalObjectCratesClasses, ?string $extraCacheKey = null, ?TemplateTypeVarianceMap $resolvedCallSiteVarianceMap = null) - { - $this->reflectionProvider = $reflectionProvider; - $this->initializerExprTypeResolver = $initializerExprTypeResolver; - $this->fileTypeMapper = $fileTypeMapper; - $this->stubPhpDocProvider = $stubPhpDocProvider; - $this->phpDocInheritanceResolver = $phpDocInheritanceResolver; - $this->phpVersion = $phpVersion; - $this->signatureMapProvider = $signatureMapProvider; - $this->propertiesClassReflectionExtensions = $propertiesClassReflectionExtensions; - $this->methodsClassReflectionExtensions = $methodsClassReflectionExtensions; - $this->allowedSubTypesClassReflectionExtensions = $allowedSubTypesClassReflectionExtensions; - $this->requireExtendsPropertiesClassReflectionExtension = $requireExtendsPropertiesClassReflectionExtension; - $this->requireExtendsMethodsClassReflectionExtension = $requireExtendsMethodsClassReflectionExtension; - $this->displayName = $displayName; - $this->reflection = $reflection; - $this->anonymousFilename = $anonymousFilename; - $this->resolvedTemplateTypeMap = $resolvedTemplateTypeMap; - $this->stubPhpDocBlock = $stubPhpDocBlock; - $this->universalObjectCratesClasses = $universalObjectCratesClasses; - $this->extraCacheKey = $extraCacheKey; - $this->resolvedCallSiteVarianceMap = $resolvedCallSiteVarianceMap; - } - - /** - * @return ReflectionClass|ReflectionEnum - */ - public function getNativeReflection() + public function __construct( + private ReflectionProvider $reflectionProvider, + private InitializerExprTypeResolver $initializerExprTypeResolver, + private FileTypeMapper $fileTypeMapper, + private StubPhpDocProvider $stubPhpDocProvider, + private PhpDocInheritanceResolver $phpDocInheritanceResolver, + private PhpVersion $phpVersion, + private SignatureMapProvider $signatureMapProvider, + private array $propertiesClassReflectionExtensions, + private array $methodsClassReflectionExtensions, + private array $allowedSubTypesClassReflectionExtensions, + private RequireExtendsPropertiesClassReflectionExtension $requireExtendsPropertiesClassReflectionExtension, + private RequireExtendsMethodsClassReflectionExtension $requireExtendsMethodsClassReflectionExtension, + private string $displayName, + private ReflectionClass|ReflectionEnum $reflection, + private ?string $anonymousFilename, + private ?TemplateTypeMap $resolvedTemplateTypeMap, + private ?ResolvedPhpDocBlock $stubPhpDocBlock, + private array $universalObjectCratesClasses, + private ?string $extraCacheKey = null, + private ?TemplateTypeVarianceMap $resolvedCallSiteVarianceMap = null, + ) + { + } + + public function getNativeReflection(): ReflectionClass|ReflectionEnum { return $this->reflection; } @@ -346,7 +215,12 @@ public function getParentClass(): ?ClassReflection $extendedType = $extendsTag->getType(); if ($this->isGeneric()) { - $extendedType = TemplateTypeHelper::resolveTemplateTypes($extendedType, $this->getPossiblyIncompleteActiveTemplateTypeMap(), $this->getCallSiteVarianceMap(), TemplateTypeVariance::createStatic()); + $extendedType = TemplateTypeHelper::resolveTemplateTypes( + $extendedType, + $this->getPossiblyIncompleteActiveTemplateTypeMap(), + $this->getCallSiteVarianceMap(), + TemplateTypeVariance::createStatic(), + ); } if (!$extendedType instanceof GenericObjectType) { @@ -358,9 +232,9 @@ public function getParentClass(): ?ClassReflection $parentReflection = $this->reflectionProvider->getClass($parentClass->getName()); if ($parentReflection->isGeneric()) { - return $parentReflection->withTypes(array_values($parentReflection->getTemplateTypeMap()->map(static function () : Type { - return new ErrorType(); - })->getTypes())); + return $parentReflection->withTypes( + array_values($parentReflection->getTemplateTypeMap()->map(static fn (): Type => new ErrorType())->getTypes()), + ); } $this->cachedParentClass = $parentReflection; @@ -486,9 +360,8 @@ public function getClassHierarchyDistances(): array /** * @return ReflectionClass[] - * @param ReflectionClass|ReflectionEnum $class */ - private function collectTraits($class): array + private function collectTraits(ReflectionClass|ReflectionEnum $class): array { $traits = []; $traitsLeftToAnalyze = $class->getTraits(); @@ -525,7 +398,11 @@ public function allowsDynamicProperties(): bool return false; } - if (UniversalObjectCratesClassReflectionExtension::isUniversalObjectCrate($this->reflectionProvider, $this->universalObjectCratesClasses, $this)) { + if (UniversalObjectCratesClassReflectionExtension::isUniversalObjectCrate( + $this->reflectionProvider, + $this->universalObjectCratesClasses, + $this, + )) { return true; } @@ -935,7 +812,7 @@ public function isSubclassOf(string $className): bool try { return $this->subclasses[$className] = $this->reflection->isSubclassOf($className); - } catch (ReflectionException $e) { + } catch (ReflectionException) { return $this->subclasses[$className] = false; } } @@ -944,7 +821,7 @@ public function implementsInterface(string $className): bool { try { return $this->reflection->implementsInterface($className); - } catch (ReflectionException $e) { + } catch (ReflectionException) { return false; } } @@ -1053,7 +930,13 @@ public function getImmediateInterfaces(): array $implementsTag = $implementsTags[$immediateInterface->getName()]; $implementedType = $implementsTag->getType(); if ($this->isGeneric()) { - $implementedType = TemplateTypeHelper::resolveTemplateTypes($implementedType, $this->getPossiblyIncompleteActiveTemplateTypeMap(), $this->getCallSiteVarianceMap(), TemplateTypeVariance::createStatic(), true); + $implementedType = TemplateTypeHelper::resolveTemplateTypes( + $implementedType, + $this->getPossiblyIncompleteActiveTemplateTypeMap(), + $this->getCallSiteVarianceMap(), + TemplateTypeVariance::createStatic(), + true, + ); } if ( @@ -1066,9 +949,9 @@ public function getImmediateInterfaces(): array } if ($immediateInterface->isGeneric()) { - $immediateInterfaces[$immediateInterface->getName()] = $immediateInterface->withTypes(array_values($immediateInterface->getTemplateTypeMap()->map(static function () : Type { - return new ErrorType(); - })->getTypes())); + $immediateInterfaces[$immediateInterface->getName()] = $immediateInterface->withTypes( + array_values($immediateInterface->getTemplateTypeMap()->map(static fn (): Type => new ErrorType())->getTypes()), + ); continue; } @@ -1093,15 +976,16 @@ public function getTraits(bool $recursive = false): array $traits = $this->getNativeReflection()->getTraits(); } - $traits = array_map(function (ReflectionClass $trait) : ClassReflection { - return $this->reflectionProvider->getClass($trait->getName()); - }, $traits); + $traits = array_map(fn (ReflectionClass $trait): ClassReflection => $this->reflectionProvider->getClass($trait->getName()), $traits); if ($recursive) { $parentClass = $this->getNativeReflection()->getParentClass(); if ($parentClass !== false) { - return array_merge($traits, $this->reflectionProvider->getClass($parentClass->getName())->getTraits(true)); + return array_merge( + $traits, + $this->reflectionProvider->getClass($parentClass->getName())->getTraits(true), + ); } } @@ -1148,13 +1032,21 @@ public function getConstant(string $name): ClassConstantReflection $declaringClass = $this->reflectionProvider->getClass($reflectionConstant->getDeclaringClass()->getName()); $fileName = $declaringClass->getFileName(); $phpDocType = null; - $resolvedPhpDoc = $this->stubPhpDocProvider->findClassConstantPhpDoc($declaringClass->getName(), $name); + $resolvedPhpDoc = $this->stubPhpDocProvider->findClassConstantPhpDoc( + $declaringClass->getName(), + $name, + ); if ($resolvedPhpDoc === null) { $docComment = null; if ($reflectionConstant->getDocComment() !== false) { $docComment = $reflectionConstant->getDocComment(); } - $resolvedPhpDoc = $this->phpDocInheritanceResolver->resolvePhpDocForConstant($docComment, $declaringClass, $fileName, $name); + $resolvedPhpDoc = $this->phpDocInheritanceResolver->resolvePhpDocForConstant( + $docComment, + $declaringClass, + $fileName, + $name, + ); } $deprecatedDescription = $resolvedPhpDoc->getDeprecatedTag() !== null ? $resolvedPhpDoc->getDeprecatedTag()->getMessage() : null; @@ -1172,7 +1064,16 @@ public function getConstant(string $name): ClassConstantReflection $nativeType = $this->signatureMapProvider->getClassConstantMetadata($declaringClass->getName(), $name)['nativeType']; } - $this->constants[$name] = new ClassConstantReflection($this->initializerExprTypeResolver, $declaringClass, $reflectionConstant, $nativeType, $phpDocType, $deprecatedDescription, $isDeprecated, $isInternal); + $this->constants[$name] = new ClassConstantReflection( + $this->initializerExprTypeResolver, + $declaringClass, + $reflectionConstant, + $nativeType, + $phpDocType, + $deprecatedDescription, + $isDeprecated, + $isInternal, + ); } return $this->constants[$name]; } @@ -1188,9 +1089,7 @@ public function hasTraitUse(string $traitName): bool private function getTraitNames(): array { $class = $this->reflection; - $traitNames = array_map(static function (ReflectionClass $class) { - return $class->getName(); - }, $this->collectTraits($class)); + $traitNames = array_map(static fn (ReflectionClass $class) => $class->getName(), $this->collectTraits($class)); while ($class->getParentClass() !== false) { $traitNames = array_values(array_unique(array_merge($traitNames, $class->getParentClass()->getTraitNames()))); $class = $class->getParentClass(); @@ -1232,7 +1131,7 @@ public function getTypeAliases(): array try { $typeAliases = $importedFromReflection->getTypeAliases(); - } catch (CircularTypeAliasDefinitionException $e) { + } catch (CircularTypeAliasDefinitionException) { return TypeAlias::invalid(); } @@ -1245,13 +1144,12 @@ public function getTypeAliases(): array unset(self::$resolvingTypeAliasImports[$this->getName()]); - $localAliases = array_map(static function (TypeAliasTag $typeAliasTag) : TypeAlias { - return $typeAliasTag->getTypeAlias(); - }, $typeAliasTags); + $localAliases = array_map(static fn (TypeAliasTag $typeAliasTag): TypeAlias => $typeAliasTag->getTypeAlias(), $typeAliasTags); - $this->typeAliases = array_filter(array_merge($importedAliases, $localAliases), static function (?TypeAlias $typeAlias) : bool { - return $typeAlias !== null; - }); + $this->typeAliases = array_filter( + array_merge($importedAliases, $localAliases), + static fn (?TypeAlias $typeAlias): bool => $typeAlias !== null, + ); } return $this->typeAliases; @@ -1374,7 +1272,10 @@ private function findAttributeFlags(): ?int if (count($arguments) === 0) { $flagType = $attributeConstructorVariant->getParameters()[0]->getDefaultValue(); } else { - $staticCall = ArgumentsNormalizer::reorderStaticCallArguments($attributeConstructorVariant, new StaticCall(new FullyQualified(Attribute::class), $attributeConstructor->getName(), $arguments)); + $staticCall = ArgumentsNormalizer::reorderStaticCallArguments( + $attributeConstructorVariant, + new StaticCall(new FullyQualified(Attribute::class), $attributeConstructor->getName(), $arguments), + ); if ($staticCall === null) { return null; } @@ -1416,9 +1317,7 @@ public function getTemplateTypeMap(): TemplateTypeMap $templateTypeScope = TemplateTypeScope::createWithClass($this->getName()); - $templateTypeMap = new TemplateTypeMap(array_map(static function (TemplateTag $tag) use($templateTypeScope) : Type { - return TemplateTypeFactory::fromTemplateTag($templateTypeScope, $tag); - }, $this->getTemplateTags())); + $templateTypeMap = new TemplateTypeMap(array_map(static fn (TemplateTag $tag): Type => TemplateTypeFactory::fromTemplateTag($templateTypeScope, $tag), $this->getTemplateTags())); $this->templateTypeMap = $templateTypeMap; @@ -1476,7 +1375,7 @@ private function getDefaultCallSiteVarianceMap(): TemplateTypeVarianceMap public function getCallSiteVarianceMap(): TemplateTypeVarianceMap { - return $this->callSiteVarianceMap = $this->callSiteVarianceMap ?? $this->resolvedCallSiteVarianceMap ?? $this->getDefaultCallSiteVarianceMap(); + return $this->callSiteVarianceMap ??= $this->resolvedCallSiteVarianceMap ?? $this->getDefaultCallSiteVarianceMap(); } public function isGeneric(): bool @@ -1569,7 +1468,28 @@ public function varianceMapToList(TemplateTypeVarianceMap $varianceMap): array */ public function withTypes(array $types): self { - return new self($this->reflectionProvider, $this->initializerExprTypeResolver, $this->fileTypeMapper, $this->stubPhpDocProvider, $this->phpDocInheritanceResolver, $this->phpVersion, $this->signatureMapProvider, $this->propertiesClassReflectionExtensions, $this->methodsClassReflectionExtensions, $this->allowedSubTypesClassReflectionExtensions, $this->requireExtendsPropertiesClassReflectionExtension, $this->requireExtendsMethodsClassReflectionExtension, $this->displayName, $this->reflection, $this->anonymousFilename, $this->typeMapFromList($types), $this->stubPhpDocBlock, $this->universalObjectCratesClasses, null, $this->resolvedCallSiteVarianceMap); + return new self( + $this->reflectionProvider, + $this->initializerExprTypeResolver, + $this->fileTypeMapper, + $this->stubPhpDocProvider, + $this->phpDocInheritanceResolver, + $this->phpVersion, + $this->signatureMapProvider, + $this->propertiesClassReflectionExtensions, + $this->methodsClassReflectionExtensions, + $this->allowedSubTypesClassReflectionExtensions, + $this->requireExtendsPropertiesClassReflectionExtension, + $this->requireExtendsMethodsClassReflectionExtension, + $this->displayName, + $this->reflection, + $this->anonymousFilename, + $this->typeMapFromList($types), + $this->stubPhpDocBlock, + $this->universalObjectCratesClasses, + null, + $this->resolvedCallSiteVarianceMap, + ); } /** @@ -1577,7 +1497,28 @@ public function withTypes(array $types): self */ public function withVariances(array $variances): self { - return new self($this->reflectionProvider, $this->initializerExprTypeResolver, $this->fileTypeMapper, $this->stubPhpDocProvider, $this->phpDocInheritanceResolver, $this->phpVersion, $this->signatureMapProvider, $this->propertiesClassReflectionExtensions, $this->methodsClassReflectionExtensions, $this->allowedSubTypesClassReflectionExtensions, $this->requireExtendsPropertiesClassReflectionExtension, $this->requireExtendsMethodsClassReflectionExtension, $this->displayName, $this->reflection, $this->anonymousFilename, $this->resolvedTemplateTypeMap, $this->stubPhpDocBlock, $this->universalObjectCratesClasses, null, $this->varianceMapFromList($variances)); + return new self( + $this->reflectionProvider, + $this->initializerExprTypeResolver, + $this->fileTypeMapper, + $this->stubPhpDocProvider, + $this->phpDocInheritanceResolver, + $this->phpVersion, + $this->signatureMapProvider, + $this->propertiesClassReflectionExtensions, + $this->methodsClassReflectionExtensions, + $this->allowedSubTypesClassReflectionExtensions, + $this->requireExtendsPropertiesClassReflectionExtension, + $this->requireExtendsMethodsClassReflectionExtension, + $this->displayName, + $this->reflection, + $this->anonymousFilename, + $this->resolvedTemplateTypeMap, + $this->stubPhpDocBlock, + $this->universalObjectCratesClasses, + null, + $this->varianceMapFromList($variances), + ); } public function getResolvedPhpDoc(): ?ResolvedPhpDocBlock @@ -1792,7 +1733,12 @@ public function getResolvedMixinTypes(): array continue; } - $types[] = TemplateTypeHelper::resolveTemplateTypes($mixinTag->getType(), $this->getActiveTemplateTypeMap(), $this->getCallSiteVarianceMap(), TemplateTypeVariance::createStatic()); + $types[] = TemplateTypeHelper::resolveTemplateTypes( + $mixinTag->getType(), + $this->getActiveTemplateTypeMap(), + $this->getCallSiteVarianceMap(), + TemplateTypeVariance::createStatic(), + ); } return $types; diff --git a/src/Reflection/ClassReflectionExtensionRegistry.php b/src/Reflection/ClassReflectionExtensionRegistry.php index 6e6ad3f5cef..6ba9c4d28aa 100644 --- a/src/Reflection/ClassReflectionExtensionRegistry.php +++ b/src/Reflection/ClassReflectionExtensionRegistry.php @@ -11,65 +11,48 @@ class ClassReflectionExtensionRegistry { /** - * @var PropertiesClassReflectionExtension[] - */ - private $propertiesClassReflectionExtensions; - /** - * @var MethodsClassReflectionExtension[] - */ - private $methodsClassReflectionExtensions; - /** - * @var AllowedSubTypesClassReflectionExtension[] - */ - private $allowedSubTypesClassReflectionExtensions; - /** - * @var RequireExtendsPropertiesClassReflectionExtension - */ - private $requireExtendsPropertiesClassReflectionExtension; - /** - * @var RequireExtendsMethodsClassReflectionExtension - */ - private $requireExtendsMethodsClassReflectionExtension; - /** - * @param PropertiesClassReflectionExtension[] $propertiesClassReflectionExtensions - * @param MethodsClassReflectionExtension[] $methodsClassReflectionExtensions - * @param AllowedSubTypesClassReflectionExtension[] $allowedSubTypesClassReflectionExtensions - */ - public function __construct(Broker $broker, array $propertiesClassReflectionExtensions, array $methodsClassReflectionExtensions, array $allowedSubTypesClassReflectionExtensions, RequireExtendsPropertiesClassReflectionExtension $requireExtendsPropertiesClassReflectionExtension, RequireExtendsMethodsClassReflectionExtension $requireExtendsMethodsClassReflectionExtension) - { - $this->propertiesClassReflectionExtensions = $propertiesClassReflectionExtensions; - $this->methodsClassReflectionExtensions = $methodsClassReflectionExtensions; - $this->allowedSubTypesClassReflectionExtensions = $allowedSubTypesClassReflectionExtensions; - $this->requireExtendsPropertiesClassReflectionExtension = $requireExtendsPropertiesClassReflectionExtension; - $this->requireExtendsMethodsClassReflectionExtension = $requireExtendsMethodsClassReflectionExtension; - foreach (array_merge($propertiesClassReflectionExtensions, $methodsClassReflectionExtensions, $allowedSubTypesClassReflectionExtensions) as $extension) { - if (!($extension instanceof BrokerAwareExtension)) { - continue; - } - - $extension->setBroker($broker); - } + * @param PropertiesClassReflectionExtension[] $propertiesClassReflectionExtensions + * @param MethodsClassReflectionExtension[] $methodsClassReflectionExtensions + * @param AllowedSubTypesClassReflectionExtension[] $allowedSubTypesClassReflectionExtensions + */ + public function __construct( + Broker $broker, + private array $propertiesClassReflectionExtensions, + private array $methodsClassReflectionExtensions, + private array $allowedSubTypesClassReflectionExtensions, + private RequireExtendsPropertiesClassReflectionExtension $requireExtendsPropertiesClassReflectionExtension, + private RequireExtendsMethodsClassReflectionExtension $requireExtendsMethodsClassReflectionExtension, + ) + { + foreach (array_merge($propertiesClassReflectionExtensions, $methodsClassReflectionExtensions, $allowedSubTypesClassReflectionExtensions) as $extension) { + if (!($extension instanceof BrokerAwareExtension)) { + continue; } - /** - * @return PropertiesClassReflectionExtension[] - */ - public function getPropertiesClassReflectionExtensions(): array + + $extension->setBroker($broker); + } + } + + /** + * @return PropertiesClassReflectionExtension[] + */ + public function getPropertiesClassReflectionExtensions(): array { return $this->propertiesClassReflectionExtensions; } /** - * @return MethodsClassReflectionExtension[] - */ - public function getMethodsClassReflectionExtensions(): array + * @return MethodsClassReflectionExtension[] + */ + public function getMethodsClassReflectionExtensions(): array { return $this->methodsClassReflectionExtensions; } /** - * @return AllowedSubTypesClassReflectionExtension[] - */ - public function getAllowedSubTypesClassReflectionExtensions(): array + * @return AllowedSubTypesClassReflectionExtension[] + */ + public function getAllowedSubTypesClassReflectionExtensions(): array { return $this->allowedSubTypesClassReflectionExtensions; } diff --git a/src/Reflection/Constant/RuntimeConstantReflection.php b/src/Reflection/Constant/RuntimeConstantReflection.php index f9b154929b6..341ae68cc42 100644 --- a/src/Reflection/Constant/RuntimeConstantReflection.php +++ b/src/Reflection/Constant/RuntimeConstantReflection.php @@ -9,24 +9,14 @@ class RuntimeConstantReflection implements GlobalConstantReflection { - /** - * @var string - */ - private $name; - /** - * @var Type - */ - private $valueType; - /** - * @var ?string - */ - private $fileName; - public function __construct(string $name, Type $valueType, ?string $fileName) + public function __construct( + private string $name, + private Type $valueType, + private ?string $fileName, + ) { - $this->name = $name; - $this->valueType = $valueType; - $this->fileName = $fileName; } + public function getName(): string { return $this->name; diff --git a/src/Reflection/ConstructorsHelper.php b/src/Reflection/ConstructorsHelper.php index bb708cdbb3a..6a721f2dd7b 100644 --- a/src/Reflection/ConstructorsHelper.php +++ b/src/Reflection/ConstructorsHelper.php @@ -10,24 +10,17 @@ final class ConstructorsHelper { - /** - * @var Container - */ - private $container; - /** - * @var list - */ - private $additionalConstructors; /** @var array> */ - private $additionalConstructorsCache = []; + private array $additionalConstructorsCache = []; /** * @param list $additionalConstructors */ - public function __construct(Container $container, array $additionalConstructors) + public function __construct( + private Container $container, + private array $additionalConstructors, + ) { - $this->container = $container; - $this->additionalConstructors = $additionalConstructors; } /** @@ -65,7 +58,7 @@ public function getConstructors(ClassReflection $classReflection): array try { $prototype = $nativeMethod->getPrototype(); - } catch (ReflectionException $e) { + } catch (ReflectionException) { $prototype = $nativeMethod; } diff --git a/src/Reflection/Dummy/ChangedTypeMethodReflection.php b/src/Reflection/Dummy/ChangedTypeMethodReflection.php index 82db9820f82..ff82f0662a2 100644 --- a/src/Reflection/Dummy/ChangedTypeMethodReflection.php +++ b/src/Reflection/Dummy/ChangedTypeMethodReflection.php @@ -14,32 +14,12 @@ class ChangedTypeMethodReflection implements ExtendedMethodReflection { - /** - * @var ClassReflection - */ - private $declaringClass; - /** - * @var ExtendedMethodReflection - */ - private $reflection; - /** - * @var ParametersAcceptorWithPhpDocs[] - */ - private $variants; - /** - * @var ParametersAcceptorWithPhpDocs[]|null - */ - private $namedArgumentsVariants; /** * @param ParametersAcceptorWithPhpDocs[] $variants * @param ParametersAcceptorWithPhpDocs[]|null $namedArgumentsVariants */ - public function __construct(ClassReflection $declaringClass, ExtendedMethodReflection $reflection, array $variants, ?array $namedArgumentsVariants) + public function __construct(private ClassReflection $declaringClass, private ExtendedMethodReflection $reflection, private array $variants, private ?array $namedArgumentsVariants) { - $this->declaringClass = $declaringClass; - $this->reflection = $reflection; - $this->variants = $variants; - $this->namedArgumentsVariants = $namedArgumentsVariants; } public function getDeclaringClass(): ClassReflection diff --git a/src/Reflection/Dummy/ChangedTypePropertyReflection.php b/src/Reflection/Dummy/ChangedTypePropertyReflection.php index e80782a2ef1..018d8593fa8 100644 --- a/src/Reflection/Dummy/ChangedTypePropertyReflection.php +++ b/src/Reflection/Dummy/ChangedTypePropertyReflection.php @@ -11,28 +11,8 @@ class ChangedTypePropertyReflection implements WrapperPropertyReflection { - /** - * @var ClassReflection - */ - private $declaringClass; - /** - * @var PropertyReflection - */ - private $reflection; - /** - * @var Type - */ - private $readableType; - /** - * @var Type - */ - private $writableType; - public function __construct(ClassReflection $declaringClass, PropertyReflection $reflection, Type $readableType, Type $writableType) + public function __construct(private ClassReflection $declaringClass, private PropertyReflection $reflection, private Type $readableType, private Type $writableType) { - $this->declaringClass = $declaringClass; - $this->reflection = $reflection; - $this->readableType = $readableType; - $this->writableType = $writableType; } public function getDeclaringClass(): ClassReflection diff --git a/src/Reflection/Dummy/DummyConstantReflection.php b/src/Reflection/Dummy/DummyConstantReflection.php index e2009dc03b7..2f2ef828ec0 100644 --- a/src/Reflection/Dummy/DummyConstantReflection.php +++ b/src/Reflection/Dummy/DummyConstantReflection.php @@ -15,13 +15,8 @@ class DummyConstantReflection implements ConstantReflection { - /** - * @var string - */ - private $name; - public function __construct(string $name) + public function __construct(private string $name) { - $this->name = $name; } public function getDeclaringClass(): ClassReflection diff --git a/src/Reflection/Dummy/DummyConstructorReflection.php b/src/Reflection/Dummy/DummyConstructorReflection.php index e55d14f2da8..f6a67026cb9 100644 --- a/src/Reflection/Dummy/DummyConstructorReflection.php +++ b/src/Reflection/Dummy/DummyConstructorReflection.php @@ -16,13 +16,8 @@ class DummyConstructorReflection implements ExtendedMethodReflection { - /** - * @var ClassReflection - */ - private $declaringClass; - public function __construct(ClassReflection $declaringClass) + public function __construct(private ClassReflection $declaringClass) { - $this->declaringClass = $declaringClass; } public function getDeclaringClass(): ClassReflection @@ -58,7 +53,16 @@ public function getPrototype(): ClassMemberReflection public function getVariants(): array { return [ - new FunctionVariantWithPhpDocs(TemplateTypeMap::createEmpty(), null, [], false, new VoidType(), new MixedType(), new MixedType(), null), + new FunctionVariantWithPhpDocs( + TemplateTypeMap::createEmpty(), + null, + [], + false, + new VoidType(), + new MixedType(), + new MixedType(), + null, + ), ]; } diff --git a/src/Reflection/Dummy/DummyMethodReflection.php b/src/Reflection/Dummy/DummyMethodReflection.php index bd322ff7270..f454126ec23 100644 --- a/src/Reflection/Dummy/DummyMethodReflection.php +++ b/src/Reflection/Dummy/DummyMethodReflection.php @@ -15,13 +15,8 @@ class DummyMethodReflection implements ExtendedMethodReflection { - /** - * @var string - */ - private $name; - public function __construct(string $name) + public function __construct(private string $name) { - $this->name = $name; } public function getDeclaringClass(): ClassReflection diff --git a/src/Reflection/EnumCaseReflection.php b/src/Reflection/EnumCaseReflection.php index d73cd76e1ff..b538f44b3f9 100644 --- a/src/Reflection/EnumCaseReflection.php +++ b/src/Reflection/EnumCaseReflection.php @@ -8,23 +8,8 @@ class EnumCaseReflection { - /** - * @var ClassReflection - */ - private $declaringEnum; - /** - * @var string - */ - private $name; - /** - * @var ?Type - */ - private $backingValueType; - public function __construct(ClassReflection $declaringEnum, string $name, ?Type $backingValueType) + public function __construct(private ClassReflection $declaringEnum, private string $name, private ?Type $backingValueType) { - $this->declaringEnum = $declaringEnum; - $this->name = $name; - $this->backingValueType = $backingValueType; } public function getDeclaringEnum(): ClassReflection diff --git a/src/Reflection/ExtendedMethodReflection.php b/src/Reflection/ExtendedMethodReflection.php index 51451005e37..47d6d4d61a3 100644 --- a/src/Reflection/ExtendedMethodReflection.php +++ b/src/Reflection/ExtendedMethodReflection.php @@ -40,9 +40,6 @@ public function returnsByReference(): TrinaryLogic; public function isFinalByKeyword(): TrinaryLogic; - /** - * @return TrinaryLogic|bool - */ - public function isAbstract(); + public function isAbstract(): TrinaryLogic|bool; } diff --git a/src/Reflection/FunctionReflectionFactory.php b/src/Reflection/FunctionReflectionFactory.php index 4480e951ccc..28382fd315e 100644 --- a/src/Reflection/FunctionReflectionFactory.php +++ b/src/Reflection/FunctionReflectionFactory.php @@ -14,6 +14,21 @@ interface FunctionReflectionFactory * @param Type[] $phpDocParameterTypes * @param Type[] $phpDocParameterOutTypes */ - public function create(ReflectionFunction $reflection, TemplateTypeMap $templateTypeMap, array $phpDocParameterTypes, ?Type $phpDocReturnType, ?Type $phpDocThrowType, ?string $deprecatedDescription, bool $isDeprecated, bool $isInternal, bool $isFinal, ?string $filename, ?bool $isPure, Assertions $asserts, ?string $phpDocComment, array $phpDocParameterOutTypes) : PhpFunctionReflection; + public function create( + ReflectionFunction $reflection, + TemplateTypeMap $templateTypeMap, + array $phpDocParameterTypes, + ?Type $phpDocReturnType, + ?Type $phpDocThrowType, + ?string $deprecatedDescription, + bool $isDeprecated, + bool $isInternal, + bool $isFinal, + ?string $filename, + ?bool $isPure, + Assertions $asserts, + ?string $phpDocComment, + array $phpDocParameterOutTypes, + ): PhpFunctionReflection; } diff --git a/src/Reflection/FunctionVariant.php b/src/Reflection/FunctionVariant.php index 24534d2eb24..3c5947ac5c8 100644 --- a/src/Reflection/FunctionVariant.php +++ b/src/Reflection/FunctionVariant.php @@ -10,42 +10,21 @@ class FunctionVariant implements ParametersAcceptor { - /** - * @var TemplateTypeMap - */ - private $templateTypeMap; - /** - * @var ?TemplateTypeMap - */ - private $resolvedTemplateTypeMap; - /** - * @var array - */ - private $parameters; - /** - * @var bool - */ - private $isVariadic; - /** - * @var Type - */ - private $returnType; - /** - * @var TemplateTypeVarianceMap - */ - private $callSiteVarianceMap; + private TemplateTypeVarianceMap $callSiteVarianceMap; /** * @api * @param array $parameters */ - public function __construct(TemplateTypeMap $templateTypeMap, ?TemplateTypeMap $resolvedTemplateTypeMap, array $parameters, bool $isVariadic, Type $returnType, ?TemplateTypeVarianceMap $callSiteVarianceMap = null) + public function __construct( + private TemplateTypeMap $templateTypeMap, + private ?TemplateTypeMap $resolvedTemplateTypeMap, + private array $parameters, + private bool $isVariadic, + private Type $returnType, + ?TemplateTypeVarianceMap $callSiteVarianceMap = null, + ) { - $this->templateTypeMap = $templateTypeMap; - $this->resolvedTemplateTypeMap = $resolvedTemplateTypeMap; - $this->parameters = $parameters; - $this->isVariadic = $isVariadic; - $this->returnType = $returnType; $this->callSiteVarianceMap = $callSiteVarianceMap ?? TemplateTypeVarianceMap::createEmpty(); } diff --git a/src/Reflection/FunctionVariantWithPhpDocs.php b/src/Reflection/FunctionVariantWithPhpDocs.php index deef7a85bc3..2efd1c1a97d 100644 --- a/src/Reflection/FunctionVariantWithPhpDocs.php +++ b/src/Reflection/FunctionVariantWithPhpDocs.php @@ -10,24 +10,31 @@ class FunctionVariantWithPhpDocs extends FunctionVariant implements ParametersAcceptorWithPhpDocs { - /** - * @var Type - */ - private $phpDocReturnType; - /** - * @var Type - */ - private $nativeReturnType; /** * @api * @param array $parameters */ - public function __construct(TemplateTypeMap $templateTypeMap, ?TemplateTypeMap $resolvedTemplateTypeMap, array $parameters, bool $isVariadic, Type $returnType, Type $phpDocReturnType, Type $nativeReturnType, ?TemplateTypeVarianceMap $callSiteVarianceMap = null) + public function __construct( + TemplateTypeMap $templateTypeMap, + ?TemplateTypeMap $resolvedTemplateTypeMap, + array $parameters, + bool $isVariadic, + Type $returnType, + private Type $phpDocReturnType, + private Type $nativeReturnType, + ?TemplateTypeVarianceMap $callSiteVarianceMap = null, + ) { - $this->phpDocReturnType = $phpDocReturnType; - $this->nativeReturnType = $nativeReturnType; - parent::__construct($templateTypeMap, $resolvedTemplateTypeMap, $parameters, $isVariadic, $returnType, $callSiteVarianceMap); + parent::__construct( + $templateTypeMap, + $resolvedTemplateTypeMap, + $parameters, + $isVariadic, + $returnType, + $callSiteVarianceMap, + ); } + /** * @return array */ diff --git a/src/Reflection/GenericParametersAcceptorResolver.php b/src/Reflection/GenericParametersAcceptorResolver.php index 0e4fd5e9052..46154a33b50 100644 --- a/src/Reflection/GenericParametersAcceptorResolver.php +++ b/src/Reflection/GenericParametersAcceptorResolver.php @@ -78,17 +78,40 @@ public static function resolve(array $argTypes, ParametersAcceptor $parametersAc $typeMap = $typeMap->union($paramType->inferTemplateTypes($argType)); } - $resolvedTemplateTypeMap = new TemplateTypeMap(array_merge($parametersAcceptor->getTemplateTypeMap()->map(static function (string $name, Type $type) : Type { - return new ErrorType(); - })->getTypes(), $typeMap->getTypes())); + $resolvedTemplateTypeMap = new TemplateTypeMap(array_merge( + $parametersAcceptor->getTemplateTypeMap()->map(static fn (string $name, Type $type): Type => new ErrorType())->getTypes(), + $typeMap->getTypes(), + )); if (!$parametersAcceptor instanceof ParametersAcceptorWithPhpDocs) { - $parametersAcceptor = new FunctionVariantWithPhpDocs($parametersAcceptor->getTemplateTypeMap(), $parametersAcceptor->getResolvedTemplateTypeMap(), array_map(static function (ParameterReflection $parameter) : ParameterReflectionWithPhpDocs { - return new DummyParameterWithPhpDocs($parameter->getName(), $parameter->getType(), $parameter->isOptional(), $parameter->passedByReference(), $parameter->isVariadic(), $parameter->getDefaultValue(), new MixedType(), $parameter->getType(), null); - }, $parametersAcceptor->getParameters()), $parametersAcceptor->isVariadic(), $parametersAcceptor->getReturnType(), $parametersAcceptor->getReturnType(), new MixedType(), TemplateTypeVarianceMap::createEmpty()); + $parametersAcceptor = new FunctionVariantWithPhpDocs( + $parametersAcceptor->getTemplateTypeMap(), + $parametersAcceptor->getResolvedTemplateTypeMap(), + array_map(static fn (ParameterReflection $parameter): ParameterReflectionWithPhpDocs => new DummyParameterWithPhpDocs( + $parameter->getName(), + $parameter->getType(), + $parameter->isOptional(), + $parameter->passedByReference(), + $parameter->isVariadic(), + $parameter->getDefaultValue(), + new MixedType(), + $parameter->getType(), + null, + ), $parametersAcceptor->getParameters()), + $parametersAcceptor->isVariadic(), + $parametersAcceptor->getReturnType(), + $parametersAcceptor->getReturnType(), + new MixedType(), + TemplateTypeVarianceMap::createEmpty(), + ); } - return new ResolvedFunctionVariant($parametersAcceptor, $resolvedTemplateTypeMap, $parametersAcceptor->getCallSiteVarianceMap(), $passedArgs); + return new ResolvedFunctionVariant( + $parametersAcceptor, + $resolvedTemplateTypeMap, + $parametersAcceptor->getCallSiteVarianceMap(), + $passedArgs, + ); } } diff --git a/src/Reflection/InaccessibleMethod.php b/src/Reflection/InaccessibleMethod.php index b6bc0a91ad2..3d732648c5c 100644 --- a/src/Reflection/InaccessibleMethod.php +++ b/src/Reflection/InaccessibleMethod.php @@ -10,13 +10,8 @@ class InaccessibleMethod implements ParametersAcceptor { - /** - * @var MethodReflection - */ - private $methodReflection; - public function __construct(MethodReflection $methodReflection) + public function __construct(private MethodReflection $methodReflection) { - $this->methodReflection = $methodReflection; } public function getMethod(): MethodReflection diff --git a/src/Reflection/InitializerExprContext.php b/src/Reflection/InitializerExprContext.php index 148487b3125..c71a75c7d0d 100644 --- a/src/Reflection/InitializerExprContext.php +++ b/src/Reflection/InitializerExprContext.php @@ -18,44 +18,29 @@ class InitializerExprContext implements NamespaceAnswerer { - /** - * @var ?string - */ - private $file; - /** - * @var ?string - */ - private $namespace; - /** - * @var ?string - */ - private $className; - /** - * @var ?string - */ - private $traitName; - /** - * @var ?string - */ - private $function; - /** - * @var ?string - */ - private $method; - private function __construct(?string $file, ?string $namespace, ?string $className, ?string $traitName, ?string $function, ?string $method) + private function __construct( + private ?string $file, + private ?string $namespace, + private ?string $className, + private ?string $traitName, + private ?string $function, + private ?string $method, + ) { - $this->file = $file; - $this->namespace = $namespace; - $this->className = $className; - $this->traitName = $traitName; - $this->function = $function; - $this->method = $method; } + public static function fromScope(Scope $scope): self { - return new self($scope->getFile(), $scope->getNamespace(), $scope->isInClass() ? $scope->getClassReflection()->getName() : null, $scope->isInTrait() ? $scope->getTraitReflection()->getName() : null, $scope->isInAnonymousFunction() ? '{closure}' : ($scope->getFunction() !== null ? $scope->getFunction()->getName() : null), $scope->isInAnonymousFunction() ? '{closure}' : ($scope->getFunction() instanceof MethodReflection + return new self( + $scope->getFile(), + $scope->getNamespace(), + $scope->isInClass() ? $scope->getClassReflection()->getName() : null, + $scope->isInTrait() ? $scope->getTraitReflection()->getName() : null, + $scope->isInAnonymousFunction() ? '{closure}' : ($scope->getFunction() !== null ? $scope->getFunction()->getName() : null), + $scope->isInAnonymousFunction() ? '{closure}' : ($scope->getFunction() instanceof MethodReflection ? sprintf('%s::%s', $scope->getFunction()->getDeclaringClass()->getName(), $scope->getFunction()->getName()) - : ($scope->getFunction() instanceof FunctionReflection ? $scope->getFunction()->getName() : null))); + : ($scope->getFunction() instanceof FunctionReflection ? $scope->getFunction()->getName() : null)), + ); } private static function parseNamespace(string $name): ?string @@ -75,7 +60,14 @@ public static function fromClassReflection(ClassReflection $classReflection): se public static function fromClass(string $className, ?string $fileName): self { - return new self($fileName, self::parseNamespace($className), $className, null, null, null); + return new self( + $fileName, + self::parseNamespace($className), + $className, + null, + null, + null, + ); } public static function fromReflectionParameter(ReflectionParameter $parameter): self @@ -83,20 +75,35 @@ public static function fromReflectionParameter(ReflectionParameter $parameter): $declaringFunction = $parameter->getDeclaringFunction(); if ($declaringFunction instanceof ReflectionFunction) { $file = $declaringFunction->getFileName(); - return new self($file === false ? null : $file, self::parseNamespace($declaringFunction->getName()), null, null, $declaringFunction->getName(), $declaringFunction->getName()); + return new self( + $file === false ? null : $file, + self::parseNamespace($declaringFunction->getName()), + null, + null, + $declaringFunction->getName(), + $declaringFunction->getName(), + ); } $file = $declaringFunction->getFileName(); $betterReflection = $declaringFunction->getBetterReflection(); - return new self($file === false ? null : $file, self::parseNamespace($betterReflection->getDeclaringClass()->getName()), $declaringFunction->getDeclaringClass()->getName(), $betterReflection->getDeclaringClass()->isTrait() ? $betterReflection->getDeclaringClass()->getName() : null, $declaringFunction->getName(), sprintf('%s::%s', $declaringFunction->getDeclaringClass()->getName(), $declaringFunction->getName())); + return new self( + $file === false ? null : $file, + self::parseNamespace($betterReflection->getDeclaringClass()->getName()), + $declaringFunction->getDeclaringClass()->getName(), + $betterReflection->getDeclaringClass()->isTrait() ? $betterReflection->getDeclaringClass()->getName() : null, + $declaringFunction->getName(), + sprintf('%s::%s', $declaringFunction->getDeclaringClass()->getName(), $declaringFunction->getName()), + ); } - /** - * @param ClassMethod|Function_ $function - */ - public static function fromStubParameter(?string $className, string $stubFile, $function) : self + public static function fromStubParameter( + ?string $className, + string $stubFile, + ClassMethod|Function_ $function, + ): self { $namespace = null; if ($className !== null) { @@ -106,14 +113,28 @@ public static function fromStubParameter(?string $className, string $stubFile, $ $namespace = self::parseNamespace($function->namespacedName->toString()); } } - return new self($stubFile, $namespace, $className, null, $function instanceof Function_ && $function->namespacedName !== null ? $function->namespacedName->toString() : ($function instanceof ClassMethod ? $function->name->toString() : null), $function instanceof ClassMethod && $className !== null + return new self( + $stubFile, + $namespace, + $className, + null, + $function instanceof Function_ && $function->namespacedName !== null ? $function->namespacedName->toString() : ($function instanceof ClassMethod ? $function->name->toString() : null), + $function instanceof ClassMethod && $className !== null ? sprintf('%s::%s', $className, $function->name->toString()) - : ($function instanceof Function_ && $function->namespacedName !== null ? $function->namespacedName->toString() : null)); + : ($function instanceof Function_ && $function->namespacedName !== null ? $function->namespacedName->toString() : null), + ); } public static function fromGlobalConstant(ReflectionConstant $constant): self { - return new self($constant->getFileName(), $constant->getNamespaceName(), null, null, null, null); + return new self( + $constant->getFileName(), + $constant->getNamespaceName(), + null, + null, + null, + null, + ); } public static function createEmpty(): self diff --git a/src/Reflection/InitializerExprTypeResolver.php b/src/Reflection/InitializerExprTypeResolver.php index 401035d68bf..91e12051898 100644 --- a/src/Reflection/InitializerExprTypeResolver.php +++ b/src/Reflection/InitializerExprTypeResolver.php @@ -87,43 +87,20 @@ class InitializerExprTypeResolver { - /** - * @var ConstantResolver - */ - private $constantResolver; - /** - * @var ReflectionProviderProvider - */ - private $reflectionProviderProvider; - /** - * @var PhpVersion - */ - private $phpVersion; - /** - * @var OperatorTypeSpecifyingExtensionRegistryProvider - */ - private $operatorTypeSpecifyingExtensionRegistryProvider; - /** - * @var OversizedArrayBuilder - */ - private $oversizedArrayBuilder; - /** - * @var bool - */ - private $usePathConstantsAsConstantString; public const CALCULATE_SCALARS_LIMIT = 128; /** @var array */ - private $currentlyResolvingClassConstant = []; - - public function __construct(ConstantResolver $constantResolver, ReflectionProviderProvider $reflectionProviderProvider, PhpVersion $phpVersion, OperatorTypeSpecifyingExtensionRegistryProvider $operatorTypeSpecifyingExtensionRegistryProvider, OversizedArrayBuilder $oversizedArrayBuilder, bool $usePathConstantsAsConstantString = false) + private array $currentlyResolvingClassConstant = []; + + public function __construct( + private ConstantResolver $constantResolver, + private ReflectionProviderProvider $reflectionProviderProvider, + private PhpVersion $phpVersion, + private OperatorTypeSpecifyingExtensionRegistryProvider $operatorTypeSpecifyingExtensionRegistryProvider, + private OversizedArrayBuilder $oversizedArrayBuilder, + private bool $usePathConstantsAsConstantString = false, + ) { - $this->constantResolver = $constantResolver; - $this->reflectionProviderProvider = $reflectionProviderProvider; - $this->phpVersion = $phpVersion; - $this->operatorTypeSpecifyingExtensionRegistryProvider = $operatorTypeSpecifyingExtensionRegistryProvider; - $this->oversizedArrayBuilder = $oversizedArrayBuilder; - $this->usePathConstantsAsConstantString = $usePathConstantsAsConstantString; } /** @api */ @@ -186,9 +163,7 @@ public function getType(Expr $expr, InitializerExprContext $context): Type return new ObjectWithoutClassType(); } if ($expr instanceof Expr\Array_) { - return $this->getArrayType($expr, function (Expr $expr) use($context) : Type { - return $this->getType($expr, $context); - }); + return $this->getArrayType($expr, fn (Expr $expr): Type => $this->getType($expr, $context)); } if ($expr instanceof Expr\ArrayDimFetch && $expr->dim !== null) { $var = $this->getType($expr->var, $context); @@ -196,17 +171,13 @@ public function getType(Expr $expr, InitializerExprContext $context): Type return $var->getOffsetValueType($dim); } if ($expr instanceof ClassConstFetch && $expr->name instanceof Identifier) { - return $this->getClassConstFetchType($expr->class, $expr->name->toString(), $context->getClassName(), function (Expr $expr) use($context) : Type { - return $this->getType($expr, $context); - }); + return $this->getClassConstFetchType($expr->class, $expr->name->toString(), $context->getClassName(), fn (Expr $expr): Type => $this->getType($expr, $context)); } if ($expr instanceof Expr\UnaryPlus) { return $this->getType($expr->expr, $context)->toNumber(); } if ($expr instanceof Expr\UnaryMinus) { - return $this->getUnaryMinusType($expr->expr, function (Expr $expr) use($context) : Type { - return $this->getType($expr, $context); - }); + return $this->getUnaryMinusType($expr->expr, fn (Expr $expr): Type => $this->getType($expr, $context)); } if ($expr instanceof Expr\BinaryOp\Coalesce) { $leftType = $this->getType($expr->left, $context); @@ -219,12 +190,18 @@ public function getType(Expr $expr, InitializerExprContext $context): Type $condType = $this->getType($expr->cond, $context); $elseType = $this->getType($expr->else, $context); if ($expr->if === null) { - return TypeCombinator::union(TypeCombinator::removeFalsey($condType), $elseType); + return TypeCombinator::union( + TypeCombinator::removeFalsey($condType), + $elseType, + ); } $ifType = $this->getType($expr->if, $context); - return TypeCombinator::union(TypeCombinator::removeFalsey($ifType), $elseType); + return TypeCombinator::union( + TypeCombinator::removeFalsey($ifType), + $elseType, + ); } if ($expr instanceof Expr\FuncCall && $expr->name instanceof Name && $expr->name->toLowerString() === 'constant') { @@ -248,39 +225,27 @@ public function getType(Expr $expr, InitializerExprContext $context): Type } if ($expr instanceof Expr\BitwiseNot) { - return $this->getBitwiseNotType($expr->expr, function (Expr $expr) use($context) : Type { - return $this->getType($expr, $context); - }); + return $this->getBitwiseNotType($expr->expr, fn (Expr $expr): Type => $this->getType($expr, $context)); } if ($expr instanceof Expr\BinaryOp\Concat) { - return $this->getConcatType($expr->left, $expr->right, function (Expr $expr) use($context) : Type { - return $this->getType($expr, $context); - }); + return $this->getConcatType($expr->left, $expr->right, fn (Expr $expr): Type => $this->getType($expr, $context)); } if ($expr instanceof Expr\BinaryOp\BitwiseAnd) { - return $this->getBitwiseAndType($expr->left, $expr->right, function (Expr $expr) use($context) : Type { - return $this->getType($expr, $context); - }); + return $this->getBitwiseAndType($expr->left, $expr->right, fn (Expr $expr): Type => $this->getType($expr, $context)); } if ($expr instanceof Expr\BinaryOp\BitwiseOr) { - return $this->getBitwiseOrType($expr->left, $expr->right, function (Expr $expr) use($context) : Type { - return $this->getType($expr, $context); - }); + return $this->getBitwiseOrType($expr->left, $expr->right, fn (Expr $expr): Type => $this->getType($expr, $context)); } if ($expr instanceof Expr\BinaryOp\BitwiseXor) { - return $this->getBitwiseXorType($expr->left, $expr->right, function (Expr $expr) use($context) : Type { - return $this->getType($expr, $context); - }); + return $this->getBitwiseXorType($expr->left, $expr->right, fn (Expr $expr): Type => $this->getType($expr, $context)); } if ($expr instanceof Expr\BinaryOp\Spaceship) { - return $this->getSpaceshipType($expr->left, $expr->right, function (Expr $expr) use($context) : Type { - return $this->getType($expr, $context); - }); + return $this->getSpaceshipType($expr->left, $expr->right, fn (Expr $expr): Type => $this->getType($expr, $context)); } if ( @@ -293,55 +258,42 @@ public function getType(Expr $expr, InitializerExprContext $context): Type } if ($expr instanceof Expr\BinaryOp\Div) { - return $this->getDivType($expr->left, $expr->right, function (Expr $expr) use($context) : Type { - return $this->getType($expr, $context); - }); + return $this->getDivType($expr->left, $expr->right, fn (Expr $expr): Type => $this->getType($expr, $context)); } if ($expr instanceof Expr\BinaryOp\Mod) { - return $this->getModType($expr->left, $expr->right, function (Expr $expr) use($context) : Type { - return $this->getType($expr, $context); - }); + return $this->getModType($expr->left, $expr->right, fn (Expr $expr): Type => $this->getType($expr, $context)); } if ($expr instanceof Expr\BinaryOp\Plus) { - return $this->getPlusType($expr->left, $expr->right, function (Expr $expr) use($context) : Type { - return $this->getType($expr, $context); - }); + return $this->getPlusType($expr->left, $expr->right, fn (Expr $expr): Type => $this->getType($expr, $context)); } if ($expr instanceof Expr\BinaryOp\Minus) { - return $this->getMinusType($expr->left, $expr->right, function (Expr $expr) use($context) : Type { - return $this->getType($expr, $context); - }); + return $this->getMinusType($expr->left, $expr->right, fn (Expr $expr): Type => $this->getType($expr, $context)); } if ($expr instanceof Expr\BinaryOp\Mul) { - return $this->getMulType($expr->left, $expr->right, function (Expr $expr) use($context) : Type { - return $this->getType($expr, $context); - }); + return $this->getMulType($expr->left, $expr->right, fn (Expr $expr): Type => $this->getType($expr, $context)); } if ($expr instanceof Expr\BinaryOp\Pow) { - return $this->getPowType($expr->left, $expr->right, function (Expr $expr) use($context) : Type { - return $this->getType($expr, $context); - }); + return $this->getPowType($expr->left, $expr->right, fn (Expr $expr): Type => $this->getType($expr, $context)); } if ($expr instanceof Expr\BinaryOp\ShiftLeft) { - return $this->getShiftLeftType($expr->left, $expr->right, function (Expr $expr) use($context) : Type { - return $this->getType($expr, $context); - }); + return $this->getShiftLeftType($expr->left, $expr->right, fn (Expr $expr): Type => $this->getType($expr, $context)); } if ($expr instanceof Expr\BinaryOp\ShiftRight) { - return $this->getShiftRightType($expr->left, $expr->right, function (Expr $expr) use($context) : Type { - return $this->getType($expr, $context); - }); + return $this->getShiftRightType($expr->left, $expr->right, fn (Expr $expr): Type => $this->getType($expr, $context)); } if ($expr instanceof BinaryOp\Identical) { - return $this->resolveIdenticalType($this->getType($expr->left, $context), $this->getType($expr->right, $context)); + return $this->resolveIdenticalType( + $this->getType($expr->left, $context), + $this->getType($expr->right, $context), + ); } if ($expr instanceof BinaryOp\NotIdentical) { @@ -349,7 +301,10 @@ public function getType(Expr $expr, InitializerExprContext $context): Type } if ($expr instanceof BinaryOp\Equal) { - return $this->resolveEqualType($this->getType($expr->left, $context), $this->getType($expr->right, $context)); + return $this->resolveEqualType( + $this->getType($expr->left, $context), + $this->getType($expr->right, $context), + ); } if ($expr instanceof BinaryOp\NotEqual) { @@ -380,7 +335,9 @@ public function getType(Expr $expr, InitializerExprContext $context): Type $leftBooleanType instanceof ConstantBooleanType && $rightBooleanType instanceof ConstantBooleanType ) { - return new ConstantBooleanType($leftBooleanType->getValue() xor $rightBooleanType->getValue()); + return new ConstantBooleanType( + $leftBooleanType->getValue() xor $rightBooleanType->getValue(), + ); } return new BooleanType(); @@ -388,7 +345,10 @@ public function getType(Expr $expr, InitializerExprContext $context): Type if ($expr instanceof MagicConst\Class_) { if ($context->getTraitName() !== null) { - return TypeCombinator::intersect(new ClassStringType(), new AccessoryLiteralStringType()); + return TypeCombinator::intersect( + new ClassStringType(), + new AccessoryLiteralStringType(), + ); } if ($context->getClassName() === null) { @@ -400,7 +360,10 @@ public function getType(Expr $expr, InitializerExprContext $context): Type if ($expr instanceof MagicConst\Namespace_) { if ($context->getTraitName() !== null) { - return TypeCombinator::intersect(new StringType(), new AccessoryLiteralStringType()); + return TypeCombinator::intersect( + new StringType(), + new AccessoryLiteralStringType(), + ); } return new ConstantStringType($context->getNamespace() ?? ''); @@ -449,7 +412,10 @@ public function resolveConcatType(Type $left, Type $right): Type { $leftStringType = $left->toString(); $rightStringType = $right->toString(); - if (TypeCombinator::union($leftStringType, $rightStringType) instanceof ErrorType) { + if (TypeCombinator::union( + $leftStringType, + $rightStringType, + ) instanceof ErrorType) { return new ErrorType(); } @@ -560,14 +526,17 @@ public function getArrayType(Expr\Array_ $expr, callable $getTypeCallback): Type $isList = false; $offsetType = $valueType->getIterableKeyType(); } else { - $isList = $isList ?? $arrayBuilder->isList(); + $isList ??= $arrayBuilder->isList(); $offsetType = new IntegerType(); } $arrayBuilder->setOffsetValueType($offsetType, $valueType->getIterableValueType(), !$valueType->isIterableAtLeastOnce()->yes()); } } else { - $arrayBuilder->setOffsetValueType($arrayItem->key !== null ? $getTypeCallback($arrayItem->key) : null, $valueType); + $arrayBuilder->setOffsetValueType( + $arrayItem->key !== null ? $getTypeCallback($arrayItem->key) : null, + $valueType, + ); } } @@ -1004,7 +973,11 @@ public function getPlusType(Expr $left, Expr $right, callable $getTypeCallback): $valueType = TypeCombinator::union($valueType, $rightConstantArray->getOffsetValueType($leftKeyType)); } } - $newArrayBuilder->setOffsetValueType($leftKeyType, $valueType, $optional); + $newArrayBuilder->setOffsetValueType( + $leftKeyType, + $valueType, + $optional, + ); } $resultTypes[] = $newArrayBuilder->getArray(); } @@ -1029,7 +1002,10 @@ public function getPlusType(Expr $left, Expr $right, callable $getTypeCallback): $keyType = TypeCombinator::union(...$keyTypes); } - $arrayType = new ArrayType($keyType, TypeCombinator::union($leftType->getIterableValueType(), $rightType->getIterableValueType())); + $arrayType = new ArrayType( + $keyType, + TypeCombinator::union($leftType->getIterableValueType(), $rightType->getIterableValueType()), + ); if ($leftType->isIterableAtLeastOnce()->yes() || $rightType->isIterableAtLeastOnce()->yes()) { $arrayType = TypeCombinator::intersect($arrayType, new NonEmptyArrayType()); @@ -1346,9 +1322,7 @@ public function resolveIdenticalType(Type $leftType, Type $rightType): BooleanTy } if ($leftType instanceof ConstantArrayType && $rightType instanceof ConstantArrayType) { - return $this->resolveConstantArrayTypeComparison($leftType, $rightType, function ($leftValueType, $rightValueType) : BooleanType { - return $this->resolveIdenticalType($leftValueType, $rightValueType); - }); + return $this->resolveConstantArrayTypeComparison($leftType, $rightType, fn ($leftValueType, $rightValueType): BooleanType => $this->resolveIdenticalType($leftValueType, $rightValueType)); } return new BooleanType(); @@ -1367,9 +1341,7 @@ public function resolveEqualType(Type $leftType, Type $rightType): BooleanType } if ($leftType instanceof ConstantArrayType && $rightType instanceof ConstantArrayType) { - return $this->resolveConstantArrayTypeComparison($leftType, $rightType, function ($leftValueType, $rightValueType) : BooleanType { - return $this->resolveEqualType($leftValueType, $rightValueType); - }); + return $this->resolveConstantArrayTypeComparison($leftType, $rightType, fn ($leftValueType, $rightValueType): BooleanType => $this->resolveEqualType($leftValueType, $rightValueType)); } return $leftType->looseCompare($rightType, $this->phpVersion); @@ -1485,7 +1457,11 @@ private function resolveCommonMath(Expr\BinaryOp $expr, Type $leftType, Type $ri ) ) { if ($leftNumberType instanceof IntegerRangeType || $leftNumberType instanceof ConstantIntegerType) { - return $this->integerRangeMath($leftNumberType, $expr, $rightNumberType); + return $this->integerRangeMath( + $leftNumberType, + $expr, + $rightNumberType, + ); } elseif ($leftNumberType instanceof UnionType) { $unionParts = []; @@ -1696,7 +1672,10 @@ private function integerRangeMath(Type $range, BinaryOp $node, Type $operand): T $positiveOperand = IntegerRangeType::fromInterval(0, $operandMax); assert($positiveOperand instanceof IntegerRangeType); - $result = TypeCombinator::union($this->integerRangeMath($range, $node, $negativeOperand), $this->integerRangeMath($range, $node, $positiveOperand))->toNumber(); + $result = TypeCombinator::union( + $this->integerRangeMath($range, $node, $negativeOperand), + $this->integerRangeMath($range, $node, $positiveOperand), + )->toNumber(); if ($result->equals(new UnionType([new IntegerType(), new FloatType()]))) { return new BenevolentUnionType([new IntegerType(), new FloatType()]); @@ -1713,7 +1692,10 @@ private function integerRangeMath(Type $range, BinaryOp $node, Type $operand): T $positiveRange = IntegerRangeType::fromInterval(0, $rangeMax); assert($positiveRange instanceof IntegerRangeType); - $result = TypeCombinator::union($this->integerRangeMath($negativeRange, $node, $operand), $this->integerRangeMath($positiveRange, $node, $operand))->toNumber(); + $result = TypeCombinator::union( + $this->integerRangeMath($negativeRange, $node, $operand), + $this->integerRangeMath($positiveRange, $node, $operand), + )->toNumber(); if ($result->equals(new UnionType([new IntegerType(), new FloatType()]))) { return new BenevolentUnionType([new IntegerType(), new FloatType()]); @@ -1784,9 +1766,8 @@ private function integerRangeMath(Type $range, BinaryOp $node, Type $operand): T /** * @param callable(Expr): Type $getTypeCallback - * @param Name|Expr $class */ - public function getClassConstFetchTypeByReflection($class, string $constantName, ?ClassReflection $classReflection, callable $getTypeCallback): Type + public function getClassConstFetchTypeByReflection(Name|Expr $class, string $constantName, ?ClassReflection $classReflection, callable $getTypeCallback): Type { $isObject = false; if ($class instanceof Name) { @@ -1827,7 +1808,9 @@ public function getClassConstFetchTypeByReflection($class, string $constantName, } if (strtolower($constantName) === 'class') { - return TypeTraverser::map($constantClassType, function (Type $type, callable $traverse): Type { + return TypeTraverser::map( + $constantClassType, + function (Type $type, callable $traverse): Type { if ($type instanceof UnionType || $type instanceof IntersectionType) { return $traverse($type); } @@ -1837,7 +1820,10 @@ public function getClassConstFetchTypeByReflection($class, string $constantName, } if ($type instanceof EnumCaseObjectType) { - return TypeCombinator::intersect(new GenericClassStringType(new ObjectType($type->getClassName())), new AccessoryLiteralStringType()); + return TypeCombinator::intersect( + new GenericClassStringType(new ObjectType($type->getClassName())), + new AccessoryLiteralStringType(), + ); } $objectClassNames = $type->getObjectClassNames(); @@ -1846,20 +1832,30 @@ public function getClassConstFetchTypeByReflection($class, string $constantName, } if ($type instanceof TemplateType && $objectClassNames === []) { - return TypeCombinator::intersect(new GenericClassStringType($type), new AccessoryLiteralStringType()); + return TypeCombinator::intersect( + new GenericClassStringType($type), + new AccessoryLiteralStringType(), + ); } elseif ($objectClassNames !== [] && $this->getReflectionProvider()->hasClass($objectClassNames[0])) { $reflection = $this->getReflectionProvider()->getClass($objectClassNames[0]); if ($reflection->isFinalByKeyword()) { return new ConstantStringType($reflection->getName(), true); } - return TypeCombinator::intersect(new GenericClassStringType($type), new AccessoryLiteralStringType()); + return TypeCombinator::intersect( + new GenericClassStringType($type), + new AccessoryLiteralStringType(), + ); } elseif ($type->isObject()->yes()) { - return TypeCombinator::intersect(new ClassStringType(), new AccessoryLiteralStringType()); + return TypeCombinator::intersect( + new ClassStringType(), + new AccessoryLiteralStringType(), + ); } return new ErrorType(); - }); + }, + ); } $types = []; @@ -1898,7 +1894,12 @@ public function getClassConstFetchTypeByReflection($class, string $constantName, if ($reflectionConstant->getType() !== null) { $nativeType = TypehintHelper::decideTypeFromReflection($reflectionConstant->getType(), null, $constantClassReflection); } - $types[] = $this->constantResolver->resolveClassConstantType($constantClassReflection->getName(), $constantName, $constantType, $nativeType); + $types[] = $this->constantResolver->resolveClassConstantType( + $constantClassReflection->getName(), + $constantName, + $constantType, + $nativeType, + ); unset($this->currentlyResolvingClassConstant[$resolvingName]); continue; } @@ -1920,7 +1921,12 @@ public function getClassConstFetchTypeByReflection($class, string $constantName, } $nativeType = $constantReflection->getNativeType(); - $constantType = $this->constantResolver->resolveClassConstantType($constantClassReflection->getName(), $constantName, $constantType, $nativeType); + $constantType = $this->constantResolver->resolveClassConstantType( + $constantClassReflection->getName(), + $constantName, + $constantType, + $nativeType, + ); unset($this->currentlyResolvingClassConstant[$resolvingName]); $types[] = $constantType; } @@ -1938,9 +1944,8 @@ public function getClassConstFetchTypeByReflection($class, string $constantName, /** * @param callable(Expr): Type $getTypeCallback - * @param Name|Expr $class */ - public function getClassConstFetchType($class, string $constantName, ?string $className, callable $getTypeCallback): Type + public function getClassConstFetchType(Name|Expr $class, string $constantName, ?string $className, callable $getTypeCallback): Type { $classReflection = null; if ($className !== null && $this->getReflectionProvider()->hasClass($className)) { diff --git a/src/Reflection/MethodPrototypeReflection.php b/src/Reflection/MethodPrototypeReflection.php index 74d2bf96e6c..cf1a6ff76ba 100644 --- a/src/Reflection/MethodPrototypeReflection.php +++ b/src/Reflection/MethodPrototypeReflection.php @@ -7,62 +7,24 @@ class MethodPrototypeReflection implements ClassMemberReflection { - /** - * @var string - */ - private $name; - /** - * @var ClassReflection - */ - private $declaringClass; - /** - * @var bool - */ - private $isStatic; - /** - * @var bool - */ - private $isPrivate; - /** - * @var bool - */ - private $isPublic; - /** - * @var bool - */ - private $isAbstract; - /** - * @var bool - */ - private $isFinal; - /** - * @var bool - */ - private $isInternal; - /** - * @var ParametersAcceptor[] - */ - private $variants; - /** - * @var ?Type - */ - private $tentativeReturnType; /** * @param ParametersAcceptor[] $variants */ - public function __construct(string $name, ClassReflection $declaringClass, bool $isStatic, bool $isPrivate, bool $isPublic, bool $isAbstract, bool $isFinal, bool $isInternal, array $variants, ?Type $tentativeReturnType) + public function __construct( + private string $name, + private ClassReflection $declaringClass, + private bool $isStatic, + private bool $isPrivate, + private bool $isPublic, + private bool $isAbstract, + private bool $isFinal, + private bool $isInternal, + private array $variants, + private ?Type $tentativeReturnType, + ) { - $this->name = $name; - $this->declaringClass = $declaringClass; - $this->isStatic = $isStatic; - $this->isPrivate = $isPrivate; - $this->isPublic = $isPublic; - $this->isAbstract = $isAbstract; - $this->isFinal = $isFinal; - $this->isInternal = $isInternal; - $this->variants = $variants; - $this->tentativeReturnType = $tentativeReturnType; } + public function getName(): string { return $this->name; diff --git a/src/Reflection/MissingConstantFromReflectionException.php b/src/Reflection/MissingConstantFromReflectionException.php index 5e9d862109a..230ba5902db 100644 --- a/src/Reflection/MissingConstantFromReflectionException.php +++ b/src/Reflection/MissingConstantFromReflectionException.php @@ -8,9 +8,18 @@ class MissingConstantFromReflectionException extends Exception { - public function __construct(string $className, string $constantName) + public function __construct( + string $className, + string $constantName, + ) { - parent::__construct(sprintf('Constant %s was not found in reflection of class %s.', $constantName, $className)); + parent::__construct( + sprintf( + 'Constant %s was not found in reflection of class %s.', + $constantName, + $className, + ), + ); } } diff --git a/src/Reflection/MissingMethodFromReflectionException.php b/src/Reflection/MissingMethodFromReflectionException.php index 94cc0c60071..49c7778cd63 100644 --- a/src/Reflection/MissingMethodFromReflectionException.php +++ b/src/Reflection/MissingMethodFromReflectionException.php @@ -8,9 +8,18 @@ class MissingMethodFromReflectionException extends Exception { - public function __construct(string $className, string $methodName) + public function __construct( + string $className, + string $methodName, + ) { - parent::__construct(sprintf('Method %s() was not found in reflection of class %s.', $methodName, $className)); + parent::__construct( + sprintf( + 'Method %s() was not found in reflection of class %s.', + $methodName, + $className, + ), + ); } } diff --git a/src/Reflection/MissingPropertyFromReflectionException.php b/src/Reflection/MissingPropertyFromReflectionException.php index 18f9cc97588..4d62565c1f2 100644 --- a/src/Reflection/MissingPropertyFromReflectionException.php +++ b/src/Reflection/MissingPropertyFromReflectionException.php @@ -8,9 +8,18 @@ class MissingPropertyFromReflectionException extends Exception { - public function __construct(string $className, string $propertyName) + public function __construct( + string $className, + string $propertyName, + ) { - parent::__construct(sprintf('Property $%s was not found in reflection of class %s.', $propertyName, $className)); + parent::__construct( + sprintf( + 'Property $%s was not found in reflection of class %s.', + $propertyName, + $className, + ), + ); } } diff --git a/src/Reflection/Mixin/MixinMethodReflection.php b/src/Reflection/Mixin/MixinMethodReflection.php index 011db117aa6..745a8cae157 100644 --- a/src/Reflection/Mixin/MixinMethodReflection.php +++ b/src/Reflection/Mixin/MixinMethodReflection.php @@ -11,18 +11,8 @@ class MixinMethodReflection implements MethodReflection { - /** - * @var MethodReflection - */ - private $reflection; - /** - * @var bool - */ - private $static; - public function __construct(MethodReflection $reflection, bool $static) + public function __construct(private MethodReflection $reflection, private bool $static) { - $this->reflection = $reflection; - $this->static = $static; } public function getDeclaringClass(): ClassReflection diff --git a/src/Reflection/Mixin/MixinMethodsClassReflectionExtension.php b/src/Reflection/Mixin/MixinMethodsClassReflectionExtension.php index 596a0c02b48..484690a8b79 100644 --- a/src/Reflection/Mixin/MixinMethodsClassReflectionExtension.php +++ b/src/Reflection/Mixin/MixinMethodsClassReflectionExtension.php @@ -14,19 +14,14 @@ class MixinMethodsClassReflectionExtension implements MethodsClassReflectionExtension { - /** - * @var string[] - */ - private $mixinExcludeClasses; /** @var array> */ - private $inProcess = []; + private array $inProcess = []; /** * @param string[] $mixinExcludeClasses */ - public function __construct(array $mixinExcludeClasses) + public function __construct(private array $mixinExcludeClasses) { - $this->mixinExcludeClasses = $mixinExcludeClasses; } public function hasMethod(ClassReflection $classReflection, string $methodName): bool diff --git a/src/Reflection/Mixin/MixinPropertiesClassReflectionExtension.php b/src/Reflection/Mixin/MixinPropertiesClassReflectionExtension.php index fa85b6372cf..b891da3894c 100644 --- a/src/Reflection/Mixin/MixinPropertiesClassReflectionExtension.php +++ b/src/Reflection/Mixin/MixinPropertiesClassReflectionExtension.php @@ -14,19 +14,14 @@ class MixinPropertiesClassReflectionExtension implements PropertiesClassReflectionExtension { - /** - * @var string[] - */ - private $mixinExcludeClasses; /** @var array> */ - private $inProcess = []; + private array $inProcess = []; /** * @param string[] $mixinExcludeClasses */ - public function __construct(array $mixinExcludeClasses) + public function __construct(private array $mixinExcludeClasses) { - $this->mixinExcludeClasses = $mixinExcludeClasses; } public function hasProperty(ClassReflection $classReflection, string $propertyName): bool diff --git a/src/Reflection/Native/NativeFunctionReflection.php b/src/Reflection/Native/NativeFunctionReflection.php index aa0482e630f..44845733140 100644 --- a/src/Reflection/Native/NativeFunctionReflection.php +++ b/src/Reflection/Native/NativeFunctionReflection.php @@ -11,57 +11,26 @@ class NativeFunctionReflection implements FunctionReflection { - /** - * @var string - */ - private $name; - /** - * @var ParametersAcceptorWithPhpDocs[] - */ - private $variants; - /** - * @var ParametersAcceptorWithPhpDocs[]|null - */ - private $namedArgumentsVariants; - /** - * @var ?Type - */ - private $throwType; - /** - * @var TrinaryLogic - */ - private $hasSideEffects; - /** - * @var bool - */ - private $isDeprecated; - /** - * @var ?string - */ - private $phpDocComment; - /** - * @var Assertions - */ - private $assertions; + private Assertions $assertions; - /** - * @var TrinaryLogic - */ - private $returnsByReference; + private TrinaryLogic $returnsByReference; /** * @param ParametersAcceptorWithPhpDocs[] $variants * @param ParametersAcceptorWithPhpDocs[]|null $namedArgumentsVariants */ - public function __construct(string $name, array $variants, ?array $namedArgumentsVariants, ?Type $throwType, TrinaryLogic $hasSideEffects, bool $isDeprecated, ?Assertions $assertions = null, ?string $phpDocComment = null, ?TrinaryLogic $returnsByReference = null) - { - $this->name = $name; - $this->variants = $variants; - $this->namedArgumentsVariants = $namedArgumentsVariants; - $this->throwType = $throwType; - $this->hasSideEffects = $hasSideEffects; - $this->isDeprecated = $isDeprecated; - $this->phpDocComment = $phpDocComment; + public function __construct( + private string $name, + private array $variants, + private ?array $namedArgumentsVariants, + private ?Type $throwType, + private TrinaryLogic $hasSideEffects, + private bool $isDeprecated, + ?Assertions $assertions = null, + private ?string $phpDocComment = null, + ?TrinaryLogic $returnsByReference = null, + ) + { $this->assertions = $assertions ?? Assertions::createEmpty(); $this->returnsByReference = $returnsByReference ?? TrinaryLogic::createMaybe(); } diff --git a/src/Reflection/Native/NativeMethodReflection.php b/src/Reflection/Native/NativeMethodReflection.php index b85d036bc00..868e4927cb7 100644 --- a/src/Reflection/Native/NativeMethodReflection.php +++ b/src/Reflection/Native/NativeMethodReflection.php @@ -19,63 +19,25 @@ class NativeMethodReflection implements ExtendedMethodReflection { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - /** - * @var ClassReflection - */ - private $declaringClass; - /** - * @var BuiltinMethodReflection - */ - private $reflection; - /** - * @var ParametersAcceptorWithPhpDocs[] - */ - private $variants; - /** - * @var ParametersAcceptorWithPhpDocs[]|null - */ - private $namedArgumentsVariants; - /** - * @var TrinaryLogic - */ - private $hasSideEffects; - /** - * @var ?Type - */ - private $throwType; - /** - * @var Assertions - */ - private $assertions; - /** - * @var ?Type - */ - private $selfOutType; - /** - * @var ?string - */ - private $phpDocComment; /** * @param ParametersAcceptorWithPhpDocs[] $variants * @param ParametersAcceptorWithPhpDocs[]|null $namedArgumentsVariants */ - public function __construct(ReflectionProvider $reflectionProvider, ClassReflection $declaringClass, BuiltinMethodReflection $reflection, array $variants, ?array $namedArgumentsVariants, TrinaryLogic $hasSideEffects, ?Type $throwType, Assertions $assertions, ?Type $selfOutType, ?string $phpDocComment) - { - $this->reflectionProvider = $reflectionProvider; - $this->declaringClass = $declaringClass; - $this->reflection = $reflection; - $this->variants = $variants; - $this->namedArgumentsVariants = $namedArgumentsVariants; - $this->hasSideEffects = $hasSideEffects; - $this->throwType = $throwType; - $this->assertions = $assertions; - $this->selfOutType = $selfOutType; - $this->phpDocComment = $phpDocComment; + public function __construct( + private ReflectionProvider $reflectionProvider, + private ClassReflection $declaringClass, + private BuiltinMethodReflection $reflection, + private array $variants, + private ?array $namedArgumentsVariants, + private TrinaryLogic $hasSideEffects, + private ?Type $throwType, + private Assertions $assertions, + private ?Type $selfOutType, + private ?string $phpDocComment, + ) + { } + public function getDeclaringClass(): ClassReflection { return $this->declaringClass; @@ -115,8 +77,19 @@ public function getPrototype(): ClassMemberReflection $tentativeReturnType = TypehintHelper::decideTypeFromReflection($prototypeMethod->getTentativeReturnType()); } - return new MethodPrototypeReflection($prototypeMethod->getName(), $prototypeDeclaringClass, $prototypeMethod->isStatic(), $prototypeMethod->isPrivate(), $prototypeMethod->isPublic(), $prototypeMethod->isAbstract(), $prototypeMethod->isFinal(), $prototypeMethod->isInternal(), $prototypeDeclaringClass->getNativeMethod($prototypeMethod->getName())->getVariants(), $tentativeReturnType); - } catch (ReflectionException $e) { + return new MethodPrototypeReflection( + $prototypeMethod->getName(), + $prototypeDeclaringClass, + $prototypeMethod->isStatic(), + $prototypeMethod->isPrivate(), + $prototypeMethod->isPublic(), + $prototypeMethod->isAbstract(), + $prototypeMethod->isFinal(), + $prototypeMethod->isInternal(), + $prototypeDeclaringClass->getNativeMethod($prototypeMethod->getName())->getVariants(), + $tentativeReturnType, + ); + } catch (ReflectionException) { return $this; } } diff --git a/src/Reflection/Native/NativeParameterReflection.php b/src/Reflection/Native/NativeParameterReflection.php index 4c24e55ac95..219f48069d2 100644 --- a/src/Reflection/Native/NativeParameterReflection.php +++ b/src/Reflection/Native/NativeParameterReflection.php @@ -9,39 +9,17 @@ class NativeParameterReflection implements ParameterReflection { - /** - * @var string - */ - private $name; - /** - * @var bool - */ - private $optional; - /** - * @var Type - */ - private $type; - /** - * @var PassedByReference - */ - private $passedByReference; - /** - * @var bool - */ - private $variadic; - /** - * @var ?Type - */ - private $defaultValue; - public function __construct(string $name, bool $optional, Type $type, PassedByReference $passedByReference, bool $variadic, ?Type $defaultValue) + public function __construct( + private string $name, + private bool $optional, + private Type $type, + private PassedByReference $passedByReference, + private bool $variadic, + private ?Type $defaultValue, + ) { - $this->name = $name; - $this->optional = $optional; - $this->type = $type; - $this->passedByReference = $passedByReference; - $this->variadic = $variadic; - $this->defaultValue = $defaultValue; } + public function getName(): string { return $this->name; @@ -77,7 +55,14 @@ public function getDefaultValue(): ?Type */ public static function __set_state(array $properties): self { - return new self($properties['name'], $properties['optional'], $properties['type'], $properties['passedByReference'], $properties['variadic'], $properties['defaultValue']); + return new self( + $properties['name'], + $properties['optional'], + $properties['type'], + $properties['passedByReference'], + $properties['variadic'], + $properties['defaultValue'], + ); } } diff --git a/src/Reflection/Native/NativeParameterWithPhpDocsReflection.php b/src/Reflection/Native/NativeParameterWithPhpDocsReflection.php index 87aad79bd68..14f79af0168 100644 --- a/src/Reflection/Native/NativeParameterWithPhpDocsReflection.php +++ b/src/Reflection/Native/NativeParameterWithPhpDocsReflection.php @@ -9,54 +9,20 @@ class NativeParameterWithPhpDocsReflection implements ParameterReflectionWithPhpDocs { - /** - * @var string - */ - private $name; - /** - * @var bool - */ - private $optional; - /** - * @var Type - */ - private $type; - /** - * @var Type - */ - private $phpDocType; - /** - * @var Type - */ - private $nativeType; - /** - * @var PassedByReference - */ - private $passedByReference; - /** - * @var bool - */ - private $variadic; - /** - * @var ?Type - */ - private $defaultValue; - /** - * @var ?Type - */ - private $outType; - public function __construct(string $name, bool $optional, Type $type, Type $phpDocType, Type $nativeType, PassedByReference $passedByReference, bool $variadic, ?Type $defaultValue, ?Type $outType) + public function __construct( + private string $name, + private bool $optional, + private Type $type, + private Type $phpDocType, + private Type $nativeType, + private PassedByReference $passedByReference, + private bool $variadic, + private ?Type $defaultValue, + private ?Type $outType, + ) { - $this->name = $name; - $this->optional = $optional; - $this->type = $type; - $this->phpDocType = $phpDocType; - $this->nativeType = $nativeType; - $this->passedByReference = $passedByReference; - $this->variadic = $variadic; - $this->defaultValue = $defaultValue; - $this->outType = $outType; } + public function getName(): string { return $this->name; @@ -107,7 +73,17 @@ public function getOutType(): ?Type */ public static function __set_state(array $properties): self { - return new self($properties['name'], $properties['optional'], $properties['type'], $properties['phpDocType'], $properties['nativeType'], $properties['passedByReference'], $properties['variadic'], $properties['defaultValue'], $properties['outType']); + return new self( + $properties['name'], + $properties['optional'], + $properties['type'], + $properties['phpDocType'], + $properties['nativeType'], + $properties['passedByReference'], + $properties['variadic'], + $properties['defaultValue'], + $properties['outType'], + ); } } diff --git a/src/Reflection/PHPStan/NativeReflectionEnumReturnDynamicReturnTypeExtension.php b/src/Reflection/PHPStan/NativeReflectionEnumReturnDynamicReturnTypeExtension.php index deb4064dc65..d0b71b91a7c 100644 --- a/src/Reflection/PHPStan/NativeReflectionEnumReturnDynamicReturnTypeExtension.php +++ b/src/Reflection/PHPStan/NativeReflectionEnumReturnDynamicReturnTypeExtension.php @@ -14,23 +14,8 @@ class NativeReflectionEnumReturnDynamicReturnTypeExtension implements DynamicMethodReturnTypeExtension { - /** - * @var PhpVersion - */ - private $phpVersion; - /** - * @var string - */ - private $className; - /** - * @var string - */ - private $methodName; - public function __construct(PhpVersion $phpVersion, string $className, string $methodName) + public function __construct(private PhpVersion $phpVersion, private string $className, private string $methodName) { - $this->phpVersion = $phpVersion; - $this->className = $className; - $this->methodName = $methodName; } public function getClass(): string diff --git a/src/Reflection/ParametersAcceptorSelector.php b/src/Reflection/ParametersAcceptorSelector.php index aded5ecca88..054ee15597c 100644 --- a/src/Reflection/ParametersAcceptorSelector.php +++ b/src/Reflection/ParametersAcceptorSelector.php @@ -51,15 +51,20 @@ class ParametersAcceptorSelector * @param T[] $parametersAcceptors * @return T */ - public static function selectSingle(array $parametersAcceptors) : ParametersAcceptor + public static function selectSingle( + array $parametersAcceptors, + ): ParametersAcceptor { $count = count($parametersAcceptors); if ($count === 0) { - throw new ShouldNotHappenException('getVariants() must return at least one variant.'); + throw new ShouldNotHappenException( + 'getVariants() must return at least one variant.', + ); } if ($count !== 1) { throw new ShouldNotHappenException('Multiple variants - use selectFromArgs() instead.'); } + return $parametersAcceptors[0]; } @@ -68,7 +73,12 @@ public static function selectSingle(array $parametersAcceptors) : ParametersAcce * @param ParametersAcceptor[] $parametersAcceptors * @param ParametersAcceptor[]|null $namedArgumentsVariants */ - public static function selectFromArgs(Scope $scope, array $args, array $parametersAcceptors, ?array $namedArgumentsVariants = null) : ParametersAcceptor + public static function selectFromArgs( + Scope $scope, + array $args, + array $parametersAcceptors, + ?array $namedArgumentsVariants = null, + ): ParametersAcceptor { $types = []; $unpack = false; @@ -84,12 +94,26 @@ public static function selectFromArgs(Scope $scope, array $args, array $paramete foreach ($arrayMapArgs as $arg) { $callbackParameters[] = new DummyParameter('item', $scope->getIterableValueType($scope->getType($arg->value)), false, PassedByReference::createNo(), false, null); } - $parameters[0] = new NativeParameterReflection($parameters[0]->getName(), $parameters[0]->isOptional(), new UnionType([ + $parameters[0] = new NativeParameterReflection( + $parameters[0]->getName(), + $parameters[0]->isOptional(), + new UnionType([ new CallableType($callbackParameters, new MixedType(), false), new NullType(), - ]), $parameters[0]->passedByReference(), $parameters[0]->isVariadic(), $parameters[0]->getDefaultValue()); + ]), + $parameters[0]->passedByReference(), + $parameters[0]->isVariadic(), + $parameters[0]->getDefaultValue(), + ); $parametersAcceptors = [ - new FunctionVariant($acceptor->getTemplateTypeMap(), $acceptor->getResolvedTemplateTypeMap(), $parameters, $acceptor->isVariadic(), $acceptor->getReturnType(), $acceptor instanceof ParametersAcceptorWithPhpDocs ? $acceptor->getCallSiteVarianceMap() : TemplateTypeVarianceMap::createEmpty()), + new FunctionVariant( + $acceptor->getTemplateTypeMap(), + $acceptor->getResolvedTemplateTypeMap(), + $parameters, + $acceptor->isVariadic(), + $acceptor->getReturnType(), + $acceptor instanceof ParametersAcceptorWithPhpDocs ? $acceptor->getCallSiteVarianceMap() : TemplateTypeVarianceMap::createEmpty(), + ), ]; } @@ -102,10 +126,24 @@ public static function selectFromArgs(Scope $scope, array $args, array $paramete $acceptor = $parametersAcceptors[0]; $parameters = $acceptor->getParameters(); - $parameters[2] = new NativeParameterReflection($parameters[2]->getName(), $parameters[2]->isOptional(), $optValueType, $parameters[2]->passedByReference(), $parameters[2]->isVariadic(), $parameters[2]->getDefaultValue()); + $parameters[2] = new NativeParameterReflection( + $parameters[2]->getName(), + $parameters[2]->isOptional(), + $optValueType, + $parameters[2]->passedByReference(), + $parameters[2]->isVariadic(), + $parameters[2]->getDefaultValue(), + ); $parametersAcceptors = [ - new FunctionVariant($acceptor->getTemplateTypeMap(), $acceptor->getResolvedTemplateTypeMap(), $parameters, $acceptor->isVariadic(), $acceptor->getReturnType(), $acceptor instanceof ParametersAcceptorWithPhpDocs ? $acceptor->getCallSiteVarianceMap() : TemplateTypeVarianceMap::createEmpty()), + new FunctionVariant( + $acceptor->getTemplateTypeMap(), + $acceptor->getResolvedTemplateTypeMap(), + $parameters, + $acceptor->isVariadic(), + $acceptor->getReturnType(), + $acceptor instanceof ParametersAcceptorWithPhpDocs ? $acceptor->getCallSiteVarianceMap() : TemplateTypeVarianceMap::createEmpty(), + ), ]; } } @@ -130,14 +168,32 @@ public static function selectFromArgs(Scope $scope, array $args, array $paramete $acceptor = $parametersAcceptors[0]; $parameters = $acceptor->getParameters(); - $parameters[1] = new NativeParameterReflection($parameters[1]->getName(), $parameters[1]->isOptional(), new UnionType([ - new CallableType($arrayFilterParameters ?? [ + $parameters[1] = new NativeParameterReflection( + $parameters[1]->getName(), + $parameters[1]->isOptional(), + new UnionType([ + new CallableType( + $arrayFilterParameters ?? [ new DummyParameter('item', $scope->getIterableValueType($scope->getType($args[0]->value)), false, PassedByReference::createNo(), false, null), - ], new BooleanType(), false), + ], + new BooleanType(), + false, + ), new NullType(), - ]), $parameters[1]->passedByReference(), $parameters[1]->isVariadic(), $parameters[1]->getDefaultValue()); + ]), + $parameters[1]->passedByReference(), + $parameters[1]->isVariadic(), + $parameters[1]->getDefaultValue(), + ); $parametersAcceptors = [ - new FunctionVariant($acceptor->getTemplateTypeMap(), $acceptor->getResolvedTemplateTypeMap(), $parameters, $acceptor->isVariadic(), $acceptor->getReturnType(), $acceptor instanceof ParametersAcceptorWithPhpDocs ? $acceptor->getCallSiteVarianceMap() : TemplateTypeVarianceMap::createEmpty()), + new FunctionVariant( + $acceptor->getTemplateTypeMap(), + $acceptor->getResolvedTemplateTypeMap(), + $parameters, + $acceptor->isVariadic(), + $acceptor->getReturnType(), + $acceptor instanceof ParametersAcceptorWithPhpDocs ? $acceptor->getCallSiteVarianceMap() : TemplateTypeVarianceMap::createEmpty(), + ), ]; } @@ -152,18 +208,34 @@ public static function selectFromArgs(Scope $scope, array $args, array $paramete $acceptor = $parametersAcceptors[0]; $parameters = $acceptor->getParameters(); - $parameters[1] = new NativeParameterReflection($parameters[1]->getName(), $parameters[1]->isOptional(), new CallableType($arrayWalkParameters, new MixedType(), false), $parameters[1]->passedByReference(), $parameters[1]->isVariadic(), $parameters[1]->getDefaultValue()); + $parameters[1] = new NativeParameterReflection( + $parameters[1]->getName(), + $parameters[1]->isOptional(), + new CallableType($arrayWalkParameters, new MixedType(), false), + $parameters[1]->passedByReference(), + $parameters[1]->isVariadic(), + $parameters[1]->getDefaultValue(), + ); $parametersAcceptors = [ - new FunctionVariant($acceptor->getTemplateTypeMap(), $acceptor->getResolvedTemplateTypeMap(), $parameters, $acceptor->isVariadic(), $acceptor->getReturnType(), $acceptor instanceof ParametersAcceptorWithPhpDocs ? $acceptor->getCallSiteVarianceMap() : TemplateTypeVarianceMap::createEmpty()), + new FunctionVariant( + $acceptor->getTemplateTypeMap(), + $acceptor->getResolvedTemplateTypeMap(), + $parameters, + $acceptor->isVariadic(), + $acceptor->getReturnType(), + $acceptor instanceof ParametersAcceptorWithPhpDocs ? $acceptor->getCallSiteVarianceMap() : TemplateTypeVarianceMap::createEmpty(), + ), ]; } } + if (count($parametersAcceptors) === 1) { $acceptor = $parametersAcceptors[0]; if (!self::hasAcceptorTemplateOrLateResolvableType($acceptor)) { return $acceptor; } } + $hasName = false; foreach ($args as $i => $arg) { $type = $scope->getType($arg->value); @@ -180,9 +252,11 @@ public static function selectFromArgs(Scope $scope, array $args, array $paramete $types[$index] = $type; } } + if ($hasName && $namedArgumentsVariants !== null) { return self::selectFromTypes($types, $namedArgumentsVariants, $unpack); } + return self::selectFromTypes($types, $parametersAcceptors, $unpack); } @@ -222,16 +296,25 @@ private static function hasTemplateOrLateResolvableType(Type $type): bool * @param array $types * @param ParametersAcceptor[] $parametersAcceptors */ - public static function selectFromTypes(array $types, array $parametersAcceptors, bool $unpack) : ParametersAcceptor + public static function selectFromTypes( + array $types, + array $parametersAcceptors, + bool $unpack, + ): ParametersAcceptor { if (count($parametersAcceptors) === 1) { return GenericParametersAcceptorResolver::resolve($types, $parametersAcceptors[0]); } + if (count($parametersAcceptors) === 0) { - throw new ShouldNotHappenException('getVariants() must return at least one variant.'); + throw new ShouldNotHappenException( + 'getVariants() must return at least one variant.', + ); } + $typesCount = count($types); $acceptableAcceptors = []; + foreach ($parametersAcceptors as $parametersAcceptor) { if ($unpack) { $acceptableAcceptors[] = $parametersAcceptor; @@ -261,12 +344,15 @@ public static function selectFromTypes(array $types, array $parametersAcceptors, $acceptableAcceptors[] = $parametersAcceptor; } + if (count($acceptableAcceptors) === 0) { return GenericParametersAcceptorResolver::resolve($types, self::combineAcceptors($parametersAcceptors)); } + if (count($acceptableAcceptors) === 1) { return GenericParametersAcceptorResolver::resolve($types, $acceptableAcceptors[0]); } + $winningAcceptors = []; $winningCertainty = null; foreach ($acceptableAcceptors as $acceptableAcceptor) { @@ -307,9 +393,11 @@ public static function selectFromTypes(array $types, array $parametersAcceptors, } } } + if (count($winningAcceptors) === 0) { return GenericParametersAcceptorResolver::resolve($types, self::combineAcceptors($acceptableAcceptors)); } + return GenericParametersAcceptorResolver::resolve($types, self::combineAcceptors($winningAcceptors)); } @@ -319,7 +407,9 @@ public static function selectFromTypes(array $types, array $parametersAcceptors, public static function combineAcceptors(array $acceptors): ParametersAcceptorWithPhpDocs { if (count($acceptors) === 0) { - throw new ShouldNotHappenException('getVariants() must return at least one variant.'); + throw new ShouldNotHappenException( + 'getVariants() must return at least one variant.', + ); } if (count($acceptors) === 1) { return self::wrapAcceptor($acceptors[0]); @@ -360,7 +450,17 @@ public static function combineAcceptors(array $acceptors): ParametersAcceptorWit foreach ($acceptor->getParameters() as $i => $parameter) { if (!isset($parameters[$i])) { - $parameters[$i] = new DummyParameterWithPhpDocs($parameter->getName(), $parameter->getType(), $i + 1 > $minimumNumberOfParameters, $parameter->passedByReference(), $parameter->isVariadic(), $parameter->getDefaultValue(), $parameter instanceof ParameterReflectionWithPhpDocs ? $parameter->getNativeType() : new MixedType(), $parameter instanceof ParameterReflectionWithPhpDocs ? $parameter->getPhpDocType() : new MixedType(), $parameter instanceof ParameterReflectionWithPhpDocs ? $parameter->getOutType() : null); + $parameters[$i] = new DummyParameterWithPhpDocs( + $parameter->getName(), + $parameter->getType(), + $i + 1 > $minimumNumberOfParameters, + $parameter->passedByReference(), + $parameter->isVariadic(), + $parameter->getDefaultValue(), + $parameter instanceof ParameterReflectionWithPhpDocs ? $parameter->getNativeType() : new MixedType(), + $parameter instanceof ParameterReflectionWithPhpDocs ? $parameter->getPhpDocType() : new MixedType(), + $parameter instanceof ParameterReflectionWithPhpDocs ? $parameter->getOutType() : null, + ); continue; } @@ -392,7 +492,17 @@ public static function combineAcceptors(array $acceptors): ParametersAcceptorWit $outType = null; } - $parameters[$i] = new DummyParameterWithPhpDocs($parameters[$i]->getName() !== $parameter->getName() ? sprintf('%s|%s', $parameters[$i]->getName(), $parameter->getName()) : $parameter->getName(), $type, $i + 1 > $minimumNumberOfParameters, $parameters[$i]->passedByReference()->combine($parameter->passedByReference()), $isVariadic, $defaultValue, $nativeType, $phpDocType, $outType); + $parameters[$i] = new DummyParameterWithPhpDocs( + $parameters[$i]->getName() !== $parameter->getName() ? sprintf('%s|%s', $parameters[$i]->getName(), $parameter->getName()) : $parameter->getName(), + $type, + $i + 1 > $minimumNumberOfParameters, + $parameters[$i]->passedByReference()->combine($parameter->passedByReference()), + $isVariadic, + $defaultValue, + $nativeType, + $phpDocType, + $outType, + ); if ($isVariadic) { $parameters = array_slice($parameters, 0, $i + 1); @@ -405,7 +515,15 @@ public static function combineAcceptors(array $acceptors): ParametersAcceptorWit $phpDocReturnType = $phpDocReturnTypes === [] ? null : TypeCombinator::union(...$phpDocReturnTypes); $nativeReturnType = $nativeReturnTypes === [] ? null : TypeCombinator::union(...$nativeReturnTypes); - return new FunctionVariantWithPhpDocs(TemplateTypeMap::createEmpty(), null, $parameters, $isVariadic, $returnType, $phpDocReturnType ?? $returnType, $nativeReturnType ?? new MixedType()); + return new FunctionVariantWithPhpDocs( + TemplateTypeMap::createEmpty(), + null, + $parameters, + $isVariadic, + $returnType, + $phpDocReturnType ?? $returnType, + $nativeReturnType ?? new MixedType(), + ); } private static function wrapAcceptor(ParametersAcceptor $acceptor): ParametersAcceptorWithPhpDocs @@ -414,14 +532,31 @@ private static function wrapAcceptor(ParametersAcceptor $acceptor): ParametersAc return $acceptor; } - return new FunctionVariantWithPhpDocs($acceptor->getTemplateTypeMap(), $acceptor->getResolvedTemplateTypeMap(), array_map(static function (ParameterReflection $parameter) : ParameterReflectionWithPhpDocs { - return self::wrapParameter($parameter); - }, $acceptor->getParameters()), $acceptor->isVariadic(), $acceptor->getReturnType(), $acceptor->getReturnType(), new MixedType(), TemplateTypeVarianceMap::createEmpty()); + return new FunctionVariantWithPhpDocs( + $acceptor->getTemplateTypeMap(), + $acceptor->getResolvedTemplateTypeMap(), + array_map(static fn (ParameterReflection $parameter): ParameterReflectionWithPhpDocs => self::wrapParameter($parameter), $acceptor->getParameters()), + $acceptor->isVariadic(), + $acceptor->getReturnType(), + $acceptor->getReturnType(), + new MixedType(), + TemplateTypeVarianceMap::createEmpty(), + ); } private static function wrapParameter(ParameterReflection $parameter): ParameterReflectionWithPhpDocs { - return $parameter instanceof ParameterReflectionWithPhpDocs ? $parameter : new DummyParameterWithPhpDocs($parameter->getName(), $parameter->getType(), $parameter->isOptional(), $parameter->passedByReference(), $parameter->isVariadic(), $parameter->getDefaultValue(), new MixedType(), $parameter->getType(), null); + return $parameter instanceof ParameterReflectionWithPhpDocs ? $parameter : new DummyParameterWithPhpDocs( + $parameter->getName(), + $parameter->getType(), + $parameter->isOptional(), + $parameter->passedByReference(), + $parameter->isVariadic(), + $parameter->getDefaultValue(), + new MixedType(), + $parameter->getType(), + null, + ); } private static function getCurlOptValueType(int $curlOpt): ?Type @@ -603,7 +738,10 @@ private static function getCurlOptValueType(int $curlOpt): ?Type ]; foreach ($nonEmptyStringConstants as $constName) { if (defined($constName) && constant($constName) === $curlOpt) { - return TypeCombinator::intersect(new StringType(), new AccessoryNonEmptyStringType()); + return TypeCombinator::intersect( + new StringType(), + new AccessoryNonEmptyStringType(), + ); } } diff --git a/src/Reflection/PassedByReference.php b/src/Reflection/PassedByReference.php index 908f8f62c6d..d4741bc1b64 100644 --- a/src/Reflection/PassedByReference.php +++ b/src/Reflection/PassedByReference.php @@ -8,20 +8,15 @@ class PassedByReference { - /** - * @var int - */ - private $value; private const NO = 1; private const READS_ARGUMENT = 2; private const CREATES_NEW_VARIABLE = 3; /** @var self[] */ - private static $registry = []; + private static array $registry = []; - private function __construct(int $value) + private function __construct(private int $value) { - $this->value = $value; } private static function create(int $value): self diff --git a/src/Reflection/Php/BuiltinMethodReflection.php b/src/Reflection/Php/BuiltinMethodReflection.php index d3ae34cecd9..d2d55336aa1 100644 --- a/src/Reflection/Php/BuiltinMethodReflection.php +++ b/src/Reflection/Php/BuiltinMethodReflection.php @@ -20,10 +20,7 @@ public function getReflection(): ?ReflectionMethod; public function getFileName(): ?string; - /** - * @return ReflectionClass|ReflectionEnum - */ - public function getDeclaringClass(); + public function getDeclaringClass(): ReflectionClass|ReflectionEnum; public function getStartLine(): ?int; @@ -43,15 +40,9 @@ public function isDeprecated(): TrinaryLogic; public function isVariadic(): bool; - /** - * @return ReflectionIntersectionType|ReflectionNamedType|ReflectionUnionType|null - */ - public function getReturnType(); + public function getReturnType(): ReflectionIntersectionType|ReflectionNamedType|ReflectionUnionType|null; - /** - * @return ReflectionIntersectionType|ReflectionNamedType|ReflectionUnionType|null - */ - public function getTentativeReturnType(); + public function getTentativeReturnType(): ReflectionIntersectionType|ReflectionNamedType|ReflectionUnionType|null; /** * @return ReflectionParameter[] diff --git a/src/Reflection/Php/ClosureCallMethodReflection.php b/src/Reflection/Php/ClosureCallMethodReflection.php index 9308bb1dbdc..e51c1e75ecd 100644 --- a/src/Reflection/Php/ClosureCallMethodReflection.php +++ b/src/Reflection/Php/ClosureCallMethodReflection.php @@ -23,19 +23,13 @@ final class ClosureCallMethodReflection implements ExtendedMethodReflection { - /** - * @var ExtendedMethodReflection - */ - private $nativeMethodReflection; - /** - * @var ClosureType - */ - private $closureType; - public function __construct(ExtendedMethodReflection $nativeMethodReflection, ClosureType $closureType) - { - $this->nativeMethodReflection = $nativeMethodReflection; - $this->closureType = $closureType; + public function __construct( + private ExtendedMethodReflection $nativeMethodReflection, + private ClosureType $closureType, + ) + { } + public function getDeclaringClass(): ClassReflection { return $this->nativeMethodReflection->getDeclaringClass(); @@ -74,14 +68,38 @@ public function getPrototype(): ClassMemberReflection public function getVariants(): array { $parameters = $this->closureType->getParameters(); - $newThis = new NativeParameterReflection('newThis', false, new ObjectWithoutClassType(), PassedByReference::createNo(), false, null); + $newThis = new NativeParameterReflection( + 'newThis', + false, + new ObjectWithoutClassType(), + PassedByReference::createNo(), + false, + null, + ); array_unshift($parameters, $newThis); return [ - new FunctionVariantWithPhpDocs($this->closureType->getTemplateTypeMap(), $this->closureType->getResolvedTemplateTypeMap(), array_map(static function (ParameterReflection $parameter) : ParameterReflectionWithPhpDocs { - return new DummyParameterWithPhpDocs($parameter->getName(), $parameter->getType(), $parameter->isOptional(), $parameter->passedByReference(), $parameter->isVariadic(), $parameter->getDefaultValue(), new MixedType(), $parameter->getType(), null); - }, $parameters), $this->closureType->isVariadic(), $this->closureType->getReturnType(), $this->closureType->getReturnType(), new MixedType(), $this->closureType->getCallSiteVarianceMap()), + new FunctionVariantWithPhpDocs( + $this->closureType->getTemplateTypeMap(), + $this->closureType->getResolvedTemplateTypeMap(), + array_map(static fn (ParameterReflection $parameter): ParameterReflectionWithPhpDocs => new DummyParameterWithPhpDocs( + $parameter->getName(), + $parameter->getType(), + $parameter->isOptional(), + $parameter->passedByReference(), + $parameter->isVariadic(), + $parameter->getDefaultValue(), + new MixedType(), + $parameter->getType(), + null, + ), $parameters), + $this->closureType->isVariadic(), + $this->closureType->getReturnType(), + $this->closureType->getReturnType(), + new MixedType(), + $this->closureType->getCallSiteVarianceMap(), + ), ]; } diff --git a/src/Reflection/Php/ClosureCallUnresolvedMethodPrototypeReflection.php b/src/Reflection/Php/ClosureCallUnresolvedMethodPrototypeReflection.php index a063e9b44cb..bd3c9b54ed5 100644 --- a/src/Reflection/Php/ClosureCallUnresolvedMethodPrototypeReflection.php +++ b/src/Reflection/Php/ClosureCallUnresolvedMethodPrototypeReflection.php @@ -10,18 +10,8 @@ class ClosureCallUnresolvedMethodPrototypeReflection implements UnresolvedMethodPrototypeReflection { - /** - * @var UnresolvedMethodPrototypeReflection - */ - private $prototype; - /** - * @var ClosureType - */ - private $closure; - public function __construct(UnresolvedMethodPrototypeReflection $prototype, ClosureType $closure) + public function __construct(private UnresolvedMethodPrototypeReflection $prototype, private ClosureType $closure) { - $this->prototype = $prototype; - $this->closure = $closure; } public function doNotResolveTemplateTypeMapToBounds(): UnresolvedMethodPrototypeReflection diff --git a/src/Reflection/Php/DummyParameter.php b/src/Reflection/Php/DummyParameter.php index 837cbbddcc1..5d73990a42c 100644 --- a/src/Reflection/Php/DummyParameter.php +++ b/src/Reflection/Php/DummyParameter.php @@ -9,38 +9,10 @@ class DummyParameter implements ParameterReflection { - /** - * @var string - */ - private $name; - /** - * @var Type - */ - private $type; - /** - * @var bool - */ - private $optional; - /** - * @var bool - */ - private $variadic; - /** - * @var ?Type - */ - private $defaultValue; - /** - * @var PassedByReference - */ - private $passedByReference; + private PassedByReference $passedByReference; - public function __construct(string $name, Type $type, bool $optional, ?PassedByReference $passedByReference, bool $variadic, ?Type $defaultValue) + public function __construct(private string $name, private Type $type, private bool $optional, ?PassedByReference $passedByReference, private bool $variadic, private ?Type $defaultValue) { - $this->name = $name; - $this->type = $type; - $this->optional = $optional; - $this->variadic = $variadic; - $this->defaultValue = $defaultValue; $this->passedByReference = $passedByReference ?? PassedByReference::createNo(); } diff --git a/src/Reflection/Php/DummyParameterWithPhpDocs.php b/src/Reflection/Php/DummyParameterWithPhpDocs.php index ff0c1f3f33a..e1b4df10dfd 100644 --- a/src/Reflection/Php/DummyParameterWithPhpDocs.php +++ b/src/Reflection/Php/DummyParameterWithPhpDocs.php @@ -9,25 +9,21 @@ class DummyParameterWithPhpDocs extends DummyParameter implements ParameterReflectionWithPhpDocs { - /** - * @var Type - */ - private $nativeType; - /** - * @var Type - */ - private $phpDocType; - /** - * @var ?Type - */ - private $outType; - public function __construct(string $name, Type $type, bool $optional, ?PassedByReference $passedByReference, bool $variadic, ?Type $defaultValue, Type $nativeType, Type $phpDocType, ?Type $outType) + public function __construct( + string $name, + Type $type, + bool $optional, + ?PassedByReference $passedByReference, + bool $variadic, + ?Type $defaultValue, + private Type $nativeType, + private Type $phpDocType, + private ?Type $outType, + ) { - $this->nativeType = $nativeType; - $this->phpDocType = $phpDocType; - $this->outType = $outType; parent::__construct($name, $type, $optional, $passedByReference, $variadic, $defaultValue); } + public function getPhpDocType(): Type { return $this->phpDocType; diff --git a/src/Reflection/Php/EnumCasesMethodReflection.php b/src/Reflection/Php/EnumCasesMethodReflection.php index 885870c651e..246901ae133 100644 --- a/src/Reflection/Php/EnumCasesMethodReflection.php +++ b/src/Reflection/Php/EnumCasesMethodReflection.php @@ -16,18 +16,8 @@ class EnumCasesMethodReflection implements ExtendedMethodReflection { - /** - * @var ClassReflection - */ - private $declaringClass; - /** - * @var Type - */ - private $returnType; - public function __construct(ClassReflection $declaringClass, Type $returnType) + public function __construct(private ClassReflection $declaringClass, private Type $returnType) { - $this->declaringClass = $declaringClass; - $this->returnType = $returnType; } public function getDeclaringClass(): ClassReflection @@ -73,7 +63,15 @@ public function getPrototype(): ClassMemberReflection public function getVariants(): array { return [ - new FunctionVariantWithPhpDocs(TemplateTypeMap::createEmpty(), TemplateTypeMap::createEmpty(), [], false, $this->returnType, new MixedType(), $this->returnType), + new FunctionVariantWithPhpDocs( + TemplateTypeMap::createEmpty(), + TemplateTypeMap::createEmpty(), + [], + false, + $this->returnType, + new MixedType(), + $this->returnType, + ), ]; } diff --git a/src/Reflection/Php/EnumPropertyReflection.php b/src/Reflection/Php/EnumPropertyReflection.php index 739b490bdf2..e3f7927dec9 100644 --- a/src/Reflection/Php/EnumPropertyReflection.php +++ b/src/Reflection/Php/EnumPropertyReflection.php @@ -10,18 +10,8 @@ class EnumPropertyReflection implements PropertyReflection { - /** - * @var ClassReflection - */ - private $declaringClass; - /** - * @var Type - */ - private $type; - public function __construct(ClassReflection $declaringClass, Type $type) + public function __construct(private ClassReflection $declaringClass, private Type $type) { - $this->declaringClass = $declaringClass; - $this->type = $type; } public function getDeclaringClass(): ClassReflection diff --git a/src/Reflection/Php/EnumUnresolvedPropertyPrototypeReflection.php b/src/Reflection/Php/EnumUnresolvedPropertyPrototypeReflection.php index 50ceff78634..5d76711ce46 100644 --- a/src/Reflection/Php/EnumUnresolvedPropertyPrototypeReflection.php +++ b/src/Reflection/Php/EnumUnresolvedPropertyPrototypeReflection.php @@ -9,13 +9,8 @@ class EnumUnresolvedPropertyPrototypeReflection implements UnresolvedPropertyPrototypeReflection { - /** - * @var EnumPropertyReflection - */ - private $property; - public function __construct(EnumPropertyReflection $property) + public function __construct(private EnumPropertyReflection $property) { - $this->property = $property; } public function doNotResolveTemplateTypeMapToBounds(): UnresolvedPropertyPrototypeReflection diff --git a/src/Reflection/Php/NativeBuiltinMethodReflection.php b/src/Reflection/Php/NativeBuiltinMethodReflection.php index 805b0197e79..2f10d431c50 100644 --- a/src/Reflection/Php/NativeBuiltinMethodReflection.php +++ b/src/Reflection/Php/NativeBuiltinMethodReflection.php @@ -14,13 +14,8 @@ class NativeBuiltinMethodReflection implements BuiltinMethodReflection { - /** - * @var ReflectionMethod - */ - private $reflection; - public function __construct(ReflectionMethod $reflection) + public function __construct(private ReflectionMethod $reflection) { - $this->reflection = $reflection; } public function getName(): string @@ -43,10 +38,7 @@ public function getFileName(): ?string return $fileName; } - /** - * @return ReflectionClass|ReflectionEnum - */ - public function getDeclaringClass() + public function getDeclaringClass(): ReflectionClass|ReflectionEnum { return $this->reflection->getDeclaringClass(); } @@ -131,18 +123,12 @@ public function isVariadic(): bool return $this->reflection->isVariadic(); } - /** - * @return ReflectionIntersectionType|ReflectionNamedType|ReflectionUnionType|null - */ - public function getReturnType() + public function getReturnType(): ReflectionIntersectionType|ReflectionNamedType|ReflectionUnionType|null { return $this->reflection->getReturnType(); } - /** - * @return ReflectionIntersectionType|ReflectionNamedType|ReflectionUnionType|null - */ - public function getTentativeReturnType() + public function getTentativeReturnType(): ReflectionIntersectionType|ReflectionNamedType|ReflectionUnionType|null { return $this->reflection->getTentativeReturnType(); } diff --git a/src/Reflection/Php/PhpClassReflectionExtension.php b/src/Reflection/Php/PhpClassReflectionExtension.php index e8f560b710c..321ee288ee3 100644 --- a/src/Reflection/Php/PhpClassReflectionExtension.php +++ b/src/Reflection/Php/PhpClassReflectionExtension.php @@ -64,86 +64,39 @@ class PhpClassReflectionExtension implements PropertiesClassReflectionExtension, MethodsClassReflectionExtension { - /** - * @var ScopeFactory - */ - private $scopeFactory; - /** - * @var NodeScopeResolver - */ - private $nodeScopeResolver; - /** - * @var PhpMethodReflectionFactory - */ - private $methodReflectionFactory; - /** - * @var PhpDocInheritanceResolver - */ - private $phpDocInheritanceResolver; - /** - * @var AnnotationsMethodsClassReflectionExtension - */ - private $annotationsMethodsClassReflectionExtension; - /** - * @var AnnotationsPropertiesClassReflectionExtension - */ - private $annotationsPropertiesClassReflectionExtension; - /** - * @var SignatureMapProvider - */ - private $signatureMapProvider; - /** - * @var Parser - */ - private $parser; - /** - * @var StubPhpDocProvider - */ - private $stubPhpDocProvider; - /** - * @var ReflectionProvider\ReflectionProviderProvider - */ - private $reflectionProviderProvider; - /** - * @var FileTypeMapper - */ - private $fileTypeMapper; - /** - * @var bool - */ - private $inferPrivatePropertyTypeFromConstructor; /** @var PropertyReflection[][] */ - private $propertiesIncludingAnnotations = []; + private array $propertiesIncludingAnnotations = []; /** @var PhpPropertyReflection[][] */ - private $nativeProperties = []; + private array $nativeProperties = []; /** @var ExtendedMethodReflection[][] */ - private $methodsIncludingAnnotations = []; + private array $methodsIncludingAnnotations = []; /** @var ExtendedMethodReflection[][] */ - private $nativeMethods = []; + private array $nativeMethods = []; /** @var array> */ - private $propertyTypesCache = []; + private array $propertyTypesCache = []; /** @var array */ - private $inferClassConstructorPropertyTypesInProcess = []; - - public function __construct(ScopeFactory $scopeFactory, NodeScopeResolver $nodeScopeResolver, PhpMethodReflectionFactory $methodReflectionFactory, PhpDocInheritanceResolver $phpDocInheritanceResolver, AnnotationsMethodsClassReflectionExtension $annotationsMethodsClassReflectionExtension, AnnotationsPropertiesClassReflectionExtension $annotationsPropertiesClassReflectionExtension, SignatureMapProvider $signatureMapProvider, Parser $parser, StubPhpDocProvider $stubPhpDocProvider, ReflectionProvider\ReflectionProviderProvider $reflectionProviderProvider, FileTypeMapper $fileTypeMapper, bool $inferPrivatePropertyTypeFromConstructor) + private array $inferClassConstructorPropertyTypesInProcess = []; + + public function __construct( + private ScopeFactory $scopeFactory, + private NodeScopeResolver $nodeScopeResolver, + private PhpMethodReflectionFactory $methodReflectionFactory, + private PhpDocInheritanceResolver $phpDocInheritanceResolver, + private AnnotationsMethodsClassReflectionExtension $annotationsMethodsClassReflectionExtension, + private AnnotationsPropertiesClassReflectionExtension $annotationsPropertiesClassReflectionExtension, + private SignatureMapProvider $signatureMapProvider, + private Parser $parser, + private StubPhpDocProvider $stubPhpDocProvider, + private ReflectionProvider\ReflectionProviderProvider $reflectionProviderProvider, + private FileTypeMapper $fileTypeMapper, + private bool $inferPrivatePropertyTypeFromConstructor, + ) { - $this->scopeFactory = $scopeFactory; - $this->nodeScopeResolver = $nodeScopeResolver; - $this->methodReflectionFactory = $methodReflectionFactory; - $this->phpDocInheritanceResolver = $phpDocInheritanceResolver; - $this->annotationsMethodsClassReflectionExtension = $annotationsMethodsClassReflectionExtension; - $this->annotationsPropertiesClassReflectionExtension = $annotationsPropertiesClassReflectionExtension; - $this->signatureMapProvider = $signatureMapProvider; - $this->parser = $parser; - $this->stubPhpDocProvider = $stubPhpDocProvider; - $this->reflectionProviderProvider = $reflectionProviderProvider; - $this->fileTypeMapper = $fileTypeMapper; - $this->inferPrivatePropertyTypeFromConstructor = $inferPrivatePropertyTypeFromConstructor; } public function evictPrivateSymbols(string $classCacheKey): void @@ -219,15 +172,24 @@ public function getNativeProperty(ClassReflection $classReflection, string $prop return $this->nativeProperties[$classReflection->getCacheKey()][$propertyName]; } - private function createProperty(ClassReflection $classReflection, string $propertyName, bool $includingAnnotations) : PropertyReflection + private function createProperty( + ClassReflection $classReflection, + string $propertyName, + bool $includingAnnotations, + ): PropertyReflection { $propertyReflection = $classReflection->getNativeReflection()->getProperty($propertyName); $propertyName = $propertyReflection->getName(); $declaringClassName = $propertyReflection->getDeclaringClass()->getName(); $declaringClassReflection = $classReflection->getAncestorWithClassName($declaringClassName); if ($declaringClassReflection === null) { - throw new ShouldNotHappenException(sprintf('Internal error: Expected to find an ancestor with class name %s on %s, but none was found.', $declaringClassName, $classReflection->getName())); + throw new ShouldNotHappenException(sprintf( + 'Internal error: Expected to find an ancestor with class name %s on %s, but none was found.', + $declaringClassName, + $classReflection->getName(), + )); } + if ($declaringClassReflection->isEnum()) { if ( $propertyName === 'name' @@ -252,11 +214,13 @@ private function createProperty(ClassReflection $classReflection, string $proper return new PhpPropertyReflection($declaringClassReflection, null, null, TypeCombinator::union(...$types), $classReflection->getNativeReflection()->getProperty($propertyName), null, false, false, false, false); } } + $deprecatedDescription = null; $isDeprecated = false; $isInternal = false; $isReadOnlyByPhpDoc = $classReflection->isImmutable(); $isAllowedPrivateMutation = false; + if ( $includingAnnotations && !$declaringClassReflection->isEnum() @@ -281,9 +245,11 @@ private function createProperty(ClassReflection $classReflection, string $proper return $annotationProperty; } } + $docComment = $propertyReflection->getDocComment() !== false ? $propertyReflection->getDocComment() : null; + $phpDocType = null; $resolvedPhpDoc = null; $declaringTraitName = $this->findPropertyTrait($propertyReflection); @@ -293,12 +259,26 @@ private function createProperty(ClassReflection $classReflection, string $proper $constructorName = $declaringClassReflection->getConstructor()->getName(); } } + if ($constructorName === null) { - $resolvedPhpDoc = $this->phpDocInheritanceResolver->resolvePhpDocForProperty($docComment, $declaringClassReflection, $declaringClassReflection->getFileName(), $declaringTraitName, $propertyName); + $resolvedPhpDoc = $this->phpDocInheritanceResolver->resolvePhpDocForProperty( + $docComment, + $declaringClassReflection, + $declaringClassReflection->getFileName(), + $declaringTraitName, + $propertyName, + ); } elseif ($docComment !== null) { - $resolvedPhpDoc = $this->fileTypeMapper->getResolvedPhpDoc($declaringClassReflection->getFileName(), $declaringClassName, $declaringTraitName, $constructorName, $docComment); + $resolvedPhpDoc = $this->fileTypeMapper->getResolvedPhpDoc( + $declaringClassReflection->getFileName(), + $declaringClassName, + $declaringTraitName, + $constructorName, + $docComment, + ); } $phpDocBlockClassReflection = $declaringClassReflection; + if ($resolvedPhpDoc !== null) { $varTags = $resolvedPhpDoc->getVarTags(); if (isset($varTags[0]) && count($varTags) === 1) { @@ -307,30 +287,42 @@ private function createProperty(ClassReflection $classReflection, string $proper $phpDocType = $varTags[$propertyName]->getType(); } - $phpDocType = $phpDocType !== null ? TemplateTypeHelper::resolveTemplateTypes($phpDocType, $phpDocBlockClassReflection->getActiveTemplateTypeMap(), $phpDocBlockClassReflection->getCallSiteVarianceMap(), TemplateTypeVariance::createInvariant()) : null; + $phpDocType = $phpDocType !== null ? TemplateTypeHelper::resolveTemplateTypes( + $phpDocType, + $phpDocBlockClassReflection->getActiveTemplateTypeMap(), + $phpDocBlockClassReflection->getCallSiteVarianceMap(), + TemplateTypeVariance::createInvariant(), + ) : null; $deprecatedDescription = $resolvedPhpDoc->getDeprecatedTag() !== null ? $resolvedPhpDoc->getDeprecatedTag()->getMessage() : null; $isDeprecated = $resolvedPhpDoc->isDeprecated(); $isInternal = $resolvedPhpDoc->isInternal(); $isReadOnlyByPhpDoc = $isReadOnlyByPhpDoc || $resolvedPhpDoc->isReadOnly(); $isAllowedPrivateMutation = $resolvedPhpDoc->isAllowedPrivateMutation(); } + if ($phpDocType === null) { if (isset($constructorName)) { $constructorDocComment = $declaringClassReflection->getConstructor()->getDocComment(); $nativeClassReflection = $declaringClassReflection->getNativeReflection(); $positionalParameterNames = []; if ($nativeClassReflection->getConstructor() !== null) { - $positionalParameterNames = array_map(static function (ReflectionParameter $parameter) : string { - return $parameter->getName(); - }, $nativeClassReflection->getConstructor()->getParameters()); + $positionalParameterNames = array_map(static fn (ReflectionParameter $parameter): string => $parameter->getName(), $nativeClassReflection->getConstructor()->getParameters()); } - $resolvedConstructorPhpDoc = $this->phpDocInheritanceResolver->resolvePhpDocForMethod($constructorDocComment, $declaringClassReflection->getFileName(), $declaringClassReflection, $declaringTraitName, $constructorName, $positionalParameterNames); + $resolvedConstructorPhpDoc = $this->phpDocInheritanceResolver->resolvePhpDocForMethod( + $constructorDocComment, + $declaringClassReflection->getFileName(), + $declaringClassReflection, + $declaringTraitName, + $constructorName, + $positionalParameterNames, + ); $paramTags = $resolvedConstructorPhpDoc->getParamTags(); if (isset($paramTags[$propertyReflection->getName()])) { $phpDocType = $paramTags[$propertyReflection->getName()]->getType(); } } } + if ( $phpDocType === null && $this->inferPrivatePropertyTypeFromConstructor @@ -341,12 +333,17 @@ private function createProperty(ClassReflection $classReflection, string $proper && $declaringClassReflection->hasConstructor() && $declaringClassReflection->getConstructor()->getDeclaringClass()->getName() === $declaringClassReflection->getName() ) { - $phpDocType = $this->inferPrivatePropertyType($propertyReflection->getName(), $declaringClassReflection->getConstructor()); + $phpDocType = $this->inferPrivatePropertyType( + $propertyReflection->getName(), + $declaringClassReflection->getConstructor(), + ); } + $nativeType = null; if ($propertyReflection->getType() !== null) { $nativeType = $propertyReflection->getType(); } + $declaringTrait = null; $reflectionProvider = $this->reflectionProviderProvider->getReflectionProvider(); if ( @@ -354,7 +351,19 @@ private function createProperty(ClassReflection $classReflection, string $proper ) { $declaringTrait = $reflectionProvider->getClass($declaringTraitName); } - return new PhpPropertyReflection($declaringClassReflection, $declaringTrait, $nativeType, $phpDocType, $propertyReflection, $deprecatedDescription, $isDeprecated, $isInternal, $isReadOnlyByPhpDoc, $isAllowedPrivateMutation); + + return new PhpPropertyReflection( + $declaringClassReflection, + $declaringTrait, + $nativeType, + $phpDocType, + $propertyReflection, + $deprecatedDescription, + $isDeprecated, + $isInternal, + $isReadOnlyByPhpDoc, + $isAllowedPrivateMutation, + ); } public function hasMethod(ClassReflection $classReflection, string $methodName): bool @@ -409,7 +418,11 @@ public function getNativeMethod(ClassReflection $classReflection, string $method return $this->nativeMethods[$classReflection->getCacheKey()][$nativeMethodReflection->getName()]; } - private function createMethod(ClassReflection $classReflection, BuiltinMethodReflection $methodReflection, bool $includingAnnotations) : ExtendedMethodReflection + private function createMethod( + ClassReflection $classReflection, + BuiltinMethodReflection $methodReflection, + bool $includingAnnotations, + ): ExtendedMethodReflection { if ($includingAnnotations && $this->annotationsMethodsClassReflectionExtension->hasMethod($classReflection, $methodReflection->getName())) { $hierarchyDistances = $classReflection->getClassHierarchyDistances(); @@ -433,9 +446,15 @@ private function createMethod(ClassReflection $classReflection, BuiltinMethodRef } $declaringClassName = $methodReflection->getDeclaringClass()->getName(); $declaringClass = $classReflection->getAncestorWithClassName($declaringClassName); + if ($declaringClass === null) { - throw new ShouldNotHappenException(sprintf('Internal error: Expected to find an ancestor with class name %s on %s, but none was found.', $declaringClassName, $classReflection->getName())); + throw new ShouldNotHappenException(sprintf( + 'Internal error: Expected to find an ancestor with class name %s on %s, but none was found.', + $declaringClassName, + $classReflection->getName(), + )); } + if ( $declaringClass->isEnum() && $declaringClass->getName() !== 'UnitEnum' @@ -448,6 +467,7 @@ private function createMethod(ClassReflection $classReflection, BuiltinMethodRef return new EnumCasesMethodReflection($declaringClass, $arrayBuilder->getArray()); } + if ($this->signatureMapProvider->hasMethodSignature($declaringClassName, $methodReflection->getName())) { $variantsByType = ['positional' => []]; $reflectionMethod = null; @@ -478,20 +498,28 @@ private function createMethod(ClassReflection $classReflection, BuiltinMethodRef $stubPhpParameterOutTypes = []; $phpDocParameterOutTypes = []; if (count($methodSignatures) === 1) { - $stubPhpDocPair = $this->findMethodPhpDocIncludingAncestors($declaringClass, $methodReflection->getName(), array_map(static function (ParameterSignature $parameterSignature) : string { - return $parameterSignature->getName(); - }, $methodSignature->getParameters())); + $stubPhpDocPair = $this->findMethodPhpDocIncludingAncestors($declaringClass, $methodReflection->getName(), array_map(static fn (ParameterSignature $parameterSignature): string => $parameterSignature->getName(), $methodSignature->getParameters())); if ($stubPhpDocPair !== null) { [$stubPhpDoc, $stubDeclaringClass] = $stubPhpDocPair; $templateTypeMap = $stubDeclaringClass->getActiveTemplateTypeMap(); $callSiteVarianceMap = $stubDeclaringClass->getCallSiteVarianceMap(); $returnTag = $stubPhpDoc->getReturnTag(); if ($returnTag !== null) { - $stubPhpDocReturnType = TemplateTypeHelper::resolveTemplateTypes($returnTag->getType(), $templateTypeMap, $callSiteVarianceMap, TemplateTypeVariance::createCovariant()); + $stubPhpDocReturnType = TemplateTypeHelper::resolveTemplateTypes( + $returnTag->getType(), + $templateTypeMap, + $callSiteVarianceMap, + TemplateTypeVariance::createCovariant(), + ); } foreach ($stubPhpDoc->getParamTags() as $name => $paramTag) { - $stubPhpDocParameterTypes[$name] = TemplateTypeHelper::resolveTemplateTypes($paramTag->getType(), $templateTypeMap, $callSiteVarianceMap, TemplateTypeVariance::createContravariant()); + $stubPhpDocParameterTypes[$name] = TemplateTypeHelper::resolveTemplateTypes( + $paramTag->getType(), + $templateTypeMap, + $callSiteVarianceMap, + TemplateTypeVariance::createContravariant(), + ); $stubPhpDocParameterVariadicity[$name] = $paramTag->isVariadic(); } @@ -508,7 +536,12 @@ private function createMethod(ClassReflection $classReflection, BuiltinMethodRef } foreach ($stubPhpDoc->getParamOutTags() as $name => $paramOutTag) { - $stubPhpParameterOutTypes[$name] = TemplateTypeHelper::resolveTemplateTypes($paramOutTag->getType(), $templateTypeMap, $callSiteVarianceMap, TemplateTypeVariance::createCovariant()); + $stubPhpParameterOutTypes[$name] = TemplateTypeHelper::resolveTemplateTypes( + $paramOutTag->getType(), + $templateTypeMap, + $callSiteVarianceMap, + TemplateTypeVariance::createCovariant(), + ); } if ($declaringClassName === $stubDeclaringClass->getName() && $stubPhpDoc->hasPhpDocString()) { @@ -519,7 +552,13 @@ private function createMethod(ClassReflection $classReflection, BuiltinMethodRef if ($stubPhpDocPair === null && $reflectionMethod !== null && $reflectionMethod->getDocComment() !== false) { $filename = $reflectionMethod->getFileName(); if ($filename !== false) { - $phpDocBlock = $this->fileTypeMapper->getResolvedPhpDoc($filename, $declaringClassName, null, $reflectionMethod->getName(), $reflectionMethod->getDocComment()); + $phpDocBlock = $this->fileTypeMapper->getResolvedPhpDoc( + $filename, + $declaringClassName, + null, + $reflectionMethod->getName(), + $reflectionMethod->getDocComment(), + ); $throwsTag = $phpDocBlock->getThrowsTag(); if ($throwsTag !== null) { $throwType = $throwsTag->getType(); @@ -565,17 +604,32 @@ private function createMethod(ClassReflection $classReflection, BuiltinMethodRef } else { $hasSideEffects = TrinaryLogic::createMaybe(); } - return new NativeMethodReflection($this->reflectionProviderProvider->getReflectionProvider(), $declaringClass, $methodReflection, $variantsByType['positional'], $variantsByType['named'] ?? null, $hasSideEffects, $throwType, $asserts, $selfOutType, $phpDocComment); + return new NativeMethodReflection( + $this->reflectionProviderProvider->getReflectionProvider(), + $declaringClass, + $methodReflection, + $variantsByType['positional'], + $variantsByType['named'] ?? null, + $hasSideEffects, + $throwType, + $asserts, + $selfOutType, + $phpDocComment, + ); } - return $this->createUserlandMethodReflection($declaringClass, $declaringClass, $methodReflection, $this->findMethodTrait($methodReflection)); + + return $this->createUserlandMethodReflection( + $declaringClass, + $declaringClass, + $methodReflection, + $this->findMethodTrait($methodReflection), + ); } public function createUserlandMethodReflection(ClassReflection $fileDeclaringClass, ClassReflection $actualDeclaringClass, BuiltinMethodReflection $methodReflection, ?string $declaringTraitName): PhpMethodReflection { $resolvedPhpDoc = null; - $stubPhpDocPair = $this->findMethodPhpDocIncludingAncestors($fileDeclaringClass, $methodReflection->getName(), array_map(static function (ReflectionParameter $parameter) : string { - return $parameter->getName(); - }, $methodReflection->getParameters())); + $stubPhpDocPair = $this->findMethodPhpDocIncludingAncestors($fileDeclaringClass, $methodReflection->getName(), array_map(static fn (ReflectionParameter $parameter): string => $parameter->getName(), $methodReflection->getParameters())); $phpDocBlockClassReflection = $fileDeclaringClass; if ($methodReflection->getReflection() !== null) { @@ -583,9 +637,14 @@ public function createUserlandMethodReflection(ClassReflection $fileDeclaringCla if ($stubPhpDocPair === null && $methodDeclaringClass->isTrait()) { if (! $methodReflection->getDeclaringClass()->isTrait() || $methodDeclaringClass->getName() !== $methodReflection->getDeclaringClass()->getName()) { - $stubPhpDocPair = $this->findMethodPhpDocIncludingAncestors($this->reflectionProviderProvider->getReflectionProvider()->getClass($methodDeclaringClass->getName()), $methodReflection->getName(), array_map(static function (ReflectionParameter $parameter) : string { - return $parameter->getName(); - }, $methodReflection->getParameters())); + $stubPhpDocPair = $this->findMethodPhpDocIncludingAncestors( + $this->reflectionProviderProvider->getReflectionProvider()->getClass($methodDeclaringClass->getName()), + $methodReflection->getName(), + array_map( + static fn (ReflectionParameter $parameter): string => $parameter->getName(), + $methodReflection->getParameters(), + ), + ); } } } @@ -596,11 +655,16 @@ public function createUserlandMethodReflection(ClassReflection $fileDeclaringCla if ($resolvedPhpDoc === null) { $docComment = $methodReflection->getDocComment(); - $positionalParameterNames = array_map(static function (ReflectionParameter $parameter) : string { - return $parameter->getName(); - }, $methodReflection->getParameters()); - - $resolvedPhpDoc = $this->phpDocInheritanceResolver->resolvePhpDocForMethod($docComment, $fileDeclaringClass->getFileName(), $fileDeclaringClass, $declaringTraitName, $methodReflection->getName(), $positionalParameterNames); + $positionalParameterNames = array_map(static fn (ReflectionParameter $parameter): string => $parameter->getName(), $methodReflection->getParameters()); + + $resolvedPhpDoc = $this->phpDocInheritanceResolver->resolvePhpDocForMethod( + $docComment, + $fileDeclaringClass->getFileName(), + $fileDeclaringClass, + $declaringTraitName, + $methodReflection->getName(), + $positionalParameterNames, + ); $phpDocBlockClassReflection = $fileDeclaringClass; } @@ -634,7 +698,13 @@ public function createUserlandMethodReflection(ClassReflection $fileDeclaringCla continue; } - $propertyDocblock = $this->fileTypeMapper->getResolvedPhpDoc($fileDeclaringClass->getFileName(), $fileDeclaringClass->getName(), $declaringTraitName, $methodReflection->getName(), $parameterProperty->getDocComment()); + $propertyDocblock = $this->fileTypeMapper->getResolvedPhpDoc( + $fileDeclaringClass->getFileName(), + $fileDeclaringClass->getName(), + $declaringTraitName, + $methodReflection->getName(), + $parameterProperty->getDocComment(), + ); $varTags = $propertyDocblock->getVarTags(); if (isset($varTags[0]) && count($varTags) === 1) { $phpDocType = $varTags[0]->getType(); @@ -657,15 +727,29 @@ public function createUserlandMethodReflection(ClassReflection $fileDeclaringCla $phpDocParameterTypes[$paramName] = $paramTag->getType(); } foreach ($phpDocParameterTypes as $paramName => $paramType) { - $phpDocParameterTypes[$paramName] = TemplateTypeHelper::resolveTemplateTypes($paramType, $phpDocBlockClassReflection->getActiveTemplateTypeMap(), $phpDocBlockClassReflection->getCallSiteVarianceMap(), TemplateTypeVariance::createContravariant()); + $phpDocParameterTypes[$paramName] = TemplateTypeHelper::resolveTemplateTypes( + $paramType, + $phpDocBlockClassReflection->getActiveTemplateTypeMap(), + $phpDocBlockClassReflection->getCallSiteVarianceMap(), + TemplateTypeVariance::createContravariant(), + ); } $phpDocParameterOutTypes = []; foreach ($resolvedPhpDoc->getParamOutTags() as $paramName => $paramOutTag) { - $phpDocParameterOutTypes[$paramName] = TemplateTypeHelper::resolveTemplateTypes($paramOutTag->getType(), $phpDocBlockClassReflection->getActiveTemplateTypeMap(), $phpDocBlockClassReflection->getCallSiteVarianceMap(), TemplateTypeVariance::createCovariant()); + $phpDocParameterOutTypes[$paramName] = TemplateTypeHelper::resolveTemplateTypes( + $paramOutTag->getType(), + $phpDocBlockClassReflection->getActiveTemplateTypeMap(), + $phpDocBlockClassReflection->getCallSiteVarianceMap(), + TemplateTypeVariance::createCovariant(), + ); } - $nativeReturnType = TypehintHelper::decideTypeFromReflection($methodReflection->getReturnType(), null, $actualDeclaringClass); + $nativeReturnType = TypehintHelper::decideTypeFromReflection( + $methodReflection->getReturnType(), + null, + $actualDeclaringClass, + ); $phpDocReturnType = $this->getPhpDocReturnType($phpDocBlockClassReflection, $resolvedPhpDoc, $nativeReturnType); $phpDocThrowType = $resolvedPhpDoc->getThrowsTag() !== null ? $resolvedPhpDoc->getThrowsTag()->getType() : null; $deprecatedDescription = $resolvedPhpDoc->getDeprecatedTag() !== null ? $resolvedPhpDoc->getDeprecatedTag()->getMessage() : null; @@ -680,7 +764,24 @@ public function createUserlandMethodReflection(ClassReflection $fileDeclaringCla $phpDocComment = $resolvedPhpDoc->getPhpDocString(); } - return $this->methodReflectionFactory->create($actualDeclaringClass, $declaringTrait, $methodReflection, $templateTypeMap, $phpDocParameterTypes, $phpDocReturnType, $phpDocThrowType, $deprecatedDescription, $isDeprecated, $isInternal, $isFinal, $isPure, $asserts, $selfOutType, $phpDocComment, $phpDocParameterOutTypes); + return $this->methodReflectionFactory->create( + $actualDeclaringClass, + $declaringTrait, + $methodReflection, + $templateTypeMap, + $phpDocParameterTypes, + $phpDocReturnType, + $phpDocThrowType, + $deprecatedDescription, + $isDeprecated, + $isInternal, + $isFinal, + $isPure, + $asserts, + $selfOutType, + $phpDocComment, + $phpDocParameterOutTypes, + ); } /** @@ -691,7 +792,18 @@ public function createUserlandMethodReflection(ClassReflection $fileDeclaringCla * @param array $stubPhpDocParameterOutTypes * @param array $phpDocParameterOutTypes */ - private function createNativeMethodVariant(FunctionSignature $methodSignature, array $stubPhpDocParameterTypes, array $stubPhpDocParameterVariadicity, ?Type $stubPhpDocReturnType, array $phpDocParameterTypes, ?Type $phpDocReturnType, array $phpDocParameterNameMapping, array $stubPhpDocParameterOutTypes, array $phpDocParameterOutTypes, bool $usePhpDocParameterNames) : FunctionVariantWithPhpDocs + private function createNativeMethodVariant( + FunctionSignature $methodSignature, + array $stubPhpDocParameterTypes, + array $stubPhpDocParameterVariadicity, + ?Type $stubPhpDocReturnType, + array $phpDocParameterTypes, + ?Type $phpDocReturnType, + array $phpDocParameterNameMapping, + array $stubPhpDocParameterOutTypes, + array $phpDocParameterOutTypes, + bool $usePhpDocParameterNames, + ): FunctionVariantWithPhpDocs { $parameters = []; foreach ($methodSignature->getParameters() as $parameterSignature) { @@ -714,17 +826,37 @@ private function createNativeMethodVariant(FunctionSignature $methodSignature, a $parameterOutType = $phpDocParameterOutTypes[$phpDocParameterName]; } - $parameters[] = new NativeParameterWithPhpDocsReflection($usePhpDocParameterNames + $parameters[] = new NativeParameterWithPhpDocsReflection( + $usePhpDocParameterNames ? $phpDocParameterName - : $parameterSignature->getName(), $parameterSignature->isOptional(), $type ?? $parameterSignature->getType(), $phpDocType ?? new MixedType(), $parameterSignature->getNativeType(), $parameterSignature->passedByReference(), $stubPhpDocParameterVariadicity[$parameterSignature->getName()] ?? $parameterSignature->isVariadic(), $parameterSignature->getDefaultValue(), $parameterOutType ?? $parameterSignature->getOutType()); + : $parameterSignature->getName(), + $parameterSignature->isOptional(), + $type ?? $parameterSignature->getType(), + $phpDocType ?? new MixedType(), + $parameterSignature->getNativeType(), + $parameterSignature->passedByReference(), + $stubPhpDocParameterVariadicity[$parameterSignature->getName()] ?? $parameterSignature->isVariadic(), + $parameterSignature->getDefaultValue(), + $parameterOutType ?? $parameterSignature->getOutType(), + ); } + if ($stubPhpDocReturnType !== null) { $returnType = $stubPhpDocReturnType; $phpDocReturnType = $stubPhpDocReturnType; } else { $returnType = TypehintHelper::decideType($methodSignature->getReturnType(), $phpDocReturnType); } - return new FunctionVariantWithPhpDocs(TemplateTypeMap::createEmpty(), null, $parameters, $methodSignature->isVariadic(), $returnType, $phpDocReturnType ?? new MixedType(), $methodSignature->getNativeReturnType()); + + return new FunctionVariantWithPhpDocs( + TemplateTypeMap::createEmpty(), + null, + $parameters, + $methodSignature->isVariadic(), + $returnType, + $phpDocReturnType ?? new MixedType(), + $methodSignature->getNativeReturnType(), + ); } private function findPropertyTrait(ReflectionProperty $propertyReflection): ?string @@ -741,11 +873,14 @@ private function findPropertyTrait(ReflectionProperty $propertyReflection): ?str return null; } - private function findMethodTrait(BuiltinMethodReflection $methodReflection) : ?string + private function findMethodTrait( + BuiltinMethodReflection $methodReflection, + ): ?string { if ($methodReflection->getReflection() === null) { return null; } + $declaringClass = $methodReflection->getReflection()->getBetterReflection()->getDeclaringClass(); if ($declaringClass->isTrait()) { if ($methodReflection->getDeclaringClass()->isTrait() && $declaringClass->getName() === $methodReflection->getDeclaringClass()->getName()) { @@ -754,10 +889,14 @@ private function findMethodTrait(BuiltinMethodReflection $methodReflection) : ?s return $declaringClass->getName(); } + return null; } - private function inferPrivatePropertyType(string $propertyName, MethodReflection $constructor) : ?Type + private function inferPrivatePropertyType( + string $propertyName, + MethodReflection $constructor, + ): ?Type { $declaringClassName = $constructor->getDeclaringClass()->getName(); if (isset($this->inferClassConstructorPropertyTypesInProcess[$declaringClassName])) { @@ -769,13 +908,16 @@ private function inferPrivatePropertyType(string $propertyName, MethodReflection if (array_key_exists($propertyName, $propertyTypes)) { return $propertyTypes[$propertyName]; } + return null; } /** * @return array */ - private function inferAndCachePropertyTypes(MethodReflection $constructor) : array + private function inferAndCachePropertyTypes( + MethodReflection $constructor, + ): array { $declaringClass = $constructor->getDeclaringClass(); if (isset($this->propertyTypesCache[$declaringClass->getName()])) { @@ -784,28 +926,49 @@ private function inferAndCachePropertyTypes(MethodReflection $constructor) : arr if ($declaringClass->getFileName() === null) { return $this->propertyTypesCache[$declaringClass->getName()] = []; } + $fileName = $declaringClass->getFileName(); $nodes = $this->parser->parseFile($fileName); $classNode = $this->findClassNode($declaringClass->getName(), $nodes); if ($classNode === null) { return $this->propertyTypesCache[$declaringClass->getName()] = []; } + $methodNode = $this->findConstructorNode($constructor->getName(), $classNode->stmts); if ($methodNode === null || $methodNode->stmts === null || count($methodNode->stmts) === 0) { return $this->propertyTypesCache[$declaringClass->getName()] = []; } + $classNameParts = explode('\\', $declaringClass->getName()); $namespace = null; if (count($classNameParts) > 1) { $namespace = implode('\\', array_slice($classNameParts, 0, -1)); } + $classScope = $this->scopeFactory->create(ScopeContext::create($fileName)); if ($namespace !== null) { $classScope = $classScope->enterNamespace($namespace); } $classScope = $classScope->enterClass($declaringClass); [$templateTypeMap, $phpDocParameterTypes, $phpDocReturnType, $phpDocThrowType, $deprecatedDescription, $isDeprecated, $isInternal, $isFinal, $isPure, $acceptsNamedArguments, , $phpDocComment, $asserts, $selfOutType, $phpDocParameterOutTypes] = $this->nodeScopeResolver->getPhpDocs($classScope, $methodNode); - $methodScope = $classScope->enterClassMethod($methodNode, $templateTypeMap, $phpDocParameterTypes, $phpDocReturnType, $phpDocThrowType, $deprecatedDescription, $isDeprecated, $isInternal, $isFinal, $isPure, $acceptsNamedArguments, $asserts, $selfOutType, $phpDocComment, $phpDocParameterOutTypes); + $methodScope = $classScope->enterClassMethod( + $methodNode, + $templateTypeMap, + $phpDocParameterTypes, + $phpDocReturnType, + $phpDocThrowType, + $deprecatedDescription, + $isDeprecated, + $isInternal, + $isFinal, + $isPure, + $acceptsNamedArguments, + $asserts, + $selfOutType, + $phpDocComment, + $phpDocParameterOutTypes, + ); + $propertyTypes = []; foreach ($methodNode->stmts as $statement) { if (!$statement instanceof Node\Stmt\Expression) { @@ -842,6 +1005,7 @@ private function inferAndCachePropertyTypes(MethodReflection $constructor) : arr $propertyTypes[$propertyFetch->name->toString()] = $propertyType; } + return $this->propertyTypesCache[$declaringClass->getName()] = $propertyTypes; } @@ -905,7 +1069,12 @@ private function getPhpDocReturnType(ClassReflection $phpDocBlockClassReflection } $phpDocReturnType = $returnTag->getType(); - $phpDocReturnType = TemplateTypeHelper::resolveTemplateTypes($phpDocReturnType, $phpDocBlockClassReflection->getActiveTemplateTypeMap(), $phpDocBlockClassReflection->getCallSiteVarianceMap(), TemplateTypeVariance::createCovariant()); + $phpDocReturnType = TemplateTypeHelper::resolveTemplateTypes( + $phpDocReturnType, + $phpDocBlockClassReflection->getActiveTemplateTypeMap(), + $phpDocBlockClassReflection->getCallSiteVarianceMap(), + TemplateTypeVariance::createCovariant(), + ); if ($returnTag->isExplicit() || $nativeReturnType->isSuperTypeOf($phpDocReturnType)->yes()) { return $phpDocReturnType; diff --git a/src/Reflection/Php/PhpFunctionFromParserNodeReflection.php b/src/Reflection/Php/PhpFunctionFromParserNodeReflection.php index 62924277482..05b4c39ac3b 100644 --- a/src/Reflection/Php/PhpFunctionFromParserNodeReflection.php +++ b/src/Reflection/Php/PhpFunctionFromParserNodeReflection.php @@ -29,79 +29,11 @@ class PhpFunctionFromParserNodeReflection implements FunctionReflection { - /** - * @var string - */ - private $fileName; - /** - * @var TemplateTypeMap - */ - private $templateTypeMap; - /** - * @var Type[] - */ - private $realParameterTypes; - /** - * @var Type[] - */ - private $phpDocParameterTypes; - /** - * @var Type[] - */ - private $realParameterDefaultValues; - /** - * @var Type - */ - private $realReturnType; - /** - * @var ?Type - */ - private $phpDocReturnType; - /** - * @var ?Type - */ - private $throwType; - /** - * @var ?string - */ - private $deprecatedDescription; - /** - * @var bool - */ - private $isDeprecated; - /** - * @var bool - */ - private $isInternal; - /** - * @var bool - */ - private $isFinal; - /** - * @var ?bool - */ - private $isPure; - /** - * @var bool - */ - private $acceptsNamedArguments; - /** - * @var Assertions - */ - private $assertions; - /** - * @var ?string - */ - private $phpDocComment; - /** - * @var Type[] - */ - private $parameterOutTypes; /** @var Function_|ClassMethod */ - private $functionLike; + private Node\FunctionLike $functionLike; /** @var FunctionVariantWithPhpDocs[]|null */ - private $variants = null; + private ?array $variants = null; /** * @param Function_|ClassMethod $functionLike @@ -110,25 +42,27 @@ class PhpFunctionFromParserNodeReflection implements FunctionReflection * @param Type[] $realParameterDefaultValues * @param Type[] $parameterOutTypes */ - public function __construct(FunctionLike $functionLike, string $fileName, TemplateTypeMap $templateTypeMap, array $realParameterTypes, array $phpDocParameterTypes, array $realParameterDefaultValues, Type $realReturnType, ?Type $phpDocReturnType, ?Type $throwType, ?string $deprecatedDescription, bool $isDeprecated, bool $isInternal, bool $isFinal, ?bool $isPure, bool $acceptsNamedArguments, Assertions $assertions, ?string $phpDocComment, array $parameterOutTypes) + public function __construct( + FunctionLike $functionLike, + private string $fileName, + private TemplateTypeMap $templateTypeMap, + private array $realParameterTypes, + private array $phpDocParameterTypes, + private array $realParameterDefaultValues, + private Type $realReturnType, + private ?Type $phpDocReturnType, + private ?Type $throwType, + private ?string $deprecatedDescription, + private bool $isDeprecated, + private bool $isInternal, + private bool $isFinal, + private ?bool $isPure, + private bool $acceptsNamedArguments, + private Assertions $assertions, + private ?string $phpDocComment, + private array $parameterOutTypes, + ) { - $this->fileName = $fileName; - $this->templateTypeMap = $templateTypeMap; - $this->realParameterTypes = $realParameterTypes; - $this->phpDocParameterTypes = $phpDocParameterTypes; - $this->realParameterDefaultValues = $realParameterDefaultValues; - $this->realReturnType = $realReturnType; - $this->phpDocReturnType = $phpDocReturnType; - $this->throwType = $throwType; - $this->deprecatedDescription = $deprecatedDescription; - $this->isDeprecated = $isDeprecated; - $this->isInternal = $isInternal; - $this->isFinal = $isFinal; - $this->isPure = $isPure; - $this->acceptsNamedArguments = $acceptsNamedArguments; - $this->assertions = $assertions; - $this->phpDocComment = $phpDocComment; - $this->parameterOutTypes = $parameterOutTypes; $this->functionLike = $functionLike; } @@ -162,7 +96,15 @@ public function getVariants(): array { if ($this->variants === null) { $this->variants = [ - new FunctionVariantWithPhpDocs($this->templateTypeMap, null, $this->getParameters(), $this->isVariadic(), $this->getReturnType(), $this->phpDocReturnType ?? new MixedType(), $this->realReturnType), + new FunctionVariantWithPhpDocs( + $this->templateTypeMap, + null, + $this->getParameters(), + $this->isVariadic(), + $this->getReturnType(), + $this->phpDocReturnType ?? new MixedType(), + $this->realReturnType, + ), ]; } @@ -191,9 +133,18 @@ private function getParameters(): array if (!$parameter->var instanceof Variable || !is_string($parameter->var->name)) { throw new ShouldNotHappenException(); } - $parameters[] = new PhpParameterFromParserNodeReflection($parameter->var->name, $isOptional, $this->realParameterTypes[$parameter->var->name], $this->phpDocParameterTypes[$parameter->var->name] ?? null, $parameter->byRef + $parameters[] = new PhpParameterFromParserNodeReflection( + $parameter->var->name, + $isOptional, + $this->realParameterTypes[$parameter->var->name], + $this->phpDocParameterTypes[$parameter->var->name] ?? null, + $parameter->byRef ? PassedByReference::createCreatesNewVariable() - : PassedByReference::createNo(), $this->realParameterDefaultValues[$parameter->var->name] ?? null, $parameter->variadic, $this->parameterOutTypes[$parameter->var->name] ?? null); + : PassedByReference::createNo(), + $this->realParameterDefaultValues[$parameter->var->name] ?? null, + $parameter->variadic, + $this->parameterOutTypes[$parameter->var->name] ?? null, + ); } return array_reverse($parameters); diff --git a/src/Reflection/Php/PhpFunctionReflection.php b/src/Reflection/Php/PhpFunctionReflection.php index a566bd191a2..17ae2baed73 100644 --- a/src/Reflection/Php/PhpFunctionReflection.php +++ b/src/Reflection/Php/PhpFunctionReflection.php @@ -33,105 +33,34 @@ class PhpFunctionReflection implements FunctionReflection { - /** - * @var InitializerExprTypeResolver - */ - private $initializerExprTypeResolver; - /** - * @var ReflectionFunction - */ - private $reflection; - /** - * @var Parser - */ - private $parser; - /** - * @var FunctionCallStatementFinder - */ - private $functionCallStatementFinder; - /** - * @var Cache - */ - private $cache; - /** - * @var TemplateTypeMap - */ - private $templateTypeMap; - /** - * @var Type[] - */ - private $phpDocParameterTypes; - /** - * @var ?Type - */ - private $phpDocReturnType; - /** - * @var ?Type - */ - private $phpDocThrowType; - /** - * @var ?string - */ - private $deprecatedDescription; - /** - * @var bool - */ - private $isDeprecated; - /** - * @var bool - */ - private $isInternal; - /** - * @var bool - */ - private $isFinal; - /** - * @var ?string - */ - private $filename; - /** - * @var ?bool - */ - private $isPure; - /** - * @var Assertions - */ - private $asserts; - /** - * @var ?string - */ - private $phpDocComment; - /** - * @var Type[] - */ - private $phpDocParameterOutTypes; /** @var FunctionVariantWithPhpDocs[]|null */ - private $variants = null; + private ?array $variants = null; /** * @param Type[] $phpDocParameterTypes * @param Type[] $phpDocParameterOutTypes */ - public function __construct(InitializerExprTypeResolver $initializerExprTypeResolver, ReflectionFunction $reflection, Parser $parser, FunctionCallStatementFinder $functionCallStatementFinder, Cache $cache, TemplateTypeMap $templateTypeMap, array $phpDocParameterTypes, ?Type $phpDocReturnType, ?Type $phpDocThrowType, ?string $deprecatedDescription, bool $isDeprecated, bool $isInternal, bool $isFinal, ?string $filename, ?bool $isPure, Assertions $asserts, ?string $phpDocComment, array $phpDocParameterOutTypes) + public function __construct( + private InitializerExprTypeResolver $initializerExprTypeResolver, + private ReflectionFunction $reflection, + private Parser $parser, + private FunctionCallStatementFinder $functionCallStatementFinder, + private Cache $cache, + private TemplateTypeMap $templateTypeMap, + private array $phpDocParameterTypes, + private ?Type $phpDocReturnType, + private ?Type $phpDocThrowType, + private ?string $deprecatedDescription, + private bool $isDeprecated, + private bool $isInternal, + private bool $isFinal, + private ?string $filename, + private ?bool $isPure, + private Assertions $asserts, + private ?string $phpDocComment, + private array $phpDocParameterOutTypes, + ) { - $this->initializerExprTypeResolver = $initializerExprTypeResolver; - $this->reflection = $reflection; - $this->parser = $parser; - $this->functionCallStatementFinder = $functionCallStatementFinder; - $this->cache = $cache; - $this->templateTypeMap = $templateTypeMap; - $this->phpDocParameterTypes = $phpDocParameterTypes; - $this->phpDocReturnType = $phpDocReturnType; - $this->phpDocThrowType = $phpDocThrowType; - $this->deprecatedDescription = $deprecatedDescription; - $this->isDeprecated = $isDeprecated; - $this->isInternal = $isInternal; - $this->isFinal = $isFinal; - $this->filename = $filename; - $this->isPure = $isPure; - $this->asserts = $asserts; - $this->phpDocComment = $phpDocComment; - $this->phpDocParameterOutTypes = $phpDocParameterOutTypes; } public function getName(): string @@ -159,7 +88,15 @@ public function getVariants(): array { if ($this->variants === null) { $this->variants = [ - new FunctionVariantWithPhpDocs($this->templateTypeMap, null, $this->getParameters(), $this->isVariadic(), $this->getReturnType(), $this->getPhpDocReturnType(), $this->getNativeReturnType()), + new FunctionVariantWithPhpDocs( + $this->templateTypeMap, + null, + $this->getParameters(), + $this->isVariadic(), + $this->getReturnType(), + $this->getPhpDocReturnType(), + $this->getNativeReturnType(), + ), ]; } @@ -176,9 +113,13 @@ public function getNamedArgumentsVariants(): ?array */ private function getParameters(): array { - return array_map(function (ReflectionParameter $reflection) : PhpParameterReflection { - return new PhpParameterReflection($this->initializerExprTypeResolver, $reflection, $this->phpDocParameterTypes[$reflection->getName()] ?? null, null, $this->phpDocParameterOutTypes[$reflection->getName()] ?? null); - }, $this->reflection->getParameters()); + return array_map(fn (ReflectionParameter $reflection): PhpParameterReflection => new PhpParameterReflection( + $this->initializerExprTypeResolver, + $reflection, + $this->phpDocParameterTypes[$reflection->getName()] ?? null, + null, + $this->phpDocParameterOutTypes[$reflection->getName()] ?? null, + ), $this->reflection->getParameters()); } private function isVariadic(): bool @@ -250,7 +191,10 @@ private function callsFuncGetArgs(array $nodes): bool private function getReturnType(): Type { - return TypehintHelper::decideTypeFromReflection($this->reflection->getReturnType(), $this->phpDocReturnType); + return TypehintHelper::decideTypeFromReflection( + $this->reflection->getReturnType(), + $this->phpDocReturnType, + ); } private function getPhpDocReturnType(): Type @@ -278,7 +222,9 @@ public function getDeprecatedDescription(): ?string public function isDeprecated(): TrinaryLogic { - return TrinaryLogic::createFromBoolean($this->isDeprecated || $this->reflection->isDeprecated()); + return TrinaryLogic::createFromBoolean( + $this->isDeprecated || $this->reflection->isDeprecated(), + ); } public function isInternal(): TrinaryLogic diff --git a/src/Reflection/Php/PhpMethodFromParserNodeReflection.php b/src/Reflection/Php/PhpMethodFromParserNodeReflection.php index bab2205a352..f04d2bac38c 100644 --- a/src/Reflection/Php/PhpMethodFromParserNodeReflection.php +++ b/src/Reflection/Php/PhpMethodFromParserNodeReflection.php @@ -30,53 +30,89 @@ class PhpMethodFromParserNodeReflection extends PhpFunctionFromParserNodeReflect { /** - * @var ClassReflection - */ - private $declaringClass; - /** - * @var ?Type - */ - private $selfOutType; - /** - * @param Type[] $realParameterTypes - * @param Type[] $phpDocParameterTypes - * @param Type[] $realParameterDefaultValues - */ - public function __construct(ClassReflection $declaringClass, ClassMethod $classMethod, string $fileName, TemplateTypeMap $templateTypeMap, array $realParameterTypes, array $phpDocParameterTypes, array $realParameterDefaultValues, Type $realReturnType, ?Type $phpDocReturnType, ?Type $throwType, ?string $deprecatedDescription, bool $isDeprecated, bool $isInternal, bool $isFinal, ?bool $isPure, bool $acceptsNamedArguments, Assertions $assertions, ?Type $selfOutType, ?string $phpDocComment, array $parameterOutTypes) - { - $this->declaringClass = $declaringClass; - $this->selfOutType = $selfOutType; - $name = strtolower($classMethod->name->name); - if (in_array($name, ['__construct', '__destruct', '__unset', '__wakeup', '__clone'], true)) { - $realReturnType = new VoidType(); - } - if ($name === '__tostring') { - $realReturnType = new StringType(); - } - if ($name === '__isset') { - $realReturnType = new BooleanType(); - } - if ($name === '__sleep') { - $realReturnType = new ArrayType(new IntegerType(), new StringType()); - } - if ($name === '__set_state') { - $realReturnType = TypeCombinator::intersect(new ObjectWithoutClassType(), $realReturnType); - } - if ($name === '__set') { - $realReturnType = new VoidType(); - } - if ($name === '__debuginfo') { - $realReturnType = TypeCombinator::intersect(TypeCombinator::addNull(new ArrayType(new MixedType(true), new MixedType(true))), $realReturnType); - } - if ($name === '__unserialize') { - $realReturnType = new VoidType(); - } - if ($name === '__serialize') { - $realReturnType = new ArrayType(new MixedType(true), new MixedType(true)); - } - parent::__construct($classMethod, $fileName, $templateTypeMap, $realParameterTypes, $phpDocParameterTypes, $realParameterDefaultValues, $realReturnType, $phpDocReturnType, $throwType, $deprecatedDescription, $isDeprecated, $isInternal, $isFinal || $classMethod->isFinal(), $isPure, $acceptsNamedArguments, $assertions, $phpDocComment, $parameterOutTypes); - } - public function getDeclaringClass(): ClassReflection + * @param Type[] $realParameterTypes + * @param Type[] $phpDocParameterTypes + * @param Type[] $realParameterDefaultValues + */ + public function __construct( + private ClassReflection $declaringClass, + ClassMethod $classMethod, + string $fileName, + TemplateTypeMap $templateTypeMap, + array $realParameterTypes, + array $phpDocParameterTypes, + array $realParameterDefaultValues, + Type $realReturnType, + ?Type $phpDocReturnType, + ?Type $throwType, + ?string $deprecatedDescription, + bool $isDeprecated, + bool $isInternal, + bool $isFinal, + ?bool $isPure, + bool $acceptsNamedArguments, + Assertions $assertions, + private ?Type $selfOutType, + ?string $phpDocComment, + array $parameterOutTypes, + ) + { + $name = strtolower($classMethod->name->name); + if (in_array($name, ['__construct', '__destruct', '__unset', '__wakeup', '__clone'], true)) { + $realReturnType = new VoidType(); + } + if ($name === '__tostring') { + $realReturnType = new StringType(); + } + if ($name === '__isset') { + $realReturnType = new BooleanType(); + } + if ($name === '__sleep') { + $realReturnType = new ArrayType(new IntegerType(), new StringType()); + } + if ($name === '__set_state') { + $realReturnType = TypeCombinator::intersect(new ObjectWithoutClassType(), $realReturnType); + } + if ($name === '__set') { + $realReturnType = new VoidType(); + } + + if ($name === '__debuginfo') { + $realReturnType = TypeCombinator::intersect(TypeCombinator::addNull( + new ArrayType(new MixedType(true), new MixedType(true)), + ), $realReturnType); + } + + if ($name === '__unserialize') { + $realReturnType = new VoidType(); + } + if ($name === '__serialize') { + $realReturnType = new ArrayType(new MixedType(true), new MixedType(true)); + } + + parent::__construct( + $classMethod, + $fileName, + $templateTypeMap, + $realParameterTypes, + $phpDocParameterTypes, + $realParameterDefaultValues, + $realReturnType, + $phpDocReturnType, + $throwType, + $deprecatedDescription, + $isDeprecated, + $isInternal, + $isFinal || $classMethod->isFinal(), + $isPure, + $acceptsNamedArguments, + $assertions, + $phpDocComment, + $parameterOutTypes, + ); + } + + public function getDeclaringClass(): ClassReflection { return $this->declaringClass; } @@ -85,7 +121,7 @@ public function getPrototype(): ClassMemberReflection { try { return $this->declaringClass->getNativeMethod($this->getClassMethod()->name->name)->getPrototype(); - } catch (MissingMethodFromReflectionException $e) { + } catch (MissingMethodFromReflectionException) { return $this; } } diff --git a/src/Reflection/Php/PhpMethodReflection.php b/src/Reflection/Php/PhpMethodReflection.php index 2ae94d71d27..b374e9e6f76 100644 --- a/src/Reflection/Php/PhpMethodReflection.php +++ b/src/Reflection/Php/PhpMethodReflection.php @@ -48,133 +48,44 @@ class PhpMethodReflection implements ExtendedMethodReflection { - /** - * @var InitializerExprTypeResolver - */ - private $initializerExprTypeResolver; - /** - * @var ClassReflection - */ - private $declaringClass; - /** - * @var ?ClassReflection - */ - private $declaringTrait; - /** - * @var BuiltinMethodReflection - */ - private $reflection; - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - /** - * @var Parser - */ - private $parser; - /** - * @var FunctionCallStatementFinder - */ - private $functionCallStatementFinder; - /** - * @var Cache - */ - private $cache; - /** - * @var TemplateTypeMap - */ - private $templateTypeMap; - /** - * @var Type[] - */ - private $phpDocParameterTypes; - /** - * @var ?Type - */ - private $phpDocReturnType; - /** - * @var ?Type - */ - private $phpDocThrowType; - /** - * @var ?string - */ - private $deprecatedDescription; - /** - * @var bool - */ - private $isDeprecated; - /** - * @var bool - */ - private $isInternal; - /** - * @var bool - */ - private $isFinal; - /** - * @var ?bool - */ - private $isPure; - /** - * @var Assertions - */ - private $asserts; - /** - * @var ?Type - */ - private $selfOutType; - /** - * @var ?string - */ - private $phpDocComment; - /** - * @var Type[] - */ - private $phpDocParameterOutTypes; /** @var PhpParameterReflection[]|null */ - private $parameters = null; + private ?array $parameters = null; - /** - * @var ?Type - */ - private $returnType = null; + private ?Type $returnType = null; - /** - * @var ?Type - */ - private $nativeReturnType = null; + private ?Type $nativeReturnType = null; /** @var FunctionVariantWithPhpDocs[]|null */ - private $variants = null; + private ?array $variants = null; /** * @param Type[] $phpDocParameterTypes * @param Type[] $phpDocParameterOutTypes */ - public function __construct(InitializerExprTypeResolver $initializerExprTypeResolver, ClassReflection $declaringClass, ?ClassReflection $declaringTrait, BuiltinMethodReflection $reflection, ReflectionProvider $reflectionProvider, Parser $parser, FunctionCallStatementFinder $functionCallStatementFinder, Cache $cache, TemplateTypeMap $templateTypeMap, array $phpDocParameterTypes, ?Type $phpDocReturnType, ?Type $phpDocThrowType, ?string $deprecatedDescription, bool $isDeprecated, bool $isInternal, bool $isFinal, ?bool $isPure, Assertions $asserts, ?Type $selfOutType, ?string $phpDocComment, array $phpDocParameterOutTypes) + public function __construct( + private InitializerExprTypeResolver $initializerExprTypeResolver, + private ClassReflection $declaringClass, + private ?ClassReflection $declaringTrait, + private BuiltinMethodReflection $reflection, + private ReflectionProvider $reflectionProvider, + private Parser $parser, + private FunctionCallStatementFinder $functionCallStatementFinder, + private Cache $cache, + private TemplateTypeMap $templateTypeMap, + private array $phpDocParameterTypes, + private ?Type $phpDocReturnType, + private ?Type $phpDocThrowType, + private ?string $deprecatedDescription, + private bool $isDeprecated, + private bool $isInternal, + private bool $isFinal, + private ?bool $isPure, + private Assertions $asserts, + private ?Type $selfOutType, + private ?string $phpDocComment, + private array $phpDocParameterOutTypes, + ) { - $this->initializerExprTypeResolver = $initializerExprTypeResolver; - $this->declaringClass = $declaringClass; - $this->declaringTrait = $declaringTrait; - $this->reflection = $reflection; - $this->reflectionProvider = $reflectionProvider; - $this->parser = $parser; - $this->functionCallStatementFinder = $functionCallStatementFinder; - $this->cache = $cache; - $this->templateTypeMap = $templateTypeMap; - $this->phpDocParameterTypes = $phpDocParameterTypes; - $this->phpDocReturnType = $phpDocReturnType; - $this->phpDocThrowType = $phpDocThrowType; - $this->deprecatedDescription = $deprecatedDescription; - $this->isDeprecated = $isDeprecated; - $this->isInternal = $isInternal; - $this->isFinal = $isFinal; - $this->isPure = $isPure; - $this->asserts = $asserts; - $this->selfOutType = $selfOutType; - $this->phpDocComment = $phpDocComment; - $this->phpDocParameterOutTypes = $phpDocParameterOutTypes; } public function getDeclaringClass(): ClassReflection @@ -204,8 +115,19 @@ public function getPrototype(): ClassMemberReflection $tentativeReturnType = TypehintHelper::decideTypeFromReflection($prototypeMethod->getTentativeReturnType()); } - return new MethodPrototypeReflection($prototypeMethod->getName(), $prototypeDeclaringClass, $prototypeMethod->isStatic(), $prototypeMethod->isPrivate(), $prototypeMethod->isPublic(), $prototypeMethod->isAbstract(), $prototypeMethod->isFinal(), $prototypeMethod->isInternal(), $prototypeDeclaringClass->getNativeMethod($prototypeMethod->getName())->getVariants(), $tentativeReturnType); - } catch (ReflectionException $e) { + return new MethodPrototypeReflection( + $prototypeMethod->getName(), + $prototypeDeclaringClass, + $prototypeMethod->isStatic(), + $prototypeMethod->isPrivate(), + $prototypeMethod->isPublic(), + $prototypeMethod->isAbstract(), + $prototypeMethod->isFinal(), + $prototypeMethod->isInternal(), + $prototypeDeclaringClass->getNativeMethod($prototypeMethod->getName())->getVariants(), + $tentativeReturnType, + ); + } catch (ReflectionException) { return $this; } } @@ -262,7 +184,15 @@ public function getVariants(): array { if ($this->variants === null) { $this->variants = [ - new FunctionVariantWithPhpDocs($this->templateTypeMap, null, $this->getParameters(), $this->isVariadic(), $this->getReturnType(), $this->getPhpDocReturnType(), $this->getNativeReturnType()), + new FunctionVariantWithPhpDocs( + $this->templateTypeMap, + null, + $this->getParameters(), + $this->isVariadic(), + $this->getReturnType(), + $this->getPhpDocReturnType(), + $this->getNativeReturnType(), + ), ]; } @@ -280,9 +210,13 @@ public function getNamedArgumentsVariants(): ?array private function getParameters(): array { if ($this->parameters === null) { - $this->parameters = array_map(function (ReflectionParameter $reflection) : PhpParameterReflection { - return new PhpParameterReflection($this->initializerExprTypeResolver, $reflection, $this->phpDocParameterTypes[$reflection->getName()] ?? null, $this->getDeclaringClass()->getName(), $this->phpDocParameterOutTypes[$reflection->getName()] ?? null); - }, $this->reflection->getParameters()); + $this->parameters = array_map(fn (ReflectionParameter $reflection): PhpParameterReflection => new PhpParameterReflection( + $this->initializerExprTypeResolver, + $reflection, + $this->phpDocParameterTypes[$reflection->getName()] ?? null, + $this->getDeclaringClass()->getName(), + $this->phpDocParameterOutTypes[$reflection->getName()] ?? null, + ), $this->reflection->getParameters()); } return $this->parameters; @@ -409,7 +343,11 @@ private function getReturnType(): Type } } - $this->returnType = TypehintHelper::decideTypeFromReflection($returnType, $this->phpDocReturnType, $this->declaringClass); + $this->returnType = TypehintHelper::decideTypeFromReflection( + $returnType, + $this->phpDocReturnType, + $this->declaringClass, + ); } return $this->returnType; @@ -427,7 +365,11 @@ private function getPhpDocReturnType(): Type private function getNativeReturnType(): Type { if ($this->nativeReturnType === null) { - $this->nativeReturnType = TypehintHelper::decideTypeFromReflection($this->reflection->getReturnType(), null, $this->declaringClass); + $this->nativeReturnType = TypehintHelper::decideTypeFromReflection( + $this->reflection->getReturnType(), + null, + $this->declaringClass, + ); } return $this->nativeReturnType; diff --git a/src/Reflection/Php/PhpMethodReflectionFactory.php b/src/Reflection/Php/PhpMethodReflectionFactory.php index 78000f0931c..a73c617df03 100644 --- a/src/Reflection/Php/PhpMethodReflectionFactory.php +++ b/src/Reflection/Php/PhpMethodReflectionFactory.php @@ -14,6 +14,23 @@ interface PhpMethodReflectionFactory * @param Type[] $phpDocParameterTypes * @param Type[] $phpDocParameterOutTypes */ - public function create(ClassReflection $declaringClass, ?ClassReflection $declaringTrait, BuiltinMethodReflection $reflection, TemplateTypeMap $templateTypeMap, array $phpDocParameterTypes, ?Type $phpDocReturnType, ?Type $phpDocThrowType, ?string $deprecatedDescription, bool $isDeprecated, bool $isInternal, bool $isFinal, ?bool $isPure, Assertions $asserts, ?Type $selfOutType, ?string $phpDocComment, array $phpDocParameterOutTypes) : PhpMethodReflection; + public function create( + ClassReflection $declaringClass, + ?ClassReflection $declaringTrait, + BuiltinMethodReflection $reflection, + TemplateTypeMap $templateTypeMap, + array $phpDocParameterTypes, + ?Type $phpDocReturnType, + ?Type $phpDocThrowType, + ?string $deprecatedDescription, + bool $isDeprecated, + bool $isInternal, + bool $isFinal, + ?bool $isPure, + Assertions $asserts, + ?Type $selfOutType, + ?string $phpDocComment, + array $phpDocParameterOutTypes, + ): PhpMethodReflection; } diff --git a/src/Reflection/Php/PhpParameterFromParserNodeReflection.php b/src/Reflection/Php/PhpParameterFromParserNodeReflection.php index 568c4c5f6fa..ad6410ccd1d 100644 --- a/src/Reflection/Php/PhpParameterFromParserNodeReflection.php +++ b/src/Reflection/Php/PhpParameterFromParserNodeReflection.php @@ -12,53 +12,19 @@ class PhpParameterFromParserNodeReflection implements ParameterReflectionWithPhpDocs { - /** - * @var string - */ - private $name; - /** - * @var bool - */ - private $optional; - /** - * @var Type - */ - private $realType; - /** - * @var ?Type - */ - private $phpDocType; - /** - * @var PassedByReference - */ - private $passedByReference; - /** - * @var ?Type - */ - private $defaultValue; - /** - * @var bool - */ - private $variadic; - /** - * @var ?Type - */ - private $outType; - /** - * @var ?Type - */ - private $type = null; - - public function __construct(string $name, bool $optional, Type $realType, ?Type $phpDocType, PassedByReference $passedByReference, ?Type $defaultValue, bool $variadic, ?Type $outType) + private ?Type $type = null; + + public function __construct( + private string $name, + private bool $optional, + private Type $realType, + private ?Type $phpDocType, + private PassedByReference $passedByReference, + private ?Type $defaultValue, + private bool $variadic, + private ?Type $outType, + ) { - $this->name = $name; - $this->optional = $optional; - $this->realType = $realType; - $this->phpDocType = $phpDocType; - $this->passedByReference = $passedByReference; - $this->defaultValue = $defaultValue; - $this->variadic = $variadic; - $this->outType = $outType; } public function getName(): string diff --git a/src/Reflection/Php/PhpParameterReflection.php b/src/Reflection/Php/PhpParameterReflection.php index 93ac5e263a8..be16f41bcb1 100644 --- a/src/Reflection/Php/PhpParameterReflection.php +++ b/src/Reflection/Php/PhpParameterReflection.php @@ -15,43 +15,18 @@ class PhpParameterReflection implements ParameterReflectionWithPhpDocs { - /** - * @var InitializerExprTypeResolver - */ - private $initializerExprTypeResolver; - /** - * @var ReflectionParameter - */ - private $reflection; - /** - * @var ?Type - */ - private $phpDocType; - /** - * @var ?string - */ - private $declaringClassName; - /** - * @var ?Type - */ - private $outType; - /** - * @var ?Type - */ - private $type = null; - - /** - * @var ?Type - */ - private $nativeType = null; - - public function __construct(InitializerExprTypeResolver $initializerExprTypeResolver, ReflectionParameter $reflection, ?Type $phpDocType, ?string $declaringClassName, ?Type $outType) + private ?Type $type = null; + + private ?Type $nativeType = null; + + public function __construct( + private InitializerExprTypeResolver $initializerExprTypeResolver, + private ReflectionParameter $reflection, + private ?Type $phpDocType, + private ?string $declaringClassName, + private ?Type $outType, + ) { - $this->initializerExprTypeResolver = $initializerExprTypeResolver; - $this->reflection = $reflection; - $this->phpDocType = $phpDocType; - $this->declaringClassName = $declaringClassName; - $this->outType = $outType; } public function isOptional(): bool @@ -72,13 +47,21 @@ public function getType(): Type $phpDocType !== null && $this->reflection->isDefaultValueAvailable() ) { - $defaultValueType = $this->initializerExprTypeResolver->getType($this->reflection->getDefaultValueExpression(), InitializerExprContext::fromReflectionParameter($this->reflection)); + $defaultValueType = $this->initializerExprTypeResolver->getType( + $this->reflection->getDefaultValueExpression(), + InitializerExprContext::fromReflectionParameter($this->reflection), + ); if ($defaultValueType->isNull()->yes()) { $phpDocType = TypeCombinator::addNull($phpDocType); } } - $this->type = TypehintHelper::decideTypeFromReflection($this->reflection->getType(), $phpDocType, $this->declaringClassName, $this->isVariadic()); + $this->type = TypehintHelper::decideTypeFromReflection( + $this->reflection->getType(), + $phpDocType, + $this->declaringClassName, + $this->isVariadic(), + ); } return $this->type; @@ -108,7 +91,12 @@ public function getPhpDocType(): Type public function getNativeType(): Type { if ($this->nativeType === null) { - $this->nativeType = TypehintHelper::decideTypeFromReflection($this->reflection->getType(), null, $this->declaringClassName, $this->isVariadic()); + $this->nativeType = TypehintHelper::decideTypeFromReflection( + $this->reflection->getType(), + null, + $this->declaringClassName, + $this->isVariadic(), + ); } return $this->nativeType; @@ -117,7 +105,10 @@ public function getNativeType(): Type public function getDefaultValue(): ?Type { if ($this->reflection->isDefaultValueAvailable()) { - return $this->initializerExprTypeResolver->getType($this->reflection->getDefaultValueExpression(), InitializerExprContext::fromReflectionParameter($this->reflection)); + return $this->initializerExprTypeResolver->getType( + $this->reflection->getDefaultValueExpression(), + InitializerExprContext::fromReflectionParameter($this->reflection), + ); } return null; diff --git a/src/Reflection/Php/PhpPropertyReflection.php b/src/Reflection/Php/PhpPropertyReflection.php index af695864b5c..00fc7e3e8eb 100644 --- a/src/Reflection/Php/PhpPropertyReflection.php +++ b/src/Reflection/Php/PhpPropertyReflection.php @@ -17,71 +17,23 @@ class PhpPropertyReflection implements PropertyReflection { - /** - * @var ClassReflection - */ - private $declaringClass; - /** - * @var ?ClassReflection - */ - private $declaringTrait; - /** - * @var ReflectionUnionType|ReflectionNamedType|ReflectionIntersectionType|null - */ - private $nativeType; - /** - * @var ?Type - */ - private $phpDocType; - /** - * @var ReflectionProperty - */ - private $reflection; - /** - * @var ?string - */ - private $deprecatedDescription; - /** - * @var bool - */ - private $isDeprecated; - /** - * @var bool - */ - private $isInternal; - /** - * @var bool - */ - private $isReadOnlyByPhpDoc; - /** - * @var bool - */ - private $isAllowedPrivateMutation; - /** - * @var ?Type - */ - private $finalNativeType = null; - - /** - * @var ?Type - */ - private $type = null; - - /** - * @param ReflectionUnionType|ReflectionNamedType|ReflectionIntersectionType|null $nativeType - */ - public function __construct(ClassReflection $declaringClass, ?ClassReflection $declaringTrait, $nativeType, ?Type $phpDocType, ReflectionProperty $reflection, ?string $deprecatedDescription, bool $isDeprecated, bool $isInternal, bool $isReadOnlyByPhpDoc, bool $isAllowedPrivateMutation) - { - $this->declaringClass = $declaringClass; - $this->declaringTrait = $declaringTrait; - $this->nativeType = $nativeType; - $this->phpDocType = $phpDocType; - $this->reflection = $reflection; - $this->deprecatedDescription = $deprecatedDescription; - $this->isDeprecated = $isDeprecated; - $this->isInternal = $isInternal; - $this->isReadOnlyByPhpDoc = $isReadOnlyByPhpDoc; - $this->isAllowedPrivateMutation = $isAllowedPrivateMutation; + private ?Type $finalNativeType = null; + + private ?Type $type = null; + + public function __construct( + private ClassReflection $declaringClass, + private ?ClassReflection $declaringTrait, + private ReflectionUnionType|ReflectionNamedType|ReflectionIntersectionType|null $nativeType, + private ?Type $phpDocType, + private ReflectionProperty $reflection, + private ?string $deprecatedDescription, + private bool $isDeprecated, + private bool $isInternal, + private bool $isReadOnlyByPhpDoc, + private bool $isAllowedPrivateMutation, + ) + { } public function getDeclaringClass(): ClassReflection @@ -132,7 +84,11 @@ public function isReadOnlyByPhpDoc(): bool public function getReadableType(): Type { if ($this->type === null) { - $this->type = TypehintHelper::decideTypeFromReflection($this->nativeType, $this->phpDocType, $this->declaringClass); + $this->type = TypehintHelper::decideTypeFromReflection( + $this->nativeType, + $this->phpDocType, + $this->declaringClass, + ); } return $this->type; @@ -175,7 +131,11 @@ public function hasNativeType(): bool public function getNativeType(): Type { if ($this->finalNativeType === null) { - $this->finalNativeType = TypehintHelper::decideTypeFromReflection($this->nativeType, null, $this->declaringClass); + $this->finalNativeType = TypehintHelper::decideTypeFromReflection( + $this->nativeType, + null, + $this->declaringClass, + ); } return $this->finalNativeType; diff --git a/src/Reflection/Php/SimpleXMLElementProperty.php b/src/Reflection/Php/SimpleXMLElementProperty.php index 8c3b0ef544e..9668d523be3 100644 --- a/src/Reflection/Php/SimpleXMLElementProperty.php +++ b/src/Reflection/Php/SimpleXMLElementProperty.php @@ -15,19 +15,13 @@ class SimpleXMLElementProperty implements PropertyReflection { - /** - * @var ClassReflection - */ - private $declaringClass; - /** - * @var Type - */ - private $type; - public function __construct(ClassReflection $declaringClass, Type $type) + public function __construct( + private ClassReflection $declaringClass, + private Type $type, + ) { - $this->declaringClass = $declaringClass; - $this->type = $type; } + public function getDeclaringClass(): ClassReflection { return $this->declaringClass; @@ -55,7 +49,13 @@ public function getReadableType(): Type public function getWritableType(): Type { - return TypeCombinator::union($this->type, new IntegerType(), new FloatType(), new StringType(), new BooleanType()); + return TypeCombinator::union( + $this->type, + new IntegerType(), + new FloatType(), + new StringType(), + new BooleanType(), + ); } public function isReadable(): bool diff --git a/src/Reflection/Php/Soap/SoapClientMethodReflection.php b/src/Reflection/Php/Soap/SoapClientMethodReflection.php index 0fbf547cb63..15a814b20a2 100644 --- a/src/Reflection/Php/Soap/SoapClientMethodReflection.php +++ b/src/Reflection/Php/Soap/SoapClientMethodReflection.php @@ -15,18 +15,8 @@ class SoapClientMethodReflection implements MethodReflection { - /** - * @var ClassReflection - */ - private $declaringClass; - /** - * @var string - */ - private $name; - public function __construct(ClassReflection $declaringClass, string $name) + public function __construct(private ClassReflection $declaringClass, private string $name) { - $this->declaringClass = $declaringClass; - $this->name = $name; } public function getDeclaringClass(): ClassReflection @@ -67,7 +57,13 @@ public function getPrototype(): ClassMemberReflection public function getVariants(): array { return [ - new FunctionVariant(TemplateTypeMap::createEmpty(), TemplateTypeMap::createEmpty(), [], true, new MixedType(true)), + new FunctionVariant( + TemplateTypeMap::createEmpty(), + TemplateTypeMap::createEmpty(), + [], + true, + new MixedType(true), + ), ]; } diff --git a/src/Reflection/Php/UniversalObjectCrateProperty.php b/src/Reflection/Php/UniversalObjectCrateProperty.php index b542baf62eb..3d766f5feeb 100644 --- a/src/Reflection/Php/UniversalObjectCrateProperty.php +++ b/src/Reflection/Php/UniversalObjectCrateProperty.php @@ -10,24 +10,14 @@ class UniversalObjectCrateProperty implements PropertyReflection { - /** - * @var ClassReflection - */ - private $declaringClass; - /** - * @var Type - */ - private $readableType; - /** - * @var Type - */ - private $writableType; - public function __construct(ClassReflection $declaringClass, Type $readableType, Type $writableType) + public function __construct( + private ClassReflection $declaringClass, + private Type $readableType, + private Type $writableType, + ) { - $this->declaringClass = $declaringClass; - $this->readableType = $readableType; - $this->writableType = $writableType; } + public function getDeclaringClass(): ClassReflection { return $this->declaringClass; diff --git a/src/Reflection/Php/UniversalObjectCratesClassReflectionExtension.php b/src/Reflection/Php/UniversalObjectCratesClassReflectionExtension.php index 84d35d94e4d..a5aaa8443f3 100644 --- a/src/Reflection/Php/UniversalObjectCratesClassReflectionExtension.php +++ b/src/Reflection/Php/UniversalObjectCratesClassReflectionExtension.php @@ -14,36 +14,34 @@ class UniversalObjectCratesClassReflectionExtension implements PropertiesClassReflectionExtension { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - /** - * @var string[] - */ - private $classes; - /** - * @var AnnotationsPropertiesClassReflectionExtension - */ - private $annotationClassReflection; /** * @param string[] $classes */ - public function __construct(ReflectionProvider $reflectionProvider, array $classes, AnnotationsPropertiesClassReflectionExtension $annotationClassReflection) + public function __construct( + private ReflectionProvider $reflectionProvider, + private array $classes, + private AnnotationsPropertiesClassReflectionExtension $annotationClassReflection, + ) { - $this->reflectionProvider = $reflectionProvider; - $this->classes = $classes; - $this->annotationClassReflection = $annotationClassReflection; } + public function hasProperty(ClassReflection $classReflection, string $propertyName): bool { - return self::isUniversalObjectCrate($this->reflectionProvider, $this->classes, $classReflection); + return self::isUniversalObjectCrate( + $this->reflectionProvider, + $this->classes, + $classReflection, + ); } /** * @param string[] $classes */ - public static function isUniversalObjectCrate(ReflectionProvider $reflectionProvider, array $classes, ClassReflection $classReflection) : bool + public static function isUniversalObjectCrate( + ReflectionProvider $reflectionProvider, + array $classes, + ClassReflection $classReflection, + ): bool { foreach ($classes as $className) { if (!$reflectionProvider->hasClass($className)) { @@ -57,6 +55,7 @@ public static function isUniversalObjectCrate(ReflectionProvider $reflectionProv return true; } } + return false; } diff --git a/src/Reflection/PhpVersionStaticAccessor.php b/src/Reflection/PhpVersionStaticAccessor.php index dab886c1d88..909c3578743 100644 --- a/src/Reflection/PhpVersionStaticAccessor.php +++ b/src/Reflection/PhpVersionStaticAccessor.php @@ -8,10 +8,7 @@ class PhpVersionStaticAccessor { - /** - * @var ?PhpVersion - */ - private static $instance = null; + private static ?PhpVersion $instance = null; private function __construct() { diff --git a/src/Reflection/ReflectionProvider.php b/src/Reflection/ReflectionProvider.php index ac3f0ed441a..12487663262 100644 --- a/src/Reflection/ReflectionProvider.php +++ b/src/Reflection/ReflectionProvider.php @@ -17,7 +17,10 @@ public function getClassName(string $className): string; public function supportsAnonymousClasses(): bool; - public function getAnonymousClassReflection(Node\Stmt\Class_ $classNode, Scope $scope) : ClassReflection; + public function getAnonymousClassReflection( + Node\Stmt\Class_ $classNode, + Scope $scope, + ): ClassReflection; public function hasFunction(Node\Name $nameNode, ?NamespaceAnswerer $namespaceAnswerer): bool; diff --git a/src/Reflection/ReflectionProvider/DirectReflectionProviderProvider.php b/src/Reflection/ReflectionProvider/DirectReflectionProviderProvider.php index 576122883ce..e1c7e31e1f1 100644 --- a/src/Reflection/ReflectionProvider/DirectReflectionProviderProvider.php +++ b/src/Reflection/ReflectionProvider/DirectReflectionProviderProvider.php @@ -7,13 +7,8 @@ class DirectReflectionProviderProvider implements ReflectionProviderProvider { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - public function __construct(ReflectionProvider $reflectionProvider) + public function __construct(private ReflectionProvider $reflectionProvider) { - $this->reflectionProvider = $reflectionProvider; } public function getReflectionProvider(): ReflectionProvider diff --git a/src/Reflection/ReflectionProvider/LazyReflectionProviderProvider.php b/src/Reflection/ReflectionProvider/LazyReflectionProviderProvider.php index e1f91409657..9e4b1957a02 100644 --- a/src/Reflection/ReflectionProvider/LazyReflectionProviderProvider.php +++ b/src/Reflection/ReflectionProvider/LazyReflectionProviderProvider.php @@ -8,13 +8,8 @@ class LazyReflectionProviderProvider implements ReflectionProviderProvider { - /** - * @var Container - */ - private $container; - public function __construct(Container $container) + public function __construct(private Container $container) { - $this->container = $container; } public function getReflectionProvider(): ReflectionProvider diff --git a/src/Reflection/ReflectionProvider/MemoizingReflectionProvider.php b/src/Reflection/ReflectionProvider/MemoizingReflectionProvider.php index 25b1d49b97c..b4059b76231 100644 --- a/src/Reflection/ReflectionProvider/MemoizingReflectionProvider.php +++ b/src/Reflection/ReflectionProvider/MemoizingReflectionProvider.php @@ -14,22 +14,17 @@ class MemoizingReflectionProvider implements ReflectionProvider { - /** - * @var ReflectionProvider - */ - private $provider; /** @var array */ - private $hasClasses = []; + private array $hasClasses = []; /** @var array */ - private $classes = []; + private array $classes = []; /** @var array */ - private $classNames = []; + private array $classNames = []; - public function __construct(ReflectionProvider $provider) + public function __construct(private ReflectionProvider $provider) { - $this->provider = $provider; } public function hasClass(string $className): bool diff --git a/src/Reflection/ReflectionProvider/ReflectionProviderFactory.php b/src/Reflection/ReflectionProvider/ReflectionProviderFactory.php index 5bd56a8c0d9..7c9501cbdde 100644 --- a/src/Reflection/ReflectionProvider/ReflectionProviderFactory.php +++ b/src/Reflection/ReflectionProvider/ReflectionProviderFactory.php @@ -7,14 +7,12 @@ class ReflectionProviderFactory { - /** - * @var ReflectionProvider - */ - private $staticReflectionProvider; - public function __construct(ReflectionProvider $staticReflectionProvider) + public function __construct( + private ReflectionProvider $staticReflectionProvider, + ) { - $this->staticReflectionProvider = $staticReflectionProvider; } + public function create(): ReflectionProvider { return new MemoizingReflectionProvider($this->staticReflectionProvider); diff --git a/src/Reflection/ReflectionProvider/SetterReflectionProviderProvider.php b/src/Reflection/ReflectionProvider/SetterReflectionProviderProvider.php index 514b513fb1c..9e897084cb7 100644 --- a/src/Reflection/ReflectionProvider/SetterReflectionProviderProvider.php +++ b/src/Reflection/ReflectionProvider/SetterReflectionProviderProvider.php @@ -7,10 +7,7 @@ class SetterReflectionProviderProvider implements ReflectionProviderProvider { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; + private ReflectionProvider $reflectionProvider; public function setReflectionProvider(ReflectionProvider $reflectionProvider): void { diff --git a/src/Reflection/ReflectionProviderStaticAccessor.php b/src/Reflection/ReflectionProviderStaticAccessor.php index ac561e0c1cd..bb772064c74 100644 --- a/src/Reflection/ReflectionProviderStaticAccessor.php +++ b/src/Reflection/ReflectionProviderStaticAccessor.php @@ -7,10 +7,7 @@ class ReflectionProviderStaticAccessor { - /** - * @var ?ReflectionProvider - */ - private static $instance = null; + private static ?ReflectionProvider $instance = null; private function __construct() { diff --git a/src/Reflection/ResolvedFunctionVariant.php b/src/Reflection/ResolvedFunctionVariant.php index 77b58b984a6..4f9b98c559c 100644 --- a/src/Reflection/ResolvedFunctionVariant.php +++ b/src/Reflection/ResolvedFunctionVariant.php @@ -22,54 +22,27 @@ class ResolvedFunctionVariant implements ParametersAcceptorWithPhpDocs { - /** - * @var ParametersAcceptorWithPhpDocs - */ - private $parametersAcceptor; - /** - * @var TemplateTypeMap - */ - private $resolvedTemplateTypeMap; - /** - * @var TemplateTypeVarianceMap - */ - private $callSiteVarianceMap; - /** - * @var array - */ - private $passedArgs; /** @var ParameterReflectionWithPhpDocs[]|null */ - private $parameters = null; + private ?array $parameters = null; - /** - * @var ?Type - */ - private $returnTypeWithUnresolvableTemplateTypes = null; + private ?Type $returnTypeWithUnresolvableTemplateTypes = null; - /** - * @var ?Type - */ - private $phpDocReturnTypeWithUnresolvableTemplateTypes = null; + private ?Type $phpDocReturnTypeWithUnresolvableTemplateTypes = null; - /** - * @var ?Type - */ - private $returnType = null; + private ?Type $returnType = null; - /** - * @var ?Type - */ - private $phpDocReturnType = null; + private ?Type $phpDocReturnType = null; /** * @param array $passedArgs */ - public function __construct(ParametersAcceptorWithPhpDocs $parametersAcceptor, TemplateTypeMap $resolvedTemplateTypeMap, TemplateTypeVarianceMap $callSiteVarianceMap, array $passedArgs) + public function __construct( + private ParametersAcceptorWithPhpDocs $parametersAcceptor, + private TemplateTypeMap $resolvedTemplateTypeMap, + private TemplateTypeVarianceMap $callSiteVarianceMap, + private array $passedArgs, + ) { - $this->parametersAcceptor = $parametersAcceptor; - $this->resolvedTemplateTypeMap = $resolvedTemplateTypeMap; - $this->callSiteVarianceMap = $callSiteVarianceMap; - $this->passedArgs = $passedArgs; } public function getOriginalParametersAcceptor(): ParametersAcceptor @@ -97,11 +70,32 @@ public function getParameters(): array $parameters = $this->parameters; if ($parameters === null) { - $parameters = array_map(function (ParameterReflectionWithPhpDocs $param): ParameterReflectionWithPhpDocs { - $paramType = TypeUtils::resolveLateResolvableTypes(TemplateTypeHelper::resolveTemplateTypes($this->resolveConditionalTypesForParameter($param->getType()), $this->resolvedTemplateTypeMap, $this->callSiteVarianceMap, TemplateTypeVariance::createContravariant()), false); - - return new DummyParameterWithPhpDocs($param->getName(), $paramType, $param->isOptional(), $param->passedByReference(), $param->isVariadic(), $param->getDefaultValue(), $param->getNativeType(), $param->getPhpDocType(), $param->getOutType()); - }, $this->parametersAcceptor->getParameters()); + $parameters = array_map( + function (ParameterReflectionWithPhpDocs $param): ParameterReflectionWithPhpDocs { + $paramType = TypeUtils::resolveLateResolvableTypes( + TemplateTypeHelper::resolveTemplateTypes( + $this->resolveConditionalTypesForParameter($param->getType()), + $this->resolvedTemplateTypeMap, + $this->callSiteVarianceMap, + TemplateTypeVariance::createContravariant(), + ), + false, + ); + + return new DummyParameterWithPhpDocs( + $param->getName(), + $paramType, + $param->isOptional(), + $param->passedByReference(), + $param->isVariadic(), + $param->getDefaultValue(), + $param->getNativeType(), + $param->getPhpDocType(), + $param->getOutType(), + ); + }, + $this->parametersAcceptor->getParameters(), + ); $this->parameters = $parameters; } @@ -116,12 +110,18 @@ public function isVariadic(): bool public function getReturnTypeWithUnresolvableTemplateTypes(): Type { - return $this->returnTypeWithUnresolvableTemplateTypes = $this->returnTypeWithUnresolvableTemplateTypes ?? $this->resolveConditionalTypesForParameter($this->resolveResolvableTemplateTypes($this->parametersAcceptor->getReturnType(), TemplateTypeVariance::createCovariant())); + return $this->returnTypeWithUnresolvableTemplateTypes ??= + $this->resolveConditionalTypesForParameter( + $this->resolveResolvableTemplateTypes($this->parametersAcceptor->getReturnType(), TemplateTypeVariance::createCovariant()), + ); } public function getPhpDocReturnTypeWithUnresolvableTemplateTypes(): Type { - return $this->phpDocReturnTypeWithUnresolvableTemplateTypes = $this->phpDocReturnTypeWithUnresolvableTemplateTypes ?? $this->resolveConditionalTypesForParameter($this->resolveResolvableTemplateTypes($this->parametersAcceptor->getPhpDocReturnType(), TemplateTypeVariance::createCovariant())); + return $this->phpDocReturnTypeWithUnresolvableTemplateTypes ??= + $this->resolveConditionalTypesForParameter( + $this->resolveResolvableTemplateTypes($this->parametersAcceptor->getPhpDocReturnType(), TemplateTypeVariance::createCovariant()), + ); } public function getReturnType(): Type @@ -129,7 +129,15 @@ public function getReturnType(): Type $type = $this->returnType; if ($type === null) { - $type = TypeUtils::resolveLateResolvableTypes(TemplateTypeHelper::resolveTemplateTypes($this->getReturnTypeWithUnresolvableTemplateTypes(), $this->resolvedTemplateTypeMap, $this->callSiteVarianceMap, TemplateTypeVariance::createCovariant()), false); + $type = TypeUtils::resolveLateResolvableTypes( + TemplateTypeHelper::resolveTemplateTypes( + $this->getReturnTypeWithUnresolvableTemplateTypes(), + $this->resolvedTemplateTypeMap, + $this->callSiteVarianceMap, + TemplateTypeVariance::createCovariant(), + ), + false, + ); $this->returnType = $type; } @@ -142,7 +150,15 @@ public function getPhpDocReturnType(): Type $type = $this->phpDocReturnType; if ($type === null) { - $type = TypeUtils::resolveLateResolvableTypes(TemplateTypeHelper::resolveTemplateTypes($this->getPhpDocReturnTypeWithUnresolvableTemplateTypes(), $this->resolvedTemplateTypeMap, $this->callSiteVarianceMap, TemplateTypeVariance::createCovariant()), false); + $type = TypeUtils::resolveLateResolvableTypes( + TemplateTypeHelper::resolveTemplateTypes( + $this->getPhpDocReturnTypeWithUnresolvableTemplateTypes(), + $this->resolvedTemplateTypeMap, + $this->callSiteVarianceMap, + TemplateTypeVariance::createCovariant(), + ), + false, + ); $this->phpDocReturnType = $type; } diff --git a/src/Reflection/ResolvedMethodReflection.php b/src/Reflection/ResolvedMethodReflection.php index f5a5a0ceb45..870941e2cf1 100644 --- a/src/Reflection/ResolvedMethodReflection.php +++ b/src/Reflection/ResolvedMethodReflection.php @@ -14,39 +14,22 @@ class ResolvedMethodReflection implements ExtendedMethodReflection { - /** - * @var ExtendedMethodReflection - */ - private $reflection; - /** - * @var TemplateTypeMap - */ - private $resolvedTemplateTypeMap; - /** - * @var TemplateTypeVarianceMap - */ - private $callSiteVarianceMap; /** @var ParametersAcceptorWithPhpDocs[]|null */ - private $variants = null; + private ?array $variants = null; /** @var ParametersAcceptorWithPhpDocs[]|null */ - private $namedArgumentVariants = null; + private ?array $namedArgumentVariants = null; - /** - * @var ?Assertions - */ - private $asserts = null; + private ?Assertions $asserts = null; - /** - * @var Type|false|null - */ - private $selfOutType = false; + private Type|false|null $selfOutType = false; - public function __construct(ExtendedMethodReflection $reflection, TemplateTypeMap $resolvedTemplateTypeMap, TemplateTypeVarianceMap $callSiteVarianceMap) + public function __construct( + private ExtendedMethodReflection $reflection, + private TemplateTypeMap $resolvedTemplateTypeMap, + private TemplateTypeVarianceMap $callSiteVarianceMap, + ) { - $this->reflection = $reflection; - $this->resolvedTemplateTypeMap = $resolvedTemplateTypeMap; - $this->callSiteVarianceMap = $callSiteVarianceMap; } public function getName(): string @@ -92,7 +75,12 @@ private function resolveVariants(array $variants): array { $result = []; foreach ($variants as $variant) { - $result[] = new ResolvedFunctionVariant($variant, $this->resolvedTemplateTypeMap, $this->callSiteVarianceMap, []); + $result[] = new ResolvedFunctionVariant( + $variant, + $this->resolvedTemplateTypeMap, + $this->callSiteVarianceMap, + [], + ); } return $result; @@ -169,9 +157,12 @@ public function hasSideEffects(): TrinaryLogic public function getAsserts(): Assertions { - return $this->asserts = $this->asserts ?? $this->reflection->getAsserts()->mapTypes(function (Type $type) { - return TemplateTypeHelper::resolveTemplateTypes($type, $this->resolvedTemplateTypeMap, $this->callSiteVarianceMap, TemplateTypeVariance::createInvariant()); - }); + return $this->asserts ??= $this->reflection->getAsserts()->mapTypes(fn (Type $type) => TemplateTypeHelper::resolveTemplateTypes( + $type, + $this->resolvedTemplateTypeMap, + $this->callSiteVarianceMap, + TemplateTypeVariance::createInvariant(), + )); } public function getSelfOutType(): ?Type @@ -179,7 +170,12 @@ public function getSelfOutType(): ?Type if ($this->selfOutType === false) { $selfOutType = $this->reflection->getSelfOutType(); if ($selfOutType !== null) { - $selfOutType = TemplateTypeHelper::resolveTemplateTypes($selfOutType, $this->resolvedTemplateTypeMap, $this->callSiteVarianceMap, TemplateTypeVariance::createInvariant()); + $selfOutType = TemplateTypeHelper::resolveTemplateTypes( + $selfOutType, + $this->resolvedTemplateTypeMap, + $this->callSiteVarianceMap, + TemplateTypeVariance::createInvariant(), + ); } $this->selfOutType = $selfOutType; diff --git a/src/Reflection/ResolvedPropertyReflection.php b/src/Reflection/ResolvedPropertyReflection.php index 52bc155899d..7888b26abdb 100644 --- a/src/Reflection/ResolvedPropertyReflection.php +++ b/src/Reflection/ResolvedPropertyReflection.php @@ -13,33 +13,16 @@ class ResolvedPropertyReflection implements WrapperPropertyReflection { - /** - * @var PropertyReflection - */ - private $reflection; - /** - * @var TemplateTypeMap - */ - private $templateTypeMap; - /** - * @var TemplateTypeVarianceMap - */ - private $callSiteVarianceMap; - /** - * @var ?Type - */ - private $readableType = null; - - /** - * @var ?Type - */ - private $writableType = null; - - public function __construct(PropertyReflection $reflection, TemplateTypeMap $templateTypeMap, TemplateTypeVarianceMap $callSiteVarianceMap) - { - $this->reflection = $reflection; - $this->templateTypeMap = $templateTypeMap; - $this->callSiteVarianceMap = $callSiteVarianceMap; + private ?Type $readableType = null; + + private ?Type $writableType = null; + + public function __construct( + private PropertyReflection $reflection, + private TemplateTypeMap $templateTypeMap, + private TemplateTypeVarianceMap $callSiteVarianceMap, + ) + { } public function getOriginalReflection(): PropertyReflection @@ -83,8 +66,18 @@ public function getReadableType(): Type return $type; } - $type = TemplateTypeHelper::resolveTemplateTypes($this->reflection->getReadableType(), $this->templateTypeMap, $this->callSiteVarianceMap, TemplateTypeVariance::createCovariant()); - $type = TemplateTypeHelper::resolveTemplateTypes($type, $this->templateTypeMap, $this->callSiteVarianceMap, TemplateTypeVariance::createCovariant()); + $type = TemplateTypeHelper::resolveTemplateTypes( + $this->reflection->getReadableType(), + $this->templateTypeMap, + $this->callSiteVarianceMap, + TemplateTypeVariance::createCovariant(), + ); + $type = TemplateTypeHelper::resolveTemplateTypes( + $type, + $this->templateTypeMap, + $this->callSiteVarianceMap, + TemplateTypeVariance::createCovariant(), + ); $this->readableType = $type; @@ -98,8 +91,18 @@ public function getWritableType(): Type return $type; } - $type = TemplateTypeHelper::resolveTemplateTypes($this->reflection->getWritableType(), $this->templateTypeMap, $this->callSiteVarianceMap, TemplateTypeVariance::createContravariant()); - $type = TemplateTypeHelper::resolveTemplateTypes($type, $this->templateTypeMap, $this->callSiteVarianceMap, TemplateTypeVariance::createContravariant()); + $type = TemplateTypeHelper::resolveTemplateTypes( + $this->reflection->getWritableType(), + $this->templateTypeMap, + $this->callSiteVarianceMap, + TemplateTypeVariance::createContravariant(), + ); + $type = TemplateTypeHelper::resolveTemplateTypes( + $type, + $this->templateTypeMap, + $this->callSiteVarianceMap, + TemplateTypeVariance::createContravariant(), + ); $this->writableType = $type; diff --git a/src/Reflection/SignatureMap/FunctionSignature.php b/src/Reflection/SignatureMap/FunctionSignature.php index 98c1cda0156..8473684acc6 100644 --- a/src/Reflection/SignatureMap/FunctionSignature.php +++ b/src/Reflection/SignatureMap/FunctionSignature.php @@ -7,32 +7,18 @@ class FunctionSignature { - /** - * @var array - */ - private $parameters; - /** - * @var Type - */ - private $returnType; - /** - * @var Type - */ - private $nativeReturnType; - /** - * @var bool - */ - private $variadic; /** * @param array $parameters */ - public function __construct(array $parameters, Type $returnType, Type $nativeReturnType, bool $variadic) + public function __construct( + private array $parameters, + private Type $returnType, + private Type $nativeReturnType, + private bool $variadic, + ) { - $this->parameters = $parameters; - $this->returnType = $returnType; - $this->nativeReturnType = $nativeReturnType; - $this->variadic = $variadic; } + /** * @return array */ diff --git a/src/Reflection/SignatureMap/FunctionSignatureMapProvider.php b/src/Reflection/SignatureMap/FunctionSignatureMapProvider.php index 09dd080a276..9b8c21910b1 100644 --- a/src/Reflection/SignatureMap/FunctionSignatureMapProvider.php +++ b/src/Reflection/SignatureMap/FunctionSignatureMapProvider.php @@ -22,34 +22,19 @@ class FunctionSignatureMapProvider implements SignatureMapProvider { - /** - * @var SignatureMapParser - */ - private $parser; - /** - * @var InitializerExprTypeResolver - */ - private $initializerExprTypeResolver; - /** - * @var PhpVersion - */ - private $phpVersion; - /** - * @var bool - */ - private $stricterFunctionMap; /** @var array */ - private static $signatureMaps = []; + private static array $signatureMaps = []; /** @var array|null */ - private static $functionMetadata = null; - - public function __construct(SignatureMapParser $parser, InitializerExprTypeResolver $initializerExprTypeResolver, PhpVersion $phpVersion, bool $stricterFunctionMap) + private static ?array $functionMetadata = null; + + public function __construct( + private SignatureMapParser $parser, + private InitializerExprTypeResolver $initializerExprTypeResolver, + private PhpVersion $phpVersion, + private bool $stricterFunctionMap, + ) { - $this->parser = $parser; - $this->initializerExprTypeResolver = $initializerExprTypeResolver; - $this->phpVersion = $phpVersion; - $this->stricterFunctionMap = $stricterFunctionMap; } public function hasMethodSignature(string $className, string $methodName): bool @@ -89,7 +74,10 @@ private function createSignature(string $functionName, ?string $className, ?Refl throw new ShouldNotHappenException(); } $signatureMap = self::getSignatureMap(); - $signature = $this->parser->getFunctionSignature($signatureMap[$functionName], $className); + $signature = $this->parser->getFunctionSignature( + $signatureMap[$functionName], + $className, + ); $parameters = []; foreach ($signature->getParameters() as $i => $parameter) { if ($reflectionFunction === null) { @@ -102,7 +90,19 @@ private function createSignature(string $functionName, ?string $className, ?Refl continue; } - $parameters[] = new ParameterSignature($parameter->getName(), $parameter->isOptional(), $parameter->getType(), TypehintHelper::decideTypeFromReflection($nativeParameters[$i]->getType()), $parameter->passedByReference(), $parameter->isVariadic(), $nativeParameters[$i]->isDefaultValueAvailable() ? $this->initializerExprTypeResolver->getType($nativeParameters[$i]->getDefaultValueExpression(), InitializerExprContext::fromReflectionParameter($nativeParameters[$i])) : null, $parameter->getOutType()); + $parameters[] = new ParameterSignature( + $parameter->getName(), + $parameter->isOptional(), + $parameter->getType(), + TypehintHelper::decideTypeFromReflection($nativeParameters[$i]->getType()), + $parameter->passedByReference(), + $parameter->isVariadic(), + $nativeParameters[$i]->isDefaultValueAvailable() ? $this->initializerExprTypeResolver->getType( + $nativeParameters[$i]->getDefaultValueExpression(), + InitializerExprContext::fromReflectionParameter($nativeParameters[$i]), + ) : null, + $parameter->getOutType(), + ); } if ($reflectionFunction === null) { @@ -111,7 +111,12 @@ private function createSignature(string $functionName, ?string $className, ?Refl $nativeReturnType = TypehintHelper::decideTypeFromReflection($reflectionFunction->getReturnType()); } - return new FunctionSignature($parameters, $signature->getReturnType(), $nativeReturnType, $signature->isVariadic()); + return new FunctionSignature( + $parameters, + $signature->getReturnType(), + $nativeReturnType, + $signature->isVariadic(), + ); } public function hasMethodMetadata(string $className, string $methodName): bool diff --git a/src/Reflection/SignatureMap/NativeFunctionReflectionProvider.php b/src/Reflection/SignatureMap/NativeFunctionReflectionProvider.php index 7a2b49f9f02..734bf96f7d6 100644 --- a/src/Reflection/SignatureMap/NativeFunctionReflectionProvider.php +++ b/src/Reflection/SignatureMap/NativeFunctionReflectionProvider.php @@ -25,31 +25,11 @@ class NativeFunctionReflectionProvider { - /** - * @var SignatureMapProvider - */ - private $signatureMapProvider; - /** - * @var Reflector - */ - private $reflector; - /** - * @var FileTypeMapper - */ - private $fileTypeMapper; - /** - * @var StubPhpDocProvider - */ - private $stubPhpDocProvider; /** @var NativeFunctionReflection[] */ - private $functionMap = []; + private array $functionMap = []; - public function __construct(SignatureMapProvider $signatureMapProvider, Reflector $reflector, FileTypeMapper $fileTypeMapper, StubPhpDocProvider $stubPhpDocProvider) + public function __construct(private SignatureMapProvider $signatureMapProvider, private Reflector $reflector, private FileTypeMapper $fileTypeMapper, private StubPhpDocProvider $stubPhpDocProvider) { - $this->signatureMapProvider = $signatureMapProvider; - $this->reflector = $reflector; - $this->fileTypeMapper = $fileTypeMapper; - $this->stubPhpDocProvider = $stubPhpDocProvider; } public function findFunctionReflection(string $functionName): ?NativeFunctionReflection @@ -88,15 +68,13 @@ public function findFunctionReflection(string $functionName): ?NativeFunctionRef $isDeprecated = $reflectionFunction->isDeprecated(); } } - } catch (IdentifierNotFound | InvalidIdentifierName $e) { + } catch (IdentifierNotFound | InvalidIdentifierName) { // pass } $functionSignaturesResult = $this->signatureMapProvider->getFunctionSignatures($lowerCasedFunctionName, null, $reflectionFunctionAdapter); - $phpDoc = $this->stubPhpDocProvider->findFunctionPhpDoc($lowerCasedFunctionName, array_map(static function (ParameterSignature $parameter) : string { - return $parameter->getName(); - }, $functionSignaturesResult['positional'][0]->getParameters())); + $phpDoc = $this->stubPhpDocProvider->findFunctionPhpDoc($lowerCasedFunctionName, array_map(static fn (ParameterSignature $parameter): string => $parameter->getName(), $functionSignaturesResult['positional'][0]->getParameters())); if ($phpDoc !== null) { if ($phpDoc->hasPhpDocString()) { $docComment = $phpDoc->getPhpDocString(); @@ -111,7 +89,10 @@ public function findFunctionReflection(string $functionName): ?NativeFunctionRef $variantsByType = ['positional' => []]; foreach ($functionSignaturesResult as $signatureType => $functionSignatures) { foreach ($functionSignatures ?? [] as $functionSignature) { - $variantsByType[$signatureType][] = new FunctionVariantWithPhpDocs(TemplateTypeMap::createEmpty(), null, array_map(static function (ParameterSignature $parameterSignature) use ($phpDoc): NativeParameterWithPhpDocsReflection { + $variantsByType[$signatureType][] = new FunctionVariantWithPhpDocs( + TemplateTypeMap::createEmpty(), + null, + array_map(static function (ParameterSignature $parameterSignature) use ($phpDoc): NativeParameterWithPhpDocsReflection { $type = $parameterSignature->getType(); $phpDocType = null; @@ -122,8 +103,23 @@ public function findFunctionReflection(string $functionName): ?NativeFunctionRef } } - return new NativeParameterWithPhpDocsReflection($parameterSignature->getName(), $parameterSignature->isOptional(), TypehintHelper::decideType($type, $phpDocType), $phpDocType ?? new MixedType(), $type, $parameterSignature->passedByReference(), $parameterSignature->isVariadic(), $parameterSignature->getDefaultValue(), $phpDoc !== null ? NativeFunctionReflectionProvider::getParamOutTypeFromPhpDoc($parameterSignature->getName(), $phpDoc) : null); - }, $functionSignature->getParameters()), $functionSignature->isVariadic(), TypehintHelper::decideType($functionSignature->getReturnType(), $phpDocReturnType), $phpDocReturnType ?? new MixedType(), $functionSignature->getReturnType()); + return new NativeParameterWithPhpDocsReflection( + $parameterSignature->getName(), + $parameterSignature->isOptional(), + TypehintHelper::decideType($type, $phpDocType), + $phpDocType ?? new MixedType(), + $type, + $parameterSignature->passedByReference(), + $parameterSignature->isVariadic(), + $parameterSignature->getDefaultValue(), + $phpDoc !== null ? NativeFunctionReflectionProvider::getParamOutTypeFromPhpDoc($parameterSignature->getName(), $phpDoc) : null, + ); + }, $functionSignature->getParameters()), + $functionSignature->isVariadic(), + TypehintHelper::decideType($functionSignature->getReturnType(), $phpDocReturnType), + $phpDocReturnType ?? new MixedType(), + $functionSignature->getReturnType(), + ); } } @@ -133,7 +129,17 @@ public function findFunctionReflection(string $functionName): ?NativeFunctionRef $hasSideEffects = TrinaryLogic::createMaybe(); } - $functionReflection = new NativeFunctionReflection($realFunctionName, $variantsByType['positional'], $variantsByType['named'] ?? null, $throwType, $hasSideEffects, $isDeprecated, $asserts, $docComment, $returnsByReference); + $functionReflection = new NativeFunctionReflection( + $realFunctionName, + $variantsByType['positional'], + $variantsByType['named'] ?? null, + $throwType, + $hasSideEffects, + $isDeprecated, + $asserts, + $docComment, + $returnsByReference, + ); $this->functionMap[$lowerCasedFunctionName] = $functionReflection; return $functionReflection; diff --git a/src/Reflection/SignatureMap/ParameterSignature.php b/src/Reflection/SignatureMap/ParameterSignature.php index b5160308edc..fc9316c3001 100644 --- a/src/Reflection/SignatureMap/ParameterSignature.php +++ b/src/Reflection/SignatureMap/ParameterSignature.php @@ -8,49 +8,19 @@ class ParameterSignature { - /** - * @var string - */ - private $name; - /** - * @var bool - */ - private $optional; - /** - * @var Type - */ - private $type; - /** - * @var Type - */ - private $nativeType; - /** - * @var PassedByReference - */ - private $passedByReference; - /** - * @var bool - */ - private $variadic; - /** - * @var ?Type - */ - private $defaultValue; - /** - * @var ?Type - */ - private $outType; - public function __construct(string $name, bool $optional, Type $type, Type $nativeType, PassedByReference $passedByReference, bool $variadic, ?Type $defaultValue, ?Type $outType) + public function __construct( + private string $name, + private bool $optional, + private Type $type, + private Type $nativeType, + private PassedByReference $passedByReference, + private bool $variadic, + private ?Type $defaultValue, + private ?Type $outType, + ) { - $this->name = $name; - $this->optional = $optional; - $this->type = $type; - $this->nativeType = $nativeType; - $this->passedByReference = $passedByReference; - $this->variadic = $variadic; - $this->defaultValue = $defaultValue; - $this->outType = $outType; } + public function getName(): string { return $this->name; diff --git a/src/Reflection/SignatureMap/Php8SignatureMapProvider.php b/src/Reflection/SignatureMap/Php8SignatureMapProvider.php index 44532a395c2..d114609b351 100644 --- a/src/Reflection/SignatureMap/Php8SignatureMapProvider.php +++ b/src/Reflection/SignatureMap/Php8SignatureMapProvider.php @@ -34,46 +34,24 @@ class Php8SignatureMapProvider implements SignatureMapProvider { - /** - * @var FunctionSignatureMapProvider - */ - private $functionSignatureMapProvider; - /** - * @var FileNodesFetcher - */ - private $fileNodesFetcher; - /** - * @var FileTypeMapper - */ - private $fileTypeMapper; - /** - * @var PhpVersion - */ - private $phpVersion; - /** - * @var InitializerExprTypeResolver - */ - private $initializerExprTypeResolver; private const DIRECTORY = __DIR__ . '/../../../vendor/phpstan/php-8-stubs'; /** @var array> */ - private $methodNodes = []; + private array $methodNodes = []; /** @var array> */ - private $constantTypes = []; + private array $constantTypes = []; - /** - * @var Php8StubsMap - */ - private $map; + private Php8StubsMap $map; - public function __construct(FunctionSignatureMapProvider $functionSignatureMapProvider, FileNodesFetcher $fileNodesFetcher, FileTypeMapper $fileTypeMapper, PhpVersion $phpVersion, InitializerExprTypeResolver $initializerExprTypeResolver) + public function __construct( + private FunctionSignatureMapProvider $functionSignatureMapProvider, + private FileNodesFetcher $fileNodesFetcher, + private FileTypeMapper $fileTypeMapper, + private PhpVersion $phpVersion, + private InitializerExprTypeResolver $initializerExprTypeResolver, + ) { - $this->functionSignatureMapProvider = $functionSignatureMapProvider; - $this->fileNodesFetcher = $fileNodesFetcher; - $this->fileTypeMapper = $fileTypeMapper; - $this->phpVersion = $phpVersion; - $this->initializerExprTypeResolver = $initializerExprTypeResolver; $this->map = new Php8StubsMap($phpVersion->getVersionId()); } @@ -204,10 +182,7 @@ public function getMethodSignatures(string $className, string $methodName, ?Refl return ['positional' => [$signature], 'named' => null]; } - /** - * @param ReflectionFunctionAbstract|null $reflectionFunction - */ - public function getFunctionSignatures(string $functionName, ?string $className, $reflectionFunction): array + public function getFunctionSignatures(string $functionName, ?string $className, ReflectionFunctionAbstract|null $reflectionFunction): array { $lowerName = strtolower($functionName); if (!array_key_exists($lowerName, $this->map->functions)) { @@ -286,10 +261,24 @@ private function getMergedSignatures(FunctionSignature $nativeSignature, array $ break; } - $parameters[] = new ParameterSignature($nativeParam->getName(), $functionParam->isOptional(), $functionParam->getType(), $functionParam->getNativeType(), $functionParam->passedByReference(), $functionParam->isVariadic(), $functionParam->getDefaultValue(), $functionParam->getOutType()); + $parameters[] = new ParameterSignature( + $nativeParam->getName(), + $functionParam->isOptional(), + $functionParam->getType(), + $functionParam->getNativeType(), + $functionParam->passedByReference(), + $functionParam->isVariadic(), + $functionParam->getDefaultValue(), + $functionParam->getOutType(), + ); } - $namedArgumentsVariants[] = new FunctionSignature($parameters, $functionMapSignature->getReturnType(), $functionMapSignature->getNativeReturnType(), $functionMapSignature->isVariadic()); + $namedArgumentsVariants[] = new FunctionSignature( + $parameters, + $functionMapSignature->getReturnType(), + $functionMapSignature->getNativeReturnType(), + $functionMapSignature->isVariadic(), + ); } if ($allParamNamesMatchNative || count($namedArgumentsVariants) === 0) { @@ -310,17 +299,43 @@ private function mergeSignatures(FunctionSignature $nativeSignature, FunctionSig $functionMapParameter = $functionMapSignature->getParameters()[$i]; $nativeParameterType = $nativeParameter->getNativeType(); - $parameters[] = new ParameterSignature($nativeParameter->getName(), $nativeParameter->isOptional(), TypehintHelper::decideType($nativeParameterType, TypehintHelper::decideType($nativeParameter->getType(), $functionMapParameter->getType())), $nativeParameterType, $nativeParameter->passedByReference()->yes() ? $functionMapParameter->passedByReference() : $nativeParameter->passedByReference(), $nativeParameter->isVariadic(), $nativeParameter->getDefaultValue(), $nativeParameter->getOutType()); + $parameters[] = new ParameterSignature( + $nativeParameter->getName(), + $nativeParameter->isOptional(), + TypehintHelper::decideType( + $nativeParameterType, + TypehintHelper::decideType( + $nativeParameter->getType(), + $functionMapParameter->getType(), + ), + ), + $nativeParameterType, + $nativeParameter->passedByReference()->yes() ? $functionMapParameter->passedByReference() : $nativeParameter->passedByReference(), + $nativeParameter->isVariadic(), + $nativeParameter->getDefaultValue(), + $nativeParameter->getOutType(), + ); } $nativeReturnType = $nativeSignature->getNativeReturnType(); if ($nativeReturnType instanceof MixedType && !$nativeReturnType->isExplicitMixed()) { $returnType = $functionMapSignature->getReturnType(); } else { - $returnType = TypehintHelper::decideType($nativeReturnType, TypehintHelper::decideType($nativeSignature->getReturnType(), $functionMapSignature->getReturnType())); + $returnType = TypehintHelper::decideType( + $nativeReturnType, + TypehintHelper::decideType( + $nativeSignature->getReturnType(), + $functionMapSignature->getReturnType(), + ), + ); } - return new FunctionSignature($parameters, $returnType, $nativeReturnType, $nativeSignature->isVariadic()); + return new FunctionSignature( + $parameters, + $returnType, + $nativeReturnType, + $nativeSignature->isVariadic(), + ); } public function hasMethodMetadata(string $className, string $methodName): bool @@ -349,10 +364,11 @@ public function getFunctionMetadata(string $functionName): array return $this->functionSignatureMapProvider->getFunctionMetadata($functionName); } - /** - * @param ClassMethod|Function_ $function - */ - private function getSignature($function, ?string $className, string $stubFile) : FunctionSignature + private function getSignature( + ClassMethod|Function_ $function, + ?string $className, + string $stubFile, + ): FunctionSignature { $phpDocParameterTypes = null; $phpDocReturnType = null; @@ -364,10 +380,14 @@ private function getSignature($function, ?string $className, string $stubFile) : } else { throw new ShouldNotHappenException(); } - $phpDoc = $this->fileTypeMapper->getResolvedPhpDoc($stubFile, $className, null, $functionName, $function->getDocComment()->getText()); - $phpDocParameterTypes = array_map(static function (ParamTag $param) : Type { - return $param->getType(); - }, $phpDoc->getParamTags()); + $phpDoc = $this->fileTypeMapper->getResolvedPhpDoc( + $stubFile, + $className, + null, + $functionName, + $function->getDocComment()->getText(), + ); + $phpDocParameterTypes = array_map(static fn (ParamTag $param): Type => $param->getType(), $phpDoc->getParamTags()); if ($phpDoc->getReturnTag() !== null) { $phpDocReturnType = $phpDoc->getReturnTag()->getType(); } @@ -380,12 +400,31 @@ private function getSignature($function, ?string $className, string $stubFile) : throw new ShouldNotHappenException(); } $parameterType = ParserNodeTypeToPHPStanType::resolve($param->type, null); - $parameters[] = new ParameterSignature($name->name, $param->default !== null || $param->variadic, TypehintHelper::decideType($parameterType, $phpDocParameterTypes[$name->name] ?? null), $parameterType, $param->byRef ? PassedByReference::createCreatesNewVariable() : PassedByReference::createNo(), $param->variadic, $param->default !== null ? $this->initializerExprTypeResolver->getType($param->default, InitializerExprContext::fromStubParameter($className, $stubFile, $function)) : null, null); + $parameters[] = new ParameterSignature( + $name->name, + $param->default !== null || $param->variadic, + TypehintHelper::decideType($parameterType, $phpDocParameterTypes[$name->name] ?? null), + $parameterType, + $param->byRef ? PassedByReference::createCreatesNewVariable() : PassedByReference::createNo(), + $param->variadic, + $param->default !== null ? $this->initializerExprTypeResolver->getType( + $param->default, + InitializerExprContext::fromStubParameter($className, $stubFile, $function), + ) : null, + null, + ); $variadic = $variadic || $param->variadic; } + $returnType = ParserNodeTypeToPHPStanType::resolve($function->getReturnType(), null); - return new FunctionSignature($parameters, TypehintHelper::decideType($returnType, $phpDocReturnType ?? null), $returnType, $variadic); + + return new FunctionSignature( + $parameters, + TypehintHelper::decideType($returnType, $phpDocReturnType ?? null), + $returnType, + $variadic, + ); } public function hasClassConstantMetadata(string $className, string $constantName): bool diff --git a/src/Reflection/SignatureMap/SignatureMapParser.php b/src/Reflection/SignatureMap/SignatureMapParser.php index b49ff3fe63e..b74f447ffad 100644 --- a/src/Reflection/SignatureMap/SignatureMapParser.php +++ b/src/Reflection/SignatureMap/SignatureMapParser.php @@ -16,12 +16,11 @@ class SignatureMapParser { - /** - * @var TypeStringResolver - */ - private $typeStringResolver; + private TypeStringResolver $typeStringResolver; - public function __construct(TypeStringResolver $typeNodeResolver) + public function __construct( + TypeStringResolver $typeNodeResolver, + ) { $this->typeStringResolver = $typeNodeResolver; } @@ -39,7 +38,12 @@ public function getFunctionSignature(array $map, ?string $className): FunctionSi break; } } - return new FunctionSignature($parameterSignatures, $this->getTypeFromString($map[0], $className), new MixedType(), $hasVariadic); + return new FunctionSignature( + $parameterSignatures, + $this->getTypeFromString($map[0], $className), + new MixedType(), + $hasVariadic, + ); } private function getTypeFromString(string $typeString, ?string $className): Type @@ -60,7 +64,16 @@ private function getParameters(array $parameterMap): array $parameterSignatures = []; foreach ($parameterMap as $parameterName => $typeString) { [$name, $isOptional, $passedByReference, $isVariadic] = $this->getParameterInfoFromName($parameterName); - $parameterSignatures[] = new ParameterSignature($name, $isOptional, $this->getTypeFromString($typeString, null), new MixedType(), $passedByReference, $isVariadic, null, null); + $parameterSignatures[] = new ParameterSignature( + $name, + $isOptional, + $this->getTypeFromString($typeString, null), + new MixedType(), + $passedByReference, + $isVariadic, + null, + null, + ); } return $parameterSignatures; @@ -71,7 +84,10 @@ private function getParameters(array $parameterMap): array */ private function getParameterInfoFromName(string $parameterNameString): array { - $matches = Strings::match($parameterNameString, '#^(?P&(?:\.\.\.)?r?w?_?)?(?P\.\.\.)?(?P[^=]+)?(?P=)?($)#'); + $matches = Strings::match( + $parameterNameString, + '#^(?P&(?:\.\.\.)?r?w?_?)?(?P\.\.\.)?(?P[^=]+)?(?P=)?($)#', + ); if ($matches === null || !isset($matches['optional'])) { throw new ShouldNotHappenException(); } diff --git a/src/Reflection/SignatureMap/SignatureMapProviderFactory.php b/src/Reflection/SignatureMap/SignatureMapProviderFactory.php index 2a8699777e0..2e318eefeb3 100644 --- a/src/Reflection/SignatureMap/SignatureMapProviderFactory.php +++ b/src/Reflection/SignatureMap/SignatureMapProviderFactory.php @@ -7,24 +7,14 @@ class SignatureMapProviderFactory { - /** - * @var PhpVersion - */ - private $phpVersion; - /** - * @var FunctionSignatureMapProvider - */ - private $functionSignatureMapProvider; - /** - * @var Php8SignatureMapProvider - */ - private $php8SignatureMapProvider; - public function __construct(PhpVersion $phpVersion, FunctionSignatureMapProvider $functionSignatureMapProvider, Php8SignatureMapProvider $php8SignatureMapProvider) + public function __construct( + private PhpVersion $phpVersion, + private FunctionSignatureMapProvider $functionSignatureMapProvider, + private Php8SignatureMapProvider $php8SignatureMapProvider, + ) { - $this->phpVersion = $phpVersion; - $this->functionSignatureMapProvider = $functionSignatureMapProvider; - $this->php8SignatureMapProvider = $php8SignatureMapProvider; } + public function create(): SignatureMapProvider { if ($this->phpVersion->getVersionId() < 80000) { diff --git a/src/Reflection/Type/CallbackUnresolvedMethodPrototypeReflection.php b/src/Reflection/Type/CallbackUnresolvedMethodPrototypeReflection.php index 47f757c1c02..61d7a2f00b8 100644 --- a/src/Reflection/Type/CallbackUnresolvedMethodPrototypeReflection.php +++ b/src/Reflection/Type/CallbackUnresolvedMethodPrototypeReflection.php @@ -16,39 +16,23 @@ class CallbackUnresolvedMethodPrototypeReflection implements UnresolvedMethodPrototypeReflection { - /** - * @var ExtendedMethodReflection - */ - private $methodReflection; - /** - * @var ClassReflection - */ - private $resolvedDeclaringClass; - /** - * @var bool - */ - private $resolveTemplateTypeMapToBounds; /** @var callable(Type): Type */ private $transformStaticTypeCallback; - /** - * @var ?ExtendedMethodReflection - */ - private $transformedMethod = null; + private ?ExtendedMethodReflection $transformedMethod = null; - /** - * @var ?self - */ - private $cachedDoNotResolveTemplateTypeMapToBounds = null; + private ?self $cachedDoNotResolveTemplateTypeMapToBounds = null; /** * @param callable(Type): Type $transformStaticTypeCallback */ - public function __construct(ExtendedMethodReflection $methodReflection, ClassReflection $resolvedDeclaringClass, bool $resolveTemplateTypeMapToBounds, callable $transformStaticTypeCallback) + public function __construct( + private ExtendedMethodReflection $methodReflection, + private ClassReflection $resolvedDeclaringClass, + private bool $resolveTemplateTypeMapToBounds, + callable $transformStaticTypeCallback, + ) { - $this->methodReflection = $methodReflection; - $this->resolvedDeclaringClass = $resolvedDeclaringClass; - $this->resolveTemplateTypeMapToBounds = $resolveTemplateTypeMapToBounds; $this->transformStaticTypeCallback = $transformStaticTypeCallback; } @@ -58,7 +42,12 @@ public function doNotResolveTemplateTypeMapToBounds(): UnresolvedMethodPrototype return $this->cachedDoNotResolveTemplateTypeMapToBounds; } - return $this->cachedDoNotResolveTemplateTypeMapToBounds = new self($this->methodReflection, $this->resolvedDeclaringClass, false, $this->transformStaticTypeCallback); + return $this->cachedDoNotResolveTemplateTypeMapToBounds = new self( + $this->methodReflection, + $this->resolvedDeclaringClass, + false, + $this->transformStaticTypeCallback, + ); } public function getNakedMethod(): ExtendedMethodReflection @@ -74,21 +63,48 @@ public function getTransformedMethod(): ExtendedMethodReflection $templateTypeMap = $this->resolvedDeclaringClass->getActiveTemplateTypeMap(); $callSiteVarianceMap = $this->resolvedDeclaringClass->getCallSiteVarianceMap(); - return $this->transformedMethod = new ResolvedMethodReflection($this->transformMethodWithStaticType($this->resolvedDeclaringClass, $this->methodReflection), $this->resolveTemplateTypeMapToBounds ? $templateTypeMap->resolveToBounds() : $templateTypeMap, $callSiteVarianceMap); + return $this->transformedMethod = new ResolvedMethodReflection( + $this->transformMethodWithStaticType($this->resolvedDeclaringClass, $this->methodReflection), + $this->resolveTemplateTypeMapToBounds ? $templateTypeMap->resolveToBounds() : $templateTypeMap, + $callSiteVarianceMap, + ); } public function withCalledOnType(Type $type): UnresolvedMethodPrototypeReflection { - return new CalledOnTypeUnresolvedMethodPrototypeReflection($this->methodReflection, $this->resolvedDeclaringClass, $this->resolveTemplateTypeMapToBounds, $type); + return new CalledOnTypeUnresolvedMethodPrototypeReflection( + $this->methodReflection, + $this->resolvedDeclaringClass, + $this->resolveTemplateTypeMapToBounds, + $type, + ); } private function transformMethodWithStaticType(ClassReflection $declaringClass, ExtendedMethodReflection $method): ExtendedMethodReflection { - $variantFn = function (ParametersAcceptorWithPhpDocs $acceptor) : ParametersAcceptorWithPhpDocs { - return new FunctionVariantWithPhpDocs($acceptor->getTemplateTypeMap(), $acceptor->getResolvedTemplateTypeMap(), array_map(function (ParameterReflectionWithPhpDocs $parameter) : ParameterReflectionWithPhpDocs { - return new DummyParameterWithPhpDocs($parameter->getName(), $this->transformStaticType($parameter->getType()), $parameter->isOptional(), $parameter->passedByReference(), $parameter->isVariadic(), $parameter->getDefaultValue(), $parameter->getNativeType(), $parameter->getPhpDocType(), $parameter->getOutType()); - }, $acceptor->getParameters()), $acceptor->isVariadic(), $this->transformStaticType($acceptor->getReturnType()), $this->transformStaticType($acceptor->getPhpDocReturnType()), $this->transformStaticType($acceptor->getNativeReturnType()), $acceptor->getCallSiteVarianceMap()); - }; + $variantFn = fn (ParametersAcceptorWithPhpDocs $acceptor): ParametersAcceptorWithPhpDocs => new FunctionVariantWithPhpDocs( + $acceptor->getTemplateTypeMap(), + $acceptor->getResolvedTemplateTypeMap(), + array_map( + fn (ParameterReflectionWithPhpDocs $parameter): ParameterReflectionWithPhpDocs => new DummyParameterWithPhpDocs( + $parameter->getName(), + $this->transformStaticType($parameter->getType()), + $parameter->isOptional(), + $parameter->passedByReference(), + $parameter->isVariadic(), + $parameter->getDefaultValue(), + $parameter->getNativeType(), + $parameter->getPhpDocType(), + $parameter->getOutType(), + ), + $acceptor->getParameters(), + ), + $acceptor->isVariadic(), + $this->transformStaticType($acceptor->getReturnType()), + $this->transformStaticType($acceptor->getPhpDocReturnType()), + $this->transformStaticType($acceptor->getNativeReturnType()), + $acceptor->getCallSiteVarianceMap(), + ); $variants = array_map($variantFn, $method->getVariants()); $namedArgumentVariants = $method->getNamedArgumentsVariants(); $namedArgumentVariants = $namedArgumentVariants !== null diff --git a/src/Reflection/Type/CallbackUnresolvedPropertyPrototypeReflection.php b/src/Reflection/Type/CallbackUnresolvedPropertyPrototypeReflection.php index 308f137f42d..5140d7296ba 100644 --- a/src/Reflection/Type/CallbackUnresolvedPropertyPrototypeReflection.php +++ b/src/Reflection/Type/CallbackUnresolvedPropertyPrototypeReflection.php @@ -11,39 +11,23 @@ class CallbackUnresolvedPropertyPrototypeReflection implements UnresolvedPropertyPrototypeReflection { - /** - * @var PropertyReflection - */ - private $propertyReflection; - /** - * @var ClassReflection - */ - private $resolvedDeclaringClass; - /** - * @var bool - */ - private $resolveTemplateTypeMapToBounds; /** @var callable(Type): Type */ private $transformStaticTypeCallback; - /** - * @var ?PropertyReflection - */ - private $transformedProperty = null; + private ?PropertyReflection $transformedProperty = null; - /** - * @var ?self - */ - private $cachedDoNotResolveTemplateTypeMapToBounds = null; + private ?self $cachedDoNotResolveTemplateTypeMapToBounds = null; /** * @param callable(Type): Type $transformStaticTypeCallback */ - public function __construct(PropertyReflection $propertyReflection, ClassReflection $resolvedDeclaringClass, bool $resolveTemplateTypeMapToBounds, callable $transformStaticTypeCallback) + public function __construct( + private PropertyReflection $propertyReflection, + private ClassReflection $resolvedDeclaringClass, + private bool $resolveTemplateTypeMapToBounds, + callable $transformStaticTypeCallback, + ) { - $this->propertyReflection = $propertyReflection; - $this->resolvedDeclaringClass = $resolvedDeclaringClass; - $this->resolveTemplateTypeMapToBounds = $resolveTemplateTypeMapToBounds; $this->transformStaticTypeCallback = $transformStaticTypeCallback; } @@ -53,7 +37,12 @@ public function doNotResolveTemplateTypeMapToBounds(): UnresolvedPropertyPrototy return $this->cachedDoNotResolveTemplateTypeMapToBounds; } - return $this->cachedDoNotResolveTemplateTypeMapToBounds = new self($this->propertyReflection, $this->resolvedDeclaringClass, false, $this->transformStaticTypeCallback); + return $this->cachedDoNotResolveTemplateTypeMapToBounds = new self( + $this->propertyReflection, + $this->resolvedDeclaringClass, + false, + $this->transformStaticTypeCallback, + ); } public function getNakedProperty(): PropertyReflection @@ -69,12 +58,21 @@ public function getTransformedProperty(): PropertyReflection $templateTypeMap = $this->resolvedDeclaringClass->getActiveTemplateTypeMap(); $callSiteVarianceMap = $this->resolvedDeclaringClass->getCallSiteVarianceMap(); - return $this->transformedProperty = new ResolvedPropertyReflection($this->transformPropertyWithStaticType($this->resolvedDeclaringClass, $this->propertyReflection), $this->resolveTemplateTypeMapToBounds ? $templateTypeMap->resolveToBounds() : $templateTypeMap, $callSiteVarianceMap); + return $this->transformedProperty = new ResolvedPropertyReflection( + $this->transformPropertyWithStaticType($this->resolvedDeclaringClass, $this->propertyReflection), + $this->resolveTemplateTypeMapToBounds ? $templateTypeMap->resolveToBounds() : $templateTypeMap, + $callSiteVarianceMap, + ); } public function withFechedOnType(Type $type): UnresolvedPropertyPrototypeReflection { - return new CalledOnTypeUnresolvedPropertyPrototypeReflection($this->propertyReflection, $this->resolvedDeclaringClass, $this->resolveTemplateTypeMapToBounds, $type); + return new CalledOnTypeUnresolvedPropertyPrototypeReflection( + $this->propertyReflection, + $this->resolvedDeclaringClass, + $this->resolveTemplateTypeMapToBounds, + $type, + ); } private function transformPropertyWithStaticType(ClassReflection $declaringClass, PropertyReflection $property): PropertyReflection diff --git a/src/Reflection/Type/CalledOnTypeUnresolvedMethodPrototypeReflection.php b/src/Reflection/Type/CalledOnTypeUnresolvedMethodPrototypeReflection.php index 73f0be8078d..a76cf064aab 100644 --- a/src/Reflection/Type/CalledOnTypeUnresolvedMethodPrototypeReflection.php +++ b/src/Reflection/Type/CalledOnTypeUnresolvedMethodPrototypeReflection.php @@ -18,38 +18,17 @@ class CalledOnTypeUnresolvedMethodPrototypeReflection implements UnresolvedMethodPrototypeReflection { - /** - * @var ExtendedMethodReflection - */ - private $methodReflection; - /** - * @var ClassReflection - */ - private $resolvedDeclaringClass; - /** - * @var bool - */ - private $resolveTemplateTypeMapToBounds; - /** - * @var Type - */ - private $calledOnType; - /** - * @var ?ExtendedMethodReflection - */ - private $transformedMethod = null; - - /** - * @var ?self - */ - private $cachedDoNotResolveTemplateTypeMapToBounds = null; - - public function __construct(ExtendedMethodReflection $methodReflection, ClassReflection $resolvedDeclaringClass, bool $resolveTemplateTypeMapToBounds, Type $calledOnType) + private ?ExtendedMethodReflection $transformedMethod = null; + + private ?self $cachedDoNotResolveTemplateTypeMapToBounds = null; + + public function __construct( + private ExtendedMethodReflection $methodReflection, + private ClassReflection $resolvedDeclaringClass, + private bool $resolveTemplateTypeMapToBounds, + private Type $calledOnType, + ) { - $this->methodReflection = $methodReflection; - $this->resolvedDeclaringClass = $resolvedDeclaringClass; - $this->resolveTemplateTypeMapToBounds = $resolveTemplateTypeMapToBounds; - $this->calledOnType = $calledOnType; } public function doNotResolveTemplateTypeMapToBounds(): UnresolvedMethodPrototypeReflection @@ -58,7 +37,12 @@ public function doNotResolveTemplateTypeMapToBounds(): UnresolvedMethodPrototype return $this->cachedDoNotResolveTemplateTypeMapToBounds; } - return $this->cachedDoNotResolveTemplateTypeMapToBounds = new self($this->methodReflection, $this->resolvedDeclaringClass, false, $this->calledOnType); + return $this->cachedDoNotResolveTemplateTypeMapToBounds = new self( + $this->methodReflection, + $this->resolvedDeclaringClass, + false, + $this->calledOnType, + ); } public function getNakedMethod(): ExtendedMethodReflection @@ -74,21 +58,48 @@ public function getTransformedMethod(): ExtendedMethodReflection $templateTypeMap = $this->resolvedDeclaringClass->getActiveTemplateTypeMap(); $callSiteVarianceMap = $this->resolvedDeclaringClass->getCallSiteVarianceMap(); - return $this->transformedMethod = new ResolvedMethodReflection($this->transformMethodWithStaticType($this->resolvedDeclaringClass, $this->methodReflection), $this->resolveTemplateTypeMapToBounds ? $templateTypeMap->resolveToBounds() : $templateTypeMap, $callSiteVarianceMap); + return $this->transformedMethod = new ResolvedMethodReflection( + $this->transformMethodWithStaticType($this->resolvedDeclaringClass, $this->methodReflection), + $this->resolveTemplateTypeMapToBounds ? $templateTypeMap->resolveToBounds() : $templateTypeMap, + $callSiteVarianceMap, + ); } public function withCalledOnType(Type $type): UnresolvedMethodPrototypeReflection { - return new self($this->methodReflection, $this->resolvedDeclaringClass, $this->resolveTemplateTypeMapToBounds, $type); + return new self( + $this->methodReflection, + $this->resolvedDeclaringClass, + $this->resolveTemplateTypeMapToBounds, + $type, + ); } private function transformMethodWithStaticType(ClassReflection $declaringClass, ExtendedMethodReflection $method): ExtendedMethodReflection { - $variantFn = function (ParametersAcceptorWithPhpDocs $acceptor) : ParametersAcceptorWithPhpDocs { - return new FunctionVariantWithPhpDocs($acceptor->getTemplateTypeMap(), $acceptor->getResolvedTemplateTypeMap(), array_map(function (ParameterReflectionWithPhpDocs $parameter) : ParameterReflectionWithPhpDocs { - return new DummyParameterWithPhpDocs($parameter->getName(), $this->transformStaticType($parameter->getType()), $parameter->isOptional(), $parameter->passedByReference(), $parameter->isVariadic(), $parameter->getDefaultValue(), $parameter->getNativeType(), $parameter->getPhpDocType(), $parameter->getOutType()); - }, $acceptor->getParameters()), $acceptor->isVariadic(), $this->transformStaticType($acceptor->getReturnType()), $this->transformStaticType($acceptor->getPhpDocReturnType()), $this->transformStaticType($acceptor->getNativeReturnType()), $acceptor->getCallSiteVarianceMap()); - }; + $variantFn = fn (ParametersAcceptorWithPhpDocs $acceptor): ParametersAcceptorWithPhpDocs => new FunctionVariantWithPhpDocs( + $acceptor->getTemplateTypeMap(), + $acceptor->getResolvedTemplateTypeMap(), + array_map( + fn (ParameterReflectionWithPhpDocs $parameter): ParameterReflectionWithPhpDocs => new DummyParameterWithPhpDocs( + $parameter->getName(), + $this->transformStaticType($parameter->getType()), + $parameter->isOptional(), + $parameter->passedByReference(), + $parameter->isVariadic(), + $parameter->getDefaultValue(), + $parameter->getNativeType(), + $parameter->getPhpDocType(), + $parameter->getOutType(), + ), + $acceptor->getParameters(), + ), + $acceptor->isVariadic(), + $this->transformStaticType($acceptor->getReturnType()), + $this->transformStaticType($acceptor->getPhpDocReturnType()), + $this->transformStaticType($acceptor->getNativeReturnType()), + $acceptor->getCallSiteVarianceMap(), + ); $variants = array_map($variantFn, $method->getVariants()); $namedArgumentsVariants = $method->getNamedArgumentsVariants(); $namedArgumentsVariants = $namedArgumentsVariants !== null diff --git a/src/Reflection/Type/CalledOnTypeUnresolvedPropertyPrototypeReflection.php b/src/Reflection/Type/CalledOnTypeUnresolvedPropertyPrototypeReflection.php index 85c50007360..e9a8b8a1612 100644 --- a/src/Reflection/Type/CalledOnTypeUnresolvedPropertyPrototypeReflection.php +++ b/src/Reflection/Type/CalledOnTypeUnresolvedPropertyPrototypeReflection.php @@ -13,38 +13,17 @@ class CalledOnTypeUnresolvedPropertyPrototypeReflection implements UnresolvedPropertyPrototypeReflection { - /** - * @var PropertyReflection - */ - private $propertyReflection; - /** - * @var ClassReflection - */ - private $resolvedDeclaringClass; - /** - * @var bool - */ - private $resolveTemplateTypeMapToBounds; - /** - * @var Type - */ - private $fetchedOnType; - /** - * @var ?PropertyReflection - */ - private $transformedProperty = null; - - /** - * @var ?self - */ - private $cachedDoNotResolveTemplateTypeMapToBounds = null; - - public function __construct(PropertyReflection $propertyReflection, ClassReflection $resolvedDeclaringClass, bool $resolveTemplateTypeMapToBounds, Type $fetchedOnType) + private ?PropertyReflection $transformedProperty = null; + + private ?self $cachedDoNotResolveTemplateTypeMapToBounds = null; + + public function __construct( + private PropertyReflection $propertyReflection, + private ClassReflection $resolvedDeclaringClass, + private bool $resolveTemplateTypeMapToBounds, + private Type $fetchedOnType, + ) { - $this->propertyReflection = $propertyReflection; - $this->resolvedDeclaringClass = $resolvedDeclaringClass; - $this->resolveTemplateTypeMapToBounds = $resolveTemplateTypeMapToBounds; - $this->fetchedOnType = $fetchedOnType; } public function doNotResolveTemplateTypeMapToBounds(): UnresolvedPropertyPrototypeReflection @@ -53,7 +32,12 @@ public function doNotResolveTemplateTypeMapToBounds(): UnresolvedPropertyPrototy return $this->cachedDoNotResolveTemplateTypeMapToBounds; } - return $this->cachedDoNotResolveTemplateTypeMapToBounds = new self($this->propertyReflection, $this->resolvedDeclaringClass, false, $this->fetchedOnType); + return $this->cachedDoNotResolveTemplateTypeMapToBounds = new self( + $this->propertyReflection, + $this->resolvedDeclaringClass, + false, + $this->fetchedOnType, + ); } public function getNakedProperty(): PropertyReflection @@ -69,12 +53,21 @@ public function getTransformedProperty(): PropertyReflection $templateTypeMap = $this->resolvedDeclaringClass->getActiveTemplateTypeMap(); $callSiteVarianceMap = $this->resolvedDeclaringClass->getCallSiteVarianceMap(); - return $this->transformedProperty = new ResolvedPropertyReflection($this->transformPropertyWithStaticType($this->resolvedDeclaringClass, $this->propertyReflection), $this->resolveTemplateTypeMapToBounds ? $templateTypeMap->resolveToBounds() : $templateTypeMap, $callSiteVarianceMap); + return $this->transformedProperty = new ResolvedPropertyReflection( + $this->transformPropertyWithStaticType($this->resolvedDeclaringClass, $this->propertyReflection), + $this->resolveTemplateTypeMapToBounds ? $templateTypeMap->resolveToBounds() : $templateTypeMap, + $callSiteVarianceMap, + ); } public function withFechedOnType(Type $type): UnresolvedPropertyPrototypeReflection { - return new self($this->propertyReflection, $this->resolvedDeclaringClass, $this->resolveTemplateTypeMapToBounds, $type); + return new self( + $this->propertyReflection, + $this->resolvedDeclaringClass, + $this->resolveTemplateTypeMapToBounds, + $type, + ); } private function transformPropertyWithStaticType(ClassReflection $declaringClass, PropertyReflection $property): PropertyReflection diff --git a/src/Reflection/Type/IntersectionTypeMethodReflection.php b/src/Reflection/Type/IntersectionTypeMethodReflection.php index 074d4ad1147..bf8dd278534 100644 --- a/src/Reflection/Type/IntersectionTypeMethodReflection.php +++ b/src/Reflection/Type/IntersectionTypeMethodReflection.php @@ -21,21 +21,11 @@ class IntersectionTypeMethodReflection implements ExtendedMethodReflection { - /** - * @var string - */ - private $methodName; - /** - * @var ExtendedMethodReflection[] - */ - private $methods; /** * @param ExtendedMethodReflection[] $methods */ - public function __construct(string $methodName, array $methods) + public function __construct(private string $methodName, private array $methods) { - $this->methodName = $methodName; - $this->methods = $methods; } public function getDeclaringClass(): ClassReflection @@ -88,25 +78,20 @@ public function getPrototype(): ClassMemberReflection public function getVariants(): array { - $returnType = TypeCombinator::intersect(...array_map(static function (MethodReflection $method) : Type { - return TypeCombinator::intersect(...array_map(static function (ParametersAcceptor $acceptor) : Type { - return $acceptor->getReturnType(); - }, $method->getVariants())); - }, $this->methods)); - $phpDocReturnType = TypeCombinator::intersect(...array_map(static function (MethodReflection $method) : Type { - return TypeCombinator::intersect(...array_map(static function (ParametersAcceptor $acceptor) : Type { - return $acceptor->getPhpDocReturnType(); - }, $method->getVariants())); - }, $this->methods)); - $nativeReturnType = TypeCombinator::intersect(...array_map(static function (MethodReflection $method) : Type { - return TypeCombinator::intersect(...array_map(static function (ParametersAcceptor $acceptor) : Type { - return $acceptor->getNativeReturnType(); - }, $method->getVariants())); - }, $this->methods)); - - return array_map(static function (ParametersAcceptorWithPhpDocs $acceptor) use($returnType, $phpDocReturnType, $nativeReturnType) : ParametersAcceptorWithPhpDocs { - return new FunctionVariantWithPhpDocs($acceptor->getTemplateTypeMap(), $acceptor->getResolvedTemplateTypeMap(), $acceptor->getParameters(), $acceptor->isVariadic(), $returnType, $phpDocReturnType, $nativeReturnType, $acceptor->getCallSiteVarianceMap()); - }, $this->methods[0]->getVariants()); + $returnType = TypeCombinator::intersect(...array_map(static fn (MethodReflection $method): Type => TypeCombinator::intersect(...array_map(static fn (ParametersAcceptor $acceptor): Type => $acceptor->getReturnType(), $method->getVariants())), $this->methods)); + $phpDocReturnType = TypeCombinator::intersect(...array_map(static fn (MethodReflection $method): Type => TypeCombinator::intersect(...array_map(static fn (ParametersAcceptor $acceptor): Type => $acceptor->getPhpDocReturnType(), $method->getVariants())), $this->methods)); + $nativeReturnType = TypeCombinator::intersect(...array_map(static fn (MethodReflection $method): Type => TypeCombinator::intersect(...array_map(static fn (ParametersAcceptor $acceptor): Type => $acceptor->getNativeReturnType(), $method->getVariants())), $this->methods)); + + return array_map(static fn (ParametersAcceptorWithPhpDocs $acceptor): ParametersAcceptorWithPhpDocs => new FunctionVariantWithPhpDocs( + $acceptor->getTemplateTypeMap(), + $acceptor->getResolvedTemplateTypeMap(), + $acceptor->getParameters(), + $acceptor->isVariadic(), + $returnType, + $phpDocReturnType, + $nativeReturnType, + $acceptor->getCallSiteVarianceMap(), + ), $this->methods[0]->getVariants()); } public function getNamedArgumentsVariants(): ?array @@ -116,9 +101,7 @@ public function getNamedArgumentsVariants(): ?array public function isDeprecated(): TrinaryLogic { - return TrinaryLogic::lazyMaxMin($this->methods, static function (MethodReflection $method) : TrinaryLogic { - return $method->isDeprecated(); - }); + return TrinaryLogic::lazyMaxMin($this->methods, static fn (MethodReflection $method): TrinaryLogic => $method->isDeprecated()); } public function getDeprecatedDescription(): ?string @@ -145,23 +128,17 @@ public function getDeprecatedDescription(): ?string public function isFinal(): TrinaryLogic { - return TrinaryLogic::lazyMaxMin($this->methods, static function (MethodReflection $method) : TrinaryLogic { - return $method->isFinal(); - }); + return TrinaryLogic::lazyMaxMin($this->methods, static fn (MethodReflection $method): TrinaryLogic => $method->isFinal()); } public function isFinalByKeyword(): TrinaryLogic { - return TrinaryLogic::lazyMaxMin($this->methods, static function (ExtendedMethodReflection $method) : TrinaryLogic { - return $method->isFinalByKeyword(); - }); + return TrinaryLogic::lazyMaxMin($this->methods, static fn (ExtendedMethodReflection $method): TrinaryLogic => $method->isFinalByKeyword()); } public function isInternal(): TrinaryLogic { - return TrinaryLogic::lazyMaxMin($this->methods, static function (MethodReflection $method) : TrinaryLogic { - return $method->isInternal(); - }); + return TrinaryLogic::lazyMaxMin($this->methods, static fn (MethodReflection $method): TrinaryLogic => $method->isInternal()); } public function getThrowType(): ?Type @@ -186,9 +163,7 @@ public function getThrowType(): ?Type public function hasSideEffects(): TrinaryLogic { - return TrinaryLogic::lazyMaxMin($this->methods, static function (MethodReflection $method) : TrinaryLogic { - return $method->hasSideEffects(); - }); + return TrinaryLogic::lazyMaxMin($this->methods, static fn (MethodReflection $method): TrinaryLogic => $method->hasSideEffects()); } public function getDocComment(): ?string @@ -214,16 +189,12 @@ public function getSelfOutType(): ?Type public function returnsByReference(): TrinaryLogic { - return TrinaryLogic::lazyMaxMin($this->methods, static function (ExtendedMethodReflection $method) : TrinaryLogic { - return $method->returnsByReference(); - }); + return TrinaryLogic::lazyMaxMin($this->methods, static fn (ExtendedMethodReflection $method): TrinaryLogic => $method->returnsByReference()); } public function isAbstract(): TrinaryLogic { - return TrinaryLogic::lazyMaxMin($this->methods, static function (ExtendedMethodReflection $method) : TrinaryLogic { - return is_bool($method->isAbstract()) ? TrinaryLogic::createFromBoolean($method->isAbstract()) : $method->isAbstract(); - }); + return TrinaryLogic::lazyMaxMin($this->methods, static fn (ExtendedMethodReflection $method): TrinaryLogic => is_bool($method->isAbstract()) ? TrinaryLogic::createFromBoolean($method->isAbstract()) : $method->isAbstract()); } } diff --git a/src/Reflection/Type/IntersectionTypePropertyReflection.php b/src/Reflection/Type/IntersectionTypePropertyReflection.php index 8f90f73834c..e93cc59e671 100644 --- a/src/Reflection/Type/IntersectionTypePropertyReflection.php +++ b/src/Reflection/Type/IntersectionTypePropertyReflection.php @@ -14,16 +14,11 @@ class IntersectionTypePropertyReflection implements PropertyReflection { - /** - * @var PropertyReflection[] - */ - private $properties; /** * @param PropertyReflection[] $properties */ - public function __construct(array $properties) + public function __construct(private array $properties) { - $this->properties = $properties; } public function getDeclaringClass(): ClassReflection @@ -33,30 +28,22 @@ public function getDeclaringClass(): ClassReflection public function isStatic(): bool { - return $this->computeResult(static function (PropertyReflection $property) { - return $property->isStatic(); - }); + return $this->computeResult(static fn (PropertyReflection $property) => $property->isStatic()); } public function isPrivate(): bool { - return $this->computeResult(static function (PropertyReflection $property) { - return $property->isPrivate(); - }); + return $this->computeResult(static fn (PropertyReflection $property) => $property->isPrivate()); } public function isPublic(): bool { - return $this->computeResult(static function (PropertyReflection $property) { - return $property->isPublic(); - }); + return $this->computeResult(static fn (PropertyReflection $property) => $property->isPublic()); } public function isDeprecated(): TrinaryLogic { - return TrinaryLogic::lazyMaxMin($this->properties, static function (PropertyReflection $propertyReflection) : TrinaryLogic { - return $propertyReflection->isDeprecated(); - }); + return TrinaryLogic::lazyMaxMin($this->properties, static fn (PropertyReflection $propertyReflection): TrinaryLogic => $propertyReflection->isDeprecated()); } public function getDeprecatedDescription(): ?string @@ -83,9 +70,7 @@ public function getDeprecatedDescription(): ?string public function isInternal(): TrinaryLogic { - return TrinaryLogic::lazyMaxMin($this->properties, static function (PropertyReflection $propertyReflection) : TrinaryLogic { - return $propertyReflection->isInternal(); - }); + return TrinaryLogic::lazyMaxMin($this->properties, static fn (PropertyReflection $propertyReflection): TrinaryLogic => $propertyReflection->isInternal()); } public function getDocComment(): ?string @@ -95,37 +80,27 @@ public function getDocComment(): ?string public function getReadableType(): Type { - return TypeCombinator::intersect(...array_map(static function (PropertyReflection $property) : Type { - return $property->getReadableType(); - }, $this->properties)); + return TypeCombinator::intersect(...array_map(static fn (PropertyReflection $property): Type => $property->getReadableType(), $this->properties)); } public function getWritableType(): Type { - return TypeCombinator::intersect(...array_map(static function (PropertyReflection $property) : Type { - return $property->getWritableType(); - }, $this->properties)); + return TypeCombinator::intersect(...array_map(static fn (PropertyReflection $property): Type => $property->getWritableType(), $this->properties)); } public function canChangeTypeAfterAssignment(): bool { - return $this->computeResult(static function (PropertyReflection $property) { - return $property->canChangeTypeAfterAssignment(); - }); + return $this->computeResult(static fn (PropertyReflection $property) => $property->canChangeTypeAfterAssignment()); } public function isReadable(): bool { - return $this->computeResult(static function (PropertyReflection $property) { - return $property->isReadable(); - }); + return $this->computeResult(static fn (PropertyReflection $property) => $property->isReadable()); } public function isWritable(): bool { - return $this->computeResult(static function (PropertyReflection $property) { - return $property->isWritable(); - }); + return $this->computeResult(static fn (PropertyReflection $property) => $property->isWritable()); } /** diff --git a/src/Reflection/Type/IntersectionTypeUnresolvedMethodPrototypeReflection.php b/src/Reflection/Type/IntersectionTypeUnresolvedMethodPrototypeReflection.php index d3680b2199b..5cda2321f1b 100644 --- a/src/Reflection/Type/IntersectionTypeUnresolvedMethodPrototypeReflection.php +++ b/src/Reflection/Type/IntersectionTypeUnresolvedMethodPrototypeReflection.php @@ -10,31 +10,18 @@ class IntersectionTypeUnresolvedMethodPrototypeReflection implements UnresolvedMethodPrototypeReflection { - /** - * @var string - */ - private $methodName; - /** - * @var UnresolvedMethodPrototypeReflection[] - */ - private $methodPrototypes; - /** - * @var ?ExtendedMethodReflection - */ - private $transformedMethod = null; + private ?ExtendedMethodReflection $transformedMethod = null; - /** - * @var ?self - */ - private $cachedDoNotResolveTemplateTypeMapToBounds = null; + private ?self $cachedDoNotResolveTemplateTypeMapToBounds = null; /** * @param UnresolvedMethodPrototypeReflection[] $methodPrototypes */ - public function __construct(string $methodName, array $methodPrototypes) + public function __construct( + private string $methodName, + private array $methodPrototypes, + ) { - $this->methodName = $methodName; - $this->methodPrototypes = $methodPrototypes; } public function doNotResolveTemplateTypeMapToBounds(): UnresolvedMethodPrototypeReflection @@ -43,9 +30,7 @@ public function doNotResolveTemplateTypeMapToBounds(): UnresolvedMethodPrototype return $this->cachedDoNotResolveTemplateTypeMapToBounds; } - return $this->cachedDoNotResolveTemplateTypeMapToBounds = new self($this->methodName, array_map(static function (UnresolvedMethodPrototypeReflection $prototype) : UnresolvedMethodPrototypeReflection { - return $prototype->doNotResolveTemplateTypeMapToBounds(); - }, $this->methodPrototypes)); + return $this->cachedDoNotResolveTemplateTypeMapToBounds = new self($this->methodName, array_map(static fn (UnresolvedMethodPrototypeReflection $prototype): UnresolvedMethodPrototypeReflection => $prototype->doNotResolveTemplateTypeMapToBounds(), $this->methodPrototypes)); } public function getNakedMethod(): ExtendedMethodReflection @@ -58,18 +43,14 @@ public function getTransformedMethod(): ExtendedMethodReflection if ($this->transformedMethod !== null) { return $this->transformedMethod; } - $methods = array_map(static function (UnresolvedMethodPrototypeReflection $prototype) : MethodReflection { - return $prototype->getTransformedMethod(); - }, $this->methodPrototypes); + $methods = array_map(static fn (UnresolvedMethodPrototypeReflection $prototype): MethodReflection => $prototype->getTransformedMethod(), $this->methodPrototypes); return $this->transformedMethod = new IntersectionTypeMethodReflection($this->methodName, $methods); } public function withCalledOnType(Type $type): UnresolvedMethodPrototypeReflection { - return new self($this->methodName, array_map(static function (UnresolvedMethodPrototypeReflection $prototype) use($type) : UnresolvedMethodPrototypeReflection { - return $prototype->withCalledOnType($type); - }, $this->methodPrototypes)); + return new self($this->methodName, array_map(static fn (UnresolvedMethodPrototypeReflection $prototype): UnresolvedMethodPrototypeReflection => $prototype->withCalledOnType($type), $this->methodPrototypes)); } } diff --git a/src/Reflection/Type/IntersectionTypeUnresolvedPropertyPrototypeReflection.php b/src/Reflection/Type/IntersectionTypeUnresolvedPropertyPrototypeReflection.php index a31f8c90093..fdfea4ebf94 100644 --- a/src/Reflection/Type/IntersectionTypeUnresolvedPropertyPrototypeReflection.php +++ b/src/Reflection/Type/IntersectionTypeUnresolvedPropertyPrototypeReflection.php @@ -9,31 +9,18 @@ class IntersectionTypeUnresolvedPropertyPrototypeReflection implements UnresolvedPropertyPrototypeReflection { - /** - * @var string - */ - private $propertyName; - /** - * @var UnresolvedPropertyPrototypeReflection[] - */ - private $propertyPrototypes; - /** - * @var ?PropertyReflection - */ - private $transformedProperty = null; + private ?PropertyReflection $transformedProperty = null; - /** - * @var ?self - */ - private $cachedDoNotResolveTemplateTypeMapToBounds = null; + private ?self $cachedDoNotResolveTemplateTypeMapToBounds = null; /** * @param UnresolvedPropertyPrototypeReflection[] $propertyPrototypes */ - public function __construct(string $propertyName, array $propertyPrototypes) + public function __construct( + private string $propertyName, + private array $propertyPrototypes, + ) { - $this->propertyName = $propertyName; - $this->propertyPrototypes = $propertyPrototypes; } public function doNotResolveTemplateTypeMapToBounds(): UnresolvedPropertyPrototypeReflection @@ -42,9 +29,7 @@ public function doNotResolveTemplateTypeMapToBounds(): UnresolvedPropertyPrototy return $this->cachedDoNotResolveTemplateTypeMapToBounds; } - return $this->cachedDoNotResolveTemplateTypeMapToBounds = new self($this->propertyName, array_map(static function (UnresolvedPropertyPrototypeReflection $prototype) : UnresolvedPropertyPrototypeReflection { - return $prototype->doNotResolveTemplateTypeMapToBounds(); - }, $this->propertyPrototypes)); + return $this->cachedDoNotResolveTemplateTypeMapToBounds = new self($this->propertyName, array_map(static fn (UnresolvedPropertyPrototypeReflection $prototype): UnresolvedPropertyPrototypeReflection => $prototype->doNotResolveTemplateTypeMapToBounds(), $this->propertyPrototypes)); } public function getNakedProperty(): PropertyReflection @@ -57,18 +42,14 @@ public function getTransformedProperty(): PropertyReflection if ($this->transformedProperty !== null) { return $this->transformedProperty; } - $properties = array_map(static function (UnresolvedPropertyPrototypeReflection $prototype) : PropertyReflection { - return $prototype->getTransformedProperty(); - }, $this->propertyPrototypes); + $properties = array_map(static fn (UnresolvedPropertyPrototypeReflection $prototype): PropertyReflection => $prototype->getTransformedProperty(), $this->propertyPrototypes); return $this->transformedProperty = new IntersectionTypePropertyReflection($properties); } public function withFechedOnType(Type $type): UnresolvedPropertyPrototypeReflection { - return new self($this->propertyName, array_map(static function (UnresolvedPropertyPrototypeReflection $prototype) use($type) : UnresolvedPropertyPrototypeReflection { - return $prototype->withFechedOnType($type); - }, $this->propertyPrototypes)); + return new self($this->propertyName, array_map(static fn (UnresolvedPropertyPrototypeReflection $prototype): UnresolvedPropertyPrototypeReflection => $prototype->withFechedOnType($type), $this->propertyPrototypes)); } } diff --git a/src/Reflection/Type/UnionTypeMethodReflection.php b/src/Reflection/Type/UnionTypeMethodReflection.php index 0f4f648317e..61298dbf0c7 100644 --- a/src/Reflection/Type/UnionTypeMethodReflection.php +++ b/src/Reflection/Type/UnionTypeMethodReflection.php @@ -20,21 +20,11 @@ class UnionTypeMethodReflection implements ExtendedMethodReflection { - /** - * @var string - */ - private $methodName; - /** - * @var ExtendedMethodReflection[] - */ - private $methods; /** * @param ExtendedMethodReflection[] $methods */ - public function __construct(string $methodName, array $methods) + public function __construct(private string $methodName, private array $methods) { - $this->methodName = $methodName; - $this->methods = $methods; } public function getDeclaringClass(): ClassReflection @@ -87,9 +77,7 @@ public function getPrototype(): ClassMemberReflection public function getVariants(): array { - $variants = array_merge(...array_map(static function (MethodReflection $method) { - return $method->getVariants(); - }, $this->methods)); + $variants = array_merge(...array_map(static fn (MethodReflection $method) => $method->getVariants(), $this->methods)); return [ParametersAcceptorSelector::combineAcceptors($variants)]; } @@ -101,9 +89,7 @@ public function getNamedArgumentsVariants(): ?array public function isDeprecated(): TrinaryLogic { - return TrinaryLogic::lazyExtremeIdentity($this->methods, static function (MethodReflection $method) : TrinaryLogic { - return $method->isDeprecated(); - }); + return TrinaryLogic::lazyExtremeIdentity($this->methods, static fn (MethodReflection $method): TrinaryLogic => $method->isDeprecated()); } public function getDeprecatedDescription(): ?string @@ -130,23 +116,17 @@ public function getDeprecatedDescription(): ?string public function isFinal(): TrinaryLogic { - return TrinaryLogic::lazyExtremeIdentity($this->methods, static function (MethodReflection $method) : TrinaryLogic { - return $method->isFinal(); - }); + return TrinaryLogic::lazyExtremeIdentity($this->methods, static fn (MethodReflection $method): TrinaryLogic => $method->isFinal()); } public function isFinalByKeyword(): TrinaryLogic { - return TrinaryLogic::lazyExtremeIdentity($this->methods, static function (ExtendedMethodReflection $method) : TrinaryLogic { - return $method->isFinalByKeyword(); - }); + return TrinaryLogic::lazyExtremeIdentity($this->methods, static fn (ExtendedMethodReflection $method): TrinaryLogic => $method->isFinalByKeyword()); } public function isInternal(): TrinaryLogic { - return TrinaryLogic::lazyExtremeIdentity($this->methods, static function (MethodReflection $method) : TrinaryLogic { - return $method->isInternal(); - }); + return TrinaryLogic::lazyExtremeIdentity($this->methods, static fn (MethodReflection $method): TrinaryLogic => $method->isInternal()); } public function getThrowType(): ?Type @@ -171,9 +151,7 @@ public function getThrowType(): ?Type public function hasSideEffects(): TrinaryLogic { - return TrinaryLogic::lazyExtremeIdentity($this->methods, static function (MethodReflection $method) : TrinaryLogic { - return $method->hasSideEffects(); - }); + return TrinaryLogic::lazyExtremeIdentity($this->methods, static fn (MethodReflection $method): TrinaryLogic => $method->hasSideEffects()); } public function getDocComment(): ?string @@ -193,16 +171,12 @@ public function getSelfOutType(): ?Type public function returnsByReference(): TrinaryLogic { - return TrinaryLogic::lazyExtremeIdentity($this->methods, static function (ExtendedMethodReflection $method) : TrinaryLogic { - return $method->returnsByReference(); - }); + return TrinaryLogic::lazyExtremeIdentity($this->methods, static fn (ExtendedMethodReflection $method): TrinaryLogic => $method->returnsByReference()); } public function isAbstract(): TrinaryLogic { - return TrinaryLogic::lazyExtremeIdentity($this->methods, static function (ExtendedMethodReflection $method) : TrinaryLogic { - return is_bool($method->isAbstract()) ? TrinaryLogic::createFromBoolean($method->isAbstract()) : $method->isAbstract(); - }); + return TrinaryLogic::lazyExtremeIdentity($this->methods, static fn (ExtendedMethodReflection $method): TrinaryLogic => is_bool($method->isAbstract()) ? TrinaryLogic::createFromBoolean($method->isAbstract()) : $method->isAbstract()); } } diff --git a/src/Reflection/Type/UnionTypePropertyReflection.php b/src/Reflection/Type/UnionTypePropertyReflection.php index dd7d5c0e844..d2587839c37 100644 --- a/src/Reflection/Type/UnionTypePropertyReflection.php +++ b/src/Reflection/Type/UnionTypePropertyReflection.php @@ -14,16 +14,11 @@ class UnionTypePropertyReflection implements PropertyReflection { - /** - * @var PropertyReflection[] - */ - private $properties; /** * @param PropertyReflection[] $properties */ - public function __construct(array $properties) + public function __construct(private array $properties) { - $this->properties = $properties; } public function getDeclaringClass(): ClassReflection @@ -33,30 +28,22 @@ public function getDeclaringClass(): ClassReflection public function isStatic(): bool { - return $this->computeResult(static function (PropertyReflection $property) { - return $property->isStatic(); - }); + return $this->computeResult(static fn (PropertyReflection $property) => $property->isStatic()); } public function isPrivate(): bool { - return $this->computeResult(static function (PropertyReflection $property) { - return $property->isPrivate(); - }); + return $this->computeResult(static fn (PropertyReflection $property) => $property->isPrivate()); } public function isPublic(): bool { - return $this->computeResult(static function (PropertyReflection $property) { - return $property->isPublic(); - }); + return $this->computeResult(static fn (PropertyReflection $property) => $property->isPublic()); } public function isDeprecated(): TrinaryLogic { - return TrinaryLogic::lazyExtremeIdentity($this->properties, static function (PropertyReflection $propertyReflection) : TrinaryLogic { - return $propertyReflection->isDeprecated(); - }); + return TrinaryLogic::lazyExtremeIdentity($this->properties, static fn (PropertyReflection $propertyReflection): TrinaryLogic => $propertyReflection->isDeprecated()); } public function getDeprecatedDescription(): ?string @@ -83,9 +70,7 @@ public function getDeprecatedDescription(): ?string public function isInternal(): TrinaryLogic { - return TrinaryLogic::lazyExtremeIdentity($this->properties, static function (PropertyReflection $propertyReflection) : TrinaryLogic { - return $propertyReflection->isInternal(); - }); + return TrinaryLogic::lazyExtremeIdentity($this->properties, static fn (PropertyReflection $propertyReflection): TrinaryLogic => $propertyReflection->isInternal()); } public function getDocComment(): ?string @@ -95,37 +80,27 @@ public function getDocComment(): ?string public function getReadableType(): Type { - return TypeCombinator::union(...array_map(static function (PropertyReflection $property) : Type { - return $property->getReadableType(); - }, $this->properties)); + return TypeCombinator::union(...array_map(static fn (PropertyReflection $property): Type => $property->getReadableType(), $this->properties)); } public function getWritableType(): Type { - return TypeCombinator::union(...array_map(static function (PropertyReflection $property) : Type { - return $property->getWritableType(); - }, $this->properties)); + return TypeCombinator::union(...array_map(static fn (PropertyReflection $property): Type => $property->getWritableType(), $this->properties)); } public function canChangeTypeAfterAssignment(): bool { - return $this->computeResult(static function (PropertyReflection $property) { - return $property->canChangeTypeAfterAssignment(); - }); + return $this->computeResult(static fn (PropertyReflection $property) => $property->canChangeTypeAfterAssignment()); } public function isReadable(): bool { - return $this->computeResult(static function (PropertyReflection $property) { - return $property->isReadable(); - }); + return $this->computeResult(static fn (PropertyReflection $property) => $property->isReadable()); } public function isWritable(): bool { - return $this->computeResult(static function (PropertyReflection $property) { - return $property->isWritable(); - }); + return $this->computeResult(static fn (PropertyReflection $property) => $property->isWritable()); } /** diff --git a/src/Reflection/Type/UnionTypeUnresolvedMethodPrototypeReflection.php b/src/Reflection/Type/UnionTypeUnresolvedMethodPrototypeReflection.php index 8efb093bd68..9f0e62bc0ca 100644 --- a/src/Reflection/Type/UnionTypeUnresolvedMethodPrototypeReflection.php +++ b/src/Reflection/Type/UnionTypeUnresolvedMethodPrototypeReflection.php @@ -10,31 +10,18 @@ class UnionTypeUnresolvedMethodPrototypeReflection implements UnresolvedMethodPrototypeReflection { - /** - * @var string - */ - private $methodName; - /** - * @var UnresolvedMethodPrototypeReflection[] - */ - private $methodPrototypes; - /** - * @var ?ExtendedMethodReflection - */ - private $transformedMethod = null; + private ?ExtendedMethodReflection $transformedMethod = null; - /** - * @var ?self - */ - private $cachedDoNotResolveTemplateTypeMapToBounds = null; + private ?self $cachedDoNotResolveTemplateTypeMapToBounds = null; /** * @param UnresolvedMethodPrototypeReflection[] $methodPrototypes */ - public function __construct(string $methodName, array $methodPrototypes) + public function __construct( + private string $methodName, + private array $methodPrototypes, + ) { - $this->methodName = $methodName; - $this->methodPrototypes = $methodPrototypes; } public function doNotResolveTemplateTypeMapToBounds(): UnresolvedMethodPrototypeReflection @@ -43,9 +30,7 @@ public function doNotResolveTemplateTypeMapToBounds(): UnresolvedMethodPrototype return $this->cachedDoNotResolveTemplateTypeMapToBounds; } - return $this->cachedDoNotResolveTemplateTypeMapToBounds = new self($this->methodName, array_map(static function (UnresolvedMethodPrototypeReflection $prototype) : UnresolvedMethodPrototypeReflection { - return $prototype->doNotResolveTemplateTypeMapToBounds(); - }, $this->methodPrototypes)); + return $this->cachedDoNotResolveTemplateTypeMapToBounds = new self($this->methodName, array_map(static fn (UnresolvedMethodPrototypeReflection $prototype): UnresolvedMethodPrototypeReflection => $prototype->doNotResolveTemplateTypeMapToBounds(), $this->methodPrototypes)); } public function getNakedMethod(): ExtendedMethodReflection @@ -59,18 +44,14 @@ public function getTransformedMethod(): ExtendedMethodReflection return $this->transformedMethod; } - $methods = array_map(static function (UnresolvedMethodPrototypeReflection $prototype) : MethodReflection { - return $prototype->getTransformedMethod(); - }, $this->methodPrototypes); + $methods = array_map(static fn (UnresolvedMethodPrototypeReflection $prototype): MethodReflection => $prototype->getTransformedMethod(), $this->methodPrototypes); return $this->transformedMethod = new UnionTypeMethodReflection($this->methodName, $methods); } public function withCalledOnType(Type $type): UnresolvedMethodPrototypeReflection { - return new self($this->methodName, array_map(static function (UnresolvedMethodPrototypeReflection $prototype) use($type) : UnresolvedMethodPrototypeReflection { - return $prototype->withCalledOnType($type); - }, $this->methodPrototypes)); + return new self($this->methodName, array_map(static fn (UnresolvedMethodPrototypeReflection $prototype): UnresolvedMethodPrototypeReflection => $prototype->withCalledOnType($type), $this->methodPrototypes)); } } diff --git a/src/Reflection/Type/UnionTypeUnresolvedPropertyPrototypeReflection.php b/src/Reflection/Type/UnionTypeUnresolvedPropertyPrototypeReflection.php index a3e21527911..fe47fa14529 100644 --- a/src/Reflection/Type/UnionTypeUnresolvedPropertyPrototypeReflection.php +++ b/src/Reflection/Type/UnionTypeUnresolvedPropertyPrototypeReflection.php @@ -9,31 +9,18 @@ class UnionTypeUnresolvedPropertyPrototypeReflection implements UnresolvedPropertyPrototypeReflection { - /** - * @var string - */ - private $propertyName; - /** - * @var UnresolvedPropertyPrototypeReflection[] - */ - private $propertyPrototypes; - /** - * @var ?PropertyReflection - */ - private $transformedProperty = null; + private ?PropertyReflection $transformedProperty = null; - /** - * @var ?self - */ - private $cachedDoNotResolveTemplateTypeMapToBounds = null; + private ?self $cachedDoNotResolveTemplateTypeMapToBounds = null; /** * @param UnresolvedPropertyPrototypeReflection[] $propertyPrototypes */ - public function __construct(string $propertyName, array $propertyPrototypes) + public function __construct( + private string $propertyName, + private array $propertyPrototypes, + ) { - $this->propertyName = $propertyName; - $this->propertyPrototypes = $propertyPrototypes; } public function doNotResolveTemplateTypeMapToBounds(): UnresolvedPropertyPrototypeReflection @@ -41,9 +28,7 @@ public function doNotResolveTemplateTypeMapToBounds(): UnresolvedPropertyPrototy if ($this->cachedDoNotResolveTemplateTypeMapToBounds !== null) { return $this->cachedDoNotResolveTemplateTypeMapToBounds; } - return $this->cachedDoNotResolveTemplateTypeMapToBounds = new self($this->propertyName, array_map(static function (UnresolvedPropertyPrototypeReflection $prototype) : UnresolvedPropertyPrototypeReflection { - return $prototype->doNotResolveTemplateTypeMapToBounds(); - }, $this->propertyPrototypes)); + return $this->cachedDoNotResolveTemplateTypeMapToBounds = new self($this->propertyName, array_map(static fn (UnresolvedPropertyPrototypeReflection $prototype): UnresolvedPropertyPrototypeReflection => $prototype->doNotResolveTemplateTypeMapToBounds(), $this->propertyPrototypes)); } public function getNakedProperty(): PropertyReflection @@ -57,18 +42,14 @@ public function getTransformedProperty(): PropertyReflection return $this->transformedProperty; } - $methods = array_map(static function (UnresolvedPropertyPrototypeReflection $prototype) : PropertyReflection { - return $prototype->getTransformedProperty(); - }, $this->propertyPrototypes); + $methods = array_map(static fn (UnresolvedPropertyPrototypeReflection $prototype): PropertyReflection => $prototype->getTransformedProperty(), $this->propertyPrototypes); return $this->transformedProperty = new UnionTypePropertyReflection($methods); } public function withFechedOnType(Type $type): UnresolvedPropertyPrototypeReflection { - return new self($this->propertyName, array_map(static function (UnresolvedPropertyPrototypeReflection $prototype) use($type) : UnresolvedPropertyPrototypeReflection { - return $prototype->withFechedOnType($type); - }, $this->propertyPrototypes)); + return new self($this->propertyName, array_map(static fn (UnresolvedPropertyPrototypeReflection $prototype): UnresolvedPropertyPrototypeReflection => $prototype->withFechedOnType($type), $this->propertyPrototypes)); } } diff --git a/src/Reflection/WrappedExtendedMethodReflection.php b/src/Reflection/WrappedExtendedMethodReflection.php index a582b5eef48..352edc5870e 100644 --- a/src/Reflection/WrappedExtendedMethodReflection.php +++ b/src/Reflection/WrappedExtendedMethodReflection.php @@ -12,13 +12,8 @@ class WrappedExtendedMethodReflection implements ExtendedMethodReflection { - /** - * @var MethodReflection - */ - private $method; - public function __construct(MethodReflection $method) + public function __construct(private MethodReflection $method) { - $this->method = $method; } public function getDeclaringClass(): ClassReflection @@ -65,9 +60,26 @@ public function getVariants(): array continue; } - $variants[] = new FunctionVariantWithPhpDocs($variant->getTemplateTypeMap(), $variant->getResolvedTemplateTypeMap(), array_map(static function (ParameterReflection $parameter) : ParameterReflectionWithPhpDocs { - return $parameter instanceof ParameterReflectionWithPhpDocs ? $parameter : new DummyParameterWithPhpDocs($parameter->getName(), $parameter->getType(), $parameter->isOptional(), $parameter->passedByReference(), $parameter->isVariadic(), $parameter->getDefaultValue(), new MixedType(), $parameter->getType(), null); - }, $variant->getParameters()), $variant->isVariadic(), $variant->getReturnType(), $variant->getReturnType(), new MixedType(), TemplateTypeVarianceMap::createEmpty()); + $variants[] = new FunctionVariantWithPhpDocs( + $variant->getTemplateTypeMap(), + $variant->getResolvedTemplateTypeMap(), + array_map(static fn (ParameterReflection $parameter): ParameterReflectionWithPhpDocs => $parameter instanceof ParameterReflectionWithPhpDocs ? $parameter : new DummyParameterWithPhpDocs( + $parameter->getName(), + $parameter->getType(), + $parameter->isOptional(), + $parameter->passedByReference(), + $parameter->isVariadic(), + $parameter->getDefaultValue(), + new MixedType(), + $parameter->getType(), + null, + ), $variant->getParameters()), + $variant->isVariadic(), + $variant->getReturnType(), + $variant->getReturnType(), + new MixedType(), + TemplateTypeVarianceMap::createEmpty(), + ); } return $variants; diff --git a/src/Rules/Api/ApiClassConstFetchRule.php b/src/Rules/Api/ApiClassConstFetchRule.php index 26eacd61afb..528d2daf8bf 100644 --- a/src/Rules/Api/ApiClassConstFetchRule.php +++ b/src/Rules/Api/ApiClassConstFetchRule.php @@ -17,19 +17,13 @@ class ApiClassConstFetchRule implements Rule { - /** - * @var ApiRuleHelper - */ - private $apiRuleHelper; - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - public function __construct(ApiRuleHelper $apiRuleHelper, ReflectionProvider $reflectionProvider) + public function __construct( + private ApiRuleHelper $apiRuleHelper, + private ReflectionProvider $reflectionProvider, + ) { - $this->apiRuleHelper = $apiRuleHelper; - $this->reflectionProvider = $reflectionProvider; } + public function getNodeType(): string { return Node\Expr\ClassConstFetch::class; @@ -55,7 +49,14 @@ public function processNode(Node $node, Scope $scope): array return []; } - $ruleError = RuleErrorBuilder::message(sprintf('Accessing %s::%s is not covered by backward compatibility promise. The class might change in a minor PHPStan version.', $classReflection->getDisplayName(), $node->name->toString()))->identifier('phpstanApi.classConstant')->tip(sprintf("If you think it should be covered by backward compatibility promise, open a discussion:\n %s\n\n See also:\n https://phpstan.org/developing-extensions/backward-compatibility-promise", 'https://github.com/phpstan/phpstan/discussions'))->build(); + $ruleError = RuleErrorBuilder::message(sprintf( + 'Accessing %s::%s is not covered by backward compatibility promise. The class might change in a minor PHPStan version.', + $classReflection->getDisplayName(), + $node->name->toString(), + ))->identifier('phpstanApi.classConstant')->tip(sprintf( + "If you think it should be covered by backward compatibility promise, open a discussion:\n %s\n\n See also:\n https://phpstan.org/developing-extensions/backward-compatibility-promise", + 'https://github.com/phpstan/phpstan/discussions', + ))->build(); $docBlock = $classReflection->getResolvedPhpDoc(); if ($docBlock !== null) { diff --git a/src/Rules/Api/ApiClassExtendsRule.php b/src/Rules/Api/ApiClassExtendsRule.php index 91377f342ee..72aad19740c 100644 --- a/src/Rules/Api/ApiClassExtendsRule.php +++ b/src/Rules/Api/ApiClassExtendsRule.php @@ -18,19 +18,13 @@ class ApiClassExtendsRule implements Rule { - /** - * @var ApiRuleHelper - */ - private $apiRuleHelper; - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - public function __construct(ApiRuleHelper $apiRuleHelper, ReflectionProvider $reflectionProvider) + public function __construct( + private ApiRuleHelper $apiRuleHelper, + private ReflectionProvider $reflectionProvider, + ) { - $this->apiRuleHelper = $apiRuleHelper; - $this->reflectionProvider = $reflectionProvider; } + public function getNodeType(): string { return Class_::class; @@ -56,7 +50,13 @@ public function processNode(Node $node, Scope $scope): array return []; } - $ruleError = RuleErrorBuilder::message(sprintf('Extending %s is not covered by backward compatibility promise. The class might change in a minor PHPStan version.', $extendedClassReflection->getDisplayName()))->identifier('phpstanApi.class')->tip(sprintf("If you think it should be covered by backward compatibility promise, open a discussion:\n %s\n\n See also:\n https://phpstan.org/developing-extensions/backward-compatibility-promise", 'https://github.com/phpstan/phpstan/discussions'))->build(); + $ruleError = RuleErrorBuilder::message(sprintf( + 'Extending %s is not covered by backward compatibility promise. The class might change in a minor PHPStan version.', + $extendedClassReflection->getDisplayName(), + ))->identifier('phpstanApi.class')->tip(sprintf( + "If you think it should be covered by backward compatibility promise, open a discussion:\n %s\n\n See also:\n https://phpstan.org/developing-extensions/backward-compatibility-promise", + 'https://github.com/phpstan/phpstan/discussions', + ))->build(); $docBlock = $extendedClassReflection->getResolvedPhpDoc(); if ($docBlock === null) { diff --git a/src/Rules/Api/ApiClassImplementsRule.php b/src/Rules/Api/ApiClassImplementsRule.php index f682fb5f565..521279becaa 100644 --- a/src/Rules/Api/ApiClassImplementsRule.php +++ b/src/Rules/Api/ApiClassImplementsRule.php @@ -20,19 +20,13 @@ class ApiClassImplementsRule implements Rule { - /** - * @var ApiRuleHelper - */ - private $apiRuleHelper; - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - public function __construct(ApiRuleHelper $apiRuleHelper, ReflectionProvider $reflectionProvider) + public function __construct( + private ApiRuleHelper $apiRuleHelper, + private ReflectionProvider $reflectionProvider, + ) { - $this->apiRuleHelper = $apiRuleHelper; - $this->reflectionProvider = $reflectionProvider; } + public function getNodeType(): string { return Class_::class; @@ -63,7 +57,13 @@ private function checkName(Scope $scope, Node\Name $name): array return []; } - $ruleError = RuleErrorBuilder::message(sprintf('Implementing %s is not covered by backward compatibility promise. The interface might change in a minor PHPStan version.', $implementedClassReflection->getDisplayName()))->identifier('phpstanApi.interface')->tip(sprintf("If you think it should be covered by backward compatibility promise, open a discussion:\n %s\n\n See also:\n https://phpstan.org/developing-extensions/backward-compatibility-promise", 'https://github.com/phpstan/phpstan/discussions'))->build(); + $ruleError = RuleErrorBuilder::message(sprintf( + 'Implementing %s is not covered by backward compatibility promise. The interface might change in a minor PHPStan version.', + $implementedClassReflection->getDisplayName(), + ))->identifier('phpstanApi.interface')->tip(sprintf( + "If you think it should be covered by backward compatibility promise, open a discussion:\n %s\n\n See also:\n https://phpstan.org/developing-extensions/backward-compatibility-promise", + 'https://github.com/phpstan/phpstan/discussions', + ))->build(); if (in_array($implementedClassReflection->getName(), BcUncoveredInterface::CLASSES, true)) { return [$ruleError]; diff --git a/src/Rules/Api/ApiInstanceofRule.php b/src/Rules/Api/ApiInstanceofRule.php index c2c9ea52c10..5f2c4d531ae 100644 --- a/src/Rules/Api/ApiInstanceofRule.php +++ b/src/Rules/Api/ApiInstanceofRule.php @@ -22,19 +22,13 @@ class ApiInstanceofRule implements Rule { - /** - * @var ApiRuleHelper - */ - private $apiRuleHelper; - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - public function __construct(ApiRuleHelper $apiRuleHelper, ReflectionProvider $reflectionProvider) + public function __construct( + private ApiRuleHelper $apiRuleHelper, + private ReflectionProvider $reflectionProvider, + ) { - $this->apiRuleHelper = $apiRuleHelper; - $this->reflectionProvider = $reflectionProvider; } + public function getNodeType(): string { return Node\Expr\Instanceof_::class; @@ -56,9 +50,16 @@ public function processNode(Node $node, Scope $scope): array return []; } - $ruleError = RuleErrorBuilder::message(sprintf('Asking about instanceof %s is not covered by backward compatibility promise. The %s might change in a minor PHPStan version.', $classReflection->getDisplayName(), strtolower($classReflection->getClassTypeDescription()))) + $ruleError = RuleErrorBuilder::message(sprintf( + 'Asking about instanceof %s is not covered by backward compatibility promise. The %s might change in a minor PHPStan version.', + $classReflection->getDisplayName(), + strtolower($classReflection->getClassTypeDescription()), + )) ->identifier(sprintf('phpstanApi.%s', strtolower($classReflection->getClassTypeDescription()))) - ->tip(sprintf("If you think it should be covered by backward compatibility promise, open a discussion:\n %s\n\n See also:\n https://phpstan.org/developing-extensions/backward-compatibility-promise", 'https://github.com/phpstan/phpstan/discussions'))->build(); + ->tip(sprintf( + "If you think it should be covered by backward compatibility promise, open a discussion:\n %s\n\n See also:\n https://phpstan.org/developing-extensions/backward-compatibility-promise", + 'https://github.com/phpstan/phpstan/discussions', + ))->build(); $docBlock = $classReflection->getResolvedPhpDoc(); if ($docBlock === null) { @@ -101,7 +102,13 @@ private function processCoveredClass(Node\Expr\Instanceof_ $node, Scope $scope, } return [ - RuleErrorBuilder::message(sprintf('Although %s is covered by backward compatibility promise, this instanceof assumption might break because it\'s not guaranteed to always stay the same.', $classReflection->getDisplayName()))->identifier('phpstanApi.instanceofAssumption')->tip(sprintf("In case of questions how to solve this correctly, open a discussion:\n %s\n\n See also:\n https://phpstan.org/developing-extensions/backward-compatibility-promise", 'https://github.com/phpstan/phpstan/discussions'))->build(), + RuleErrorBuilder::message(sprintf( + 'Although %s is covered by backward compatibility promise, this instanceof assumption might break because it\'s not guaranteed to always stay the same.', + $classReflection->getDisplayName(), + ))->identifier('phpstanApi.instanceofAssumption')->tip(sprintf( + "In case of questions how to solve this correctly, open a discussion:\n %s\n\n See also:\n https://phpstan.org/developing-extensions/backward-compatibility-promise", + 'https://github.com/phpstan/phpstan/discussions', + ))->build(), ]; } diff --git a/src/Rules/Api/ApiInstanceofTypeRule.php b/src/Rules/Api/ApiInstanceofTypeRule.php index 0ff4fd73acf..fd4a3c6e20f 100644 --- a/src/Rules/Api/ApiInstanceofTypeRule.php +++ b/src/Rules/Api/ApiInstanceofTypeRule.php @@ -53,18 +53,6 @@ class ApiInstanceofTypeRule implements Rule { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - /** - * @var bool - */ - private $enabled; - /** - * @var bool - */ - private $deprecationRulesInstalled; private const MAP = [ TypeWithClassName::class => 'Type::getObjectClassNames() or Type::getObjectClassReflections()', EnumCaseObjectType::class => 'Type::getEnumCases()', @@ -104,11 +92,12 @@ class ApiInstanceofTypeRule implements Rule AccessoryType::class => 'methods on PHPStan\\Type\\Type', ]; - public function __construct(ReflectionProvider $reflectionProvider, bool $enabled, bool $deprecationRulesInstalled) + public function __construct( + private ReflectionProvider $reflectionProvider, + private bool $enabled, + private bool $deprecationRulesInstalled, + ) { - $this->reflectionProvider = $reflectionProvider; - $this->enabled = $enabled; - $this->deprecationRulesInstalled = $deprecationRulesInstalled; } public function getNodeType(): string @@ -153,12 +142,19 @@ public function processNode(Node $node, Scope $scope): array $tip = 'Learn more: https://phpstan.org/blog/why-is-instanceof-type-wrong-and-getting-deprecated'; if ($lowerMap[$lowerClassName] === null) { return [ - RuleErrorBuilder::message(sprintf('Doing instanceof %s is error-prone and deprecated.', $className))->identifier('phpstanApi.instanceofType')->tip($tip)->build(), + RuleErrorBuilder::message(sprintf( + 'Doing instanceof %s is error-prone and deprecated.', + $className, + ))->identifier('phpstanApi.instanceofType')->tip($tip)->build(), ]; } return [ - RuleErrorBuilder::message(sprintf('Doing instanceof %s is error-prone and deprecated. Use %s instead.', $className, $lowerMap[$lowerClassName]))->identifier('phpstanApi.instanceofType')->tip($tip)->build(), + RuleErrorBuilder::message(sprintf( + 'Doing instanceof %s is error-prone and deprecated. Use %s instead.', + $className, + $lowerMap[$lowerClassName], + ))->identifier('phpstanApi.instanceofType')->tip($tip)->build(), ]; } diff --git a/src/Rules/Api/ApiInstantiationRule.php b/src/Rules/Api/ApiInstantiationRule.php index 290cd06392f..bea7e29b681 100644 --- a/src/Rules/Api/ApiInstantiationRule.php +++ b/src/Rules/Api/ApiInstantiationRule.php @@ -16,19 +16,13 @@ class ApiInstantiationRule implements Rule { - /** - * @var ApiRuleHelper - */ - private $apiRuleHelper; - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - public function __construct(ApiRuleHelper $apiRuleHelper, ReflectionProvider $reflectionProvider) + public function __construct( + private ApiRuleHelper $apiRuleHelper, + private ReflectionProvider $reflectionProvider, + ) { - $this->apiRuleHelper = $apiRuleHelper; - $this->reflectionProvider = $reflectionProvider; } + public function getNodeType(): string { return Node\Expr\New_::class; @@ -50,7 +44,13 @@ public function processNode(Node $node, Scope $scope): array return []; } - $ruleError = RuleErrorBuilder::message(sprintf('Creating new %s is not covered by backward compatibility promise. The class might change in a minor PHPStan version.', $classReflection->getDisplayName()))->identifier('phpstanApi.constructor')->tip(sprintf("If you think it should be covered by backward compatibility promise, open a discussion:\n %s\n\n See also:\n https://phpstan.org/developing-extensions/backward-compatibility-promise", 'https://github.com/phpstan/phpstan/discussions'))->build(); + $ruleError = RuleErrorBuilder::message(sprintf( + 'Creating new %s is not covered by backward compatibility promise. The class might change in a minor PHPStan version.', + $classReflection->getDisplayName(), + ))->identifier('phpstanApi.constructor')->tip(sprintf( + "If you think it should be covered by backward compatibility promise, open a discussion:\n %s\n\n See also:\n https://phpstan.org/developing-extensions/backward-compatibility-promise", + 'https://github.com/phpstan/phpstan/discussions', + ))->build(); if (!$classReflection->hasConstructor()) { return [$ruleError]; diff --git a/src/Rules/Api/ApiInterfaceExtendsRule.php b/src/Rules/Api/ApiInterfaceExtendsRule.php index ba529a0cd98..fc5d8ca505f 100644 --- a/src/Rules/Api/ApiInterfaceExtendsRule.php +++ b/src/Rules/Api/ApiInterfaceExtendsRule.php @@ -20,19 +20,13 @@ class ApiInterfaceExtendsRule implements Rule { - /** - * @var ApiRuleHelper - */ - private $apiRuleHelper; - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - public function __construct(ApiRuleHelper $apiRuleHelper, ReflectionProvider $reflectionProvider) + public function __construct( + private ApiRuleHelper $apiRuleHelper, + private ReflectionProvider $reflectionProvider, + ) { - $this->apiRuleHelper = $apiRuleHelper; - $this->reflectionProvider = $reflectionProvider; } + public function getNodeType(): string { return Interface_::class; @@ -63,7 +57,13 @@ private function checkName(Scope $scope, Node\Name $name): array return []; } - $ruleError = RuleErrorBuilder::message(sprintf('Extending %s is not covered by backward compatibility promise. The interface might change in a minor PHPStan version.', $extendedInterfaceReflection->getDisplayName()))->identifier('phpstanApi.interface')->tip(sprintf("If you think it should be covered by backward compatibility promise, open a discussion:\n %s\n\n See also:\n https://phpstan.org/developing-extensions/backward-compatibility-promise", 'https://github.com/phpstan/phpstan/discussions'))->build(); + $ruleError = RuleErrorBuilder::message(sprintf( + 'Extending %s is not covered by backward compatibility promise. The interface might change in a minor PHPStan version.', + $extendedInterfaceReflection->getDisplayName(), + ))->identifier('phpstanApi.interface')->tip(sprintf( + "If you think it should be covered by backward compatibility promise, open a discussion:\n %s\n\n See also:\n https://phpstan.org/developing-extensions/backward-compatibility-promise", + 'https://github.com/phpstan/phpstan/discussions', + ))->build(); if (in_array($extendedInterfaceReflection->getName(), BcUncoveredInterface::CLASSES, true)) { return [$ruleError]; diff --git a/src/Rules/Api/ApiMethodCallRule.php b/src/Rules/Api/ApiMethodCallRule.php index d9dca3099af..52472fb47eb 100644 --- a/src/Rules/Api/ApiMethodCallRule.php +++ b/src/Rules/Api/ApiMethodCallRule.php @@ -17,13 +17,8 @@ class ApiMethodCallRule implements Rule { - /** - * @var ApiRuleHelper - */ - private $apiRuleHelper; - public function __construct(ApiRuleHelper $apiRuleHelper) + public function __construct(private ApiRuleHelper $apiRuleHelper) { - $this->apiRuleHelper = $apiRuleHelper; } public function getNodeType(): string @@ -51,7 +46,14 @@ public function processNode(Node $node, Scope $scope): array return []; } - $ruleError = RuleErrorBuilder::message(sprintf('Calling %s::%s() is not covered by backward compatibility promise. The method might change in a minor PHPStan version.', $declaringClass->getDisplayName(), $methodReflection->getName()))->identifier('phpstanApi.method')->tip(sprintf("If you think it should be covered by backward compatibility promise, open a discussion:\n %s\n\n See also:\n https://phpstan.org/developing-extensions/backward-compatibility-promise", 'https://github.com/phpstan/phpstan/discussions'))->build(); + $ruleError = RuleErrorBuilder::message(sprintf( + 'Calling %s::%s() is not covered by backward compatibility promise. The method might change in a minor PHPStan version.', + $declaringClass->getDisplayName(), + $methodReflection->getName(), + ))->identifier('phpstanApi.method')->tip(sprintf( + "If you think it should be covered by backward compatibility promise, open a discussion:\n %s\n\n See also:\n https://phpstan.org/developing-extensions/backward-compatibility-promise", + 'https://github.com/phpstan/phpstan/discussions', + ))->build(); return [$ruleError]; } diff --git a/src/Rules/Api/ApiStaticCallRule.php b/src/Rules/Api/ApiStaticCallRule.php index d6e71cc60c1..6d48c393c05 100644 --- a/src/Rules/Api/ApiStaticCallRule.php +++ b/src/Rules/Api/ApiStaticCallRule.php @@ -18,19 +18,13 @@ class ApiStaticCallRule implements Rule { - /** - * @var ApiRuleHelper - */ - private $apiRuleHelper; - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - public function __construct(ApiRuleHelper $apiRuleHelper, ReflectionProvider $reflectionProvider) + public function __construct( + private ApiRuleHelper $apiRuleHelper, + private ReflectionProvider $reflectionProvider, + ) { - $this->apiRuleHelper = $apiRuleHelper; - $this->reflectionProvider = $reflectionProvider; } + public function getNodeType(): string { return Node\Expr\StaticCall::class; @@ -67,7 +61,14 @@ public function processNode(Node $node, Scope $scope): array return []; } - $ruleError = RuleErrorBuilder::message(sprintf('Calling %s::%s() is not covered by backward compatibility promise. The method might change in a minor PHPStan version.', $declaringClass->getDisplayName(), $methodReflection->getName()))->identifier('phpstanApi.method')->tip(sprintf("If you think it should be covered by backward compatibility promise, open a discussion:\n %s\n\n See also:\n https://phpstan.org/developing-extensions/backward-compatibility-promise", 'https://github.com/phpstan/phpstan/discussions'))->build(); + $ruleError = RuleErrorBuilder::message(sprintf( + 'Calling %s::%s() is not covered by backward compatibility promise. The method might change in a minor PHPStan version.', + $declaringClass->getDisplayName(), + $methodReflection->getName(), + ))->identifier('phpstanApi.method')->tip(sprintf( + "If you think it should be covered by backward compatibility promise, open a discussion:\n %s\n\n See also:\n https://phpstan.org/developing-extensions/backward-compatibility-promise", + 'https://github.com/phpstan/phpstan/discussions', + ))->build(); return [$ruleError]; } diff --git a/src/Rules/Api/ApiTraitUseRule.php b/src/Rules/Api/ApiTraitUseRule.php index d2ec58f0e4e..33da77eb364 100644 --- a/src/Rules/Api/ApiTraitUseRule.php +++ b/src/Rules/Api/ApiTraitUseRule.php @@ -15,19 +15,13 @@ class ApiTraitUseRule implements Rule { - /** - * @var ApiRuleHelper - */ - private $apiRuleHelper; - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - public function __construct(ApiRuleHelper $apiRuleHelper, ReflectionProvider $reflectionProvider) + public function __construct( + private ApiRuleHelper $apiRuleHelper, + private ReflectionProvider $reflectionProvider, + ) { - $this->apiRuleHelper = $apiRuleHelper; - $this->reflectionProvider = $reflectionProvider; } + public function getNodeType(): string { return Node\Stmt\TraitUse::class; @@ -36,7 +30,10 @@ public function getNodeType(): string public function processNode(Node $node, Scope $scope): array { $errors = []; - $tip = sprintf("If you think it should be covered by backward compatibility promise, open a discussion:\n %s\n\n See also:\n https://phpstan.org/developing-extensions/backward-compatibility-promise", 'https://github.com/phpstan/phpstan/discussions'); + $tip = sprintf( + "If you think it should be covered by backward compatibility promise, open a discussion:\n %s\n\n See also:\n https://phpstan.org/developing-extensions/backward-compatibility-promise", + 'https://github.com/phpstan/phpstan/discussions', + ); foreach ($node->traits as $traitName) { $traitName = $traitName->toString(); if (!$this->reflectionProvider->hasClass($traitName)) { @@ -48,7 +45,10 @@ public function processNode(Node $node, Scope $scope): array continue; } - $errors[] = RuleErrorBuilder::message(sprintf('Using %s is not covered by backward compatibility promise. The trait might change in a minor PHPStan version.', $traitReflection->getDisplayName()))->identifier('phpstanApi.trait')->tip($tip)->build(); + $errors[] = RuleErrorBuilder::message(sprintf( + 'Using %s is not covered by backward compatibility promise. The trait might change in a minor PHPStan version.', + $traitReflection->getDisplayName(), + ))->identifier('phpstanApi.trait')->tip($tip)->build(); } return $errors; diff --git a/src/Rules/Api/GetTemplateTypeRule.php b/src/Rules/Api/GetTemplateTypeRule.php index a56eb7f6245..05c48497d0f 100644 --- a/src/Rules/Api/GetTemplateTypeRule.php +++ b/src/Rules/Api/GetTemplateTypeRule.php @@ -18,13 +18,8 @@ class GetTemplateTypeRule implements Rule { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - public function __construct(ReflectionProvider $reflectionProvider) + public function __construct(private ReflectionProvider $reflectionProvider) { - $this->reflectionProvider = $reflectionProvider; } public function getNodeType(): string @@ -70,7 +65,13 @@ public function processNode(Node $node, Scope $scope): array continue; } - $errors[] = RuleErrorBuilder::message(sprintf('Call to %s::%s() references unknown template type %s on class %s.', $methodReflection->getDeclaringClass()->getDisplayName(), $methodReflection->getName(), $templateTypeName->getValue(), $classReflection->getDisplayName()))->identifier('phpstanApi.getTemplateType')->build(); + $errors[] = RuleErrorBuilder::message(sprintf( + 'Call to %s::%s() references unknown template type %s on class %s.', + $methodReflection->getDeclaringClass()->getDisplayName(), + $methodReflection->getName(), + $templateTypeName->getValue(), + $classReflection->getDisplayName(), + ))->identifier('phpstanApi.getTemplateType')->build(); } } diff --git a/src/Rules/Api/NodeConnectingVisitorAttributesRule.php b/src/Rules/Api/NodeConnectingVisitorAttributesRule.php index e63900fbc41..0907413ca76 100644 --- a/src/Rules/Api/NodeConnectingVisitorAttributesRule.php +++ b/src/Rules/Api/NodeConnectingVisitorAttributesRule.php @@ -24,13 +24,8 @@ class NodeConnectingVisitorAttributesRule implements Rule { - /** - * @var Container - */ - private $container; - public function __construct(Container $container) + public function __construct(private Container $container) { - $this->container = $container; } public function getNodeType(): string diff --git a/src/Rules/Api/PhpStanNamespaceIn3rdPartyPackageRule.php b/src/Rules/Api/PhpStanNamespaceIn3rdPartyPackageRule.php index 3009364fc6c..cc449b8f306 100644 --- a/src/Rules/Api/PhpStanNamespaceIn3rdPartyPackageRule.php +++ b/src/Rules/Api/PhpStanNamespaceIn3rdPartyPackageRule.php @@ -21,13 +21,8 @@ class PhpStanNamespaceIn3rdPartyPackageRule implements Rule { - /** - * @var ApiRuleHelper - */ - private $apiRuleHelper; - public function __construct(ApiRuleHelper $apiRuleHelper) + public function __construct(private ApiRuleHelper $apiRuleHelper) { - $this->apiRuleHelper = $apiRuleHelper; } public function getNodeType(): string @@ -84,9 +79,9 @@ private function findComposerJsonContents(string $fromDirectory): ?array try { return Json::decode(FileReader::read($composerJsonPath), Json::FORCE_ARRAY); - } catch (JsonException $e) { + } catch (JsonException) { return null; - } catch (CouldNotReadFileException $e) { + } catch (CouldNotReadFileException) { return null; } } diff --git a/src/Rules/Api/RuntimeReflectionFunctionRule.php b/src/Rules/Api/RuntimeReflectionFunctionRule.php index f8eea739ecb..8b8fbf67222 100644 --- a/src/Rules/Api/RuntimeReflectionFunctionRule.php +++ b/src/Rules/Api/RuntimeReflectionFunctionRule.php @@ -18,13 +18,8 @@ class RuntimeReflectionFunctionRule implements Rule { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - public function __construct(ReflectionProvider $reflectionProvider) + public function __construct(private ReflectionProvider $reflectionProvider) { - $this->reflectionProvider = $reflectionProvider; } public function getNodeType(): string @@ -72,7 +67,9 @@ public function processNode(Node $node, Scope $scope): array } return [ - RuleErrorBuilder::message(sprintf('Function %s() is a runtime reflection concept that might not work in PHPStan because it uses fully static reflection engine. Use objects retrieved from ReflectionProvider instead.', $functionReflection->getName()))->identifier('phpstanApi.runtimeReflection')->build(), + RuleErrorBuilder::message( + sprintf('Function %s() is a runtime reflection concept that might not work in PHPStan because it uses fully static reflection engine. Use objects retrieved from ReflectionProvider instead.', $functionReflection->getName()), + )->identifier('phpstanApi.runtimeReflection')->build(), ]; } diff --git a/src/Rules/Api/RuntimeReflectionInstantiationRule.php b/src/Rules/Api/RuntimeReflectionInstantiationRule.php index 42b50712493..3e5dc7524c7 100644 --- a/src/Rules/Api/RuntimeReflectionInstantiationRule.php +++ b/src/Rules/Api/RuntimeReflectionInstantiationRule.php @@ -28,13 +28,8 @@ class RuntimeReflectionInstantiationRule implements Rule { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - public function __construct(ReflectionProvider $reflectionProvider) + public function __construct(private ReflectionProvider $reflectionProvider) { - $this->reflectionProvider = $reflectionProvider; } public function getNodeType(): string @@ -91,7 +86,9 @@ public function processNode(Node $node, Scope $scope): array } return [ - RuleErrorBuilder::message(sprintf('Creating new %s is a runtime reflection concept that might not work in PHPStan because it uses fully static reflection engine. Use objects retrieved from ReflectionProvider instead.', $classReflection->getName()))->identifier('phpstanApi.runtimeReflection')->build(), + RuleErrorBuilder::message( + sprintf('Creating new %s is a runtime reflection concept that might not work in PHPStan because it uses fully static reflection engine. Use objects retrieved from ReflectionProvider instead.', $classReflection->getName()), + )->identifier('phpstanApi.runtimeReflection')->build(), ]; } diff --git a/src/Rules/Arrays/AppendedArrayItemTypeRule.php b/src/Rules/Arrays/AppendedArrayItemTypeRule.php index 9f042eaee30..96409f9aa10 100644 --- a/src/Rules/Arrays/AppendedArrayItemTypeRule.php +++ b/src/Rules/Arrays/AppendedArrayItemTypeRule.php @@ -22,19 +22,13 @@ class AppendedArrayItemTypeRule implements Rule { - /** - * @var PropertyReflectionFinder - */ - private $propertyReflectionFinder; - /** - * @var RuleLevelHelper - */ - private $ruleLevelHelper; - public function __construct(PropertyReflectionFinder $propertyReflectionFinder, RuleLevelHelper $ruleLevelHelper) + public function __construct( + private PropertyReflectionFinder $propertyReflectionFinder, + private RuleLevelHelper $ruleLevelHelper, + ) { - $this->propertyReflectionFinder = $propertyReflectionFinder; - $this->ruleLevelHelper = $ruleLevelHelper; } + public function getNodeType(): string { return Node\Expr::class; @@ -82,7 +76,11 @@ public function processNode(Node $node, Scope $scope): array if (!$accepts->result) { $verbosityLevel = VerbosityLevel::getRecommendedLevelByType($itemType, $assignedValueType); return [ - RuleErrorBuilder::message(sprintf('Array (%s) does not accept %s.', $assignedToType->describe($verbosityLevel), $assignedValueType->describe($verbosityLevel))) + RuleErrorBuilder::message(sprintf( + 'Array (%s) does not accept %s.', + $assignedToType->describe($verbosityLevel), + $assignedValueType->describe($verbosityLevel), + )) ->acceptsReasonsTip($accepts->reasons) ->identifier('array.valueType') ->build(), diff --git a/src/Rules/Arrays/AppendedArrayKeyTypeRule.php b/src/Rules/Arrays/AppendedArrayKeyTypeRule.php index 55a2bb46d5c..cf35062fafc 100644 --- a/src/Rules/Arrays/AppendedArrayKeyTypeRule.php +++ b/src/Rules/Arrays/AppendedArrayKeyTypeRule.php @@ -21,19 +21,13 @@ class AppendedArrayKeyTypeRule implements Rule { - /** - * @var PropertyReflectionFinder - */ - private $propertyReflectionFinder; - /** - * @var bool - */ - private $checkUnionTypes; - public function __construct(PropertyReflectionFinder $propertyReflectionFinder, bool $checkUnionTypes) + public function __construct( + private PropertyReflectionFinder $propertyReflectionFinder, + private bool $checkUnionTypes, + ) { - $this->propertyReflectionFinder = $propertyReflectionFinder; - $this->checkUnionTypes = $checkUnionTypes; } + public function getNodeType(): string { return Assign::class; @@ -81,7 +75,11 @@ public function processNode(Node $node, Scope $scope): array if (!$arrayType->getIterableKeyType()->isSuperTypeOf($keyType)->yes()) { $verbosity = VerbosityLevel::getRecommendedLevelByType($arrayType->getIterableKeyType(), $keyType); return [ - RuleErrorBuilder::message(sprintf('Array (%s) does not accept key %s.', $arrayType->describe($verbosity), $keyType->describe(VerbosityLevel::value())))->identifier('array.keyType')->build(), + RuleErrorBuilder::message(sprintf( + 'Array (%s) does not accept key %s.', + $arrayType->describe($verbosity), + $keyType->describe(VerbosityLevel::value()), + ))->identifier('array.keyType')->build(), ]; } diff --git a/src/Rules/Arrays/ArrayDestructuringRule.php b/src/Rules/Arrays/ArrayDestructuringRule.php index db34625933d..332d192698e 100644 --- a/src/Rules/Arrays/ArrayDestructuringRule.php +++ b/src/Rules/Arrays/ArrayDestructuringRule.php @@ -26,19 +26,13 @@ class ArrayDestructuringRule implements Rule { - /** - * @var RuleLevelHelper - */ - private $ruleLevelHelper; - /** - * @var NonexistentOffsetInArrayDimFetchCheck - */ - private $nonexistentOffsetInArrayDimFetchCheck; - public function __construct(RuleLevelHelper $ruleLevelHelper, NonexistentOffsetInArrayDimFetchCheck $nonexistentOffsetInArrayDimFetchCheck) + public function __construct( + private RuleLevelHelper $ruleLevelHelper, + private NonexistentOffsetInArrayDimFetchCheck $nonexistentOffsetInArrayDimFetchCheck, + ) { - $this->ruleLevelHelper = $ruleLevelHelper; - $this->nonexistentOffsetInArrayDimFetchCheck = $nonexistentOffsetInArrayDimFetchCheck; } + public function getNodeType(): string { return Assign::class; @@ -50,7 +44,11 @@ public function processNode(Node $node, Scope $scope): array return []; } - return $this->getErrors($scope, $node->var, $node->expr); + return $this->getErrors( + $scope, + $node->var, + $node->expr, + ); } /** @@ -59,9 +57,12 @@ public function processNode(Node $node, Scope $scope): array */ private function getErrors(Scope $scope, Expr $var, Expr $expr): array { - $exprTypeResult = $this->ruleLevelHelper->findTypeToCheck($scope, $expr, '', static function (Type $varType) : bool { - return $varType->isArray()->yes() || (new ObjectType(ArrayAccess::class))->isSuperTypeOf($varType)->yes(); - }); + $exprTypeResult = $this->ruleLevelHelper->findTypeToCheck( + $scope, + $expr, + '', + static fn (Type $varType): bool => $varType->isArray()->yes() || (new ObjectType(ArrayAccess::class))->isSuperTypeOf($varType)->yes(), + ); $exprType = $exprTypeResult->getType(); if ($exprType instanceof ErrorType) { return []; @@ -91,7 +92,12 @@ private function getErrors(Scope $scope, Expr $var, Expr $expr): array $keyExpr = new TypeExpr($keyType); } - $itemErrors = $this->nonexistentOffsetInArrayDimFetchCheck->check($scope, $expr, '', $keyType); + $itemErrors = $this->nonexistentOffsetInArrayDimFetchCheck->check( + $scope, + $expr, + '', + $keyType, + ); $errors = array_merge($errors, $itemErrors); if (!$item->value instanceof Node\Expr\List_ && !$item->value instanceof Node\Expr\Array_) { @@ -99,7 +105,11 @@ private function getErrors(Scope $scope, Expr $var, Expr $expr): array continue; } - $errors = array_merge($errors, $this->getErrors($scope, $item->value, new Expr\ArrayDimFetch($expr, $keyExpr))); + $errors = array_merge($errors, $this->getErrors( + $scope, + $item->value, + new Expr\ArrayDimFetch($expr, $keyExpr), + )); } return $errors; diff --git a/src/Rules/Arrays/ArrayUnpackingRule.php b/src/Rules/Arrays/ArrayUnpackingRule.php index 49952c53dc6..21092c21009 100644 --- a/src/Rules/Arrays/ArrayUnpackingRule.php +++ b/src/Rules/Arrays/ArrayUnpackingRule.php @@ -21,18 +21,8 @@ class ArrayUnpackingRule implements Rule { - /** - * @var PhpVersion - */ - private $phpVersion; - /** - * @var RuleLevelHelper - */ - private $ruleLevelHelper; - public function __construct(PhpVersion $phpVersion, RuleLevelHelper $ruleLevelHelper) + public function __construct(private PhpVersion $phpVersion, private RuleLevelHelper $ruleLevelHelper) { - $this->phpVersion = $phpVersion; - $this->ruleLevelHelper = $ruleLevelHelper; } public function getNodeType(): string @@ -46,9 +36,12 @@ public function processNode(Node $node, Scope $scope): array return []; } - $typeResult = $this->ruleLevelHelper->findTypeToCheck($scope, new GetIterableKeyTypeExpr($node->value), '', static function (Type $type) : bool { - return $type->isString()->no(); - }); + $typeResult = $this->ruleLevelHelper->findTypeToCheck( + $scope, + new GetIterableKeyTypeExpr($node->value), + '', + static fn (Type $type): bool => $type->isString()->no(), + ); $keyType = $typeResult->getType(); if ($keyType instanceof ErrorType) { @@ -61,7 +54,11 @@ public function processNode(Node $node, Scope $scope): array } return [ - RuleErrorBuilder::message(sprintf('Array unpacking cannot be used on an array with %sstring keys: %s', $isString->yes() ? '' : 'potential ', $scope->getType($node->value)->describe(VerbosityLevel::value())))->identifier('arrayUnpacking.stringOffset')->build(), + RuleErrorBuilder::message(sprintf( + 'Array unpacking cannot be used on an array with %sstring keys: %s', + $isString->yes() ? '' : 'potential ', + $scope->getType($node->value)->describe(VerbosityLevel::value()), + ))->identifier('arrayUnpacking.stringOffset')->build(), ]; } diff --git a/src/Rules/Arrays/DuplicateKeysInLiteralArraysRule.php b/src/Rules/Arrays/DuplicateKeysInLiteralArraysRule.php index 1bfeb8aeb55..606ef7aa207 100644 --- a/src/Rules/Arrays/DuplicateKeysInLiteralArraysRule.php +++ b/src/Rules/Arrays/DuplicateKeysInLiteralArraysRule.php @@ -21,14 +21,12 @@ class DuplicateKeysInLiteralArraysRule implements Rule { - /** - * @var ExprPrinter - */ - private $exprPrinter; - public function __construct(ExprPrinter $exprPrinter) + public function __construct( + private ExprPrinter $exprPrinter, + ) { - $this->exprPrinter = $exprPrinter; } + public function getNodeType(): string { return LiteralArrayNode::class; @@ -76,7 +74,13 @@ public function processNode(Node $node, Scope $scope): array $messages = []; foreach (array_keys($duplicateKeys) as $value) { - $messages[] = RuleErrorBuilder::message(sprintf('Array has %d %s with value %s (%s).', count($printedValues[$value]), count($printedValues[$value]) === 1 ? 'duplicate key' : 'duplicate keys', var_export($value, true), implode(', ', $printedValues[$value])))->identifier('array.duplicateKey')->line($valueLines[$value])->build(); + $messages[] = RuleErrorBuilder::message(sprintf( + 'Array has %d %s with value %s (%s).', + count($printedValues[$value]), + count($printedValues[$value]) === 1 ? 'duplicate key' : 'duplicate keys', + var_export($value, true), + implode(', ', $printedValues[$value]), + ))->identifier('array.duplicateKey')->line($valueLines[$value])->build(); } return $messages; diff --git a/src/Rules/Arrays/InvalidKeyInArrayDimFetchRule.php b/src/Rules/Arrays/InvalidKeyInArrayDimFetchRule.php index 9b47a2813fd..1242f85cfd5 100644 --- a/src/Rules/Arrays/InvalidKeyInArrayDimFetchRule.php +++ b/src/Rules/Arrays/InvalidKeyInArrayDimFetchRule.php @@ -19,19 +19,13 @@ class InvalidKeyInArrayDimFetchRule implements Rule { - /** - * @var RuleLevelHelper - */ - private $ruleLevelHelper; - /** - * @var bool - */ - private $reportMaybes; - public function __construct(RuleLevelHelper $ruleLevelHelper, bool $reportMaybes) + public function __construct( + private RuleLevelHelper $ruleLevelHelper, + private bool $reportMaybes, + ) { - $this->ruleLevelHelper = $ruleLevelHelper; - $this->reportMaybes = $reportMaybes; } + public function getNodeType(): string { return Node\Expr\ArrayDimFetch::class; @@ -48,9 +42,12 @@ public function processNode(Node $node, Scope $scope): array return []; } - $varType = $this->ruleLevelHelper->findTypeToCheck($scope, $node->var, '', static function (Type $varType) use($dimensionType) : bool { - return $varType->isArray()->no() || AllowedArrayKeysTypes::getType()->isSuperTypeOf($dimensionType)->yes(); - })->getType(); + $varType = $this->ruleLevelHelper->findTypeToCheck( + $scope, + $node->var, + '', + static fn (Type $varType): bool => $varType->isArray()->no() || AllowedArrayKeysTypes::getType()->isSuperTypeOf($dimensionType)->yes(), + )->getType(); if ($varType instanceof ErrorType || $varType->isArray()->no()) { return []; @@ -62,7 +59,9 @@ public function processNode(Node $node, Scope $scope): array } return [ - RuleErrorBuilder::message(sprintf('%s array key type %s.', $isSuperType->no() ? 'Invalid' : 'Possibly invalid', $dimensionType->describe(VerbosityLevel::typeOnly())))->identifier('offsetAccess.invalidOffset')->build(), + RuleErrorBuilder::message( + sprintf('%s array key type %s.', $isSuperType->no() ? 'Invalid' : 'Possibly invalid', $dimensionType->describe(VerbosityLevel::typeOnly())), + )->identifier('offsetAccess.invalidOffset')->build(), ]; } diff --git a/src/Rules/Arrays/InvalidKeyInArrayItemRule.php b/src/Rules/Arrays/InvalidKeyInArrayItemRule.php index e60f37fab5e..61c4fd342c5 100644 --- a/src/Rules/Arrays/InvalidKeyInArrayItemRule.php +++ b/src/Rules/Arrays/InvalidKeyInArrayItemRule.php @@ -16,13 +16,8 @@ class InvalidKeyInArrayItemRule implements Rule { - /** - * @var bool - */ - private $reportMaybes; - public function __construct(bool $reportMaybes) + public function __construct(private bool $reportMaybes) { - $this->reportMaybes = $reportMaybes; } public function getNodeType(): string @@ -40,11 +35,15 @@ public function processNode(Node $node, Scope $scope): array $isSuperType = AllowedArrayKeysTypes::getType()->isSuperTypeOf($dimensionType); if ($isSuperType->no()) { return [ - RuleErrorBuilder::message(sprintf('Invalid array key type %s.', $dimensionType->describe(VerbosityLevel::typeOnly())))->identifier('array.invalidKey')->build(), + RuleErrorBuilder::message( + sprintf('Invalid array key type %s.', $dimensionType->describe(VerbosityLevel::typeOnly())), + )->identifier('array.invalidKey')->build(), ]; } elseif ($this->reportMaybes && $isSuperType->maybe() && !$dimensionType instanceof MixedType) { return [ - RuleErrorBuilder::message(sprintf('Possibly invalid array key type %s.', $dimensionType->describe(VerbosityLevel::typeOnly())))->identifier('array.invalidKey')->build(), + RuleErrorBuilder::message( + sprintf('Possibly invalid array key type %s.', $dimensionType->describe(VerbosityLevel::typeOnly())), + )->identifier('array.invalidKey')->build(), ]; } diff --git a/src/Rules/Arrays/IterableInForeachRule.php b/src/Rules/Arrays/IterableInForeachRule.php index 026dd72dd8a..c455cd8d219 100644 --- a/src/Rules/Arrays/IterableInForeachRule.php +++ b/src/Rules/Arrays/IterableInForeachRule.php @@ -19,13 +19,8 @@ class IterableInForeachRule implements Rule { - /** - * @var RuleLevelHelper - */ - private $ruleLevelHelper; - public function __construct(RuleLevelHelper $ruleLevelHelper) + public function __construct(private RuleLevelHelper $ruleLevelHelper) { - $this->ruleLevelHelper = $ruleLevelHelper; } public function getNodeType(): string @@ -36,9 +31,12 @@ public function getNodeType(): string public function processNode(Node $node, Scope $scope): array { $originalNode = $node->getOriginalNode(); - $typeResult = $this->ruleLevelHelper->findTypeToCheck($scope, $originalNode->expr, 'Iterating over an object of an unknown class %s.', static function (Type $type) : bool { - return $type->isIterable()->yes(); - }); + $typeResult = $this->ruleLevelHelper->findTypeToCheck( + $scope, + $originalNode->expr, + 'Iterating over an object of an unknown class %s.', + static fn (Type $type): bool => $type->isIterable()->yes(), + ); $type = $typeResult->getType(); if ($type instanceof ErrorType) { return $typeResult->getUnknownClassErrors(); @@ -48,7 +46,10 @@ public function processNode(Node $node, Scope $scope): array } return [ - RuleErrorBuilder::message(sprintf('Argument of an invalid type %s supplied for foreach, only iterables are supported.', $type->describe(VerbosityLevel::typeOnly())))->identifier('foreach.nonIterable')->line($originalNode->expr->getStartLine())->build(), + RuleErrorBuilder::message(sprintf( + 'Argument of an invalid type %s supplied for foreach, only iterables are supported.', + $type->describe(VerbosityLevel::typeOnly()), + ))->identifier('foreach.nonIterable')->line($originalNode->expr->getStartLine())->build(), ]; } diff --git a/src/Rules/Arrays/NonexistentOffsetInArrayDimFetchCheck.php b/src/Rules/Arrays/NonexistentOffsetInArrayDimFetchCheck.php index e9f1542e550..ede68cc01a5 100644 --- a/src/Rules/Arrays/NonexistentOffsetInArrayDimFetchCheck.php +++ b/src/Rules/Arrays/NonexistentOffsetInArrayDimFetchCheck.php @@ -18,85 +18,89 @@ class NonexistentOffsetInArrayDimFetchCheck { - /** - * @var RuleLevelHelper - */ - private $ruleLevelHelper; - /** - * @var bool - */ - private $reportMaybes; - /** - * @var bool - */ - private $bleedingEdge; - public function __construct(RuleLevelHelper $ruleLevelHelper, bool $reportMaybes, bool $bleedingEdge) - { - $this->ruleLevelHelper = $ruleLevelHelper; - $this->reportMaybes = $reportMaybes; - $this->bleedingEdge = $bleedingEdge; + + public function __construct( + private RuleLevelHelper $ruleLevelHelper, + private bool $reportMaybes, + private bool $bleedingEdge, + ) + { + } + + /** + * @return list + */ + public function check( + Scope $scope, + Expr $var, + string $unknownClassPattern, + Type $dimType, + ): array + { + $typeResult = $this->ruleLevelHelper->findTypeToCheck( + $scope, + NullsafeOperatorHelper::getNullsafeShortcircuitedExprRespectingScope($scope, $var), + $unknownClassPattern, + static fn (Type $type): bool => $type->hasOffsetValueType($dimType)->yes(), + ); + $type = $typeResult->getType(); + if ($type instanceof ErrorType) { + return $typeResult->getUnknownClassErrors(); + } + + if ($scope->isInExpressionAssign($var) || $scope->isUndefinedExpressionAllowed($var)) { + return []; + } + + if ($type->hasOffsetValueType($dimType)->no()) { + return [ + RuleErrorBuilder::message(sprintf('Offset %s does not exist on %s.', $dimType->describe(VerbosityLevel::value()), $type->describe(VerbosityLevel::value()))) + ->identifier('offsetAccess.notFound') + ->build(), + ]; + } + + if ($this->reportMaybes) { + $report = false; + + if ($type instanceof BenevolentUnionType) { + $flattenedTypes = [$type]; + } else { + $flattenedTypes = TypeUtils::flattenTypes($type); + } + foreach ($flattenedTypes as $innerType) { + if ($dimType instanceof UnionType) { + if ($innerType->hasOffsetValueType($dimType)->no()) { + $report = true; + break; + } + continue; + } + foreach (TypeUtils::flattenTypes($dimType) as $innerDimType) { + if ($innerType->hasOffsetValueType($innerDimType)->no()) { + $report = true; + break 2; + } } - /** - * @return list - */ - public function check(Scope $scope, Expr $var, string $unknownClassPattern, Type $dimType) : array - { - $typeResult = $this->ruleLevelHelper->findTypeToCheck($scope, NullsafeOperatorHelper::getNullsafeShortcircuitedExprRespectingScope($scope, $var), $unknownClassPattern, static function (Type $type) use($dimType) : bool { - return $type->hasOffsetValueType($dimType)->yes(); - }); - $type = $typeResult->getType(); - if ($type instanceof ErrorType) { - return $typeResult->getUnknownClassErrors(); - } - if ($scope->isInExpressionAssign($var) || $scope->isUndefinedExpressionAllowed($var)) { - return []; - } - if ($type->hasOffsetValueType($dimType)->no()) { - return [ - RuleErrorBuilder::message(sprintf('Offset %s does not exist on %s.', $dimType->describe(VerbosityLevel::value()), $type->describe(VerbosityLevel::value()))) - ->identifier('offsetAccess.notFound') - ->build(), - ]; - } - if ($this->reportMaybes) { - $report = false; - - if ($type instanceof BenevolentUnionType) { - $flattenedTypes = [$type]; - } else { - $flattenedTypes = TypeUtils::flattenTypes($type); - } - foreach ($flattenedTypes as $innerType) { - if ($dimType instanceof UnionType) { - if ($innerType->hasOffsetValueType($dimType)->no()) { - $report = true; - break; - } - continue; - } - foreach (TypeUtils::flattenTypes($dimType) as $innerDimType) { - if ($innerType->hasOffsetValueType($innerDimType)->no()) { - $report = true; - break 2; - } - } - } - - if ($report) { - if ($this->bleedingEdge) { - return [ - RuleErrorBuilder::message(sprintf('Offset %s might not exist on %s.', $dimType->describe(VerbosityLevel::value()), $type->describe(VerbosityLevel::value()))) - ->identifier('offsetAccess.notFound') - ->build(), - ]; - } - return [ - RuleErrorBuilder::message(sprintf('Offset %s does not exist on %s.', $dimType->describe(VerbosityLevel::value()), $type->describe(VerbosityLevel::value()))) - ->identifier('offsetAccess.notFound') - ->build(), - ]; - } - } - return []; + } + + if ($report) { + if ($this->bleedingEdge) { + return [ + RuleErrorBuilder::message(sprintf('Offset %s might not exist on %s.', $dimType->describe(VerbosityLevel::value()), $type->describe(VerbosityLevel::value()))) + ->identifier('offsetAccess.notFound') + ->build(), + ]; } + return [ + RuleErrorBuilder::message(sprintf('Offset %s does not exist on %s.', $dimType->describe(VerbosityLevel::value()), $type->describe(VerbosityLevel::value()))) + ->identifier('offsetAccess.notFound') + ->build(), + ]; + } + } + + return []; + } + } diff --git a/src/Rules/Arrays/NonexistentOffsetInArrayDimFetchRule.php b/src/Rules/Arrays/NonexistentOffsetInArrayDimFetchRule.php index 4269eb699f0..cf8f3f43c1d 100644 --- a/src/Rules/Arrays/NonexistentOffsetInArrayDimFetchRule.php +++ b/src/Rules/Arrays/NonexistentOffsetInArrayDimFetchRule.php @@ -20,24 +20,14 @@ class NonexistentOffsetInArrayDimFetchRule implements Rule { - /** - * @var RuleLevelHelper - */ - private $ruleLevelHelper; - /** - * @var NonexistentOffsetInArrayDimFetchCheck - */ - private $nonexistentOffsetInArrayDimFetchCheck; - /** - * @var bool - */ - private $reportMaybes; - public function __construct(RuleLevelHelper $ruleLevelHelper, NonexistentOffsetInArrayDimFetchCheck $nonexistentOffsetInArrayDimFetchCheck, bool $reportMaybes) + public function __construct( + private RuleLevelHelper $ruleLevelHelper, + private NonexistentOffsetInArrayDimFetchCheck $nonexistentOffsetInArrayDimFetchCheck, + private bool $reportMaybes, + ) { - $this->ruleLevelHelper = $ruleLevelHelper; - $this->nonexistentOffsetInArrayDimFetchCheck = $nonexistentOffsetInArrayDimFetchCheck; - $this->reportMaybes = $reportMaybes; } + public function getNodeType(): string { return Node\Expr\ArrayDimFetch::class; @@ -53,9 +43,12 @@ public function processNode(Node $node, Scope $scope): array $unknownClassPattern = 'Access to an offset on an unknown class %s.'; } - $isOffsetAccessibleTypeResult = $this->ruleLevelHelper->findTypeToCheck($scope, NullsafeOperatorHelper::getNullsafeShortcircuitedExprRespectingScope($scope, $node->var), $unknownClassPattern, static function (Type $type) : bool { - return $type->isOffsetAccessible()->yes(); - }); + $isOffsetAccessibleTypeResult = $this->ruleLevelHelper->findTypeToCheck( + $scope, + NullsafeOperatorHelper::getNullsafeShortcircuitedExprRespectingScope($scope, $node->var), + $unknownClassPattern, + static fn (Type $type): bool => $type->isOffsetAccessible()->yes(), + ); $isOffsetAccessibleType = $isOffsetAccessibleTypeResult->getType(); if ($isOffsetAccessibleType instanceof ErrorType) { return $isOffsetAccessibleTypeResult->getUnknownClassErrors(); @@ -79,12 +72,19 @@ public function processNode(Node $node, Scope $scope): array if ($isOffsetAccessible->no() || $this->reportMaybes) { if ($dimType !== null) { return [ - RuleErrorBuilder::message(sprintf('Cannot access offset %s on %s.', $dimType->describe(VerbosityLevel::value()), $isOffsetAccessibleType->describe(VerbosityLevel::value())))->identifier('offsetAccess.nonOffsetAccessible')->build(), + RuleErrorBuilder::message(sprintf( + 'Cannot access offset %s on %s.', + $dimType->describe(VerbosityLevel::value()), + $isOffsetAccessibleType->describe(VerbosityLevel::value()), + ))->identifier('offsetAccess.nonOffsetAccessible')->build(), ]; } return [ - RuleErrorBuilder::message(sprintf('Cannot access an offset on %s.', $isOffsetAccessibleType->describe(VerbosityLevel::typeOnly())))->identifier('offsetAccess.nonOffsetAccessible')->build(), + RuleErrorBuilder::message(sprintf( + 'Cannot access an offset on %s.', + $isOffsetAccessibleType->describe(VerbosityLevel::typeOnly()), + ))->identifier('offsetAccess.nonOffsetAccessible')->build(), ]; } @@ -95,7 +95,12 @@ public function processNode(Node $node, Scope $scope): array return []; } - return $this->nonexistentOffsetInArrayDimFetchCheck->check($scope, $node->var, $unknownClassPattern, $dimType); + return $this->nonexistentOffsetInArrayDimFetchCheck->check( + $scope, + $node->var, + $unknownClassPattern, + $dimType, + ); } } diff --git a/src/Rules/Arrays/OffsetAccessAssignOpRule.php b/src/Rules/Arrays/OffsetAccessAssignOpRule.php index 16a5e03c8d8..ff66d9bb9f5 100644 --- a/src/Rules/Arrays/OffsetAccessAssignOpRule.php +++ b/src/Rules/Arrays/OffsetAccessAssignOpRule.php @@ -20,13 +20,8 @@ class OffsetAccessAssignOpRule implements Rule { - /** - * @var RuleLevelHelper - */ - private $ruleLevelHelper; - public function __construct(RuleLevelHelper $ruleLevelHelper) + public function __construct(private RuleLevelHelper $ruleLevelHelper) { - $this->ruleLevelHelper = $ruleLevelHelper; } public function getNodeType(): string @@ -47,17 +42,27 @@ public function processNode(Node $node, Scope $scope): array $potentialDimType = $scope->getType($arrayDimFetch->dim); } - $varTypeResult = $this->ruleLevelHelper->findTypeToCheck($scope, $arrayDimFetch->var, '', static function (Type $varType) use ($potentialDimType): bool { + $varTypeResult = $this->ruleLevelHelper->findTypeToCheck( + $scope, + $arrayDimFetch->var, + '', + static function (Type $varType) use ($potentialDimType): bool { $arrayDimType = $varType->setOffsetValueType($potentialDimType, new MixedType()); return !($arrayDimType instanceof ErrorType); - }); + }, + ); $varType = $varTypeResult->getType(); if ($arrayDimFetch->dim !== null) { - $dimTypeResult = $this->ruleLevelHelper->findTypeToCheck($scope, $arrayDimFetch->dim, '', static function (Type $dimType) use ($varType): bool { + $dimTypeResult = $this->ruleLevelHelper->findTypeToCheck( + $scope, + $arrayDimFetch->dim, + '', + static function (Type $dimType) use ($varType): bool { $arrayDimType = $varType->setOffsetValueType($dimType, new MixedType()); return !($arrayDimType instanceof ErrorType); - }); + }, + ); $dimType = $dimTypeResult->getType(); if ($varType->hasOffsetValueType($dimType)->no()) { return []; @@ -73,12 +78,19 @@ public function processNode(Node $node, Scope $scope): array if ($dimType === null) { return [ - RuleErrorBuilder::message(sprintf('Cannot assign new offset to %s.', $varType->describe(VerbosityLevel::typeOnly())))->identifier('offsetAssign.dimType')->build(), + RuleErrorBuilder::message(sprintf( + 'Cannot assign new offset to %s.', + $varType->describe(VerbosityLevel::typeOnly()), + ))->identifier('offsetAssign.dimType')->build(), ]; } return [ - RuleErrorBuilder::message(sprintf('Cannot assign offset %s to %s.', $dimType->describe(VerbosityLevel::value()), $varType->describe(VerbosityLevel::typeOnly())))->identifier('offsetAssign.dimType')->build(), + RuleErrorBuilder::message(sprintf( + 'Cannot assign offset %s to %s.', + $dimType->describe(VerbosityLevel::value()), + $varType->describe(VerbosityLevel::typeOnly()), + ))->identifier('offsetAssign.dimType')->build(), ]; } diff --git a/src/Rules/Arrays/OffsetAccessAssignmentRule.php b/src/Rules/Arrays/OffsetAccessAssignmentRule.php index d04b26c9697..0bafe975d00 100644 --- a/src/Rules/Arrays/OffsetAccessAssignmentRule.php +++ b/src/Rules/Arrays/OffsetAccessAssignmentRule.php @@ -20,13 +20,8 @@ class OffsetAccessAssignmentRule implements Rule { - /** - * @var RuleLevelHelper - */ - private $ruleLevelHelper; - public function __construct(RuleLevelHelper $ruleLevelHelper) + public function __construct(private RuleLevelHelper $ruleLevelHelper) { - $this->ruleLevelHelper = $ruleLevelHelper; } public function getNodeType(): string @@ -45,10 +40,15 @@ public function processNode(Node $node, Scope $scope): array $potentialDimType = $scope->getType($node->dim); } - $varTypeResult = $this->ruleLevelHelper->findTypeToCheck($scope, NullsafeOperatorHelper::getNullsafeShortcircuitedExprRespectingScope($scope, $node->var), '', static function (Type $varType) use ($potentialDimType): bool { + $varTypeResult = $this->ruleLevelHelper->findTypeToCheck( + $scope, + NullsafeOperatorHelper::getNullsafeShortcircuitedExprRespectingScope($scope, $node->var), + '', + static function (Type $varType) use ($potentialDimType): bool { $arrayDimType = $varType->setOffsetValueType($potentialDimType, new MixedType()); return !($arrayDimType instanceof ErrorType); - }); + }, + ); $varType = $varTypeResult->getType(); if ($varType instanceof ErrorType) { return []; @@ -58,10 +58,15 @@ public function processNode(Node $node, Scope $scope): array } if ($node->dim !== null) { - $dimTypeResult = $this->ruleLevelHelper->findTypeToCheck($scope, $node->dim, '', static function (Type $dimType) use ($varType): bool { + $dimTypeResult = $this->ruleLevelHelper->findTypeToCheck( + $scope, + $node->dim, + '', + static function (Type $dimType) use ($varType): bool { $arrayDimType = $varType->setOffsetValueType($dimType, new MixedType()); return !($arrayDimType instanceof ErrorType); - }); + }, + ); $dimType = $dimTypeResult->getType(); } else { $dimType = $potentialDimType; @@ -74,12 +79,19 @@ public function processNode(Node $node, Scope $scope): array if ($dimType === null) { return [ - RuleErrorBuilder::message(sprintf('Cannot assign new offset to %s.', $varType->describe(VerbosityLevel::typeOnly())))->identifier('offsetAssign.dimType')->build(), + RuleErrorBuilder::message(sprintf( + 'Cannot assign new offset to %s.', + $varType->describe(VerbosityLevel::typeOnly()), + ))->identifier('offsetAssign.dimType')->build(), ]; } return [ - RuleErrorBuilder::message(sprintf('Cannot assign offset %s to %s.', $dimType->describe(VerbosityLevel::value()), $varType->describe(VerbosityLevel::typeOnly())))->identifier('offsetAssign.dimType')->build(), + RuleErrorBuilder::message(sprintf( + 'Cannot assign offset %s to %s.', + $dimType->describe(VerbosityLevel::value()), + $varType->describe(VerbosityLevel::typeOnly()), + ))->identifier('offsetAssign.dimType')->build(), ]; } diff --git a/src/Rules/Arrays/OffsetAccessValueAssignmentRule.php b/src/Rules/Arrays/OffsetAccessValueAssignmentRule.php index 8d85504d34b..03688957604 100644 --- a/src/Rules/Arrays/OffsetAccessValueAssignmentRule.php +++ b/src/Rules/Arrays/OffsetAccessValueAssignmentRule.php @@ -22,13 +22,8 @@ class OffsetAccessValueAssignmentRule implements Rule { - /** - * @var RuleLevelHelper - */ - private $ruleLevelHelper; - public function __construct(RuleLevelHelper $ruleLevelHelper) + public function __construct(private RuleLevelHelper $ruleLevelHelper) { - $this->ruleLevelHelper = $ruleLevelHelper; } public function getNodeType(): string @@ -58,10 +53,15 @@ public function processNode(Node $node, Scope $scope): array $assignedValueType = $scope->getType($node); } - $arrayTypeResult = $this->ruleLevelHelper->findTypeToCheck($scope, $arrayDimFetch->var, '', static function (Type $varType) use ($assignedValueType): bool { + $arrayTypeResult = $this->ruleLevelHelper->findTypeToCheck( + $scope, + $arrayDimFetch->var, + '', + static function (Type $varType) use ($assignedValueType): bool { $result = $varType->setOffsetValueType(new MixedType(), $assignedValueType); return !($result instanceof ErrorType); - }); + }, + ); $arrayType = $arrayTypeResult->getType(); if ($arrayType instanceof ErrorType) { return []; @@ -78,7 +78,11 @@ public function processNode(Node $node, Scope $scope): array $originalArrayType = $scope->getType($arrayDimFetch->var); return [ - RuleErrorBuilder::message(sprintf('%s does not accept %s.', $originalArrayType->describe(VerbosityLevel::value()), $assignedValueType->describe(VerbosityLevel::typeOnly())))->identifier('offsetAssign.valueType')->build(), + RuleErrorBuilder::message(sprintf( + '%s does not accept %s.', + $originalArrayType->describe(VerbosityLevel::value()), + $assignedValueType->describe(VerbosityLevel::typeOnly()), + ))->identifier('offsetAssign.valueType')->build(), ]; } diff --git a/src/Rules/Arrays/UnpackIterableInArrayRule.php b/src/Rules/Arrays/UnpackIterableInArrayRule.php index be59b3dffd2..10a3a677581 100644 --- a/src/Rules/Arrays/UnpackIterableInArrayRule.php +++ b/src/Rules/Arrays/UnpackIterableInArrayRule.php @@ -19,14 +19,12 @@ class UnpackIterableInArrayRule implements Rule { - /** - * @var RuleLevelHelper - */ - private $ruleLevelHelper; - public function __construct(RuleLevelHelper $ruleLevelHelper) + public function __construct( + private RuleLevelHelper $ruleLevelHelper, + ) { - $this->ruleLevelHelper = $ruleLevelHelper; } + public function getNodeType(): string { return LiteralArrayNode::class; @@ -44,9 +42,12 @@ public function processNode(Node $node, Scope $scope): array continue; } - $typeResult = $this->ruleLevelHelper->findTypeToCheck($scope, $item->value, '', static function (Type $type) : bool { - return $type->isIterable()->yes(); - }); + $typeResult = $this->ruleLevelHelper->findTypeToCheck( + $scope, + $item->value, + '', + static fn (Type $type): bool => $type->isIterable()->yes(), + ); $type = $typeResult->getType(); if ($type instanceof ErrorType) { continue; @@ -56,7 +57,10 @@ public function processNode(Node $node, Scope $scope): array continue; } - $errors[] = RuleErrorBuilder::message(sprintf('Only iterables can be unpacked, %s given.', $type->describe(VerbosityLevel::typeOnly())))->identifier('arrayUnpacking.nonIterable')->line($item->getStartLine())->build(); + $errors[] = RuleErrorBuilder::message(sprintf( + 'Only iterables can be unpacked, %s given.', + $type->describe(VerbosityLevel::typeOnly()), + ))->identifier('arrayUnpacking.nonIterable')->line($item->getStartLine())->build(); } return $errors; diff --git a/src/Rules/AttributesCheck.php b/src/Rules/AttributesCheck.php index 50480951a34..151e2581ed4 100644 --- a/src/Rules/AttributesCheck.php +++ b/src/Rules/AttributesCheck.php @@ -16,146 +16,152 @@ class AttributesCheck { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - /** - * @var FunctionCallParametersCheck - */ - private $functionCallParametersCheck; - /** - * @var ClassCaseSensitivityCheck - */ - private $classCaseSensitivityCheck; - /** - * @var bool - */ - private $deprecationRulesInstalled; - public function __construct(ReflectionProvider $reflectionProvider, FunctionCallParametersCheck $functionCallParametersCheck, ClassCaseSensitivityCheck $classCaseSensitivityCheck, bool $deprecationRulesInstalled) - { - $this->reflectionProvider = $reflectionProvider; - $this->functionCallParametersCheck = $functionCallParametersCheck; - $this->classCaseSensitivityCheck = $classCaseSensitivityCheck; - $this->deprecationRulesInstalled = $deprecationRulesInstalled; + + public function __construct( + private ReflectionProvider $reflectionProvider, + private FunctionCallParametersCheck $functionCallParametersCheck, + private ClassCaseSensitivityCheck $classCaseSensitivityCheck, + private bool $deprecationRulesInstalled, + ) + { + } + + /** + * @param AttributeGroup[] $attrGroups + * @param int-mask-of $requiredTarget + * @return list + */ + public function check( + Scope $scope, + array $attrGroups, + int $requiredTarget, + string $targetName, + ): array + { + $errors = []; + $alreadyPresent = []; + foreach ($attrGroups as $attrGroup) { + foreach ($attrGroup->attrs as $attribute) { + $name = $attribute->name->toString(); + if (!$this->reflectionProvider->hasClass($name)) { + $errors[] = RuleErrorBuilder::message(sprintf('Attribute class %s does not exist.', $name)) + ->line($attribute->getStartLine()) + ->identifier('attribute.notFound') + ->build(); + continue; + } + + $attributeClass = $this->reflectionProvider->getClass($name); + if (!$attributeClass->isAttributeClass()) { + $errors[] = RuleErrorBuilder::message(sprintf('%s %s is not an Attribute class.', $attributeClass->getClassTypeDescription(), $attributeClass->getDisplayName())) + ->identifier('attribute.notAttribute') + ->line($attribute->getStartLine()) + ->build(); + continue; } - /** - * @param AttributeGroup[] $attrGroups - * @param int-mask-of $requiredTarget - * @return list - */ - public function check(Scope $scope, array $attrGroups, int $requiredTarget, string $targetName) : array - { - $errors = []; - $alreadyPresent = []; - foreach ($attrGroups as $attrGroup) { - foreach ($attrGroup->attrs as $attribute) { - $name = $attribute->name->toString(); - if (!$this->reflectionProvider->hasClass($name)) { - $errors[] = RuleErrorBuilder::message(sprintf('Attribute class %s does not exist.', $name)) - ->line($attribute->getStartLine()) - ->identifier('attribute.notFound') - ->build(); - continue; - } - - $attributeClass = $this->reflectionProvider->getClass($name); - if (!$attributeClass->isAttributeClass()) { - $errors[] = RuleErrorBuilder::message(sprintf('%s %s is not an Attribute class.', $attributeClass->getClassTypeDescription(), $attributeClass->getDisplayName())) - ->identifier('attribute.notAttribute') - ->line($attribute->getStartLine()) - ->build(); - continue; - } - - if ($attributeClass->isAbstract()) { - $errors[] = RuleErrorBuilder::message(sprintf('Attribute class %s is abstract.', $name)) - ->identifier('attribute.abstract') - ->line($attribute->getStartLine()) - ->build(); - } - - foreach ($this->classCaseSensitivityCheck->checkClassNames([new ClassNameNodePair($name, $attribute)]) as $caseSensitivityError) { - $errors[] = $caseSensitivityError; - } - - $flags = $attributeClass->getAttributeClassFlags(); - if (($flags & $requiredTarget) === 0) { - $errors[] = RuleErrorBuilder::message(sprintf('Attribute class %s does not have the %s target.', $name, $targetName)) - ->identifier('attribute.target') - ->line($attribute->getStartLine()) - ->build(); - } - - if (($flags & Attribute::IS_REPEATABLE) === 0) { - $loweredName = strtolower($name); - if (array_key_exists($loweredName, $alreadyPresent)) { - $errors[] = RuleErrorBuilder::message(sprintf('Attribute class %s is not repeatable but is already present above the %s.', $name, $targetName)) - ->identifier('attribute.nonRepeatable') - ->line($attribute->getStartLine()) - ->build(); - } - - $alreadyPresent[$loweredName] = true; - } - - if ($this->deprecationRulesInstalled && $attributeClass->isDeprecated()) { - if ($attributeClass->getDeprecatedDescription() !== null) { - $deprecatedError = sprintf('Attribute class %s is deprecated: %s', $name, $attributeClass->getDeprecatedDescription()); - } else { - $deprecatedError = sprintf('Attribute class %s is deprecated.', $name); - } - $errors[] = RuleErrorBuilder::message($deprecatedError) - ->identifier('attribute.deprecated') - ->line($attribute->getStartLine()) - ->build(); - } - - if (!$attributeClass->hasConstructor()) { - if (count($attribute->args) > 0) { - $errors[] = RuleErrorBuilder::message(sprintf('Attribute class %s does not have a constructor and must be instantiated without any parameters.', $name)) - ->identifier('attribute.noConstructor') - ->line($attribute->getStartLine()) - ->build(); - } - continue; - } - - $attributeConstructor = $attributeClass->getConstructor(); - if (!$attributeConstructor->isPublic()) { - $errors[] = RuleErrorBuilder::message(sprintf('Constructor of attribute class %s is not public.', $name)) - ->identifier('attribute.constructorNotPublic') - ->line($attribute->getStartLine()) - ->build(); - } - - $attributeClassName = SprintfHelper::escapeFormatString($attributeClass->getDisplayName()); - - $nodeAttributes = $attribute->getAttributes(); - $nodeAttributes['isAttribute'] = true; - - $parameterErrors = $this->functionCallParametersCheck->check(ParametersAcceptorSelector::selectFromArgs($scope, $attribute->args, $attributeConstructor->getVariants(), $attributeConstructor->getNamedArgumentsVariants()), $scope, $attributeConstructor->getDeclaringClass()->isBuiltin(), new New_($attribute->name, $attribute->args, $nodeAttributes), [ - 'Attribute class ' . $attributeClassName . ' constructor invoked with %d parameter, %d required.', - 'Attribute class ' . $attributeClassName . ' constructor invoked with %d parameters, %d required.', - 'Attribute class ' . $attributeClassName . ' constructor invoked with %d parameter, at least %d required.', - 'Attribute class ' . $attributeClassName . ' constructor invoked with %d parameters, at least %d required.', - 'Attribute class ' . $attributeClassName . ' constructor invoked with %d parameter, %d-%d required.', - 'Attribute class ' . $attributeClassName . ' constructor invoked with %d parameters, %d-%d required.', - 'Parameter %s of attribute class ' . $attributeClassName . ' constructor expects %s, %s given.', - '', // constructor does not have a return type - 'Parameter %s of attribute class ' . $attributeClassName . ' constructor is passed by reference, so it expects variables only', - 'Unable to resolve the template type %s in instantiation of attribute class ' . $attributeClassName, - 'Missing parameter $%s in call to ' . $attributeClassName . ' constructor.', - 'Unknown parameter $%s in call to ' . $attributeClassName . ' constructor.', - 'Return type of call to ' . $attributeClassName . ' constructor contains unresolvable type.', - 'Parameter %s of attribute class ' . $attributeClassName . ' constructor contains unresolvable type.', - ], 'attribute'); - - foreach ($parameterErrors as $error) { - $errors[] = $error; - } - } - } - return $errors; + + if ($attributeClass->isAbstract()) { + $errors[] = RuleErrorBuilder::message(sprintf('Attribute class %s is abstract.', $name)) + ->identifier('attribute.abstract') + ->line($attribute->getStartLine()) + ->build(); + } + + foreach ($this->classCaseSensitivityCheck->checkClassNames([new ClassNameNodePair($name, $attribute)]) as $caseSensitivityError) { + $errors[] = $caseSensitivityError; } + + $flags = $attributeClass->getAttributeClassFlags(); + if (($flags & $requiredTarget) === 0) { + $errors[] = RuleErrorBuilder::message(sprintf('Attribute class %s does not have the %s target.', $name, $targetName)) + ->identifier('attribute.target') + ->line($attribute->getStartLine()) + ->build(); + } + + if (($flags & Attribute::IS_REPEATABLE) === 0) { + $loweredName = strtolower($name); + if (array_key_exists($loweredName, $alreadyPresent)) { + $errors[] = RuleErrorBuilder::message(sprintf('Attribute class %s is not repeatable but is already present above the %s.', $name, $targetName)) + ->identifier('attribute.nonRepeatable') + ->line($attribute->getStartLine()) + ->build(); + } + + $alreadyPresent[$loweredName] = true; + } + + if ($this->deprecationRulesInstalled && $attributeClass->isDeprecated()) { + if ($attributeClass->getDeprecatedDescription() !== null) { + $deprecatedError = sprintf('Attribute class %s is deprecated: %s', $name, $attributeClass->getDeprecatedDescription()); + } else { + $deprecatedError = sprintf('Attribute class %s is deprecated.', $name); + } + $errors[] = RuleErrorBuilder::message($deprecatedError) + ->identifier('attribute.deprecated') + ->line($attribute->getStartLine()) + ->build(); + } + + if (!$attributeClass->hasConstructor()) { + if (count($attribute->args) > 0) { + $errors[] = RuleErrorBuilder::message(sprintf('Attribute class %s does not have a constructor and must be instantiated without any parameters.', $name)) + ->identifier('attribute.noConstructor') + ->line($attribute->getStartLine()) + ->build(); + } + continue; + } + + $attributeConstructor = $attributeClass->getConstructor(); + if (!$attributeConstructor->isPublic()) { + $errors[] = RuleErrorBuilder::message(sprintf('Constructor of attribute class %s is not public.', $name)) + ->identifier('attribute.constructorNotPublic') + ->line($attribute->getStartLine()) + ->build(); + } + + $attributeClassName = SprintfHelper::escapeFormatString($attributeClass->getDisplayName()); + + $nodeAttributes = $attribute->getAttributes(); + $nodeAttributes['isAttribute'] = true; + + $parameterErrors = $this->functionCallParametersCheck->check( + ParametersAcceptorSelector::selectFromArgs( + $scope, + $attribute->args, + $attributeConstructor->getVariants(), + $attributeConstructor->getNamedArgumentsVariants(), + ), + $scope, + $attributeConstructor->getDeclaringClass()->isBuiltin(), + new New_($attribute->name, $attribute->args, $nodeAttributes), + [ + 'Attribute class ' . $attributeClassName . ' constructor invoked with %d parameter, %d required.', + 'Attribute class ' . $attributeClassName . ' constructor invoked with %d parameters, %d required.', + 'Attribute class ' . $attributeClassName . ' constructor invoked with %d parameter, at least %d required.', + 'Attribute class ' . $attributeClassName . ' constructor invoked with %d parameters, at least %d required.', + 'Attribute class ' . $attributeClassName . ' constructor invoked with %d parameter, %d-%d required.', + 'Attribute class ' . $attributeClassName . ' constructor invoked with %d parameters, %d-%d required.', + 'Parameter %s of attribute class ' . $attributeClassName . ' constructor expects %s, %s given.', + '', // constructor does not have a return type + 'Parameter %s of attribute class ' . $attributeClassName . ' constructor is passed by reference, so it expects variables only', + 'Unable to resolve the template type %s in instantiation of attribute class ' . $attributeClassName, + 'Missing parameter $%s in call to ' . $attributeClassName . ' constructor.', + 'Unknown parameter $%s in call to ' . $attributeClassName . ' constructor.', + 'Return type of call to ' . $attributeClassName . ' constructor contains unresolvable type.', + 'Parameter %s of attribute class ' . $attributeClassName . ' constructor contains unresolvable type.', + ], + 'attribute', + ); + + foreach ($parameterErrors as $error) { + $errors[] = $error; + } + } + } + + return $errors; + } + } diff --git a/src/Rules/Cast/EchoRule.php b/src/Rules/Cast/EchoRule.php index c0152dd6550..d8033f53942 100644 --- a/src/Rules/Cast/EchoRule.php +++ b/src/Rules/Cast/EchoRule.php @@ -18,13 +18,8 @@ class EchoRule implements Rule { - /** - * @var RuleLevelHelper - */ - private $ruleLevelHelper; - public function __construct(RuleLevelHelper $ruleLevelHelper) + public function __construct(private RuleLevelHelper $ruleLevelHelper) { - $this->ruleLevelHelper = $ruleLevelHelper; } public function getNodeType(): string @@ -37,9 +32,12 @@ public function processNode(Node $node, Scope $scope): array $messages = []; foreach ($node->exprs as $key => $expr) { - $typeResult = $this->ruleLevelHelper->findTypeToCheck($scope, $expr, '', static function (Type $type) : bool { - return !$type->toString() instanceof ErrorType; - }); + $typeResult = $this->ruleLevelHelper->findTypeToCheck( + $scope, + $expr, + '', + static fn (Type $type): bool => !$type->toString() instanceof ErrorType, + ); if ($typeResult->getType() instanceof ErrorType || !$typeResult->getType()->toString() instanceof ErrorType @@ -47,7 +45,11 @@ public function processNode(Node $node, Scope $scope): array continue; } - $messages[] = RuleErrorBuilder::message(sprintf('Parameter #%d (%s) of echo cannot be converted to string.', $key + 1, $typeResult->getType()->describe(VerbosityLevel::value())))->identifier('echo.nonString')->line($expr->getStartLine())->build(); + $messages[] = RuleErrorBuilder::message(sprintf( + 'Parameter #%d (%s) of echo cannot be converted to string.', + $key + 1, + $typeResult->getType()->describe(VerbosityLevel::value()), + ))->identifier('echo.nonString')->line($expr->getStartLine())->build(); } return $messages; } diff --git a/src/Rules/Cast/InvalidCastRule.php b/src/Rules/Cast/InvalidCastRule.php index 51fa07f3463..ceb074e36cd 100644 --- a/src/Rules/Cast/InvalidCastRule.php +++ b/src/Rules/Cast/InvalidCastRule.php @@ -22,19 +22,13 @@ class InvalidCastRule implements Rule { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - /** - * @var RuleLevelHelper - */ - private $ruleLevelHelper; - public function __construct(ReflectionProvider $reflectionProvider, RuleLevelHelper $ruleLevelHelper) + public function __construct( + private ReflectionProvider $reflectionProvider, + private RuleLevelHelper $ruleLevelHelper, + ) { - $this->reflectionProvider = $reflectionProvider; - $this->ruleLevelHelper = $ruleLevelHelper; } + public function getNodeType(): string { return Node\Expr\Cast::class; @@ -56,7 +50,11 @@ public function processNode(Node $node, Scope $scope): array return null; }; - $typeResult = $this->ruleLevelHelper->findTypeToCheck($scope, $node->expr, '', static function (Type $type) use ($castTypeCallback): bool { + $typeResult = $this->ruleLevelHelper->findTypeToCheck( + $scope, + $node->expr, + '', + static function (Type $type) use ($castTypeCallback): bool { $castResult = $castTypeCallback($type); if ($castResult === null) { return true; @@ -65,7 +63,8 @@ public function processNode(Node $node, Scope $scope): array [$castType] = $castResult; return !$castType instanceof ErrorType; - }); + }, + ); $type = $typeResult->getType(); if ($type instanceof ErrorType) { return []; @@ -89,7 +88,11 @@ public function processNode(Node $node, Scope $scope): array } return [ - RuleErrorBuilder::message(sprintf('Cannot cast %s to %s.', $scope->getType($node->expr)->describe(VerbosityLevel::value()), $shortName))->identifier(sprintf('cast.%s', $castIdentifier))->line($node->getStartLine())->build(), + RuleErrorBuilder::message(sprintf( + 'Cannot cast %s to %s.', + $scope->getType($node->expr)->describe(VerbosityLevel::value()), + $shortName, + ))->identifier(sprintf('cast.%s', $castIdentifier))->line($node->getStartLine())->build(), ]; } diff --git a/src/Rules/Cast/InvalidPartOfEncapsedStringRule.php b/src/Rules/Cast/InvalidPartOfEncapsedStringRule.php index de6119a8c21..773aabe5d5e 100644 --- a/src/Rules/Cast/InvalidPartOfEncapsedStringRule.php +++ b/src/Rules/Cast/InvalidPartOfEncapsedStringRule.php @@ -19,19 +19,13 @@ class InvalidPartOfEncapsedStringRule implements Rule { - /** - * @var ExprPrinter - */ - private $exprPrinter; - /** - * @var RuleLevelHelper - */ - private $ruleLevelHelper; - public function __construct(ExprPrinter $exprPrinter, RuleLevelHelper $ruleLevelHelper) + public function __construct( + private ExprPrinter $exprPrinter, + private RuleLevelHelper $ruleLevelHelper, + ) { - $this->exprPrinter = $exprPrinter; - $this->ruleLevelHelper = $ruleLevelHelper; } + public function getNodeType(): string { return Node\Scalar\Encapsed::class; @@ -45,9 +39,12 @@ public function processNode(Node $node, Scope $scope): array continue; } - $typeResult = $this->ruleLevelHelper->findTypeToCheck($scope, $part, '', static function (Type $type) : bool { - return !$type->toString() instanceof ErrorType; - }); + $typeResult = $this->ruleLevelHelper->findTypeToCheck( + $scope, + $part, + '', + static fn (Type $type): bool => !$type->toString() instanceof ErrorType, + ); $partType = $typeResult->getType(); if ($partType instanceof ErrorType) { continue; @@ -57,7 +54,11 @@ public function processNode(Node $node, Scope $scope): array if (!$stringPartType instanceof ErrorType) { continue; } - $messages[] = RuleErrorBuilder::message(sprintf('Part %s (%s) of encapsed string cannot be cast to string.', $this->exprPrinter->printExpr($part), $partType->describe(VerbosityLevel::value())))->identifier('encapsedStringPart.nonString')->line($part->getStartLine())->build(); + $messages[] = RuleErrorBuilder::message(sprintf( + 'Part %s (%s) of encapsed string cannot be cast to string.', + $this->exprPrinter->printExpr($part), + $partType->describe(VerbosityLevel::value()), + ))->identifier('encapsedStringPart.nonString')->line($part->getStartLine())->build(); } return $messages; diff --git a/src/Rules/Cast/PrintRule.php b/src/Rules/Cast/PrintRule.php index cd81efc8c3f..3b8ad5f97dc 100644 --- a/src/Rules/Cast/PrintRule.php +++ b/src/Rules/Cast/PrintRule.php @@ -18,13 +18,8 @@ class PrintRule implements Rule { - /** - * @var RuleLevelHelper - */ - private $ruleLevelHelper; - public function __construct(RuleLevelHelper $ruleLevelHelper) + public function __construct(private RuleLevelHelper $ruleLevelHelper) { - $this->ruleLevelHelper = $ruleLevelHelper; } public function getNodeType(): string @@ -34,14 +29,20 @@ public function getNodeType(): string public function processNode(Node $node, Scope $scope): array { - $typeResult = $this->ruleLevelHelper->findTypeToCheck($scope, $node->expr, '', static function (Type $type) : bool { - return !$type->toString() instanceof ErrorType; - }); + $typeResult = $this->ruleLevelHelper->findTypeToCheck( + $scope, + $node->expr, + '', + static fn (Type $type): bool => !$type->toString() instanceof ErrorType, + ); if (!$typeResult->getType() instanceof ErrorType && $typeResult->getType()->toString() instanceof ErrorType ) { - return [RuleErrorBuilder::message(sprintf('Parameter %s of print cannot be converted to string.', $typeResult->getType()->describe(VerbosityLevel::value())))->identifier('print.nonString')->line($node->expr->getStartLine())->build()]; + return [RuleErrorBuilder::message(sprintf( + 'Parameter %s of print cannot be converted to string.', + $typeResult->getType()->describe(VerbosityLevel::value()), + ))->identifier('print.nonString')->line($node->expr->getStartLine())->build()]; } return []; diff --git a/src/Rules/Cast/UnsetCastRule.php b/src/Rules/Cast/UnsetCastRule.php index 28d9d6be9bd..be527ffad08 100644 --- a/src/Rules/Cast/UnsetCastRule.php +++ b/src/Rules/Cast/UnsetCastRule.php @@ -14,13 +14,8 @@ class UnsetCastRule implements Rule { - /** - * @var PhpVersion - */ - private $phpVersion; - public function __construct(PhpVersion $phpVersion) + public function __construct(private PhpVersion $phpVersion) { - $this->phpVersion = $phpVersion; } public function getNodeType(): string diff --git a/src/Rules/ClassCaseSensitivityCheck.php b/src/Rules/ClassCaseSensitivityCheck.php index d129bfde1fd..f7cdfdaab37 100644 --- a/src/Rules/ClassCaseSensitivityCheck.php +++ b/src/Rules/ClassCaseSensitivityCheck.php @@ -9,18 +9,8 @@ class ClassCaseSensitivityCheck { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - /** - * @var bool - */ - private $checkInternalClassCaseSensitivity; - public function __construct(ReflectionProvider $reflectionProvider, bool $checkInternalClassCaseSensitivity) + public function __construct(private ReflectionProvider $reflectionProvider, private bool $checkInternalClassCaseSensitivity) { - $this->reflectionProvider = $reflectionProvider; - $this->checkInternalClassCaseSensitivity = $checkInternalClassCaseSensitivity; } /** @@ -48,7 +38,12 @@ public function checkClassNames(array $pairs): array } $typeName = $classReflection->getClassTypeDescription(); - $errors[] = RuleErrorBuilder::message(sprintf('%s %s referenced with incorrect case: %s.', $typeName, $realClassName, $className)) + $errors[] = RuleErrorBuilder::message(sprintf( + '%s %s referenced with incorrect case: %s.', + $typeName, + $realClassName, + $className, + )) ->identifier(sprintf('%s.nameCase', strtolower($typeName))) ->line($pair->getNode()->getStartLine()) ->build(); diff --git a/src/Rules/ClassNameNodePair.php b/src/Rules/ClassNameNodePair.php index dbf6241e18c..355fa61e01d 100644 --- a/src/Rules/ClassNameNodePair.php +++ b/src/Rules/ClassNameNodePair.php @@ -7,18 +7,8 @@ class ClassNameNodePair { - /** - * @var string - */ - private $className; - /** - * @var Node - */ - private $node; - public function __construct(string $className, Node $node) + public function __construct(private string $className, private Node $node) { - $this->className = $className; - $this->node = $node; } public function getClassName(): string diff --git a/src/Rules/Classes/AccessPrivateConstantThroughStaticRule.php b/src/Rules/Classes/AccessPrivateConstantThroughStaticRule.php index d3a6c216c10..438398a4f9b 100644 --- a/src/Rules/Classes/AccessPrivateConstantThroughStaticRule.php +++ b/src/Rules/Classes/AccessPrivateConstantThroughStaticRule.php @@ -50,7 +50,11 @@ public function processNode(Node $node, Scope $scope): array } return [ - RuleErrorBuilder::message(sprintf('Unsafe access to private constant %s::%s through static::.', $constant->getDeclaringClass()->getDisplayName(), $constantName))->identifier('staticClassAccess.privateConstant')->build(), + RuleErrorBuilder::message(sprintf( + 'Unsafe access to private constant %s::%s through static::.', + $constant->getDeclaringClass()->getDisplayName(), + $constantName, + ))->identifier('staticClassAccess.privateConstant')->build(), ]; } diff --git a/src/Rules/Classes/AllowedSubTypesRule.php b/src/Rules/Classes/AllowedSubTypesRule.php index 92bd00b08c5..164e63d9d75 100644 --- a/src/Rules/Classes/AllowedSubTypesRule.php +++ b/src/Rules/Classes/AllowedSubTypesRule.php @@ -55,7 +55,11 @@ public function processNode(Node $node, Scope $scope): array } $identifierType = strtolower($classReflection->getClassTypeDescription()); - $messages[] = RuleErrorBuilder::message(sprintf('Type %s is not allowed to be a subtype of %s.', $className, $parentReflection->getName()))->identifier(sprintf('%s.disallowedSubtype', $identifierType))->build(); + $messages[] = RuleErrorBuilder::message(sprintf( + 'Type %s is not allowed to be a subtype of %s.', + $className, + $parentReflection->getName(), + ))->identifier(sprintf('%s.disallowedSubtype', $identifierType))->build(); } return $messages; diff --git a/src/Rules/Classes/ClassAttributesRule.php b/src/Rules/Classes/ClassAttributesRule.php index 8e7a7fa45d4..21d6bda7499 100644 --- a/src/Rules/Classes/ClassAttributesRule.php +++ b/src/Rules/Classes/ClassAttributesRule.php @@ -14,13 +14,8 @@ class ClassAttributesRule implements Rule { - /** - * @var AttributesCheck - */ - private $attributesCheck; - public function __construct(AttributesCheck $attributesCheck) + public function __construct(private AttributesCheck $attributesCheck) { - $this->attributesCheck = $attributesCheck; } public function getNodeType(): string @@ -30,7 +25,12 @@ public function getNodeType(): string public function processNode(Node $node, Scope $scope): array { - return $this->attributesCheck->check($scope, $node->attrGroups, Attribute::TARGET_CLASS, 'class'); + return $this->attributesCheck->check( + $scope, + $node->attrGroups, + Attribute::TARGET_CLASS, + 'class', + ); } } diff --git a/src/Rules/Classes/ClassConstantAttributesRule.php b/src/Rules/Classes/ClassConstantAttributesRule.php index 19b97500da0..d8256191a09 100644 --- a/src/Rules/Classes/ClassConstantAttributesRule.php +++ b/src/Rules/Classes/ClassConstantAttributesRule.php @@ -14,13 +14,8 @@ class ClassConstantAttributesRule implements Rule { - /** - * @var AttributesCheck - */ - private $attributesCheck; - public function __construct(AttributesCheck $attributesCheck) + public function __construct(private AttributesCheck $attributesCheck) { - $this->attributesCheck = $attributesCheck; } public function getNodeType(): string @@ -30,7 +25,12 @@ public function getNodeType(): string public function processNode(Node $node, Scope $scope): array { - return $this->attributesCheck->check($scope, $node->attrGroups, Attribute::TARGET_CLASS_CONSTANT, 'class constant'); + return $this->attributesCheck->check( + $scope, + $node->attrGroups, + Attribute::TARGET_CLASS_CONSTANT, + 'class constant', + ); } } diff --git a/src/Rules/Classes/ClassConstantRule.php b/src/Rules/Classes/ClassConstantRule.php index db21c568826..2217ba992dd 100644 --- a/src/Rules/Classes/ClassConstantRule.php +++ b/src/Rules/Classes/ClassConstantRule.php @@ -31,29 +31,15 @@ class ClassConstantRule implements Rule { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - /** - * @var RuleLevelHelper - */ - private $ruleLevelHelper; - /** - * @var ClassCaseSensitivityCheck - */ - private $classCaseSensitivityCheck; - /** - * @var PhpVersion - */ - private $phpVersion; - public function __construct(ReflectionProvider $reflectionProvider, RuleLevelHelper $ruleLevelHelper, ClassCaseSensitivityCheck $classCaseSensitivityCheck, PhpVersion $phpVersion) + public function __construct( + private ReflectionProvider $reflectionProvider, + private RuleLevelHelper $ruleLevelHelper, + private ClassCaseSensitivityCheck $classCaseSensitivityCheck, + private PhpVersion $phpVersion, + ) { - $this->reflectionProvider = $reflectionProvider; - $this->ruleLevelHelper = $ruleLevelHelper; - $this->classCaseSensitivityCheck = $classCaseSensitivityCheck; - $this->phpVersion = $phpVersion; } + public function getNodeType(): string { return ClassConstFetch::class; @@ -92,7 +78,11 @@ public function processNode(Node $node, Scope $scope): array $currentClassReflection = $scope->getClassReflection(); if ($currentClassReflection->getParentClass() === null) { return [ - RuleErrorBuilder::message(sprintf('Access to parent::%s but %s does not extend any class.', $constantName, $currentClassReflection->getDisplayName()))->identifier('class.noParent')->build(), + RuleErrorBuilder::message(sprintf( + 'Access to parent::%s but %s does not extend any class.', + $constantName, + $currentClassReflection->getDisplayName(), + ))->identifier('class.noParent')->build(), ]; } $classType = $scope->resolveTypeByName($class); @@ -112,7 +102,9 @@ public function processNode(Node $node, Scope $scope): array } return [ - RuleErrorBuilder::message(sprintf('Access to constant %s on an unknown class %s.', $constantName, $className)) + RuleErrorBuilder::message( + sprintf('Access to constant %s on an unknown class %s.', $constantName, $className), + ) ->identifier('class.notFound') ->discoveringSymbolsTip() ->build(), @@ -128,9 +120,12 @@ public function processNode(Node $node, Scope $scope): array return $messages; } } else { - $classTypeResult = $this->ruleLevelHelper->findTypeToCheck($scope, NullsafeOperatorHelper::getNullsafeShortcircuitedExprRespectingScope($scope, $class), sprintf('Access to constant %s on an unknown class %%s.', SprintfHelper::escapeFormatString($constantName)), static function (Type $type) use($constantName) : bool { - return $type->canAccessConstants()->yes() && $type->hasConstant($constantName)->yes(); - }); + $classTypeResult = $this->ruleLevelHelper->findTypeToCheck( + $scope, + NullsafeOperatorHelper::getNullsafeShortcircuitedExprRespectingScope($scope, $class), + sprintf('Access to constant %s on an unknown class %%s.', SprintfHelper::escapeFormatString($constantName)), + static fn (Type $type): bool => $type->canAccessConstants()->yes() && $type->hasConstant($constantName)->yes(), + ); $classType = $classTypeResult->getType(); if ($classType instanceof ErrorType) { return $classTypeResult->getUnknownClassErrors(); @@ -169,7 +164,11 @@ public function processNode(Node $node, Scope $scope): array if (!$classType->canAccessConstants()->yes()) { return array_merge($messages, [ - RuleErrorBuilder::message(sprintf('Cannot access constant %s on %s.', $constantName, $typeForDescribe->describe(VerbosityLevel::typeOnly())))->identifier('classConstant.nonObject')->build(), + RuleErrorBuilder::message(sprintf( + 'Cannot access constant %s on %s.', + $constantName, + $typeForDescribe->describe(VerbosityLevel::typeOnly()), + ))->identifier('classConstant.nonObject')->build(), ]); } @@ -179,14 +178,26 @@ public function processNode(Node $node, Scope $scope): array if (!$classType->hasConstant($constantName)->yes()) { return array_merge($messages, [ - RuleErrorBuilder::message(sprintf('Access to undefined constant %s::%s.', $typeForDescribe->describe(VerbosityLevel::typeOnly()), $constantName))->identifier('classConstant.notFound')->build(), + RuleErrorBuilder::message(sprintf( + 'Access to undefined constant %s::%s.', + $typeForDescribe->describe(VerbosityLevel::typeOnly()), + $constantName, + ))->identifier('classConstant.notFound')->build(), ]); } $constantReflection = $classType->getConstant($constantName); if (!$scope->canAccessConstant($constantReflection)) { return array_merge($messages, [ - RuleErrorBuilder::message(sprintf('Access to %s constant %s of class %s.', $constantReflection->isPrivate() ? 'private' : 'protected', $constantName, $constantReflection->getDeclaringClass()->getDisplayName()))->identifier(sprintf('classConstant.%s', $constantReflection->isPrivate() ? 'private' : 'protected'))->build(), + RuleErrorBuilder::message(sprintf( + 'Access to %s constant %s of class %s.', + $constantReflection->isPrivate() ? 'private' : 'protected', + $constantName, + $constantReflection->getDeclaringClass()->getDisplayName(), + ))->identifier(sprintf( + 'classConstant.%s', + $constantReflection->isPrivate() ? 'private' : 'protected', + ))->build(), ]); } diff --git a/src/Rules/Classes/DuplicateClassDeclarationRule.php b/src/Rules/Classes/DuplicateClassDeclarationRule.php index b6b37e75f9e..ae2658de794 100644 --- a/src/Rules/Classes/DuplicateClassDeclarationRule.php +++ b/src/Rules/Classes/DuplicateClassDeclarationRule.php @@ -23,18 +23,8 @@ class DuplicateClassDeclarationRule implements Rule { - /** - * @var Reflector - */ - private $reflector; - /** - * @var RelativePathHelper - */ - private $relativePathHelper; - public function __construct(Reflector $reflector, RelativePathHelper $relativePathHelper) + public function __construct(private Reflector $reflector, private RelativePathHelper $relativePathHelper) { - $this->reflector = $reflector; - $this->relativePathHelper = $relativePathHelper; } public function getNodeType(): string @@ -60,16 +50,16 @@ public function processNode(Node $node, Scope $scope): array return []; } - $filteredClasses = array_filter($filteredClasses, static function (ReflectionClass $class) use($thisClass) { - return $class->getStartLine() !== $thisClass->getNativeReflection()->getStartLine(); - }); + $filteredClasses = array_filter($filteredClasses, static fn (ReflectionClass $class) => $class->getStartLine() !== $thisClass->getNativeReflection()->getStartLine()); $identifierType = strtolower($thisClass->getClassTypeDescription()); return [ - RuleErrorBuilder::message(sprintf("Class %s declared multiple times:\n%s", $thisClass->getDisplayName(), implode("\n", array_map(function (ReflectionClass $class) { - return sprintf('- %s:%d', $this->relativePathHelper->getRelativePath($class->getFileName() ?? 'unknown'), $class->getStartLine()); - }, $filteredClasses))))->identifier(sprintf('%s.duplicate', $identifierType))->build(), + RuleErrorBuilder::message(sprintf( + "Class %s declared multiple times:\n%s", + $thisClass->getDisplayName(), + implode("\n", array_map(fn (ReflectionClass $class) => sprintf('- %s:%d', $this->relativePathHelper->getRelativePath($class->getFileName() ?? 'unknown'), $class->getStartLine()), $filteredClasses)), + ))->identifier(sprintf('%s.duplicate', $identifierType))->build(), ]; } diff --git a/src/Rules/Classes/DuplicateDeclarationRule.php b/src/Rules/Classes/DuplicateDeclarationRule.php index b8ec0a20b05..b5e122eb0e7 100644 --- a/src/Rules/Classes/DuplicateDeclarationRule.php +++ b/src/Rules/Classes/DuplicateDeclarationRule.php @@ -38,7 +38,11 @@ public function processNode(Node $node, Scope $scope): array foreach ($node->getOriginalNode()->stmts as $stmtNode) { if ($stmtNode instanceof EnumCase) { if (array_key_exists($stmtNode->name->name, $declaredClassConstantsOrEnumCases)) { - $errors[] = RuleErrorBuilder::message(sprintf('Cannot redeclare enum case %s::%s.', $classReflection->getDisplayName(), $stmtNode->name->name))->identifier(sprintf('%s.duplicateEnumCase', $identifierType)) + $errors[] = RuleErrorBuilder::message(sprintf( + 'Cannot redeclare enum case %s::%s.', + $classReflection->getDisplayName(), + $stmtNode->name->name, + ))->identifier(sprintf('%s.duplicateEnumCase', $identifierType)) ->line($stmtNode->getStartLine()) ->nonIgnorable() ->build(); @@ -48,7 +52,11 @@ public function processNode(Node $node, Scope $scope): array } elseif ($stmtNode instanceof ClassConst) { foreach ($stmtNode->consts as $classConstNode) { if (array_key_exists($classConstNode->name->name, $declaredClassConstantsOrEnumCases)) { - $errors[] = RuleErrorBuilder::message(sprintf('Cannot redeclare constant %s::%s.', $classReflection->getDisplayName(), $classConstNode->name->name))->identifier(sprintf('%s.duplicateConstant', $identifierType)) + $errors[] = RuleErrorBuilder::message(sprintf( + 'Cannot redeclare constant %s::%s.', + $classReflection->getDisplayName(), + $classConstNode->name->name, + ))->identifier(sprintf('%s.duplicateConstant', $identifierType)) ->line($classConstNode->getStartLine()) ->nonIgnorable() ->build(); @@ -63,7 +71,11 @@ public function processNode(Node $node, Scope $scope): array foreach ($node->getOriginalNode()->getProperties() as $propertyDecl) { foreach ($propertyDecl->props as $property) { if (array_key_exists($property->name->name, $declaredProperties)) { - $errors[] = RuleErrorBuilder::message(sprintf('Cannot redeclare property %s::$%s.', $classReflection->getDisplayName(), $property->name->name))->identifier(sprintf('%s.duplicateProperty', $identifierType)) + $errors[] = RuleErrorBuilder::message(sprintf( + 'Cannot redeclare property %s::$%s.', + $classReflection->getDisplayName(), + $property->name->name, + ))->identifier(sprintf('%s.duplicateProperty', $identifierType)) ->line($property->getStartLine()) ->nonIgnorable() ->build(); @@ -88,7 +100,11 @@ public function processNode(Node $node, Scope $scope): array $propertyName = $param->var->name; if (array_key_exists($propertyName, $declaredProperties)) { - $errors[] = RuleErrorBuilder::message(sprintf('Cannot redeclare property %s::$%s.', $classReflection->getDisplayName(), $propertyName))->identifier(sprintf('%s.duplicateProperty', $identifierType)) + $errors[] = RuleErrorBuilder::message(sprintf( + 'Cannot redeclare property %s::$%s.', + $classReflection->getDisplayName(), + $propertyName, + ))->identifier(sprintf('%s.duplicateProperty', $identifierType)) ->line($param->getStartLine()) ->nonIgnorable() ->build(); @@ -98,7 +114,11 @@ public function processNode(Node $node, Scope $scope): array } } if (array_key_exists(strtolower($method->name->name), $declaredFunctions)) { - $errors[] = RuleErrorBuilder::message(sprintf('Cannot redeclare method %s::%s().', $classReflection->getDisplayName(), $method->name->name))->identifier(sprintf('%s.duplicateMethod', $identifierType)) + $errors[] = RuleErrorBuilder::message(sprintf( + 'Cannot redeclare method %s::%s().', + $classReflection->getDisplayName(), + $method->name->name, + ))->identifier(sprintf('%s.duplicateMethod', $identifierType)) ->line($method->getStartLine()) ->nonIgnorable() ->build(); diff --git a/src/Rules/Classes/EnumSanityRule.php b/src/Rules/Classes/EnumSanityRule.php index b295cca2349..742dbd18426 100644 --- a/src/Rules/Classes/EnumSanityRule.php +++ b/src/Rules/Classes/EnumSanityRule.php @@ -48,7 +48,11 @@ public function processNode(Node $node, Scope $scope): array foreach ($enumNode->getMethods() as $methodNode) { if ($methodNode->isAbstract()) { - $errors[] = RuleErrorBuilder::message(sprintf('Enum %s contains abstract method %s().', $classReflection->getDisplayName(), $methodNode->name->name)) + $errors[] = RuleErrorBuilder::message(sprintf( + 'Enum %s contains abstract method %s().', + $classReflection->getDisplayName(), + $methodNode->name->name, + )) ->identifier('enum.abstractMethod') ->line($methodNode->getStartLine()) ->nonIgnorable() @@ -59,19 +63,29 @@ public function processNode(Node $node, Scope $scope): array if ($methodNode->isMagic()) { if ($lowercasedMethodName === '__construct') { - $errors[] = RuleErrorBuilder::message(sprintf('Enum %s contains constructor.', $classReflection->getDisplayName())) + $errors[] = RuleErrorBuilder::message(sprintf( + 'Enum %s contains constructor.', + $classReflection->getDisplayName(), + )) ->identifier('enum.constructor') ->line($methodNode->getStartLine()) ->nonIgnorable() ->build(); } elseif ($lowercasedMethodName === '__destruct') { - $errors[] = RuleErrorBuilder::message(sprintf('Enum %s contains destructor.', $classReflection->getDisplayName())) + $errors[] = RuleErrorBuilder::message(sprintf( + 'Enum %s contains destructor.', + $classReflection->getDisplayName(), + )) ->identifier('enum.destructor') ->line($methodNode->getStartLine()) ->nonIgnorable() ->build(); } elseif (!array_key_exists($lowercasedMethodName, self::ALLOWED_MAGIC_METHODS)) { - $errors[] = RuleErrorBuilder::message(sprintf('Enum %s contains magic method %s().', $classReflection->getDisplayName(), $methodNode->name->name)) + $errors[] = RuleErrorBuilder::message(sprintf( + 'Enum %s contains magic method %s().', + $classReflection->getDisplayName(), + $methodNode->name->name, + )) ->identifier('enum.magicMethod') ->line($methodNode->getStartLine()) ->nonIgnorable() @@ -80,7 +94,11 @@ public function processNode(Node $node, Scope $scope): array } if ($lowercasedMethodName === 'cases') { - $errors[] = RuleErrorBuilder::message(sprintf('Enum %s cannot redeclare native method %s().', $classReflection->getDisplayName(), $methodNode->name->name)) + $errors[] = RuleErrorBuilder::message(sprintf( + 'Enum %s cannot redeclare native method %s().', + $classReflection->getDisplayName(), + $methodNode->name->name, + )) ->identifier('enum.methodRedeclaration') ->line($methodNode->getStartLine()) ->nonIgnorable() @@ -95,7 +113,11 @@ public function processNode(Node $node, Scope $scope): array continue; } - $errors[] = RuleErrorBuilder::message(sprintf('Enum %s cannot redeclare native method %s().', $classReflection->getDisplayName(), $methodNode->name->name)) + $errors[] = RuleErrorBuilder::message(sprintf( + 'Enum %s cannot redeclare native method %s().', + $classReflection->getDisplayName(), + $methodNode->name->name, + )) ->identifier('enum.methodRedeclaration') ->line($methodNode->getStartLine()) ->nonIgnorable() @@ -106,7 +128,10 @@ public function processNode(Node $node, Scope $scope): array $enumNode->scalarType !== null && !in_array($enumNode->scalarType->name, ['int', 'string'], true) ) { - $errors[] = RuleErrorBuilder::message(sprintf('Backed enum %s can have only "int" or "string" type.', $classReflection->getDisplayName())) + $errors[] = RuleErrorBuilder::message(sprintf( + 'Backed enum %s can have only "int" or "string" type.', + $classReflection->getDisplayName(), + )) ->identifier('enum.backingType') ->line($enumNode->scalarType->getStartLine()) ->nonIgnorable() @@ -114,7 +139,10 @@ public function processNode(Node $node, Scope $scope): array } if ($classReflection->implementsInterface(Serializable::class)) { - $errors[] = RuleErrorBuilder::message(sprintf('Enum %s cannot implement the Serializable interface.', $classReflection->getDisplayName())) + $errors[] = RuleErrorBuilder::message(sprintf( + 'Enum %s cannot implement the Serializable interface.', + $classReflection->getDisplayName(), + )) ->identifier('enum.serializable') ->line($enumNode->getStartLine()) ->nonIgnorable() @@ -130,7 +158,12 @@ public function processNode(Node $node, Scope $scope): array if ($stmt->expr instanceof Node\Scalar\LNumber || $stmt->expr instanceof Node\Scalar\String_) { if ($enumNode->scalarType === null) { - $errors[] = RuleErrorBuilder::message(sprintf('Enum %s is not backed, but case %s has value %s.', $classReflection->getDisplayName(), $caseName, $stmt->expr->value)) + $errors[] = RuleErrorBuilder::message(sprintf( + 'Enum %s is not backed, but case %s has value %s.', + $classReflection->getDisplayName(), + $caseName, + $stmt->expr->value, + )) ->identifier('enum.caseWithValue') ->line($stmt->getStartLine()) ->nonIgnorable() @@ -151,7 +184,12 @@ public function processNode(Node $node, Scope $scope): array } if ($stmt->expr === null) { - $errors[] = RuleErrorBuilder::message(sprintf('Enum case %s::%s does not have a value but the enum is backed with the "%s" type.', $classReflection->getDisplayName(), $caseName, $enumNode->scalarType->name)) + $errors[] = RuleErrorBuilder::message(sprintf( + 'Enum case %s::%s does not have a value but the enum is backed with the "%s" type.', + $classReflection->getDisplayName(), + $caseName, + $enumNode->scalarType->name, + )) ->identifier('enum.missingCase') ->line($stmt->getStartLine()) ->nonIgnorable() @@ -165,7 +203,13 @@ public function processNode(Node $node, Scope $scope): array continue; } - $errors[] = RuleErrorBuilder::message(sprintf('Enum case %s::%s value %s does not match the "%s" type.', $classReflection->getDisplayName(), $caseName, $exprType->describe(VerbosityLevel::value()), $scalarType->describe(VerbosityLevel::typeOnly()))) + $errors[] = RuleErrorBuilder::message(sprintf( + 'Enum case %s::%s value %s does not match the "%s" type.', + $classReflection->getDisplayName(), + $caseName, + $exprType->describe(VerbosityLevel::value()), + $scalarType->describe(VerbosityLevel::typeOnly()), + )) ->identifier('enum.caseType') ->line($stmt->getStartLine()) ->nonIgnorable() @@ -177,7 +221,12 @@ public function processNode(Node $node, Scope $scope): array continue; } - $errors[] = RuleErrorBuilder::message(sprintf('Enum %s has duplicate value %s for cases %s.', $classReflection->getDisplayName(), $caseValue, implode(', ', $caseNames))) + $errors[] = RuleErrorBuilder::message(sprintf( + 'Enum %s has duplicate value %s for cases %s.', + $classReflection->getDisplayName(), + $caseValue, + implode(', ', $caseNames), + )) ->identifier('enum.duplicateValue') ->line($enumNode->getStartLine()) ->nonIgnorable() diff --git a/src/Rules/Classes/ExistingClassInClassExtendsRule.php b/src/Rules/Classes/ExistingClassInClassExtendsRule.php index 8d6d9a913c5..df11f732477 100644 --- a/src/Rules/Classes/ExistingClassInClassExtendsRule.php +++ b/src/Rules/Classes/ExistingClassInClassExtendsRule.php @@ -17,19 +17,13 @@ class ExistingClassInClassExtendsRule implements Rule { - /** - * @var ClassCaseSensitivityCheck - */ - private $classCaseSensitivityCheck; - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - public function __construct(ClassCaseSensitivityCheck $classCaseSensitivityCheck, ReflectionProvider $reflectionProvider) + public function __construct( + private ClassCaseSensitivityCheck $classCaseSensitivityCheck, + private ReflectionProvider $reflectionProvider, + ) { - $this->classCaseSensitivityCheck = $classCaseSensitivityCheck; - $this->reflectionProvider = $reflectionProvider; } + public function getNodeType(): string { return Node\Stmt\Class_::class; @@ -48,7 +42,11 @@ public function processNode(Node $node, Scope $scope): array } if (!$this->reflectionProvider->hasClass($extendedClassName)) { if (!$scope->isInClassExists($extendedClassName)) { - $messages[] = RuleErrorBuilder::message(sprintf('%s extends unknown class %s.', $currentClassName !== null ? sprintf('Class %s', $currentClassName) : 'Anonymous class', $extendedClassName)) + $messages[] = RuleErrorBuilder::message(sprintf( + '%s extends unknown class %s.', + $currentClassName !== null ? sprintf('Class %s', $currentClassName) : 'Anonymous class', + $extendedClassName, + )) ->identifier('class.notFound') ->nonIgnorable() ->discoveringSymbolsTip() @@ -57,27 +55,47 @@ public function processNode(Node $node, Scope $scope): array } else { $reflection = $this->reflectionProvider->getClass($extendedClassName); if ($reflection->isInterface()) { - $messages[] = RuleErrorBuilder::message(sprintf('%s extends interface %s.', $currentClassName !== null ? sprintf('Class %s', $currentClassName) : 'Anonymous class', $reflection->getDisplayName())) + $messages[] = RuleErrorBuilder::message(sprintf( + '%s extends interface %s.', + $currentClassName !== null ? sprintf('Class %s', $currentClassName) : 'Anonymous class', + $reflection->getDisplayName(), + )) ->identifier('class.extendsInterface') ->nonIgnorable() ->build(); } elseif ($reflection->isTrait()) { - $messages[] = RuleErrorBuilder::message(sprintf('%s extends trait %s.', $currentClassName !== null ? sprintf('Class %s', $currentClassName) : 'Anonymous class', $reflection->getDisplayName())) + $messages[] = RuleErrorBuilder::message(sprintf( + '%s extends trait %s.', + $currentClassName !== null ? sprintf('Class %s', $currentClassName) : 'Anonymous class', + $reflection->getDisplayName(), + )) ->identifier('class.extendsTrait') ->nonIgnorable() ->build(); } elseif ($reflection->isEnum()) { - $messages[] = RuleErrorBuilder::message(sprintf('%s extends enum %s.', $currentClassName !== null ? sprintf('Class %s', $currentClassName) : 'Anonymous class', $reflection->getDisplayName())) + $messages[] = RuleErrorBuilder::message(sprintf( + '%s extends enum %s.', + $currentClassName !== null ? sprintf('Class %s', $currentClassName) : 'Anonymous class', + $reflection->getDisplayName(), + )) ->identifier('class.extendsEnum') ->nonIgnorable() ->build(); } elseif ($reflection->isFinalByKeyword()) { - $messages[] = RuleErrorBuilder::message(sprintf('%s extends final class %s.', $currentClassName !== null ? sprintf('Class %s', $currentClassName) : 'Anonymous class', $reflection->getDisplayName())) + $messages[] = RuleErrorBuilder::message(sprintf( + '%s extends final class %s.', + $currentClassName !== null ? sprintf('Class %s', $currentClassName) : 'Anonymous class', + $reflection->getDisplayName(), + )) ->identifier('class.extendsFinal') ->nonIgnorable() ->build(); } elseif ($reflection->isFinal()) { - $messages[] = RuleErrorBuilder::message(sprintf('%s extends @final class %s.', $currentClassName !== null ? sprintf('Class %s', $currentClassName) : 'Anonymous class', $reflection->getDisplayName())) + $messages[] = RuleErrorBuilder::message(sprintf( + '%s extends @final class %s.', + $currentClassName !== null ? sprintf('Class %s', $currentClassName) : 'Anonymous class', + $reflection->getDisplayName(), + )) ->identifier('class.extendsFinalByPhpDoc') ->build(); } diff --git a/src/Rules/Classes/ExistingClassInInstanceOfRule.php b/src/Rules/Classes/ExistingClassInInstanceOfRule.php index f609f7c2612..a3f130db953 100644 --- a/src/Rules/Classes/ExistingClassInInstanceOfRule.php +++ b/src/Rules/Classes/ExistingClassInInstanceOfRule.php @@ -22,24 +22,14 @@ class ExistingClassInInstanceOfRule implements Rule { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - /** - * @var ClassCaseSensitivityCheck - */ - private $classCaseSensitivityCheck; - /** - * @var bool - */ - private $checkClassCaseSensitivity; - public function __construct(ReflectionProvider $reflectionProvider, ClassCaseSensitivityCheck $classCaseSensitivityCheck, bool $checkClassCaseSensitivity) + public function __construct( + private ReflectionProvider $reflectionProvider, + private ClassCaseSensitivityCheck $classCaseSensitivityCheck, + private bool $checkClassCaseSensitivity, + ) { - $this->reflectionProvider = $reflectionProvider; - $this->classCaseSensitivityCheck = $classCaseSensitivityCheck; - $this->checkClassCaseSensitivity = $checkClassCaseSensitivity; } + public function getNodeType(): string { return Instanceof_::class; @@ -87,7 +77,10 @@ public function processNode(Node $node, Scope $scope): array ->build(), ]; } elseif ($this->checkClassCaseSensitivity) { - $errors = array_merge($errors, $this->classCaseSensitivityCheck->checkClassNames([new ClassNameNodePair($name, $class)])); + $errors = array_merge( + $errors, + $this->classCaseSensitivityCheck->checkClassNames([new ClassNameNodePair($name, $class)]), + ); } $classReflection = $this->reflectionProvider->getClass($name); @@ -95,7 +88,11 @@ public function processNode(Node $node, Scope $scope): array if ($classReflection->isTrait()) { $expressionType = $scope->getType($node->expr); - $errors[] = RuleErrorBuilder::message(sprintf('Instanceof between %s and trait %s will always evaluate to false.', $expressionType->describe(VerbosityLevel::typeOnly()), $name))->identifier('instanceof.trait')->build(); + $errors[] = RuleErrorBuilder::message(sprintf( + 'Instanceof between %s and trait %s will always evaluate to false.', + $expressionType->describe(VerbosityLevel::typeOnly()), + $name, + ))->identifier('instanceof.trait')->build(); } return $errors; diff --git a/src/Rules/Classes/ExistingClassInTraitUseRule.php b/src/Rules/Classes/ExistingClassInTraitUseRule.php index 7cb46345643..d3cbd76660c 100644 --- a/src/Rules/Classes/ExistingClassInTraitUseRule.php +++ b/src/Rules/Classes/ExistingClassInTraitUseRule.php @@ -19,19 +19,13 @@ class ExistingClassInTraitUseRule implements Rule { - /** - * @var ClassCaseSensitivityCheck - */ - private $classCaseSensitivityCheck; - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - public function __construct(ClassCaseSensitivityCheck $classCaseSensitivityCheck, ReflectionProvider $reflectionProvider) + public function __construct( + private ClassCaseSensitivityCheck $classCaseSensitivityCheck, + private ReflectionProvider $reflectionProvider, + ) { - $this->classCaseSensitivityCheck = $classCaseSensitivityCheck; - $this->reflectionProvider = $reflectionProvider; } + public function getNodeType(): string { return Node\Stmt\TraitUse::class; @@ -39,9 +33,9 @@ public function getNodeType(): string public function processNode(Node $node, Scope $scope): array { - $messages = $this->classCaseSensitivityCheck->checkClassNames(array_map(static function (Node\Name $traitName) : ClassNameNodePair { - return new ClassNameNodePair((string) $traitName, $traitName); - }, $node->traits)); + $messages = $this->classCaseSensitivityCheck->checkClassNames( + array_map(static fn (Node\Name $traitName): ClassNameNodePair => new ClassNameNodePair((string) $traitName, $traitName), $node->traits), + ); if (!$scope->isInClass()) { throw new ShouldNotHappenException(); diff --git a/src/Rules/Classes/ExistingClassesInClassImplementsRule.php b/src/Rules/Classes/ExistingClassesInClassImplementsRule.php index 4caad8b0d5f..c7d5238b023 100644 --- a/src/Rules/Classes/ExistingClassesInClassImplementsRule.php +++ b/src/Rules/Classes/ExistingClassesInClassImplementsRule.php @@ -18,19 +18,13 @@ class ExistingClassesInClassImplementsRule implements Rule { - /** - * @var ClassCaseSensitivityCheck - */ - private $classCaseSensitivityCheck; - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - public function __construct(ClassCaseSensitivityCheck $classCaseSensitivityCheck, ReflectionProvider $reflectionProvider) + public function __construct( + private ClassCaseSensitivityCheck $classCaseSensitivityCheck, + private ReflectionProvider $reflectionProvider, + ) { - $this->classCaseSensitivityCheck = $classCaseSensitivityCheck; - $this->reflectionProvider = $reflectionProvider; } + public function getNodeType(): string { return Node\Stmt\Class_::class; @@ -38,9 +32,9 @@ public function getNodeType(): string public function processNode(Node $node, Scope $scope): array { - $messages = $this->classCaseSensitivityCheck->checkClassNames(array_map(static function (Node\Name $interfaceName) : ClassNameNodePair { - return new ClassNameNodePair((string) $interfaceName, $interfaceName); - }, $node->implements)); + $messages = $this->classCaseSensitivityCheck->checkClassNames( + array_map(static fn (Node\Name $interfaceName): ClassNameNodePair => new ClassNameNodePair((string) $interfaceName, $interfaceName), $node->implements), + ); $currentClassName = null; if (isset($node->namespacedName)) { @@ -51,7 +45,11 @@ public function processNode(Node $node, Scope $scope): array $implementedClassName = (string) $implements; if (!$this->reflectionProvider->hasClass($implementedClassName)) { if (!$scope->isInClassExists($implementedClassName)) { - $messages[] = RuleErrorBuilder::message(sprintf('%s implements unknown interface %s.', $currentClassName !== null ? sprintf('Class %s', $currentClassName) : 'Anonymous class', $implementedClassName)) + $messages[] = RuleErrorBuilder::message(sprintf( + '%s implements unknown interface %s.', + $currentClassName !== null ? sprintf('Class %s', $currentClassName) : 'Anonymous class', + $implementedClassName, + )) ->identifier('interface.notFound') ->nonIgnorable() ->discoveringSymbolsTip() @@ -60,17 +58,29 @@ public function processNode(Node $node, Scope $scope): array } else { $reflection = $this->reflectionProvider->getClass($implementedClassName); if ($reflection->isClass()) { - $messages[] = RuleErrorBuilder::message(sprintf('%s implements class %s.', $currentClassName !== null ? sprintf('Class %s', $currentClassName) : 'Anonymous class', $reflection->getDisplayName())) + $messages[] = RuleErrorBuilder::message(sprintf( + '%s implements class %s.', + $currentClassName !== null ? sprintf('Class %s', $currentClassName) : 'Anonymous class', + $reflection->getDisplayName(), + )) ->identifier('classImplements.class') ->nonIgnorable() ->build(); } elseif ($reflection->isTrait()) { - $messages[] = RuleErrorBuilder::message(sprintf('%s implements trait %s.', $currentClassName !== null ? sprintf('Class %s', $currentClassName) : 'Anonymous class', $reflection->getDisplayName())) + $messages[] = RuleErrorBuilder::message(sprintf( + '%s implements trait %s.', + $currentClassName !== null ? sprintf('Class %s', $currentClassName) : 'Anonymous class', + $reflection->getDisplayName(), + )) ->identifier('classImplements.trait') ->nonIgnorable() ->build(); } elseif ($reflection->isEnum()) { - $messages[] = RuleErrorBuilder::message(sprintf('%s implements enum %s.', $currentClassName !== null ? sprintf('Class %s', $currentClassName) : 'Anonymous class', $reflection->getDisplayName())) + $messages[] = RuleErrorBuilder::message(sprintf( + '%s implements enum %s.', + $currentClassName !== null ? sprintf('Class %s', $currentClassName) : 'Anonymous class', + $reflection->getDisplayName(), + )) ->identifier('classImplements.enum') ->nonIgnorable() ->build(); diff --git a/src/Rules/Classes/ExistingClassesInEnumImplementsRule.php b/src/Rules/Classes/ExistingClassesInEnumImplementsRule.php index bacea5d032e..f596681c0c4 100644 --- a/src/Rules/Classes/ExistingClassesInEnumImplementsRule.php +++ b/src/Rules/Classes/ExistingClassesInEnumImplementsRule.php @@ -18,19 +18,13 @@ class ExistingClassesInEnumImplementsRule implements Rule { - /** - * @var ClassCaseSensitivityCheck - */ - private $classCaseSensitivityCheck; - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - public function __construct(ClassCaseSensitivityCheck $classCaseSensitivityCheck, ReflectionProvider $reflectionProvider) + public function __construct( + private ClassCaseSensitivityCheck $classCaseSensitivityCheck, + private ReflectionProvider $reflectionProvider, + ) { - $this->classCaseSensitivityCheck = $classCaseSensitivityCheck; - $this->reflectionProvider = $reflectionProvider; } + public function getNodeType(): string { return Node\Stmt\Enum_::class; @@ -38,9 +32,9 @@ public function getNodeType(): string public function processNode(Node $node, Scope $scope): array { - $messages = $this->classCaseSensitivityCheck->checkClassNames(array_map(static function (Node\Name $interfaceName) : ClassNameNodePair { - return new ClassNameNodePair((string) $interfaceName, $interfaceName); - }, $node->implements)); + $messages = $this->classCaseSensitivityCheck->checkClassNames( + array_map(static fn (Node\Name $interfaceName): ClassNameNodePair => new ClassNameNodePair((string) $interfaceName, $interfaceName), $node->implements), + ); $currentEnumName = (string) $node->namespacedName; @@ -48,7 +42,11 @@ public function processNode(Node $node, Scope $scope): array $implementedClassName = (string) $implements; if (!$this->reflectionProvider->hasClass($implementedClassName)) { if (!$scope->isInClassExists($implementedClassName)) { - $messages[] = RuleErrorBuilder::message(sprintf('Enum %s implements unknown interface %s.', $currentEnumName, $implementedClassName)) + $messages[] = RuleErrorBuilder::message(sprintf( + 'Enum %s implements unknown interface %s.', + $currentEnumName, + $implementedClassName, + )) ->identifier('interface.notFound') ->nonIgnorable() ->discoveringSymbolsTip() @@ -57,17 +55,29 @@ public function processNode(Node $node, Scope $scope): array } else { $reflection = $this->reflectionProvider->getClass($implementedClassName); if ($reflection->isClass()) { - $messages[] = RuleErrorBuilder::message(sprintf('Enum %s implements class %s.', $currentEnumName, $reflection->getDisplayName())) + $messages[] = RuleErrorBuilder::message(sprintf( + 'Enum %s implements class %s.', + $currentEnumName, + $reflection->getDisplayName(), + )) ->identifier('enumImplements.class') ->nonIgnorable() ->build(); } elseif ($reflection->isTrait()) { - $messages[] = RuleErrorBuilder::message(sprintf('Enum %s implements trait %s.', $currentEnumName, $reflection->getDisplayName())) + $messages[] = RuleErrorBuilder::message(sprintf( + 'Enum %s implements trait %s.', + $currentEnumName, + $reflection->getDisplayName(), + )) ->identifier('enumImplements.trait') ->nonIgnorable() ->build(); } elseif ($reflection->isEnum()) { - $messages[] = RuleErrorBuilder::message(sprintf('Enum %s implements enum %s.', $currentEnumName, $reflection->getDisplayName())) + $messages[] = RuleErrorBuilder::message(sprintf( + 'Enum %s implements enum %s.', + $currentEnumName, + $reflection->getDisplayName(), + )) ->identifier('enumImplements.enum') ->nonIgnorable() ->build(); diff --git a/src/Rules/Classes/ExistingClassesInInterfaceExtendsRule.php b/src/Rules/Classes/ExistingClassesInInterfaceExtendsRule.php index 1e9e3c4cf32..7968563bdd7 100644 --- a/src/Rules/Classes/ExistingClassesInInterfaceExtendsRule.php +++ b/src/Rules/Classes/ExistingClassesInInterfaceExtendsRule.php @@ -18,19 +18,13 @@ class ExistingClassesInInterfaceExtendsRule implements Rule { - /** - * @var ClassCaseSensitivityCheck - */ - private $classCaseSensitivityCheck; - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - public function __construct(ClassCaseSensitivityCheck $classCaseSensitivityCheck, ReflectionProvider $reflectionProvider) + public function __construct( + private ClassCaseSensitivityCheck $classCaseSensitivityCheck, + private ReflectionProvider $reflectionProvider, + ) { - $this->classCaseSensitivityCheck = $classCaseSensitivityCheck; - $this->reflectionProvider = $reflectionProvider; } + public function getNodeType(): string { return Node\Stmt\Interface_::class; @@ -38,16 +32,20 @@ public function getNodeType(): string public function processNode(Node $node, Scope $scope): array { - $messages = $this->classCaseSensitivityCheck->checkClassNames(array_map(static function (Node\Name $interfaceName) : ClassNameNodePair { - return new ClassNameNodePair((string) $interfaceName, $interfaceName); - }, $node->extends)); + $messages = $this->classCaseSensitivityCheck->checkClassNames( + array_map(static fn (Node\Name $interfaceName): ClassNameNodePair => new ClassNameNodePair((string) $interfaceName, $interfaceName), $node->extends), + ); $currentInterfaceName = (string) $node->namespacedName; foreach ($node->extends as $extends) { $extendedInterfaceName = (string) $extends; if (!$this->reflectionProvider->hasClass($extendedInterfaceName)) { if (!$scope->isInClassExists($extendedInterfaceName)) { - $messages[] = RuleErrorBuilder::message(sprintf('Interface %s extends unknown interface %s.', $currentInterfaceName, $extendedInterfaceName)) + $messages[] = RuleErrorBuilder::message(sprintf( + 'Interface %s extends unknown interface %s.', + $currentInterfaceName, + $extendedInterfaceName, + )) ->identifier('interface.notFound') ->nonIgnorable() ->discoveringSymbolsTip() @@ -56,17 +54,29 @@ public function processNode(Node $node, Scope $scope): array } else { $reflection = $this->reflectionProvider->getClass($extendedInterfaceName); if ($reflection->isClass()) { - $messages[] = RuleErrorBuilder::message(sprintf('Interface %s extends class %s.', $currentInterfaceName, $reflection->getDisplayName())) + $messages[] = RuleErrorBuilder::message(sprintf( + 'Interface %s extends class %s.', + $currentInterfaceName, + $reflection->getDisplayName(), + )) ->identifier('interfaceExtends.class') ->nonIgnorable() ->build(); } elseif ($reflection->isTrait()) { - $messages[] = RuleErrorBuilder::message(sprintf('Interface %s extends trait %s.', $currentInterfaceName, $reflection->getDisplayName())) + $messages[] = RuleErrorBuilder::message(sprintf( + 'Interface %s extends trait %s.', + $currentInterfaceName, + $reflection->getDisplayName(), + )) ->identifier('interfaceExtends.trait') ->nonIgnorable() ->build(); } elseif ($reflection->isEnum()) { - $messages[] = RuleErrorBuilder::message(sprintf('Interface %s extends enum %s.', $currentInterfaceName, $reflection->getDisplayName())) + $messages[] = RuleErrorBuilder::message(sprintf( + 'Interface %s extends enum %s.', + $currentInterfaceName, + $reflection->getDisplayName(), + )) ->identifier('interfaceExtends.enum') ->nonIgnorable() ->build(); diff --git a/src/Rules/Classes/ImpossibleInstanceOfRule.php b/src/Rules/Classes/ImpossibleInstanceOfRule.php index 7df14872d31..69eb96f8326 100644 --- a/src/Rules/Classes/ImpossibleInstanceOfRule.php +++ b/src/Rules/Classes/ImpossibleInstanceOfRule.php @@ -21,24 +21,14 @@ class ImpossibleInstanceOfRule implements Rule { - /** - * @var bool - */ - private $checkAlwaysTrueInstanceof; - /** - * @var bool - */ - private $treatPhpDocTypesAsCertain; - /** - * @var bool - */ - private $reportAlwaysTrueInLastCondition; - public function __construct(bool $checkAlwaysTrueInstanceof, bool $treatPhpDocTypesAsCertain, bool $reportAlwaysTrueInLastCondition) + public function __construct( + private bool $checkAlwaysTrueInstanceof, + private bool $treatPhpDocTypesAsCertain, + private bool $reportAlwaysTrueInLastCondition, + ) { - $this->checkAlwaysTrueInstanceof = $checkAlwaysTrueInstanceof; - $this->treatPhpDocTypesAsCertain = $treatPhpDocTypesAsCertain; - $this->reportAlwaysTrueInLastCondition = $reportAlwaysTrueInLastCondition; } + public function getNodeType(): string { return Node\Expr\Instanceof_::class; @@ -56,10 +46,17 @@ public function processNode(Node $node, Scope $scope): array $classType = new ObjectType($className); } else { $classType = $this->treatPhpDocTypesAsCertain ? $scope->getType($node->class) : $scope->getNativeType($node->class); - $allowed = TypeCombinator::union(new StringType(), new ObjectWithoutClassType()); + $allowed = TypeCombinator::union( + new StringType(), + new ObjectWithoutClassType(), + ); if (!$allowed->isSuperTypeOf($classType)->yes()) { return [ - RuleErrorBuilder::message(sprintf('Instanceof between %s and %s results in an error.', $scope->getType($node->expr)->describe(VerbosityLevel::typeOnly()), $classType->describe(VerbosityLevel::typeOnly())))->identifier('instanceof.invalidExprType')->build(), + RuleErrorBuilder::message(sprintf( + 'Instanceof between %s and %s results in an error.', + $scope->getType($node->expr)->describe(VerbosityLevel::typeOnly()), + $classType->describe(VerbosityLevel::typeOnly()), + ))->identifier('instanceof.invalidExprType')->build(), ]; } } @@ -81,7 +78,11 @@ public function processNode(Node $node, Scope $scope): array $exprType = $this->treatPhpDocTypesAsCertain ? $scope->getType($node->expr) : $scope->getNativeType($node->expr); return [ - $addTip(RuleErrorBuilder::message(sprintf('Instanceof between %s and %s will always evaluate to false.', $exprType->describe(VerbosityLevel::typeOnly()), $classType->describe(VerbosityLevel::getRecommendedLevelByType($classType)))))->identifier('instanceof.alwaysFalse')->build(), + $addTip(RuleErrorBuilder::message(sprintf( + 'Instanceof between %s and %s will always evaluate to false.', + $exprType->describe(VerbosityLevel::typeOnly()), + $classType->describe(VerbosityLevel::getRecommendedLevelByType($classType)), + )))->identifier('instanceof.alwaysFalse')->build(), ]; } elseif ($this->checkAlwaysTrueInstanceof) { $isLast = $node->getAttribute(LastConditionVisitor::ATTRIBUTE_NAME); @@ -90,7 +91,11 @@ public function processNode(Node $node, Scope $scope): array } $exprType = $this->treatPhpDocTypesAsCertain ? $scope->getType($node->expr) : $scope->getNativeType($node->expr); - $errorBuilder = $addTip(RuleErrorBuilder::message(sprintf('Instanceof between %s and %s will always evaluate to true.', $exprType->describe(VerbosityLevel::typeOnly()), $classType->describe(VerbosityLevel::getRecommendedLevelByType($classType))))); + $errorBuilder = $addTip(RuleErrorBuilder::message(sprintf( + 'Instanceof between %s and %s will always evaluate to true.', + $exprType->describe(VerbosityLevel::typeOnly()), + $classType->describe(VerbosityLevel::getRecommendedLevelByType($classType)), + ))); if ($isLast === false && !$this->reportAlwaysTrueInLastCondition) { $errorBuilder->tip('Remove remaining cases below this one and this error will disappear too.'); } diff --git a/src/Rules/Classes/InstantiationRule.php b/src/Rules/Classes/InstantiationRule.php index 23fc1561a88..51143e7c0c7 100644 --- a/src/Rules/Classes/InstantiationRule.php +++ b/src/Rules/Classes/InstantiationRule.php @@ -29,24 +29,14 @@ class InstantiationRule implements Rule { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - /** - * @var FunctionCallParametersCheck - */ - private $check; - /** - * @var ClassCaseSensitivityCheck - */ - private $classCaseSensitivityCheck; - public function __construct(ReflectionProvider $reflectionProvider, FunctionCallParametersCheck $check, ClassCaseSensitivityCheck $classCaseSensitivityCheck) + public function __construct( + private ReflectionProvider $reflectionProvider, + private FunctionCallParametersCheck $check, + private ClassCaseSensitivityCheck $classCaseSensitivityCheck, + ) { - $this->reflectionProvider = $reflectionProvider; - $this->check = $check; - $this->classCaseSensitivityCheck = $classCaseSensitivityCheck; } + public function getNodeType(): string { return New_::class; @@ -115,7 +105,12 @@ private function checkClassName(string $class, bool $isName, Node $node, Scope $ } if ($scope->getClassReflection()->getParentClass() === null) { return [ - RuleErrorBuilder::message(sprintf('%s::%s() calls new parent but %s does not extend any class.', $scope->getClassReflection()->getDisplayName(), $scope->getFunctionName(), $scope->getClassReflection()->getDisplayName()))->identifier('class.noParent')->build(), + RuleErrorBuilder::message(sprintf( + '%s::%s() calls new parent but %s does not extend any class.', + $scope->getClassReflection()->getDisplayName(), + $scope->getFunctionName(), + $scope->getClassReflection()->getDisplayName(), + ))->identifier('class.noParent')->build(), ]; } $classReflection = $scope->getClassReflection()->getParentClass(); @@ -142,19 +137,25 @@ private function checkClassName(string $class, bool $isName, Node $node, Scope $ if ($classReflection->isEnum() && $isName) { return [ - RuleErrorBuilder::message(sprintf('Cannot instantiate enum %s.', $classReflection->getDisplayName()))->identifier('new.enum')->build(), + RuleErrorBuilder::message( + sprintf('Cannot instantiate enum %s.', $classReflection->getDisplayName()), + )->identifier('new.enum')->build(), ]; } if (!$isStatic && $classReflection->isInterface() && $isName) { return [ - RuleErrorBuilder::message(sprintf('Cannot instantiate interface %s.', $classReflection->getDisplayName()))->identifier('new.interface')->build(), + RuleErrorBuilder::message( + sprintf('Cannot instantiate interface %s.', $classReflection->getDisplayName()), + )->identifier('new.interface')->build(), ]; } if (!$isStatic && $classReflection->isAbstract() && $isName) { return [ - RuleErrorBuilder::message(sprintf('Instantiated class %s is abstract.', $classReflection->getDisplayName()))->identifier('new.abstract')->build(), + RuleErrorBuilder::message( + sprintf('Instantiated class %s is abstract.', $classReflection->getDisplayName()), + )->identifier('new.abstract')->build(), ]; } @@ -165,7 +166,10 @@ private function checkClassName(string $class, bool $isName, Node $node, Scope $ if (!$classReflection->hasConstructor()) { if (count($node->getArgs()) > 0) { return array_merge($messages, [ - RuleErrorBuilder::message(sprintf('Class %s does not have a constructor and must be instantiated without any parameters.', $classReflection->getDisplayName()))->identifier('new.noConstructor')->build(), + RuleErrorBuilder::message(sprintf( + 'Class %s does not have a constructor and must be instantiated without any parameters.', + $classReflection->getDisplayName(), + ))->identifier('new.noConstructor')->build(), ]); } @@ -174,14 +178,30 @@ private function checkClassName(string $class, bool $isName, Node $node, Scope $ $constructorReflection = $classReflection->getConstructor(); if (!$scope->canCallMethod($constructorReflection)) { - $messages[] = RuleErrorBuilder::message(sprintf('Cannot instantiate class %s via %s constructor %s::%s().', $classReflection->getDisplayName(), $constructorReflection->isPrivate() ? 'private' : 'protected', $constructorReflection->getDeclaringClass()->getDisplayName(), $constructorReflection->getName())) + $messages[] = RuleErrorBuilder::message(sprintf( + 'Cannot instantiate class %s via %s constructor %s::%s().', + $classReflection->getDisplayName(), + $constructorReflection->isPrivate() ? 'private' : 'protected', + $constructorReflection->getDeclaringClass()->getDisplayName(), + $constructorReflection->getName(), + )) ->identifier(sprintf('new.%sConstructor', $constructorReflection->isPrivate() ? 'private' : 'protected')) ->build(); } $classDisplayName = SprintfHelper::escapeFormatString($classReflection->getDisplayName()); - return array_merge($messages, $this->check->check(ParametersAcceptorSelector::selectFromArgs($scope, $node->getArgs(), $constructorReflection->getVariants(), $constructorReflection->getNamedArgumentsVariants()), $scope, $constructorReflection->getDeclaringClass()->isBuiltin(), $node, [ + return array_merge($messages, $this->check->check( + ParametersAcceptorSelector::selectFromArgs( + $scope, + $node->getArgs(), + $constructorReflection->getVariants(), + $constructorReflection->getNamedArgumentsVariants(), + ), + $scope, + $constructorReflection->getDeclaringClass()->isBuiltin(), + $node, + [ 'Class ' . $classDisplayName . ' constructor invoked with %d parameter, %d required.', 'Class ' . $classDisplayName . ' constructor invoked with %d parameters, %d required.', 'Class ' . $classDisplayName . ' constructor invoked with %d parameter, at least %d required.', @@ -196,7 +216,9 @@ private function checkClassName(string $class, bool $isName, Node $node, Scope $ 'Unknown parameter $%s in call to ' . $classDisplayName . ' constructor.', 'Return type of call to ' . $classDisplayName . ' constructor contains unresolvable type.', 'Parameter %s of class ' . $classDisplayName . ' constructor contains unresolvable type.', - ], 'new')); + ], + 'new', + )); } /** @@ -215,18 +237,24 @@ private function getClassNames(Node $node, Scope $scope): array throw new ShouldNotHappenException(); } - return array_map(static function (string $className) { - return [$className, true]; - }, $classNames); + return array_map( + static fn (string $className) => [$className, true], + $classNames, + ); } $type = $scope->getType($node->class); - return array_merge(array_map(static function (ConstantStringType $type) : array { - return [$type->getValue(), true]; - }, $type->getConstantStrings()), array_map(static function (string $name) : array { - return [$name, false]; - }, $type->getObjectClassNames())); + return array_merge( + array_map( + static fn (ConstantStringType $type): array => [$type->getValue(), true], + $type->getConstantStrings(), + ), + array_map( + static fn (string $name): array => [$name, false], + $type->getObjectClassNames(), + ), + ); } } diff --git a/src/Rules/Classes/InvalidPromotedPropertiesRule.php b/src/Rules/Classes/InvalidPromotedPropertiesRule.php index 46a14891ac2..5376f6b17e2 100644 --- a/src/Rules/Classes/InvalidPromotedPropertiesRule.php +++ b/src/Rules/Classes/InvalidPromotedPropertiesRule.php @@ -17,13 +17,8 @@ class InvalidPromotedPropertiesRule implements Rule { - /** - * @var PhpVersion - */ - private $phpVersion; - public function __construct(PhpVersion $phpVersion) + public function __construct(private PhpVersion $phpVersion) { - $this->phpVersion = $phpVersion; } public function getNodeType(): string @@ -50,7 +45,9 @@ public function processNode(Node $node, Scope $scope): array if (!$this->phpVersion->supportsPromotedProperties()) { return [ - RuleErrorBuilder::message('Promoted properties are supported only on PHP 8.0 and later.')->identifier('property.promotedNotSupported')->nonIgnorable()->build(), + RuleErrorBuilder::message( + 'Promoted properties are supported only on PHP 8.0 and later.', + )->identifier('property.promotedNotSupported')->nonIgnorable()->build(), ]; } @@ -61,13 +58,17 @@ public function processNode(Node $node, Scope $scope): array && $node->getAttribute('originalTraitMethodName') !== '__construct') ) { return [ - RuleErrorBuilder::message('Promoted properties can be in constructor only.')->identifier('property.invalidPromoted')->nonIgnorable()->build(), + RuleErrorBuilder::message( + 'Promoted properties can be in constructor only.', + )->identifier('property.invalidPromoted')->nonIgnorable()->build(), ]; } if ($node->getStmts() === null) { return [ - RuleErrorBuilder::message('Promoted properties are not allowed in abstract constructors.')->identifier('property.invalidPromoted')->nonIgnorable()->build(), + RuleErrorBuilder::message( + 'Promoted properties are not allowed in abstract constructors.', + )->identifier('property.invalidPromoted')->nonIgnorable()->build(), ]; } @@ -86,7 +87,9 @@ public function processNode(Node $node, Scope $scope): array } $propertyName = $param->var->name; - $errors[] = RuleErrorBuilder::message(sprintf('Promoted property parameter $%s can not be variadic.', $propertyName))->identifier('property.invalidPromoted')->nonIgnorable()->line($param->getStartLine())->build(); + $errors[] = RuleErrorBuilder::message( + sprintf('Promoted property parameter $%s can not be variadic.', $propertyName), + )->identifier('property.invalidPromoted')->nonIgnorable()->line($param->getStartLine())->build(); } return $errors; diff --git a/src/Rules/Classes/LocalTypeAliasesCheck.php b/src/Rules/Classes/LocalTypeAliasesCheck.php index f5ced459f9c..78940cac126 100644 --- a/src/Rules/Classes/LocalTypeAliasesCheck.php +++ b/src/Rules/Classes/LocalTypeAliasesCheck.php @@ -21,27 +21,17 @@ class LocalTypeAliasesCheck { - /** - * @var array - */ - private $globalTypeAliases; - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - /** - * @var TypeNodeResolver - */ - private $typeNodeResolver; /** * @param array $globalTypeAliases */ - public function __construct(array $globalTypeAliases, ReflectionProvider $reflectionProvider, TypeNodeResolver $typeNodeResolver) + public function __construct( + private array $globalTypeAliases, + private ReflectionProvider $reflectionProvider, + private TypeNodeResolver $typeNodeResolver, + ) { - $this->globalTypeAliases = $globalTypeAliases; - $this->reflectionProvider = $reflectionProvider; - $this->typeNodeResolver = $typeNodeResolver; } + /** * @return list */ diff --git a/src/Rules/Classes/LocalTypeAliasesRule.php b/src/Rules/Classes/LocalTypeAliasesRule.php index 02752326638..86697971b80 100644 --- a/src/Rules/Classes/LocalTypeAliasesRule.php +++ b/src/Rules/Classes/LocalTypeAliasesRule.php @@ -13,13 +13,8 @@ class LocalTypeAliasesRule implements Rule { - /** - * @var LocalTypeAliasesCheck - */ - private $check; - public function __construct(LocalTypeAliasesCheck $check) + public function __construct(private LocalTypeAliasesCheck $check) { - $this->check = $check; } public function getNodeType(): string diff --git a/src/Rules/Classes/LocalTypeTraitAliasesRule.php b/src/Rules/Classes/LocalTypeTraitAliasesRule.php index 1ac29366eda..406108db1b9 100644 --- a/src/Rules/Classes/LocalTypeTraitAliasesRule.php +++ b/src/Rules/Classes/LocalTypeTraitAliasesRule.php @@ -13,18 +13,8 @@ class LocalTypeTraitAliasesRule implements Rule { - /** - * @var LocalTypeAliasesCheck - */ - private $check; - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - public function __construct(LocalTypeAliasesCheck $check, ReflectionProvider $reflectionProvider) + public function __construct(private LocalTypeAliasesCheck $check, private ReflectionProvider $reflectionProvider) { - $this->check = $check; - $this->reflectionProvider = $reflectionProvider; } public function getNodeType(): string diff --git a/src/Rules/Classes/MixinRule.php b/src/Rules/Classes/MixinRule.php index b4b18fe8134..29f8bdd1622 100644 --- a/src/Rules/Classes/MixinRule.php +++ b/src/Rules/Classes/MixinRule.php @@ -24,39 +24,17 @@ class MixinRule implements Rule { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - /** - * @var ClassCaseSensitivityCheck - */ - private $classCaseSensitivityCheck; - /** - * @var GenericObjectTypeCheck - */ - private $genericObjectTypeCheck; - /** - * @var MissingTypehintCheck - */ - private $missingTypehintCheck; - /** - * @var UnresolvableTypeHelper - */ - private $unresolvableTypeHelper; - /** - * @var bool - */ - private $checkClassCaseSensitivity; - public function __construct(ReflectionProvider $reflectionProvider, ClassCaseSensitivityCheck $classCaseSensitivityCheck, GenericObjectTypeCheck $genericObjectTypeCheck, MissingTypehintCheck $missingTypehintCheck, UnresolvableTypeHelper $unresolvableTypeHelper, bool $checkClassCaseSensitivity) + public function __construct( + private ReflectionProvider $reflectionProvider, + private ClassCaseSensitivityCheck $classCaseSensitivityCheck, + private GenericObjectTypeCheck $genericObjectTypeCheck, + private MissingTypehintCheck $missingTypehintCheck, + private UnresolvableTypeHelper $unresolvableTypeHelper, + private bool $checkClassCaseSensitivity, + ) { - $this->reflectionProvider = $reflectionProvider; - $this->classCaseSensitivityCheck = $classCaseSensitivityCheck; - $this->genericObjectTypeCheck = $genericObjectTypeCheck; - $this->missingTypehintCheck = $missingTypehintCheck; - $this->unresolvableTypeHelper = $unresolvableTypeHelper; - $this->checkClassCaseSensitivity = $checkClassCaseSensitivity; } + public function getNodeType(): string { return InClassNode::class; @@ -85,10 +63,22 @@ public function processNode(Node $node, Scope $scope): array continue; } - $errors = array_merge($errors, $this->genericObjectTypeCheck->check($type, 'PHPDoc tag @mixin contains generic type %s but %s %s is not generic.', 'Generic type %s in PHPDoc tag @mixin does not specify all template types of %s %s: %s', 'Generic type %s in PHPDoc tag @mixin specifies %d template types, but %s %s supports only %d: %s', 'Type %s in generic type %s in PHPDoc tag @mixin is not subtype of template type %s of %s %s.', 'Call-site variance of %s in generic type %s in PHPDoc tag @mixin is in conflict with %s template type %s of %s %s.', 'Call-site variance of %s in generic type %s in PHPDoc tag @mixin is redundant, template type %s of %s %s has the same variance.')); + $errors = array_merge($errors, $this->genericObjectTypeCheck->check( + $type, + 'PHPDoc tag @mixin contains generic type %s but %s %s is not generic.', + 'Generic type %s in PHPDoc tag @mixin does not specify all template types of %s %s: %s', + 'Generic type %s in PHPDoc tag @mixin specifies %d template types, but %s %s supports only %d: %s', + 'Type %s in generic type %s in PHPDoc tag @mixin is not subtype of template type %s of %s %s.', + 'Call-site variance of %s in generic type %s in PHPDoc tag @mixin is in conflict with %s template type %s of %s %s.', + 'Call-site variance of %s in generic type %s in PHPDoc tag @mixin is redundant, template type %s of %s %s has the same variance.', + )); foreach ($this->missingTypehintCheck->getNonGenericObjectTypesWithGenericClass($type) as [$innerName, $genericTypeNames]) { - $errors[] = RuleErrorBuilder::message(sprintf('PHPDoc tag @mixin contains generic %s but does not specify its types: %s', $innerName, implode(', ', $genericTypeNames))) + $errors[] = RuleErrorBuilder::message(sprintf( + 'PHPDoc tag @mixin contains generic %s but does not specify its types: %s', + $innerName, + implode(', ', $genericTypeNames), + )) ->tip(MissingTypehintCheck::TURN_OFF_NON_GENERIC_CHECK_TIP) ->identifier('missingType.generics') ->build(); @@ -105,9 +95,12 @@ public function processNode(Node $node, Scope $scope): array ->identifier('mixin.trait') ->build(); } elseif ($this->checkClassCaseSensitivity) { - $errors = array_merge($errors, $this->classCaseSensitivityCheck->checkClassNames([ + $errors = array_merge( + $errors, + $this->classCaseSensitivityCheck->checkClassNames([ new ClassNameNodePair($class, $node), - ])); + ]), + ); } } } diff --git a/src/Rules/Classes/NonClassAttributeClassRule.php b/src/Rules/Classes/NonClassAttributeClassRule.php index 4b45943046e..c6318d07a4e 100644 --- a/src/Rules/Classes/NonClassAttributeClassRule.php +++ b/src/Rules/Classes/NonClassAttributeClassRule.php @@ -49,7 +49,10 @@ private function check(Scope $scope): array $classReflection = $scope->getClassReflection(); if (!$classReflection->isClass()) { return [ - RuleErrorBuilder::message(sprintf('%s cannot be an Attribute class.', $classReflection->getClassTypeDescription())) + RuleErrorBuilder::message(sprintf( + '%s cannot be an Attribute class.', + $classReflection->getClassTypeDescription(), + )) ->identifier(sprintf('attribute.%s', strtolower($classReflection->getClassTypeDescription()))) ->build(), ]; diff --git a/src/Rules/Classes/ReadOnlyClassRule.php b/src/Rules/Classes/ReadOnlyClassRule.php index dbaf1a7656a..21755c623cd 100644 --- a/src/Rules/Classes/ReadOnlyClassRule.php +++ b/src/Rules/Classes/ReadOnlyClassRule.php @@ -15,13 +15,8 @@ class ReadOnlyClassRule implements Rule { - /** - * @var PhpVersion - */ - private $phpVersion; - public function __construct(PhpVersion $phpVersion) + public function __construct(private PhpVersion $phpVersion) { - $this->phpVersion = $phpVersion; } public function getNodeType(): string diff --git a/src/Rules/Classes/RequireExtendsRule.php b/src/Rules/Classes/RequireExtendsRule.php index aa017237956..34a35ab11f4 100644 --- a/src/Rules/Classes/RequireExtendsRule.php +++ b/src/Rules/Classes/RequireExtendsRule.php @@ -43,7 +43,14 @@ public function processNode(Node $node, Scope $scope): array continue; } - $errors[] = RuleErrorBuilder::message(sprintf('Interface %s requires implementing class to extend %s, but %s does not.', $interface->getDisplayName(), $type->describe(VerbosityLevel::typeOnly()), $classReflection->getDisplayName())) + $errors[] = RuleErrorBuilder::message( + sprintf( + 'Interface %s requires implementing class to extend %s, but %s does not.', + $interface->getDisplayName(), + $type->describe(VerbosityLevel::typeOnly()), + $classReflection->getDisplayName(), + ), + ) ->identifier('class.missingExtends') ->build(); } @@ -61,7 +68,14 @@ public function processNode(Node $node, Scope $scope): array continue; } - $errors[] = RuleErrorBuilder::message(sprintf('Trait %s requires using class to extend %s, but %s does not.', $trait->getDisplayName(), $type->describe(VerbosityLevel::typeOnly()), $classReflection->getDisplayName())) + $errors[] = RuleErrorBuilder::message( + sprintf( + 'Trait %s requires using class to extend %s, but %s does not.', + $trait->getDisplayName(), + $type->describe(VerbosityLevel::typeOnly()), + $classReflection->getDisplayName(), + ), + ) ->identifier('class.missingExtends') ->build(); } diff --git a/src/Rules/Classes/RequireImplementsRule.php b/src/Rules/Classes/RequireImplementsRule.php index ebb19173c5d..32c9361d65a 100644 --- a/src/Rules/Classes/RequireImplementsRule.php +++ b/src/Rules/Classes/RequireImplementsRule.php @@ -39,7 +39,14 @@ public function processNode(Node $node, Scope $scope): array continue; } - $errors[] = RuleErrorBuilder::message(sprintf('Trait %s requires using class to implement %s, but %s does not.', $trait->getDisplayName(), $type->describe(VerbosityLevel::typeOnly()), $classReflection->getDisplayName())) + $errors[] = RuleErrorBuilder::message( + sprintf( + 'Trait %s requires using class to implement %s, but %s does not.', + $trait->getDisplayName(), + $type->describe(VerbosityLevel::typeOnly()), + $classReflection->getDisplayName(), + ), + ) ->identifier('class.missingImplements') ->build(); } diff --git a/src/Rules/Classes/UnusedConstructorParametersRule.php b/src/Rules/Classes/UnusedConstructorParametersRule.php index fffa448c873..2850e2bafeb 100644 --- a/src/Rules/Classes/UnusedConstructorParametersRule.php +++ b/src/Rules/Classes/UnusedConstructorParametersRule.php @@ -25,13 +25,8 @@ class UnusedConstructorParametersRule implements Rule { - /** - * @var UnusedFunctionParametersCheck - */ - private $check; - public function __construct(UnusedFunctionParametersCheck $check) + public function __construct(private UnusedFunctionParametersCheck $check) { - $this->check = $check; } public function getNodeType(): string @@ -51,19 +46,26 @@ public function processNode(Node $node, Scope $scope): array return []; } - $message = sprintf('Constructor of class %s has an unused parameter $%%s.', SprintfHelper::escapeFormatString($node->getClassReflection()->getDisplayName())); + $message = sprintf( + 'Constructor of class %s has an unused parameter $%%s.', + SprintfHelper::escapeFormatString($node->getClassReflection()->getDisplayName()), + ); if ($node->getClassReflection()->isAnonymous()) { $message = 'Constructor of an anonymous class has an unused parameter $%s.'; } - return $this->check->getUnusedParameters($scope, array_map(static function (Param $parameter): string { + return $this->check->getUnusedParameters( + $scope, + array_map(static function (Param $parameter): string { if (!$parameter->var instanceof Variable || !is_string($parameter->var->name)) { throw new ShouldNotHappenException(); } return $parameter->var->name; - }, array_values(array_filter($originalNode->params, static function (Param $parameter) : bool { - return $parameter->flags === 0; - }))), $originalNode->stmts, $message, 'constructor.unusedParameter'); + }, array_values(array_filter($originalNode->params, static fn (Param $parameter): bool => $parameter->flags === 0))), + $originalNode->stmts, + $message, + 'constructor.unusedParameter', + ); } } diff --git a/src/Rules/Comparison/BooleanAndConstantConditionRule.php b/src/Rules/Comparison/BooleanAndConstantConditionRule.php index 27b15d8ee89..37024cf299d 100644 --- a/src/Rules/Comparison/BooleanAndConstantConditionRule.php +++ b/src/Rules/Comparison/BooleanAndConstantConditionRule.php @@ -18,35 +18,24 @@ class BooleanAndConstantConditionRule implements Rule { - /** - * @var ConstantConditionRuleHelper - */ - private $helper; - /** - * @var bool - */ - private $treatPhpDocTypesAsCertain; - /** - * @var bool - */ - private $bleedingEdge; - /** - * @var bool - */ - private $reportAlwaysTrueInLastCondition; - public function __construct(ConstantConditionRuleHelper $helper, bool $treatPhpDocTypesAsCertain, bool $bleedingEdge, bool $reportAlwaysTrueInLastCondition) + public function __construct( + private ConstantConditionRuleHelper $helper, + private bool $treatPhpDocTypesAsCertain, + private bool $bleedingEdge, + private bool $reportAlwaysTrueInLastCondition, + ) { - $this->helper = $helper; - $this->treatPhpDocTypesAsCertain = $treatPhpDocTypesAsCertain; - $this->bleedingEdge = $bleedingEdge; - $this->reportAlwaysTrueInLastCondition = $reportAlwaysTrueInLastCondition; } + public function getNodeType(): string { return BooleanAndNode::class; } - public function processNode(Node $node, Scope $scope) : array + public function processNode( + Node $node, + Scope $scope, + ): array { $errors = []; $originalNode = $node->getOriginalNode(); @@ -70,7 +59,11 @@ public function processNode(Node $node, Scope $scope) : array $isLast = $node->getAttribute(LastConditionVisitor::ATTRIBUTE_NAME); if (!$leftType->getValue() || $isLast !== true || $this->reportAlwaysTrueInLastCondition) { - $errorBuilder = $addTipLeft(RuleErrorBuilder::message(sprintf('Left side of %s is always %s.', $nodeText, $leftType->getValue() ? 'true' : 'false'))) + $errorBuilder = $addTipLeft(RuleErrorBuilder::message(sprintf( + 'Left side of %s is always %s.', + $nodeText, + $leftType->getValue() ? 'true' : 'false', + ))) ->identifier(sprintf('%s.leftAlways%s', $identifierType, $leftType->getValue() ? 'True' : 'False')) ->line($originalNode->left->getStartLine()); if ($leftType->getValue() && $isLast === false && !$this->reportAlwaysTrueInLastCondition) { @@ -79,15 +72,22 @@ public function processNode(Node $node, Scope $scope) : array $errors[] = $errorBuilder->build(); } } + $rightScope = $node->getRightScope(); - $rightType = $this->helper->getBooleanType($rightScope, $originalNode->right); + $rightType = $this->helper->getBooleanType( + $rightScope, + $originalNode->right, + ); if ($rightType instanceof ConstantBooleanType && !$scope->isInFirstLevelStatement()) { $addTipRight = function (RuleErrorBuilder $ruleErrorBuilder) use ($rightScope, $originalNode, $tipText): RuleErrorBuilder { if (!$this->treatPhpDocTypesAsCertain) { return $ruleErrorBuilder; } - $booleanNativeType = $this->helper->getNativeBooleanType($rightScope, $originalNode->right); + $booleanNativeType = $this->helper->getNativeBooleanType( + $rightScope, + $originalNode->right, + ); if ($booleanNativeType instanceof ConstantBooleanType) { return $ruleErrorBuilder; } @@ -97,7 +97,11 @@ public function processNode(Node $node, Scope $scope) : array $isLast = $node->getAttribute(LastConditionVisitor::ATTRIBUTE_NAME); if (!$rightType->getValue() || $isLast !== true || $this->reportAlwaysTrueInLastCondition) { - $errorBuilder = $addTipRight(RuleErrorBuilder::message(sprintf('Right side of %s is always %s.', $nodeText, $rightType->getValue() ? 'true' : 'false'))) + $errorBuilder = $addTipRight(RuleErrorBuilder::message(sprintf( + 'Right side of %s is always %s.', + $nodeText, + $rightType->getValue() ? 'true' : 'false', + ))) ->identifier(sprintf('%s.rightAlways%s', $identifierType, $rightType->getValue() ? 'True' : 'False')) ->line($originalNode->right->getStartLine()); if ($rightType->getValue() && $isLast === false && !$this->reportAlwaysTrueInLastCondition) { @@ -106,6 +110,7 @@ public function processNode(Node $node, Scope $scope) : array $errors[] = $errorBuilder->build(); } } + if (count($errors) === 0 && !$scope->isInFirstLevelStatement()) { $nodeType = $this->treatPhpDocTypesAsCertain ? $scope->getType($originalNode) : $scope->getNativeType($originalNode); if ($nodeType instanceof ConstantBooleanType) { @@ -124,7 +129,11 @@ public function processNode(Node $node, Scope $scope) : array $isLast = $node->getAttribute(LastConditionVisitor::ATTRIBUTE_NAME); if (!$nodeType->getValue() || $isLast !== true || $this->reportAlwaysTrueInLastCondition) { - $errorBuilder = $addTip(RuleErrorBuilder::message(sprintf('Result of %s is always %s.', $nodeText, $nodeType->getValue() ? 'true' : 'false'))); + $errorBuilder = $addTip(RuleErrorBuilder::message(sprintf( + 'Result of %s is always %s.', + $nodeText, + $nodeType->getValue() ? 'true' : 'false', + ))); if ($nodeType->getValue() && $isLast === false && !$this->reportAlwaysTrueInLastCondition) { $errorBuilder->tip('Remove remaining cases below this one and this error will disappear too.'); } @@ -135,6 +144,7 @@ public function processNode(Node $node, Scope $scope) : array } } } + return $errors; } diff --git a/src/Rules/Comparison/BooleanNotConstantConditionRule.php b/src/Rules/Comparison/BooleanNotConstantConditionRule.php index a4e6659009d..95c993f6934 100644 --- a/src/Rules/Comparison/BooleanNotConstantConditionRule.php +++ b/src/Rules/Comparison/BooleanNotConstantConditionRule.php @@ -16,30 +16,23 @@ class BooleanNotConstantConditionRule implements Rule { - /** - * @var ConstantConditionRuleHelper - */ - private $helper; - /** - * @var bool - */ - private $treatPhpDocTypesAsCertain; - /** - * @var bool - */ - private $reportAlwaysTrueInLastCondition; - public function __construct(ConstantConditionRuleHelper $helper, bool $treatPhpDocTypesAsCertain, bool $reportAlwaysTrueInLastCondition) + public function __construct( + private ConstantConditionRuleHelper $helper, + private bool $treatPhpDocTypesAsCertain, + private bool $reportAlwaysTrueInLastCondition, + ) { - $this->helper = $helper; - $this->treatPhpDocTypesAsCertain = $treatPhpDocTypesAsCertain; - $this->reportAlwaysTrueInLastCondition = $reportAlwaysTrueInLastCondition; } + public function getNodeType(): string { return Node\Expr\BooleanNot::class; } - public function processNode(Node $node, Scope $scope) : array + public function processNode( + Node $node, + Scope $scope, + ): array { $exprType = $this->helper->getBooleanType($scope, $node->expr); if ($exprType instanceof ConstantBooleanType) { @@ -58,7 +51,10 @@ public function processNode(Node $node, Scope $scope) : array $isLast = $node->getAttribute(LastConditionVisitor::ATTRIBUTE_NAME); if ($exprType->getValue() || $isLast !== true || $this->reportAlwaysTrueInLastCondition) { - $errorBuilder = $addTip(RuleErrorBuilder::message(sprintf('Negated boolean expression is always %s.', $exprType->getValue() ? 'false' : 'true')))->line($node->expr->getStartLine()); + $errorBuilder = $addTip(RuleErrorBuilder::message(sprintf( + 'Negated boolean expression is always %s.', + $exprType->getValue() ? 'false' : 'true', + )))->line($node->expr->getStartLine()); if (!$exprType->getValue() && $isLast === false && !$this->reportAlwaysTrueInLastCondition) { $errorBuilder->tip('Remove remaining cases below this one and this error will disappear too.'); } @@ -70,6 +66,7 @@ public function processNode(Node $node, Scope $scope) : array ]; } } + return []; } diff --git a/src/Rules/Comparison/BooleanOrConstantConditionRule.php b/src/Rules/Comparison/BooleanOrConstantConditionRule.php index 8f71d60c0ac..bcc25056c41 100644 --- a/src/Rules/Comparison/BooleanOrConstantConditionRule.php +++ b/src/Rules/Comparison/BooleanOrConstantConditionRule.php @@ -18,35 +18,24 @@ class BooleanOrConstantConditionRule implements Rule { - /** - * @var ConstantConditionRuleHelper - */ - private $helper; - /** - * @var bool - */ - private $treatPhpDocTypesAsCertain; - /** - * @var bool - */ - private $bleedingEdge; - /** - * @var bool - */ - private $reportAlwaysTrueInLastCondition; - public function __construct(ConstantConditionRuleHelper $helper, bool $treatPhpDocTypesAsCertain, bool $bleedingEdge, bool $reportAlwaysTrueInLastCondition) + public function __construct( + private ConstantConditionRuleHelper $helper, + private bool $treatPhpDocTypesAsCertain, + private bool $bleedingEdge, + private bool $reportAlwaysTrueInLastCondition, + ) { - $this->helper = $helper; - $this->treatPhpDocTypesAsCertain = $treatPhpDocTypesAsCertain; - $this->bleedingEdge = $bleedingEdge; - $this->reportAlwaysTrueInLastCondition = $reportAlwaysTrueInLastCondition; } + public function getNodeType(): string { return BooleanOrNode::class; } - public function processNode(Node $node, Scope $scope) : array + public function processNode( + Node $node, + Scope $scope, + ): array { $originalNode = $node->getOriginalNode(); $nodeText = $this->bleedingEdge ? $originalNode->getOperatorSigil() : '||'; @@ -70,7 +59,11 @@ public function processNode(Node $node, Scope $scope) : array $isLast = $node->getAttribute(LastConditionVisitor::ATTRIBUTE_NAME); if (!$leftType->getValue() || $isLast !== true || $this->reportAlwaysTrueInLastCondition) { - $errorBuilder = $addTipLeft(RuleErrorBuilder::message(sprintf('Left side of %s is always %s.', $nodeText, $leftType->getValue() ? 'true' : 'false'))) + $errorBuilder = $addTipLeft(RuleErrorBuilder::message(sprintf( + 'Left side of %s is always %s.', + $nodeText, + $leftType->getValue() ? 'true' : 'false', + ))) ->identifier(sprintf('%s.leftAlways%s', $identifierType, $leftType->getValue() ? 'True' : 'False')) ->line($originalNode->left->getStartLine()); if ($leftType->getValue() && $isLast === false && !$this->reportAlwaysTrueInLastCondition) { @@ -79,15 +72,22 @@ public function processNode(Node $node, Scope $scope) : array $messages[] = $errorBuilder->build(); } } + $rightScope = $node->getRightScope(); - $rightType = $this->helper->getBooleanType($rightScope, $originalNode->right); + $rightType = $this->helper->getBooleanType( + $rightScope, + $originalNode->right, + ); if ($rightType instanceof ConstantBooleanType && !$scope->isInFirstLevelStatement()) { $addTipRight = function (RuleErrorBuilder $ruleErrorBuilder) use ($rightScope, $originalNode, $tipText): RuleErrorBuilder { if (!$this->treatPhpDocTypesAsCertain) { return $ruleErrorBuilder; } - $booleanNativeType = $this->helper->getNativeBooleanType($rightScope, $originalNode->right); + $booleanNativeType = $this->helper->getNativeBooleanType( + $rightScope, + $originalNode->right, + ); if ($booleanNativeType instanceof ConstantBooleanType) { return $ruleErrorBuilder; } @@ -97,7 +97,11 @@ public function processNode(Node $node, Scope $scope) : array $isLast = $node->getAttribute(LastConditionVisitor::ATTRIBUTE_NAME); if (!$rightType->getValue() || $isLast !== true || $this->reportAlwaysTrueInLastCondition) { - $errorBuilder = $addTipRight(RuleErrorBuilder::message(sprintf('Right side of %s is always %s.', $nodeText, $rightType->getValue() ? 'true' : 'false'))) + $errorBuilder = $addTipRight(RuleErrorBuilder::message(sprintf( + 'Right side of %s is always %s.', + $nodeText, + $rightType->getValue() ? 'true' : 'false', + ))) ->identifier(sprintf('%s.rightAlways%s', $identifierType, $rightType->getValue() ? 'True' : 'False')) ->line($originalNode->right->getStartLine()); if ($rightType->getValue() && $isLast === false && !$this->reportAlwaysTrueInLastCondition) { @@ -106,6 +110,7 @@ public function processNode(Node $node, Scope $scope) : array $messages[] = $errorBuilder->build(); } } + if (count($messages) === 0 && !$scope->isInFirstLevelStatement()) { $nodeType = $this->treatPhpDocTypesAsCertain ? $scope->getType($originalNode) : $scope->getNativeType($originalNode); if ($nodeType instanceof ConstantBooleanType) { @@ -124,7 +129,11 @@ public function processNode(Node $node, Scope $scope) : array $isLast = $node->getAttribute(LastConditionVisitor::ATTRIBUTE_NAME); if (!$nodeType->getValue() || $isLast !== true || $this->reportAlwaysTrueInLastCondition) { - $errorBuilder = $addTip(RuleErrorBuilder::message(sprintf('Result of %s is always %s.', $nodeText, $nodeType->getValue() ? 'true' : 'false'))); + $errorBuilder = $addTip(RuleErrorBuilder::message(sprintf( + 'Result of %s is always %s.', + $nodeText, + $nodeType->getValue() ? 'true' : 'false', + ))); if ($nodeType->getValue() && $isLast === false && !$this->reportAlwaysTrueInLastCondition) { $errorBuilder->tip('Remove remaining cases below this one and this error will disappear too.'); } @@ -135,6 +144,7 @@ public function processNode(Node $node, Scope $scope) : array } } } + return $messages; } diff --git a/src/Rules/Comparison/ConstantConditionRuleHelper.php b/src/Rules/Comparison/ConstantConditionRuleHelper.php index aef8f839823..60da2b56ff0 100644 --- a/src/Rules/Comparison/ConstantConditionRuleHelper.php +++ b/src/Rules/Comparison/ConstantConditionRuleHelper.php @@ -11,24 +11,14 @@ class ConstantConditionRuleHelper { - /** - * @var ImpossibleCheckTypeHelper - */ - private $impossibleCheckTypeHelper; - /** - * @var bool - */ - private $treatPhpDocTypesAsCertain; - /** - * @var bool - */ - private $looseComparisonRuleEnabled; - public function __construct(ImpossibleCheckTypeHelper $impossibleCheckTypeHelper, bool $treatPhpDocTypesAsCertain, bool $looseComparisonRuleEnabled) + public function __construct( + private ImpossibleCheckTypeHelper $impossibleCheckTypeHelper, + private bool $treatPhpDocTypesAsCertain, + private bool $looseComparisonRuleEnabled, + ) { - $this->impossibleCheckTypeHelper = $impossibleCheckTypeHelper; - $this->treatPhpDocTypesAsCertain = $treatPhpDocTypesAsCertain; - $this->looseComparisonRuleEnabled = $looseComparisonRuleEnabled; } + public function shouldReportAlwaysTrueByDefault(Expr $expr): bool { return $expr instanceof Expr\BooleanNot diff --git a/src/Rules/Comparison/ConstantLooseComparisonRule.php b/src/Rules/Comparison/ConstantLooseComparisonRule.php index d299c94de35..0b84c5fc85e 100644 --- a/src/Rules/Comparison/ConstantLooseComparisonRule.php +++ b/src/Rules/Comparison/ConstantLooseComparisonRule.php @@ -17,24 +17,14 @@ class ConstantLooseComparisonRule implements Rule { - /** - * @var bool - */ - private $checkAlwaysTrueLooseComparison; - /** - * @var bool - */ - private $treatPhpDocTypesAsCertain; - /** - * @var bool - */ - private $reportAlwaysTrueInLastCondition; - public function __construct(bool $checkAlwaysTrueLooseComparison, bool $treatPhpDocTypesAsCertain, bool $reportAlwaysTrueInLastCondition) + public function __construct( + private bool $checkAlwaysTrueLooseComparison, + private bool $treatPhpDocTypesAsCertain, + private bool $reportAlwaysTrueInLastCondition, + ) { - $this->checkAlwaysTrueLooseComparison = $checkAlwaysTrueLooseComparison; - $this->treatPhpDocTypesAsCertain = $treatPhpDocTypesAsCertain; - $this->reportAlwaysTrueInLastCondition = $reportAlwaysTrueInLastCondition; } + public function getNodeType(): string { return Node\Expr\BinaryOp::class; @@ -66,7 +56,12 @@ public function processNode(Node $node, Scope $scope): array if (!$nodeType->getValue()) { return [ - $addTip(RuleErrorBuilder::message(sprintf('Loose comparison using %s between %s and %s will always evaluate to false.', $node->getOperatorSigil(), $scope->getType($node->left)->describe(VerbosityLevel::value()), $scope->getType($node->right)->describe(VerbosityLevel::value()))))->identifier(sprintf('%s.alwaysFalse', $node instanceof Node\Expr\BinaryOp\Equal ? 'equal' : 'notEqual'))->build(), + $addTip(RuleErrorBuilder::message(sprintf( + 'Loose comparison using %s between %s and %s will always evaluate to false.', + $node->getOperatorSigil(), + $scope->getType($node->left)->describe(VerbosityLevel::value()), + $scope->getType($node->right)->describe(VerbosityLevel::value()), + )))->identifier(sprintf('%s.alwaysFalse', $node instanceof Node\Expr\BinaryOp\Equal ? 'equal' : 'notEqual'))->build(), ]; } elseif ($this->checkAlwaysTrueLooseComparison) { $isLast = $node->getAttribute(LastConditionVisitor::ATTRIBUTE_NAME); @@ -74,7 +69,12 @@ public function processNode(Node $node, Scope $scope): array return []; } - $errorBuilder = $addTip(RuleErrorBuilder::message(sprintf('Loose comparison using %s between %s and %s will always evaluate to true.', $node->getOperatorSigil(), $scope->getType($node->left)->describe(VerbosityLevel::value()), $scope->getType($node->right)->describe(VerbosityLevel::value())))); + $errorBuilder = $addTip(RuleErrorBuilder::message(sprintf( + 'Loose comparison using %s between %s and %s will always evaluate to true.', + $node->getOperatorSigil(), + $scope->getType($node->left)->describe(VerbosityLevel::value()), + $scope->getType($node->right)->describe(VerbosityLevel::value()), + ))); if ($isLast === false && !$this->reportAlwaysTrueInLastCondition) { $errorBuilder->tip('Remove remaining cases below this one and this error will disappear too.'); } diff --git a/src/Rules/Comparison/DoWhileLoopConstantConditionRule.php b/src/Rules/Comparison/DoWhileLoopConstantConditionRule.php index 09306084f63..967011118ff 100644 --- a/src/Rules/Comparison/DoWhileLoopConstantConditionRule.php +++ b/src/Rules/Comparison/DoWhileLoopConstantConditionRule.php @@ -19,19 +19,13 @@ class DoWhileLoopConstantConditionRule implements Rule { - /** - * @var ConstantConditionRuleHelper - */ - private $helper; - /** - * @var bool - */ - private $treatPhpDocTypesAsCertain; - public function __construct(ConstantConditionRuleHelper $helper, bool $treatPhpDocTypesAsCertain) + public function __construct( + private ConstantConditionRuleHelper $helper, + private bool $treatPhpDocTypesAsCertain, + ) { - $this->helper = $helper; - $this->treatPhpDocTypesAsCertain = $treatPhpDocTypesAsCertain; } + public function getNodeType(): string { return DoWhileLoopConditionNode::class; @@ -81,7 +75,10 @@ public function processNode(Node $node, Scope $scope): array }; return [ - $addTip(RuleErrorBuilder::message(sprintf('Do-while loop condition is always %s.', $exprType->getValue() ? 'true' : 'false'))) + $addTip(RuleErrorBuilder::message(sprintf( + 'Do-while loop condition is always %s.', + $exprType->getValue() ? 'true' : 'false', + ))) ->line($node->getCond()->getStartLine()) ->identifier(sprintf('doWhile.always%s', $exprType->getValue() ? 'True' : 'False')) ->build(), diff --git a/src/Rules/Comparison/ElseIfConstantConditionRule.php b/src/Rules/Comparison/ElseIfConstantConditionRule.php index 8fc4ffe4433..11af13a5aa9 100644 --- a/src/Rules/Comparison/ElseIfConstantConditionRule.php +++ b/src/Rules/Comparison/ElseIfConstantConditionRule.php @@ -16,30 +16,23 @@ class ElseIfConstantConditionRule implements Rule { - /** - * @var ConstantConditionRuleHelper - */ - private $helper; - /** - * @var bool - */ - private $treatPhpDocTypesAsCertain; - /** - * @var bool - */ - private $reportAlwaysTrueInLastCondition; - public function __construct(ConstantConditionRuleHelper $helper, bool $treatPhpDocTypesAsCertain, bool $reportAlwaysTrueInLastCondition) + public function __construct( + private ConstantConditionRuleHelper $helper, + private bool $treatPhpDocTypesAsCertain, + private bool $reportAlwaysTrueInLastCondition, + ) { - $this->helper = $helper; - $this->treatPhpDocTypesAsCertain = $treatPhpDocTypesAsCertain; - $this->reportAlwaysTrueInLastCondition = $reportAlwaysTrueInLastCondition; } + public function getNodeType(): string { return Node\Stmt\ElseIf_::class; } - public function processNode(Node $node, Scope $scope) : array + public function processNode( + Node $node, + Scope $scope, + ): array { $exprType = $this->helper->getBooleanType($scope, $node->cond); if ($exprType instanceof ConstantBooleanType) { @@ -58,7 +51,10 @@ public function processNode(Node $node, Scope $scope) : array $isLast = $node->cond->getAttribute(LastConditionVisitor::ATTRIBUTE_NAME); if (!$exprType->getValue() || $isLast !== true || $this->reportAlwaysTrueInLastCondition) { - $errorBuilder = $addTip(RuleErrorBuilder::message(sprintf('Elseif condition is always %s.', $exprType->getValue() ? 'true' : 'false')))->line($node->cond->getStartLine()); + $errorBuilder = $addTip(RuleErrorBuilder::message(sprintf( + 'Elseif condition is always %s.', + $exprType->getValue() ? 'true' : 'false', + )))->line($node->cond->getStartLine()); if ($exprType->getValue() && $isLast === false && !$this->reportAlwaysTrueInLastCondition) { $errorBuilder->tip('Remove remaining cases below this one and this error will disappear too.'); @@ -69,6 +65,7 @@ public function processNode(Node $node, Scope $scope) : array return [$errorBuilder->build()]; } } + return []; } diff --git a/src/Rules/Comparison/IfConstantConditionRule.php b/src/Rules/Comparison/IfConstantConditionRule.php index cee5b6338b6..23cba9a8396 100644 --- a/src/Rules/Comparison/IfConstantConditionRule.php +++ b/src/Rules/Comparison/IfConstantConditionRule.php @@ -15,25 +15,22 @@ class IfConstantConditionRule implements Rule { - /** - * @var ConstantConditionRuleHelper - */ - private $helper; - /** - * @var bool - */ - private $treatPhpDocTypesAsCertain; - public function __construct(ConstantConditionRuleHelper $helper, bool $treatPhpDocTypesAsCertain) + public function __construct( + private ConstantConditionRuleHelper $helper, + private bool $treatPhpDocTypesAsCertain, + ) { - $this->helper = $helper; - $this->treatPhpDocTypesAsCertain = $treatPhpDocTypesAsCertain; } + public function getNodeType(): string { return Node\Stmt\If_::class; } - public function processNode(Node $node, Scope $scope) : array + public function processNode( + Node $node, + Scope $scope, + ): array { $exprType = $this->helper->getBooleanType($scope, $node->cond); if ($exprType instanceof ConstantBooleanType) { @@ -51,11 +48,15 @@ public function processNode(Node $node, Scope $scope) : array }; return [ - $addTip(RuleErrorBuilder::message(sprintf('If condition is always %s.', $exprType->getValue() ? 'true' : 'false'))) + $addTip(RuleErrorBuilder::message(sprintf( + 'If condition is always %s.', + $exprType->getValue() ? 'true' : 'false', + ))) ->identifier(sprintf('if.always%s', $exprType->getValue() ? 'True' : 'False')) ->line($node->cond->getStartLine())->build(), ]; } + return []; } diff --git a/src/Rules/Comparison/ImpossibleCheckTypeFunctionCallRule.php b/src/Rules/Comparison/ImpossibleCheckTypeFunctionCallRule.php index a51ad8735d3..914f78640ee 100644 --- a/src/Rules/Comparison/ImpossibleCheckTypeFunctionCallRule.php +++ b/src/Rules/Comparison/ImpossibleCheckTypeFunctionCallRule.php @@ -16,29 +16,15 @@ class ImpossibleCheckTypeFunctionCallRule implements Rule { - /** - * @var ImpossibleCheckTypeHelper - */ - private $impossibleCheckTypeHelper; - /** - * @var bool - */ - private $checkAlwaysTrueCheckTypeFunctionCall; - /** - * @var bool - */ - private $treatPhpDocTypesAsCertain; - /** - * @var bool - */ - private $reportAlwaysTrueInLastCondition; - public function __construct(ImpossibleCheckTypeHelper $impossibleCheckTypeHelper, bool $checkAlwaysTrueCheckTypeFunctionCall, bool $treatPhpDocTypesAsCertain, bool $reportAlwaysTrueInLastCondition) + public function __construct( + private ImpossibleCheckTypeHelper $impossibleCheckTypeHelper, + private bool $checkAlwaysTrueCheckTypeFunctionCall, + private bool $treatPhpDocTypesAsCertain, + private bool $reportAlwaysTrueInLastCondition, + ) { - $this->impossibleCheckTypeHelper = $impossibleCheckTypeHelper; - $this->checkAlwaysTrueCheckTypeFunctionCall = $checkAlwaysTrueCheckTypeFunctionCall; - $this->treatPhpDocTypesAsCertain = $treatPhpDocTypesAsCertain; - $this->reportAlwaysTrueInLastCondition = $reportAlwaysTrueInLastCondition; } + public function getNodeType(): string { return Node\Expr\FuncCall::class; @@ -74,7 +60,11 @@ public function processNode(Node $node, Scope $scope): array if (!$isAlways) { return [ - $addTip(RuleErrorBuilder::message(sprintf('Call to function %s()%s will always evaluate to false.', $functionName, $this->impossibleCheckTypeHelper->getArgumentsDescription($scope, $node->getArgs()))))->identifier('function.impossibleType')->build(), + $addTip(RuleErrorBuilder::message(sprintf( + 'Call to function %s()%s will always evaluate to false.', + $functionName, + $this->impossibleCheckTypeHelper->getArgumentsDescription($scope, $node->getArgs()), + )))->identifier('function.impossibleType')->build(), ]; } elseif ($this->checkAlwaysTrueCheckTypeFunctionCall) { $isLast = $node->getAttribute(LastConditionVisitor::ATTRIBUTE_NAME); @@ -82,7 +72,11 @@ public function processNode(Node $node, Scope $scope): array return []; } - $errorBuilder = $addTip(RuleErrorBuilder::message(sprintf('Call to function %s()%s will always evaluate to true.', $functionName, $this->impossibleCheckTypeHelper->getArgumentsDescription($scope, $node->getArgs())))); + $errorBuilder = $addTip(RuleErrorBuilder::message(sprintf( + 'Call to function %s()%s will always evaluate to true.', + $functionName, + $this->impossibleCheckTypeHelper->getArgumentsDescription($scope, $node->getArgs()), + ))); if ($isLast === false && !$this->reportAlwaysTrueInLastCondition) { $errorBuilder->tip('Remove remaining cases below this one and this error will disappear too.'); } diff --git a/src/Rules/Comparison/ImpossibleCheckTypeHelper.php b/src/Rules/Comparison/ImpossibleCheckTypeHelper.php index 1c522b11b74..94630723406 100644 --- a/src/Rules/Comparison/ImpossibleCheckTypeHelper.php +++ b/src/Rules/Comparison/ImpossibleCheckTypeHelper.php @@ -41,262 +41,257 @@ class ImpossibleCheckTypeHelper { /** - * @var ReflectionProvider - */ - private $reflectionProvider; - /** - * @var TypeSpecifier - */ - private $typeSpecifier; - /** - * @var string[] - */ - private $universalObjectCratesClasses; - /** - * @var bool - */ - private $treatPhpDocTypesAsCertain; - /** - * @var bool - */ - private $nullContextForVoidReturningFunctions; - /** - * @param string[] $universalObjectCratesClasses - */ - public function __construct(ReflectionProvider $reflectionProvider, TypeSpecifier $typeSpecifier, array $universalObjectCratesClasses, bool $treatPhpDocTypesAsCertain, bool $nullContextForVoidReturningFunctions) - { - $this->reflectionProvider = $reflectionProvider; - $this->typeSpecifier = $typeSpecifier; - $this->universalObjectCratesClasses = $universalObjectCratesClasses; - $this->treatPhpDocTypesAsCertain = $treatPhpDocTypesAsCertain; - $this->nullContextForVoidReturningFunctions = $nullContextForVoidReturningFunctions; + * @param string[] $universalObjectCratesClasses + */ + public function __construct( + private ReflectionProvider $reflectionProvider, + private TypeSpecifier $typeSpecifier, + private array $universalObjectCratesClasses, + private bool $treatPhpDocTypesAsCertain, + private bool $nullContextForVoidReturningFunctions, + ) + { + } + + public function findSpecifiedType( + Scope $scope, + Expr $node, + ): ?bool + { + if ($node instanceof FuncCall) { + if ($node->isFirstClassCallable()) { + return null; + } + $argsCount = count($node->getArgs()); + if ($node->name instanceof Node\Name) { + $functionName = strtolower((string) $node->name); + if ($functionName === 'assert' && $argsCount >= 1) { + $arg = $node->getArgs()[0]->value; + $assertValue = ($this->treatPhpDocTypesAsCertain ? $scope->getType($arg) : $scope->getNativeType($arg))->toBoolean(); + if (!$assertValue instanceof ConstantBooleanType) { + return null; + } + + return $assertValue->getValue(); + } + if (in_array($functionName, [ + 'class_exists', + 'interface_exists', + 'trait_exists', + 'enum_exists', + ], true)) { + return null; + } + if (in_array($functionName, ['count', 'sizeof'], true)) { + return null; + } elseif ($functionName === 'defined') { + return null; + } elseif ($functionName === 'array_search') { + return null; + } elseif ($functionName === 'in_array' && $argsCount >= 3) { + $haystackArg = $node->getArgs()[1]->value; + $haystackType = ($this->treatPhpDocTypesAsCertain ? $scope->getType($haystackArg) : $scope->getNativeType($haystackArg)); + if ($haystackType instanceof MixedType) { + return null; + } + + if (!$haystackType->isArray()->yes()) { + return null; + } + + $needleArg = $node->getArgs()[0]->value; + $needleType = ($this->treatPhpDocTypesAsCertain ? $scope->getType($needleArg) : $scope->getNativeType($needleArg)); + $valueType = $haystackType->getIterableValueType(); + $constantNeedleTypesCount = count($needleType->getFiniteTypes()); + $constantHaystackTypesCount = count($valueType->getFiniteTypes()); + $isNeedleSupertype = $needleType->isSuperTypeOf($valueType); + if ($haystackType->isConstantArray()->no()) { + if ($haystackType->isIterableAtLeastOnce()->yes()) { + // In this case the generic implementation via typeSpecifier fails, because the argument types cannot be narrowed down. + if ($constantNeedleTypesCount === 1 && $constantHaystackTypesCount === 1) { + if ($isNeedleSupertype->yes()) { + return true; + } + if ($isNeedleSupertype->no()) { + return false; + } + } + + return null; + } + } + + if (!$haystackType instanceof ConstantArrayType || count($haystackType->getValueTypes()) > 0) { + $haystackArrayTypes = $haystackType->getArrays(); + if (count($haystackArrayTypes) === 1 && $haystackArrayTypes[0]->getIterableValueType() instanceof NeverType) { + return null; + } + + if ($isNeedleSupertype->maybe() || $isNeedleSupertype->yes()) { + foreach ($haystackArrayTypes as $haystackArrayType) { + if ($haystackArrayType instanceof ConstantArrayType) { + foreach ($haystackArrayType->getValueTypes() as $i => $haystackArrayValueType) { + if ($haystackArrayType->isOptionalKey($i)) { + continue; + } + + foreach ($haystackArrayValueType->getConstantScalarTypes() as $constantScalarType) { + if ($constantScalarType->isSuperTypeOf($needleType)->yes()) { + continue 3; + } + } + } + } else { + foreach ($haystackArrayType->getIterableValueType()->getConstantScalarTypes() as $constantScalarType) { + if ($constantScalarType->isSuperTypeOf($needleType)->yes()) { + continue 2; + } + } + } + + return null; + } + } + + if ($isNeedleSupertype->yes()) { + $hasConstantNeedleTypes = $constantNeedleTypesCount > 0; + $hasConstantHaystackTypes = $constantHaystackTypesCount > 0; + if ( + (!$hasConstantNeedleTypes && !$hasConstantHaystackTypes) + || $hasConstantNeedleTypes !== $hasConstantHaystackTypes + ) { + return null; + } + } + } + } elseif ($functionName === 'method_exists' && $argsCount >= 2) { + $objectArg = $node->getArgs()[0]->value; + $objectType = ($this->treatPhpDocTypesAsCertain ? $scope->getType($objectArg) : $scope->getNativeType($objectArg)); + + if ($objectType instanceof ConstantStringType + && !$this->reflectionProvider->hasClass($objectType->getValue()) + ) { + return false; + } + + $methodArg = $node->getArgs()[1]->value; + $methodType = ($this->treatPhpDocTypesAsCertain ? $scope->getType($methodArg) : $scope->getNativeType($methodArg)); + + if ($methodType instanceof ConstantStringType) { + if ($objectType instanceof ConstantStringType) { + $objectType = new ObjectType($objectType->getValue()); + } + + if ($objectType->getObjectClassNames() !== []) { + if ($objectType->hasMethod($methodType->getValue())->yes()) { + return true; + } + + if ($objectType->hasMethod($methodType->getValue())->no()) { + return false; + } + } + + $genericType = TypeTraverser::map($objectType, static function (Type $type, callable $traverse): Type { + if ($type instanceof UnionType || $type instanceof IntersectionType) { + return $traverse($type); + } + if ($type instanceof GenericClassStringType) { + return $type->getGenericType(); + } + return new MixedType(); + }); + + if ($genericType instanceof TypeWithClassName) { + if ($genericType->hasMethod($methodType->getValue())->yes()) { + return true; + } + + $classReflection = $genericType->getClassReflection(); + if ( + $classReflection !== null + && $classReflection->isFinal() + && $genericType->hasMethod($methodType->getValue())->no()) { + return false; + } + } + } + } + } } - public function findSpecifiedType(Scope $scope, Expr $node) : ?bool - { - if ($node instanceof FuncCall) { - if ($node->isFirstClassCallable()) { - return null; - } - $argsCount = count($node->getArgs()); - if ($node->name instanceof Node\Name) { - $functionName = strtolower((string) $node->name); - if ($functionName === 'assert' && $argsCount >= 1) { - $arg = $node->getArgs()[0]->value; - $assertValue = ($this->treatPhpDocTypesAsCertain ? $scope->getType($arg) : $scope->getNativeType($arg))->toBoolean(); - if (!$assertValue instanceof ConstantBooleanType) { - return null; - } - - return $assertValue->getValue(); - } - if (in_array($functionName, [ - 'class_exists', - 'interface_exists', - 'trait_exists', - 'enum_exists', - ], true)) { - return null; - } - if (in_array($functionName, ['count', 'sizeof'], true)) { - return null; - } elseif ($functionName === 'defined') { - return null; - } elseif ($functionName === 'array_search') { - return null; - } elseif ($functionName === 'in_array' && $argsCount >= 3) { - $haystackArg = $node->getArgs()[1]->value; - $haystackType = ($this->treatPhpDocTypesAsCertain ? $scope->getType($haystackArg) : $scope->getNativeType($haystackArg)); - if ($haystackType instanceof MixedType) { - return null; - } - - if (!$haystackType->isArray()->yes()) { - return null; - } - - $needleArg = $node->getArgs()[0]->value; - $needleType = ($this->treatPhpDocTypesAsCertain ? $scope->getType($needleArg) : $scope->getNativeType($needleArg)); - $valueType = $haystackType->getIterableValueType(); - $constantNeedleTypesCount = count($needleType->getFiniteTypes()); - $constantHaystackTypesCount = count($valueType->getFiniteTypes()); - $isNeedleSupertype = $needleType->isSuperTypeOf($valueType); - if ($haystackType->isConstantArray()->no()) { - if ($haystackType->isIterableAtLeastOnce()->yes()) { - // In this case the generic implementation via typeSpecifier fails, because the argument types cannot be narrowed down. - if ($constantNeedleTypesCount === 1 && $constantHaystackTypesCount === 1) { - if ($isNeedleSupertype->yes()) { - return true; - } - if ($isNeedleSupertype->no()) { - return false; - } - } - - return null; - } - } - - if (!$haystackType instanceof ConstantArrayType || count($haystackType->getValueTypes()) > 0) { - $haystackArrayTypes = $haystackType->getArrays(); - if (count($haystackArrayTypes) === 1 && $haystackArrayTypes[0]->getIterableValueType() instanceof NeverType) { - return null; - } - - if ($isNeedleSupertype->maybe() || $isNeedleSupertype->yes()) { - foreach ($haystackArrayTypes as $haystackArrayType) { - if ($haystackArrayType instanceof ConstantArrayType) { - foreach ($haystackArrayType->getValueTypes() as $i => $haystackArrayValueType) { - if ($haystackArrayType->isOptionalKey($i)) { - continue; - } - - foreach ($haystackArrayValueType->getConstantScalarTypes() as $constantScalarType) { - if ($constantScalarType->isSuperTypeOf($needleType)->yes()) { - continue 3; - } - } - } - } else { - foreach ($haystackArrayType->getIterableValueType()->getConstantScalarTypes() as $constantScalarType) { - if ($constantScalarType->isSuperTypeOf($needleType)->yes()) { - continue 2; - } - } - } - - return null; - } - } - - if ($isNeedleSupertype->yes()) { - $hasConstantNeedleTypes = $constantNeedleTypesCount > 0; - $hasConstantHaystackTypes = $constantHaystackTypesCount > 0; - if ( - (!$hasConstantNeedleTypes && !$hasConstantHaystackTypes) - || $hasConstantNeedleTypes !== $hasConstantHaystackTypes - ) { - return null; - } - } - } - } elseif ($functionName === 'method_exists' && $argsCount >= 2) { - $objectArg = $node->getArgs()[0]->value; - $objectType = ($this->treatPhpDocTypesAsCertain ? $scope->getType($objectArg) : $scope->getNativeType($objectArg)); - - if ($objectType instanceof ConstantStringType - && !$this->reflectionProvider->hasClass($objectType->getValue()) - ) { - return false; - } - - $methodArg = $node->getArgs()[1]->value; - $methodType = ($this->treatPhpDocTypesAsCertain ? $scope->getType($methodArg) : $scope->getNativeType($methodArg)); - - if ($methodType instanceof ConstantStringType) { - if ($objectType instanceof ConstantStringType) { - $objectType = new ObjectType($objectType->getValue()); - } - - if ($objectType->getObjectClassNames() !== []) { - if ($objectType->hasMethod($methodType->getValue())->yes()) { - return true; - } - - if ($objectType->hasMethod($methodType->getValue())->no()) { - return false; - } - } - - $genericType = TypeTraverser::map($objectType, static function (Type $type, callable $traverse): Type { - if ($type instanceof UnionType || $type instanceof IntersectionType) { - return $traverse($type); - } - if ($type instanceof GenericClassStringType) { - return $type->getGenericType(); - } - return new MixedType(); - }); - - if ($genericType instanceof TypeWithClassName) { - if ($genericType->hasMethod($methodType->getValue())->yes()) { - return true; - } - - $classReflection = $genericType->getClassReflection(); - if ( - $classReflection !== null - && $classReflection->isFinal() - && $genericType->hasMethod($methodType->getValue())->no()) { - return false; - } - } - } - } - } - } - $typeSpecifierScope = $this->treatPhpDocTypesAsCertain ? $scope : $scope->doNotTreatPhpDocTypesAsCertain(); - $specifiedTypes = $this->typeSpecifier->specifyTypesInCondition($typeSpecifierScope, $node, $this->determineContext($typeSpecifierScope, $node)); - // don't validate types on overwrite - if ($specifiedTypes->shouldOverwrite()) { - return null; - } - $sureTypes = $specifiedTypes->getSureTypes(); - $sureNotTypes = $specifiedTypes->getSureNotTypes(); - $rootExpr = $specifiedTypes->getRootExpr(); - if ($rootExpr !== null) { - if (self::isSpecified($typeSpecifierScope, $node, $rootExpr)) { - return null; - } - - $rootExprType = ($this->treatPhpDocTypesAsCertain ? $scope->getType($rootExpr) : $scope->getNativeType($rootExpr)); - if ($rootExprType instanceof ConstantBooleanType) { - return $rootExprType->getValue(); - } - - return null; - } - $results = []; - foreach ($sureTypes as $sureType) { - if (self::isSpecified($typeSpecifierScope, $node, $sureType[0])) { - $results[] = TrinaryLogic::createMaybe(); - continue; - } - - if ($this->treatPhpDocTypesAsCertain) { - $argumentType = $scope->getType($sureType[0]); - } else { - $argumentType = $scope->getNativeType($sureType[0]); - } - - /** @var Type $resultType */ - $resultType = $sureType[1]; - - $results[] = $resultType->isSuperTypeOf($argumentType); - } - foreach ($sureNotTypes as $sureNotType) { - if (self::isSpecified($typeSpecifierScope, $node, $sureNotType[0])) { - $results[] = TrinaryLogic::createMaybe(); - continue; - } - - if ($this->treatPhpDocTypesAsCertain) { - $argumentType = $scope->getType($sureNotType[0]); - } else { - $argumentType = $scope->getNativeType($sureNotType[0]); - } - - /** @var Type $resultType */ - $resultType = $sureNotType[1]; - - $results[] = $resultType->isSuperTypeOf($argumentType)->negate(); - } - if (count($results) === 0) { - return null; - } - $result = TrinaryLogic::createYes()->and(...$results); - return $result->maybe() ? null : $result->yes(); + + $typeSpecifierScope = $this->treatPhpDocTypesAsCertain ? $scope : $scope->doNotTreatPhpDocTypesAsCertain(); + $specifiedTypes = $this->typeSpecifier->specifyTypesInCondition($typeSpecifierScope, $node, $this->determineContext($typeSpecifierScope, $node)); + + // don't validate types on overwrite + if ($specifiedTypes->shouldOverwrite()) { + return null; } - private static function isSpecified(Scope $scope, Expr $node, Expr $expr): bool + + $sureTypes = $specifiedTypes->getSureTypes(); + $sureNotTypes = $specifiedTypes->getSureNotTypes(); + + $rootExpr = $specifiedTypes->getRootExpr(); + if ($rootExpr !== null) { + if (self::isSpecified($typeSpecifierScope, $node, $rootExpr)) { + return null; + } + + $rootExprType = ($this->treatPhpDocTypesAsCertain ? $scope->getType($rootExpr) : $scope->getNativeType($rootExpr)); + if ($rootExprType instanceof ConstantBooleanType) { + return $rootExprType->getValue(); + } + + return null; + } + + $results = []; + + foreach ($sureTypes as $sureType) { + if (self::isSpecified($typeSpecifierScope, $node, $sureType[0])) { + $results[] = TrinaryLogic::createMaybe(); + continue; + } + + if ($this->treatPhpDocTypesAsCertain) { + $argumentType = $scope->getType($sureType[0]); + } else { + $argumentType = $scope->getNativeType($sureType[0]); + } + + /** @var Type $resultType */ + $resultType = $sureType[1]; + + $results[] = $resultType->isSuperTypeOf($argumentType); + } + + foreach ($sureNotTypes as $sureNotType) { + if (self::isSpecified($typeSpecifierScope, $node, $sureNotType[0])) { + $results[] = TrinaryLogic::createMaybe(); + continue; + } + + if ($this->treatPhpDocTypesAsCertain) { + $argumentType = $scope->getType($sureNotType[0]); + } else { + $argumentType = $scope->getNativeType($sureNotType[0]); + } + + /** @var Type $resultType */ + $resultType = $sureNotType[1]; + + $results[] = $resultType->isSuperTypeOf($argumentType)->negate(); + } + + if (count($results) === 0) { + return null; + } + + $result = TrinaryLogic::createYes()->and(...$results); + return $result->maybe() ? null : $result->yes(); + } + + private static function isSpecified(Scope $scope, Expr $node, Expr $expr): bool { if ($expr === $node) { return true; @@ -322,30 +317,45 @@ private static function isSpecified(Scope $scope, Expr $node, Expr $expr): bool } /** - * @param Node\Arg[] $args - */ - public function getArgumentsDescription(Scope $scope, array $args) : string - { - if (count($args) === 0) { - return ''; - } - $descriptions = array_map(function (Arg $arg) use($scope) : string { - return ($this->treatPhpDocTypesAsCertain ? $scope->getType($arg->value) : $scope->getNativeType($arg->value))->describe(VerbosityLevel::value()); - }, $args); - if (count($descriptions) < 3) { - return sprintf(' with %s', implode(' and ', $descriptions)); - } - $lastDescription = array_pop($descriptions); - return sprintf(' with arguments %s and %s', implode(', ', $descriptions), $lastDescription); + * @param Node\Arg[] $args + */ + public function getArgumentsDescription( + Scope $scope, + array $args, + ): string + { + if (count($args) === 0) { + return ''; + } + + $descriptions = array_map(fn (Arg $arg): string => ($this->treatPhpDocTypesAsCertain ? $scope->getType($arg->value) : $scope->getNativeType($arg->value))->describe(VerbosityLevel::value()), $args); + + if (count($descriptions) < 3) { + return sprintf(' with %s', implode(' and ', $descriptions)); } + $lastDescription = array_pop($descriptions); + + return sprintf( + ' with arguments %s and %s', + implode(', ', $descriptions), + $lastDescription, + ); + } + public function doNotTreatPhpDocTypesAsCertain(): self { if (!$this->treatPhpDocTypesAsCertain) { return $this; } - return new self($this->reflectionProvider, $this->typeSpecifier, $this->universalObjectCratesClasses, false, $this->nullContextForVoidReturningFunctions); + return new self( + $this->reflectionProvider, + $this->typeSpecifier, + $this->universalObjectCratesClasses, + false, + $this->nullContextForVoidReturningFunctions, + ); } private function determineContext(Scope $scope, Expr $node): TypeSpecifierContext diff --git a/src/Rules/Comparison/ImpossibleCheckTypeMethodCallRule.php b/src/Rules/Comparison/ImpossibleCheckTypeMethodCallRule.php index 43b9b388f63..f5e6ae4ec5b 100644 --- a/src/Rules/Comparison/ImpossibleCheckTypeMethodCallRule.php +++ b/src/Rules/Comparison/ImpossibleCheckTypeMethodCallRule.php @@ -18,29 +18,15 @@ class ImpossibleCheckTypeMethodCallRule implements Rule { - /** - * @var ImpossibleCheckTypeHelper - */ - private $impossibleCheckTypeHelper; - /** - * @var bool - */ - private $checkAlwaysTrueCheckTypeFunctionCall; - /** - * @var bool - */ - private $treatPhpDocTypesAsCertain; - /** - * @var bool - */ - private $reportAlwaysTrueInLastCondition; - public function __construct(ImpossibleCheckTypeHelper $impossibleCheckTypeHelper, bool $checkAlwaysTrueCheckTypeFunctionCall, bool $treatPhpDocTypesAsCertain, bool $reportAlwaysTrueInLastCondition) + public function __construct( + private ImpossibleCheckTypeHelper $impossibleCheckTypeHelper, + private bool $checkAlwaysTrueCheckTypeFunctionCall, + private bool $treatPhpDocTypesAsCertain, + private bool $reportAlwaysTrueInLastCondition, + ) { - $this->impossibleCheckTypeHelper = $impossibleCheckTypeHelper; - $this->checkAlwaysTrueCheckTypeFunctionCall = $checkAlwaysTrueCheckTypeFunctionCall; - $this->treatPhpDocTypesAsCertain = $treatPhpDocTypesAsCertain; - $this->reportAlwaysTrueInLastCondition = $reportAlwaysTrueInLastCondition; } + public function getNodeType(): string { return Node\Expr\MethodCall::class; @@ -73,7 +59,12 @@ public function processNode(Node $node, Scope $scope): array if (!$isAlways) { $method = $this->getMethod($node->var, $node->name->name, $scope); return [ - $addTip(RuleErrorBuilder::message(sprintf('Call to method %s::%s()%s will always evaluate to false.', $method->getDeclaringClass()->getDisplayName(), $method->getName(), $this->impossibleCheckTypeHelper->getArgumentsDescription($scope, $node->getArgs()))))->identifier('method.impossibleType')->build(), + $addTip(RuleErrorBuilder::message(sprintf( + 'Call to method %s::%s()%s will always evaluate to false.', + $method->getDeclaringClass()->getDisplayName(), + $method->getName(), + $this->impossibleCheckTypeHelper->getArgumentsDescription($scope, $node->getArgs()), + )))->identifier('method.impossibleType')->build(), ]; } elseif ($this->checkAlwaysTrueCheckTypeFunctionCall) { $isLast = $node->getAttribute(LastConditionVisitor::ATTRIBUTE_NAME); @@ -82,7 +73,12 @@ public function processNode(Node $node, Scope $scope): array } $method = $this->getMethod($node->var, $node->name->name, $scope); - $errorBuilder = $addTip(RuleErrorBuilder::message(sprintf('Call to method %s::%s()%s will always evaluate to true.', $method->getDeclaringClass()->getDisplayName(), $method->getName(), $this->impossibleCheckTypeHelper->getArgumentsDescription($scope, $node->getArgs())))); + $errorBuilder = $addTip(RuleErrorBuilder::message(sprintf( + 'Call to method %s::%s()%s will always evaluate to true.', + $method->getDeclaringClass()->getDisplayName(), + $method->getName(), + $this->impossibleCheckTypeHelper->getArgumentsDescription($scope, $node->getArgs()), + ))); if ($isLast === false && !$this->reportAlwaysTrueInLastCondition) { $errorBuilder->tip('Remove remaining cases below this one and this error will disappear too.'); } @@ -95,13 +91,18 @@ public function processNode(Node $node, Scope $scope): array return []; } - private function getMethod(Expr $var, string $methodName, Scope $scope) : MethodReflection + private function getMethod( + Expr $var, + string $methodName, + Scope $scope, + ): MethodReflection { $calledOnType = $scope->getType($var); $method = $scope->getMethodReflection($calledOnType, $methodName); if ($method === null) { throw new ShouldNotHappenException(); } + return $method; } diff --git a/src/Rules/Comparison/ImpossibleCheckTypeStaticMethodCallRule.php b/src/Rules/Comparison/ImpossibleCheckTypeStaticMethodCallRule.php index 1e9237ae1f7..ae497b945e0 100644 --- a/src/Rules/Comparison/ImpossibleCheckTypeStaticMethodCallRule.php +++ b/src/Rules/Comparison/ImpossibleCheckTypeStaticMethodCallRule.php @@ -18,29 +18,15 @@ class ImpossibleCheckTypeStaticMethodCallRule implements Rule { - /** - * @var ImpossibleCheckTypeHelper - */ - private $impossibleCheckTypeHelper; - /** - * @var bool - */ - private $checkAlwaysTrueCheckTypeFunctionCall; - /** - * @var bool - */ - private $treatPhpDocTypesAsCertain; - /** - * @var bool - */ - private $reportAlwaysTrueInLastCondition; - public function __construct(ImpossibleCheckTypeHelper $impossibleCheckTypeHelper, bool $checkAlwaysTrueCheckTypeFunctionCall, bool $treatPhpDocTypesAsCertain, bool $reportAlwaysTrueInLastCondition) + public function __construct( + private ImpossibleCheckTypeHelper $impossibleCheckTypeHelper, + private bool $checkAlwaysTrueCheckTypeFunctionCall, + private bool $treatPhpDocTypesAsCertain, + private bool $reportAlwaysTrueInLastCondition, + ) { - $this->impossibleCheckTypeHelper = $impossibleCheckTypeHelper; - $this->checkAlwaysTrueCheckTypeFunctionCall = $checkAlwaysTrueCheckTypeFunctionCall; - $this->treatPhpDocTypesAsCertain = $treatPhpDocTypesAsCertain; - $this->reportAlwaysTrueInLastCondition = $reportAlwaysTrueInLastCondition; } + public function getNodeType(): string { return Node\Expr\StaticCall::class; @@ -74,7 +60,12 @@ public function processNode(Node $node, Scope $scope): array $method = $this->getMethod($node->class, $node->name->name, $scope); return [ - $addTip(RuleErrorBuilder::message(sprintf('Call to static method %s::%s()%s will always evaluate to false.', $method->getDeclaringClass()->getDisplayName(), $method->getName(), $this->impossibleCheckTypeHelper->getArgumentsDescription($scope, $node->getArgs()))))->identifier('staticMethod.impossibleType')->build(), + $addTip(RuleErrorBuilder::message(sprintf( + 'Call to static method %s::%s()%s will always evaluate to false.', + $method->getDeclaringClass()->getDisplayName(), + $method->getName(), + $this->impossibleCheckTypeHelper->getArgumentsDescription($scope, $node->getArgs()), + )))->identifier('staticMethod.impossibleType')->build(), ]; } elseif ($this->checkAlwaysTrueCheckTypeFunctionCall) { $isLast = $node->getAttribute(LastConditionVisitor::ATTRIBUTE_NAME); @@ -83,7 +74,12 @@ public function processNode(Node $node, Scope $scope): array } $method = $this->getMethod($node->class, $node->name->name, $scope); - $errorBuilder = $addTip(RuleErrorBuilder::message(sprintf('Call to static method %s::%s()%s will always evaluate to true.', $method->getDeclaringClass()->getDisplayName(), $method->getName(), $this->impossibleCheckTypeHelper->getArgumentsDescription($scope, $node->getArgs())))); + $errorBuilder = $addTip(RuleErrorBuilder::message(sprintf( + 'Call to static method %s::%s()%s will always evaluate to true.', + $method->getDeclaringClass()->getDisplayName(), + $method->getName(), + $this->impossibleCheckTypeHelper->getArgumentsDescription($scope, $node->getArgs()), + ))); if ($isLast === false && !$this->reportAlwaysTrueInLastCondition) { $errorBuilder->tip('Remove remaining cases below this one and this error will disappear too.'); } @@ -100,17 +96,23 @@ public function processNode(Node $node, Scope $scope): array * @param Node\Name|Expr $class * @throws ShouldNotHappenException */ - private function getMethod($class, string $methodName, Scope $scope) : MethodReflection + private function getMethod( + $class, + string $methodName, + Scope $scope, + ): MethodReflection { if ($class instanceof Node\Name) { $calledOnType = $scope->resolveTypeByName($class); } else { $calledOnType = $scope->getType($class); } + $method = $scope->getMethodReflection($calledOnType, $methodName); if ($method === null) { throw new ShouldNotHappenException(); } + return $method; } diff --git a/src/Rules/Comparison/LogicalXorConstantConditionRule.php b/src/Rules/Comparison/LogicalXorConstantConditionRule.php index 572bd1ed132..d807b4c041c 100644 --- a/src/Rules/Comparison/LogicalXorConstantConditionRule.php +++ b/src/Rules/Comparison/LogicalXorConstantConditionRule.php @@ -17,24 +17,14 @@ class LogicalXorConstantConditionRule implements Rule { - /** - * @var ConstantConditionRuleHelper - */ - private $helper; - /** - * @var bool - */ - private $treatPhpDocTypesAsCertain; - /** - * @var bool - */ - private $reportAlwaysTrueInLastCondition; - public function __construct(ConstantConditionRuleHelper $helper, bool $treatPhpDocTypesAsCertain, bool $reportAlwaysTrueInLastCondition) + public function __construct( + private ConstantConditionRuleHelper $helper, + private bool $treatPhpDocTypesAsCertain, + private bool $reportAlwaysTrueInLastCondition, + ) { - $this->helper = $helper; - $this->treatPhpDocTypesAsCertain = $treatPhpDocTypesAsCertain; - $this->reportAlwaysTrueInLastCondition = $reportAlwaysTrueInLastCondition; } + public function getNodeType(): string { return LogicalXor::class; @@ -61,7 +51,10 @@ public function processNode(Node $node, Scope $scope): array $isLast = $node->getAttribute(LastConditionVisitor::ATTRIBUTE_NAME); if (!$leftType->getValue() || $isLast !== true || $this->reportAlwaysTrueInLastCondition) { - $errorBuilder = $addTipLeft(RuleErrorBuilder::message(sprintf('Left side of xor is always %s.', $leftType->getValue() ? 'true' : 'false'))) + $errorBuilder = $addTipLeft(RuleErrorBuilder::message(sprintf( + 'Left side of xor is always %s.', + $leftType->getValue() ? 'true' : 'false', + ))) ->identifier(sprintf('logicalXor.leftAlways%s', $leftType->getValue() ? 'True' : 'False')) ->line($node->left->getStartLine()); if ($leftType->getValue() && $isLast === false && !$this->reportAlwaysTrueInLastCondition) { @@ -78,7 +71,10 @@ public function processNode(Node $node, Scope $scope): array return $ruleErrorBuilder; } - $booleanNativeType = $this->helper->getNativeBooleanType($scope, $node->right); + $booleanNativeType = $this->helper->getNativeBooleanType( + $scope, + $node->right, + ); if ($booleanNativeType instanceof ConstantBooleanType) { return $ruleErrorBuilder; } @@ -88,7 +84,10 @@ public function processNode(Node $node, Scope $scope): array $isLast = $node->getAttribute(LastConditionVisitor::ATTRIBUTE_NAME); if (!$rightType->getValue() || $isLast !== true || $this->reportAlwaysTrueInLastCondition) { - $errorBuilder = $addTipRight(RuleErrorBuilder::message(sprintf('Right side of xor is always %s.', $rightType->getValue() ? 'true' : 'false'))) + $errorBuilder = $addTipRight(RuleErrorBuilder::message(sprintf( + 'Right side of xor is always %s.', + $rightType->getValue() ? 'true' : 'false', + ))) ->identifier(sprintf('logicalXor.rightAlways%s', $rightType->getValue() ? 'True' : 'False')) ->line($node->right->getStartLine()); if ($rightType->getValue() && $isLast === false && !$this->reportAlwaysTrueInLastCondition) { diff --git a/src/Rules/Comparison/MatchExpressionRule.php b/src/Rules/Comparison/MatchExpressionRule.php index f9a5ec43223..d7d318322e9 100644 --- a/src/Rules/Comparison/MatchExpressionRule.php +++ b/src/Rules/Comparison/MatchExpressionRule.php @@ -25,34 +25,16 @@ class MatchExpressionRule implements Rule { - /** - * @var ConstantConditionRuleHelper - */ - private $constantConditionRuleHelper; - /** - * @var bool - */ - private $checkAlwaysTrueStrictComparison; - /** - * @var bool - */ - private $disableUnreachable; - /** - * @var bool - */ - private $reportAlwaysTrueInLastCondition; - /** - * @var bool - */ - private $treatPhpDocTypesAsCertain; - public function __construct(ConstantConditionRuleHelper $constantConditionRuleHelper, bool $checkAlwaysTrueStrictComparison, bool $disableUnreachable, bool $reportAlwaysTrueInLastCondition, bool $treatPhpDocTypesAsCertain) + public function __construct( + private ConstantConditionRuleHelper $constantConditionRuleHelper, + private bool $checkAlwaysTrueStrictComparison, + private bool $disableUnreachable, + private bool $reportAlwaysTrueInLastCondition, + private bool $treatPhpDocTypesAsCertain, + ) { - $this->constantConditionRuleHelper = $constantConditionRuleHelper; - $this->checkAlwaysTrueStrictComparison = $checkAlwaysTrueStrictComparison; - $this->disableUnreachable = $disableUnreachable; - $this->reportAlwaysTrueInLastCondition = $reportAlwaysTrueInLastCondition; - $this->treatPhpDocTypesAsCertain = $treatPhpDocTypesAsCertain; } + public function getNodeType(): string { return MatchExpressionNode::class; @@ -86,7 +68,10 @@ public function processNode(Node $node, Scope $scope): array } foreach ($armConditions as $armCondition) { $armConditionScope = $armCondition->getScope(); - $armConditionExpr = new Node\Expr\BinaryOp\Identical($matchCondition, $armCondition->getCondition()); + $armConditionExpr = new Node\Expr\BinaryOp\Identical( + $matchCondition, + $armCondition->getCondition(), + ); $armConditionResult = $armConditionScope->getType($armConditionExpr); if (!$armConditionResult instanceof ConstantBooleanType) { @@ -115,13 +100,21 @@ public function processNode(Node $node, Scope $scope): array $armLine = $armCondition->getLine(); if (!$armConditionResult->getValue()) { - $errors[] = RuleErrorBuilder::message(sprintf('Match arm comparison between %s and %s is always false.', $armConditionScope->getType($matchCondition)->describe(VerbosityLevel::value()), $armConditionScope->getType($armCondition->getCondition())->describe(VerbosityLevel::value())))->line($armLine)->identifier('match.alwaysFalse')->build(); + $errors[] = RuleErrorBuilder::message(sprintf( + 'Match arm comparison between %s and %s is always false.', + $armConditionScope->getType($matchCondition)->describe(VerbosityLevel::value()), + $armConditionScope->getType($armCondition->getCondition())->describe(VerbosityLevel::value()), + ))->line($armLine)->identifier('match.alwaysFalse')->build(); } else { if ($this->checkAlwaysTrueStrictComparison) { if ($i === $armsCount - 1 && !$this->reportAlwaysTrueInLastCondition) { continue; } - $errorBuilder = RuleErrorBuilder::message(sprintf('Match arm comparison between %s and %s is always true.', $armConditionScope->getType($matchCondition)->describe(VerbosityLevel::value()), $armConditionScope->getType($armCondition->getCondition())->describe(VerbosityLevel::value())))->line($armLine); + $errorBuilder = RuleErrorBuilder::message(sprintf( + 'Match arm comparison between %s and %s is always true.', + $armConditionScope->getType($matchCondition)->describe(VerbosityLevel::value()), + $armConditionScope->getType($armCondition->getCondition())->describe(VerbosityLevel::value()), + ))->line($armLine); if ($i !== $armsCount - 1 && !$this->reportAlwaysTrueInLastCondition) { $errorBuilder->tip('Remove remaining cases below this one and this error will disappear too.'); } @@ -149,7 +142,11 @@ public function processNode(Node $node, Scope $scope): array && !$this->isUnhandledMatchErrorCaught($node) && !$this->hasUnhandledMatchErrorThrowsTag($scope) ) { - $errors[] = RuleErrorBuilder::message(sprintf('Match expression does not handle remaining %s: %s', $remainingType instanceof UnionType ? 'values' : 'value', $remainingType->describe(VerbosityLevel::value())))->identifier('match.unhandled')->build(); + $errors[] = RuleErrorBuilder::message(sprintf( + 'Match expression does not handle remaining %s: %s', + $remainingType instanceof UnionType ? 'values' : 'value', + $remainingType->describe(VerbosityLevel::value()), + ))->identifier('match.unhandled')->build(); } } @@ -163,9 +160,7 @@ private function isUnhandledMatchErrorCaught(Node $node): bool return false; } - $tryCatchType = TypeCombinator::union(...array_map(static function (string $class) { - return new ObjectType($class); - }, $tryCatchTypes)); + $tryCatchType = TypeCombinator::union(...array_map(static fn (string $class) => new ObjectType($class), $tryCatchTypes)); return $tryCatchType->isSuperTypeOf(new ObjectType(UnhandledMatchError::class))->yes(); } diff --git a/src/Rules/Comparison/NumberComparisonOperatorsConstantConditionRule.php b/src/Rules/Comparison/NumberComparisonOperatorsConstantConditionRule.php index d450255c61b..5ab373b77ad 100644 --- a/src/Rules/Comparison/NumberComparisonOperatorsConstantConditionRule.php +++ b/src/Rules/Comparison/NumberComparisonOperatorsConstantConditionRule.php @@ -19,20 +19,21 @@ class NumberComparisonOperatorsConstantConditionRule implements Rule { - /** - * @var bool - */ - private $treatPhpDocTypesAsCertain; - public function __construct(bool $treatPhpDocTypesAsCertain) + public function __construct( + private bool $treatPhpDocTypesAsCertain, + ) { - $this->treatPhpDocTypesAsCertain = $treatPhpDocTypesAsCertain; } + public function getNodeType(): string { return BinaryOp::class; } - public function processNode(Node $node, Scope $scope) : array + public function processNode( + Node $node, + Scope $scope, + ): array { if ( !$node instanceof BinaryOp\Greater @@ -42,6 +43,7 @@ public function processNode(Node $node, Scope $scope) : array ) { return []; } + $exprType = $this->treatPhpDocTypesAsCertain ? $scope->getType($node) : $scope->getNativeType($node); if ($exprType instanceof ConstantBooleanType) { $addTip = function (RuleErrorBuilder $ruleErrorBuilder) use ($scope, $node): RuleErrorBuilder { @@ -75,9 +77,16 @@ public function processNode(Node $node, Scope $scope) : array } return [ - $addTip(RuleErrorBuilder::message(sprintf('Comparison operation "%s" between %s and %s is always %s.', $node->getOperatorSigil(), $scope->getType($node->left)->describe(VerbosityLevel::value()), $scope->getType($node->right)->describe(VerbosityLevel::value()), $exprType->getValue() ? 'true' : 'false')))->identifier(sprintf('%s.always%s', $nodeType, $exprType->getValue() ? 'True' : 'False'))->build(), + $addTip(RuleErrorBuilder::message(sprintf( + 'Comparison operation "%s" between %s and %s is always %s.', + $node->getOperatorSigil(), + $scope->getType($node->left)->describe(VerbosityLevel::value()), + $scope->getType($node->right)->describe(VerbosityLevel::value()), + $exprType->getValue() ? 'true' : 'false', + )))->identifier(sprintf('%s.always%s', $nodeType, $exprType->getValue() ? 'True' : 'False'))->build(), ]; } + return []; } diff --git a/src/Rules/Comparison/StrictComparisonOfDifferentTypesRule.php b/src/Rules/Comparison/StrictComparisonOfDifferentTypesRule.php index 52cc70fbb0d..1b40ed5080b 100644 --- a/src/Rules/Comparison/StrictComparisonOfDifferentTypesRule.php +++ b/src/Rules/Comparison/StrictComparisonOfDifferentTypesRule.php @@ -17,24 +17,14 @@ class StrictComparisonOfDifferentTypesRule implements Rule { - /** - * @var bool - */ - private $checkAlwaysTrueStrictComparison; - /** - * @var bool - */ - private $treatPhpDocTypesAsCertain; - /** - * @var bool - */ - private $reportAlwaysTrueInLastCondition; - public function __construct(bool $checkAlwaysTrueStrictComparison, bool $treatPhpDocTypesAsCertain, bool $reportAlwaysTrueInLastCondition) + public function __construct( + private bool $checkAlwaysTrueStrictComparison, + private bool $treatPhpDocTypesAsCertain, + private bool $reportAlwaysTrueInLastCondition, + ) { - $this->checkAlwaysTrueStrictComparison = $checkAlwaysTrueStrictComparison; - $this->treatPhpDocTypesAsCertain = $treatPhpDocTypesAsCertain; - $this->reportAlwaysTrueInLastCondition = $reportAlwaysTrueInLastCondition; } + public function getNodeType(): string { return Node\Expr\BinaryOp::class; @@ -69,7 +59,12 @@ public function processNode(Node $node, Scope $scope): array if (!$nodeType->getValue()) { return [ - $addTip(RuleErrorBuilder::message(sprintf('Strict comparison using %s between %s and %s will always evaluate to false.', $node->getOperatorSigil(), $leftType->describe(VerbosityLevel::value()), $rightType->describe(VerbosityLevel::value()))))->identifier(sprintf('%s.alwaysFalse', $node instanceof Node\Expr\BinaryOp\Identical ? 'identical' : 'notIdentical'))->build(), + $addTip(RuleErrorBuilder::message(sprintf( + 'Strict comparison using %s between %s and %s will always evaluate to false.', + $node->getOperatorSigil(), + $leftType->describe(VerbosityLevel::value()), + $rightType->describe(VerbosityLevel::value()), + )))->identifier(sprintf('%s.alwaysFalse', $node instanceof Node\Expr\BinaryOp\Identical ? 'identical' : 'notIdentical'))->build(), ]; } elseif ($this->checkAlwaysTrueStrictComparison) { $isLast = $node->getAttribute(LastConditionVisitor::ATTRIBUTE_NAME); @@ -77,7 +72,12 @@ public function processNode(Node $node, Scope $scope): array return []; } - $errorBuilder = $addTip(RuleErrorBuilder::message(sprintf('Strict comparison using %s between %s and %s will always evaluate to true.', $node->getOperatorSigil(), $leftType->describe(VerbosityLevel::value()), $rightType->describe(VerbosityLevel::value())))); + $errorBuilder = $addTip(RuleErrorBuilder::message(sprintf( + 'Strict comparison using %s between %s and %s will always evaluate to true.', + $node->getOperatorSigil(), + $leftType->describe(VerbosityLevel::value()), + $rightType->describe(VerbosityLevel::value()), + ))); if ($isLast === false && !$this->reportAlwaysTrueInLastCondition) { $errorBuilder->addTip('Remove remaining cases below this one and this error will disappear too.'); } diff --git a/src/Rules/Comparison/TernaryOperatorConstantConditionRule.php b/src/Rules/Comparison/TernaryOperatorConstantConditionRule.php index 1ec62f12366..01f35d64d6a 100644 --- a/src/Rules/Comparison/TernaryOperatorConstantConditionRule.php +++ b/src/Rules/Comparison/TernaryOperatorConstantConditionRule.php @@ -15,25 +15,22 @@ class TernaryOperatorConstantConditionRule implements Rule { - /** - * @var ConstantConditionRuleHelper - */ - private $helper; - /** - * @var bool - */ - private $treatPhpDocTypesAsCertain; - public function __construct(ConstantConditionRuleHelper $helper, bool $treatPhpDocTypesAsCertain) + public function __construct( + private ConstantConditionRuleHelper $helper, + private bool $treatPhpDocTypesAsCertain, + ) { - $this->helper = $helper; - $this->treatPhpDocTypesAsCertain = $treatPhpDocTypesAsCertain; } + public function getNodeType(): string { return Node\Expr\Ternary::class; } - public function processNode(Node $node, Scope $scope) : array + public function processNode( + Node $node, + Scope $scope, + ): array { $exprType = $this->helper->getBooleanType($scope, $node->cond); if ($exprType instanceof ConstantBooleanType) { @@ -50,9 +47,13 @@ public function processNode(Node $node, Scope $scope) : array return $ruleErrorBuilder->tip('Because the type is coming from a PHPDoc, you can turn off this check by setting treatPhpDocTypesAsCertain: false in your %configurationFile%.'); }; return [ - $addTip(RuleErrorBuilder::message(sprintf('Ternary operator condition is always %s.', $exprType->getValue() ? 'true' : 'false')))->identifier(sprintf('ternary.always%s', $exprType->getValue() ? 'True' : 'False'))->build(), + $addTip(RuleErrorBuilder::message(sprintf( + 'Ternary operator condition is always %s.', + $exprType->getValue() ? 'true' : 'false', + )))->identifier(sprintf('ternary.always%s', $exprType->getValue() ? 'True' : 'False'))->build(), ]; } + return []; } diff --git a/src/Rules/Comparison/UnreachableIfBranchesRule.php b/src/Rules/Comparison/UnreachableIfBranchesRule.php index eb363b61a1c..120fb0b69d2 100644 --- a/src/Rules/Comparison/UnreachableIfBranchesRule.php +++ b/src/Rules/Comparison/UnreachableIfBranchesRule.php @@ -14,24 +14,14 @@ class UnreachableIfBranchesRule implements Rule { - /** - * @var ConstantConditionRuleHelper - */ - private $helper; - /** - * @var bool - */ - private $treatPhpDocTypesAsCertain; - /** - * @var bool - */ - private $disable; - public function __construct(ConstantConditionRuleHelper $helper, bool $treatPhpDocTypesAsCertain, bool $disable) + public function __construct( + private ConstantConditionRuleHelper $helper, + private bool $treatPhpDocTypesAsCertain, + private bool $disable, + ) { - $this->helper = $helper; - $this->treatPhpDocTypesAsCertain = $treatPhpDocTypesAsCertain; - $this->disable = $disable; } + public function getNodeType(): string { return Node\Stmt\If_::class; diff --git a/src/Rules/Comparison/UnreachableTernaryElseBranchRule.php b/src/Rules/Comparison/UnreachableTernaryElseBranchRule.php index c5fee4c67f7..aa3975df1c1 100644 --- a/src/Rules/Comparison/UnreachableTernaryElseBranchRule.php +++ b/src/Rules/Comparison/UnreachableTernaryElseBranchRule.php @@ -14,24 +14,14 @@ class UnreachableTernaryElseBranchRule implements Rule { - /** - * @var ConstantConditionRuleHelper - */ - private $helper; - /** - * @var bool - */ - private $treatPhpDocTypesAsCertain; - /** - * @var bool - */ - private $disable; - public function __construct(ConstantConditionRuleHelper $helper, bool $treatPhpDocTypesAsCertain, bool $disable) + public function __construct( + private ConstantConditionRuleHelper $helper, + private bool $treatPhpDocTypesAsCertain, + private bool $disable, + ) { - $this->helper = $helper; - $this->treatPhpDocTypesAsCertain = $treatPhpDocTypesAsCertain; - $this->disable = $disable; } + public function getNodeType(): string { return Node\Expr\Ternary::class; diff --git a/src/Rules/Comparison/WhileLoopAlwaysFalseConditionRule.php b/src/Rules/Comparison/WhileLoopAlwaysFalseConditionRule.php index 0e36e06270c..f53fa8ce3e4 100644 --- a/src/Rules/Comparison/WhileLoopAlwaysFalseConditionRule.php +++ b/src/Rules/Comparison/WhileLoopAlwaysFalseConditionRule.php @@ -15,25 +15,22 @@ class WhileLoopAlwaysFalseConditionRule implements Rule { - /** - * @var ConstantConditionRuleHelper - */ - private $helper; - /** - * @var bool - */ - private $treatPhpDocTypesAsCertain; - public function __construct(ConstantConditionRuleHelper $helper, bool $treatPhpDocTypesAsCertain) + public function __construct( + private ConstantConditionRuleHelper $helper, + private bool $treatPhpDocTypesAsCertain, + ) { - $this->helper = $helper; - $this->treatPhpDocTypesAsCertain = $treatPhpDocTypesAsCertain; } + public function getNodeType(): string { return While_::class; } - public function processNode(Node $node, Scope $scope) : array + public function processNode( + Node $node, + Scope $scope, + ): array { $exprType = $this->helper->getBooleanType($scope, $node->cond); if ($exprType->isFalse()->yes()) { @@ -56,6 +53,7 @@ public function processNode(Node $node, Scope $scope) : array ->build(), ]; } + return []; } diff --git a/src/Rules/Comparison/WhileLoopAlwaysTrueConditionRule.php b/src/Rules/Comparison/WhileLoopAlwaysTrueConditionRule.php index 632714856d3..26aa3047a7a 100644 --- a/src/Rules/Comparison/WhileLoopAlwaysTrueConditionRule.php +++ b/src/Rules/Comparison/WhileLoopAlwaysTrueConditionRule.php @@ -18,25 +18,22 @@ class WhileLoopAlwaysTrueConditionRule implements Rule { - /** - * @var ConstantConditionRuleHelper - */ - private $helper; - /** - * @var bool - */ - private $treatPhpDocTypesAsCertain; - public function __construct(ConstantConditionRuleHelper $helper, bool $treatPhpDocTypesAsCertain) + public function __construct( + private ConstantConditionRuleHelper $helper, + private bool $treatPhpDocTypesAsCertain, + ) { - $this->helper = $helper; - $this->treatPhpDocTypesAsCertain = $treatPhpDocTypesAsCertain; } + public function getNodeType(): string { return BreaklessWhileLoopNode::class; } - public function processNode(Node $node, Scope $scope) : array + public function processNode( + Node $node, + Scope $scope, + ): array { foreach ($node->getExitPoints() as $exitPoint) { $statement = $exitPoint->getStatement(); @@ -83,6 +80,7 @@ public function processNode(Node $node, Scope $scope) : array ->build(), ]; } + return []; } diff --git a/src/Rules/Constants/ConstantRule.php b/src/Rules/Constants/ConstantRule.php index 212257988d8..27003ecade7 100644 --- a/src/Rules/Constants/ConstantRule.php +++ b/src/Rules/Constants/ConstantRule.php @@ -23,7 +23,10 @@ public function processNode(Node $node, Scope $scope): array { if (!$scope->hasConstant($node->name)) { return [ - RuleErrorBuilder::message(sprintf('Constant %s not found.', (string) $node->name)) + RuleErrorBuilder::message(sprintf( + 'Constant %s not found.', + (string) $node->name, + )) ->identifier('constant.notFound') ->discoveringSymbolsTip() ->build(), diff --git a/src/Rules/Constants/DynamicClassConstantFetchRule.php b/src/Rules/Constants/DynamicClassConstantFetchRule.php index 6216406b22d..ce1295ffc48 100644 --- a/src/Rules/Constants/DynamicClassConstantFetchRule.php +++ b/src/Rules/Constants/DynamicClassConstantFetchRule.php @@ -20,18 +20,8 @@ class DynamicClassConstantFetchRule implements Rule { - /** - * @var PhpVersion - */ - private $phpVersion; - /** - * @var RuleLevelHelper - */ - private $ruleLevelHelper; - public function __construct(PhpVersion $phpVersion, RuleLevelHelper $ruleLevelHelper) + public function __construct(private PhpVersion $phpVersion, private RuleLevelHelper $ruleLevelHelper) { - $this->phpVersion = $phpVersion; - $this->ruleLevelHelper = $ruleLevelHelper; } public function getNodeType(): string @@ -54,9 +44,12 @@ public function processNode(Node $node, Scope $scope): array ]; } - $typeResult = $this->ruleLevelHelper->findTypeToCheck($scope, $node->name, '', static function (Type $type) : bool { - return $type->isString()->yes(); - }); + $typeResult = $this->ruleLevelHelper->findTypeToCheck( + $scope, + $node->name, + '', + static fn (Type $type): bool => $type->isString()->yes(), + ); $type = $typeResult->getType(); if ($type instanceof ErrorType) { return []; @@ -66,7 +59,10 @@ public function processNode(Node $node, Scope $scope): array } return [ - RuleErrorBuilder::message(sprintf('Class constant name in dynamic fetch can only be a string, %s given.', $type->describe(VerbosityLevel::typeOnly())))->identifier('classConstant.nameType')->build(), + RuleErrorBuilder::message(sprintf( + 'Class constant name in dynamic fetch can only be a string, %s given.', + $type->describe(VerbosityLevel::typeOnly()), + ))->identifier('classConstant.nameType')->build(), ]; } diff --git a/src/Rules/Constants/FinalConstantRule.php b/src/Rules/Constants/FinalConstantRule.php index 77bd669e9d3..d6b891f4652 100644 --- a/src/Rules/Constants/FinalConstantRule.php +++ b/src/Rules/Constants/FinalConstantRule.php @@ -13,13 +13,8 @@ class FinalConstantRule implements Rule { - /** - * @var PhpVersion - */ - private $phpVersion; - public function __construct(PhpVersion $phpVersion) + public function __construct(private PhpVersion $phpVersion) { - $this->phpVersion = $phpVersion; } public function getNodeType(): string diff --git a/src/Rules/Constants/LazyAlwaysUsedClassConstantsExtensionProvider.php b/src/Rules/Constants/LazyAlwaysUsedClassConstantsExtensionProvider.php index a0a0a0aeab5..895fb96360d 100644 --- a/src/Rules/Constants/LazyAlwaysUsedClassConstantsExtensionProvider.php +++ b/src/Rules/Constants/LazyAlwaysUsedClassConstantsExtensionProvider.php @@ -7,16 +7,11 @@ class LazyAlwaysUsedClassConstantsExtensionProvider implements AlwaysUsedClassConstantsExtensionProvider { - /** - * @var Container - */ - private $container; /** @var AlwaysUsedClassConstantsExtension[]|null */ - private $extensions = null; + private ?array $extensions = null; - public function __construct(Container $container) + public function __construct(private Container $container) { - $this->container = $container; } public function getExtensions(): array diff --git a/src/Rules/Constants/MagicConstantContextRule.php b/src/Rules/Constants/MagicConstantContextRule.php index f882e94f95c..5cfb38f0744 100644 --- a/src/Rules/Constants/MagicConstantContextRule.php +++ b/src/Rules/Constants/MagicConstantContextRule.php @@ -29,7 +29,9 @@ public function processNode(Node $node, Scope $scope): array } return [ - RuleErrorBuilder::message(sprintf('Magic constant %s is always empty outside a class.', $node->getName()))->identifier('magicConstant.outOfClass')->build(), + RuleErrorBuilder::message( + sprintf('Magic constant %s is always empty outside a class.', $node->getName()), + )->identifier('magicConstant.outOfClass')->build(), ]; } elseif ($node instanceof MagicConst\Trait_) { if ($scope->isInTrait()) { @@ -37,7 +39,9 @@ public function processNode(Node $node, Scope $scope): array } return [ - RuleErrorBuilder::message(sprintf('Magic constant %s is always empty outside a trait.', $node->getName()))->identifier('magicConstant.outOfTrait')->build(), + RuleErrorBuilder::message( + sprintf('Magic constant %s is always empty outside a trait.', $node->getName()), + )->identifier('magicConstant.outOfTrait')->build(), ]; } elseif ($node instanceof MagicConst\Method || $node instanceof MagicConst\Function_) { if ($scope->getFunctionName() !== null) { @@ -52,12 +56,16 @@ public function processNode(Node $node, Scope $scope): array } return [ - RuleErrorBuilder::message(sprintf('Magic constant %s is always empty outside a function.', $node->getName()))->identifier('magicConstant.outOfFunction')->build(), + RuleErrorBuilder::message( + sprintf('Magic constant %s is always empty outside a function.', $node->getName()), + )->identifier('magicConstant.outOfFunction')->build(), ]; } elseif ($node instanceof MagicConst\Namespace_) { if ($scope->getNamespace() === null) { return [ - RuleErrorBuilder::message(sprintf('Magic constant %s is always empty in global namespace.', $node->getName()))->identifier('magicConstant.outOfNamespace')->build(), + RuleErrorBuilder::message( + sprintf('Magic constant %s is always empty in global namespace.', $node->getName()), + )->identifier('magicConstant.outOfNamespace')->build(), ]; } } diff --git a/src/Rules/Constants/MissingClassConstantTypehintRule.php b/src/Rules/Constants/MissingClassConstantTypehintRule.php index 12f7ee95976..7de4b9fec5e 100644 --- a/src/Rules/Constants/MissingClassConstantTypehintRule.php +++ b/src/Rules/Constants/MissingClassConstantTypehintRule.php @@ -21,13 +21,8 @@ final class MissingClassConstantTypehintRule implements Rule { - /** - * @var MissingTypehintCheck - */ - private $missingTypehintCheck; - public function __construct(MissingTypehintCheck $missingTypehintCheck) + public function __construct(private MissingTypehintCheck $missingTypehintCheck) { - $this->missingTypehintCheck = $missingTypehintCheck; } public function getNodeType(): string @@ -64,21 +59,37 @@ private function processSingleConstant(ClassReflection $classReflection, string $errors = []; foreach ($this->missingTypehintCheck->getIterableTypesWithMissingValueTypehint($constantType) as $iterableType) { $iterableTypeDescription = $iterableType->describe(VerbosityLevel::typeOnly()); - $errors[] = RuleErrorBuilder::message(sprintf('Constant %s::%s type has no value type specified in iterable type %s.', $constantReflection->getDeclaringClass()->getDisplayName(), $constantName, $iterableTypeDescription)) + $errors[] = RuleErrorBuilder::message(sprintf( + 'Constant %s::%s type has no value type specified in iterable type %s.', + $constantReflection->getDeclaringClass()->getDisplayName(), + $constantName, + $iterableTypeDescription, + )) ->tip(MissingTypehintCheck::MISSING_ITERABLE_VALUE_TYPE_TIP) ->identifier('missingType.iterableValue') ->build(); } foreach ($this->missingTypehintCheck->getNonGenericObjectTypesWithGenericClass($constantType) as [$name, $genericTypeNames]) { - $errors[] = RuleErrorBuilder::message(sprintf('Constant %s::%s with generic %s does not specify its types: %s', $constantReflection->getDeclaringClass()->getDisplayName(), $constantName, $name, implode(', ', $genericTypeNames))) + $errors[] = RuleErrorBuilder::message(sprintf( + 'Constant %s::%s with generic %s does not specify its types: %s', + $constantReflection->getDeclaringClass()->getDisplayName(), + $constantName, + $name, + implode(', ', $genericTypeNames), + )) ->tip(MissingTypehintCheck::TURN_OFF_NON_GENERIC_CHECK_TIP) ->identifier('missingType.generics') ->build(); } foreach ($this->missingTypehintCheck->getCallablesWithMissingSignature($constantType) as $callableType) { - $errors[] = RuleErrorBuilder::message(sprintf('Constant %s::%s type has no signature specified for %s.', $constantReflection->getDeclaringClass()->getDisplayName(), $constantName, $callableType->describe(VerbosityLevel::typeOnly())))->identifier('missingType.callable')->build(); + $errors[] = RuleErrorBuilder::message(sprintf( + 'Constant %s::%s type has no signature specified for %s.', + $constantReflection->getDeclaringClass()->getDisplayName(), + $constantName, + $callableType->describe(VerbosityLevel::typeOnly()), + ))->identifier('missingType.callable')->build(); } return $errors; diff --git a/src/Rules/Constants/NativeTypedClassConstantRule.php b/src/Rules/Constants/NativeTypedClassConstantRule.php index a2c2264b0d5..ce2ea802d8c 100644 --- a/src/Rules/Constants/NativeTypedClassConstantRule.php +++ b/src/Rules/Constants/NativeTypedClassConstantRule.php @@ -14,13 +14,8 @@ class NativeTypedClassConstantRule implements Rule { - /** - * @var PhpVersion - */ - private $phpVersion; - public function __construct(PhpVersion $phpVersion) + public function __construct(private PhpVersion $phpVersion) { - $this->phpVersion = $phpVersion; } public function getNodeType(): string diff --git a/src/Rules/Constants/OverridingConstantRule.php b/src/Rules/Constants/OverridingConstantRule.php index 83335c9c158..555cbfc0ddb 100644 --- a/src/Rules/Constants/OverridingConstantRule.php +++ b/src/Rules/Constants/OverridingConstantRule.php @@ -21,14 +21,12 @@ class OverridingConstantRule implements Rule { - /** - * @var bool - */ - private $checkPhpDocMethodSignatures; - public function __construct(bool $checkPhpDocMethodSignatures) + public function __construct( + private bool $checkPhpDocMethodSignatures, + ) { - $this->checkPhpDocMethodSignatures = $checkPhpDocMethodSignatures; } + public function getNodeType(): string { return Node\Stmt\ClassConst::class; @@ -62,15 +60,34 @@ private function processSingleConstant(ClassReflection $classReflection, string $constantReflection = $classReflection->getConstant($constantName); $errors = []; if ($prototype->isFinal()) { - $errors[] = RuleErrorBuilder::message(sprintf('Constant %s::%s overrides final constant %s::%s.', $classReflection->getDisplayName(), $constantReflection->getName(), $prototype->getDeclaringClass()->getDisplayName(), $prototype->getName()))->identifier('classConstant.final')->nonIgnorable()->build(); + $errors[] = RuleErrorBuilder::message(sprintf( + 'Constant %s::%s overrides final constant %s::%s.', + $classReflection->getDisplayName(), + $constantReflection->getName(), + $prototype->getDeclaringClass()->getDisplayName(), + $prototype->getName(), + ))->identifier('classConstant.final')->nonIgnorable()->build(); } if ($prototype->isPublic()) { if (!$constantReflection->isPublic()) { - $errors[] = RuleErrorBuilder::message(sprintf('%s constant %s::%s overriding public constant %s::%s should also be public.', $constantReflection->isPrivate() ? 'Private' : 'Protected', $constantReflection->getDeclaringClass()->getDisplayName(), $constantReflection->getName(), $prototype->getDeclaringClass()->getDisplayName(), $prototype->getName()))->identifier('classConstant.visibility')->nonIgnorable()->build(); + $errors[] = RuleErrorBuilder::message(sprintf( + '%s constant %s::%s overriding public constant %s::%s should also be public.', + $constantReflection->isPrivate() ? 'Private' : 'Protected', + $constantReflection->getDeclaringClass()->getDisplayName(), + $constantReflection->getName(), + $prototype->getDeclaringClass()->getDisplayName(), + $prototype->getName(), + ))->identifier('classConstant.visibility')->nonIgnorable()->build(); } } elseif ($constantReflection->isPrivate()) { - $errors[] = RuleErrorBuilder::message(sprintf('Private constant %s::%s overriding protected constant %s::%s should be protected or public.', $constantReflection->getDeclaringClass()->getDisplayName(), $constantReflection->getName(), $prototype->getDeclaringClass()->getDisplayName(), $prototype->getName()))->identifier('classConstant.visibility')->nonIgnorable()->build(); + $errors[] = RuleErrorBuilder::message(sprintf( + 'Private constant %s::%s overriding protected constant %s::%s should be protected or public.', + $constantReflection->getDeclaringClass()->getDisplayName(), + $constantReflection->getName(), + $prototype->getDeclaringClass()->getDisplayName(), + $prototype->getName(), + ))->identifier('classConstant.visibility')->nonIgnorable()->build(); } if (!$this->checkPhpDocMethodSignatures) { @@ -82,10 +99,26 @@ private function processSingleConstant(ClassReflection $classReflection, string if ($prototypeNativeType !== null) { if ($constantNativeType !== null) { if (!$prototypeNativeType->isSuperTypeOf($constantNativeType)->yes()) { - $errors[] = RuleErrorBuilder::message(sprintf('Native type %s of constant %s::%s is not covariant with native type %s of constant %s::%s.', $constantNativeType->describe(VerbosityLevel::typeOnly()), $constantReflection->getDeclaringClass()->getDisplayName(), $constantReflection->getName(), $prototypeNativeType->describe(VerbosityLevel::typeOnly()), $prototype->getDeclaringClass()->getDisplayName(), $prototype->getName()))->identifier('classConstant.nativeType')->nonIgnorable()->build(); + $errors[] = RuleErrorBuilder::message(sprintf( + 'Native type %s of constant %s::%s is not covariant with native type %s of constant %s::%s.', + $constantNativeType->describe(VerbosityLevel::typeOnly()), + $constantReflection->getDeclaringClass()->getDisplayName(), + $constantReflection->getName(), + $prototypeNativeType->describe(VerbosityLevel::typeOnly()), + $prototype->getDeclaringClass()->getDisplayName(), + $prototype->getName(), + ))->identifier('classConstant.nativeType')->nonIgnorable()->build(); } } else { - $errors[] = RuleErrorBuilder::message(sprintf('Constant %s::%s overriding constant %s::%s (%s) should also have native type %s.', $constantReflection->getDeclaringClass()->getDisplayName(), $constantReflection->getName(), $prototype->getDeclaringClass()->getDisplayName(), $prototype->getName(), $prototypeNativeType->describe(VerbosityLevel::typeOnly()), $prototypeNativeType->describe(VerbosityLevel::typeOnly())))->identifier('classConstant.missingNativeType')->nonIgnorable()->build(); + $errors[] = RuleErrorBuilder::message(sprintf( + 'Constant %s::%s overriding constant %s::%s (%s) should also have native type %s.', + $constantReflection->getDeclaringClass()->getDisplayName(), + $constantReflection->getName(), + $prototype->getDeclaringClass()->getDisplayName(), + $prototype->getName(), + $prototypeNativeType->describe(VerbosityLevel::typeOnly()), + $prototypeNativeType->describe(VerbosityLevel::typeOnly()), + ))->identifier('classConstant.missingNativeType')->nonIgnorable()->build(); } } @@ -98,7 +131,15 @@ private function processSingleConstant(ClassReflection $classReflection, string } if (!$prototype->getValueType()->isSuperTypeOf($constantReflection->getValueType())->yes()) { - $errors[] = RuleErrorBuilder::message(sprintf('Type %s of constant %s::%s is not covariant with type %s of constant %s::%s.', $constantReflection->getValueType()->describe(VerbosityLevel::value()), $constantReflection->getDeclaringClass()->getDisplayName(), $constantReflection->getName(), $prototype->getValueType()->describe(VerbosityLevel::value()), $prototype->getDeclaringClass()->getDisplayName(), $prototype->getName()))->identifier('classConstant.type')->build(); + $errors[] = RuleErrorBuilder::message(sprintf( + 'Type %s of constant %s::%s is not covariant with type %s of constant %s::%s.', + $constantReflection->getValueType()->describe(VerbosityLevel::value()), + $constantReflection->getDeclaringClass()->getDisplayName(), + $constantReflection->getName(), + $prototype->getValueType()->describe(VerbosityLevel::value()), + $prototype->getDeclaringClass()->getDisplayName(), + $prototype->getName(), + ))->identifier('classConstant.type')->build(); } return $errors; diff --git a/src/Rules/Constants/ValueAssignedToClassConstantRule.php b/src/Rules/Constants/ValueAssignedToClassConstantRule.php index 686b898bd47..37b72e1c721 100644 --- a/src/Rules/Constants/ValueAssignedToClassConstantRule.php +++ b/src/Rules/Constants/ValueAssignedToClassConstantRule.php @@ -40,7 +40,12 @@ public function processNode(Node $node, Scope $scope): array $errors = []; foreach ($node->consts as $const) { $constantName = $const->name->toString(); - $errors = array_merge($errors, $this->processSingleConstant($scope->getClassReflection(), $constantName, $scope->getType($const->value), $nativeType)); + $errors = array_merge($errors, $this->processSingleConstant( + $scope->getClassReflection(), + $constantName, + $scope->getType($const->value), + $nativeType, + )); } return $errors; @@ -64,19 +69,37 @@ private function processSingleConstant(ClassReflection $classReflection, string } return [ - RuleErrorBuilder::message(sprintf('Constant %s::%s (%s) does not accept value %s.', $constantReflection->getDeclaringClass()->getDisplayName(), $constantName, $nativeType->describe(VerbosityLevel::typeOnly()), $valueExprType->describe(VerbosityLevel::value())))->acceptsReasonsTip($accepts->reasons)->nonIgnorable()->identifier('classConstant.value')->build(), + RuleErrorBuilder::message(sprintf( + 'Constant %s::%s (%s) does not accept value %s.', + $constantReflection->getDeclaringClass()->getDisplayName(), + $constantName, + $nativeType->describe(VerbosityLevel::typeOnly()), + $valueExprType->describe(VerbosityLevel::value()), + ))->acceptsReasonsTip($accepts->reasons)->nonIgnorable()->identifier('classConstant.value')->build(), ]; } elseif ($nativeType === null) { $isSuperType = $phpDocType->isSuperTypeOf($valueExprType); $verbosity = VerbosityLevel::getRecommendedLevelByType($phpDocType, $valueExprType); if ($isSuperType->no()) { return [ - RuleErrorBuilder::message(sprintf('PHPDoc tag @var for constant %s::%s with type %s is incompatible with value %s.', $constantReflection->getDeclaringClass()->getDisplayName(), $constantName, $phpDocType->describe($verbosity), $valueExprType->describe(VerbosityLevel::value())))->identifier('classConstant.phpDocType')->build(), + RuleErrorBuilder::message(sprintf( + 'PHPDoc tag @var for constant %s::%s with type %s is incompatible with value %s.', + $constantReflection->getDeclaringClass()->getDisplayName(), + $constantName, + $phpDocType->describe($verbosity), + $valueExprType->describe(VerbosityLevel::value()), + ))->identifier('classConstant.phpDocType')->build(), ]; } elseif ($isSuperType->maybe()) { return [ - RuleErrorBuilder::message(sprintf('PHPDoc tag @var for constant %s::%s with type %s is not subtype of value %s.', $constantReflection->getDeclaringClass()->getDisplayName(), $constantName, $phpDocType->describe($verbosity), $valueExprType->describe(VerbosityLevel::value())))->identifier('classConstant.phpDocType')->build(), + RuleErrorBuilder::message(sprintf( + 'PHPDoc tag @var for constant %s::%s with type %s is not subtype of value %s.', + $constantReflection->getDeclaringClass()->getDisplayName(), + $constantName, + $phpDocType->describe($verbosity), + $valueExprType->describe(VerbosityLevel::value()), + ))->identifier('classConstant.phpDocType')->build(), ]; } @@ -92,7 +115,13 @@ private function processSingleConstant(ClassReflection $classReflection, string $verbosity = VerbosityLevel::getRecommendedLevelByType($type, $valueExprType); return [ - RuleErrorBuilder::message(sprintf('Constant %s::%s (%s) does not accept value %s.', $constantReflection->getDeclaringClass()->getDisplayName(), $constantName, $type->describe(VerbosityLevel::typeOnly()), $valueExprType->describe($verbosity)))->acceptsReasonsTip($accepts->reasons)->identifier('classConstant.value')->build(), + RuleErrorBuilder::message(sprintf( + 'Constant %s::%s (%s) does not accept value %s.', + $constantReflection->getDeclaringClass()->getDisplayName(), + $constantName, + $type->describe(VerbosityLevel::typeOnly()), + $valueExprType->describe($verbosity), + ))->acceptsReasonsTip($accepts->reasons)->identifier('classConstant.value')->build(), ]; } diff --git a/src/Rules/DateTimeInstantiationRule.php b/src/Rules/DateTimeInstantiationRule.php index 935b17f1149..b8cd1684dd6 100644 --- a/src/Rules/DateTimeInstantiationRule.php +++ b/src/Rules/DateTimeInstantiationRule.php @@ -47,7 +47,7 @@ public function processNode(Node $node, Scope $scope): array $dateString = $constantString->getValue(); try { new DateTime($dateString); - } catch (Throwable $e) { + } catch (Throwable) { // an exception is thrown for errors only but we want to catch warnings too } $lastErrors = DateTime::getLastErrors(); @@ -56,7 +56,12 @@ public function processNode(Node $node, Scope $scope): array } foreach ($lastErrors['errors'] as $error) { - $errors[] = RuleErrorBuilder::message(sprintf('Instantiating %s with %s produces an error: %s', $lowerClassName === 'datetime' ? 'DateTime' : 'DateTimeImmutable', $dateString, $error))->identifier(sprintf('new.%s', $lowerClassName === 'datetime' ? 'dateTime' : 'dateTimeImmutable'))->build(); + $errors[] = RuleErrorBuilder::message(sprintf( + 'Instantiating %s with %s produces an error: %s', + $lowerClassName === 'datetime' ? 'DateTime' : 'DateTimeImmutable', + $dateString, + $error, + ))->identifier(sprintf('new.%s', $lowerClassName === 'datetime' ? 'dateTime' : 'dateTimeImmutable'))->build(); } } diff --git a/src/Rules/DeadCode/NoopRule.php b/src/Rules/DeadCode/NoopRule.php index 71ea62a0495..8105463cc07 100644 --- a/src/Rules/DeadCode/NoopRule.php +++ b/src/Rules/DeadCode/NoopRule.php @@ -15,18 +15,8 @@ class NoopRule implements Rule { - /** - * @var ExprPrinter - */ - private $exprPrinter; - /** - * @var bool - */ - private $logicalXor; - public function __construct(ExprPrinter $exprPrinter, bool $logicalXor) + public function __construct(private ExprPrinter $exprPrinter, private bool $logicalXor) { - $this->exprPrinter = $exprPrinter; - $this->logicalXor = $logicalXor; } public function getNodeType(): string @@ -49,7 +39,9 @@ public function processNode(Node $node, Scope $scope): array if ($this->logicalXor) { if ($expr instanceof Node\Expr\BinaryOp\LogicalXor) { return [ - RuleErrorBuilder::message('Unused result of "xor" operator.')->line($expr->getStartLine()) + RuleErrorBuilder::message( + 'Unused result of "xor" operator.', + )->line($expr->getStartLine()) ->tip('This operator has unexpected precedence, try disambiguating the logic with parentheses ().') ->identifier('logicalXor.resultUnused') ->build(), @@ -63,7 +55,10 @@ public function processNode(Node $node, Scope $scope): array $identifierType = $expr instanceof Node\Expr\BinaryOp\LogicalAnd ? 'logicalAnd' : 'logicalOr'; return [ - RuleErrorBuilder::message(sprintf('Unused result of "%s" operator.', $expr->getOperatorSigil()))->line($expr->getStartLine()) + RuleErrorBuilder::message(sprintf( + 'Unused result of "%s" operator.', + $expr->getOperatorSigil(), + ))->line($expr->getStartLine()) ->tip('This operator has unexpected precedence, try disambiguating the logic with parentheses ().') ->identifier(sprintf('%s.resultUnused', $identifierType)) ->build(), @@ -78,7 +73,10 @@ public function processNode(Node $node, Scope $scope): array $identifierType = $expr instanceof Node\Expr\BinaryOp\BooleanAnd ? 'booleanAnd' : 'booleanOr'; return [ - RuleErrorBuilder::message(sprintf('Unused result of "%s" operator.', $expr->getOperatorSigil()))->line($expr->getStartLine()) + RuleErrorBuilder::message(sprintf( + 'Unused result of "%s" operator.', + $expr->getOperatorSigil(), + ))->line($expr->getStartLine()) ->identifier(sprintf('%s.resultUnused', $identifierType)) ->build(), ]; @@ -107,7 +105,10 @@ public function processNode(Node $node, Scope $scope): array } return [ - RuleErrorBuilder::message(sprintf('Expression "%s" on a separate line does not do anything.', $this->exprPrinter->printExpr($originalExpr)))->line($expr->getStartLine()) + RuleErrorBuilder::message(sprintf( + 'Expression "%s" on a separate line does not do anything.', + $this->exprPrinter->printExpr($originalExpr), + ))->line($expr->getStartLine()) ->identifier('expr.resultUnused') ->build(), ]; diff --git a/src/Rules/DeadCode/UnusedPrivateConstantRule.php b/src/Rules/DeadCode/UnusedPrivateConstantRule.php index 88233438951..9036f249317 100644 --- a/src/Rules/DeadCode/UnusedPrivateConstantRule.php +++ b/src/Rules/DeadCode/UnusedPrivateConstantRule.php @@ -17,13 +17,8 @@ class UnusedPrivateConstantRule implements Rule { - /** - * @var AlwaysUsedClassConstantsExtensionProvider - */ - private $extensionProvider; - public function __construct(AlwaysUsedClassConstantsExtensionProvider $extensionProvider) + public function __construct(private AlwaysUsedClassConstantsExtensionProvider $extensionProvider) { - $this->extensionProvider = $extensionProvider; } public function getNodeType(): string diff --git a/src/Rules/DeadCode/UnusedPrivateMethodRule.php b/src/Rules/DeadCode/UnusedPrivateMethodRule.php index 11d29f1321b..9cce91220e0 100644 --- a/src/Rules/DeadCode/UnusedPrivateMethodRule.php +++ b/src/Rules/DeadCode/UnusedPrivateMethodRule.php @@ -74,9 +74,7 @@ public function processNode(Node $node, Scope $scope): array return []; } - $methodNames = array_map(static function (ConstantStringType $type) : string { - return $type->getValue(); - }, $strings); + $methodNames = array_map(static fn (ConstantStringType $type): string => $type->getValue(), $strings); } if ($methodCallNode instanceof Node\Expr\MethodCall) { diff --git a/src/Rules/DeadCode/UnusedPrivatePropertyRule.php b/src/Rules/DeadCode/UnusedPrivatePropertyRule.php index 9e8c71c507e..5f4ce6eef15 100644 --- a/src/Rules/DeadCode/UnusedPrivatePropertyRule.php +++ b/src/Rules/DeadCode/UnusedPrivatePropertyRule.php @@ -23,33 +23,19 @@ class UnusedPrivatePropertyRule implements Rule { - /** - * @var ReadWritePropertiesExtensionProvider - */ - private $extensionProvider; - /** - * @var string[] - */ - private $alwaysWrittenTags; - /** - * @var string[] - */ - private $alwaysReadTags; - /** - * @var bool - */ - private $checkUninitializedProperties; /** * @param string[] $alwaysWrittenTags * @param string[] $alwaysReadTags */ - public function __construct(ReadWritePropertiesExtensionProvider $extensionProvider, array $alwaysWrittenTags, array $alwaysReadTags, bool $checkUninitializedProperties) + public function __construct( + private ReadWritePropertiesExtensionProvider $extensionProvider, + private array $alwaysWrittenTags, + private array $alwaysReadTags, + private bool $checkUninitializedProperties, + ) { - $this->extensionProvider = $extensionProvider; - $this->alwaysWrittenTags = $alwaysWrittenTags; - $this->alwaysReadTags = $alwaysReadTags; - $this->checkUninitializedProperties = $checkUninitializedProperties; } + public function getNodeType(): string { return ClassPropertiesNode::class; @@ -137,9 +123,7 @@ public function processNode(Node $node, Scope $scope): array return []; } - $propertyNames = array_map(static function (ConstantStringType $type) : string { - return $type->getValue(); - }, $strings); + $propertyNames = array_map(static fn (ConstantStringType $type): string => $type->getValue(), $strings); } if ($fetch instanceof Node\Expr\PropertyFetch) { $fetchedOnType = $usage->getScope()->getType($fetch->var); diff --git a/src/Rules/Debug/DumpTypeRule.php b/src/Rules/Debug/DumpTypeRule.php index 3a87bd90de6..db1020b18a0 100644 --- a/src/Rules/Debug/DumpTypeRule.php +++ b/src/Rules/Debug/DumpTypeRule.php @@ -18,13 +18,8 @@ class DumpTypeRule implements Rule { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - public function __construct(ReflectionProvider $reflectionProvider) + public function __construct(private ReflectionProvider $reflectionProvider) { - $this->reflectionProvider = $reflectionProvider; } public function getNodeType(): string @@ -52,7 +47,12 @@ public function processNode(Node $node, Scope $scope): array } return [ - RuleErrorBuilder::message(sprintf('Dumped type: %s', $scope->getType($node->getArgs()[0]->value)->describe(VerbosityLevel::precise())))->nonIgnorable()->identifier('phpstan.dumpType')->build(), + RuleErrorBuilder::message( + sprintf( + 'Dumped type: %s', + $scope->getType($node->getArgs()[0]->value)->describe(VerbosityLevel::precise()), + ), + )->nonIgnorable()->identifier('phpstan.dumpType')->build(), ]; } diff --git a/src/Rules/Debug/FileAssertRule.php b/src/Rules/Debug/FileAssertRule.php index 1fe00be676e..e0899850c33 100644 --- a/src/Rules/Debug/FileAssertRule.php +++ b/src/Rules/Debug/FileAssertRule.php @@ -21,13 +21,8 @@ class FileAssertRule implements Rule { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - public function __construct(ReflectionProvider $reflectionProvider) + public function __construct(private ReflectionProvider $reflectionProvider) { - $this->reflectionProvider = $reflectionProvider; } public function getNodeType(): string diff --git a/src/Rules/DirectRegistry.php b/src/Rules/DirectRegistry.php index 6bf7d150dc3..7ee53824ee8 100644 --- a/src/Rules/DirectRegistry.php +++ b/src/Rules/DirectRegistry.php @@ -10,10 +10,10 @@ class DirectRegistry implements Registry { /** @var Rule[][] */ - private $rules = []; + private array $rules = []; /** @var Rule[][] */ - private $cache = []; + private array $cache = []; /** * @param Rule[] $rules diff --git a/src/Rules/EnumCases/EnumCaseAttributesRule.php b/src/Rules/EnumCases/EnumCaseAttributesRule.php index f1e9fc0ded3..8d584b72f6f 100644 --- a/src/Rules/EnumCases/EnumCaseAttributesRule.php +++ b/src/Rules/EnumCases/EnumCaseAttributesRule.php @@ -14,13 +14,8 @@ class EnumCaseAttributesRule implements Rule { - /** - * @var AttributesCheck - */ - private $attributesCheck; - public function __construct(AttributesCheck $attributesCheck) + public function __construct(private AttributesCheck $attributesCheck) { - $this->attributesCheck = $attributesCheck; } public function getNodeType(): string @@ -30,7 +25,12 @@ public function getNodeType(): string public function processNode(Node $node, Scope $scope): array { - return $this->attributesCheck->check($scope, $node->attrGroups, Attribute::TARGET_CLASS_CONSTANT, 'class constant'); + return $this->attributesCheck->check( + $scope, + $node->attrGroups, + Attribute::TARGET_CLASS_CONSTANT, + 'class constant', + ); } } diff --git a/src/Rules/Exceptions/CatchWithUnthrownExceptionRule.php b/src/Rules/Exceptions/CatchWithUnthrownExceptionRule.php index 300d5edf7bd..267d8c8200d 100644 --- a/src/Rules/Exceptions/CatchWithUnthrownExceptionRule.php +++ b/src/Rules/Exceptions/CatchWithUnthrownExceptionRule.php @@ -17,19 +17,13 @@ class CatchWithUnthrownExceptionRule implements Rule { - /** - * @var ExceptionTypeResolver - */ - private $exceptionTypeResolver; - /** - * @var bool - */ - private $reportUncheckedExceptionDeadCatch; - public function __construct(ExceptionTypeResolver $exceptionTypeResolver, bool $reportUncheckedExceptionDeadCatch) + public function __construct( + private ExceptionTypeResolver $exceptionTypeResolver, + private bool $reportUncheckedExceptionDeadCatch, + ) { - $this->exceptionTypeResolver = $exceptionTypeResolver; - $this->reportUncheckedExceptionDeadCatch = $reportUncheckedExceptionDeadCatch; } + public function getNodeType(): string { return CatchWithUnthrownExceptionNode::class; @@ -39,7 +33,9 @@ public function processNode(Node $node, Scope $scope): array { if ($node->getCaughtType() instanceof NeverType) { return [ - RuleErrorBuilder::message(sprintf('Dead catch - %s is already caught above.', $node->getOriginalCaughtType()->describe(VerbosityLevel::typeOnly()))) + RuleErrorBuilder::message( + sprintf('Dead catch - %s is already caught above.', $node->getOriginalCaughtType()->describe(VerbosityLevel::typeOnly())), + ) ->line($node->getStartLine()) ->identifier('catch.alreadyCaught') ->build(), @@ -61,7 +57,9 @@ public function processNode(Node $node, Scope $scope): array } return [ - RuleErrorBuilder::message(sprintf('Dead catch - %s is never thrown in the try block.', $node->getCaughtType()->describe(VerbosityLevel::typeOnly()))) + RuleErrorBuilder::message( + sprintf('Dead catch - %s is never thrown in the try block.', $node->getCaughtType()->describe(VerbosityLevel::typeOnly())), + ) ->line($node->getStartLine()) ->identifier('catch.neverThrown') ->build(), diff --git a/src/Rules/Exceptions/CaughtExceptionExistenceRule.php b/src/Rules/Exceptions/CaughtExceptionExistenceRule.php index c8731f8b716..620a75def15 100644 --- a/src/Rules/Exceptions/CaughtExceptionExistenceRule.php +++ b/src/Rules/Exceptions/CaughtExceptionExistenceRule.php @@ -20,24 +20,14 @@ class CaughtExceptionExistenceRule implements Rule { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - /** - * @var ClassCaseSensitivityCheck - */ - private $classCaseSensitivityCheck; - /** - * @var bool - */ - private $checkClassCaseSensitivity; - public function __construct(ReflectionProvider $reflectionProvider, ClassCaseSensitivityCheck $classCaseSensitivityCheck, bool $checkClassCaseSensitivity) + public function __construct( + private ReflectionProvider $reflectionProvider, + private ClassCaseSensitivityCheck $classCaseSensitivityCheck, + private bool $checkClassCaseSensitivity, + ) { - $this->reflectionProvider = $reflectionProvider; - $this->classCaseSensitivityCheck = $classCaseSensitivityCheck; - $this->checkClassCaseSensitivity = $checkClassCaseSensitivity; } + public function getNodeType(): string { return Catch_::class; @@ -72,7 +62,10 @@ public function processNode(Node $node, Scope $scope): array continue; } - $errors = array_merge($errors, $this->classCaseSensitivityCheck->checkClassNames([new ClassNameNodePair($className, $class)])); + $errors = array_merge( + $errors, + $this->classCaseSensitivityCheck->checkClassNames([new ClassNameNodePair($className, $class)]), + ); } return $errors; diff --git a/src/Rules/Exceptions/DefaultExceptionTypeResolver.php b/src/Rules/Exceptions/DefaultExceptionTypeResolver.php index a12f1ea29b3..cdb62d25973 100644 --- a/src/Rules/Exceptions/DefaultExceptionTypeResolver.php +++ b/src/Rules/Exceptions/DefaultExceptionTypeResolver.php @@ -11,40 +11,22 @@ class DefaultExceptionTypeResolver implements ExceptionTypeResolver { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - /** - * @var string[] - */ - private $uncheckedExceptionRegexes; - /** - * @var string[] - */ - private $uncheckedExceptionClasses; - /** - * @var string[] - */ - private $checkedExceptionRegexes; - /** - * @var string[] - */ - private $checkedExceptionClasses; /** * @param string[] $uncheckedExceptionRegexes * @param string[] $uncheckedExceptionClasses * @param string[] $checkedExceptionRegexes * @param string[] $checkedExceptionClasses */ - public function __construct(ReflectionProvider $reflectionProvider, array $uncheckedExceptionRegexes, array $uncheckedExceptionClasses, array $checkedExceptionRegexes, array $checkedExceptionClasses) + public function __construct( + private ReflectionProvider $reflectionProvider, + private array $uncheckedExceptionRegexes, + private array $uncheckedExceptionClasses, + private array $checkedExceptionRegexes, + private array $checkedExceptionClasses, + ) { - $this->reflectionProvider = $reflectionProvider; - $this->uncheckedExceptionRegexes = $uncheckedExceptionRegexes; - $this->uncheckedExceptionClasses = $uncheckedExceptionClasses; - $this->checkedExceptionRegexes = $checkedExceptionRegexes; - $this->checkedExceptionClasses = $checkedExceptionClasses; } + public function isCheckedException(string $className, Scope $scope): bool { foreach ($this->uncheckedExceptionRegexes as $regex) { diff --git a/src/Rules/Exceptions/MissingCheckedExceptionInFunctionThrowsRule.php b/src/Rules/Exceptions/MissingCheckedExceptionInFunctionThrowsRule.php index 960c1bb02bf..e2ee44c4662 100644 --- a/src/Rules/Exceptions/MissingCheckedExceptionInFunctionThrowsRule.php +++ b/src/Rules/Exceptions/MissingCheckedExceptionInFunctionThrowsRule.php @@ -15,13 +15,8 @@ class MissingCheckedExceptionInFunctionThrowsRule implements Rule { - /** - * @var MissingCheckedExceptionInThrowsCheck - */ - private $check; - public function __construct(MissingCheckedExceptionInThrowsCheck $check) + public function __construct(private MissingCheckedExceptionInThrowsCheck $check) { - $this->check = $check; } public function getNodeType(): string @@ -36,7 +31,11 @@ public function processNode(Node $node, Scope $scope): array $errors = []; foreach ($this->check->check($functionReflection->getThrowType(), $statementResult->getThrowPoints()) as [$className, $throwPointNode]) { - $errors[] = RuleErrorBuilder::message(sprintf('Function %s() throws checked exception %s but it\'s missing from the PHPDoc @throws tag.', $functionReflection->getName(), $className)) + $errors[] = RuleErrorBuilder::message(sprintf( + 'Function %s() throws checked exception %s but it\'s missing from the PHPDoc @throws tag.', + $functionReflection->getName(), + $className, + )) ->line($throwPointNode->getStartLine()) ->identifier('missingType.checkedException') ->build(); diff --git a/src/Rules/Exceptions/MissingCheckedExceptionInMethodThrowsRule.php b/src/Rules/Exceptions/MissingCheckedExceptionInMethodThrowsRule.php index 895ecbb9140..2aae5d488c9 100644 --- a/src/Rules/Exceptions/MissingCheckedExceptionInMethodThrowsRule.php +++ b/src/Rules/Exceptions/MissingCheckedExceptionInMethodThrowsRule.php @@ -15,13 +15,8 @@ class MissingCheckedExceptionInMethodThrowsRule implements Rule { - /** - * @var MissingCheckedExceptionInThrowsCheck - */ - private $check; - public function __construct(MissingCheckedExceptionInThrowsCheck $check) + public function __construct(private MissingCheckedExceptionInThrowsCheck $check) { - $this->check = $check; } public function getNodeType(): string @@ -36,7 +31,12 @@ public function processNode(Node $node, Scope $scope): array $errors = []; foreach ($this->check->check($methodReflection->getThrowType(), $statementResult->getThrowPoints()) as [$className, $throwPointNode]) { - $errors[] = RuleErrorBuilder::message(sprintf('Method %s::%s() throws checked exception %s but it\'s missing from the PHPDoc @throws tag.', $methodReflection->getDeclaringClass()->getDisplayName(), $methodReflection->getName(), $className)) + $errors[] = RuleErrorBuilder::message(sprintf( + 'Method %s::%s() throws checked exception %s but it\'s missing from the PHPDoc @throws tag.', + $methodReflection->getDeclaringClass()->getDisplayName(), + $methodReflection->getName(), + $className, + )) ->line($throwPointNode->getStartLine()) ->identifier('missingType.checkedException') ->build(); diff --git a/src/Rules/Exceptions/MissingCheckedExceptionInThrowsCheck.php b/src/Rules/Exceptions/MissingCheckedExceptionInThrowsCheck.php index d0ac13a37f8..508214f275e 100644 --- a/src/Rules/Exceptions/MissingCheckedExceptionInThrowsCheck.php +++ b/src/Rules/Exceptions/MissingCheckedExceptionInThrowsCheck.php @@ -15,13 +15,8 @@ class MissingCheckedExceptionInThrowsCheck { - /** - * @var ExceptionTypeResolver - */ - private $exceptionTypeResolver; - public function __construct(ExceptionTypeResolver $exceptionTypeResolver) + public function __construct(private ExceptionTypeResolver $exceptionTypeResolver) { - $this->exceptionTypeResolver = $exceptionTypeResolver; } /** @@ -48,9 +43,10 @@ public function check(?Type $throwType, array $throwPoints): array continue; } - $isCheckedException = TrinaryLogic::createNo()->lazyOr($throwPointType->getObjectClassNames(), function (string $objectClassName) use($throwPoint) { - return TrinaryLogic::createFromBoolean($this->exceptionTypeResolver->isCheckedException($objectClassName, $throwPoint->getScope())); - }); + $isCheckedException = TrinaryLogic::createNo()->lazyOr( + $throwPointType->getObjectClassNames(), + fn (string $objectClassName) => TrinaryLogic::createFromBoolean($this->exceptionTypeResolver->isCheckedException($objectClassName, $throwPoint->getScope())), + ); if ($isCheckedException->no()) { continue; } diff --git a/src/Rules/Exceptions/NoncapturingCatchRule.php b/src/Rules/Exceptions/NoncapturingCatchRule.php index 5ba27812163..d91bf2fc142 100644 --- a/src/Rules/Exceptions/NoncapturingCatchRule.php +++ b/src/Rules/Exceptions/NoncapturingCatchRule.php @@ -14,13 +14,8 @@ class NoncapturingCatchRule implements Rule { - /** - * @var PhpVersion - */ - private $phpVersion; - public function __construct(PhpVersion $phpVersion) + public function __construct(private PhpVersion $phpVersion) { - $this->phpVersion = $phpVersion; } public function getNodeType(): string diff --git a/src/Rules/Exceptions/ThrowExprTypeRule.php b/src/Rules/Exceptions/ThrowExprTypeRule.php index 5b30b1ab6ea..85f648ab971 100644 --- a/src/Rules/Exceptions/ThrowExprTypeRule.php +++ b/src/Rules/Exceptions/ThrowExprTypeRule.php @@ -20,14 +20,12 @@ class ThrowExprTypeRule implements Rule { - /** - * @var RuleLevelHelper - */ - private $ruleLevelHelper; - public function __construct(RuleLevelHelper $ruleLevelHelper) + public function __construct( + private RuleLevelHelper $ruleLevelHelper, + ) { - $this->ruleLevelHelper = $ruleLevelHelper; } + public function getNodeType(): string { return Node\Expr\Throw_::class; @@ -36,9 +34,12 @@ public function getNodeType(): string public function processNode(Node $node, Scope $scope): array { $throwableType = new ObjectType(Throwable::class); - $typeResult = $this->ruleLevelHelper->findTypeToCheck($scope, $node->expr, 'Throwing object of an unknown class %s.', static function (Type $type) use($throwableType) : bool { - return $throwableType->isSuperTypeOf($type)->yes(); - }); + $typeResult = $this->ruleLevelHelper->findTypeToCheck( + $scope, + $node->expr, + 'Throwing object of an unknown class %s.', + static fn (Type $type): bool => $throwableType->isSuperTypeOf($type)->yes(), + ); $foundType = $typeResult->getType(); if ($foundType instanceof ErrorType) { @@ -51,7 +52,10 @@ public function processNode(Node $node, Scope $scope): array } return [ - RuleErrorBuilder::message(sprintf('Invalid type %s to throw.', $foundType->describe(VerbosityLevel::typeOnly())))->identifier('throw.notThrowable')->build(), + RuleErrorBuilder::message(sprintf( + 'Invalid type %s to throw.', + $foundType->describe(VerbosityLevel::typeOnly()), + ))->identifier('throw.notThrowable')->build(), ]; } diff --git a/src/Rules/Exceptions/ThrowExpressionRule.php b/src/Rules/Exceptions/ThrowExpressionRule.php index 99782c76179..d9b5655ff6d 100644 --- a/src/Rules/Exceptions/ThrowExpressionRule.php +++ b/src/Rules/Exceptions/ThrowExpressionRule.php @@ -14,13 +14,8 @@ class ThrowExpressionRule implements Rule { - /** - * @var PhpVersion - */ - private $phpVersion; - public function __construct(PhpVersion $phpVersion) + public function __construct(private PhpVersion $phpVersion) { - $this->phpVersion = $phpVersion; } public function getNodeType(): string diff --git a/src/Rules/Exceptions/ThrowsVoidFunctionWithExplicitThrowPointRule.php b/src/Rules/Exceptions/ThrowsVoidFunctionWithExplicitThrowPointRule.php index 8316da262ef..f07d6dc5c07 100644 --- a/src/Rules/Exceptions/ThrowsVoidFunctionWithExplicitThrowPointRule.php +++ b/src/Rules/Exceptions/ThrowsVoidFunctionWithExplicitThrowPointRule.php @@ -18,19 +18,13 @@ class ThrowsVoidFunctionWithExplicitThrowPointRule implements Rule { - /** - * @var ExceptionTypeResolver - */ - private $exceptionTypeResolver; - /** - * @var bool - */ - private $missingCheckedExceptionInThrows; - public function __construct(ExceptionTypeResolver $exceptionTypeResolver, bool $missingCheckedExceptionInThrows) + public function __construct( + private ExceptionTypeResolver $exceptionTypeResolver, + private bool $missingCheckedExceptionInThrows, + ) { - $this->exceptionTypeResolver = $exceptionTypeResolver; - $this->missingCheckedExceptionInThrows = $missingCheckedExceptionInThrows; } + public function getNodeType(): string { return FunctionReturnStatementsNode::class; @@ -52,14 +46,19 @@ public function processNode(Node $node, Scope $scope): array } foreach (TypeUtils::flattenTypes($throwPoint->getType()) as $throwPointType) { - $isCheckedException = TrinaryLogic::createFromBoolean($this->missingCheckedExceptionInThrows)->lazyAnd($throwPointType->getObjectClassNames(), function (string $objectClassName) use($throwPoint) { - return TrinaryLogic::createFromBoolean($this->exceptionTypeResolver->isCheckedException($objectClassName, $throwPoint->getScope())); - }); + $isCheckedException = TrinaryLogic::createFromBoolean($this->missingCheckedExceptionInThrows)->lazyAnd( + $throwPointType->getObjectClassNames(), + fn (string $objectClassName) => TrinaryLogic::createFromBoolean($this->exceptionTypeResolver->isCheckedException($objectClassName, $throwPoint->getScope())), + ); if ($isCheckedException->yes()) { continue; } - $errors[] = RuleErrorBuilder::message(sprintf('Function %s() throws exception %s but the PHPDoc contains @throws void.', $functionReflection->getName(), $throwPointType->describe(VerbosityLevel::typeOnly()))) + $errors[] = RuleErrorBuilder::message(sprintf( + 'Function %s() throws exception %s but the PHPDoc contains @throws void.', + $functionReflection->getName(), + $throwPointType->describe(VerbosityLevel::typeOnly()), + )) ->line($throwPoint->getNode()->getStartLine()) ->identifier('throws.void') ->build(); diff --git a/src/Rules/Exceptions/ThrowsVoidMethodWithExplicitThrowPointRule.php b/src/Rules/Exceptions/ThrowsVoidMethodWithExplicitThrowPointRule.php index d0074f21b09..59c0bd84486 100644 --- a/src/Rules/Exceptions/ThrowsVoidMethodWithExplicitThrowPointRule.php +++ b/src/Rules/Exceptions/ThrowsVoidMethodWithExplicitThrowPointRule.php @@ -18,19 +18,13 @@ class ThrowsVoidMethodWithExplicitThrowPointRule implements Rule { - /** - * @var ExceptionTypeResolver - */ - private $exceptionTypeResolver; - /** - * @var bool - */ - private $missingCheckedExceptionInThrows; - public function __construct(ExceptionTypeResolver $exceptionTypeResolver, bool $missingCheckedExceptionInThrows) + public function __construct( + private ExceptionTypeResolver $exceptionTypeResolver, + private bool $missingCheckedExceptionInThrows, + ) { - $this->exceptionTypeResolver = $exceptionTypeResolver; - $this->missingCheckedExceptionInThrows = $missingCheckedExceptionInThrows; } + public function getNodeType(): string { return MethodReturnStatementsNode::class; @@ -52,14 +46,20 @@ public function processNode(Node $node, Scope $scope): array } foreach (TypeUtils::flattenTypes($throwPoint->getType()) as $throwPointType) { - $isCheckedException = TrinaryLogic::createFromBoolean($this->missingCheckedExceptionInThrows)->lazyAnd($throwPointType->getObjectClassNames(), function (string $objectClassName) use($throwPoint) { - return TrinaryLogic::createFromBoolean($this->exceptionTypeResolver->isCheckedException($objectClassName, $throwPoint->getScope())); - }); + $isCheckedException = TrinaryLogic::createFromBoolean($this->missingCheckedExceptionInThrows)->lazyAnd( + $throwPointType->getObjectClassNames(), + fn (string $objectClassName) => TrinaryLogic::createFromBoolean($this->exceptionTypeResolver->isCheckedException($objectClassName, $throwPoint->getScope())), + ); if ($isCheckedException->yes()) { continue; } - $errors[] = RuleErrorBuilder::message(sprintf('Method %s::%s() throws exception %s but the PHPDoc contains @throws void.', $methodReflection->getDeclaringClass()->getDisplayName(), $methodReflection->getName(), $throwPointType->describe(VerbosityLevel::typeOnly()))) + $errors[] = RuleErrorBuilder::message(sprintf( + 'Method %s::%s() throws exception %s but the PHPDoc contains @throws void.', + $methodReflection->getDeclaringClass()->getDisplayName(), + $methodReflection->getName(), + $throwPointType->describe(VerbosityLevel::typeOnly()), + )) ->line($throwPoint->getNode()->getStartLine()) ->identifier('throws.void') ->build(); diff --git a/src/Rules/Exceptions/TooWideFunctionThrowTypeRule.php b/src/Rules/Exceptions/TooWideFunctionThrowTypeRule.php index 112b732a790..e7f7f9849e4 100644 --- a/src/Rules/Exceptions/TooWideFunctionThrowTypeRule.php +++ b/src/Rules/Exceptions/TooWideFunctionThrowTypeRule.php @@ -15,13 +15,8 @@ class TooWideFunctionThrowTypeRule implements Rule { - /** - * @var TooWideThrowTypeCheck - */ - private $check; - public function __construct(TooWideThrowTypeCheck $check) + public function __construct(private TooWideThrowTypeCheck $check) { - $this->check = $check; } public function getNodeType(): string @@ -41,7 +36,11 @@ public function processNode(Node $node, Scope $scope): array $errors = []; foreach ($this->check->check($throwType, $statementResult->getThrowPoints()) as $throwClass) { - $errors[] = RuleErrorBuilder::message(sprintf('Function %s() has %s in PHPDoc @throws tag but it\'s not thrown.', $functionReflection->getName(), $throwClass)) + $errors[] = RuleErrorBuilder::message(sprintf( + 'Function %s() has %s in PHPDoc @throws tag but it\'s not thrown.', + $functionReflection->getName(), + $throwClass, + )) ->identifier('throws.unusedType') ->build(); } diff --git a/src/Rules/Exceptions/TooWideMethodThrowTypeRule.php b/src/Rules/Exceptions/TooWideMethodThrowTypeRule.php index 384d341ceb5..c9a5f231b6c 100644 --- a/src/Rules/Exceptions/TooWideMethodThrowTypeRule.php +++ b/src/Rules/Exceptions/TooWideMethodThrowTypeRule.php @@ -16,18 +16,8 @@ class TooWideMethodThrowTypeRule implements Rule { - /** - * @var FileTypeMapper - */ - private $fileTypeMapper; - /** - * @var TooWideThrowTypeCheck - */ - private $check; - public function __construct(FileTypeMapper $fileTypeMapper, TooWideThrowTypeCheck $check) + public function __construct(private FileTypeMapper $fileTypeMapper, private TooWideThrowTypeCheck $check) { - $this->fileTypeMapper = $fileTypeMapper; - $this->check = $check; } public function getNodeType(): string @@ -45,7 +35,13 @@ public function processNode(Node $node, Scope $scope): array $statementResult = $node->getStatementResult(); $methodReflection = $node->getMethodReflection(); $classReflection = $node->getClassReflection(); - $resolvedPhpDoc = $this->fileTypeMapper->getResolvedPhpDoc($scope->getFile(), $classReflection->getName(), $scope->isInTrait() ? $scope->getTraitReflection()->getName() : null, $methodReflection->getName(), $docComment->getText()); + $resolvedPhpDoc = $this->fileTypeMapper->getResolvedPhpDoc( + $scope->getFile(), + $classReflection->getName(), + $scope->isInTrait() ? $scope->getTraitReflection()->getName() : null, + $methodReflection->getName(), + $docComment->getText(), + ); if ($resolvedPhpDoc->getThrowsTag() === null) { return []; @@ -55,7 +51,12 @@ public function processNode(Node $node, Scope $scope): array $errors = []; foreach ($this->check->check($throwType, $statementResult->getThrowPoints()) as $throwClass) { - $errors[] = RuleErrorBuilder::message(sprintf('Method %s::%s() has %s in PHPDoc @throws tag but it\'s not thrown.', $methodReflection->getDeclaringClass()->getDisplayName(), $methodReflection->getName(), $throwClass)) + $errors[] = RuleErrorBuilder::message(sprintf( + 'Method %s::%s() has %s in PHPDoc @throws tag but it\'s not thrown.', + $methodReflection->getDeclaringClass()->getDisplayName(), + $methodReflection->getName(), + $throwClass, + )) ->identifier('throws.unusedType') ->build(); } diff --git a/src/Rules/FoundTypeResult.php b/src/Rules/FoundTypeResult.php index 1aa77cc799f..be17a4c76cc 100644 --- a/src/Rules/FoundTypeResult.php +++ b/src/Rules/FoundTypeResult.php @@ -8,33 +8,19 @@ class FoundTypeResult { - /** - * @var Type - */ - private $type; - /** - * @var string[] - */ - private $referencedClasses; - /** - * @var list - */ - private $unknownClassErrors; - /** - * @var ?string - */ - private $tip; /** * @param string[] $referencedClasses * @param list $unknownClassErrors */ - public function __construct(Type $type, array $referencedClasses, array $unknownClassErrors, ?string $tip) + public function __construct( + private Type $type, + private array $referencedClasses, + private array $unknownClassErrors, + private ?string $tip, + ) { - $this->type = $type; - $this->referencedClasses = $referencedClasses; - $this->unknownClassErrors = $unknownClassErrors; - $this->tip = $tip; } + public function getType(): Type { return $this->type; diff --git a/src/Rules/FunctionCallParametersCheck.php b/src/Rules/FunctionCallParametersCheck.php index 7c94cb8cd4f..4d4a29c7137 100644 --- a/src/Rules/FunctionCallParametersCheck.php +++ b/src/Rules/FunctionCallParametersCheck.php @@ -32,505 +32,548 @@ class FunctionCallParametersCheck { - /** - * @var RuleLevelHelper - */ - private $ruleLevelHelper; - /** - * @var NullsafeCheck - */ - private $nullsafeCheck; - /** - * @var PhpVersion - */ - private $phpVersion; - /** - * @var UnresolvableTypeHelper - */ - private $unresolvableTypeHelper; - /** - * @var PropertyReflectionFinder - */ - private $propertyReflectionFinder; - /** - * @var bool - */ - private $checkArgumentTypes; - /** - * @var bool - */ - private $checkArgumentsPassedByReference; - /** - * @var bool - */ - private $checkExtraArguments; - /** - * @var bool - */ - private $checkMissingTypehints; - /** - * @var bool - */ - private $checkUnresolvableParameterTypes; - public function __construct(RuleLevelHelper $ruleLevelHelper, NullsafeCheck $nullsafeCheck, PhpVersion $phpVersion, UnresolvableTypeHelper $unresolvableTypeHelper, PropertyReflectionFinder $propertyReflectionFinder, bool $checkArgumentTypes, bool $checkArgumentsPassedByReference, bool $checkExtraArguments, bool $checkMissingTypehints, bool $checkUnresolvableParameterTypes) - { - $this->ruleLevelHelper = $ruleLevelHelper; - $this->nullsafeCheck = $nullsafeCheck; - $this->phpVersion = $phpVersion; - $this->unresolvableTypeHelper = $unresolvableTypeHelper; - $this->propertyReflectionFinder = $propertyReflectionFinder; - $this->checkArgumentTypes = $checkArgumentTypes; - $this->checkArgumentsPassedByReference = $checkArgumentsPassedByReference; - $this->checkExtraArguments = $checkExtraArguments; - $this->checkMissingTypehints = $checkMissingTypehints; - $this->checkUnresolvableParameterTypes = $checkUnresolvableParameterTypes; + + public function __construct( + private RuleLevelHelper $ruleLevelHelper, + private NullsafeCheck $nullsafeCheck, + private PhpVersion $phpVersion, + private UnresolvableTypeHelper $unresolvableTypeHelper, + private PropertyReflectionFinder $propertyReflectionFinder, + private bool $checkArgumentTypes, + private bool $checkArgumentsPassedByReference, + private bool $checkExtraArguments, + private bool $checkMissingTypehints, + private bool $checkUnresolvableParameterTypes, + ) + { + } + + /** + * @param Node\Expr\FuncCall|Node\Expr\MethodCall|Node\Expr\StaticCall|Node\Expr\New_ $funcCall + * @param array{0: string, 1: string, 2: string, 3: string, 4: string, 5: string, 6: string, 7: string, 8: string, 9: string, 10: string, 11: string, 12: string, 13?: string} $messages + * @param 'attribute'|'callable'|'method'|'staticMethod'|'function'|'new' $nodeType + * @return list + */ + public function check( + ParametersAcceptor $parametersAcceptor, + Scope $scope, + bool $isBuiltin, + $funcCall, + array $messages, + string $nodeType = 'function', + ): array + { + $functionParametersMinCount = 0; + $functionParametersMaxCount = 0; + foreach ($parametersAcceptor->getParameters() as $parameter) { + if (!$parameter->isOptional()) { + $functionParametersMinCount++; + } + + $functionParametersMaxCount++; + } + + if ($parametersAcceptor->isVariadic()) { + $functionParametersMaxCount = -1; + } + + /** @var array $arguments */ + $arguments = []; + /** @var array $args */ + $args = $funcCall->getArgs(); + $hasNamedArguments = false; + $hasUnpackedArgument = false; + $errors = []; + foreach ($args as $i => $arg) { + $type = $scope->getType($arg->value); + if ($hasNamedArguments && $arg->unpack) { + $errors[] = RuleErrorBuilder::message('Named argument cannot be followed by an unpacked (...) argument.') + ->identifier('argument.unpackAfterNamed') + ->line($arg->getStartLine()) + ->nonIgnorable() + ->build(); + } + if ($hasUnpackedArgument && !$arg->unpack) { + $errors[] = RuleErrorBuilder::message('Unpacked argument (...) cannot be followed by a non-unpacked argument.') + ->identifier('argument.nonUnpackAfterUnpacked') + ->line($arg->getStartLine()) + ->nonIgnorable() + ->build(); + } + if ($arg->unpack) { + $hasUnpackedArgument = true; + } + $argumentName = null; + if ($arg->name !== null) { + $hasNamedArguments = true; + $argumentName = $arg->name->toString(); + } + if ($arg->unpack) { + $arrays = $type->getConstantArrays(); + if (count($arrays) > 0) { + $minKeys = null; + foreach ($arrays as $array) { + $countType = $array->getArraySize(); + if ($countType instanceof ConstantIntegerType) { + $keysCount = $countType->getValue(); + } elseif ($countType instanceof IntegerRangeType) { + $keysCount = $countType->getMin(); + if ($keysCount === null) { + throw new ShouldNotHappenException(); + } + } else { + throw new ShouldNotHappenException(); + } + if ($minKeys !== null && $keysCount >= $minKeys) { + continue; + } + + $minKeys = $keysCount; + } + + for ($j = 0; $j < $minKeys; $j++) { + $types = []; + $commonKey = null; + foreach ($arrays as $constantArray) { + $types[] = $constantArray->getValueTypes()[$j]; + $keyType = $constantArray->getKeyTypes()[$j]; + if ($commonKey === null) { + $commonKey = $keyType->getValue(); + } elseif ($commonKey !== $keyType->getValue()) { + $commonKey = false; + } + } + $keyArgumentName = null; + if (is_string($commonKey)) { + $keyArgumentName = $commonKey; + $hasNamedArguments = true; + } + $arguments[] = [ + $arg->value, + TypeCombinator::union(...$types), + false, + $keyArgumentName, + $arg->getStartLine(), + ]; + } + } else { + $arguments[] = [ + $arg->value, + $type->getIterableValueType(), + true, + null, + $arg->getStartLine(), + ]; + } + continue; + } + + $arguments[] = [ + $arg->value, + $type, + false, + $argumentName, + $arg->getStartLine(), + ]; + } + + if ($hasNamedArguments && !$this->phpVersion->supportsNamedArguments() && !(bool) $funcCall->getAttribute('isAttribute', false)) { + $errors[] = RuleErrorBuilder::message('Named arguments are supported only on PHP 8.0 and later.') + ->identifier('argument.namedNotSupported') + ->line($funcCall->getStartLine()) + ->nonIgnorable() + ->build(); + } + + if (!$hasNamedArguments) { + $invokedParametersCount = count($arguments); + foreach ($arguments as $i => [$argumentValue, $argumentValueType, $unpack, $argumentName]) { + if ($unpack) { + $invokedParametersCount = max($functionParametersMinCount, $functionParametersMaxCount); + break; + } + } + + if ( + $invokedParametersCount < $functionParametersMinCount + || ($this->checkExtraArguments && $invokedParametersCount > $functionParametersMaxCount) + ) { + if ($functionParametersMinCount === $functionParametersMaxCount) { + $errors[] = RuleErrorBuilder::message(sprintf( + $invokedParametersCount === 1 ? $messages[0] : $messages[1], + $invokedParametersCount, + $functionParametersMinCount, + )) + ->identifier('arguments.count') + ->line($funcCall->getStartLine()) + ->build(); + } elseif ($functionParametersMaxCount === -1 && $invokedParametersCount < $functionParametersMinCount) { + $errors[] = RuleErrorBuilder::message(sprintf( + $invokedParametersCount === 1 ? $messages[2] : $messages[3], + $invokedParametersCount, + $functionParametersMinCount, + )) + ->identifier('arguments.count') + ->line($funcCall->getStartLine()) + ->build(); + } elseif ($functionParametersMaxCount !== -1) { + $errors[] = RuleErrorBuilder::message(sprintf( + $invokedParametersCount === 1 ? $messages[4] : $messages[5], + $invokedParametersCount, + $functionParametersMinCount, + $functionParametersMaxCount, + )) + ->identifier('arguments.count') + ->line($funcCall->getStartLine()) + ->build(); + } + } + } + + if ( + !$funcCall instanceof Node\Expr\New_ + && !$scope->isInFirstLevelStatement() + && $scope->getKeepVoidType($funcCall)->isVoid()->yes() + ) { + $errors[] = RuleErrorBuilder::message($messages[7]) + ->identifier(sprintf('%s.void', $nodeType)) + ->line($funcCall->getStartLine()) + ->build(); + } + + [$addedErrors, $argumentsWithParameters] = $this->processArguments($parametersAcceptor, $funcCall->getStartLine(), $isBuiltin, $arguments, $hasNamedArguments, $messages[10], $messages[11]); + foreach ($addedErrors as $error) { + $errors[] = $error; + } + + if (!$this->checkArgumentTypes && !$this->checkArgumentsPassedByReference) { + return $errors; + } + + foreach ($argumentsWithParameters as $i => [$argumentValue, $argumentValueType, $unpack, $argumentName, $argumentLine, $parameter, $originalParameter]) { + if ($this->checkArgumentTypes && $unpack) { + $iterableTypeResult = $this->ruleLevelHelper->findTypeToCheck( + $scope, + $argumentValue, + '', + static fn (Type $type): bool => $type->isIterable()->yes(), + ); + $iterableTypeResultType = $iterableTypeResult->getType(); + if ( + !$iterableTypeResultType instanceof ErrorType + && !$iterableTypeResultType->isIterable()->yes() + ) { + $errors[] = RuleErrorBuilder::message(sprintf( + 'Only iterables can be unpacked, %s given in argument #%d.', + $iterableTypeResultType->describe(VerbosityLevel::typeOnly()), + $i + 1, + ))->identifier('argument.unpackNonIterable')->line($argumentLine)->build(); + } + } + + if ($parameter === null) { + continue; + } + + if ($this->checkArgumentTypes) { + $parameterType = TypeUtils::resolveLateResolvableTypes($parameter->getType()); + + if (!$parameter->passedByReference()->createsNewVariable()) { + $accepts = $this->ruleLevelHelper->acceptsWithReason($parameterType, $argumentValueType, $scope->isDeclareStrictTypes()); + + if (!$accepts->result) { + $verbosityLevel = VerbosityLevel::getRecommendedLevelByType($parameterType, $argumentValueType); + $parameterDescription = sprintf('%s$%s', $parameter->isVariadic() ? '...' : '', $parameter->getName()); + $errors[] = RuleErrorBuilder::message(sprintf( + $messages[6], + $argumentName === null ? sprintf( + '#%d %s', + $i + 1, + $parameterDescription, + ) : $parameterDescription, + $parameterType->describe($verbosityLevel), + $argumentValueType->describe($verbosityLevel), + )) + ->identifier('argument.type') + ->line($argumentLine) + ->acceptsReasonsTip($accepts->reasons) + ->build(); + } } - /** - * @param Node\Expr\FuncCall|Node\Expr\MethodCall|Node\Expr\StaticCall|Node\Expr\New_ $funcCall - * @param array{0: string, 1: string, 2: string, 3: string, 4: string, 5: string, 6: string, 7: string, 8: string, 9: string, 10: string, 11: string, 12: string, 13?: string} $messages - * @param 'attribute'|'callable'|'method'|'staticMethod'|'function'|'new' $nodeType - * @return list - */ - public function check(ParametersAcceptor $parametersAcceptor, Scope $scope, bool $isBuiltin, $funcCall, array $messages, string $nodeType = 'function') : array - { - $functionParametersMinCount = 0; - $functionParametersMaxCount = 0; - foreach ($parametersAcceptor->getParameters() as $parameter) { - if (!$parameter->isOptional()) { - $functionParametersMinCount++; - } - - $functionParametersMaxCount++; - } - if ($parametersAcceptor->isVariadic()) { - $functionParametersMaxCount = -1; - } - /** @var array $arguments */ - $arguments = []; - /** @var array $args */ - $args = $funcCall->getArgs(); - $hasNamedArguments = false; - $hasUnpackedArgument = false; - $errors = []; - foreach ($args as $i => $arg) { - $type = $scope->getType($arg->value); - if ($hasNamedArguments && $arg->unpack) { - $errors[] = RuleErrorBuilder::message('Named argument cannot be followed by an unpacked (...) argument.') - ->identifier('argument.unpackAfterNamed') - ->line($arg->getStartLine()) - ->nonIgnorable() - ->build(); - } - if ($hasUnpackedArgument && !$arg->unpack) { - $errors[] = RuleErrorBuilder::message('Unpacked argument (...) cannot be followed by a non-unpacked argument.') - ->identifier('argument.nonUnpackAfterUnpacked') - ->line($arg->getStartLine()) - ->nonIgnorable() - ->build(); - } - if ($arg->unpack) { - $hasUnpackedArgument = true; - } - $argumentName = null; - if ($arg->name !== null) { - $hasNamedArguments = true; - $argumentName = $arg->name->toString(); - } - if ($arg->unpack) { - $arrays = $type->getConstantArrays(); - if (count($arrays) > 0) { - $minKeys = null; - foreach ($arrays as $array) { - $countType = $array->getArraySize(); - if ($countType instanceof ConstantIntegerType) { - $keysCount = $countType->getValue(); - } elseif ($countType instanceof IntegerRangeType) { - $keysCount = $countType->getMin(); - if ($keysCount === null) { - throw new ShouldNotHappenException(); - } - } else { - throw new ShouldNotHappenException(); - } - if ($minKeys !== null && $keysCount >= $minKeys) { - continue; - } - - $minKeys = $keysCount; - } - - for ($j = 0; $j < $minKeys; $j++) { - $types = []; - $commonKey = null; - foreach ($arrays as $constantArray) { - $types[] = $constantArray->getValueTypes()[$j]; - $keyType = $constantArray->getKeyTypes()[$j]; - if ($commonKey === null) { - $commonKey = $keyType->getValue(); - } elseif ($commonKey !== $keyType->getValue()) { - $commonKey = false; - } - } - $keyArgumentName = null; - if (is_string($commonKey)) { - $keyArgumentName = $commonKey; - $hasNamedArguments = true; - } - $arguments[] = [ - $arg->value, - TypeCombinator::union(...$types), - false, - $keyArgumentName, - $arg->getStartLine(), - ]; - } - } else { - $arguments[] = [ - $arg->value, - $type->getIterableValueType(), - true, - null, - $arg->getStartLine(), - ]; - } - continue; - } - - $arguments[] = [ - $arg->value, - $type, - false, - $argumentName, - $arg->getStartLine(), - ]; - } - if ($hasNamedArguments && !$this->phpVersion->supportsNamedArguments() && !(bool) $funcCall->getAttribute('isAttribute', false)) { - $errors[] = RuleErrorBuilder::message('Named arguments are supported only on PHP 8.0 and later.') - ->identifier('argument.namedNotSupported') - ->line($funcCall->getStartLine()) - ->nonIgnorable() - ->build(); - } - if (!$hasNamedArguments) { - $invokedParametersCount = count($arguments); - foreach ($arguments as $i => [$argumentValue, $argumentValueType, $unpack, $argumentName]) { - if ($unpack) { - $invokedParametersCount = max($functionParametersMinCount, $functionParametersMaxCount); - break; - } - } - - if ( - $invokedParametersCount < $functionParametersMinCount - || ($this->checkExtraArguments && $invokedParametersCount > $functionParametersMaxCount) - ) { - if ($functionParametersMinCount === $functionParametersMaxCount) { - $errors[] = RuleErrorBuilder::message(sprintf($invokedParametersCount === 1 ? $messages[0] : $messages[1], $invokedParametersCount, $functionParametersMinCount)) - ->identifier('arguments.count') - ->line($funcCall->getStartLine()) - ->build(); - } elseif ($functionParametersMaxCount === -1 && $invokedParametersCount < $functionParametersMinCount) { - $errors[] = RuleErrorBuilder::message(sprintf($invokedParametersCount === 1 ? $messages[2] : $messages[3], $invokedParametersCount, $functionParametersMinCount)) - ->identifier('arguments.count') - ->line($funcCall->getStartLine()) - ->build(); - } elseif ($functionParametersMaxCount !== -1) { - $errors[] = RuleErrorBuilder::message(sprintf($invokedParametersCount === 1 ? $messages[4] : $messages[5], $invokedParametersCount, $functionParametersMinCount, $functionParametersMaxCount)) - ->identifier('arguments.count') - ->line($funcCall->getStartLine()) - ->build(); - } - } - } - if ( - !$funcCall instanceof Node\Expr\New_ - && !$scope->isInFirstLevelStatement() - && $scope->getKeepVoidType($funcCall)->isVoid()->yes() - ) { - $errors[] = RuleErrorBuilder::message($messages[7]) - ->identifier(sprintf('%s.void', $nodeType)) - ->line($funcCall->getStartLine()) - ->build(); - } - [$addedErrors, $argumentsWithParameters] = $this->processArguments($parametersAcceptor, $funcCall->getStartLine(), $isBuiltin, $arguments, $hasNamedArguments, $messages[10], $messages[11]); - foreach ($addedErrors as $error) { - $errors[] = $error; - } - if (!$this->checkArgumentTypes && !$this->checkArgumentsPassedByReference) { - return $errors; - } - foreach ($argumentsWithParameters as $i => [$argumentValue, $argumentValueType, $unpack, $argumentName, $argumentLine, $parameter, $originalParameter]) { - if ($this->checkArgumentTypes && $unpack) { - $iterableTypeResult = $this->ruleLevelHelper->findTypeToCheck($scope, $argumentValue, '', static function (Type $type) : bool { - return $type->isIterable()->yes(); - }); - $iterableTypeResultType = $iterableTypeResult->getType(); - if ( - !$iterableTypeResultType instanceof ErrorType - && !$iterableTypeResultType->isIterable()->yes() - ) { - $errors[] = RuleErrorBuilder::message(sprintf('Only iterables can be unpacked, %s given in argument #%d.', $iterableTypeResultType->describe(VerbosityLevel::typeOnly()), $i + 1))->identifier('argument.unpackNonIterable')->line($argumentLine)->build(); - } - } - - if ($parameter === null) { - continue; - } - - if ($this->checkArgumentTypes) { - $parameterType = TypeUtils::resolveLateResolvableTypes($parameter->getType()); - - if (!$parameter->passedByReference()->createsNewVariable()) { - $accepts = $this->ruleLevelHelper->acceptsWithReason($parameterType, $argumentValueType, $scope->isDeclareStrictTypes()); - - if (!$accepts->result) { - $verbosityLevel = VerbosityLevel::getRecommendedLevelByType($parameterType, $argumentValueType); - $parameterDescription = sprintf('%s$%s', $parameter->isVariadic() ? '...' : '', $parameter->getName()); - $errors[] = RuleErrorBuilder::message(sprintf($messages[6], $argumentName === null ? sprintf('#%d %s', $i + 1, $parameterDescription) : $parameterDescription, $parameterType->describe($verbosityLevel), $argumentValueType->describe($verbosityLevel))) - ->identifier('argument.type') - ->line($argumentLine) - ->acceptsReasonsTip($accepts->reasons) - ->build(); - } - } - - if ($this->checkUnresolvableParameterTypes - && $originalParameter !== null - && isset($messages[13]) - && !$this->unresolvableTypeHelper->containsUnresolvableType($originalParameter->getType()) - && $this->unresolvableTypeHelper->containsUnresolvableType($parameterType) - ) { - $parameterDescription = sprintf('%s$%s', $parameter->isVariadic() ? '...' : '', $parameter->getName()); - $errors[] = RuleErrorBuilder::message(sprintf($messages[13], $argumentName === null ? sprintf('#%d %s', $i + 1, $parameterDescription) : $parameterDescription))->identifier('argument.unresolvableType')->line($argumentLine)->build(); - } - } - - if ( - !$this->checkArgumentsPassedByReference - || !$parameter->passedByReference()->yes() - ) { - continue; - } - - if ($this->nullsafeCheck->containsNullSafe($argumentValue)) { - $parameterDescription = sprintf('%s$%s', $parameter->isVariadic() ? '...' : '', $parameter->getName()); - $errors[] = RuleErrorBuilder::message(sprintf($messages[8], $argumentName === null ? sprintf('#%d %s', $i + 1, $parameterDescription) : $parameterDescription)) - ->identifier('argument.byRef') - ->line($argumentLine) - ->build(); - continue; - } - - if ( - $argumentValue instanceof Node\Expr\PropertyFetch - || $argumentValue instanceof Node\Expr\StaticPropertyFetch) { - $propertyReflections = $this->propertyReflectionFinder->findPropertyReflectionsFromNode($argumentValue, $scope); - foreach ($propertyReflections as $propertyReflection) { - $nativePropertyReflection = $propertyReflection->getNativeReflection(); - if ($nativePropertyReflection === null) { - continue; - } - if (!$nativePropertyReflection->isReadOnly()) { - continue; - } - - if ($nativePropertyReflection->isStatic()) { - $propertyDescription = sprintf('static readonly property %s::$%s', $propertyReflection->getDeclaringClass()->getDisplayName(), $propertyReflection->getName()); - } else { - $propertyDescription = sprintf('readonly property %s::$%s', $propertyReflection->getDeclaringClass()->getDisplayName(), $propertyReflection->getName()); - } - - $parameterDescription = sprintf('%s$%s', $parameter->isVariadic() ? '...' : '', $parameter->getName()); - $errors[] = RuleErrorBuilder::message(sprintf('Parameter %s is passed by reference so it does not accept %s.', $argumentName === null ? sprintf('#%d %s', $i + 1, $parameterDescription) : $parameterDescription, $propertyDescription))->identifier('argument.byRef')->line($argumentLine)->build(); - } - } - - if ($argumentValue instanceof Node\Expr\Variable - || $argumentValue instanceof Node\Expr\ArrayDimFetch - || $argumentValue instanceof Node\Expr\PropertyFetch - || $argumentValue instanceof Node\Expr\StaticPropertyFetch) { - continue; - } - - $parameterDescription = sprintf('%s$%s', $parameter->isVariadic() ? '...' : '', $parameter->getName()); - $errors[] = RuleErrorBuilder::message(sprintf($messages[8], $argumentName === null ? sprintf('#%d %s', $i + 1, $parameterDescription) : $parameterDescription))->identifier('argument.byRef')->line($argumentLine)->build(); - } - if ($this->checkMissingTypehints && $parametersAcceptor instanceof ResolvedFunctionVariant) { - $originalParametersAcceptor = $parametersAcceptor->getOriginalParametersAcceptor(); - $resolvedTypes = $parametersAcceptor->getResolvedTemplateTypeMap()->getTypes(); - if (count($resolvedTypes) > 0) { - $returnTemplateTypes = []; - TypeTraverser::map($parametersAcceptor->getReturnTypeWithUnresolvableTemplateTypes(), static function (Type $type, callable $traverse) use (&$returnTemplateTypes): Type { - while ($type instanceof ConditionalType && $type->isResolvable()) { - $type = $type->resolve(); - } - - if ($type instanceof TemplateType) { - $returnTemplateTypes[$type->getName()] = true; - return $type; - } - - return $traverse($type); - }); - - $parameterTemplateTypes = []; - foreach ($originalParametersAcceptor->getParameters() as $parameter) { - TypeTraverser::map($parameter->getType(), static function (Type $type, callable $traverse) use (&$parameterTemplateTypes): Type { - if ($type instanceof TemplateType) { - $parameterTemplateTypes[$type->getName()] = true; - return $type; - } - - return $traverse($type); - }); - } - - foreach ($resolvedTypes as $name => $type) { - if ( - !($type instanceof ErrorType) - && ( - !$type instanceof NeverType - || $type->isExplicit() - ) - ) { - continue; - } - - if (!array_key_exists($name, $returnTemplateTypes)) { - continue; - } - - if (!array_key_exists($name, $parameterTemplateTypes)) { - continue; - } - - $errors[] = RuleErrorBuilder::message(sprintf($messages[9], $name)) - ->identifier('argument.templateType') - ->line($funcCall->getStartLine()) - ->tip('See: https://phpstan.org/blog/solving-phpstan-error-unable-to-resolve-template-type') - ->build(); - } - } - - if ( - !$this->unresolvableTypeHelper->containsUnresolvableType($originalParametersAcceptor->getReturnType()) - && $this->unresolvableTypeHelper->containsUnresolvableType($parametersAcceptor->getReturnType()) - ) { - $errors[] = RuleErrorBuilder::message($messages[12]) - ->identifier(sprintf('%s.unresolvableReturnType', $nodeType)) - ->line($funcCall->getStartLine()) - ->build(); - } - } - return $errors; + + if ($this->checkUnresolvableParameterTypes + && $originalParameter !== null + && isset($messages[13]) + && !$this->unresolvableTypeHelper->containsUnresolvableType($originalParameter->getType()) + && $this->unresolvableTypeHelper->containsUnresolvableType($parameterType) + ) { + $parameterDescription = sprintf('%s$%s', $parameter->isVariadic() ? '...' : '', $parameter->getName()); + $errors[] = RuleErrorBuilder::message(sprintf( + $messages[13], + $argumentName === null ? sprintf( + '#%d %s', + $i + 1, + $parameterDescription, + ) : $parameterDescription, + ))->identifier('argument.unresolvableType')->line($argumentLine)->build(); } - /** - * @param array $arguments - * @return array{list, array} - */ - private function processArguments(ParametersAcceptor $parametersAcceptor, int $line, bool $isBuiltin, array $arguments, bool $hasNamedArguments, string $missingParameterMessage, string $unknownParameterMessage) : array - { - $parameters = $parametersAcceptor->getParameters(); - $originalParameters = $parametersAcceptor instanceof ResolvedFunctionVariant - ? $parametersAcceptor->getOriginalParametersAcceptor()->getParameters() - : array_fill(0, count($parameters), null); - $parametersByName = []; - $originalParametersByName = []; - $unusedParametersByName = []; - $errors = []; - foreach ($parameters as $i => $parameter) { - $parametersByName[$parameter->getName()] = $parameter; - $originalParametersByName[$parameter->getName()] = $originalParameters[$i]; - - if ($parameter->isVariadic()) { - continue; - } - - $unusedParametersByName[$parameter->getName()] = $parameter; - } - $newArguments = []; - $namedArgumentAlreadyOccurred = false; - foreach ($arguments as $i => [$argumentValue, $argumentValueType, $unpack, $argumentName, $argumentLine]) { - if ($argumentName === null) { - if (!isset($parameters[$i])) { - if (!$parametersAcceptor->isVariadic() || count($parameters) === 0) { - $newArguments[$i] = [$argumentValue, $argumentValueType, $unpack, $argumentName, $argumentLine, null, null]; - break; - } - - $parameter = $parameters[count($parameters) - 1]; - $originalParameter = $originalParameters[count($originalParameters) - 1]; - if (!$parameter->isVariadic()) { - $newArguments[$i] = [$argumentValue, $argumentValueType, $unpack, $argumentName, $argumentLine, null, null]; - break; // func_get_args - } - } else { - $parameter = $parameters[$i]; - $originalParameter = $originalParameters[$i]; - } - } elseif (array_key_exists($argumentName, $parametersByName)) { - $namedArgumentAlreadyOccurred = true; - $parameter = $parametersByName[$argumentName]; - $originalParameter = $originalParametersByName[$argumentName]; - } else { - $namedArgumentAlreadyOccurred = true; - - $parametersCount = count($parameters); - if ( - !$parametersAcceptor->isVariadic() - || $parametersCount <= 0 - || $isBuiltin - ) { - $errors[] = RuleErrorBuilder::message(sprintf($unknownParameterMessage, $argumentName)) - ->identifier('argument.unknown') - ->line($argumentLine) - ->build(); - $newArguments[$i] = [$argumentValue, $argumentValueType, $unpack, $argumentName, $argumentLine, null, null]; - continue; - } - - $parameter = $parameters[$parametersCount - 1]; - $originalParameter = $originalParameters[$parametersCount - 1]; - } - - if ($namedArgumentAlreadyOccurred && $argumentName === null && !$unpack) { - $errors[] = RuleErrorBuilder::message('Named argument cannot be followed by a positional argument.') - ->identifier('argument.positionalAfterNamed') - ->line($argumentLine) - ->nonIgnorable() - ->build(); - $newArguments[$i] = [$argumentValue, $argumentValueType, $unpack, $argumentName, $argumentLine, null, null]; - continue; - } - - $newArguments[$i] = [$argumentValue, $argumentValueType, $unpack, $argumentName, $argumentLine, $parameter, $originalParameter]; - - if ( - $hasNamedArguments - && !$parameter->isVariadic() - && !array_key_exists($parameter->getName(), $unusedParametersByName) - ) { - $errors[] = RuleErrorBuilder::message(sprintf('Argument for parameter $%s has already been passed.', $parameter->getName())) - ->identifier('argument.duplicate') - ->line($argumentLine) - ->build(); - continue; - } - - unset($unusedParametersByName[$parameter->getName()]); - } - if ($hasNamedArguments) { - foreach ($unusedParametersByName as $parameter) { - if ($parameter->isOptional()) { - continue; - } - - $errors[] = RuleErrorBuilder::message(sprintf($missingParameterMessage, sprintf('%s (%s)', $parameter->getName(), $parameter->getType()->describe(VerbosityLevel::typeOnly())))) - ->identifier('argument.missing') - ->line($line) - ->build(); - } - } - return [$errors, $newArguments]; + } + + if ( + !$this->checkArgumentsPassedByReference + || !$parameter->passedByReference()->yes() + ) { + continue; + } + + if ($this->nullsafeCheck->containsNullSafe($argumentValue)) { + $parameterDescription = sprintf('%s$%s', $parameter->isVariadic() ? '...' : '', $parameter->getName()); + $errors[] = RuleErrorBuilder::message(sprintf( + $messages[8], + $argumentName === null ? sprintf('#%d %s', $i + 1, $parameterDescription) : $parameterDescription, + )) + ->identifier('argument.byRef') + ->line($argumentLine) + ->build(); + continue; + } + + if ( + $argumentValue instanceof Node\Expr\PropertyFetch + || $argumentValue instanceof Node\Expr\StaticPropertyFetch) { + $propertyReflections = $this->propertyReflectionFinder->findPropertyReflectionsFromNode($argumentValue, $scope); + foreach ($propertyReflections as $propertyReflection) { + $nativePropertyReflection = $propertyReflection->getNativeReflection(); + if ($nativePropertyReflection === null) { + continue; + } + if (!$nativePropertyReflection->isReadOnly()) { + continue; + } + + if ($nativePropertyReflection->isStatic()) { + $propertyDescription = sprintf('static readonly property %s::$%s', $propertyReflection->getDeclaringClass()->getDisplayName(), $propertyReflection->getName()); + } else { + $propertyDescription = sprintf('readonly property %s::$%s', $propertyReflection->getDeclaringClass()->getDisplayName(), $propertyReflection->getName()); + } + + $parameterDescription = sprintf('%s$%s', $parameter->isVariadic() ? '...' : '', $parameter->getName()); + $errors[] = RuleErrorBuilder::message(sprintf( + 'Parameter %s is passed by reference so it does not accept %s.', + $argumentName === null ? sprintf('#%d %s', $i + 1, $parameterDescription) : $parameterDescription, + $propertyDescription, + ))->identifier('argument.byRef')->line($argumentLine)->build(); } + } + + if ($argumentValue instanceof Node\Expr\Variable + || $argumentValue instanceof Node\Expr\ArrayDimFetch + || $argumentValue instanceof Node\Expr\PropertyFetch + || $argumentValue instanceof Node\Expr\StaticPropertyFetch) { + continue; + } + + $parameterDescription = sprintf('%s$%s', $parameter->isVariadic() ? '...' : '', $parameter->getName()); + $errors[] = RuleErrorBuilder::message(sprintf( + $messages[8], + $argumentName === null ? sprintf('#%d %s', $i + 1, $parameterDescription) : $parameterDescription, + ))->identifier('argument.byRef')->line($argumentLine)->build(); + } + + if ($this->checkMissingTypehints && $parametersAcceptor instanceof ResolvedFunctionVariant) { + $originalParametersAcceptor = $parametersAcceptor->getOriginalParametersAcceptor(); + $resolvedTypes = $parametersAcceptor->getResolvedTemplateTypeMap()->getTypes(); + if (count($resolvedTypes) > 0) { + $returnTemplateTypes = []; + TypeTraverser::map( + $parametersAcceptor->getReturnTypeWithUnresolvableTemplateTypes(), + static function (Type $type, callable $traverse) use (&$returnTemplateTypes): Type { + while ($type instanceof ConditionalType && $type->isResolvable()) { + $type = $type->resolve(); + } + + if ($type instanceof TemplateType) { + $returnTemplateTypes[$type->getName()] = true; + return $type; + } + + return $traverse($type); + }, + ); + + $parameterTemplateTypes = []; + foreach ($originalParametersAcceptor->getParameters() as $parameter) { + TypeTraverser::map($parameter->getType(), static function (Type $type, callable $traverse) use (&$parameterTemplateTypes): Type { + if ($type instanceof TemplateType) { + $parameterTemplateTypes[$type->getName()] = true; + return $type; + } + + return $traverse($type); + }); + } + + foreach ($resolvedTypes as $name => $type) { + if ( + !($type instanceof ErrorType) + && ( + !$type instanceof NeverType + || $type->isExplicit() + ) + ) { + continue; + } + + if (!array_key_exists($name, $returnTemplateTypes)) { + continue; + } + + if (!array_key_exists($name, $parameterTemplateTypes)) { + continue; + } + + $errors[] = RuleErrorBuilder::message(sprintf($messages[9], $name)) + ->identifier('argument.templateType') + ->line($funcCall->getStartLine()) + ->tip('See: https://phpstan.org/blog/solving-phpstan-error-unable-to-resolve-template-type') + ->build(); + } + } + + if ( + !$this->unresolvableTypeHelper->containsUnresolvableType($originalParametersAcceptor->getReturnType()) + && $this->unresolvableTypeHelper->containsUnresolvableType($parametersAcceptor->getReturnType()) + ) { + $errors[] = RuleErrorBuilder::message($messages[12]) + ->identifier(sprintf('%s.unresolvableReturnType', $nodeType)) + ->line($funcCall->getStartLine()) + ->build(); + } + } + + return $errors; + } + + /** + * @param array $arguments + * @return array{list, array} + */ + private function processArguments( + ParametersAcceptor $parametersAcceptor, + int $line, + bool $isBuiltin, + array $arguments, + bool $hasNamedArguments, + string $missingParameterMessage, + string $unknownParameterMessage, + ): array + { + $parameters = $parametersAcceptor->getParameters(); + $originalParameters = $parametersAcceptor instanceof ResolvedFunctionVariant + ? $parametersAcceptor->getOriginalParametersAcceptor()->getParameters() + : array_fill(0, count($parameters), null); + $parametersByName = []; + $originalParametersByName = []; + $unusedParametersByName = []; + $errors = []; + foreach ($parameters as $i => $parameter) { + $parametersByName[$parameter->getName()] = $parameter; + $originalParametersByName[$parameter->getName()] = $originalParameters[$i]; + + if ($parameter->isVariadic()) { + continue; + } + + $unusedParametersByName[$parameter->getName()] = $parameter; + } + + $newArguments = []; + + $namedArgumentAlreadyOccurred = false; + foreach ($arguments as $i => [$argumentValue, $argumentValueType, $unpack, $argumentName, $argumentLine]) { + if ($argumentName === null) { + if (!isset($parameters[$i])) { + if (!$parametersAcceptor->isVariadic() || count($parameters) === 0) { + $newArguments[$i] = [$argumentValue, $argumentValueType, $unpack, $argumentName, $argumentLine, null, null]; + break; + } + + $parameter = $parameters[count($parameters) - 1]; + $originalParameter = $originalParameters[count($originalParameters) - 1]; + if (!$parameter->isVariadic()) { + $newArguments[$i] = [$argumentValue, $argumentValueType, $unpack, $argumentName, $argumentLine, null, null]; + break; // func_get_args + } + } else { + $parameter = $parameters[$i]; + $originalParameter = $originalParameters[$i]; + } + } elseif (array_key_exists($argumentName, $parametersByName)) { + $namedArgumentAlreadyOccurred = true; + $parameter = $parametersByName[$argumentName]; + $originalParameter = $originalParametersByName[$argumentName]; + } else { + $namedArgumentAlreadyOccurred = true; + + $parametersCount = count($parameters); + if ( + !$parametersAcceptor->isVariadic() + || $parametersCount <= 0 + || $isBuiltin + ) { + $errors[] = RuleErrorBuilder::message(sprintf($unknownParameterMessage, $argumentName)) + ->identifier('argument.unknown') + ->line($argumentLine) + ->build(); + $newArguments[$i] = [$argumentValue, $argumentValueType, $unpack, $argumentName, $argumentLine, null, null]; + continue; + } + + $parameter = $parameters[$parametersCount - 1]; + $originalParameter = $originalParameters[$parametersCount - 1]; + } + + if ($namedArgumentAlreadyOccurred && $argumentName === null && !$unpack) { + $errors[] = RuleErrorBuilder::message('Named argument cannot be followed by a positional argument.') + ->identifier('argument.positionalAfterNamed') + ->line($argumentLine) + ->nonIgnorable() + ->build(); + $newArguments[$i] = [$argumentValue, $argumentValueType, $unpack, $argumentName, $argumentLine, null, null]; + continue; + } + + $newArguments[$i] = [$argumentValue, $argumentValueType, $unpack, $argumentName, $argumentLine, $parameter, $originalParameter]; + + if ( + $hasNamedArguments + && !$parameter->isVariadic() + && !array_key_exists($parameter->getName(), $unusedParametersByName) + ) { + $errors[] = RuleErrorBuilder::message(sprintf('Argument for parameter $%s has already been passed.', $parameter->getName())) + ->identifier('argument.duplicate') + ->line($argumentLine) + ->build(); + continue; + } + + unset($unusedParametersByName[$parameter->getName()]); + } + + if ($hasNamedArguments) { + foreach ($unusedParametersByName as $parameter) { + if ($parameter->isOptional()) { + continue; + } + + $errors[] = RuleErrorBuilder::message(sprintf($missingParameterMessage, sprintf('%s (%s)', $parameter->getName(), $parameter->getType()->describe(VerbosityLevel::typeOnly())))) + ->identifier('argument.missing') + ->line($line) + ->build(); + } + } + + return [$errors, $newArguments]; + } + } diff --git a/src/Rules/FunctionDefinitionCheck.php b/src/Rules/FunctionDefinitionCheck.php index d722ddd402c..1aee6ba688e 100644 --- a/src/Rules/FunctionDefinitionCheck.php +++ b/src/Rules/FunctionDefinitionCheck.php @@ -39,364 +39,432 @@ class FunctionDefinitionCheck { + public function __construct( + private ReflectionProvider $reflectionProvider, + private ClassCaseSensitivityCheck $classCaseSensitivityCheck, + private UnresolvableTypeHelper $unresolvableTypeHelper, + private PhpVersion $phpVersion, + private bool $checkClassCaseSensitivity, + private bool $checkThisOnly, + ) + { + } + + /** + * @return list + */ + public function checkFunction( + Function_ $function, + FunctionReflection $functionReflection, + string $parameterMessage, + string $returnMessage, + string $unionTypesMessage, + string $templateTypeMissingInParameterMessage, + string $unresolvableParameterTypeMessage, + string $unresolvableReturnTypeMessage, + ): array + { + $parametersAcceptor = ParametersAcceptorSelector::selectSingle($functionReflection->getVariants()); + + return $this->checkParametersAcceptor( + $parametersAcceptor, + $function, + $parameterMessage, + $returnMessage, + $unionTypesMessage, + $templateTypeMissingInParameterMessage, + $unresolvableParameterTypeMessage, + $unresolvableReturnTypeMessage, + ); + } + /** - * @var ReflectionProvider - */ - private $reflectionProvider; - /** - * @var ClassCaseSensitivityCheck - */ - private $classCaseSensitivityCheck; - /** - * @var UnresolvableTypeHelper - */ - private $unresolvableTypeHelper; - /** - * @var PhpVersion - */ - private $phpVersion; - /** - * @var bool - */ - private $checkClassCaseSensitivity; - /** - * @var bool - */ - private $checkThisOnly; - public function __construct(ReflectionProvider $reflectionProvider, ClassCaseSensitivityCheck $classCaseSensitivityCheck, UnresolvableTypeHelper $unresolvableTypeHelper, PhpVersion $phpVersion, bool $checkClassCaseSensitivity, bool $checkThisOnly) - { - $this->reflectionProvider = $reflectionProvider; - $this->classCaseSensitivityCheck = $classCaseSensitivityCheck; - $this->unresolvableTypeHelper = $unresolvableTypeHelper; - $this->phpVersion = $phpVersion; - $this->checkClassCaseSensitivity = $checkClassCaseSensitivity; - $this->checkThisOnly = $checkThisOnly; + * @param Node\Param[] $parameters + * @param Node\Identifier|Node\Name|Node\ComplexType|null $returnTypeNode + * @return list + */ + public function checkAnonymousFunction( + Scope $scope, + array $parameters, + $returnTypeNode, + string $parameterMessage, + string $returnMessage, + string $unionTypesMessage, + string $unresolvableParameterTypeMessage, + string $unresolvableReturnTypeMessage, + ): array + { + $errors = []; + $unionTypeReported = false; + foreach ($parameters as $param) { + if ($param->type === null) { + continue; + } + if ( + !$unionTypeReported + && $param->type instanceof UnionType + && !$this->phpVersion->supportsNativeUnionTypes() + ) { + $errors[] = RuleErrorBuilder::message($unionTypesMessage) + ->line($param->getStartLine()) + ->identifier('parameter.unionTypeNotSupported') + ->nonIgnorable() + ->build(); + $unionTypeReported = true; + } + + if (!$param->var instanceof Variable || !is_string($param->var->name)) { + throw new ShouldNotHappenException(); + } + $type = $scope->getFunctionType($param->type, false, false); + if ($type->isVoid()->yes()) { + $errors[] = RuleErrorBuilder::message(sprintf($parameterMessage, $param->var->name, 'void')) + ->line($param->type->getStartLine()) + ->identifier('parameter.void') + ->nonIgnorable() + ->build(); + } + if ( + $this->phpVersion->supportsPureIntersectionTypes() + && $this->unresolvableTypeHelper->containsUnresolvableType($type) + ) { + $errors[] = RuleErrorBuilder::message(sprintf($unresolvableParameterTypeMessage, $param->var->name)) + ->line($param->type->getStartLine()) + ->identifier('parameter.unresolvableNativeType') + ->nonIgnorable() + ->build(); + } + + foreach ($type->getReferencedClasses() as $class) { + if (!$this->reflectionProvider->hasClass($class)) { + $errors[] = RuleErrorBuilder::message(sprintf($parameterMessage, $param->var->name, $class)) + ->line($param->type->getStartLine()) + ->identifier('class.notFound') + ->build(); + continue; + } + + $classReflection = $this->reflectionProvider->getClass($class); + if ($classReflection->isTrait()) { + $errors[] = RuleErrorBuilder::message(sprintf($parameterMessage, $param->var->name, $class)) + ->line($param->type->getStartLine()) + ->identifier('parameter.trait') + ->build(); + continue; + } + + if (!$this->checkClassCaseSensitivity) { + continue; + } + + $errors = array_merge( + $errors, + $this->classCaseSensitivityCheck->checkClassNames([ + new ClassNameNodePair($class, $param->type), + ]), + ); + } } - /** - * @return list - */ - public function checkFunction(Function_ $function, FunctionReflection $functionReflection, string $parameterMessage, string $returnMessage, string $unionTypesMessage, string $templateTypeMissingInParameterMessage, string $unresolvableParameterTypeMessage, string $unresolvableReturnTypeMessage) : array - { - $parametersAcceptor = ParametersAcceptorSelector::selectSingle($functionReflection->getVariants()); - return $this->checkParametersAcceptor($parametersAcceptor, $function, $parameterMessage, $returnMessage, $unionTypesMessage, $templateTypeMissingInParameterMessage, $unresolvableParameterTypeMessage, $unresolvableReturnTypeMessage); + + if ($this->phpVersion->deprecatesRequiredParameterAfterOptional()) { + $errors = array_merge($errors, $this->checkRequiredParameterAfterOptional($parameters)); } - /** - * @param Node\Param[] $parameters - * @param Node\Identifier|Node\Name|Node\ComplexType|null $returnTypeNode - * @return list - */ - public function checkAnonymousFunction(Scope $scope, array $parameters, $returnTypeNode, string $parameterMessage, string $returnMessage, string $unionTypesMessage, string $unresolvableParameterTypeMessage, string $unresolvableReturnTypeMessage) : array - { - $errors = []; - $unionTypeReported = false; - foreach ($parameters as $param) { - if ($param->type === null) { - continue; - } - if ( - !$unionTypeReported - && $param->type instanceof UnionType - && !$this->phpVersion->supportsNativeUnionTypes() - ) { - $errors[] = RuleErrorBuilder::message($unionTypesMessage) - ->line($param->getStartLine()) - ->identifier('parameter.unionTypeNotSupported') - ->nonIgnorable() - ->build(); - $unionTypeReported = true; - } - - if (!$param->var instanceof Variable || !is_string($param->var->name)) { - throw new ShouldNotHappenException(); - } - $type = $scope->getFunctionType($param->type, false, false); - if ($type->isVoid()->yes()) { - $errors[] = RuleErrorBuilder::message(sprintf($parameterMessage, $param->var->name, 'void')) - ->line($param->type->getStartLine()) - ->identifier('parameter.void') - ->nonIgnorable() - ->build(); - } - if ( - $this->phpVersion->supportsPureIntersectionTypes() - && $this->unresolvableTypeHelper->containsUnresolvableType($type) - ) { - $errors[] = RuleErrorBuilder::message(sprintf($unresolvableParameterTypeMessage, $param->var->name)) - ->line($param->type->getStartLine()) - ->identifier('parameter.unresolvableNativeType') - ->nonIgnorable() - ->build(); - } - - foreach ($type->getReferencedClasses() as $class) { - if (!$this->reflectionProvider->hasClass($class)) { - $errors[] = RuleErrorBuilder::message(sprintf($parameterMessage, $param->var->name, $class)) - ->line($param->type->getStartLine()) - ->identifier('class.notFound') - ->build(); - continue; - } - - $classReflection = $this->reflectionProvider->getClass($class); - if ($classReflection->isTrait()) { - $errors[] = RuleErrorBuilder::message(sprintf($parameterMessage, $param->var->name, $class)) - ->line($param->type->getStartLine()) - ->identifier('parameter.trait') - ->build(); - continue; - } - - if (!$this->checkClassCaseSensitivity) { - continue; - } - - $errors = array_merge($errors, $this->classCaseSensitivityCheck->checkClassNames([ - new ClassNameNodePair($class, $param->type), - ])); - } - } - if ($this->phpVersion->deprecatesRequiredParameterAfterOptional()) { - $errors = array_merge($errors, $this->checkRequiredParameterAfterOptional($parameters)); - } - if ($returnTypeNode === null) { - return $errors; - } - if ( - !$unionTypeReported - && $returnTypeNode instanceof UnionType - && !$this->phpVersion->supportsNativeUnionTypes() - ) { - $errors[] = RuleErrorBuilder::message($unionTypesMessage) - ->line($returnTypeNode->getStartLine()) - ->identifier('reeturn.unionTypeNotSupported') - ->nonIgnorable() - ->build(); - } - $returnType = $scope->getFunctionType($returnTypeNode, false, false); - if ( - $this->phpVersion->supportsPureIntersectionTypes() - && $this->unresolvableTypeHelper->containsUnresolvableType($returnType) - ) { - $errors[] = RuleErrorBuilder::message($unresolvableReturnTypeMessage) - ->line($returnTypeNode->getStartLine()) - ->identifier('return.unresolvableNativeType') - ->nonIgnorable() - ->build(); - } - foreach ($returnType->getReferencedClasses() as $returnTypeClass) { - if (!$this->reflectionProvider->hasClass($returnTypeClass)) { - $errors[] = RuleErrorBuilder::message(sprintf($returnMessage, $returnTypeClass)) - ->line($returnTypeNode->getStartLine()) - ->identifier('class.notFound') - ->build(); - continue; - } - - if ($this->reflectionProvider->getClass($returnTypeClass)->isTrait()) { - $errors[] = RuleErrorBuilder::message(sprintf($returnMessage, $returnTypeClass)) - ->line($returnTypeNode->getStartLine()) - ->identifier('return.trait') - ->build(); - continue; - } - - if (!$this->checkClassCaseSensitivity) { - continue; - } - - $errors = array_merge($errors, $this->classCaseSensitivityCheck->checkClassNames([ + + if ($returnTypeNode === null) { + return $errors; + } + + if ( + !$unionTypeReported + && $returnTypeNode instanceof UnionType + && !$this->phpVersion->supportsNativeUnionTypes() + ) { + $errors[] = RuleErrorBuilder::message($unionTypesMessage) + ->line($returnTypeNode->getStartLine()) + ->identifier('reeturn.unionTypeNotSupported') + ->nonIgnorable() + ->build(); + } + + $returnType = $scope->getFunctionType($returnTypeNode, false, false); + if ( + $this->phpVersion->supportsPureIntersectionTypes() + && $this->unresolvableTypeHelper->containsUnresolvableType($returnType) + ) { + $errors[] = RuleErrorBuilder::message($unresolvableReturnTypeMessage) + ->line($returnTypeNode->getStartLine()) + ->identifier('return.unresolvableNativeType') + ->nonIgnorable() + ->build(); + } + + foreach ($returnType->getReferencedClasses() as $returnTypeClass) { + if (!$this->reflectionProvider->hasClass($returnTypeClass)) { + $errors[] = RuleErrorBuilder::message(sprintf($returnMessage, $returnTypeClass)) + ->line($returnTypeNode->getStartLine()) + ->identifier('class.notFound') + ->build(); + continue; + } + + if ($this->reflectionProvider->getClass($returnTypeClass)->isTrait()) { + $errors[] = RuleErrorBuilder::message(sprintf($returnMessage, $returnTypeClass)) + ->line($returnTypeNode->getStartLine()) + ->identifier('return.trait') + ->build(); + continue; + } + + if (!$this->checkClassCaseSensitivity) { + continue; + } + + $errors = array_merge( + $errors, + $this->classCaseSensitivityCheck->checkClassNames([ new ClassNameNodePair($returnTypeClass, $returnTypeNode), - ])); - } - return $errors; + ]), + ); + } + + return $errors; + } + + /** + * @return list + */ + public function checkClassMethod( + PhpMethodFromParserNodeReflection $methodReflection, + ClassMethod $methodNode, + string $parameterMessage, + string $returnMessage, + string $unionTypesMessage, + string $templateTypeMissingInParameterMessage, + string $unresolvableParameterTypeMessage, + string $unresolvableReturnTypeMessage, + ): array + { + /** @var ParametersAcceptorWithPhpDocs $parametersAcceptor */ + $parametersAcceptor = ParametersAcceptorSelector::selectSingle($methodReflection->getVariants()); + + return $this->checkParametersAcceptor( + $parametersAcceptor, + $methodNode, + $parameterMessage, + $returnMessage, + $unionTypesMessage, + $templateTypeMissingInParameterMessage, + $unresolvableParameterTypeMessage, + $unresolvableReturnTypeMessage, + ); + } + + /** + * @return list + */ + private function checkParametersAcceptor( + ParametersAcceptor $parametersAcceptor, + FunctionLike $functionNode, + string $parameterMessage, + string $returnMessage, + string $unionTypesMessage, + string $templateTypeMissingInParameterMessage, + string $unresolvableParameterTypeMessage, + string $unresolvableReturnTypeMessage, + ): array + { + $errors = []; + $parameterNodes = $functionNode->getParams(); + if (!$this->phpVersion->supportsNativeUnionTypes()) { + $unionTypeReported = false; + foreach ($parameterNodes as $parameterNode) { + if (!$parameterNode->type instanceof UnionType) { + continue; + } + + $errors[] = RuleErrorBuilder::message($unionTypesMessage) + ->line($parameterNode->getStartLine()) + ->identifier('parameter.unionTypeNotSupported') + ->nonIgnorable() + ->build(); + $unionTypeReported = true; + break; + } + + if (!$unionTypeReported && $functionNode->getReturnType() instanceof UnionType) { + $errors[] = RuleErrorBuilder::message($unionTypesMessage) + ->line($functionNode->getReturnType()->getStartLine()) + ->identifier('return.unionTypeNotSupported') + ->nonIgnorable() + ->build(); + } + } + + if ($this->phpVersion->deprecatesRequiredParameterAfterOptional()) { + $errors = array_merge($errors, $this->checkRequiredParameterAfterOptional($parameterNodes)); + } + + $returnTypeNode = $functionNode->getReturnType() ?? $functionNode; + foreach ($parametersAcceptor->getParameters() as $parameter) { + $referencedClasses = $this->getParameterReferencedClasses($parameter); + $parameterNode = null; + $parameterNodeCallback = function () use ($parameter, $parameterNodes, &$parameterNode): Param { + if ($parameterNode === null) { + $parameterNode = $this->getParameterNode($parameter->getName(), $parameterNodes); + } + + return $parameterNode; + }; + if ($parameter instanceof ParameterReflectionWithPhpDocs) { + $parameterVar = $parameterNodeCallback()->var; + if (!$parameterVar instanceof Variable || !is_string($parameterVar->name)) { + throw new ShouldNotHappenException(); + } + if ($parameter->getNativeType()->isVoid()->yes()) { + $errors[] = RuleErrorBuilder::message(sprintf($parameterMessage, $parameterVar->name, 'void')) + ->line($parameterNodeCallback()->getStartLine()) + ->identifier('parameter.void') + ->nonIgnorable() + ->build(); + } + if ( + $this->phpVersion->supportsPureIntersectionTypes() + && $this->unresolvableTypeHelper->containsUnresolvableType($parameter->getNativeType()) + ) { + $errors[] = RuleErrorBuilder::message(sprintf($unresolvableParameterTypeMessage, $parameterVar->name)) + ->line($parameterNodeCallback()->getStartLine()) + ->identifier('parameter.unresolvableNativeType') + ->nonIgnorable() + ->build(); + } + } + foreach ($referencedClasses as $class) { + if (!$this->reflectionProvider->hasClass($class)) { + $errors[] = RuleErrorBuilder::message(sprintf( + $parameterMessage, + $parameter->getName(), + $class, + )) + ->line($parameterNodeCallback()->getStartLine()) + ->identifier('class.notFound') + ->build(); + continue; + } + if (!$this->reflectionProvider->getClass($class)->isTrait()) { + continue; + } + + $errors[] = RuleErrorBuilder::message(sprintf( + $parameterMessage, + $parameter->getName(), + $class, + )) + ->line($parameterNodeCallback()->getStartLine()) + ->identifier('parameter.trait') + ->build(); + } + + if ($this->checkClassCaseSensitivity) { + $errors = array_merge( + $errors, + $this->classCaseSensitivityCheck->checkClassNames(array_map(static fn (string $class): ClassNameNodePair => new ClassNameNodePair($class, $parameterNodeCallback()), $referencedClasses)), + ); + } + if (!($parameter->getType() instanceof NonexistentParentClassType)) { + continue; + } + + $errors[] = RuleErrorBuilder::message(sprintf($parameterMessage, $parameter->getName(), $parameter->getType()->describe(VerbosityLevel::typeOnly()))) + ->line($parameterNodeCallback()->getStartLine()) + ->identifier('parameter.noParent') + ->build(); + } + + if ($this->phpVersion->supportsPureIntersectionTypes() && $functionNode->getReturnType() !== null) { + $nativeReturnType = ParserNodeTypeToPHPStanType::resolve($functionNode->getReturnType(), null); + if ($this->unresolvableTypeHelper->containsUnresolvableType($nativeReturnType)) { + $errors[] = RuleErrorBuilder::message($unresolvableReturnTypeMessage) + ->nonIgnorable() + ->line($returnTypeNode->getStartLine()) + ->identifier('return.unresolvableNativeType') + ->build(); + } + } + + $returnTypeReferencedClasses = $this->getReturnTypeReferencedClasses($parametersAcceptor); + + foreach ($returnTypeReferencedClasses as $class) { + if (!$this->reflectionProvider->hasClass($class)) { + $errors[] = RuleErrorBuilder::message(sprintf($returnMessage, $class)) + ->line($returnTypeNode->getStartLine()) + ->identifier('class.notFound') + ->build(); + continue; + } + if (!$this->reflectionProvider->getClass($class)->isTrait()) { + continue; + } + + $errors[] = RuleErrorBuilder::message(sprintf($returnMessage, $class)) + ->line($returnTypeNode->getStartLine()) + ->identifier('return.trait') + ->build(); } - /** - * @return list - */ - public function checkClassMethod(PhpMethodFromParserNodeReflection $methodReflection, ClassMethod $methodNode, string $parameterMessage, string $returnMessage, string $unionTypesMessage, string $templateTypeMissingInParameterMessage, string $unresolvableParameterTypeMessage, string $unresolvableReturnTypeMessage) : array - { - /** @var ParametersAcceptorWithPhpDocs $parametersAcceptor */ - $parametersAcceptor = ParametersAcceptorSelector::selectSingle($methodReflection->getVariants()); - return $this->checkParametersAcceptor($parametersAcceptor, $methodNode, $parameterMessage, $returnMessage, $unionTypesMessage, $templateTypeMissingInParameterMessage, $unresolvableParameterTypeMessage, $unresolvableReturnTypeMessage); + + if ($this->checkClassCaseSensitivity) { + $errors = array_merge( + $errors, + $this->classCaseSensitivityCheck->checkClassNames(array_map(static fn (string $class): ClassNameNodePair => new ClassNameNodePair($class, $returnTypeNode), $returnTypeReferencedClasses)), + ); + } + if ($parametersAcceptor->getReturnType() instanceof NonexistentParentClassType) { + $errors[] = RuleErrorBuilder::message(sprintf($returnMessage, $parametersAcceptor->getReturnType()->describe(VerbosityLevel::typeOnly()))) + ->line($returnTypeNode->getStartLine()) + ->identifier('return.noParent') + ->build(); } - /** - * @return list - */ - private function checkParametersAcceptor(ParametersAcceptor $parametersAcceptor, FunctionLike $functionNode, string $parameterMessage, string $returnMessage, string $unionTypesMessage, string $templateTypeMissingInParameterMessage, string $unresolvableParameterTypeMessage, string $unresolvableReturnTypeMessage) : array - { - $errors = []; - $parameterNodes = $functionNode->getParams(); - if (!$this->phpVersion->supportsNativeUnionTypes()) { - $unionTypeReported = false; - foreach ($parameterNodes as $parameterNode) { - if (!$parameterNode->type instanceof UnionType) { - continue; - } - - $errors[] = RuleErrorBuilder::message($unionTypesMessage) - ->line($parameterNode->getStartLine()) - ->identifier('parameter.unionTypeNotSupported') - ->nonIgnorable() - ->build(); - $unionTypeReported = true; - break; - } - - if (!$unionTypeReported && $functionNode->getReturnType() instanceof UnionType) { - $errors[] = RuleErrorBuilder::message($unionTypesMessage) - ->line($functionNode->getReturnType()->getStartLine()) - ->identifier('return.unionTypeNotSupported') - ->nonIgnorable() - ->build(); - } - } - if ($this->phpVersion->deprecatesRequiredParameterAfterOptional()) { - $errors = array_merge($errors, $this->checkRequiredParameterAfterOptional($parameterNodes)); - } - $returnTypeNode = $functionNode->getReturnType() ?? $functionNode; - foreach ($parametersAcceptor->getParameters() as $parameter) { - $referencedClasses = $this->getParameterReferencedClasses($parameter); - $parameterNode = null; - $parameterNodeCallback = function () use ($parameter, $parameterNodes, &$parameterNode): Param { - if ($parameterNode === null) { - $parameterNode = $this->getParameterNode($parameter->getName(), $parameterNodes); - } - - return $parameterNode; - }; - if ($parameter instanceof ParameterReflectionWithPhpDocs) { - $parameterVar = $parameterNodeCallback()->var; - if (!$parameterVar instanceof Variable || !is_string($parameterVar->name)) { - throw new ShouldNotHappenException(); - } - if ($parameter->getNativeType()->isVoid()->yes()) { - $errors[] = RuleErrorBuilder::message(sprintf($parameterMessage, $parameterVar->name, 'void')) - ->line($parameterNodeCallback()->getStartLine()) - ->identifier('parameter.void') - ->nonIgnorable() - ->build(); - } - if ( - $this->phpVersion->supportsPureIntersectionTypes() - && $this->unresolvableTypeHelper->containsUnresolvableType($parameter->getNativeType()) - ) { - $errors[] = RuleErrorBuilder::message(sprintf($unresolvableParameterTypeMessage, $parameterVar->name)) - ->line($parameterNodeCallback()->getStartLine()) - ->identifier('parameter.unresolvableNativeType') - ->nonIgnorable() - ->build(); - } - } - foreach ($referencedClasses as $class) { - if (!$this->reflectionProvider->hasClass($class)) { - $errors[] = RuleErrorBuilder::message(sprintf($parameterMessage, $parameter->getName(), $class)) - ->line($parameterNodeCallback()->getStartLine()) - ->identifier('class.notFound') - ->build(); - continue; - } - if (!$this->reflectionProvider->getClass($class)->isTrait()) { - continue; - } - - $errors[] = RuleErrorBuilder::message(sprintf($parameterMessage, $parameter->getName(), $class)) - ->line($parameterNodeCallback()->getStartLine()) - ->identifier('parameter.trait') - ->build(); - } - - if ($this->checkClassCaseSensitivity) { - $errors = array_merge($errors, $this->classCaseSensitivityCheck->checkClassNames(array_map(static function (string $class) use($parameterNodeCallback) : ClassNameNodePair { - return new ClassNameNodePair($class, $parameterNodeCallback()); - }, $referencedClasses))); - } - if (!($parameter->getType() instanceof NonexistentParentClassType)) { - continue; - } - - $errors[] = RuleErrorBuilder::message(sprintf($parameterMessage, $parameter->getName(), $parameter->getType()->describe(VerbosityLevel::typeOnly()))) - ->line($parameterNodeCallback()->getStartLine()) - ->identifier('parameter.noParent') - ->build(); - } - if ($this->phpVersion->supportsPureIntersectionTypes() && $functionNode->getReturnType() !== null) { - $nativeReturnType = ParserNodeTypeToPHPStanType::resolve($functionNode->getReturnType(), null); - if ($this->unresolvableTypeHelper->containsUnresolvableType($nativeReturnType)) { - $errors[] = RuleErrorBuilder::message($unresolvableReturnTypeMessage) - ->nonIgnorable() - ->line($returnTypeNode->getStartLine()) - ->identifier('return.unresolvableNativeType') - ->build(); - } - } - $returnTypeReferencedClasses = $this->getReturnTypeReferencedClasses($parametersAcceptor); - foreach ($returnTypeReferencedClasses as $class) { - if (!$this->reflectionProvider->hasClass($class)) { - $errors[] = RuleErrorBuilder::message(sprintf($returnMessage, $class)) - ->line($returnTypeNode->getStartLine()) - ->identifier('class.notFound') - ->build(); - continue; - } - if (!$this->reflectionProvider->getClass($class)->isTrait()) { - continue; - } - - $errors[] = RuleErrorBuilder::message(sprintf($returnMessage, $class)) - ->line($returnTypeNode->getStartLine()) - ->identifier('return.trait') - ->build(); - } - if ($this->checkClassCaseSensitivity) { - $errors = array_merge($errors, $this->classCaseSensitivityCheck->checkClassNames(array_map(static function (string $class) use($returnTypeNode) : ClassNameNodePair { - return new ClassNameNodePair($class, $returnTypeNode); - }, $returnTypeReferencedClasses))); - } - if ($parametersAcceptor->getReturnType() instanceof NonexistentParentClassType) { - $errors[] = RuleErrorBuilder::message(sprintf($returnMessage, $parametersAcceptor->getReturnType()->describe(VerbosityLevel::typeOnly()))) - ->line($returnTypeNode->getStartLine()) - ->identifier('return.noParent') - ->build(); - } - $templateTypeMap = $parametersAcceptor->getTemplateTypeMap(); - $templateTypes = $templateTypeMap->getTypes(); - if (count($templateTypes) > 0) { - foreach ($parametersAcceptor->getParameters() as $parameter) { - TypeTraverser::map($parameter->getType(), static function (Type $type, callable $traverse) use (&$templateTypes): Type { - if ($type instanceof TemplateType) { - unset($templateTypes[$type->getName()]); - return $traverse($type); - } - - return $traverse($type); - }); - } - - $returnType = $parametersAcceptor->getReturnType(); - if ($returnType instanceof ConditionalTypeForParameter && !$returnType->isNegated()) { - TypeTraverser::map($returnType, static function (Type $type, callable $traverse) use (&$templateTypes): Type { - if ($type instanceof TemplateType) { - unset($templateTypes[$type->getName()]); - return $traverse($type); - } - - return $traverse($type); - }); - } - - foreach (array_keys($templateTypes) as $templateTypeName) { - $errors[] = RuleErrorBuilder::message(sprintf($templateTypeMissingInParameterMessage, $templateTypeName)) - ->identifier('method.templateTypeNotInParameter') - ->build(); - } - } - return $errors; + + $templateTypeMap = $parametersAcceptor->getTemplateTypeMap(); + $templateTypes = $templateTypeMap->getTypes(); + if (count($templateTypes) > 0) { + foreach ($parametersAcceptor->getParameters() as $parameter) { + TypeTraverser::map($parameter->getType(), static function (Type $type, callable $traverse) use (&$templateTypes): Type { + if ($type instanceof TemplateType) { + unset($templateTypes[$type->getName()]); + return $traverse($type); + } + + return $traverse($type); + }); + } + + $returnType = $parametersAcceptor->getReturnType(); + if ($returnType instanceof ConditionalTypeForParameter && !$returnType->isNegated()) { + TypeTraverser::map($returnType, static function (Type $type, callable $traverse) use (&$templateTypes): Type { + if ($type instanceof TemplateType) { + unset($templateTypes[$type->getName()]); + return $traverse($type); + } + + return $traverse($type); + }); + } + + foreach (array_keys($templateTypes) as $templateTypeName) { + $errors[] = RuleErrorBuilder::message(sprintf($templateTypeMissingInParameterMessage, $templateTypeName)) + ->identifier('method.templateTypeNotInParameter') + ->build(); + } } - /** - * @param Param[] $parameterNodes - * @return list - */ - private function checkRequiredParameterAfterOptional(array $parameterNodes): array + + return $errors; + } + + /** + * @param Param[] $parameterNodes + * @return list + */ + private function checkRequiredParameterAfterOptional(array $parameterNodes): array { /** @var string|null $optionalParameter */ $optionalParameter = null; @@ -442,30 +510,34 @@ private function checkRequiredParameterAfterOptional(array $parameterNodes): arr } /** - * @param Param[] $parameterNodes - */ - private function getParameterNode(string $parameterName, array $parameterNodes) : Param - { - foreach ($parameterNodes as $param) { - if ($param->var instanceof Node\Expr\Error) { - continue; - } - - if (!is_string($param->var->name)) { - continue; - } - - if ($param->var->name === $parameterName) { - return $param; - } - } - throw new ShouldNotHappenException(sprintf('Parameter %s not found.', $parameterName)); + * @param Param[] $parameterNodes + */ + private function getParameterNode( + string $parameterName, + array $parameterNodes, + ): Param + { + foreach ($parameterNodes as $param) { + if ($param->var instanceof Node\Expr\Error) { + continue; + } + + if (!is_string($param->var->name)) { + continue; + } + + if ($param->var->name === $parameterName) { + return $param; + } } + throw new ShouldNotHappenException(sprintf('Parameter %s not found.', $parameterName)); + } + /** - * @return string[] - */ - private function getParameterReferencedClasses(ParameterReflection $parameter): array + * @return string[] + */ + private function getParameterReferencedClasses(ParameterReflection $parameter): array { if (!$parameter instanceof ParameterReflectionWithPhpDocs) { return $parameter->getType()->getReferencedClasses(); @@ -475,13 +547,16 @@ private function getParameterReferencedClasses(ParameterReflection $parameter): return $parameter->getNativeType()->getReferencedClasses(); } - return array_merge($parameter->getNativeType()->getReferencedClasses(), $parameter->getPhpDocType()->getReferencedClasses()); + return array_merge( + $parameter->getNativeType()->getReferencedClasses(), + $parameter->getPhpDocType()->getReferencedClasses(), + ); } /** - * @return string[] - */ - private function getReturnTypeReferencedClasses(ParametersAcceptor $parametersAcceptor): array + * @return string[] + */ + private function getReturnTypeReferencedClasses(ParametersAcceptor $parametersAcceptor): array { if (!$parametersAcceptor instanceof ParametersAcceptorWithPhpDocs) { return $parametersAcceptor->getReturnType()->getReferencedClasses(); @@ -491,7 +566,10 @@ private function getReturnTypeReferencedClasses(ParametersAcceptor $parametersAc return $parametersAcceptor->getNativeReturnType()->getReferencedClasses(); } - return array_merge($parametersAcceptor->getNativeReturnType()->getReferencedClasses(), $parametersAcceptor->getPhpDocReturnType()->getReferencedClasses()); + return array_merge( + $parametersAcceptor->getNativeReturnType()->getReferencedClasses(), + $parametersAcceptor->getPhpDocReturnType()->getReferencedClasses(), + ); } } diff --git a/src/Rules/FunctionReturnTypeCheck.php b/src/Rules/FunctionReturnTypeCheck.php index 3d7991491dc..82bb5d529b9 100644 --- a/src/Rules/FunctionReturnTypeCheck.php +++ b/src/Rules/FunctionReturnTypeCheck.php @@ -16,73 +16,96 @@ class FunctionReturnTypeCheck { + public function __construct(private RuleLevelHelper $ruleLevelHelper) + { + } + /** - * @var RuleLevelHelper - */ - private $ruleLevelHelper; - public function __construct(RuleLevelHelper $ruleLevelHelper) - { - $this->ruleLevelHelper = $ruleLevelHelper; + * @return list + */ + public function checkReturnType( + Scope $scope, + Type $returnType, + ?Expr $returnValue, + Node $returnNode, + string $emptyReturnStatementMessage, + string $voidMessage, + string $typeMismatchMessage, + string $neverMessage, + bool $isGenerator, + ): array + { + $returnType = TypeUtils::resolveLateResolvableTypes($returnType); + + if ($returnType instanceof NeverType && $returnType->isExplicit()) { + return [ + RuleErrorBuilder::message($neverMessage) + ->line($returnNode->getStartLine()) + ->identifier('return.never') + ->build(), + ]; } - /** - * @return list - */ - public function checkReturnType(Scope $scope, Type $returnType, ?Expr $returnValue, Node $returnNode, string $emptyReturnStatementMessage, string $voidMessage, string $typeMismatchMessage, string $neverMessage, bool $isGenerator) : array - { - $returnType = TypeUtils::resolveLateResolvableTypes($returnType); - if ($returnType instanceof NeverType && $returnType->isExplicit()) { - return [ - RuleErrorBuilder::message($neverMessage) - ->line($returnNode->getStartLine()) - ->identifier('return.never') - ->build(), - ]; - } - if ($isGenerator) { - $returnType = $returnType->getTemplateType(Generator::class, 'TReturn'); - if ($returnType instanceof ErrorType) { - return []; - } - } - $isVoidSuperType = $returnType->isVoid(); - $verbosityLevel = VerbosityLevel::getRecommendedLevelByType($returnType, null); - if ($returnValue === null) { - if (!$isVoidSuperType->no()) { - return []; - } - - return [ - RuleErrorBuilder::message(sprintf($emptyReturnStatementMessage, $returnType->describe($verbosityLevel))) - ->line($returnNode->getStartLine()) - ->identifier('return.empty') - ->build(), - ]; - } - if ($returnNode instanceof Expr\Yield_ || $returnNode instanceof Expr\YieldFrom) { - return []; - } - $returnValueType = $scope->getType($returnValue); - $verbosityLevel = VerbosityLevel::getRecommendedLevelByType($returnType, $returnValueType); - if ($isVoidSuperType->yes()) { - return [ - RuleErrorBuilder::message(sprintf($voidMessage, $returnValueType->describe($verbosityLevel))) - ->line($returnNode->getStartLine()) - ->identifier('return.void') - ->build(), - ]; - } - $accepts = $this->ruleLevelHelper->acceptsWithReason($returnType, $returnValueType, $scope->isDeclareStrictTypes()); - if (!$accepts->result) { - return [ - RuleErrorBuilder::message(sprintf($typeMismatchMessage, $returnType->describe($verbosityLevel), $returnValueType->describe($verbosityLevel))) - ->line($returnNode->getStartLine()) - ->identifier('return.type') - ->acceptsReasonsTip($accepts->reasons) - ->build(), - ]; - } - return []; + if ($isGenerator) { + $returnType = $returnType->getTemplateType(Generator::class, 'TReturn'); + if ($returnType instanceof ErrorType) { + return []; + } + } + + $isVoidSuperType = $returnType->isVoid(); + $verbosityLevel = VerbosityLevel::getRecommendedLevelByType($returnType, null); + if ($returnValue === null) { + if (!$isVoidSuperType->no()) { + return []; + } + + return [ + RuleErrorBuilder::message(sprintf( + $emptyReturnStatementMessage, + $returnType->describe($verbosityLevel), + )) + ->line($returnNode->getStartLine()) + ->identifier('return.empty') + ->build(), + ]; + } + + if ($returnNode instanceof Expr\Yield_ || $returnNode instanceof Expr\YieldFrom) { + return []; + } + + $returnValueType = $scope->getType($returnValue); + $verbosityLevel = VerbosityLevel::getRecommendedLevelByType($returnType, $returnValueType); + + if ($isVoidSuperType->yes()) { + return [ + RuleErrorBuilder::message(sprintf( + $voidMessage, + $returnValueType->describe($verbosityLevel), + )) + ->line($returnNode->getStartLine()) + ->identifier('return.void') + ->build(), + ]; } + $accepts = $this->ruleLevelHelper->acceptsWithReason($returnType, $returnValueType, $scope->isDeclareStrictTypes()); + if (!$accepts->result) { + return [ + RuleErrorBuilder::message(sprintf( + $typeMismatchMessage, + $returnType->describe($verbosityLevel), + $returnValueType->describe($verbosityLevel), + )) + ->line($returnNode->getStartLine()) + ->identifier('return.type') + ->acceptsReasonsTip($accepts->reasons) + ->build(), + ]; + } + + return []; + } + } diff --git a/src/Rules/Functions/ArrayFilterRule.php b/src/Rules/Functions/ArrayFilterRule.php index f51cf993f40..d40cdbae121 100644 --- a/src/Rules/Functions/ArrayFilterRule.php +++ b/src/Rules/Functions/ArrayFilterRule.php @@ -20,19 +20,13 @@ class ArrayFilterRule implements Rule { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - /** - * @var bool - */ - private $treatPhpDocTypesAsCertain; - public function __construct(ReflectionProvider $reflectionProvider, bool $treatPhpDocTypesAsCertain) + public function __construct( + private ReflectionProvider $reflectionProvider, + private bool $treatPhpDocTypesAsCertain, + ) { - $this->reflectionProvider = $reflectionProvider; - $this->treatPhpDocTypesAsCertain = $treatPhpDocTypesAsCertain; } + public function getNodeType(): string { return FuncCall::class; @@ -64,7 +58,10 @@ public function processNode(Node $node, Scope $scope): array if ($arrayType->isIterableAtLeastOnce()->no()) { $message = 'Parameter #1 $array (%s) to function array_filter is empty, call has no effect.'; return [ - RuleErrorBuilder::message(sprintf($message, $arrayType->describe(VerbosityLevel::value())))->identifier('arrayFilter.empty')->build(), + RuleErrorBuilder::message(sprintf( + $message, + $arrayType->describe(VerbosityLevel::value()), + ))->identifier('arrayFilter.empty')->build(), ]; } @@ -74,14 +71,20 @@ public function processNode(Node $node, Scope $scope): array if ($isSuperType->no()) { $message = 'Parameter #1 $array (%s) to function array_filter does not contain falsy values, the array will always stay the same.'; return [ - RuleErrorBuilder::message(sprintf($message, $arrayType->describe(VerbosityLevel::value())))->identifier('arrayFilter.same')->build(), + RuleErrorBuilder::message(sprintf( + $message, + $arrayType->describe(VerbosityLevel::value()), + ))->identifier('arrayFilter.same')->build(), ]; } if ($isSuperType->yes()) { $message = 'Parameter #1 $array (%s) to function array_filter contains falsy values only, the result will always be an empty array.'; return [ - RuleErrorBuilder::message(sprintf($message, $arrayType->describe(VerbosityLevel::value())))->identifier('arrayFilter.alwaysEmpty')->build(), + RuleErrorBuilder::message(sprintf( + $message, + $arrayType->describe(VerbosityLevel::value()), + ))->identifier('arrayFilter.alwaysEmpty')->build(), ]; } diff --git a/src/Rules/Functions/ArrowFunctionAttributesRule.php b/src/Rules/Functions/ArrowFunctionAttributesRule.php index 61777a15787..1b4e1ddf031 100644 --- a/src/Rules/Functions/ArrowFunctionAttributesRule.php +++ b/src/Rules/Functions/ArrowFunctionAttributesRule.php @@ -14,13 +14,8 @@ class ArrowFunctionAttributesRule implements Rule { - /** - * @var AttributesCheck - */ - private $attributesCheck; - public function __construct(AttributesCheck $attributesCheck) + public function __construct(private AttributesCheck $attributesCheck) { - $this->attributesCheck = $attributesCheck; } public function getNodeType(): string @@ -30,7 +25,12 @@ public function getNodeType(): string public function processNode(Node $node, Scope $scope): array { - return $this->attributesCheck->check($scope, $node->attrGroups, Attribute::TARGET_FUNCTION, 'function'); + return $this->attributesCheck->check( + $scope, + $node->attrGroups, + Attribute::TARGET_FUNCTION, + 'function', + ); } } diff --git a/src/Rules/Functions/ArrowFunctionReturnNullsafeByRefRule.php b/src/Rules/Functions/ArrowFunctionReturnNullsafeByRefRule.php index ce1dcc02722..371f2fa61a2 100644 --- a/src/Rules/Functions/ArrowFunctionReturnNullsafeByRefRule.php +++ b/src/Rules/Functions/ArrowFunctionReturnNullsafeByRefRule.php @@ -14,13 +14,8 @@ class ArrowFunctionReturnNullsafeByRefRule implements Rule { - /** - * @var NullsafeCheck - */ - private $nullsafeCheck; - public function __construct(NullsafeCheck $nullsafeCheck) + public function __construct(private NullsafeCheck $nullsafeCheck) { - $this->nullsafeCheck = $nullsafeCheck; } public function getNodeType(): string diff --git a/src/Rules/Functions/ArrowFunctionReturnTypeRule.php b/src/Rules/Functions/ArrowFunctionReturnTypeRule.php index 218a947e22b..aa0a9436de4 100644 --- a/src/Rules/Functions/ArrowFunctionReturnTypeRule.php +++ b/src/Rules/Functions/ArrowFunctionReturnTypeRule.php @@ -19,13 +19,8 @@ class ArrowFunctionReturnTypeRule implements Rule { - /** - * @var FunctionReturnTypeCheck - */ - private $returnTypeCheck; - public function __construct(FunctionReturnTypeCheck $returnTypeCheck) + public function __construct(private FunctionReturnTypeCheck $returnTypeCheck) { - $this->returnTypeCheck = $returnTypeCheck; } public function getNodeType(): string @@ -59,7 +54,17 @@ public function processNode(Node $node, Scope $scope): array return []; } - return $this->returnTypeCheck->checkReturnType($scope, $returnType, $originalNode->expr, $originalNode->expr, 'Anonymous function should return %s but empty return statement found.', 'Anonymous function with return type void returns %s but should not return anything.', 'Anonymous function should return %s but returns %s.', 'Anonymous function should never return but return statement found.', $generatorType->isSuperTypeOf($returnType)->yes()); + return $this->returnTypeCheck->checkReturnType( + $scope, + $returnType, + $originalNode->expr, + $originalNode->expr, + 'Anonymous function should return %s but empty return statement found.', + 'Anonymous function with return type void returns %s but should not return anything.', + 'Anonymous function should return %s but returns %s.', + 'Anonymous function should never return but return statement found.', + $generatorType->isSuperTypeOf($returnType)->yes(), + ); } } diff --git a/src/Rules/Functions/CallCallablesRule.php b/src/Rules/Functions/CallCallablesRule.php index 5985f04fad0..e5c0d7dc8cf 100644 --- a/src/Rules/Functions/CallCallablesRule.php +++ b/src/Rules/Functions/CallCallablesRule.php @@ -27,68 +27,92 @@ class CallCallablesRule implements Rule { - /** - * @var FunctionCallParametersCheck - */ - private $check; - /** - * @var RuleLevelHelper - */ - private $ruleLevelHelper; - /** - * @var bool - */ - private $reportMaybes; - public function __construct(FunctionCallParametersCheck $check, RuleLevelHelper $ruleLevelHelper, bool $reportMaybes) + public function __construct( + private FunctionCallParametersCheck $check, + private RuleLevelHelper $ruleLevelHelper, + private bool $reportMaybes, + ) { - $this->check = $check; - $this->ruleLevelHelper = $ruleLevelHelper; - $this->reportMaybes = $reportMaybes; } + public function getNodeType(): string { return Node\Expr\FuncCall::class; } - public function processNode(Node $node, Scope $scope) : array + public function processNode( + Node $node, + Scope $scope, + ): array { if (!$node->name instanceof Node\Expr) { return []; } - $typeResult = $this->ruleLevelHelper->findTypeToCheck($scope, NullsafeOperatorHelper::getNullsafeShortcircuitedExprRespectingScope($scope, $node->name), 'Invoking callable on an unknown class %s.', static function (Type $type) : bool { - return $type->isCallable()->yes(); - }); + + $typeResult = $this->ruleLevelHelper->findTypeToCheck( + $scope, + NullsafeOperatorHelper::getNullsafeShortcircuitedExprRespectingScope($scope, $node->name), + 'Invoking callable on an unknown class %s.', + static fn (Type $type): bool => $type->isCallable()->yes(), + ); $type = $typeResult->getType(); if ($type instanceof ErrorType) { return $typeResult->getUnknownClassErrors(); } + $isCallable = $type->isCallable(); if ($isCallable->no()) { return [ - RuleErrorBuilder::message(sprintf('Trying to invoke %s but it\'s not a callable.', $type->describe(VerbosityLevel::value())))->identifier('callable.nonCallable')->build(), + RuleErrorBuilder::message( + sprintf('Trying to invoke %s but it\'s not a callable.', $type->describe(VerbosityLevel::value())), + )->identifier('callable.nonCallable')->build(), ]; } if ($this->reportMaybes && $isCallable->maybe()) { return [ - RuleErrorBuilder::message(sprintf('Trying to invoke %s but it might not be a callable.', $type->describe(VerbosityLevel::value())))->identifier('callable.nonCallable')->build(), + RuleErrorBuilder::message( + sprintf('Trying to invoke %s but it might not be a callable.', $type->describe(VerbosityLevel::value())), + )->identifier('callable.nonCallable')->build(), ]; } + $parametersAcceptors = $type->getCallableParametersAcceptors($scope); $messages = []; + if ( count($parametersAcceptors) === 1 && $parametersAcceptors[0] instanceof InaccessibleMethod ) { $method = $parametersAcceptors[0]->getMethod(); - $messages[] = RuleErrorBuilder::message(sprintf('Call to %s method %s() of class %s.', $method->isPrivate() ? 'private' : 'protected', $method->getName(), $method->getDeclaringClass()->getDisplayName()))->identifier('callable.inaccessibleMethod')->build(); + $messages[] = RuleErrorBuilder::message(sprintf( + 'Call to %s method %s() of class %s.', + $method->isPrivate() ? 'private' : 'protected', + $method->getName(), + $method->getDeclaringClass()->getDisplayName(), + ))->identifier('callable.inaccessibleMethod')->build(); } - $parametersAcceptor = ParametersAcceptorSelector::selectFromArgs($scope, $node->getArgs(), $parametersAcceptors, null); + + $parametersAcceptor = ParametersAcceptorSelector::selectFromArgs( + $scope, + $node->getArgs(), + $parametersAcceptors, + null, + ); + if ($type instanceof ClosureType) { $callableDescription = 'closure'; } else { $callableDescription = sprintf('callable %s', SprintfHelper::escapeFormatString($type->describe(VerbosityLevel::value()))); } - return array_merge($messages, $this->check->check($parametersAcceptor, $scope, false, $node, [ + + return array_merge( + $messages, + $this->check->check( + $parametersAcceptor, + $scope, + false, + $node, + [ ucfirst($callableDescription) . ' invoked with %d parameter, %d required.', ucfirst($callableDescription) . ' invoked with %d parameters, %d required.', ucfirst($callableDescription) . ' invoked with %d parameter, at least %d required.', @@ -103,7 +127,10 @@ public function processNode(Node $node, Scope $scope) : array 'Unknown parameter $%s in call to ' . $callableDescription . '.', 'Return type of call to ' . $callableDescription . ' contains unresolvable type.', 'Parameter %s of ' . $callableDescription . ' contains unresolvable type.', - ], 'callable')); + ], + 'callable', + ), + ); } } diff --git a/src/Rules/Functions/CallToFunctionParametersRule.php b/src/Rules/Functions/CallToFunctionParametersRule.php index 36cea8115a8..01b80d7f689 100644 --- a/src/Rules/Functions/CallToFunctionParametersRule.php +++ b/src/Rules/Functions/CallToFunctionParametersRule.php @@ -17,18 +17,8 @@ class CallToFunctionParametersRule implements Rule { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - /** - * @var FunctionCallParametersCheck - */ - private $check; - public function __construct(ReflectionProvider $reflectionProvider, FunctionCallParametersCheck $check) + public function __construct(private ReflectionProvider $reflectionProvider, private FunctionCallParametersCheck $check) { - $this->reflectionProvider = $reflectionProvider; - $this->check = $check; } public function getNodeType(): string @@ -49,7 +39,17 @@ public function processNode(Node $node, Scope $scope): array $function = $this->reflectionProvider->getFunction($node->name, $scope); $functionName = SprintfHelper::escapeFormatString($function->getName()); - return $this->check->check(ParametersAcceptorSelector::selectFromArgs($scope, $node->getArgs(), $function->getVariants(), $function->getNamedArgumentsVariants()), $scope, $function->isBuiltin(), $node, [ + return $this->check->check( + ParametersAcceptorSelector::selectFromArgs( + $scope, + $node->getArgs(), + $function->getVariants(), + $function->getNamedArgumentsVariants(), + ), + $scope, + $function->isBuiltin(), + $node, + [ 'Function ' . $functionName . ' invoked with %d parameter, %d required.', 'Function ' . $functionName . ' invoked with %d parameters, %d required.', 'Function ' . $functionName . ' invoked with %d parameter, at least %d required.', @@ -64,7 +64,9 @@ public function processNode(Node $node, Scope $scope): array 'Unknown parameter $%s in call to function ' . $functionName . '.', 'Return type of call to function ' . $functionName . ' contains unresolvable type.', 'Parameter %s of function ' . $functionName . ' contains unresolvable type.', - ], 'function'); + ], + 'function', + ); } } diff --git a/src/Rules/Functions/CallToFunctionStatementWithoutSideEffectsRule.php b/src/Rules/Functions/CallToFunctionStatementWithoutSideEffectsRule.php index 3c1aa855c81..545bcd1a270 100644 --- a/src/Rules/Functions/CallToFunctionStatementWithoutSideEffectsRule.php +++ b/src/Rules/Functions/CallToFunctionStatementWithoutSideEffectsRule.php @@ -19,10 +19,6 @@ class CallToFunctionStatementWithoutSideEffectsRule implements Rule { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; private const SIDE_EFFECT_FLIP_PARAMETERS = [ // functionName => [name, pos, testName, defaultHasSideEffect] 'file_get_contents' => ['context', 2, 'isNotNull', false], @@ -30,9 +26,8 @@ class CallToFunctionStatementWithoutSideEffectsRule implements Rule 'var_export' => ['return', 1, 'isTruthy', true], ]; - public function __construct(ReflectionProvider $reflectionProvider) + public function __construct(private ReflectionProvider $reflectionProvider) { - $this->reflectionProvider = $reflectionProvider; } public function getNodeType(): string @@ -79,12 +74,8 @@ public function processNode(Node $node, Scope $scope): array $sideEffectFlipped = false; $hasNamedParameter = false; $checker = [ - 'isNotNull' => static function (Type $type) { - return $type->isNull()->no(); - }, - 'isTruthy' => static function (Type $type) { - return $type->toBoolean()->isTrue()->yes(); - }, + 'isNotNull' => static fn (Type $type) => $type->isNull()->no(), + 'isTruthy' => static fn (Type $type) => $type->toBoolean()->isTrue()->yes(), ][$testName]; foreach ($funcCall->getRawArgs() as $i => $arg) { @@ -132,7 +123,10 @@ public function processNode(Node $node, Scope $scope): array } return [ - RuleErrorBuilder::message(sprintf('Call to function %s() on a separate line has no effect.', $function->getName()))->identifier('function.resultUnused')->build(), + RuleErrorBuilder::message(sprintf( + 'Call to function %s() on a separate line has no effect.', + $function->getName(), + ))->identifier('function.resultUnused')->build(), ]; } diff --git a/src/Rules/Functions/CallToNonExistentFunctionRule.php b/src/Rules/Functions/CallToNonExistentFunctionRule.php index a62ee9cf7f4..72fca5073c6 100644 --- a/src/Rules/Functions/CallToNonExistentFunctionRule.php +++ b/src/Rules/Functions/CallToNonExistentFunctionRule.php @@ -17,19 +17,13 @@ class CallToNonExistentFunctionRule implements Rule { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - /** - * @var bool - */ - private $checkFunctionNameCase; - public function __construct(ReflectionProvider $reflectionProvider, bool $checkFunctionNameCase) + public function __construct( + private ReflectionProvider $reflectionProvider, + private bool $checkFunctionNameCase, + ) { - $this->reflectionProvider = $reflectionProvider; - $this->checkFunctionNameCase = $checkFunctionNameCase; } + public function getNodeType(): string { return FuncCall::class; @@ -62,7 +56,11 @@ public function processNode(Node $node, Scope $scope): array && $function->getName() !== $calledFunctionName ) { return [ - RuleErrorBuilder::message(sprintf('Call to function %s() with incorrect case: %s', $function->getName(), $name))->identifier('function.nameCase')->build(), + RuleErrorBuilder::message(sprintf( + 'Call to function %s() with incorrect case: %s', + $function->getName(), + $name, + ))->identifier('function.nameCase')->build(), ]; } } diff --git a/src/Rules/Functions/CallUserFuncRule.php b/src/Rules/Functions/CallUserFuncRule.php index 02dfbf91495..040a5aeccec 100644 --- a/src/Rules/Functions/CallUserFuncRule.php +++ b/src/Rules/Functions/CallUserFuncRule.php @@ -18,19 +18,13 @@ class CallUserFuncRule implements Rule { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - /** - * @var FunctionCallParametersCheck - */ - private $check; - public function __construct(ReflectionProvider $reflectionProvider, FunctionCallParametersCheck $check) + public function __construct( + private ReflectionProvider $reflectionProvider, + private FunctionCallParametersCheck $check, + ) { - $this->reflectionProvider = $reflectionProvider; - $this->check = $check; } + public function getNodeType(): string { return FuncCall::class; @@ -55,7 +49,10 @@ public function processNode(Node $node, Scope $scope): array return []; } - $result = ArgumentsNormalizer::reorderCallUserFuncArguments($node, $scope); + $result = ArgumentsNormalizer::reorderCallUserFuncArguments( + $node, + $scope, + ); if ($result === null) { return []; } diff --git a/src/Rules/Functions/ClosureAttributesRule.php b/src/Rules/Functions/ClosureAttributesRule.php index f15c69e1be6..170d9ad05e9 100644 --- a/src/Rules/Functions/ClosureAttributesRule.php +++ b/src/Rules/Functions/ClosureAttributesRule.php @@ -14,13 +14,8 @@ class ClosureAttributesRule implements Rule { - /** - * @var AttributesCheck - */ - private $attributesCheck; - public function __construct(AttributesCheck $attributesCheck) + public function __construct(private AttributesCheck $attributesCheck) { - $this->attributesCheck = $attributesCheck; } public function getNodeType(): string @@ -30,7 +25,12 @@ public function getNodeType(): string public function processNode(Node $node, Scope $scope): array { - return $this->attributesCheck->check($scope, $node->attrGroups, Attribute::TARGET_FUNCTION, 'function'); + return $this->attributesCheck->check( + $scope, + $node->attrGroups, + Attribute::TARGET_FUNCTION, + 'function', + ); } } diff --git a/src/Rules/Functions/ClosureReturnTypeRule.php b/src/Rules/Functions/ClosureReturnTypeRule.php index 5ba78e29f7f..98f72deb737 100644 --- a/src/Rules/Functions/ClosureReturnTypeRule.php +++ b/src/Rules/Functions/ClosureReturnTypeRule.php @@ -16,13 +16,8 @@ class ClosureReturnTypeRule implements Rule { - /** - * @var FunctionReturnTypeCheck - */ - private $returnTypeCheck; - public function __construct(FunctionReturnTypeCheck $returnTypeCheck) + public function __construct(private FunctionReturnTypeCheck $returnTypeCheck) { - $this->returnTypeCheck = $returnTypeCheck; } public function getNodeType(): string @@ -48,7 +43,17 @@ public function processNode(Node $node, Scope $scope): array if ($returnExpr === null && $containsNull && !$hasNativeTypehint) { $returnExpr = new Node\Expr\ConstFetch(new Node\Name\FullyQualified('null')); } - $returnMessages = $this->returnTypeCheck->checkReturnType($returnStatement->getScope(), $returnType, $returnExpr, $returnNode, 'Anonymous function should return %s but empty return statement found.', 'Anonymous function with return type void returns %s but should not return anything.', 'Anonymous function should return %s but returns %s.', 'Anonymous function should never return but return statement found.', $node->isGenerator()); + $returnMessages = $this->returnTypeCheck->checkReturnType( + $returnStatement->getScope(), + $returnType, + $returnExpr, + $returnNode, + 'Anonymous function should return %s but empty return statement found.', + 'Anonymous function with return type void returns %s but should not return anything.', + 'Anonymous function should return %s but returns %s.', + 'Anonymous function should never return but return statement found.', + $node->isGenerator(), + ); foreach ($returnMessages as $returnMessage) { $messages[] = $returnMessage; diff --git a/src/Rules/Functions/DefineParametersRule.php b/src/Rules/Functions/DefineParametersRule.php index 5252a8e6414..5aac3ee5c2c 100644 --- a/src/Rules/Functions/DefineParametersRule.php +++ b/src/Rules/Functions/DefineParametersRule.php @@ -17,13 +17,8 @@ class DefineParametersRule implements Rule { - /** - * @var PhpVersion - */ - private $phpVersion; - public function __construct(PhpVersion $phpVersion) + public function __construct(private PhpVersion $phpVersion) { - $this->phpVersion = $phpVersion; } public function getNodeType(): string @@ -50,7 +45,9 @@ public function processNode(Node $node, Scope $scope): array return []; } return [ - RuleErrorBuilder::message('Argument #3 ($case_insensitive) is ignored since declaration of case-insensitive constants is no longer supported.') + RuleErrorBuilder::message( + 'Argument #3 ($case_insensitive) is ignored since declaration of case-insensitive constants is no longer supported.', + ) ->line($node->getStartLine()) ->identifier('argument.unused') ->build(), diff --git a/src/Rules/Functions/DuplicateFunctionDeclarationRule.php b/src/Rules/Functions/DuplicateFunctionDeclarationRule.php index 1b88d15c1c8..06d92643aee 100644 --- a/src/Rules/Functions/DuplicateFunctionDeclarationRule.php +++ b/src/Rules/Functions/DuplicateFunctionDeclarationRule.php @@ -21,18 +21,8 @@ class DuplicateFunctionDeclarationRule implements Rule { - /** - * @var Reflector - */ - private $reflector; - /** - * @var RelativePathHelper - */ - private $relativePathHelper; - public function __construct(Reflector $reflector, RelativePathHelper $relativePathHelper) + public function __construct(private Reflector $reflector, private RelativePathHelper $relativePathHelper) { - $this->reflector = $reflector; - $this->relativePathHelper = $relativePathHelper; } public function getNodeType(): string @@ -58,9 +48,11 @@ public function processNode(Node $node, Scope $scope): array } return [ - RuleErrorBuilder::message(sprintf("Function %s declared multiple times:\n%s", $thisFunction->getName(), implode("\n", array_map(function (ReflectionFunction $function) { - return sprintf('- %s:%d', $this->relativePathHelper->getRelativePath($function->getFileName() ?? 'unknown'), $function->getStartLine()); - }, $filteredFunctions))))->identifier('function.duplicate')->build(), + RuleErrorBuilder::message(sprintf( + "Function %s declared multiple times:\n%s", + $thisFunction->getName(), + implode("\n", array_map(fn (ReflectionFunction $function) => sprintf('- %s:%d', $this->relativePathHelper->getRelativePath($function->getFileName() ?? 'unknown'), $function->getStartLine()), $filteredFunctions)), + ))->identifier('function.duplicate')->build(), ]; } diff --git a/src/Rules/Functions/ExistingClassesInArrowFunctionTypehintsRule.php b/src/Rules/Functions/ExistingClassesInArrowFunctionTypehintsRule.php index ad78bd124e6..a2107c73a01 100644 --- a/src/Rules/Functions/ExistingClassesInArrowFunctionTypehintsRule.php +++ b/src/Rules/Functions/ExistingClassesInArrowFunctionTypehintsRule.php @@ -18,18 +18,8 @@ class ExistingClassesInArrowFunctionTypehintsRule implements Rule { - /** - * @var FunctionDefinitionCheck - */ - private $check; - /** - * @var PhpVersion - */ - private $phpVersion; - public function __construct(FunctionDefinitionCheck $check, PhpVersion $phpVersion) + public function __construct(private FunctionDefinitionCheck $check, private PhpVersion $phpVersion) { - $this->check = $check; - $this->phpVersion = $phpVersion; } public function getNodeType(): string @@ -50,7 +40,16 @@ public function processNode(Node $node, Scope $scope): array } } - return array_merge($messages, $this->check->checkAnonymousFunction($scope, $node->getParams(), $node->getReturnType(), 'Parameter $%s of anonymous function has invalid type %s.', 'Anonymous function has invalid return type %s.', 'Anonymous function uses native union types but they\'re supported only on PHP 8.0 and later.', 'Parameter $%s of anonymous function has unresolvable native type.', 'Anonymous function has unresolvable native return type.')); + return array_merge($messages, $this->check->checkAnonymousFunction( + $scope, + $node->getParams(), + $node->getReturnType(), + 'Parameter $%s of anonymous function has invalid type %s.', + 'Anonymous function has invalid return type %s.', + 'Anonymous function uses native union types but they\'re supported only on PHP 8.0 and later.', + 'Parameter $%s of anonymous function has unresolvable native type.', + 'Anonymous function has unresolvable native return type.', + )); } } diff --git a/src/Rules/Functions/ExistingClassesInClosureTypehintsRule.php b/src/Rules/Functions/ExistingClassesInClosureTypehintsRule.php index c77b02b7bc4..2c6dbd3ad04 100644 --- a/src/Rules/Functions/ExistingClassesInClosureTypehintsRule.php +++ b/src/Rules/Functions/ExistingClassesInClosureTypehintsRule.php @@ -14,13 +14,8 @@ class ExistingClassesInClosureTypehintsRule implements Rule { - /** - * @var FunctionDefinitionCheck - */ - private $check; - public function __construct(FunctionDefinitionCheck $check) + public function __construct(private FunctionDefinitionCheck $check) { - $this->check = $check; } public function getNodeType(): string @@ -30,7 +25,16 @@ public function getNodeType(): string public function processNode(Node $node, Scope $scope): array { - return $this->check->checkAnonymousFunction($scope, $node->getParams(), $node->getReturnType(), 'Parameter $%s of anonymous function has invalid type %s.', 'Anonymous function has invalid return type %s.', 'Anonymous function uses native union types but they\'re supported only on PHP 8.0 and later.', 'Parameter $%s of anonymous function has unresolvable native type.', 'Anonymous function has unresolvable native return type.'); + return $this->check->checkAnonymousFunction( + $scope, + $node->getParams(), + $node->getReturnType(), + 'Parameter $%s of anonymous function has invalid type %s.', + 'Anonymous function has invalid return type %s.', + 'Anonymous function uses native union types but they\'re supported only on PHP 8.0 and later.', + 'Parameter $%s of anonymous function has unresolvable native type.', + 'Anonymous function has unresolvable native return type.', + ); } } diff --git a/src/Rules/Functions/ExistingClassesInTypehintsRule.php b/src/Rules/Functions/ExistingClassesInTypehintsRule.php index 0e69aade124..6a9586a820a 100644 --- a/src/Rules/Functions/ExistingClassesInTypehintsRule.php +++ b/src/Rules/Functions/ExistingClassesInTypehintsRule.php @@ -16,13 +16,8 @@ class ExistingClassesInTypehintsRule implements Rule { - /** - * @var FunctionDefinitionCheck - */ - private $check; - public function __construct(FunctionDefinitionCheck $check) + public function __construct(private FunctionDefinitionCheck $check) { - $this->check = $check; } public function getNodeType(): string @@ -34,7 +29,28 @@ public function processNode(Node $node, Scope $scope): array { $functionName = SprintfHelper::escapeFormatString($node->getFunctionReflection()->getName()); - return $this->check->checkFunction($node->getOriginalNode(), $node->getFunctionReflection(), sprintf('Parameter $%%s of function %s() has invalid type %%s.', $functionName), sprintf('Function %s() has invalid return type %%s.', $functionName), sprintf('Function %s() uses native union types but they\'re supported only on PHP 8.0 and later.', $functionName), sprintf('Template type %%s of function %s() is not referenced in a parameter.', $functionName), sprintf('Parameter $%%s of function %s() has unresolvable native type.', $functionName), sprintf('Function %s() has unresolvable native return type.', $functionName)); + return $this->check->checkFunction( + $node->getOriginalNode(), + $node->getFunctionReflection(), + sprintf( + 'Parameter $%%s of function %s() has invalid type %%s.', + $functionName, + ), + sprintf( + 'Function %s() has invalid return type %%s.', + $functionName, + ), + sprintf('Function %s() uses native union types but they\'re supported only on PHP 8.0 and later.', $functionName), + sprintf('Template type %%s of function %s() is not referenced in a parameter.', $functionName), + sprintf( + 'Parameter $%%s of function %s() has unresolvable native type.', + $functionName, + ), + sprintf( + 'Function %s() has unresolvable native return type.', + $functionName, + ), + ); } } diff --git a/src/Rules/Functions/FunctionAttributesRule.php b/src/Rules/Functions/FunctionAttributesRule.php index 4fe6ef6bed1..2ccf122ac21 100644 --- a/src/Rules/Functions/FunctionAttributesRule.php +++ b/src/Rules/Functions/FunctionAttributesRule.php @@ -14,13 +14,8 @@ class FunctionAttributesRule implements Rule { - /** - * @var AttributesCheck - */ - private $attributesCheck; - public function __construct(AttributesCheck $attributesCheck) + public function __construct(private AttributesCheck $attributesCheck) { - $this->attributesCheck = $attributesCheck; } public function getNodeType(): string @@ -30,7 +25,12 @@ public function getNodeType(): string public function processNode(Node $node, Scope $scope): array { - return $this->attributesCheck->check($scope, $node->attrGroups, Attribute::TARGET_FUNCTION, 'function'); + return $this->attributesCheck->check( + $scope, + $node->attrGroups, + Attribute::TARGET_FUNCTION, + 'function', + ); } } diff --git a/src/Rules/Functions/FunctionCallableRule.php b/src/Rules/Functions/FunctionCallableRule.php index 911a25267e4..fdecd2073f8 100644 --- a/src/Rules/Functions/FunctionCallableRule.php +++ b/src/Rules/Functions/FunctionCallableRule.php @@ -23,33 +23,8 @@ class FunctionCallableRule implements Rule { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - /** - * @var RuleLevelHelper - */ - private $ruleLevelHelper; - /** - * @var PhpVersion - */ - private $phpVersion; - /** - * @var bool - */ - private $checkFunctionNameCase; - /** - * @var bool - */ - private $reportMaybes; - public function __construct(ReflectionProvider $reflectionProvider, RuleLevelHelper $ruleLevelHelper, PhpVersion $phpVersion, bool $checkFunctionNameCase, bool $reportMaybes) + public function __construct(private ReflectionProvider $reflectionProvider, private RuleLevelHelper $ruleLevelHelper, private PhpVersion $phpVersion, private bool $checkFunctionNameCase, private bool $reportMaybes) { - $this->reflectionProvider = $reflectionProvider; - $this->ruleLevelHelper = $ruleLevelHelper; - $this->phpVersion = $phpVersion; - $this->checkFunctionNameCase = $checkFunctionNameCase; - $this->reportMaybes = $reportMaybes; } public function getNodeType(): string @@ -82,7 +57,11 @@ public function processNode(Node $node, Scope $scope): array && $function->getName() !== $calledFunctionName ) { return [ - RuleErrorBuilder::message(sprintf('Call to function %s() with incorrect case: %s', $function->getName(), $functionNameName))->identifier('function.nameCase')->build(), + RuleErrorBuilder::message(sprintf( + 'Call to function %s() with incorrect case: %s', + $function->getName(), + $functionNameName, + ))->identifier('function.nameCase')->build(), ]; } } @@ -101,9 +80,12 @@ public function processNode(Node $node, Scope $scope): array ]; } - $typeResult = $this->ruleLevelHelper->findTypeToCheck($scope, NullsafeOperatorHelper::getNullsafeShortcircuitedExprRespectingScope($scope, $functionName), 'Creating callable from an unknown class %s.', static function (Type $type) : bool { - return $type->isCallable()->yes(); - }); + $typeResult = $this->ruleLevelHelper->findTypeToCheck( + $scope, + NullsafeOperatorHelper::getNullsafeShortcircuitedExprRespectingScope($scope, $functionName), + 'Creating callable from an unknown class %s.', + static fn (Type $type): bool => $type->isCallable()->yes(), + ); $type = $typeResult->getType(); if ($type instanceof ErrorType) { return $typeResult->getUnknownClassErrors(); @@ -112,12 +94,16 @@ public function processNode(Node $node, Scope $scope): array $isCallable = $type->isCallable(); if ($isCallable->no()) { return [ - RuleErrorBuilder::message(sprintf('Creating callable from %s but it\'s not a callable.', $type->describe(VerbosityLevel::value())))->identifier('callable.nonCallable')->build(), + RuleErrorBuilder::message( + sprintf('Creating callable from %s but it\'s not a callable.', $type->describe(VerbosityLevel::value())), + )->identifier('callable.nonCallable')->build(), ]; } if ($this->reportMaybes && $isCallable->maybe()) { return [ - RuleErrorBuilder::message(sprintf('Creating callable from %s but it might not be a callable.', $type->describe(VerbosityLevel::value())))->identifier('callable.nonCallable')->build(), + RuleErrorBuilder::message( + sprintf('Creating callable from %s but it might not be a callable.', $type->describe(VerbosityLevel::value())), + )->identifier('callable.nonCallable')->build(), ]; } diff --git a/src/Rules/Functions/ImplodeFunctionRule.php b/src/Rules/Functions/ImplodeFunctionRule.php index c5493b8c309..a9615bedeb2 100644 --- a/src/Rules/Functions/ImplodeFunctionRule.php +++ b/src/Rules/Functions/ImplodeFunctionRule.php @@ -22,19 +22,13 @@ class ImplodeFunctionRule implements Rule { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - /** - * @var RuleLevelHelper - */ - private $ruleLevelHelper; - public function __construct(ReflectionProvider $reflectionProvider, RuleLevelHelper $ruleLevelHelper) + public function __construct( + private ReflectionProvider $reflectionProvider, + private RuleLevelHelper $ruleLevelHelper, + ) { - $this->reflectionProvider = $reflectionProvider; - $this->ruleLevelHelper = $ruleLevelHelper; } + public function getNodeType(): string { return FuncCall::class; @@ -62,9 +56,12 @@ public function processNode(Node $node, Scope $scope): array return []; } - $typeResult = $this->ruleLevelHelper->findTypeToCheck($scope, $arrayArg, '', static function (Type $type) : bool { - return !$type->getIterableValueType()->toString() instanceof ErrorType; - }); + $typeResult = $this->ruleLevelHelper->findTypeToCheck( + $scope, + $arrayArg, + '', + static fn (Type $type): bool => !$type->getIterableValueType()->toString() instanceof ErrorType, + ); if ($typeResult->getType() instanceof ErrorType || !$typeResult->getType()->getIterableValueType()->toString() instanceof ErrorType) { @@ -72,7 +69,9 @@ public function processNode(Node $node, Scope $scope): array } return [ - RuleErrorBuilder::message(sprintf('Parameter #%d $array of function %s expects array, %s given.', $paramNo, $functionName, $typeResult->getType()->describe(VerbosityLevel::typeOnly())))->identifier('argument.type')->build(), + RuleErrorBuilder::message( + sprintf('Parameter #%d $array of function %s expects array, %s given.', $paramNo, $functionName, $typeResult->getType()->describe(VerbosityLevel::typeOnly())), + )->identifier('argument.type')->build(), ]; } diff --git a/src/Rules/Functions/IncompatibleArrowFunctionDefaultParameterTypeRule.php b/src/Rules/Functions/IncompatibleArrowFunctionDefaultParameterTypeRule.php index 42233fa9b65..585b00137a2 100644 --- a/src/Rules/Functions/IncompatibleArrowFunctionDefaultParameterTypeRule.php +++ b/src/Rules/Functions/IncompatibleArrowFunctionDefaultParameterTypeRule.php @@ -51,7 +51,13 @@ public function processNode(Node $node, Scope $scope): array $verbosityLevel = VerbosityLevel::getRecommendedLevelByType($parameterType, $defaultValueType); - $errors[] = RuleErrorBuilder::message(sprintf('Default value of the parameter #%d $%s (%s) of anonymous function is incompatible with type %s.', $paramI + 1, $param->var->name, $defaultValueType->describe($verbosityLevel), $parameterType->describe($verbosityLevel))) + $errors[] = RuleErrorBuilder::message(sprintf( + 'Default value of the parameter #%d $%s (%s) of anonymous function is incompatible with type %s.', + $paramI + 1, + $param->var->name, + $defaultValueType->describe($verbosityLevel), + $parameterType->describe($verbosityLevel), + )) ->line($param->getStartLine()) ->identifier('parameter.defaultValue') ->acceptsReasonsTip($accepts->reasons) diff --git a/src/Rules/Functions/IncompatibleClosureDefaultParameterTypeRule.php b/src/Rules/Functions/IncompatibleClosureDefaultParameterTypeRule.php index 998dcdcbea9..3cd1c513902 100644 --- a/src/Rules/Functions/IncompatibleClosureDefaultParameterTypeRule.php +++ b/src/Rules/Functions/IncompatibleClosureDefaultParameterTypeRule.php @@ -51,7 +51,13 @@ public function processNode(Node $node, Scope $scope): array $verbosityLevel = VerbosityLevel::getRecommendedLevelByType($parameterType, $defaultValueType); - $errors[] = RuleErrorBuilder::message(sprintf('Default value of the parameter #%d $%s (%s) of anonymous function is incompatible with type %s.', $paramI + 1, $param->var->name, $defaultValueType->describe($verbosityLevel), $parameterType->describe($verbosityLevel))) + $errors[] = RuleErrorBuilder::message(sprintf( + 'Default value of the parameter #%d $%s (%s) of anonymous function is incompatible with type %s.', + $paramI + 1, + $param->var->name, + $defaultValueType->describe($verbosityLevel), + $parameterType->describe($verbosityLevel), + )) ->line($param->getStartLine()) ->identifier('parameter.defaultValue') ->acceptsReasonsTip($accepts->reasons) diff --git a/src/Rules/Functions/IncompatibleDefaultParameterTypeRule.php b/src/Rules/Functions/IncompatibleDefaultParameterTypeRule.php index 176530ecdfc..a142269a68b 100644 --- a/src/Rules/Functions/IncompatibleDefaultParameterTypeRule.php +++ b/src/Rules/Functions/IncompatibleDefaultParameterTypeRule.php @@ -53,7 +53,14 @@ public function processNode(Node $node, Scope $scope): array $verbosityLevel = VerbosityLevel::getRecommendedLevelByType($parameterType, $defaultValueType); - $errors[] = RuleErrorBuilder::message(sprintf('Default value of the parameter #%d $%s (%s) of function %s() is incompatible with type %s.', $paramI + 1, $param->var->name, $defaultValueType->describe($verbosityLevel), $function->getName(), $parameterType->describe($verbosityLevel))) + $errors[] = RuleErrorBuilder::message(sprintf( + 'Default value of the parameter #%d $%s (%s) of function %s() is incompatible with type %s.', + $paramI + 1, + $param->var->name, + $defaultValueType->describe($verbosityLevel), + $function->getName(), + $parameterType->describe($verbosityLevel), + )) ->line($param->getStartLine()) ->identifier('parameter.defaultValue') ->acceptsReasonsTip($accepts->reasons) diff --git a/src/Rules/Functions/InnerFunctionRule.php b/src/Rules/Functions/InnerFunctionRule.php index f5820a57a85..24118f5fbbe 100644 --- a/src/Rules/Functions/InnerFunctionRule.php +++ b/src/Rules/Functions/InnerFunctionRule.php @@ -26,7 +26,9 @@ public function processNode(Node $node, Scope $scope): array } return [ - RuleErrorBuilder::message('Inner named functions are not supported by PHPStan. Consider refactoring to an anonymous function, class method, or a top-level-defined function. See issue #165 (https://github.com/phpstan/phpstan/issues/165) for more details.')->identifier('function.inner')->build(), + RuleErrorBuilder::message( + 'Inner named functions are not supported by PHPStan. Consider refactoring to an anonymous function, class method, or a top-level-defined function. See issue #165 (https://github.com/phpstan/phpstan/issues/165) for more details.', + )->identifier('function.inner')->build(), ]; } diff --git a/src/Rules/Functions/InvalidLexicalVariablesInClosureUseRule.php b/src/Rules/Functions/InvalidLexicalVariablesInClosureUseRule.php index 43cbd0c28b1..5c924f370ba 100644 --- a/src/Rules/Functions/InvalidLexicalVariablesInClosureUseRule.php +++ b/src/Rules/Functions/InvalidLexicalVariablesInClosureUseRule.php @@ -41,7 +41,8 @@ public function getNodeType(): string public function processNode(Node $node, Scope $scope): array { $errors = []; - $params = array_filter(array_map(static function (Node\Param $param) { + $params = array_filter(array_map( + static function (Node\Param $param) { if (!$param->var instanceof Node\Expr\Variable) { return false; } @@ -51,7 +52,9 @@ public function processNode(Node $node, Scope $scope): array } return $param->var->name; - }, $node->getParams())); + }, + $node->getParams(), + )); foreach ($node->uses as $use) { if (!is_string($use->var->name)) { diff --git a/src/Rules/Functions/MissingFunctionParameterTypehintRule.php b/src/Rules/Functions/MissingFunctionParameterTypehintRule.php index 29d8a635677..1cafd368929 100644 --- a/src/Rules/Functions/MissingFunctionParameterTypehintRule.php +++ b/src/Rules/Functions/MissingFunctionParameterTypehintRule.php @@ -23,14 +23,12 @@ final class MissingFunctionParameterTypehintRule implements Rule { - /** - * @var MissingTypehintCheck - */ - private $missingTypehintCheck; - public function __construct(MissingTypehintCheck $missingTypehintCheck) + public function __construct( + private MissingTypehintCheck $missingTypehintCheck, + ) { - $this->missingTypehintCheck = $missingTypehintCheck; } + public function getNodeType(): string { return InFunctionNode::class; @@ -59,28 +57,48 @@ private function checkFunctionParameter(FunctionReflection $functionReflection, if ($parameterType instanceof MixedType && !$parameterType->isExplicitMixed()) { return [ - RuleErrorBuilder::message(sprintf('Function %s() has parameter $%s with no type specified.', $functionReflection->getName(), $parameterReflection->getName()))->identifier('missingType.parameter')->build(), + RuleErrorBuilder::message(sprintf( + 'Function %s() has parameter $%s with no type specified.', + $functionReflection->getName(), + $parameterReflection->getName(), + ))->identifier('missingType.parameter')->build(), ]; } $messages = []; foreach ($this->missingTypehintCheck->getIterableTypesWithMissingValueTypehint($parameterType) as $iterableType) { $iterableTypeDescription = $iterableType->describe(VerbosityLevel::typeOnly()); - $messages[] = RuleErrorBuilder::message(sprintf('Function %s() has parameter $%s with no value type specified in iterable type %s.', $functionReflection->getName(), $parameterReflection->getName(), $iterableTypeDescription)) + $messages[] = RuleErrorBuilder::message(sprintf( + 'Function %s() has parameter $%s with no value type specified in iterable type %s.', + $functionReflection->getName(), + $parameterReflection->getName(), + $iterableTypeDescription, + )) ->tip(MissingTypehintCheck::MISSING_ITERABLE_VALUE_TYPE_TIP) ->identifier('missingType.iterableValue') ->build(); } foreach ($this->missingTypehintCheck->getNonGenericObjectTypesWithGenericClass($parameterType) as [$name, $genericTypeNames]) { - $messages[] = RuleErrorBuilder::message(sprintf('Function %s() has parameter $%s with generic %s but does not specify its types: %s', $functionReflection->getName(), $parameterReflection->getName(), $name, implode(', ', $genericTypeNames))) + $messages[] = RuleErrorBuilder::message(sprintf( + 'Function %s() has parameter $%s with generic %s but does not specify its types: %s', + $functionReflection->getName(), + $parameterReflection->getName(), + $name, + implode(', ', $genericTypeNames), + )) ->tip(MissingTypehintCheck::TURN_OFF_NON_GENERIC_CHECK_TIP) ->identifier('missingType.generics') ->build(); } foreach ($this->missingTypehintCheck->getCallablesWithMissingSignature($parameterType) as $callableType) { - $messages[] = RuleErrorBuilder::message(sprintf('Function %s() has parameter $%s with no signature specified for %s.', $functionReflection->getName(), $parameterReflection->getName(), $callableType->describe(VerbosityLevel::typeOnly())))->identifier('missingType.callable')->build(); + $messages[] = RuleErrorBuilder::message(sprintf( + 'Function %s() has parameter $%s with no signature specified for %s.', + $functionReflection->getName(), + $parameterReflection->getName(), + $callableType->describe(VerbosityLevel::typeOnly()), + ))->identifier('missingType.callable')->build(); } return $messages; diff --git a/src/Rules/Functions/MissingFunctionReturnTypehintRule.php b/src/Rules/Functions/MissingFunctionReturnTypehintRule.php index 45eeaafaa79..9f2607f8130 100644 --- a/src/Rules/Functions/MissingFunctionReturnTypehintRule.php +++ b/src/Rules/Functions/MissingFunctionReturnTypehintRule.php @@ -20,14 +20,12 @@ final class MissingFunctionReturnTypehintRule implements Rule { - /** - * @var MissingTypehintCheck - */ - private $missingTypehintCheck; - public function __construct(MissingTypehintCheck $missingTypehintCheck) + public function __construct( + private MissingTypehintCheck $missingTypehintCheck, + ) { - $this->missingTypehintCheck = $missingTypehintCheck; } + public function getNodeType(): string { return InFunctionNode::class; @@ -40,7 +38,10 @@ public function processNode(Node $node, Scope $scope): array if ($returnType instanceof MixedType && !$returnType->isExplicitMixed()) { return [ - RuleErrorBuilder::message(sprintf('Function %s() has no return type specified.', $functionReflection->getName()))->identifier('missingType.return')->build(), + RuleErrorBuilder::message(sprintf( + 'Function %s() has no return type specified.', + $functionReflection->getName(), + ))->identifier('missingType.return')->build(), ]; } @@ -54,14 +55,23 @@ public function processNode(Node $node, Scope $scope): array } foreach ($this->missingTypehintCheck->getNonGenericObjectTypesWithGenericClass($returnType) as [$name, $genericTypeNames]) { - $messages[] = RuleErrorBuilder::message(sprintf('Function %s() return type with generic %s does not specify its types: %s', $functionReflection->getName(), $name, implode(', ', $genericTypeNames))) + $messages[] = RuleErrorBuilder::message(sprintf( + 'Function %s() return type with generic %s does not specify its types: %s', + $functionReflection->getName(), + $name, + implode(', ', $genericTypeNames), + )) ->tip(MissingTypehintCheck::TURN_OFF_NON_GENERIC_CHECK_TIP) ->identifier('missingType.generics') ->build(); } foreach ($this->missingTypehintCheck->getCallablesWithMissingSignature($returnType) as $callableType) { - $messages[] = RuleErrorBuilder::message(sprintf('Function %s() return type has no signature specified for %s.', $functionReflection->getName(), $callableType->describe(VerbosityLevel::typeOnly())))->identifier('missingType.callable')->build(); + $messages[] = RuleErrorBuilder::message(sprintf( + 'Function %s() return type has no signature specified for %s.', + $functionReflection->getName(), + $callableType->describe(VerbosityLevel::typeOnly()), + ))->identifier('missingType.callable')->build(); } return $messages; diff --git a/src/Rules/Functions/ParamAttributesRule.php b/src/Rules/Functions/ParamAttributesRule.php index 4e1db5cdf15..ee9e8f257c5 100644 --- a/src/Rules/Functions/ParamAttributesRule.php +++ b/src/Rules/Functions/ParamAttributesRule.php @@ -14,13 +14,8 @@ class ParamAttributesRule implements Rule { - /** - * @var AttributesCheck - */ - private $attributesCheck; - public function __construct(AttributesCheck $attributesCheck) + public function __construct(private AttributesCheck $attributesCheck) { - $this->attributesCheck = $attributesCheck; } public function getNodeType(): string @@ -37,7 +32,12 @@ public function processNode(Node $node, Scope $scope): array $targetType |= Attribute::TARGET_PROPERTY; } - return $this->attributesCheck->check($scope, $node->attrGroups, $targetType, $targetName); + return $this->attributesCheck->check( + $scope, + $node->attrGroups, + $targetType, + $targetName, + ); } } diff --git a/src/Rules/Functions/PrintfParametersRule.php b/src/Rules/Functions/PrintfParametersRule.php index 15c94de062f..8f5f9f2bd57 100644 --- a/src/Rules/Functions/PrintfParametersRule.php +++ b/src/Rules/Functions/PrintfParametersRule.php @@ -25,13 +25,8 @@ class PrintfParametersRule implements Rule { - /** - * @var PhpVersion - */ - private $phpVersion; - public function __construct(PhpVersion $phpVersion) + public function __construct(private PhpVersion $phpVersion) { - $this->phpVersion = $phpVersion; } public function getNodeType(): string @@ -96,7 +91,16 @@ public function processNode(Node $node, Scope $scope): array if ($argsCount !== $placeHoldersCount + 1) { return [ - RuleErrorBuilder::message(sprintf(sprintf('%s, %s.', $placeHoldersCount === 1 ? 'Call to %s contains %d placeholder' : 'Call to %s contains %d placeholders', $argsCount - 1 === 1 ? '%d value given' : '%d values given'), $name, $placeHoldersCount, $argsCount - 1))->identifier(sprintf('argument.%s', $name))->build(), + RuleErrorBuilder::message(sprintf( + sprintf( + '%s, %s.', + $placeHoldersCount === 1 ? 'Call to %s contains %d placeholder' : 'Call to %s contains %d placeholders', + $argsCount - 1 === 1 ? '%d value given' : '%d values given', + ), + $name, + $placeHoldersCount, + $argsCount - 1, + ))->identifier(sprintf('argument.%s', $name))->build(), ]; } @@ -121,9 +125,7 @@ private function getPlaceholdersCount(string $functionName, string $format): int return 0; } - $placeholders = array_filter($matches, static function (array $match) : bool { - return strlen($match['before']) % 2 === 0; - }); + $placeholders = array_filter($matches, static fn (array $match): bool => strlen($match['before']) % 2 === 0); if (count($placeholders) === 0) { return 0; diff --git a/src/Rules/Functions/RandomIntParametersRule.php b/src/Rules/Functions/RandomIntParametersRule.php index d72ebc67d96..cc9da2c3ed0 100644 --- a/src/Rules/Functions/RandomIntParametersRule.php +++ b/src/Rules/Functions/RandomIntParametersRule.php @@ -21,18 +21,8 @@ class RandomIntParametersRule implements Rule { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - /** - * @var bool - */ - private $reportMaybes; - public function __construct(ReflectionProvider $reflectionProvider, bool $reportMaybes) + public function __construct(private ReflectionProvider $reflectionProvider, private bool $reportMaybes) { - $this->reflectionProvider = $reflectionProvider; - $this->reportMaybes = $reportMaybes; } public function getNodeType(): string @@ -70,7 +60,11 @@ public function processNode(Node $node, Scope $scope): array if ($isSmaller->yes() || $isSmaller->maybe() && $this->reportMaybes) { $message = 'Parameter #1 $min (%s) of function random_int expects lower number than parameter #2 $max (%s).'; return [ - RuleErrorBuilder::message(sprintf($message, $minType->describe(VerbosityLevel::value()), $maxType->describe(VerbosityLevel::value())))->identifier('argument.type')->build(), + RuleErrorBuilder::message(sprintf( + $message, + $minType->describe(VerbosityLevel::value()), + $maxType->describe(VerbosityLevel::value()), + ))->identifier('argument.type')->build(), ]; } diff --git a/src/Rules/Functions/ReturnNullsafeByRefRule.php b/src/Rules/Functions/ReturnNullsafeByRefRule.php index 1086898bb84..84f2c81f3cd 100644 --- a/src/Rules/Functions/ReturnNullsafeByRefRule.php +++ b/src/Rules/Functions/ReturnNullsafeByRefRule.php @@ -15,13 +15,8 @@ class ReturnNullsafeByRefRule implements Rule { - /** - * @var NullsafeCheck - */ - private $nullsafeCheck; - public function __construct(NullsafeCheck $nullsafeCheck) + public function __construct(private NullsafeCheck $nullsafeCheck) { - $this->nullsafeCheck = $nullsafeCheck; } public function getNodeType(): string diff --git a/src/Rules/Functions/ReturnTypeRule.php b/src/Rules/Functions/ReturnTypeRule.php index 94e2c23810e..ab9897713b9 100644 --- a/src/Rules/Functions/ReturnTypeRule.php +++ b/src/Rules/Functions/ReturnTypeRule.php @@ -18,14 +18,12 @@ class ReturnTypeRule implements Rule { - /** - * @var FunctionReturnTypeCheck - */ - private $returnTypeCheck; - public function __construct(FunctionReturnTypeCheck $returnTypeCheck) + public function __construct( + private FunctionReturnTypeCheck $returnTypeCheck, + ) { - $this->returnTypeCheck = $returnTypeCheck; } + public function getNodeType(): string { return Return_::class; @@ -49,7 +47,29 @@ public function processNode(Node $node, Scope $scope): array return []; } - return $this->returnTypeCheck->checkReturnType($scope, ParametersAcceptorSelector::selectSingle($function->getVariants())->getReturnType(), $node->expr, $node, sprintf('Function %s() should return %%s but empty return statement found.', $function->getName()), sprintf('Function %s() with return type void returns %%s but should not return anything.', $function->getName()), sprintf('Function %s() should return %%s but returns %%s.', $function->getName()), sprintf('Function %s() should never return but return statement found.', $function->getName()), $function->isGenerator()); + return $this->returnTypeCheck->checkReturnType( + $scope, + ParametersAcceptorSelector::selectSingle($function->getVariants())->getReturnType(), + $node->expr, + $node, + sprintf( + 'Function %s() should return %%s but empty return statement found.', + $function->getName(), + ), + sprintf( + 'Function %s() with return type void returns %%s but should not return anything.', + $function->getName(), + ), + sprintf( + 'Function %s() should return %%s but returns %%s.', + $function->getName(), + ), + sprintf( + 'Function %s() should never return but return statement found.', + $function->getName(), + ), + $function->isGenerator(), + ); } } diff --git a/src/Rules/Functions/UnusedClosureUsesRule.php b/src/Rules/Functions/UnusedClosureUsesRule.php index 9a27d4d5230..0caa2c2ae96 100644 --- a/src/Rules/Functions/UnusedClosureUsesRule.php +++ b/src/Rules/Functions/UnusedClosureUsesRule.php @@ -17,13 +17,8 @@ class UnusedClosureUsesRule implements Rule { - /** - * @var UnusedFunctionParametersCheck - */ - private $check; - public function __construct(UnusedFunctionParametersCheck $check) + public function __construct(private UnusedFunctionParametersCheck $check) { - $this->check = $check; } public function getNodeType(): string @@ -37,12 +32,18 @@ public function processNode(Node $node, Scope $scope): array return []; } - return $this->check->getUnusedParameters($scope, array_map(static function (Node\Expr\ClosureUse $use): string { + return $this->check->getUnusedParameters( + $scope, + array_map(static function (Node\Expr\ClosureUse $use): string { if (!is_string($use->var->name)) { throw new ShouldNotHappenException(); } return $use->var->name; - }, $node->uses), $node->stmts, 'Anonymous function has an unused use $%s.', 'closure.unusedUse'); + }, $node->uses), + $node->stmts, + 'Anonymous function has an unused use $%s.', + 'closure.unusedUse', + ); } } diff --git a/src/Rules/Generators/YieldFromTypeRule.php b/src/Rules/Generators/YieldFromTypeRule.php index 61667d66b84..deb3f8212ee 100644 --- a/src/Rules/Generators/YieldFromTypeRule.php +++ b/src/Rules/Generators/YieldFromTypeRule.php @@ -21,19 +21,13 @@ class YieldFromTypeRule implements Rule { - /** - * @var RuleLevelHelper - */ - private $ruleLevelHelper; - /** - * @var bool - */ - private $reportMaybes; - public function __construct(RuleLevelHelper $ruleLevelHelper, bool $reportMaybes) + public function __construct( + private RuleLevelHelper $ruleLevelHelper, + private bool $reportMaybes, + ) { - $this->ruleLevelHelper = $ruleLevelHelper; - $this->reportMaybes = $reportMaybes; } + public function getNodeType(): string { return YieldFrom::class; @@ -46,7 +40,10 @@ public function processNode(Node $node, Scope $scope): array $messagePattern = 'Argument of an invalid type %s passed to yield from, only iterables are supported.'; if ($isIterable->no()) { return [ - RuleErrorBuilder::message(sprintf($messagePattern, $exprType->describe(VerbosityLevel::typeOnly()))) + RuleErrorBuilder::message(sprintf( + $messagePattern, + $exprType->describe(VerbosityLevel::typeOnly()), + )) ->line($node->expr->getStartLine()) ->identifier('generator.nonIterable') ->build(), @@ -57,7 +54,10 @@ public function processNode(Node $node, Scope $scope): array && $isIterable->maybe() ) { return [ - RuleErrorBuilder::message(sprintf($messagePattern, $exprType->describe(VerbosityLevel::typeOnly()))) + RuleErrorBuilder::message(sprintf( + $messagePattern, + $exprType->describe(VerbosityLevel::typeOnly()), + )) ->line($node->expr->getStartLine()) ->identifier('generator.nonIterable') ->build(), @@ -82,7 +82,11 @@ public function processNode(Node $node, Scope $scope): array $acceptsKey = $this->ruleLevelHelper->acceptsWithReason($returnType->getIterableKeyType(), $exprType->getIterableKeyType(), $scope->isDeclareStrictTypes()); if (!$acceptsKey->result) { $verbosityLevel = VerbosityLevel::getRecommendedLevelByType($returnType->getIterableKeyType(), $exprType->getIterableKeyType()); - $messages[] = RuleErrorBuilder::message(sprintf('Generator expects key type %s, %s given.', $returnType->getIterableKeyType()->describe($verbosityLevel), $exprType->getIterableKeyType()->describe($verbosityLevel))) + $messages[] = RuleErrorBuilder::message(sprintf( + 'Generator expects key type %s, %s given.', + $returnType->getIterableKeyType()->describe($verbosityLevel), + $exprType->getIterableKeyType()->describe($verbosityLevel), + )) ->line($node->expr->getStartLine()) ->identifier('generator.keyType') ->acceptsReasonsTip($acceptsKey->reasons) @@ -92,7 +96,11 @@ public function processNode(Node $node, Scope $scope): array $acceptsValue = $this->ruleLevelHelper->acceptsWithReason($returnType->getIterableValueType(), $exprType->getIterableValueType(), $scope->isDeclareStrictTypes()); if (!$acceptsValue->result) { $verbosityLevel = VerbosityLevel::getRecommendedLevelByType($returnType->getIterableValueType(), $exprType->getIterableValueType()); - $messages[] = RuleErrorBuilder::message(sprintf('Generator expects value type %s, %s given.', $returnType->getIterableValueType()->describe($verbosityLevel), $exprType->getIterableValueType()->describe($verbosityLevel))) + $messages[] = RuleErrorBuilder::message(sprintf( + 'Generator expects value type %s, %s given.', + $returnType->getIterableValueType()->describe($verbosityLevel), + $exprType->getIterableValueType()->describe($verbosityLevel), + )) ->line($node->expr->getStartLine()) ->identifier('generator.valueType') ->acceptsReasonsTip($acceptsValue->reasons) @@ -113,9 +121,17 @@ public function processNode(Node $node, Scope $scope): array $isSuperType = $exprSendType->isSuperTypeOf($thisSendType); if ($isSuperType->no()) { - $messages[] = RuleErrorBuilder::message(sprintf('Generator expects delegated TSend type %s, %s given.', $exprSendType->describe(VerbosityLevel::typeOnly()), $thisSendType->describe(VerbosityLevel::typeOnly())))->identifier('generator.sendType')->build(); + $messages[] = RuleErrorBuilder::message(sprintf( + 'Generator expects delegated TSend type %s, %s given.', + $exprSendType->describe(VerbosityLevel::typeOnly()), + $thisSendType->describe(VerbosityLevel::typeOnly()), + ))->identifier('generator.sendType')->build(); } elseif ($this->reportMaybes && !$isSuperType->yes()) { - $messages[] = RuleErrorBuilder::message(sprintf('Generator expects delegated TSend type %s, %s given.', $exprSendType->describe(VerbosityLevel::typeOnly()), $thisSendType->describe(VerbosityLevel::typeOnly())))->identifier('generator.sendType')->build(); + $messages[] = RuleErrorBuilder::message(sprintf( + 'Generator expects delegated TSend type %s, %s given.', + $exprSendType->describe(VerbosityLevel::typeOnly()), + $thisSendType->describe(VerbosityLevel::typeOnly()), + ))->identifier('generator.sendType')->build(); } if (!$scope->isInFirstLevelStatement() && $scope->getType($node)->isVoid()->yes()) { diff --git a/src/Rules/Generators/YieldInGeneratorRule.php b/src/Rules/Generators/YieldInGeneratorRule.php index 0a7294c61e8..9be06b937d4 100644 --- a/src/Rules/Generators/YieldInGeneratorRule.php +++ b/src/Rules/Generators/YieldInGeneratorRule.php @@ -18,13 +18,8 @@ class YieldInGeneratorRule implements Rule { - /** - * @var bool - */ - private $reportMaybes; - public function __construct(bool $reportMaybes) + public function __construct(private bool $reportMaybes) { - $this->reportMaybes = $reportMaybes; } public function getNodeType(): string @@ -60,7 +55,9 @@ public function processNode(Node $node, Scope $scope): array if ($returnType instanceof NeverType && $returnType->isExplicit()) { $isSuperType = TrinaryLogic::createNo(); } else { - $isSuperType = $returnType->isIterable()->and(TrinaryLogic::createFromBoolean(!$returnType->isArray()->yes())); + $isSuperType = $returnType->isIterable()->and(TrinaryLogic::createFromBoolean( + !$returnType->isArray()->yes(), + )); } if ($isSuperType->yes()) { return []; @@ -71,7 +68,10 @@ public function processNode(Node $node, Scope $scope): array } return [ - RuleErrorBuilder::message(sprintf('Yield can be used only with these return types: %s.', 'Generator, Iterator, Traversable, iterable'))->identifier('generator.returnType')->build(), + RuleErrorBuilder::message(sprintf( + 'Yield can be used only with these return types: %s.', + 'Generator, Iterator, Traversable, iterable', + ))->identifier('generator.returnType')->build(), ]; } diff --git a/src/Rules/Generators/YieldTypeRule.php b/src/Rules/Generators/YieldTypeRule.php index aff89dcf28b..3de12e41a38 100644 --- a/src/Rules/Generators/YieldTypeRule.php +++ b/src/Rules/Generators/YieldTypeRule.php @@ -20,14 +20,12 @@ class YieldTypeRule implements Rule { - /** - * @var RuleLevelHelper - */ - private $ruleLevelHelper; - public function __construct(RuleLevelHelper $ruleLevelHelper) + public function __construct( + private RuleLevelHelper $ruleLevelHelper, + ) { - $this->ruleLevelHelper = $ruleLevelHelper; } + public function getNodeType(): string { return Node\Expr\Yield_::class; @@ -59,7 +57,11 @@ public function processNode(Node $node, Scope $scope): array $acceptsKey = $this->ruleLevelHelper->acceptsWithReason($returnType->getIterableKeyType(), $keyType, $scope->isDeclareStrictTypes()); if (!$acceptsKey->result) { $verbosityLevel = VerbosityLevel::getRecommendedLevelByType($returnType->getIterableKeyType(), $keyType); - $messages[] = RuleErrorBuilder::message(sprintf('Generator expects key type %s, %s given.', $returnType->getIterableKeyType()->describe($verbosityLevel), $keyType->describe($verbosityLevel))) + $messages[] = RuleErrorBuilder::message(sprintf( + 'Generator expects key type %s, %s given.', + $returnType->getIterableKeyType()->describe($verbosityLevel), + $keyType->describe($verbosityLevel), + )) ->acceptsReasonsTip($acceptsKey->reasons) ->identifier('generator.keyType') ->build(); @@ -74,7 +76,11 @@ public function processNode(Node $node, Scope $scope): array $acceptsValue = $this->ruleLevelHelper->acceptsWithReason($returnType->getIterableValueType(), $valueType, $scope->isDeclareStrictTypes()); if (!$acceptsValue->result) { $verbosityLevel = VerbosityLevel::getRecommendedLevelByType($returnType->getIterableValueType(), $valueType); - $messages[] = RuleErrorBuilder::message(sprintf('Generator expects value type %s, %s given.', $returnType->getIterableValueType()->describe($verbosityLevel), $valueType->describe($verbosityLevel))) + $messages[] = RuleErrorBuilder::message(sprintf( + 'Generator expects value type %s, %s given.', + $returnType->getIterableValueType()->describe($verbosityLevel), + $valueType->describe($verbosityLevel), + )) ->acceptsReasonsTip($acceptsValue->reasons) ->identifier('generator.valueType') ->build(); diff --git a/src/Rules/Generics/ClassAncestorsRule.php b/src/Rules/Generics/ClassAncestorsRule.php index b4ec3a6c26c..0359073c44f 100644 --- a/src/Rules/Generics/ClassAncestorsRule.php +++ b/src/Rules/Generics/ClassAncestorsRule.php @@ -20,19 +20,13 @@ class ClassAncestorsRule implements Rule { - /** - * @var GenericAncestorsCheck - */ - private $genericAncestorsCheck; - /** - * @var CrossCheckInterfacesHelper - */ - private $crossCheckInterfacesHelper; - public function __construct(GenericAncestorsCheck $genericAncestorsCheck, CrossCheckInterfacesHelper $crossCheckInterfacesHelper) + public function __construct( + private GenericAncestorsCheck $genericAncestorsCheck, + private CrossCheckInterfacesHelper $crossCheckInterfacesHelper, + ) { - $this->genericAncestorsCheck = $genericAncestorsCheck; - $this->crossCheckInterfacesHelper = $crossCheckInterfacesHelper; } + public function getNodeType(): string { return InClassNode::class; @@ -51,13 +45,37 @@ public function processNode(Node $node, Scope $scope): array $className = $classReflection->getName(); $escapedClassName = SprintfHelper::escapeFormatString($className); - $extendsErrors = $this->genericAncestorsCheck->check($originalNode->extends !== null ? [$originalNode->extends] : [], array_map(static function (ExtendsTag $tag) : Type { - return $tag->getType(); - }, $classReflection->getExtendsTags()), sprintf('Class %s @extends tag contains incompatible type %%s.', $escapedClassName), sprintf('Class %s has @extends tag, but does not extend any class.', $escapedClassName), sprintf('The @extends tag of class %s describes %%s but the class extends %%s.', $escapedClassName), 'PHPDoc tag @extends contains generic type %s but %s %s is not generic.', 'Generic type %s in PHPDoc tag @extends does not specify all template types of %s %s: %s', 'Generic type %s in PHPDoc tag @extends specifies %d template types, but %s %s supports only %d: %s', 'Type %s in generic type %s in PHPDoc tag @extends is not subtype of template type %s of %s %s.', 'Call-site variance annotation of %s in generic type %s in PHPDoc tag @extends is not allowed.', 'PHPDoc tag @extends has invalid type %s.', sprintf('Class %s extends generic class %%s but does not specify its types: %%s', $escapedClassName), sprintf('in extended type %%s of class %s', $escapedClassName)); + $extendsErrors = $this->genericAncestorsCheck->check( + $originalNode->extends !== null ? [$originalNode->extends] : [], + array_map(static fn (ExtendsTag $tag): Type => $tag->getType(), $classReflection->getExtendsTags()), + sprintf('Class %s @extends tag contains incompatible type %%s.', $escapedClassName), + sprintf('Class %s has @extends tag, but does not extend any class.', $escapedClassName), + sprintf('The @extends tag of class %s describes %%s but the class extends %%s.', $escapedClassName), + 'PHPDoc tag @extends contains generic type %s but %s %s is not generic.', + 'Generic type %s in PHPDoc tag @extends does not specify all template types of %s %s: %s', + 'Generic type %s in PHPDoc tag @extends specifies %d template types, but %s %s supports only %d: %s', + 'Type %s in generic type %s in PHPDoc tag @extends is not subtype of template type %s of %s %s.', + 'Call-site variance annotation of %s in generic type %s in PHPDoc tag @extends is not allowed.', + 'PHPDoc tag @extends has invalid type %s.', + sprintf('Class %s extends generic class %%s but does not specify its types: %%s', $escapedClassName), + sprintf('in extended type %%s of class %s', $escapedClassName), + ); - $implementsErrors = $this->genericAncestorsCheck->check($originalNode->implements, array_map(static function (ImplementsTag $tag) : Type { - return $tag->getType(); - }, $classReflection->getImplementsTags()), sprintf('Class %s @implements tag contains incompatible type %%s.', $escapedClassName), sprintf('Class %s has @implements tag, but does not implement any interface.', $escapedClassName), sprintf('The @implements tag of class %s describes %%s but the class implements: %%s', $escapedClassName), 'PHPDoc tag @implements contains generic type %s but %s %s is not generic.', 'Generic type %s in PHPDoc tag @implements does not specify all template types of %s %s: %s', 'Generic type %s in PHPDoc tag @implements specifies %d template types, but %s %s supports only %d: %s', 'Type %s in generic type %s in PHPDoc tag @implements is not subtype of template type %s of %s %s.', 'Call-site variance annotation of %s in generic type %s in PHPDoc tag @implements is not allowed.', 'PHPDoc tag @implements has invalid type %s.', sprintf('Class %s implements generic interface %%s but does not specify its types: %%s', $escapedClassName), sprintf('in implemented type %%s of class %s', $escapedClassName)); + $implementsErrors = $this->genericAncestorsCheck->check( + $originalNode->implements, + array_map(static fn (ImplementsTag $tag): Type => $tag->getType(), $classReflection->getImplementsTags()), + sprintf('Class %s @implements tag contains incompatible type %%s.', $escapedClassName), + sprintf('Class %s has @implements tag, but does not implement any interface.', $escapedClassName), + sprintf('The @implements tag of class %s describes %%s but the class implements: %%s', $escapedClassName), + 'PHPDoc tag @implements contains generic type %s but %s %s is not generic.', + 'Generic type %s in PHPDoc tag @implements does not specify all template types of %s %s: %s', + 'Generic type %s in PHPDoc tag @implements specifies %d template types, but %s %s supports only %d: %s', + 'Type %s in generic type %s in PHPDoc tag @implements is not subtype of template type %s of %s %s.', + 'Call-site variance annotation of %s in generic type %s in PHPDoc tag @implements is not allowed.', + 'PHPDoc tag @implements has invalid type %s.', + sprintf('Class %s implements generic interface %%s but does not specify its types: %%s', $escapedClassName), + sprintf('in implemented type %%s of class %s', $escapedClassName), + ); foreach ($this->crossCheckInterfacesHelper->check($classReflection) as $error) { $implementsErrors[] = $error; diff --git a/src/Rules/Generics/ClassTemplateTypeRule.php b/src/Rules/Generics/ClassTemplateTypeRule.php index f5267be126f..a21d0561e57 100644 --- a/src/Rules/Generics/ClassTemplateTypeRule.php +++ b/src/Rules/Generics/ClassTemplateTypeRule.php @@ -16,14 +16,12 @@ class ClassTemplateTypeRule implements Rule { - /** - * @var TemplateTypeCheck - */ - private $templateTypeCheck; - public function __construct(TemplateTypeCheck $templateTypeCheck) + public function __construct( + private TemplateTypeCheck $templateTypeCheck, + ) { - $this->templateTypeCheck = $templateTypeCheck; } + public function getNodeType(): string { return InClassNode::class; @@ -42,7 +40,16 @@ public function processNode(Node $node, Scope $scope): array $displayName = 'class ' . SprintfHelper::escapeFormatString($classReflection->getDisplayName()); } - return $this->templateTypeCheck->check($scope, $node, TemplateTypeScope::createWithClass($className), $classReflection->getTemplateTags(), sprintf('PHPDoc tag @template for %s cannot have existing class %%s as its name.', $displayName), sprintf('PHPDoc tag @template for %s cannot have existing type alias %%s as its name.', $displayName), sprintf('PHPDoc tag @template %%s for %s has invalid bound type %%s.', $displayName), sprintf('PHPDoc tag @template %%s for %s with bound type %%s is not supported.', $displayName)); + return $this->templateTypeCheck->check( + $scope, + $node, + TemplateTypeScope::createWithClass($className), + $classReflection->getTemplateTags(), + sprintf('PHPDoc tag @template for %s cannot have existing class %%s as its name.', $displayName), + sprintf('PHPDoc tag @template for %s cannot have existing type alias %%s as its name.', $displayName), + sprintf('PHPDoc tag @template %%s for %s has invalid bound type %%s.', $displayName), + sprintf('PHPDoc tag @template %%s for %s with bound type %%s is not supported.', $displayName), + ); } } diff --git a/src/Rules/Generics/CrossCheckInterfacesHelper.php b/src/Rules/Generics/CrossCheckInterfacesHelper.php index 24f6931a09c..e35854b5ecf 100644 --- a/src/Rules/Generics/CrossCheckInterfacesHelper.php +++ b/src/Rules/Generics/CrossCheckInterfacesHelper.php @@ -37,7 +37,14 @@ public function check(ClassReflection $classReflection): array continue; } - $errors[] = RuleErrorBuilder::message(sprintf('%s specifies template type %s of interface %s as %s but it\'s already specified as %s.', $classReflection->isInterface() ? sprintf('Interface %s', $classReflection->getName()) : sprintf('Class %s', $classReflection->getName()), $name, $interface->getName(), $type->describe(VerbosityLevel::value()), $otherType->describe(VerbosityLevel::value())))->identifier('generics.interfaceConflict')->build(); + $errors[] = RuleErrorBuilder::message(sprintf( + '%s specifies template type %s of interface %s as %s but it\'s already specified as %s.', + $classReflection->isInterface() ? sprintf('Interface %s', $classReflection->getName()) : sprintf('Class %s', $classReflection->getName()), + $name, + $interface->getName(), + $type->describe(VerbosityLevel::value()), + $otherType->describe(VerbosityLevel::value()), + ))->identifier('generics.interfaceConflict')->build(); } continue; } diff --git a/src/Rules/Generics/EnumAncestorsRule.php b/src/Rules/Generics/EnumAncestorsRule.php index bd6e9e4d3c9..8c786d73596 100644 --- a/src/Rules/Generics/EnumAncestorsRule.php +++ b/src/Rules/Generics/EnumAncestorsRule.php @@ -20,19 +20,13 @@ class EnumAncestorsRule implements Rule { - /** - * @var GenericAncestorsCheck - */ - private $genericAncestorsCheck; - /** - * @var CrossCheckInterfacesHelper - */ - private $crossCheckInterfacesHelper; - public function __construct(GenericAncestorsCheck $genericAncestorsCheck, CrossCheckInterfacesHelper $crossCheckInterfacesHelper) + public function __construct( + private GenericAncestorsCheck $genericAncestorsCheck, + private CrossCheckInterfacesHelper $crossCheckInterfacesHelper, + ) { - $this->genericAncestorsCheck = $genericAncestorsCheck; - $this->crossCheckInterfacesHelper = $crossCheckInterfacesHelper; } + public function getNodeType(): string { return InClassNode::class; @@ -49,13 +43,37 @@ public function processNode(Node $node, Scope $scope): array $enumName = $classReflection->getName(); $escapedEnumName = SprintfHelper::escapeFormatString($enumName); - $extendsErrors = $this->genericAncestorsCheck->check([], array_map(static function (ExtendsTag $tag) : Type { - return $tag->getType(); - }, $classReflection->getExtendsTags()), sprintf('Enum %s @extends tag contains incompatible type %%s.', $escapedEnumName), sprintf('Enum %s has @extends tag, but cannot extend anything.', $escapedEnumName), '', '', '', '', '', '', '', '', ''); + $extendsErrors = $this->genericAncestorsCheck->check( + [], + array_map(static fn (ExtendsTag $tag): Type => $tag->getType(), $classReflection->getExtendsTags()), + sprintf('Enum %s @extends tag contains incompatible type %%s.', $escapedEnumName), + sprintf('Enum %s has @extends tag, but cannot extend anything.', $escapedEnumName), + '', + '', + '', + '', + '', + '', + '', + '', + '', + ); - $implementsErrors = $this->genericAncestorsCheck->check($originalNode->implements, array_map(static function (ImplementsTag $tag) : Type { - return $tag->getType(); - }, $classReflection->getImplementsTags()), sprintf('Enum %s @implements tag contains incompatible type %%s.', $escapedEnumName), sprintf('Enum %s has @implements tag, but does not implement any interface.', $escapedEnumName), sprintf('The @implements tag of eunm %s describes %%s but the enum implements: %%s', $escapedEnumName), 'PHPDoc tag @implements contains generic type %s but %s %s is not generic.', 'Generic type %s in PHPDoc tag @implements does not specify all template types of %s %s: %s', 'Generic type %s in PHPDoc tag @implements specifies %d template types, but %s %s supports only %d: %s', 'Type %s in generic type %s in PHPDoc tag @implements is not subtype of template type %s of %s %s.', 'Call-site variance annotation of %s in generic type %s in PHPDoc tag @implements is not allowed.', 'PHPDoc tag @implements has invalid type %s.', sprintf('Enum %s implements generic interface %%s but does not specify its types: %%s', $escapedEnumName), sprintf('in implemented type %%s of enum %s', $escapedEnumName)); + $implementsErrors = $this->genericAncestorsCheck->check( + $originalNode->implements, + array_map(static fn (ImplementsTag $tag): Type => $tag->getType(), $classReflection->getImplementsTags()), + sprintf('Enum %s @implements tag contains incompatible type %%s.', $escapedEnumName), + sprintf('Enum %s has @implements tag, but does not implement any interface.', $escapedEnumName), + sprintf('The @implements tag of eunm %s describes %%s but the enum implements: %%s', $escapedEnumName), + 'PHPDoc tag @implements contains generic type %s but %s %s is not generic.', + 'Generic type %s in PHPDoc tag @implements does not specify all template types of %s %s: %s', + 'Generic type %s in PHPDoc tag @implements specifies %d template types, but %s %s supports only %d: %s', + 'Type %s in generic type %s in PHPDoc tag @implements is not subtype of template type %s of %s %s.', + 'Call-site variance annotation of %s in generic type %s in PHPDoc tag @implements is not allowed.', + 'PHPDoc tag @implements has invalid type %s.', + sprintf('Enum %s implements generic interface %%s but does not specify its types: %%s', $escapedEnumName), + sprintf('in implemented type %%s of enum %s', $escapedEnumName), + ); foreach ($this->crossCheckInterfacesHelper->check($classReflection) as $error) { $implementsErrors[] = $error; diff --git a/src/Rules/Generics/FunctionSignatureVarianceRule.php b/src/Rules/Generics/FunctionSignatureVarianceRule.php index 379bd52d01f..e95b2e7712c 100644 --- a/src/Rules/Generics/FunctionSignatureVarianceRule.php +++ b/src/Rules/Generics/FunctionSignatureVarianceRule.php @@ -16,13 +16,8 @@ class FunctionSignatureVarianceRule implements Rule { - /** - * @var VarianceCheck - */ - private $varianceCheck; - public function __construct(VarianceCheck $varianceCheck) + public function __construct(private VarianceCheck $varianceCheck) { - $this->varianceCheck = $varianceCheck; } public function getNodeType(): string @@ -35,7 +30,16 @@ public function processNode(Node $node, Scope $scope): array $functionReflection = $node->getFunctionReflection(); $functionName = $functionReflection->getName(); - return $this->varianceCheck->checkParametersAcceptor(ParametersAcceptorSelector::selectSingle($functionReflection->getVariants()), sprintf('in parameter %%s of function %s()', SprintfHelper::escapeFormatString($functionName)), sprintf('in param-out type of parameter %%s of function %s()', SprintfHelper::escapeFormatString($functionName)), sprintf('in return type of function %s()', $functionName), sprintf('in function %s()', $functionName), false, false, 'function'); + return $this->varianceCheck->checkParametersAcceptor( + ParametersAcceptorSelector::selectSingle($functionReflection->getVariants()), + sprintf('in parameter %%s of function %s()', SprintfHelper::escapeFormatString($functionName)), + sprintf('in param-out type of parameter %%s of function %s()', SprintfHelper::escapeFormatString($functionName)), + sprintf('in return type of function %s()', $functionName), + sprintf('in function %s()', $functionName), + false, + false, + 'function', + ); } } diff --git a/src/Rules/Generics/FunctionTemplateTypeRule.php b/src/Rules/Generics/FunctionTemplateTypeRule.php index 4a7f6837d50..3700dd3b734 100644 --- a/src/Rules/Generics/FunctionTemplateTypeRule.php +++ b/src/Rules/Generics/FunctionTemplateTypeRule.php @@ -17,19 +17,13 @@ class FunctionTemplateTypeRule implements Rule { - /** - * @var FileTypeMapper - */ - private $fileTypeMapper; - /** - * @var TemplateTypeCheck - */ - private $templateTypeCheck; - public function __construct(FileTypeMapper $fileTypeMapper, TemplateTypeCheck $templateTypeCheck) + public function __construct( + private FileTypeMapper $fileTypeMapper, + private TemplateTypeCheck $templateTypeCheck, + ) { - $this->fileTypeMapper = $fileTypeMapper; - $this->templateTypeCheck = $templateTypeCheck; } + public function getNodeType(): string { return Node\Stmt\Function_::class; @@ -47,11 +41,26 @@ public function processNode(Node $node, Scope $scope): array } $functionName = (string) $node->namespacedName; - $resolvedPhpDoc = $this->fileTypeMapper->getResolvedPhpDoc($scope->getFile(), null, null, $functionName, $docComment->getText()); + $resolvedPhpDoc = $this->fileTypeMapper->getResolvedPhpDoc( + $scope->getFile(), + null, + null, + $functionName, + $docComment->getText(), + ); $escapedFunctionName = SprintfHelper::escapeFormatString($functionName); - return $this->templateTypeCheck->check($scope, $node, TemplateTypeScope::createWithFunction($functionName), $resolvedPhpDoc->getTemplateTags(), sprintf('PHPDoc tag @template for function %s() cannot have existing class %%s as its name.', $escapedFunctionName), sprintf('PHPDoc tag @template for function %s() cannot have existing type alias %%s as its name.', $escapedFunctionName), sprintf('PHPDoc tag @template %%s for function %s() has invalid bound type %%s.', $escapedFunctionName), sprintf('PHPDoc tag @template %%s for function %s() with bound type %%s is not supported.', $escapedFunctionName)); + return $this->templateTypeCheck->check( + $scope, + $node, + TemplateTypeScope::createWithFunction($functionName), + $resolvedPhpDoc->getTemplateTags(), + sprintf('PHPDoc tag @template for function %s() cannot have existing class %%s as its name.', $escapedFunctionName), + sprintf('PHPDoc tag @template for function %s() cannot have existing type alias %%s as its name.', $escapedFunctionName), + sprintf('PHPDoc tag @template %%s for function %s() has invalid bound type %%s.', $escapedFunctionName), + sprintf('PHPDoc tag @template %%s for function %s() with bound type %%s is not supported.', $escapedFunctionName), + ); } } diff --git a/src/Rules/Generics/GenericAncestorsCheck.php b/src/Rules/Generics/GenericAncestorsCheck.php index 316b2117233..14ebfb0c71e 100644 --- a/src/Rules/Generics/GenericAncestorsCheck.php +++ b/src/Rules/Generics/GenericAncestorsCheck.php @@ -24,121 +24,140 @@ class GenericAncestorsCheck { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - /** - * @var GenericObjectTypeCheck - */ - private $genericObjectTypeCheck; - /** - * @var VarianceCheck - */ - private $varianceCheck; - /** - * @var bool - */ - private $checkGenericClassInNonGenericObjectType; - /** - * @var string[] - */ - private $skipCheckGenericClasses; - /** - * @param string[] $skipCheckGenericClasses - */ - public function __construct(ReflectionProvider $reflectionProvider, GenericObjectTypeCheck $genericObjectTypeCheck, VarianceCheck $varianceCheck, bool $checkGenericClassInNonGenericObjectType, array $skipCheckGenericClasses) - { - $this->reflectionProvider = $reflectionProvider; - $this->genericObjectTypeCheck = $genericObjectTypeCheck; - $this->varianceCheck = $varianceCheck; - $this->checkGenericClassInNonGenericObjectType = $checkGenericClassInNonGenericObjectType; - $this->skipCheckGenericClasses = $skipCheckGenericClasses; + + /** + * @param string[] $skipCheckGenericClasses + */ + public function __construct( + private ReflectionProvider $reflectionProvider, + private GenericObjectTypeCheck $genericObjectTypeCheck, + private VarianceCheck $varianceCheck, + private bool $checkGenericClassInNonGenericObjectType, + private array $skipCheckGenericClasses, + ) + { + } + + /** + * @param array $nameNodes + * @param array $ancestorTypes + * @return list + */ + public function check( + array $nameNodes, + array $ancestorTypes, + string $incompatibleTypeMessage, + string $noNamesMessage, + string $noRelatedNameMessage, + string $classNotGenericMessage, + string $notEnoughTypesMessage, + string $extraTypesMessage, + string $typeIsNotSubtypeMessage, + string $typeProjectionIsNotAllowedMessage, + string $invalidTypeMessage, + string $genericClassInNonGenericObjectType, + string $invalidVarianceMessage, + ): array + { + $names = array_fill_keys(array_map(static fn (Name $nameNode): string => $nameNode->toString(), $nameNodes), true); + + $unusedNames = $names; + + $messages = []; + foreach ($ancestorTypes as $ancestorType) { + if (!$ancestorType instanceof GenericObjectType) { + $messages[] = RuleErrorBuilder::message(sprintf($incompatibleTypeMessage, $ancestorType->describe(VerbosityLevel::typeOnly()))) + ->identifier('generics.notCompatible') + ->build(); + continue; + } + + $ancestorTypeClassName = $ancestorType->getClassName(); + if (!isset($names[$ancestorTypeClassName])) { + if (count($names) === 0) { + $messages[] = RuleErrorBuilder::message($noNamesMessage) + ->identifier('generics.noParent') + ->build(); + } else { + $messages[] = RuleErrorBuilder::message(sprintf($noRelatedNameMessage, $ancestorTypeClassName, implode(', ', array_keys($names)))) + ->identifier('generics.wrongParent') + ->build(); + } + + continue; + } + + unset($unusedNames[$ancestorTypeClassName]); + + $genericObjectTypeCheckMessages = $this->genericObjectTypeCheck->check( + $ancestorType, + $classNotGenericMessage, + $notEnoughTypesMessage, + $extraTypesMessage, + $typeIsNotSubtypeMessage, + '', + '', + ); + $messages = array_merge($messages, $genericObjectTypeCheckMessages); + + foreach ($ancestorType->getReferencedClasses() as $referencedClass) { + if ($this->reflectionProvider->hasClass($referencedClass)) { + continue; + } + + $messages[] = RuleErrorBuilder::message(sprintf($invalidTypeMessage, $referencedClass)) + ->identifier('class.notFound') + ->build(); + } + + $variance = TemplateTypeVariance::createStatic(); + $messageContext = sprintf( + $invalidVarianceMessage, + $ancestorType->describe(VerbosityLevel::typeOnly()), + ); + foreach ($this->varianceCheck->check($variance, $ancestorType, $messageContext) as $message) { + $messages[] = $message; + } + + foreach ($ancestorType->getVariances() as $index => $typeVariance) { + if ($typeVariance->invariant()) { + continue; } - /** - * @param array $nameNodes - * @param array $ancestorTypes - * @return list - */ - public function check(array $nameNodes, array $ancestorTypes, string $incompatibleTypeMessage, string $noNamesMessage, string $noRelatedNameMessage, string $classNotGenericMessage, string $notEnoughTypesMessage, string $extraTypesMessage, string $typeIsNotSubtypeMessage, string $typeProjectionIsNotAllowedMessage, string $invalidTypeMessage, string $genericClassInNonGenericObjectType, string $invalidVarianceMessage) : array - { - $names = array_fill_keys(array_map(static function (Name $nameNode) : string { - return $nameNode->toString(); - }, $nameNodes), true); - $unusedNames = $names; - $messages = []; - foreach ($ancestorTypes as $ancestorType) { - if (!$ancestorType instanceof GenericObjectType) { - $messages[] = RuleErrorBuilder::message(sprintf($incompatibleTypeMessage, $ancestorType->describe(VerbosityLevel::typeOnly()))) - ->identifier('generics.notCompatible') - ->build(); - continue; - } - - $ancestorTypeClassName = $ancestorType->getClassName(); - if (!isset($names[$ancestorTypeClassName])) { - if (count($names) === 0) { - $messages[] = RuleErrorBuilder::message($noNamesMessage) - ->identifier('generics.noParent') - ->build(); - } else { - $messages[] = RuleErrorBuilder::message(sprintf($noRelatedNameMessage, $ancestorTypeClassName, implode(', ', array_keys($names)))) - ->identifier('generics.wrongParent') - ->build(); - } - - continue; - } - - unset($unusedNames[$ancestorTypeClassName]); - - $genericObjectTypeCheckMessages = $this->genericObjectTypeCheck->check($ancestorType, $classNotGenericMessage, $notEnoughTypesMessage, $extraTypesMessage, $typeIsNotSubtypeMessage, '', ''); - $messages = array_merge($messages, $genericObjectTypeCheckMessages); - - foreach ($ancestorType->getReferencedClasses() as $referencedClass) { - if ($this->reflectionProvider->hasClass($referencedClass)) { - continue; - } - - $messages[] = RuleErrorBuilder::message(sprintf($invalidTypeMessage, $referencedClass)) - ->identifier('class.notFound') - ->build(); - } - - $variance = TemplateTypeVariance::createStatic(); - $messageContext = sprintf($invalidVarianceMessage, $ancestorType->describe(VerbosityLevel::typeOnly())); - foreach ($this->varianceCheck->check($variance, $ancestorType, $messageContext) as $message) { - $messages[] = $message; - } - - foreach ($ancestorType->getVariances() as $index => $typeVariance) { - if ($typeVariance->invariant()) { - continue; - } - - $messages[] = RuleErrorBuilder::message(sprintf($typeProjectionIsNotAllowedMessage, TypeProjectionHelper::describe($ancestorType->getTypes()[$index], $typeVariance, VerbosityLevel::typeOnly()), $ancestorType->describe(VerbosityLevel::typeOnly())))->identifier('generics.callSiteVarianceNotAllowed')->build(); - } - } - if ($this->checkGenericClassInNonGenericObjectType) { - foreach (array_keys($unusedNames) as $unusedName) { - if (!$this->reflectionProvider->hasClass($unusedName)) { - continue; - } - - $unusedNameClassReflection = $this->reflectionProvider->getClass($unusedName); - if (in_array($unusedNameClassReflection->getName(), $this->skipCheckGenericClasses, true)) { - continue; - } - if (!$unusedNameClassReflection->isGeneric()) { - continue; - } - - $messages[] = RuleErrorBuilder::message(sprintf($genericClassInNonGenericObjectType, $unusedName, implode(', ', array_keys($unusedNameClassReflection->getTemplateTypeMap()->getTypes())))) - ->tip(MissingTypehintCheck::TURN_OFF_NON_GENERIC_CHECK_TIP) - ->identifier('missingType.generics') - ->build(); - } - } - return $messages; + + $messages[] = RuleErrorBuilder::message(sprintf( + $typeProjectionIsNotAllowedMessage, + TypeProjectionHelper::describe($ancestorType->getTypes()[$index], $typeVariance, VerbosityLevel::typeOnly()), + $ancestorType->describe(VerbosityLevel::typeOnly()), + ))->identifier('generics.callSiteVarianceNotAllowed')->build(); + } + } + + if ($this->checkGenericClassInNonGenericObjectType) { + foreach (array_keys($unusedNames) as $unusedName) { + if (!$this->reflectionProvider->hasClass($unusedName)) { + continue; } + + $unusedNameClassReflection = $this->reflectionProvider->getClass($unusedName); + if (in_array($unusedNameClassReflection->getName(), $this->skipCheckGenericClasses, true)) { + continue; + } + if (!$unusedNameClassReflection->isGeneric()) { + continue; + } + + $messages[] = RuleErrorBuilder::message(sprintf( + $genericClassInNonGenericObjectType, + $unusedName, + implode(', ', array_keys($unusedNameClassReflection->getTemplateTypeMap()->getTypes())), + )) + ->tip(MissingTypehintCheck::TURN_OFF_NON_GENERIC_CHECK_TIP) + ->identifier('missingType.generics') + ->build(); + } + } + + return $messages; + } + } diff --git a/src/Rules/Generics/GenericObjectTypeCheck.php b/src/Rules/Generics/GenericObjectTypeCheck.php index ff5ce986c4a..9df0d06b44b 100644 --- a/src/Rules/Generics/GenericObjectTypeCheck.php +++ b/src/Rules/Generics/GenericObjectTypeCheck.php @@ -27,7 +27,15 @@ class GenericObjectTypeCheck /** * @return list */ - public function check(Type $phpDocType, string $classNotGenericMessage, string $notEnoughTypesMessage, string $extraTypesMessage, string $typeIsNotSubtypeMessage, string $typeProjectionHasConflictingVarianceMessage, string $typeProjectionIsRedundantMessage) : array + public function check( + Type $phpDocType, + string $classNotGenericMessage, + string $notEnoughTypesMessage, + string $extraTypesMessage, + string $typeIsNotSubtypeMessage, + string $typeProjectionHasConflictingVarianceMessage, + string $typeProjectionIsRedundantMessage, + ): array { $genericTypes = $this->getGenericTypes($phpDocType); $messages = []; @@ -52,9 +60,23 @@ public function check(Type $phpDocType, string $classNotGenericMessage, string $ $templateTypesCount = count($templateTypes); $genericTypeTypesCount = count($genericTypeTypes); if ($templateTypesCount > $genericTypeTypesCount) { - $messages[] = RuleErrorBuilder::message(sprintf($notEnoughTypesMessage, $genericType->describe(VerbosityLevel::typeOnly()), $classLikeDescription, $classReflection->getDisplayName(false), implode(', ', array_keys($classReflection->getTemplateTypeMap()->getTypes()))))->identifier('generics.lessTypes')->build(); + $messages[] = RuleErrorBuilder::message(sprintf( + $notEnoughTypesMessage, + $genericType->describe(VerbosityLevel::typeOnly()), + $classLikeDescription, + $classReflection->getDisplayName(false), + implode(', ', array_keys($classReflection->getTemplateTypeMap()->getTypes())), + ))->identifier('generics.lessTypes')->build(); } elseif ($templateTypesCount < $genericTypeTypesCount) { - $messages[] = RuleErrorBuilder::message(sprintf($extraTypesMessage, $genericType->describe(VerbosityLevel::typeOnly()), $genericTypeTypesCount, $classLikeDescription, $classReflection->getDisplayName(false), $templateTypesCount, implode(', ', array_keys($classReflection->getTemplateTypeMap()->getTypes()))))->identifier('generics.moreTypes')->build(); + $messages[] = RuleErrorBuilder::message(sprintf( + $extraTypesMessage, + $genericType->describe(VerbosityLevel::typeOnly()), + $genericTypeTypesCount, + $classLikeDescription, + $classReflection->getDisplayName(false), + $templateTypesCount, + implode(', ', array_keys($classReflection->getTemplateTypeMap()->getTypes())), + ))->identifier('generics.moreTypes')->build(); } $templateTypesCount = count($templateTypes); @@ -69,12 +91,27 @@ public function check(Type $phpDocType, string $classNotGenericMessage, string $ $genericTypeVariance = $genericTypeVariances[$i] ?? TemplateTypeVariance::createInvariant(); if ($templateType instanceof TemplateType && !$genericTypeVariance->invariant()) { if ($genericTypeVariance->equals($templateType->getVariance())) { - $messages[] = RuleErrorBuilder::message(sprintf($typeProjectionIsRedundantMessage, TypeProjectionHelper::describe($genericTypeType, $genericTypeVariance, VerbosityLevel::typeOnly()), $genericType->describe(VerbosityLevel::typeOnly()), $templateType->describe(VerbosityLevel::typeOnly()), $classLikeDescription, $classReflection->getDisplayName(false))) + $messages[] = RuleErrorBuilder::message(sprintf( + $typeProjectionIsRedundantMessage, + TypeProjectionHelper::describe($genericTypeType, $genericTypeVariance, VerbosityLevel::typeOnly()), + $genericType->describe(VerbosityLevel::typeOnly()), + $templateType->describe(VerbosityLevel::typeOnly()), + $classLikeDescription, + $classReflection->getDisplayName(false), + )) ->identifier('generics.callSiteVarianceRedundant') ->tip('You can safely remove the call-site variance annotation.') ->build(); } elseif (!$genericTypeVariance->validPosition($templateType->getVariance())) { - $messages[] = RuleErrorBuilder::message(sprintf($typeProjectionHasConflictingVarianceMessage, TypeProjectionHelper::describe($genericTypeType, $genericTypeVariance, VerbosityLevel::typeOnly()), $genericType->describe(VerbosityLevel::typeOnly()), $templateType->getVariance()->describe(), $templateType->describe(VerbosityLevel::typeOnly()), $classLikeDescription, $classReflection->getDisplayName(false)))->identifier('generics.callSiteVarianceConflict')->build(); + $messages[] = RuleErrorBuilder::message(sprintf( + $typeProjectionHasConflictingVarianceMessage, + TypeProjectionHelper::describe($genericTypeType, $genericTypeVariance, VerbosityLevel::typeOnly()), + $genericType->describe(VerbosityLevel::typeOnly()), + $templateType->getVariance()->describe(), + $templateType->describe(VerbosityLevel::typeOnly()), + $classLikeDescription, + $classReflection->getDisplayName(false), + ))->identifier('generics.callSiteVarianceConflict')->build(); } } @@ -89,7 +126,12 @@ public function check(Type $phpDocType, string $classNotGenericMessage, string $ continue; } - $templateTypes[$j] = TemplateTypeHelper::resolveTemplateTypes($templateTypes[$j], $map, TemplateTypeVarianceMap::createEmpty(), TemplateTypeVariance::createStatic()); + $templateTypes[$j] = TemplateTypeHelper::resolveTemplateTypes( + $templateTypes[$j], + $map, + TemplateTypeVarianceMap::createEmpty(), + TemplateTypeVariance::createStatic(), + ); } continue; } @@ -98,9 +140,17 @@ public function check(Type $phpDocType, string $classNotGenericMessage, string $ continue; } - $messages[] = RuleErrorBuilder::message(sprintf($typeIsNotSubtypeMessage, $genericTypeType->describe(VerbosityLevel::typeOnly()), $genericType->describe(VerbosityLevel::typeOnly()), $templateType->describe(VerbosityLevel::typeOnly()), $classLikeDescription, $classReflection->getDisplayName(false)))->identifier('generics.notSubtype')->build(); + $messages[] = RuleErrorBuilder::message(sprintf( + $typeIsNotSubtypeMessage, + $genericTypeType->describe(VerbosityLevel::typeOnly()), + $genericType->describe(VerbosityLevel::typeOnly()), + $templateType->describe(VerbosityLevel::typeOnly()), + $classLikeDescription, + $classReflection->getDisplayName(false), + ))->identifier('generics.notSubtype')->build(); } } + return $messages; } diff --git a/src/Rules/Generics/InterfaceAncestorsRule.php b/src/Rules/Generics/InterfaceAncestorsRule.php index 759e43a8a6a..465c2b9f365 100644 --- a/src/Rules/Generics/InterfaceAncestorsRule.php +++ b/src/Rules/Generics/InterfaceAncestorsRule.php @@ -20,19 +20,13 @@ class InterfaceAncestorsRule implements Rule { - /** - * @var GenericAncestorsCheck - */ - private $genericAncestorsCheck; - /** - * @var CrossCheckInterfacesHelper - */ - private $crossCheckInterfacesHelper; - public function __construct(GenericAncestorsCheck $genericAncestorsCheck, CrossCheckInterfacesHelper $crossCheckInterfacesHelper) + public function __construct( + private GenericAncestorsCheck $genericAncestorsCheck, + private CrossCheckInterfacesHelper $crossCheckInterfacesHelper, + ) { - $this->genericAncestorsCheck = $genericAncestorsCheck; - $this->crossCheckInterfacesHelper = $crossCheckInterfacesHelper; } + public function getNodeType(): string { return InClassNode::class; @@ -49,13 +43,37 @@ public function processNode(Node $node, Scope $scope): array $interfaceName = $classReflection->getName(); $escapedInterfaceName = SprintfHelper::escapeFormatString($interfaceName); - $extendsErrors = $this->genericAncestorsCheck->check($originalNode->extends, array_map(static function (ExtendsTag $tag) : Type { - return $tag->getType(); - }, $classReflection->getExtendsTags()), sprintf('Interface %s @extends tag contains incompatible type %%s.', $escapedInterfaceName), sprintf('Interface %s has @extends tag, but does not extend any interface.', $escapedInterfaceName), sprintf('The @extends tag of interface %s describes %%s but the interface extends: %%s', $escapedInterfaceName), 'PHPDoc tag @extends contains generic type %s but %s %s is not generic.', 'Generic type %s in PHPDoc tag @extends does not specify all template types of %s %s: %s', 'Generic type %s in PHPDoc tag @extends specifies %d template types, but %s %s supports only %d: %s', 'Type %s in generic type %s in PHPDoc tag @extends is not subtype of template type %s of %s %s.', 'Call-site variance annotation of %s in generic type %s in PHPDoc tag @extends is not allowed.', 'PHPDoc tag @extends has invalid type %s.', sprintf('Interface %s extends generic interface %%s but does not specify its types: %%s', $escapedInterfaceName), sprintf('in extended type %%s of interface %s', $escapedInterfaceName)); + $extendsErrors = $this->genericAncestorsCheck->check( + $originalNode->extends, + array_map(static fn (ExtendsTag $tag): Type => $tag->getType(), $classReflection->getExtendsTags()), + sprintf('Interface %s @extends tag contains incompatible type %%s.', $escapedInterfaceName), + sprintf('Interface %s has @extends tag, but does not extend any interface.', $escapedInterfaceName), + sprintf('The @extends tag of interface %s describes %%s but the interface extends: %%s', $escapedInterfaceName), + 'PHPDoc tag @extends contains generic type %s but %s %s is not generic.', + 'Generic type %s in PHPDoc tag @extends does not specify all template types of %s %s: %s', + 'Generic type %s in PHPDoc tag @extends specifies %d template types, but %s %s supports only %d: %s', + 'Type %s in generic type %s in PHPDoc tag @extends is not subtype of template type %s of %s %s.', + 'Call-site variance annotation of %s in generic type %s in PHPDoc tag @extends is not allowed.', + 'PHPDoc tag @extends has invalid type %s.', + sprintf('Interface %s extends generic interface %%s but does not specify its types: %%s', $escapedInterfaceName), + sprintf('in extended type %%s of interface %s', $escapedInterfaceName), + ); - $implementsErrors = $this->genericAncestorsCheck->check([], array_map(static function (ImplementsTag $tag) : Type { - return $tag->getType(); - }, $classReflection->getImplementsTags()), sprintf('Interface %s @implements tag contains incompatible type %%s.', $escapedInterfaceName), sprintf('Interface %s has @implements tag, but can not implement any interface, must extend from it.', $escapedInterfaceName), '', '', '', '', '', '', '', '', ''); + $implementsErrors = $this->genericAncestorsCheck->check( + [], + array_map(static fn (ImplementsTag $tag): Type => $tag->getType(), $classReflection->getImplementsTags()), + sprintf('Interface %s @implements tag contains incompatible type %%s.', $escapedInterfaceName), + sprintf('Interface %s has @implements tag, but can not implement any interface, must extend from it.', $escapedInterfaceName), + '', + '', + '', + '', + '', + '', + '', + '', + '', + ); foreach ($this->crossCheckInterfacesHelper->check($classReflection) as $error) { $implementsErrors[] = $error; diff --git a/src/Rules/Generics/InterfaceTemplateTypeRule.php b/src/Rules/Generics/InterfaceTemplateTypeRule.php index c2683b2c39b..e808174a9f9 100644 --- a/src/Rules/Generics/InterfaceTemplateTypeRule.php +++ b/src/Rules/Generics/InterfaceTemplateTypeRule.php @@ -16,14 +16,12 @@ class InterfaceTemplateTypeRule implements Rule { - /** - * @var TemplateTypeCheck - */ - private $templateTypeCheck; - public function __construct(TemplateTypeCheck $templateTypeCheck) + public function __construct( + private TemplateTypeCheck $templateTypeCheck, + ) { - $this->templateTypeCheck = $templateTypeCheck; } + public function getNodeType(): string { return InClassNode::class; @@ -39,7 +37,16 @@ public function processNode(Node $node, Scope $scope): array $escapadInterfaceName = SprintfHelper::escapeFormatString($interfaceName); - return $this->templateTypeCheck->check($scope, $node, TemplateTypeScope::createWithClass($interfaceName), $classReflection->getTemplateTags(), sprintf('PHPDoc tag @template for interface %s cannot have existing class %%s as its name.', $escapadInterfaceName), sprintf('PHPDoc tag @template for interface %s cannot have existing type alias %%s as its name.', $escapadInterfaceName), sprintf('PHPDoc tag @template %%s for interface %s has invalid bound type %%s.', $escapadInterfaceName), sprintf('PHPDoc tag @template %%s for interface %s with bound type %%s is not supported.', $escapadInterfaceName)); + return $this->templateTypeCheck->check( + $scope, + $node, + TemplateTypeScope::createWithClass($interfaceName), + $classReflection->getTemplateTags(), + sprintf('PHPDoc tag @template for interface %s cannot have existing class %%s as its name.', $escapadInterfaceName), + sprintf('PHPDoc tag @template for interface %s cannot have existing type alias %%s as its name.', $escapadInterfaceName), + sprintf('PHPDoc tag @template %%s for interface %s has invalid bound type %%s.', $escapadInterfaceName), + sprintf('PHPDoc tag @template %%s for interface %s with bound type %%s is not supported.', $escapadInterfaceName), + ); } } diff --git a/src/Rules/Generics/MethodSignatureVarianceRule.php b/src/Rules/Generics/MethodSignatureVarianceRule.php index aae4e53e565..4f99378be00 100644 --- a/src/Rules/Generics/MethodSignatureVarianceRule.php +++ b/src/Rules/Generics/MethodSignatureVarianceRule.php @@ -16,13 +16,8 @@ class MethodSignatureVarianceRule implements Rule { - /** - * @var VarianceCheck - */ - private $varianceCheck; - public function __construct(VarianceCheck $varianceCheck) + public function __construct(private VarianceCheck $varianceCheck) { - $this->varianceCheck = $varianceCheck; } public function getNodeType(): string @@ -34,7 +29,16 @@ public function processNode(Node $node, Scope $scope): array { $method = $node->getMethodReflection(); - return $this->varianceCheck->checkParametersAcceptor(ParametersAcceptorSelector::selectSingle($method->getVariants()), sprintf('in parameter %%s of method %s::%s()', SprintfHelper::escapeFormatString($method->getDeclaringClass()->getDisplayName()), SprintfHelper::escapeFormatString($method->getName())), sprintf('in param-out type of parameter %%s of method %s::%s()', SprintfHelper::escapeFormatString($method->getDeclaringClass()->getDisplayName()), SprintfHelper::escapeFormatString($method->getName())), sprintf('in return type of method %s::%s()', $method->getDeclaringClass()->getDisplayName(), $method->getName()), sprintf('in method %s::%s()', $method->getDeclaringClass()->getDisplayName(), $method->getName()), $method->isStatic(), $method->isPrivate() || $method->getName() === '__construct', 'method'); + return $this->varianceCheck->checkParametersAcceptor( + ParametersAcceptorSelector::selectSingle($method->getVariants()), + sprintf('in parameter %%s of method %s::%s()', SprintfHelper::escapeFormatString($method->getDeclaringClass()->getDisplayName()), SprintfHelper::escapeFormatString($method->getName())), + sprintf('in param-out type of parameter %%s of method %s::%s()', SprintfHelper::escapeFormatString($method->getDeclaringClass()->getDisplayName()), SprintfHelper::escapeFormatString($method->getName())), + sprintf('in return type of method %s::%s()', $method->getDeclaringClass()->getDisplayName(), $method->getName()), + sprintf('in method %s::%s()', $method->getDeclaringClass()->getDisplayName(), $method->getName()), + $method->isStatic(), + $method->isPrivate() || $method->getName() === '__construct', + 'method', + ); } } diff --git a/src/Rules/Generics/MethodTemplateTypeRule.php b/src/Rules/Generics/MethodTemplateTypeRule.php index 8fdec670849..80f21c3de76 100644 --- a/src/Rules/Generics/MethodTemplateTypeRule.php +++ b/src/Rules/Generics/MethodTemplateTypeRule.php @@ -20,19 +20,13 @@ class MethodTemplateTypeRule implements Rule { - /** - * @var FileTypeMapper - */ - private $fileTypeMapper; - /** - * @var TemplateTypeCheck - */ - private $templateTypeCheck; - public function __construct(FileTypeMapper $fileTypeMapper, TemplateTypeCheck $templateTypeCheck) + public function __construct( + private FileTypeMapper $fileTypeMapper, + private TemplateTypeCheck $templateTypeCheck, + ) { - $this->fileTypeMapper = $fileTypeMapper; - $this->templateTypeCheck = $templateTypeCheck; } + public function getNodeType(): string { return Node\Stmt\ClassMethod::class; @@ -52,12 +46,27 @@ public function processNode(Node $node, Scope $scope): array $classReflection = $scope->getClassReflection(); $className = $classReflection->getDisplayName(); $methodName = $node->name->toString(); - $resolvedPhpDoc = $this->fileTypeMapper->getResolvedPhpDoc($scope->getFile(), $classReflection->getName(), $scope->isInTrait() ? $scope->getTraitReflection()->getName() : null, $methodName, $docComment->getText()); + $resolvedPhpDoc = $this->fileTypeMapper->getResolvedPhpDoc( + $scope->getFile(), + $classReflection->getName(), + $scope->isInTrait() ? $scope->getTraitReflection()->getName() : null, + $methodName, + $docComment->getText(), + ); $methodTemplateTags = $resolvedPhpDoc->getTemplateTags(); $escapedClassName = SprintfHelper::escapeFormatString($className); $escapedMethodName = SprintfHelper::escapeFormatString($methodName); - $messages = $this->templateTypeCheck->check($scope, $node, TemplateTypeScope::createWithMethod($className, $methodName), $methodTemplateTags, sprintf('PHPDoc tag @template for method %s::%s() cannot have existing class %%s as its name.', $escapedClassName, $escapedMethodName), sprintf('PHPDoc tag @template for method %s::%s() cannot have existing type alias %%s as its name.', $escapedClassName, $escapedMethodName), sprintf('PHPDoc tag @template %%s for method %s::%s() has invalid bound type %%s.', $escapedClassName, $escapedMethodName), sprintf('PHPDoc tag @template %%s for method %s::%s() with bound type %%s is not supported.', $escapedClassName, $escapedMethodName)); + $messages = $this->templateTypeCheck->check( + $scope, + $node, + TemplateTypeScope::createWithMethod($className, $methodName), + $methodTemplateTags, + sprintf('PHPDoc tag @template for method %s::%s() cannot have existing class %%s as its name.', $escapedClassName, $escapedMethodName), + sprintf('PHPDoc tag @template for method %s::%s() cannot have existing type alias %%s as its name.', $escapedClassName, $escapedMethodName), + sprintf('PHPDoc tag @template %%s for method %s::%s() has invalid bound type %%s.', $escapedClassName, $escapedMethodName), + sprintf('PHPDoc tag @template %%s for method %s::%s() with bound type %%s is not supported.', $escapedClassName, $escapedMethodName), + ); $classTemplateTypes = $classReflection->getTemplateTypeMap()->getTypes(); foreach (array_keys($methodTemplateTags) as $name) { diff --git a/src/Rules/Generics/PropertyVarianceRule.php b/src/Rules/Generics/PropertyVarianceRule.php index 8da53f65ae6..b62c494ba51 100644 --- a/src/Rules/Generics/PropertyVarianceRule.php +++ b/src/Rules/Generics/PropertyVarianceRule.php @@ -16,19 +16,13 @@ class PropertyVarianceRule implements Rule { - /** - * @var VarianceCheck - */ - private $varianceCheck; - /** - * @var bool - */ - private $readOnlyByPhpDoc; - public function __construct(VarianceCheck $varianceCheck, bool $readOnlyByPhpDoc) + public function __construct( + private VarianceCheck $varianceCheck, + private bool $readOnlyByPhpDoc, + ) { - $this->varianceCheck = $varianceCheck; - $this->readOnlyByPhpDoc = $readOnlyByPhpDoc; } + public function getNodeType(): string { return ClassPropertyNode::class; @@ -52,7 +46,11 @@ public function processNode(Node $node, Scope $scope): array ? TemplateTypeVariance::createCovariant() : TemplateTypeVariance::createInvariant(); - return $this->varianceCheck->check($variance, $propertyReflection->getReadableType(), sprintf('in property %s::$%s', SprintfHelper::escapeFormatString($classReflection->getDisplayName()), SprintfHelper::escapeFormatString($node->getName()))); + return $this->varianceCheck->check( + $variance, + $propertyReflection->getReadableType(), + sprintf('in property %s::$%s', SprintfHelper::escapeFormatString($classReflection->getDisplayName()), SprintfHelper::escapeFormatString($node->getName())), + ); } } diff --git a/src/Rules/Generics/TemplateTypeCheck.php b/src/Rules/Generics/TemplateTypeCheck.php index 9ed765b4a28..ff739cb4579 100644 --- a/src/Rules/Generics/TemplateTypeCheck.php +++ b/src/Rules/Generics/TemplateTypeCheck.php @@ -38,101 +38,115 @@ class TemplateTypeCheck { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - /** - * @var ClassCaseSensitivityCheck - */ - private $classCaseSensitivityCheck; - /** - * @var GenericObjectTypeCheck - */ - private $genericObjectTypeCheck; - /** - * @var TypeAliasResolver - */ - private $typeAliasResolver; - /** - * @var bool - */ - private $checkClassCaseSensitivity; - public function __construct(ReflectionProvider $reflectionProvider, ClassCaseSensitivityCheck $classCaseSensitivityCheck, GenericObjectTypeCheck $genericObjectTypeCheck, TypeAliasResolver $typeAliasResolver, bool $checkClassCaseSensitivity) - { - $this->reflectionProvider = $reflectionProvider; - $this->classCaseSensitivityCheck = $classCaseSensitivityCheck; - $this->genericObjectTypeCheck = $genericObjectTypeCheck; - $this->typeAliasResolver = $typeAliasResolver; - $this->checkClassCaseSensitivity = $checkClassCaseSensitivity; + + public function __construct( + private ReflectionProvider $reflectionProvider, + private ClassCaseSensitivityCheck $classCaseSensitivityCheck, + private GenericObjectTypeCheck $genericObjectTypeCheck, + private TypeAliasResolver $typeAliasResolver, + private bool $checkClassCaseSensitivity, + ) + { + } + + /** + * @param array $templateTags + * @return list + */ + public function check( + Scope $scope, + Node $node, + TemplateTypeScope $templateTypeScope, + array $templateTags, + string $sameTemplateTypeNameAsClassMessage, + string $sameTemplateTypeNameAsTypeMessage, + string $invalidBoundTypeMessage, + string $notSupportedBoundMessage, + ): array + { + $messages = []; + foreach ($templateTags as $templateTag) { + $templateTagName = $scope->resolveName(new Node\Name($templateTag->getName())); + if ($this->reflectionProvider->hasClass($templateTagName)) { + $messages[] = RuleErrorBuilder::message(sprintf( + $sameTemplateTypeNameAsClassMessage, + $templateTagName, + ))->identifier('generics.existingClass')->build(); + } + if ($this->typeAliasResolver->hasTypeAlias($templateTagName, $templateTypeScope->getClassName())) { + $messages[] = RuleErrorBuilder::message(sprintf( + $sameTemplateTypeNameAsTypeMessage, + $templateTagName, + ))->identifier('generics.existingTypeAlias')->build(); + } + $boundType = $templateTag->getBound(); + foreach ($boundType->getReferencedClasses() as $referencedClass) { + if (!$this->reflectionProvider->hasClass($referencedClass)) { + $messages[] = RuleErrorBuilder::message(sprintf( + $invalidBoundTypeMessage, + $templateTagName, + $referencedClass, + ))->identifier('class.notFound')->build(); + continue; } - /** - * @param array $templateTags - * @return list - */ - public function check(Scope $scope, Node $node, TemplateTypeScope $templateTypeScope, array $templateTags, string $sameTemplateTypeNameAsClassMessage, string $sameTemplateTypeNameAsTypeMessage, string $invalidBoundTypeMessage, string $notSupportedBoundMessage) : array - { - $messages = []; - foreach ($templateTags as $templateTag) { - $templateTagName = $scope->resolveName(new Node\Name($templateTag->getName())); - if ($this->reflectionProvider->hasClass($templateTagName)) { - $messages[] = RuleErrorBuilder::message(sprintf($sameTemplateTypeNameAsClassMessage, $templateTagName))->identifier('generics.existingClass')->build(); - } - if ($this->typeAliasResolver->hasTypeAlias($templateTagName, $templateTypeScope->getClassName())) { - $messages[] = RuleErrorBuilder::message(sprintf($sameTemplateTypeNameAsTypeMessage, $templateTagName))->identifier('generics.existingTypeAlias')->build(); - } - $boundType = $templateTag->getBound(); - foreach ($boundType->getReferencedClasses() as $referencedClass) { - if (!$this->reflectionProvider->hasClass($referencedClass)) { - $messages[] = RuleErrorBuilder::message(sprintf($invalidBoundTypeMessage, $templateTagName, $referencedClass))->identifier('class.notFound')->build(); - continue; - } - if (!$this->reflectionProvider->getClass($referencedClass)->isTrait()) { - continue; - } - - $messages[] = RuleErrorBuilder::message(sprintf($invalidBoundTypeMessage, $templateTagName, $referencedClass))->identifier('generics.traitBound')->build(); - } - - if ($this->checkClassCaseSensitivity) { - $classNameNodePairs = array_map(static function (string $referencedClass) use($node) : ClassNameNodePair { - return new ClassNameNodePair($referencedClass, $node); - }, $boundType->getReferencedClasses()); - $messages = array_merge($messages, $this->classCaseSensitivityCheck->checkClassNames($classNameNodePairs)); - } - - $boundType = $templateTag->getBound(); - $boundTypeClass = get_class($boundType); - if ( - $boundTypeClass !== MixedType::class - && $boundTypeClass !== ConstantArrayType::class - && $boundTypeClass !== ArrayType::class - && $boundTypeClass !== ConstantStringType::class - && $boundTypeClass !== StringType::class - && $boundTypeClass !== ConstantIntegerType::class - && $boundTypeClass !== IntegerType::class - && $boundTypeClass !== FloatType::class - && $boundTypeClass !== BooleanType::class - && $boundTypeClass !== ObjectWithoutClassType::class - && $boundTypeClass !== ObjectType::class - && $boundTypeClass !== ObjectShapeType::class - && $boundTypeClass !== GenericObjectType::class - && $boundTypeClass !== KeyOfType::class - && !$boundType instanceof UnionType - && !$boundType instanceof IntersectionType - && !$boundType instanceof TemplateType - ) { - $messages[] = RuleErrorBuilder::message(sprintf($notSupportedBoundMessage, $templateTagName, $boundType->describe(VerbosityLevel::typeOnly()))) - ->identifier('generics.notSupportedBound') - ->build(); - } - - $escapedTemplateTagName = SprintfHelper::escapeFormatString($templateTagName); - $genericObjectErrors = $this->genericObjectTypeCheck->check($boundType, sprintf('PHPDoc tag @template %s bound contains generic type %%s but %%s %%s is not generic.', $escapedTemplateTagName), sprintf('PHPDoc tag @template %s bound has type %%s which does not specify all template types of %%s %%s: %%s', $escapedTemplateTagName), sprintf('PHPDoc tag @template %s bound has type %%s which specifies %%d template types, but %%s %%s supports only %%d: %%s', $escapedTemplateTagName), sprintf('Type %%s in generic type %%s in PHPDoc tag @template %s is not subtype of template type %%s of %%s %%s.', $escapedTemplateTagName), sprintf('Call-site variance of %%s in generic type %%s in PHPDoc tag @template %s is in conflict with %%s template type %%s of %%s %%s.', $escapedTemplateTagName), sprintf('Call-site variance of %%s in generic type %%s in PHPDoc tag @template %s is redundant, template type %%s of %%s %%s has the same variance.', $escapedTemplateTagName)); - foreach ($genericObjectErrors as $genericObjectError) { - $messages[] = $genericObjectError; - } - } - return $messages; + if (!$this->reflectionProvider->getClass($referencedClass)->isTrait()) { + continue; } + + $messages[] = RuleErrorBuilder::message(sprintf( + $invalidBoundTypeMessage, + $templateTagName, + $referencedClass, + ))->identifier('generics.traitBound')->build(); + } + + if ($this->checkClassCaseSensitivity) { + $classNameNodePairs = array_map(static fn (string $referencedClass): ClassNameNodePair => new ClassNameNodePair($referencedClass, $node), $boundType->getReferencedClasses()); + $messages = array_merge($messages, $this->classCaseSensitivityCheck->checkClassNames($classNameNodePairs)); + } + + $boundType = $templateTag->getBound(); + $boundTypeClass = get_class($boundType); + if ( + $boundTypeClass !== MixedType::class + && $boundTypeClass !== ConstantArrayType::class + && $boundTypeClass !== ArrayType::class + && $boundTypeClass !== ConstantStringType::class + && $boundTypeClass !== StringType::class + && $boundTypeClass !== ConstantIntegerType::class + && $boundTypeClass !== IntegerType::class + && $boundTypeClass !== FloatType::class + && $boundTypeClass !== BooleanType::class + && $boundTypeClass !== ObjectWithoutClassType::class + && $boundTypeClass !== ObjectType::class + && $boundTypeClass !== ObjectShapeType::class + && $boundTypeClass !== GenericObjectType::class + && $boundTypeClass !== KeyOfType::class + && !$boundType instanceof UnionType + && !$boundType instanceof IntersectionType + && !$boundType instanceof TemplateType + ) { + $messages[] = RuleErrorBuilder::message(sprintf($notSupportedBoundMessage, $templateTagName, $boundType->describe(VerbosityLevel::typeOnly()))) + ->identifier('generics.notSupportedBound') + ->build(); + } + + $escapedTemplateTagName = SprintfHelper::escapeFormatString($templateTagName); + $genericObjectErrors = $this->genericObjectTypeCheck->check( + $boundType, + sprintf('PHPDoc tag @template %s bound contains generic type %%s but %%s %%s is not generic.', $escapedTemplateTagName), + sprintf('PHPDoc tag @template %s bound has type %%s which does not specify all template types of %%s %%s: %%s', $escapedTemplateTagName), + sprintf('PHPDoc tag @template %s bound has type %%s which specifies %%d template types, but %%s %%s supports only %%d: %%s', $escapedTemplateTagName), + sprintf('Type %%s in generic type %%s in PHPDoc tag @template %s is not subtype of template type %%s of %%s %%s.', $escapedTemplateTagName), + sprintf('Call-site variance of %%s in generic type %%s in PHPDoc tag @template %s is in conflict with %%s template type %%s of %%s %%s.', $escapedTemplateTagName), + sprintf('Call-site variance of %%s in generic type %%s in PHPDoc tag @template %s is redundant, template type %%s of %%s %%s has the same variance.', $escapedTemplateTagName), + ); + foreach ($genericObjectErrors as $genericObjectError) { + $messages[] = $genericObjectError; + } + } + + return $messages; + } + } diff --git a/src/Rules/Generics/TraitTemplateTypeRule.php b/src/Rules/Generics/TraitTemplateTypeRule.php index b285fb3a66a..c90b398fcf1 100644 --- a/src/Rules/Generics/TraitTemplateTypeRule.php +++ b/src/Rules/Generics/TraitTemplateTypeRule.php @@ -17,19 +17,13 @@ class TraitTemplateTypeRule implements Rule { - /** - * @var FileTypeMapper - */ - private $fileTypeMapper; - /** - * @var TemplateTypeCheck - */ - private $templateTypeCheck; - public function __construct(FileTypeMapper $fileTypeMapper, TemplateTypeCheck $templateTypeCheck) + public function __construct( + private FileTypeMapper $fileTypeMapper, + private TemplateTypeCheck $templateTypeCheck, + ) { - $this->fileTypeMapper = $fileTypeMapper; - $this->templateTypeCheck = $templateTypeCheck; } + public function getNodeType(): string { return Node\Stmt\Trait_::class; @@ -47,11 +41,26 @@ public function processNode(Node $node, Scope $scope): array } $traitName = (string) $node->namespacedName; - $resolvedPhpDoc = $this->fileTypeMapper->getResolvedPhpDoc($scope->getFile(), $traitName, null, null, $docComment->getText()); + $resolvedPhpDoc = $this->fileTypeMapper->getResolvedPhpDoc( + $scope->getFile(), + $traitName, + null, + null, + $docComment->getText(), + ); $escapedTraitName = SprintfHelper::escapeFormatString($traitName); - return $this->templateTypeCheck->check($scope, $node, TemplateTypeScope::createWithClass($traitName), $resolvedPhpDoc->getTemplateTags(), sprintf('PHPDoc tag @template for trait %s cannot have existing class %%s as its name.', $escapedTraitName), sprintf('PHPDoc tag @template for trait %s cannot have existing type alias %%s as its name.', $escapedTraitName), sprintf('PHPDoc tag @template %%s for trait %s has invalid bound type %%s.', $escapedTraitName), sprintf('PHPDoc tag @template %%s for trait %s with bound type %%s is not supported.', $escapedTraitName)); + return $this->templateTypeCheck->check( + $scope, + $node, + TemplateTypeScope::createWithClass($traitName), + $resolvedPhpDoc->getTemplateTags(), + sprintf('PHPDoc tag @template for trait %s cannot have existing class %%s as its name.', $escapedTraitName), + sprintf('PHPDoc tag @template for trait %s cannot have existing type alias %%s as its name.', $escapedTraitName), + sprintf('PHPDoc tag @template %%s for trait %s has invalid bound type %%s.', $escapedTraitName), + sprintf('PHPDoc tag @template %%s for trait %s with bound type %%s is not supported.', $escapedTraitName), + ); } } diff --git a/src/Rules/Generics/UsedTraitsRule.php b/src/Rules/Generics/UsedTraitsRule.php index 2d99f5188a6..5ad6141c065 100644 --- a/src/Rules/Generics/UsedTraitsRule.php +++ b/src/Rules/Generics/UsedTraitsRule.php @@ -21,19 +21,13 @@ class UsedTraitsRule implements Rule { - /** - * @var FileTypeMapper - */ - private $fileTypeMapper; - /** - * @var GenericAncestorsCheck - */ - private $genericAncestorsCheck; - public function __construct(FileTypeMapper $fileTypeMapper, GenericAncestorsCheck $genericAncestorsCheck) + public function __construct( + private FileTypeMapper $fileTypeMapper, + private GenericAncestorsCheck $genericAncestorsCheck, + ) { - $this->fileTypeMapper = $fileTypeMapper; - $this->genericAncestorsCheck = $genericAncestorsCheck; } + public function getNodeType(): string { return Node\Stmt\TraitUse::class; @@ -53,7 +47,13 @@ public function processNode(Node $node, Scope $scope): array $useTags = []; $docComment = $node->getDocComment(); if ($docComment !== null) { - $resolvedPhpDoc = $this->fileTypeMapper->getResolvedPhpDoc($scope->getFile(), $className, $traitName, null, $docComment->getText()); + $resolvedPhpDoc = $this->fileTypeMapper->getResolvedPhpDoc( + $scope->getFile(), + $className, + $traitName, + null, + $docComment->getText(), + ); $useTags = $resolvedPhpDoc->getUsesTags(); } @@ -64,9 +64,21 @@ public function processNode(Node $node, Scope $scope): array $description = sprintf('%s %s', $typeDescription, SprintfHelper::escapeFormatString($traitName)); } - return $this->genericAncestorsCheck->check($node->traits, array_map(static function (UsesTag $tag) : Type { - return $tag->getType(); - }, $useTags), sprintf('%s @use tag contains incompatible type %%s.', ucfirst($description)), sprintf('%s has @use tag, but does not use any trait.', ucfirst($description)), sprintf('The @use tag of %s describes %%s but the %s uses %%s.', $description, $typeDescription), 'PHPDoc tag @use contains generic type %s but %s %s is not generic.', 'Generic type %s in PHPDoc tag @use does not specify all template types of %s %s: %s', 'Generic type %s in PHPDoc tag @use specifies %d template types, but %s %s supports only %d: %s', 'Type %s in generic type %s in PHPDoc tag @use is not subtype of template type %s of %s %s.', 'Call-site variance annotation of %s in generic type %s in PHPDoc tag @use is not allowed.', 'PHPDoc tag @use has invalid type %s.', sprintf('%s uses generic trait %%s but does not specify its types: %%s', ucfirst($description)), sprintf('in used type %%s of %s', $description)); + return $this->genericAncestorsCheck->check( + $node->traits, + array_map(static fn (UsesTag $tag): Type => $tag->getType(), $useTags), + sprintf('%s @use tag contains incompatible type %%s.', ucfirst($description)), + sprintf('%s has @use tag, but does not use any trait.', ucfirst($description)), + sprintf('The @use tag of %s describes %%s but the %s uses %%s.', $description, $typeDescription), + 'PHPDoc tag @use contains generic type %s but %s %s is not generic.', + 'Generic type %s in PHPDoc tag @use does not specify all template types of %s %s: %s', + 'Generic type %s in PHPDoc tag @use specifies %d template types, but %s %s supports only %d: %s', + 'Type %s in generic type %s in PHPDoc tag @use is not subtype of template type %s of %s %s.', + 'Call-site variance annotation of %s in generic type %s in PHPDoc tag @use is not allowed.', + 'PHPDoc tag @use has invalid type %s.', + sprintf('%s uses generic trait %%s but does not specify its types: %%s', ucfirst($description)), + sprintf('in used type %%s of %s', $description), + ); } } diff --git a/src/Rules/Generics/VarianceCheck.php b/src/Rules/Generics/VarianceCheck.php index 3a4919526ea..7447c13cced 100644 --- a/src/Rules/Generics/VarianceCheck.php +++ b/src/Rules/Generics/VarianceCheck.php @@ -13,72 +13,86 @@ class VarianceCheck { + public function __construct( + private bool $checkParamOutVariance, + private bool $strictStaticVariance, + ) + { + } + /** - * @var bool - */ - private $checkParamOutVariance; - /** - * @var bool - */ - private $strictStaticVariance; - public function __construct(bool $checkParamOutVariance, bool $strictStaticVariance) - { - $this->checkParamOutVariance = $checkParamOutVariance; - $this->strictStaticVariance = $strictStaticVariance; + * @param 'function'|'method' $identifier + * @return list + */ + public function checkParametersAcceptor( + ParametersAcceptorWithPhpDocs $parametersAcceptor, + string $parameterTypeMessage, + string $parameterOutTypeMessage, + string $returnTypeMessage, + string $generalMessage, + bool $isStatic, + bool $isPrivate, + string $identifier, + ): array + { + $errors = []; + + foreach ($parametersAcceptor->getTemplateTypeMap()->getTypes() as $templateType) { + if (!$templateType instanceof TemplateType + || $templateType->getScope()->getFunctionName() === null + || $templateType->getVariance()->invariant() + ) { + continue; + } + + $errors[] = RuleErrorBuilder::message(sprintf( + 'Variance annotation is only allowed for type parameters of classes and interfaces, but occurs in template type %s in %s.', + $templateType->getName(), + $generalMessage, + ))->identifier(sprintf('%s.variance', $identifier))->build(); + } + + if ($isPrivate) { + return $errors; + } + + $covariant = TemplateTypeVariance::createCovariant(); + $parameterVariance = $isStatic && !$this->strictStaticVariance + ? TemplateTypeVariance::createStatic() + : TemplateTypeVariance::createContravariant(); + + foreach ($parametersAcceptor->getParameters() as $parameterReflection) { + $type = $parameterReflection->getType(); + $message = sprintf($parameterTypeMessage, $parameterReflection->getName()); + foreach ($this->check($parameterVariance, $type, $message) as $error) { + $errors[] = $error; + } + + if (!$this->checkParamOutVariance) { + continue; + } + + $paramOutType = $parameterReflection->getOutType(); + if ($paramOutType === null) { + continue; + } + + $outMessage = sprintf($parameterOutTypeMessage, $parameterReflection->getName()); + foreach ($this->check($covariant, $paramOutType, $outMessage) as $error) { + $errors[] = $error; + } } - /** - * @param 'function'|'method' $identifier - * @return list - */ - public function checkParametersAcceptor(ParametersAcceptorWithPhpDocs $parametersAcceptor, string $parameterTypeMessage, string $parameterOutTypeMessage, string $returnTypeMessage, string $generalMessage, bool $isStatic, bool $isPrivate, string $identifier) : array - { - $errors = []; - foreach ($parametersAcceptor->getTemplateTypeMap()->getTypes() as $templateType) { - if (!$templateType instanceof TemplateType - || $templateType->getScope()->getFunctionName() === null - || $templateType->getVariance()->invariant() - ) { - continue; - } - - $errors[] = RuleErrorBuilder::message(sprintf('Variance annotation is only allowed for type parameters of classes and interfaces, but occurs in template type %s in %s.', $templateType->getName(), $generalMessage))->identifier(sprintf('%s.variance', $identifier))->build(); - } - if ($isPrivate) { - return $errors; - } - $covariant = TemplateTypeVariance::createCovariant(); - $parameterVariance = $isStatic && !$this->strictStaticVariance - ? TemplateTypeVariance::createStatic() - : TemplateTypeVariance::createContravariant(); - foreach ($parametersAcceptor->getParameters() as $parameterReflection) { - $type = $parameterReflection->getType(); - $message = sprintf($parameterTypeMessage, $parameterReflection->getName()); - foreach ($this->check($parameterVariance, $type, $message) as $error) { - $errors[] = $error; - } - - if (!$this->checkParamOutVariance) { - continue; - } - - $paramOutType = $parameterReflection->getOutType(); - if ($paramOutType === null) { - continue; - } - - $outMessage = sprintf($parameterOutTypeMessage, $parameterReflection->getName()); - foreach ($this->check($covariant, $paramOutType, $outMessage) as $error) { - $errors[] = $error; - } - } - $type = $parametersAcceptor->getReturnType(); - foreach ($this->check($covariant, $type, $returnTypeMessage) as $error) { - $errors[] = $error; - } - return $errors; + + $type = $parametersAcceptor->getReturnType(); + foreach ($this->check($covariant, $type, $returnTypeMessage) as $error) { + $errors[] = $error; } - /** @return list */ - public function check(TemplateTypeVariance $positionVariance, Type $type, string $messageContext): array + + return $errors; + } + + /** @return list */ + public function check(TemplateTypeVariance $positionVariance, Type $type, string $messageContext): array { $errors = []; @@ -89,7 +103,13 @@ public function check(TemplateTypeVariance $positionVariance, Type $type, string continue; } - $errors[] = RuleErrorBuilder::message(sprintf('Template type %s is declared as %s, but occurs in %s position %s.', $referredType->getName(), $referredType->getVariance()->describe(), $reference->getPositionVariance()->describe(), $messageContext))->identifier('generics.variance')->build(); + $errors[] = RuleErrorBuilder::message(sprintf( + 'Template type %s is declared as %s, but occurs in %s position %s.', + $referredType->getName(), + $referredType->getVariance()->describe(), + $reference->getPositionVariance()->describe(), + $messageContext, + ))->identifier('generics.variance')->build(); } return $errors; diff --git a/src/Rules/IssetCheck.php b/src/Rules/IssetCheck.php index a9ae510a593..a660be4e612 100644 --- a/src/Rules/IssetCheck.php +++ b/src/Rules/IssetCheck.php @@ -20,34 +20,16 @@ class IssetCheck { - /** - * @var PropertyDescriptor - */ - private $propertyDescriptor; - /** - * @var PropertyReflectionFinder - */ - private $propertyReflectionFinder; - /** - * @var bool - */ - private $checkAdvancedIsset; - /** - * @var bool - */ - private $treatPhpDocTypesAsCertain; - /** - * @var bool - */ - private $strictUnnecessaryNullsafePropertyFetch; - public function __construct(PropertyDescriptor $propertyDescriptor, PropertyReflectionFinder $propertyReflectionFinder, bool $checkAdvancedIsset, bool $treatPhpDocTypesAsCertain, bool $strictUnnecessaryNullsafePropertyFetch) + public function __construct( + private PropertyDescriptor $propertyDescriptor, + private PropertyReflectionFinder $propertyReflectionFinder, + private bool $checkAdvancedIsset, + private bool $treatPhpDocTypesAsCertain, + private bool $strictUnnecessaryNullsafePropertyFetch, + ) { - $this->propertyDescriptor = $propertyDescriptor; - $this->propertyReflectionFinder = $propertyReflectionFinder; - $this->checkAdvancedIsset = $checkAdvancedIsset; - $this->treatPhpDocTypesAsCertain = $treatPhpDocTypesAsCertain; - $this->strictUnnecessaryNullsafePropertyFetch = $strictUnnecessaryNullsafePropertyFetch; } + /** * @param ErrorIdentifier $identifier * @param callable(Type): ?string $typeMessageCallback @@ -69,7 +51,13 @@ public function check(Expr $expr, Scope $scope, string $operatorDescription, str $type = $this->treatPhpDocTypesAsCertain ? $scope->getType($expr) : $scope->getNativeType($expr); if (!$type instanceof NeverType) { - return $this->generateError($type, sprintf('Variable $%s %s always exists and', $expr->name, $operatorDescription), $typeMessageCallback, $identifier, 'variable'); + return $this->generateError( + $type, + sprintf('Variable $%s %s always exists and', $expr->name, $operatorDescription), + $typeMessageCallback, + $identifier, + 'variable', + ); } } @@ -96,7 +84,14 @@ public function check(Expr $expr, Scope $scope, string $operatorDescription, str return null; } - return RuleErrorBuilder::message(sprintf('Offset %s on %s %s does not exist.', $dimType->describe(VerbosityLevel::value()), $type->describe(VerbosityLevel::value()), $operatorDescription))->identifier(sprintf('%s.offset', $identifier))->build(); + return RuleErrorBuilder::message( + sprintf( + 'Offset %s on %s %s does not exist.', + $dimType->describe(VerbosityLevel::value()), + $type->describe(VerbosityLevel::value()), + $operatorDescription, + ), + )->identifier(sprintf('%s.offset', $identifier))->build(); } // If offset cannot be null, store this error message and see if one of the earlier offsets is. @@ -106,7 +101,12 @@ public function check(Expr $expr, Scope $scope, string $operatorDescription, str return null; } - $error = $error ?? $this->generateError($type->getOffsetValueType($dimType), sprintf('Offset %s on %s %s always exists and', $dimType->describe(VerbosityLevel::value()), $type->describe(VerbosityLevel::value()), $operatorDescription), $typeMessageCallback, $identifier, 'offset'); + $error ??= $this->generateError($type->getOffsetValueType($dimType), sprintf( + 'Offset %s on %s %s always exists and', + $dimType->describe(VerbosityLevel::value()), + $type->describe(VerbosityLevel::value()), + $operatorDescription, + ), $typeMessageCallback, $identifier, 'offset'); if ($error !== null) { return $this->check($expr->var, $scope, $operatorDescription, $identifier, $typeMessageCallback, $error); @@ -176,7 +176,13 @@ public function check(Expr $expr, Scope $scope, string $operatorDescription, str return null; } - $error = $this->generateError($propertyReflection->getWritableType(), sprintf('%s (%s) %s', $propertyDescription, $propertyType->describe(VerbosityLevel::typeOnly()), $operatorDescription), $typeMessageCallback, $identifier, 'property'); + $error = $this->generateError( + $propertyReflection->getWritableType(), + sprintf('%s (%s) %s', $propertyDescription, $propertyType->describe(VerbosityLevel::typeOnly()), $operatorDescription), + $typeMessageCallback, + $identifier, + 'property', + ); if ($error !== null) { if ($expr instanceof Node\Expr\PropertyFetch) { @@ -199,7 +205,13 @@ public function check(Expr $expr, Scope $scope, string $operatorDescription, str return null; } - $error = $this->generateError($this->treatPhpDocTypesAsCertain ? $scope->getType($expr) : $scope->getNativeType($expr), sprintf('Expression %s', $operatorDescription), $typeMessageCallback, $identifier, 'expr'); + $error = $this->generateError( + $this->treatPhpDocTypesAsCertain ? $scope->getType($expr) : $scope->getNativeType($expr), + sprintf('Expression %s', $operatorDescription), + $typeMessageCallback, + $identifier, + 'expr', + ); if ($error !== null) { return $error; } @@ -251,7 +263,14 @@ private function checkUndefined(Expr $expr, Scope $scope, string $operatorDescri return $this->checkUndefined($expr->var, $scope, $operatorDescription, $identifier); } - return RuleErrorBuilder::message(sprintf('Offset %s on %s %s does not exist.', $dimType->describe(VerbosityLevel::value()), $type->describe(VerbosityLevel::value()), $operatorDescription))->identifier(sprintf('%s.offset', $identifier))->build(); + return RuleErrorBuilder::message( + sprintf( + 'Offset %s on %s %s does not exist.', + $dimType->describe(VerbosityLevel::value()), + $type->describe(VerbosityLevel::value()), + $operatorDescription, + ), + )->identifier(sprintf('%s.offset', $identifier))->build(); } if ($expr instanceof Expr\PropertyFetch) { @@ -277,7 +296,9 @@ private function generateError(Type $type, string $message, callable $typeMessag return null; } - return RuleErrorBuilder::message(sprintf('%s %s.', $message, $typeMessage))->identifier(sprintf('%s.%s', $identifier, $identifierSecondPart))->build(); + return RuleErrorBuilder::message( + sprintf('%s %s.', $message, $typeMessage), + )->identifier(sprintf('%s.%s', $identifier, $identifierSecondPart))->build(); } } diff --git a/src/Rules/Keywords/ContinueBreakInLoopRule.php b/src/Rules/Keywords/ContinueBreakInLoopRule.php index e5d05e8b510..d97e3fd119d 100644 --- a/src/Rules/Keywords/ContinueBreakInLoopRule.php +++ b/src/Rules/Keywords/ContinueBreakInLoopRule.php @@ -45,7 +45,10 @@ public function processNode(Node $node, Scope $scope): array || $parentStmtType === Node\Expr\Closure::class ) { return [ - RuleErrorBuilder::message(sprintf('Keyword %s used outside of a loop or a switch statement.', $node instanceof Stmt\Continue_ ? 'continue' : 'break')) + RuleErrorBuilder::message(sprintf( + 'Keyword %s used outside of a loop or a switch statement.', + $node instanceof Stmt\Continue_ ? 'continue' : 'break', + )) ->nonIgnorable() ->identifier(sprintf('%s.outOfLoop', $node instanceof Stmt\Continue_ ? 'continue' : 'break')) ->build(), @@ -67,7 +70,10 @@ public function processNode(Node $node, Scope $scope): array if ($value > 0) { return [ - RuleErrorBuilder::message(sprintf('Keyword %s used outside of a loop or a switch statement.', $node instanceof Stmt\Continue_ ? 'continue' : 'break')) + RuleErrorBuilder::message(sprintf( + 'Keyword %s used outside of a loop or a switch statement.', + $node instanceof Stmt\Continue_ ? 'continue' : 'break', + )) ->nonIgnorable() ->identifier(sprintf('%s.outOfLoop', $node instanceof Stmt\Continue_ ? 'continue' : 'break')) ->build(), diff --git a/src/Rules/Keywords/DeclareStrictTypesRule.php b/src/Rules/Keywords/DeclareStrictTypesRule.php index e05b7cad9de..3878c1c77cb 100644 --- a/src/Rules/Keywords/DeclareStrictTypesRule.php +++ b/src/Rules/Keywords/DeclareStrictTypesRule.php @@ -18,15 +18,12 @@ class DeclareStrictTypesRule implements Rule { - /** - * @readonly - * @var ExprPrinter - */ - private $exprPrinter; - public function __construct(ExprPrinter $exprPrinter) + public function __construct( + private readonly ExprPrinter $exprPrinter, + ) { - $this->exprPrinter = $exprPrinter; } + public function getNodeType(): string { return Stmt\Declare_::class; @@ -47,7 +44,12 @@ public function processNode(Node $node, Scope $scope): array || !in_array($declare->value->value, [0, 1], true) ) { return [ - RuleErrorBuilder::message(sprintf(sprintf('Declare strict_types must have 0 or 1 as its value, %s given.', $this->exprPrinter->printExpr($declare->value))))->identifier('declareStrictTypes.value')->nonIgnorable()->build(), + RuleErrorBuilder::message(sprintf( + sprintf( + 'Declare strict_types must have 0 or 1 as its value, %s given.', + $this->exprPrinter->printExpr($declare->value), + ), + ))->identifier('declareStrictTypes.value')->nonIgnorable()->build(), ]; } @@ -69,7 +71,9 @@ public function processNode(Node $node, Scope $scope): array } return [ - RuleErrorBuilder::message(sprintf('Declare strict_types must be the very first statement.'))->identifier('declareStrictTypes.notFirst')->nonIgnorable()->build(), + RuleErrorBuilder::message(sprintf( + 'Declare strict_types must be the very first statement.', + ))->identifier('declareStrictTypes.notFirst')->nonIgnorable()->build(), ]; } diff --git a/src/Rules/LazyRegistry.php b/src/Rules/LazyRegistry.php index 464e3ba5249..a9a1a728ec3 100644 --- a/src/Rules/LazyRegistry.php +++ b/src/Rules/LazyRegistry.php @@ -10,21 +10,16 @@ class LazyRegistry implements Registry { - /** - * @var Container - */ - private $container; public const RULE_TAG = 'phpstan.rules.rule'; /** @var Rule[][]|null */ - private $rules = null; + private ?array $rules = null; /** @var Rule[][] */ - private $cache = []; + private array $cache = []; - public function __construct(Container $container) + public function __construct(private Container $container) { - $this->container = $container; } /** diff --git a/src/Rules/Methods/AbstractMethodInNonAbstractClassRule.php b/src/Rules/Methods/AbstractMethodInNonAbstractClassRule.php index cd31dc5b7cf..d6d7b603c8a 100644 --- a/src/Rules/Methods/AbstractMethodInNonAbstractClassRule.php +++ b/src/Rules/Methods/AbstractMethodInNonAbstractClassRule.php @@ -31,7 +31,12 @@ public function processNode(Node $node, Scope $scope): array if (!$class->isAbstract() && $node->isAbstract()) { $description = $class->getClassTypeDescription(); return [ - RuleErrorBuilder::message(sprintf('%s %s contains abstract method %s().', $description === 'Class' ? 'Non-abstract class' : $description, $class->getDisplayName(), $node->name->toString())) + RuleErrorBuilder::message(sprintf( + '%s %s contains abstract method %s().', + $description === 'Class' ? 'Non-abstract class' : $description, + $class->getDisplayName(), + $node->name->toString(), + )) ->nonIgnorable() ->identifier('method.abstract') ->build(), @@ -40,7 +45,11 @@ public function processNode(Node $node, Scope $scope): array if (!$class->isAbstract() && !$class->isInterface() && $node->getStmts() === null) { return [ - RuleErrorBuilder::message(sprintf('Non-abstract method %s::%s() must contain a body.', $class->getDisplayName(), $node->name->toString())) + RuleErrorBuilder::message(sprintf( + 'Non-abstract method %s::%s() must contain a body.', + $class->getDisplayName(), + $node->name->toString(), + )) ->nonIgnorable() ->identifier('method.nonAbstract') ->build(), diff --git a/src/Rules/Methods/AbstractPrivateMethodRule.php b/src/Rules/Methods/AbstractPrivateMethodRule.php index ff62cb08f20..060bb2a27ad 100644 --- a/src/Rules/Methods/AbstractPrivateMethodRule.php +++ b/src/Rules/Methods/AbstractPrivateMethodRule.php @@ -44,7 +44,11 @@ public function processNode(Node $node, Scope $scope): array } return [ - RuleErrorBuilder::message(sprintf('Private method %s::%s() cannot be abstract.', $method->getDeclaringClass()->getDisplayName(), $method->getName())) + RuleErrorBuilder::message(sprintf( + 'Private method %s::%s() cannot be abstract.', + $method->getDeclaringClass()->getDisplayName(), + $method->getName(), + )) ->identifier('method.abstractPrivate') ->nonIgnorable() ->build(), diff --git a/src/Rules/Methods/CallMethodsRule.php b/src/Rules/Methods/CallMethodsRule.php index 12db58a2df6..388dcb3208c 100644 --- a/src/Rules/Methods/CallMethodsRule.php +++ b/src/Rules/Methods/CallMethodsRule.php @@ -17,19 +17,13 @@ class CallMethodsRule implements Rule { - /** - * @var MethodCallCheck - */ - private $methodCallCheck; - /** - * @var FunctionCallParametersCheck - */ - private $parametersCheck; - public function __construct(MethodCallCheck $methodCallCheck, FunctionCallParametersCheck $parametersCheck) + public function __construct( + private MethodCallCheck $methodCallCheck, + private FunctionCallParametersCheck $parametersCheck, + ) { - $this->methodCallCheck = $methodCallCheck; - $this->parametersCheck = $parametersCheck; } + public function getNodeType(): string { return MethodCall::class; @@ -51,7 +45,17 @@ public function processNode(Node $node, Scope $scope): array $declaringClass = $methodReflection->getDeclaringClass(); $messagesMethodName = SprintfHelper::escapeFormatString($declaringClass->getDisplayName() . '::' . $methodReflection->getName() . '()'); - return array_merge($errors, $this->parametersCheck->check(ParametersAcceptorSelector::selectFromArgs($scope, $node->getArgs(), $methodReflection->getVariants(), $methodReflection->getNamedArgumentsVariants()), $scope, $declaringClass->isBuiltin(), $node, [ + return array_merge($errors, $this->parametersCheck->check( + ParametersAcceptorSelector::selectFromArgs( + $scope, + $node->getArgs(), + $methodReflection->getVariants(), + $methodReflection->getNamedArgumentsVariants(), + ), + $scope, + $declaringClass->isBuiltin(), + $node, + [ 'Method ' . $messagesMethodName . ' invoked with %d parameter, %d required.', 'Method ' . $messagesMethodName . ' invoked with %d parameters, %d required.', 'Method ' . $messagesMethodName . ' invoked with %d parameter, at least %d required.', @@ -66,7 +70,9 @@ public function processNode(Node $node, Scope $scope): array 'Unknown parameter $%s in call to method ' . $messagesMethodName . '.', 'Return type of call to method ' . $messagesMethodName . ' contains unresolvable type.', 'Parameter %s of method ' . $messagesMethodName . ' contains unresolvable type.', - ], 'method')); + ], + 'method', + )); } } diff --git a/src/Rules/Methods/CallPrivateMethodThroughStaticRule.php b/src/Rules/Methods/CallPrivateMethodThroughStaticRule.php index 5d2ae68047b..0a37e486570 100644 --- a/src/Rules/Methods/CallPrivateMethodThroughStaticRule.php +++ b/src/Rules/Methods/CallPrivateMethodThroughStaticRule.php @@ -51,7 +51,11 @@ public function processNode(Node $node, Scope $scope): array } return [ - RuleErrorBuilder::message(sprintf('Unsafe call to private method %s::%s() through static::.', $method->getDeclaringClass()->getDisplayName(), $method->getName()))->identifier('staticClassAccess.privateMethod')->build(), + RuleErrorBuilder::message(sprintf( + 'Unsafe call to private method %s::%s() through static::.', + $method->getDeclaringClass()->getDisplayName(), + $method->getName(), + ))->identifier('staticClassAccess.privateMethod')->build(), ]; } diff --git a/src/Rules/Methods/CallStaticMethodsRule.php b/src/Rules/Methods/CallStaticMethodsRule.php index 08fa7482ecc..b1f2f013c23 100644 --- a/src/Rules/Methods/CallStaticMethodsRule.php +++ b/src/Rules/Methods/CallStaticMethodsRule.php @@ -18,19 +18,13 @@ class CallStaticMethodsRule implements Rule { - /** - * @var StaticMethodCallCheck - */ - private $methodCallCheck; - /** - * @var FunctionCallParametersCheck - */ - private $parametersCheck; - public function __construct(StaticMethodCallCheck $methodCallCheck, FunctionCallParametersCheck $parametersCheck) + public function __construct( + private StaticMethodCallCheck $methodCallCheck, + private FunctionCallParametersCheck $parametersCheck, + ) { - $this->methodCallCheck = $methodCallCheck; - $this->parametersCheck = $parametersCheck; } + public function getNodeType(): string { return StaticCall::class; @@ -48,10 +42,28 @@ public function processNode(Node $node, Scope $scope): array return $errors; } - $displayMethodName = SprintfHelper::escapeFormatString(sprintf('%s %s', $method->isStatic() ? 'Static method' : 'Method', $method->getDeclaringClass()->getDisplayName() . '::' . $method->getName() . '()')); - $lowercasedMethodName = SprintfHelper::escapeFormatString(sprintf('%s %s', $method->isStatic() ? 'static method' : 'method', $method->getDeclaringClass()->getDisplayName() . '::' . $method->getName() . '()')); + $displayMethodName = SprintfHelper::escapeFormatString(sprintf( + '%s %s', + $method->isStatic() ? 'Static method' : 'Method', + $method->getDeclaringClass()->getDisplayName() . '::' . $method->getName() . '()', + )); + $lowercasedMethodName = SprintfHelper::escapeFormatString(sprintf( + '%s %s', + $method->isStatic() ? 'static method' : 'method', + $method->getDeclaringClass()->getDisplayName() . '::' . $method->getName() . '()', + )); - $errors = array_merge($errors, $this->parametersCheck->check(ParametersAcceptorSelector::selectFromArgs($scope, $node->getArgs(), $method->getVariants(), $method->getNamedArgumentsVariants()), $scope, $method->getDeclaringClass()->isBuiltin(), $node, [ + $errors = array_merge($errors, $this->parametersCheck->check( + ParametersAcceptorSelector::selectFromArgs( + $scope, + $node->getArgs(), + $method->getVariants(), + $method->getNamedArgumentsVariants(), + ), + $scope, + $method->getDeclaringClass()->isBuiltin(), + $node, + [ $displayMethodName . ' invoked with %d parameter, %d required.', $displayMethodName . ' invoked with %d parameters, %d required.', $displayMethodName . ' invoked with %d parameter, at least %d required.', @@ -66,7 +78,9 @@ public function processNode(Node $node, Scope $scope): array 'Unknown parameter $%s in call to ' . $lowercasedMethodName . '.', 'Return type of call to ' . $lowercasedMethodName . ' contains unresolvable type.', 'Parameter %s of ' . $lowercasedMethodName . ' contains unresolvable type.', - ], 'staticMethod')); + ], + 'staticMethod', + )); return $errors; } diff --git a/src/Rules/Methods/CallToConstructorStatementWithoutSideEffectsRule.php b/src/Rules/Methods/CallToConstructorStatementWithoutSideEffectsRule.php index c7475f6875a..4dec25393a9 100644 --- a/src/Rules/Methods/CallToConstructorStatementWithoutSideEffectsRule.php +++ b/src/Rules/Methods/CallToConstructorStatementWithoutSideEffectsRule.php @@ -16,13 +16,8 @@ class CallToConstructorStatementWithoutSideEffectsRule implements Rule { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - public function __construct(ReflectionProvider $reflectionProvider) + public function __construct(private ReflectionProvider $reflectionProvider) { - $this->reflectionProvider = $reflectionProvider; } public function getNodeType(): string @@ -64,7 +59,11 @@ public function processNode(Node $node, Scope $scope): array } return [ - RuleErrorBuilder::message(sprintf('Call to %s::%s() on a separate line has no effect.', $classReflection->getDisplayName(), $constructor->getName()))->identifier('new.resultUnused')->build(), + RuleErrorBuilder::message(sprintf( + 'Call to %s::%s() on a separate line has no effect.', + $classReflection->getDisplayName(), + $constructor->getName(), + ))->identifier('new.resultUnused')->build(), ]; } diff --git a/src/Rules/Methods/CallToMethodStatementWithoutSideEffectsRule.php b/src/Rules/Methods/CallToMethodStatementWithoutSideEffectsRule.php index 5c387476f74..abeaff4110d 100644 --- a/src/Rules/Methods/CallToMethodStatementWithoutSideEffectsRule.php +++ b/src/Rules/Methods/CallToMethodStatementWithoutSideEffectsRule.php @@ -19,13 +19,8 @@ class CallToMethodStatementWithoutSideEffectsRule implements Rule { - /** - * @var RuleLevelHelper - */ - private $ruleLevelHelper; - public function __construct(RuleLevelHelper $ruleLevelHelper) + public function __construct(private RuleLevelHelper $ruleLevelHelper) { - $this->ruleLevelHelper = $ruleLevelHelper; } public function getNodeType(): string @@ -47,9 +42,12 @@ public function processNode(Node $node, Scope $scope): array } $methodName = $methodCall->name->toString(); - $typeResult = $this->ruleLevelHelper->findTypeToCheck($scope, NullsafeOperatorHelper::getNullsafeShortcircuitedExprRespectingScope($scope, $methodCall->var), '', static function (Type $type) use($methodName) : bool { - return $type->canCallMethods()->yes() && $type->hasMethod($methodName)->yes(); - }); + $typeResult = $this->ruleLevelHelper->findTypeToCheck( + $scope, + NullsafeOperatorHelper::getNullsafeShortcircuitedExprRespectingScope($scope, $methodCall->var), + '', + static fn (Type $type): bool => $type->canCallMethods()->yes() && $type->hasMethod($methodName)->yes(), + ); $calledOnType = $typeResult->getType(); if ($calledOnType instanceof ErrorType) { return []; @@ -77,7 +75,12 @@ public function processNode(Node $node, Scope $scope): array } return [ - RuleErrorBuilder::message(sprintf('Call to %s %s::%s() on a separate line has no effect.', $method->isStatic() ? 'static method' : 'method', $method->getDeclaringClass()->getDisplayName(), $method->getName()))->identifier('method.resultUnused')->build(), + RuleErrorBuilder::message(sprintf( + 'Call to %s %s::%s() on a separate line has no effect.', + $method->isStatic() ? 'static method' : 'method', + $method->getDeclaringClass()->getDisplayName(), + $method->getName(), + ))->identifier('method.resultUnused')->build(), ]; } diff --git a/src/Rules/Methods/CallToStaticMethodStatementWithoutSideEffectsRule.php b/src/Rules/Methods/CallToStaticMethodStatementWithoutSideEffectsRule.php index e5dbf15c381..9db2493f65e 100644 --- a/src/Rules/Methods/CallToStaticMethodStatementWithoutSideEffectsRule.php +++ b/src/Rules/Methods/CallToStaticMethodStatementWithoutSideEffectsRule.php @@ -22,19 +22,13 @@ class CallToStaticMethodStatementWithoutSideEffectsRule implements Rule { - /** - * @var RuleLevelHelper - */ - private $ruleLevelHelper; - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - public function __construct(RuleLevelHelper $ruleLevelHelper, ReflectionProvider $reflectionProvider) + public function __construct( + private RuleLevelHelper $ruleLevelHelper, + private ReflectionProvider $reflectionProvider, + ) { - $this->ruleLevelHelper = $ruleLevelHelper; - $this->reflectionProvider = $reflectionProvider; } + public function getNodeType(): string { return Node\Stmt\Expression::class; @@ -60,9 +54,12 @@ public function processNode(Node $node, Scope $scope): array $calledOnType = new ObjectType($className); } else { - $typeResult = $this->ruleLevelHelper->findTypeToCheck($scope, NullsafeOperatorHelper::getNullsafeShortcircuitedExprRespectingScope($scope, $staticCall->class), '', static function (Type $type) use($methodName) : bool { - return $type->canCallMethods()->yes() && $type->hasMethod($methodName)->yes(); - }); + $typeResult = $this->ruleLevelHelper->findTypeToCheck( + $scope, + NullsafeOperatorHelper::getNullsafeShortcircuitedExprRespectingScope($scope, $staticCall->class), + '', + static fn (Type $type): bool => $type->canCallMethods()->yes() && $type->hasMethod($methodName)->yes(), + ); $calledOnType = $typeResult->getType(); if ($calledOnType instanceof ErrorType) { return []; @@ -101,7 +98,12 @@ public function processNode(Node $node, Scope $scope): array } return [ - RuleErrorBuilder::message(sprintf('Call to %s %s::%s() on a separate line has no effect.', $method->isStatic() ? 'static method' : 'method', $method->getDeclaringClass()->getDisplayName(), $method->getName()))->identifier('staticMethod.resultUnused')->build(), + RuleErrorBuilder::message(sprintf( + 'Call to %s %s::%s() on a separate line has no effect.', + $method->isStatic() ? 'static method' : 'method', + $method->getDeclaringClass()->getDisplayName(), + $method->getName(), + ))->identifier('staticMethod.resultUnused')->build(), ]; } diff --git a/src/Rules/Methods/ConsistentConstructorRule.php b/src/Rules/Methods/ConsistentConstructorRule.php index e4099fb608e..e32d6fa5512 100644 --- a/src/Rules/Methods/ConsistentConstructorRule.php +++ b/src/Rules/Methods/ConsistentConstructorRule.php @@ -13,14 +13,12 @@ class ConsistentConstructorRule implements Rule { - /** - * @var MethodParameterComparisonHelper - */ - private $methodParameterComparisonHelper; - public function __construct(MethodParameterComparisonHelper $methodParameterComparisonHelper) + public function __construct( + private MethodParameterComparisonHelper $methodParameterComparisonHelper, + ) { - $this->methodParameterComparisonHelper = $methodParameterComparisonHelper; } + public function getNodeType(): string { return InClassMethodNode::class; diff --git a/src/Rules/Methods/ExistingClassesInTypehintsRule.php b/src/Rules/Methods/ExistingClassesInTypehintsRule.php index afe6f22e181..524f5093951 100644 --- a/src/Rules/Methods/ExistingClassesInTypehintsRule.php +++ b/src/Rules/Methods/ExistingClassesInTypehintsRule.php @@ -16,13 +16,8 @@ class ExistingClassesInTypehintsRule implements Rule { - /** - * @var FunctionDefinitionCheck - */ - private $check; - public function __construct(FunctionDefinitionCheck $check) + public function __construct(private FunctionDefinitionCheck $check) { - $this->check = $check; } public function getNodeType(): string @@ -36,7 +31,32 @@ public function processNode(Node $node, Scope $scope): array $className = SprintfHelper::escapeFormatString($node->getClassReflection()->getDisplayName()); $methodName = SprintfHelper::escapeFormatString($methodReflection->getName()); - return $this->check->checkClassMethod($methodReflection, $node->getOriginalNode(), sprintf('Parameter $%%s of method %s::%s() has invalid type %%s.', $className, $methodName), sprintf('Method %s::%s() has invalid return type %%s.', $className, $methodName), sprintf('Method %s::%s() uses native union types but they\'re supported only on PHP 8.0 and later.', $className, $methodName), sprintf('Template type %%s of method %s::%s() is not referenced in a parameter.', $className, $methodName), sprintf('Parameter $%%s of method %s::%s() has unresolvable native type.', $className, $methodName), sprintf('Method %s::%s() has unresolvable native return type.', $className, $methodName)); + return $this->check->checkClassMethod( + $methodReflection, + $node->getOriginalNode(), + sprintf( + 'Parameter $%%s of method %s::%s() has invalid type %%s.', + $className, + $methodName, + ), + sprintf( + 'Method %s::%s() has invalid return type %%s.', + $className, + $methodName, + ), + sprintf('Method %s::%s() uses native union types but they\'re supported only on PHP 8.0 and later.', $className, $methodName), + sprintf('Template type %%s of method %s::%s() is not referenced in a parameter.', $className, $methodName), + sprintf( + 'Parameter $%%s of method %s::%s() has unresolvable native type.', + $className, + $methodName, + ), + sprintf( + 'Method %s::%s() has unresolvable native return type.', + $className, + $methodName, + ), + ); } } diff --git a/src/Rules/Methods/FinalPrivateMethodRule.php b/src/Rules/Methods/FinalPrivateMethodRule.php index b53070d4b0a..b0934bb0c47 100644 --- a/src/Rules/Methods/FinalPrivateMethodRule.php +++ b/src/Rules/Methods/FinalPrivateMethodRule.php @@ -14,14 +14,12 @@ class FinalPrivateMethodRule implements Rule { - /** - * @var PhpVersion - */ - private $phpVersion; - public function __construct(PhpVersion $phpVersion) + public function __construct( + private PhpVersion $phpVersion, + ) { - $this->phpVersion = $phpVersion; } + public function getNodeType(): string { return InClassMethodNode::class; @@ -43,7 +41,11 @@ public function processNode(Node $node, Scope $scope): array } return [ - RuleErrorBuilder::message(sprintf('Private method %s::%s() cannot be final as it is never overridden by other classes.', $method->getDeclaringClass()->getDisplayName(), $method->getName()))->identifier('method.finalPrivate')->build(), + RuleErrorBuilder::message(sprintf( + 'Private method %s::%s() cannot be final as it is never overridden by other classes.', + $method->getDeclaringClass()->getDisplayName(), + $method->getName(), + ))->identifier('method.finalPrivate')->build(), ]; } diff --git a/src/Rules/Methods/IllegalConstructorStaticCallRule.php b/src/Rules/Methods/IllegalConstructorStaticCallRule.php index 4397fbfbe06..6e839f54ca7 100644 --- a/src/Rules/Methods/IllegalConstructorStaticCallRule.php +++ b/src/Rules/Methods/IllegalConstructorStaticCallRule.php @@ -61,9 +61,7 @@ private function isCollectCallingConstructor(Node\Expr\StaticCall $node, Scope $ return false; } - $parentClasses = array_map(static function (string $name) { - return strtolower($name); - }, $scope->getClassReflection()->getParentClassesNames()); + $parentClasses = array_map(static fn (string $name) => strtolower($name), $scope->getClassReflection()->getParentClassesNames()); return in_array(strtolower($scope->resolveName($node->class)), $parentClasses, true); } diff --git a/src/Rules/Methods/IncompatibleDefaultParameterTypeRule.php b/src/Rules/Methods/IncompatibleDefaultParameterTypeRule.php index cb0fbb8507d..92c7f49aac1 100644 --- a/src/Rules/Methods/IncompatibleDefaultParameterTypeRule.php +++ b/src/Rules/Methods/IncompatibleDefaultParameterTypeRule.php @@ -53,7 +53,15 @@ public function processNode(Node $node, Scope $scope): array $verbosityLevel = VerbosityLevel::getRecommendedLevelByType($parameterType, $defaultValueType); - $errors[] = RuleErrorBuilder::message(sprintf('Default value of the parameter #%d $%s (%s) of method %s::%s() is incompatible with type %s.', $paramI + 1, $param->var->name, $defaultValueType->describe($verbosityLevel), $method->getDeclaringClass()->getDisplayName(), $method->getName(), $parameterType->describe($verbosityLevel))) + $errors[] = RuleErrorBuilder::message(sprintf( + 'Default value of the parameter #%d $%s (%s) of method %s::%s() is incompatible with type %s.', + $paramI + 1, + $param->var->name, + $defaultValueType->describe($verbosityLevel), + $method->getDeclaringClass()->getDisplayName(), + $method->getName(), + $parameterType->describe($verbosityLevel), + )) ->line($param->getStartLine()) ->identifier('parameter.defaultValue') ->acceptsReasonsTip($accepts->reasons) diff --git a/src/Rules/Methods/MethodAttributesRule.php b/src/Rules/Methods/MethodAttributesRule.php index b4066974ef2..ae220df96ed 100644 --- a/src/Rules/Methods/MethodAttributesRule.php +++ b/src/Rules/Methods/MethodAttributesRule.php @@ -14,13 +14,8 @@ class MethodAttributesRule implements Rule { - /** - * @var AttributesCheck - */ - private $attributesCheck; - public function __construct(AttributesCheck $attributesCheck) + public function __construct(private AttributesCheck $attributesCheck) { - $this->attributesCheck = $attributesCheck; } public function getNodeType(): string @@ -30,7 +25,12 @@ public function getNodeType(): string public function processNode(Node $node, Scope $scope): array { - return $this->attributesCheck->check($scope, $node->attrGroups, Attribute::TARGET_METHOD, 'method'); + return $this->attributesCheck->check( + $scope, + $node->attrGroups, + Attribute::TARGET_METHOD, + 'method', + ); } } diff --git a/src/Rules/Methods/MethodCallCheck.php b/src/Rules/Methods/MethodCallCheck.php index 291b06c7b4d..bbf66a2f688 100644 --- a/src/Rules/Methods/MethodCallCheck.php +++ b/src/Rules/Methods/MethodCallCheck.php @@ -20,106 +20,125 @@ class MethodCallCheck { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - /** - * @var RuleLevelHelper - */ - private $ruleLevelHelper; - /** - * @var bool - */ - private $checkFunctionNameCase; - /** - * @var bool - */ - private $reportMagicMethods; - public function __construct(ReflectionProvider $reflectionProvider, RuleLevelHelper $ruleLevelHelper, bool $checkFunctionNameCase, bool $reportMagicMethods) - { - $this->reflectionProvider = $reflectionProvider; - $this->ruleLevelHelper = $ruleLevelHelper; - $this->checkFunctionNameCase = $checkFunctionNameCase; - $this->reportMagicMethods = $reportMagicMethods; + + public function __construct( + private ReflectionProvider $reflectionProvider, + private RuleLevelHelper $ruleLevelHelper, + private bool $checkFunctionNameCase, + private bool $reportMagicMethods, + ) + { + } + + /** + * @return array{list, ExtendedMethodReflection|null} + */ + public function check( + Scope $scope, + string $methodName, + Expr $var, + ): array + { + $typeResult = $this->ruleLevelHelper->findTypeToCheck( + $scope, + NullsafeOperatorHelper::getNullsafeShortcircuitedExprRespectingScope($scope, $var), + sprintf('Call to method %s() on an unknown class %%s.', SprintfHelper::escapeFormatString($methodName)), + static fn (Type $type): bool => $type->canCallMethods()->yes() && $type->hasMethod($methodName)->yes(), + ); + + $type = $typeResult->getType(); + if ($type instanceof ErrorType) { + return [$typeResult->getUnknownClassErrors(), null]; + } + if (!$type->canCallMethods()->yes() || $type->isClassStringType()->yes()) { + return [ + [ + RuleErrorBuilder::message(sprintf( + 'Cannot call method %s() on %s.', + $methodName, + $type->describe(VerbosityLevel::typeOnly()), + ))->identifier('method.nonObject')->build(), + ], + null, + ]; + } + + if (!$type->hasMethod($methodName)->yes()) { + $directClassNames = $typeResult->getReferencedClasses(); + if (!$this->reportMagicMethods) { + foreach ($directClassNames as $className) { + if (!$this->reflectionProvider->hasClass($className)) { + continue; + } + + $classReflection = $this->reflectionProvider->getClass($className); + if ($classReflection->hasNativeMethod('__call')) { + return [[], null]; + } } - /** - * @return array{list, ExtendedMethodReflection|null} - */ - public function check(Scope $scope, string $methodName, Expr $var) : array - { - $typeResult = $this->ruleLevelHelper->findTypeToCheck($scope, NullsafeOperatorHelper::getNullsafeShortcircuitedExprRespectingScope($scope, $var), sprintf('Call to method %s() on an unknown class %%s.', SprintfHelper::escapeFormatString($methodName)), static function (Type $type) use($methodName) : bool { - return $type->canCallMethods()->yes() && $type->hasMethod($methodName)->yes(); - }); - $type = $typeResult->getType(); - if ($type instanceof ErrorType) { - return [$typeResult->getUnknownClassErrors(), null]; - } - if (!$type->canCallMethods()->yes() || $type->isClassStringType()->yes()) { - return [ - [ - RuleErrorBuilder::message(sprintf('Cannot call method %s() on %s.', $methodName, $type->describe(VerbosityLevel::typeOnly())))->identifier('method.nonObject')->build(), - ], - null, - ]; - } - if (!$type->hasMethod($methodName)->yes()) { - $directClassNames = $typeResult->getReferencedClasses(); - if (!$this->reportMagicMethods) { - foreach ($directClassNames as $className) { - if (!$this->reflectionProvider->hasClass($className)) { - continue; - } - - $classReflection = $this->reflectionProvider->getClass($className); - if ($classReflection->hasNativeMethod('__call')) { - return [[], null]; - } - } - } - - if (count($directClassNames) === 1) { - $referencedClass = $directClassNames[0]; - $methodClassReflection = $this->reflectionProvider->getClass($referencedClass); - $parentClassReflection = $methodClassReflection->getParentClass(); - while ($parentClassReflection !== null) { - if ($parentClassReflection->hasMethod($methodName)) { - $methodReflection = $parentClassReflection->getMethod($methodName, $scope); - return [ - [ - RuleErrorBuilder::message(sprintf('Call to private method %s() of parent class %s.', $methodReflection->getName(), $parentClassReflection->getDisplayName()))->identifier('method.private')->build(), - ], - $methodReflection, - ]; - } - - $parentClassReflection = $parentClassReflection->getParentClass(); - } - } - - return [ - [ - RuleErrorBuilder::message(sprintf('Call to an undefined method %s::%s().', $type->describe(VerbosityLevel::typeOnly()), $methodName))->identifier('method.notFound')->build(), - ], - null, - ]; - } - $methodReflection = $type->getMethod($methodName, $scope); - $declaringClass = $methodReflection->getDeclaringClass(); - $messagesMethodName = SprintfHelper::escapeFormatString($declaringClass->getDisplayName() . '::' . $methodReflection->getName() . '()'); - $errors = []; - if (!$scope->canCallMethod($methodReflection)) { - $errors[] = RuleErrorBuilder::message(sprintf('Call to %s method %s() of class %s.', $methodReflection->isPrivate() ? 'private' : 'protected', $methodReflection->getName(), $declaringClass->getDisplayName())) - ->identifier(sprintf('method.%s', $methodReflection->isPrivate() ? 'private' : 'protected')) - ->build(); - } - if ( - $this->checkFunctionNameCase - && strtolower($methodReflection->getName()) === strtolower($methodName) - && $methodReflection->getName() !== $methodName - ) { - $errors[] = RuleErrorBuilder::message(sprintf('Call to method %s with incorrect case: %s', $messagesMethodName, $methodName))->identifier('method.nameCase')->build(); - } - return [$errors, $methodReflection]; + } + + if (count($directClassNames) === 1) { + $referencedClass = $directClassNames[0]; + $methodClassReflection = $this->reflectionProvider->getClass($referencedClass); + $parentClassReflection = $methodClassReflection->getParentClass(); + while ($parentClassReflection !== null) { + if ($parentClassReflection->hasMethod($methodName)) { + $methodReflection = $parentClassReflection->getMethod($methodName, $scope); + return [ + [ + RuleErrorBuilder::message(sprintf( + 'Call to private method %s() of parent class %s.', + $methodReflection->getName(), + $parentClassReflection->getDisplayName(), + ))->identifier('method.private')->build(), + ], + $methodReflection, + ]; + } + + $parentClassReflection = $parentClassReflection->getParentClass(); } + } + + return [ + [ + RuleErrorBuilder::message(sprintf( + 'Call to an undefined method %s::%s().', + $type->describe(VerbosityLevel::typeOnly()), + $methodName, + ))->identifier('method.notFound')->build(), + ], + null, + ]; + } + + $methodReflection = $type->getMethod($methodName, $scope); + $declaringClass = $methodReflection->getDeclaringClass(); + $messagesMethodName = SprintfHelper::escapeFormatString($declaringClass->getDisplayName() . '::' . $methodReflection->getName() . '()'); + $errors = []; + if (!$scope->canCallMethod($methodReflection)) { + $errors[] = RuleErrorBuilder::message(sprintf( + 'Call to %s method %s() of class %s.', + $methodReflection->isPrivate() ? 'private' : 'protected', + $methodReflection->getName(), + $declaringClass->getDisplayName(), + )) + ->identifier(sprintf('method.%s', $methodReflection->isPrivate() ? 'private' : 'protected')) + ->build(); + } + + if ( + $this->checkFunctionNameCase + && strtolower($methodReflection->getName()) === strtolower($methodName) + && $methodReflection->getName() !== $methodName + ) { + $errors[] = RuleErrorBuilder::message( + sprintf('Call to method %s with incorrect case: %s', $messagesMethodName, $methodName), + )->identifier('method.nameCase')->build(); + } + + return [$errors, $methodReflection]; + } + } diff --git a/src/Rules/Methods/MethodCallableRule.php b/src/Rules/Methods/MethodCallableRule.php index cc4195beaa6..15027c8c2c2 100644 --- a/src/Rules/Methods/MethodCallableRule.php +++ b/src/Rules/Methods/MethodCallableRule.php @@ -17,18 +17,8 @@ class MethodCallableRule implements Rule { - /** - * @var MethodCallCheck - */ - private $methodCallCheck; - /** - * @var PhpVersion - */ - private $phpVersion; - public function __construct(MethodCallCheck $methodCallCheck, PhpVersion $phpVersion) + public function __construct(private MethodCallCheck $methodCallCheck, private PhpVersion $phpVersion) { - $this->methodCallCheck = $methodCallCheck; - $this->phpVersion = $phpVersion; } public function getNodeType(): string diff --git a/src/Rules/Methods/MethodParameterComparisonHelper.php b/src/Rules/Methods/MethodParameterComparisonHelper.php index 0a6196728a6..357d3cf9b32 100644 --- a/src/Rules/Methods/MethodParameterComparisonHelper.php +++ b/src/Rules/Methods/MethodParameterComparisonHelper.php @@ -24,18 +24,8 @@ class MethodParameterComparisonHelper { - /** - * @var PhpVersion - */ - private $phpVersion; - /** - * @var bool - */ - private $genericPrototypeMessage; - public function __construct(PhpVersion $phpVersion, bool $genericPrototypeMessage) + public function __construct(private PhpVersion $phpVersion, private bool $genericPrototypeMessage) { - $this->phpVersion = $phpVersion; - $this->genericPrototypeMessage = $genericPrototypeMessage; } /** @@ -53,7 +43,15 @@ public function compare(ExtendedMethodReflection $prototype, ClassReflection $pr $prototypeAfterVariadic = false; foreach ($prototypeVariant->getParameters() as $i => $prototypeParameter) { if (!array_key_exists($i, $methodParameters)) { - $error = RuleErrorBuilder::message(sprintf('Method %s::%s() overrides method %s::%s() but misses parameter #%d $%s.', $method->getDeclaringClass()->getDisplayName(), $method->getName(), $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), $prototype->getName(), $i + 1, $prototypeParameter->getName()))->identifier('parameter.missing'); + $error = RuleErrorBuilder::message(sprintf( + 'Method %s::%s() overrides method %s::%s() but misses parameter #%d $%s.', + $method->getDeclaringClass()->getDisplayName(), + $method->getName(), + $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), + $prototype->getName(), + $i + 1, + $prototypeParameter->getName(), + ))->identifier('parameter.missing'); if (! $ignorable) { $error->nonIgnorable(); @@ -67,7 +65,17 @@ public function compare(ExtendedMethodReflection $prototype, ClassReflection $pr $methodParameter = $methodParameters[$i]; if ($prototypeParameter->passedByReference()->no()) { if (!$methodParameter->passedByReference()->no()) { - $error = RuleErrorBuilder::message(sprintf('Parameter #%d $%s of method %s::%s() is passed by reference but parameter #%d $%s of method %s::%s() is not passed by reference.', $i + 1, $methodParameter->getName(), $method->getDeclaringClass()->getDisplayName(), $method->getName(), $i + 1, $prototypeParameter->getName(), $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), $prototype->getName()))->identifier('parameter.byRef'); + $error = RuleErrorBuilder::message(sprintf( + 'Parameter #%d $%s of method %s::%s() is passed by reference but parameter #%d $%s of method %s::%s() is not passed by reference.', + $i + 1, + $methodParameter->getName(), + $method->getDeclaringClass()->getDisplayName(), + $method->getName(), + $i + 1, + $prototypeParameter->getName(), + $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), + $prototype->getName(), + ))->identifier('parameter.byRef'); if (! $ignorable) { $error->nonIgnorable(); @@ -76,7 +84,17 @@ public function compare(ExtendedMethodReflection $prototype, ClassReflection $pr $messages[] = $error->build(); } } elseif ($methodParameter->passedByReference()->no()) { - $error = RuleErrorBuilder::message(sprintf('Parameter #%d $%s of method %s::%s() is not passed by reference but parameter #%d $%s of method %s::%s() is passed by reference.', $i + 1, $methodParameter->getName(), $method->getDeclaringClass()->getDisplayName(), $method->getName(), $i + 1, $prototypeParameter->getName(), $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), $prototype->getName()))->identifier('parameter.notByRef'); + $error = RuleErrorBuilder::message(sprintf( + 'Parameter #%d $%s of method %s::%s() is not passed by reference but parameter #%d $%s of method %s::%s() is passed by reference.', + $i + 1, + $methodParameter->getName(), + $method->getDeclaringClass()->getDisplayName(), + $method->getName(), + $i + 1, + $prototypeParameter->getName(), + $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), + $prototype->getName(), + ))->identifier('parameter.notByRef'); if (! $ignorable) { $error->nonIgnorable(); @@ -90,7 +108,13 @@ public function compare(ExtendedMethodReflection $prototype, ClassReflection $pr if (!$methodParameter->isVariadic()) { if (!$methodParameter->isOptional()) { if (count($methodParameters) !== $i + 1) { - $error = RuleErrorBuilder::message(sprintf('Parameter #%d $%s of method %s::%s() is not optional.', $i + 1, $methodParameter->getName(), $method->getDeclaringClass()->getDisplayName(), $method->getName()))->identifier('parameter.notOptional'); + $error = RuleErrorBuilder::message(sprintf( + 'Parameter #%d $%s of method %s::%s() is not optional.', + $i + 1, + $methodParameter->getName(), + $method->getDeclaringClass()->getDisplayName(), + $method->getName(), + ))->identifier('parameter.notOptional'); if (! $ignorable) { $error->nonIgnorable(); @@ -101,7 +125,17 @@ public function compare(ExtendedMethodReflection $prototype, ClassReflection $pr continue; } - $error = RuleErrorBuilder::message(sprintf('Parameter #%d $%s of method %s::%s() is not variadic but parameter #%d $%s of method %s::%s() is variadic.', $i + 1, $methodParameter->getName(), $method->getDeclaringClass()->getDisplayName(), $method->getName(), $i + 1, $prototypeParameter->getName(), $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), $prototype->getName()))->identifier('parameter.notVariadic'); + $error = RuleErrorBuilder::message(sprintf( + 'Parameter #%d $%s of method %s::%s() is not variadic but parameter #%d $%s of method %s::%s() is variadic.', + $i + 1, + $methodParameter->getName(), + $method->getDeclaringClass()->getDisplayName(), + $method->getName(), + $i + 1, + $prototypeParameter->getName(), + $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), + $prototype->getName(), + ))->identifier('parameter.notVariadic'); if (! $ignorable) { $error->nonIgnorable(); @@ -111,7 +145,13 @@ public function compare(ExtendedMethodReflection $prototype, ClassReflection $pr continue; } elseif (count($methodParameters) === $i + 1) { - $error = RuleErrorBuilder::message(sprintf('Parameter #%d $%s of method %s::%s() is not variadic.', $i + 1, $methodParameter->getName(), $method->getDeclaringClass()->getDisplayName(), $method->getName()))->identifier('parameter.notVariadic'); + $error = RuleErrorBuilder::message(sprintf( + 'Parameter #%d $%s of method %s::%s() is not variadic.', + $i + 1, + $methodParameter->getName(), + $method->getDeclaringClass()->getDisplayName(), + $method->getName(), + ))->identifier('parameter.notVariadic'); if (! $ignorable) { $error->nonIgnorable(); @@ -128,7 +168,19 @@ public function compare(ExtendedMethodReflection $prototype, ClassReflection $pr continue; } - $error = RuleErrorBuilder::message(sprintf('Parameter #%d ...$%s (%s) of method %s::%s() is not contravariant with parameter #%d $%s (%s) of method %s::%s().', $i + 1, $methodParameter->getName(), $methodParameter->getNativeType()->describe(VerbosityLevel::typeOnly()), $method->getDeclaringClass()->getDisplayName(), $method->getName(), $i + $j + 1, $remainingPrototypeParameter->getName(), $remainingPrototypeParameter->getNativeType()->describe(VerbosityLevel::typeOnly()), $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), $prototype->getName()))->identifier('method.childParameterType'); + $error = RuleErrorBuilder::message(sprintf( + 'Parameter #%d ...$%s (%s) of method %s::%s() is not contravariant with parameter #%d $%s (%s) of method %s::%s().', + $i + 1, + $methodParameter->getName(), + $methodParameter->getNativeType()->describe(VerbosityLevel::typeOnly()), + $method->getDeclaringClass()->getDisplayName(), + $method->getName(), + $i + $j + 1, + $remainingPrototypeParameter->getName(), + $remainingPrototypeParameter->getNativeType()->describe(VerbosityLevel::typeOnly()), + $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), + $prototype->getName(), + ))->identifier('method.childParameterType'); if (! $ignorable) { $error->nonIgnorable(); @@ -138,7 +190,17 @@ public function compare(ExtendedMethodReflection $prototype, ClassReflection $pr } break; } - $error = RuleErrorBuilder::message(sprintf('Parameter #%d $%s of method %s::%s() is variadic but parameter #%d $%s of method %s::%s() is not variadic.', $i + 1, $methodParameter->getName(), $method->getDeclaringClass()->getDisplayName(), $method->getName(), $i + 1, $prototypeParameter->getName(), $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), $prototype->getName()))->identifier('parameter.variadic'); + $error = RuleErrorBuilder::message(sprintf( + 'Parameter #%d $%s of method %s::%s() is variadic but parameter #%d $%s of method %s::%s() is not variadic.', + $i + 1, + $methodParameter->getName(), + $method->getDeclaringClass()->getDisplayName(), + $method->getName(), + $i + 1, + $prototypeParameter->getName(), + $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), + $prototype->getName(), + ))->identifier('parameter.variadic'); if (! $ignorable) { $error->nonIgnorable(); @@ -150,7 +212,17 @@ public function compare(ExtendedMethodReflection $prototype, ClassReflection $pr } if ($prototypeParameter->isOptional() && !$methodParameter->isOptional()) { - $error = RuleErrorBuilder::message(sprintf('Parameter #%d $%s of method %s::%s() is required but parameter #%d $%s of method %s::%s() is optional.', $i + 1, $methodParameter->getName(), $method->getDeclaringClass()->getDisplayName(), $method->getName(), $i + 1, $prototypeParameter->getName(), $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), $prototype->getName()))->identifier('parameter.notOptional'); + $error = RuleErrorBuilder::message(sprintf( + 'Parameter #%d $%s of method %s::%s() is required but parameter #%d $%s of method %s::%s() is optional.', + $i + 1, + $methodParameter->getName(), + $method->getDeclaringClass()->getDisplayName(), + $method->getName(), + $i + 1, + $prototypeParameter->getName(), + $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), + $prototype->getName(), + ))->identifier('parameter.notOptional'); if (! $ignorable) { $error->nonIgnorable(); @@ -164,7 +236,19 @@ public function compare(ExtendedMethodReflection $prototype, ClassReflection $pr $prototypeParameterType = $prototypeParameter->getNativeType(); if (!$this->phpVersion->supportsParameterTypeWidening()) { if (!$methodParameterType->equals($prototypeParameterType)) { - $error = RuleErrorBuilder::message(sprintf('Parameter #%d $%s (%s) of method %s::%s() does not match parameter #%d $%s (%s) of method %s::%s().', $i + 1, $methodParameter->getName(), $methodParameterType->describe(VerbosityLevel::typeOnly()), $method->getDeclaringClass()->getDisplayName(), $method->getName(), $i + 1, $prototypeParameter->getName(), $prototypeParameterType->describe(VerbosityLevel::typeOnly()), $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), $prototype->getName()))->identifier('method.childParameterType'); + $error = RuleErrorBuilder::message(sprintf( + 'Parameter #%d $%s (%s) of method %s::%s() does not match parameter #%d $%s (%s) of method %s::%s().', + $i + 1, + $methodParameter->getName(), + $methodParameterType->describe(VerbosityLevel::typeOnly()), + $method->getDeclaringClass()->getDisplayName(), + $method->getName(), + $i + 1, + $prototypeParameter->getName(), + $prototypeParameterType->describe(VerbosityLevel::typeOnly()), + $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), + $prototype->getName(), + ))->identifier('method.childParameterType'); if (! $ignorable) { $error->nonIgnorable(); @@ -180,7 +264,19 @@ public function compare(ExtendedMethodReflection $prototype, ClassReflection $pr } if ($this->phpVersion->supportsParameterContravariance()) { - $error = RuleErrorBuilder::message(sprintf('Parameter #%d $%s (%s) of method %s::%s() is not contravariant with parameter #%d $%s (%s) of method %s::%s().', $i + 1, $methodParameter->getName(), $methodParameterType->describe(VerbosityLevel::typeOnly()), $method->getDeclaringClass()->getDisplayName(), $method->getName(), $i + 1, $prototypeParameter->getName(), $prototypeParameterType->describe(VerbosityLevel::typeOnly()), $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), $prototype->getName()))->identifier('method.childParameterType'); + $error = RuleErrorBuilder::message(sprintf( + 'Parameter #%d $%s (%s) of method %s::%s() is not contravariant with parameter #%d $%s (%s) of method %s::%s().', + $i + 1, + $methodParameter->getName(), + $methodParameterType->describe(VerbosityLevel::typeOnly()), + $method->getDeclaringClass()->getDisplayName(), + $method->getName(), + $i + 1, + $prototypeParameter->getName(), + $prototypeParameterType->describe(VerbosityLevel::typeOnly()), + $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), + $prototype->getName(), + ))->identifier('method.childParameterType'); if (! $ignorable) { $error->nonIgnorable(); @@ -188,7 +284,19 @@ public function compare(ExtendedMethodReflection $prototype, ClassReflection $pr $messages[] = $error->build(); } else { - $error = RuleErrorBuilder::message(sprintf('Parameter #%d $%s (%s) of method %s::%s() is not compatible with parameter #%d $%s (%s) of method %s::%s().', $i + 1, $methodParameter->getName(), $methodParameterType->describe(VerbosityLevel::typeOnly()), $method->getDeclaringClass()->getDisplayName(), $method->getName(), $i + 1, $prototypeParameter->getName(), $prototypeParameterType->describe(VerbosityLevel::typeOnly()), $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), $prototype->getName()))->identifier('method.childParameterType'); + $error = RuleErrorBuilder::message(sprintf( + 'Parameter #%d $%s (%s) of method %s::%s() is not compatible with parameter #%d $%s (%s) of method %s::%s().', + $i + 1, + $methodParameter->getName(), + $methodParameterType->describe(VerbosityLevel::typeOnly()), + $method->getDeclaringClass()->getDisplayName(), + $method->getName(), + $i + 1, + $prototypeParameter->getName(), + $prototypeParameterType->describe(VerbosityLevel::typeOnly()), + $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), + $prototype->getName(), + ))->identifier('method.childParameterType'); if (! $ignorable) { $error->nonIgnorable(); @@ -212,7 +320,13 @@ public function compare(ExtendedMethodReflection $prototype, ClassReflection $pr && $prototypeAfterVariadic && !$methodParameter->isVariadic() ) { - $error = RuleErrorBuilder::message(sprintf('Parameter #%d $%s of method %s::%s() is not variadic.', $j + 1, $methodParameter->getName(), $method->getDeclaringClass()->getDisplayName(), $method->getName()))->identifier('parameter.notVariadic'); + $error = RuleErrorBuilder::message(sprintf( + 'Parameter #%d $%s of method %s::%s() is not variadic.', + $j + 1, + $methodParameter->getName(), + $method->getDeclaringClass()->getDisplayName(), + $method->getName(), + ))->identifier('parameter.notVariadic'); if (! $ignorable) { $error->nonIgnorable(); @@ -227,7 +341,13 @@ public function compare(ExtendedMethodReflection $prototype, ClassReflection $pr continue; } - $error = RuleErrorBuilder::message(sprintf('Parameter #%d $%s of method %s::%s() is not optional.', $j + 1, $methodParameter->getName(), $method->getDeclaringClass()->getDisplayName(), $method->getName()))->identifier('parameter.notOptional'); + $error = RuleErrorBuilder::message(sprintf( + 'Parameter #%d $%s of method %s::%s() is not optional.', + $j + 1, + $methodParameter->getName(), + $method->getDeclaringClass()->getDisplayName(), + $method->getName(), + ))->identifier('parameter.notOptional'); if (! $ignorable) { $error->nonIgnorable(); diff --git a/src/Rules/Methods/MethodSignatureRule.php b/src/Rules/Methods/MethodSignatureRule.php index 28965100b24..f7a1a8120bc 100644 --- a/src/Rules/Methods/MethodSignatureRule.php +++ b/src/Rules/Methods/MethodSignatureRule.php @@ -40,29 +40,15 @@ class MethodSignatureRule implements Rule { - /** - * @var PhpClassReflectionExtension - */ - private $phpClassReflectionExtension; - /** - * @var bool - */ - private $reportMaybes; - /** - * @var bool - */ - private $reportStatic; - /** - * @var bool - */ - private $abstractTraitMethod; - public function __construct(PhpClassReflectionExtension $phpClassReflectionExtension, bool $reportMaybes, bool $reportStatic, bool $abstractTraitMethod) + public function __construct( + private PhpClassReflectionExtension $phpClassReflectionExtension, + private bool $reportMaybes, + private bool $reportStatic, + private bool $abstractTraitMethod, + ) { - $this->phpClassReflectionExtension = $phpClassReflectionExtension; - $this->reportMaybes = $reportMaybes; - $this->reportStatic = $reportStatic; - $this->abstractTraitMethod = $abstractTraitMethod; } + public function getNodeType(): string { return InClassMethodNode::class; @@ -93,7 +79,16 @@ public function processNode(Node $node, Scope $scope): array $parentParameters = ParametersAcceptorSelector::selectSingle($parentVariants); [$returnTypeCompatibility, $returnType, $parentReturnType] = $this->checkReturnTypeCompatibility($declaringClass, $parameters, $parentParameters); if ($returnTypeCompatibility->no() || (!$returnTypeCompatibility->yes() && $this->reportMaybes)) { - $builder = RuleErrorBuilder::message(sprintf('Return type (%s) of method %s::%s() should be %s with return type (%s) of method %s::%s()', $returnType->describe(VerbosityLevel::value()), $method->getDeclaringClass()->getDisplayName(), $method->getName(), $returnTypeCompatibility->no() ? 'compatible' : 'covariant', $parentReturnType->describe(VerbosityLevel::value()), $parentMethodDeclaringClass->getDisplayName(), $parentMethod->getName()))->identifier('method.childReturnType'); + $builder = RuleErrorBuilder::message(sprintf( + 'Return type (%s) of method %s::%s() should be %s with return type (%s) of method %s::%s()', + $returnType->describe(VerbosityLevel::value()), + $method->getDeclaringClass()->getDisplayName(), + $method->getName(), + $returnTypeCompatibility->no() ? 'compatible' : 'covariant', + $parentReturnType->describe(VerbosityLevel::value()), + $parentMethodDeclaringClass->getDisplayName(), + $parentMethod->getName(), + ))->identifier('method.childReturnType'); if ( $parentMethod->getDeclaringClass()->getName() === Rule::class && strtolower($methodName) === 'processnode' @@ -131,7 +126,19 @@ public function processNode(Node $node, Scope $scope): array } $parameter = $parameters->getParameters()[$parameterIndex]; $parentParameter = $parentParameters->getParameters()[$parameterIndex]; - $errors[] = RuleErrorBuilder::message(sprintf('Parameter #%d $%s (%s) of method %s::%s() should be %s with parameter $%s (%s) of method %s::%s()', $parameterIndex + 1, $parameter->getName(), $parameterType->describe(VerbosityLevel::value()), $method->getDeclaringClass()->getDisplayName(), $method->getName(), $parameterResult->no() ? 'compatible' : 'contravariant', $parentParameter->getName(), $parentParameterType->describe(VerbosityLevel::value()), $parentMethodDeclaringClass->getDisplayName(), $parentMethod->getName()))->identifier('method.childParameterType')->build(); + $errors[] = RuleErrorBuilder::message(sprintf( + 'Parameter #%d $%s (%s) of method %s::%s() should be %s with parameter $%s (%s) of method %s::%s()', + $parameterIndex + 1, + $parameter->getName(), + $parameterType->describe(VerbosityLevel::value()), + $method->getDeclaringClass()->getDisplayName(), + $method->getName(), + $parameterResult->no() ? 'compatible' : 'contravariant', + $parentParameter->getName(), + $parentParameterType->describe(VerbosityLevel::value()), + $parentMethodDeclaringClass->getDisplayName(), + $parentMethod->getName(), + ))->identifier('method.childParameterType')->build(); } } @@ -177,7 +184,12 @@ private function collectParentMethods(string $methodName, ClassReflection $class $declaringTrait = $trait->getNativeMethod($methodName)->getDeclaringClass(); $parentMethods[] = [ - $this->phpClassReflectionExtension->createUserlandMethodReflection($trait, $class, new NativeBuiltinMethodReflection($methodReflection), $declaringTrait->getName()), + $this->phpClassReflectionExtension->createUserlandMethodReflection( + $trait, + $class, + new NativeBuiltinMethodReflection($methodReflection), + $declaringTrait->getName(), + ), $declaringTrait, ]; } @@ -189,20 +201,35 @@ private function collectParentMethods(string $methodName, ClassReflection $class /** * @return array{TrinaryLogic, Type, Type} */ - private function checkReturnTypeCompatibility(ClassReflection $declaringClass, ParametersAcceptorWithPhpDocs $currentVariant, ParametersAcceptorWithPhpDocs $parentVariant) : array + private function checkReturnTypeCompatibility( + ClassReflection $declaringClass, + ParametersAcceptorWithPhpDocs $currentVariant, + ParametersAcceptorWithPhpDocs $parentVariant, + ): array { - $returnType = TypehintHelper::decideType($currentVariant->getNativeReturnType(), TemplateTypeHelper::resolveToBounds($currentVariant->getPhpDocReturnType())); - $originalParentReturnType = TypehintHelper::decideType($parentVariant->getNativeReturnType(), TemplateTypeHelper::resolveToBounds($parentVariant->getPhpDocReturnType())); + $returnType = TypehintHelper::decideType( + $currentVariant->getNativeReturnType(), + TemplateTypeHelper::resolveToBounds($currentVariant->getPhpDocReturnType()), + ); + $originalParentReturnType = TypehintHelper::decideType( + $parentVariant->getNativeReturnType(), + TemplateTypeHelper::resolveToBounds($parentVariant->getPhpDocReturnType()), + ); $parentReturnType = $this->transformStaticType($declaringClass, $originalParentReturnType); // Allow adding `void` return type hints when the parent defines no return type if ($returnType->isVoid()->yes() && $parentReturnType instanceof MixedType) { return [TrinaryLogic::createYes(), $returnType, $parentReturnType]; } + // We can return anything if ($parentReturnType->isVoid()->yes()) { return [TrinaryLogic::createYes(), $returnType, $parentReturnType]; } - return [$parentReturnType->isSuperTypeOf($returnType), TypehintHelper::decideType($currentVariant->getNativeReturnType(), $currentVariant->getPhpDocReturnType()), $originalParentReturnType]; + + return [$parentReturnType->isSuperTypeOf($returnType), TypehintHelper::decideType( + $currentVariant->getNativeReturnType(), + $currentVariant->getPhpDocReturnType(), + ), $originalParentReturnType]; } /** @@ -210,20 +237,35 @@ private function checkReturnTypeCompatibility(ClassReflection $declaringClass, P * @param ParameterReflectionWithPhpDocs[] $parentParameters * @return array */ - private function checkParameterTypeCompatibility(ClassReflection $declaringClass, array $parameters, array $parentParameters) : array + private function checkParameterTypeCompatibility( + ClassReflection $declaringClass, + array $parameters, + array $parentParameters, + ): array { $parameterResults = []; + $numberOfParameters = min(count($parameters), count($parentParameters)); for ($i = 0; $i < $numberOfParameters; $i++) { $parameter = $parameters[$i]; $parentParameter = $parentParameters[$i]; - $parameterType = TypehintHelper::decideType($parameter->getNativeType(), TemplateTypeHelper::resolveToBounds($parameter->getPhpDocType())); - $originalParameterType = TypehintHelper::decideType($parentParameter->getNativeType(), TemplateTypeHelper::resolveToBounds($parentParameter->getPhpDocType())); + $parameterType = TypehintHelper::decideType( + $parameter->getNativeType(), + TemplateTypeHelper::resolveToBounds($parameter->getPhpDocType()), + ); + $originalParameterType = TypehintHelper::decideType( + $parentParameter->getNativeType(), + TemplateTypeHelper::resolveToBounds($parentParameter->getPhpDocType()), + ); $parentParameterType = $this->transformStaticType($declaringClass, $originalParameterType); - $parameterResults[] = [$parameterType->isSuperTypeOf($parentParameterType), TypehintHelper::decideType($parameter->getNativeType(), $parameter->getPhpDocType()), $originalParameterType]; + $parameterResults[] = [$parameterType->isSuperTypeOf($parentParameterType), TypehintHelper::decideType( + $parameter->getNativeType(), + $parameter->getPhpDocType(), + ), $originalParameterType]; } + return $parameterResults; } diff --git a/src/Rules/Methods/MethodVisibilityInInterfaceRule.php b/src/Rules/Methods/MethodVisibilityInInterfaceRule.php index 9454cb68da9..2bb1fb915d8 100644 --- a/src/Rules/Methods/MethodVisibilityInInterfaceRule.php +++ b/src/Rules/Methods/MethodVisibilityInInterfaceRule.php @@ -36,7 +36,11 @@ public function processNode(Node $node, Scope $scope): array } return [ - RuleErrorBuilder::message(sprintf('Method %s::%s() cannot use non-public visibility in interface.', $method->getDeclaringClass()->getDisplayName(), $method->getName()))->identifier('method.visibility')->nonIgnorable()->build(), + RuleErrorBuilder::message(sprintf( + 'Method %s::%s() cannot use non-public visibility in interface.', + $method->getDeclaringClass()->getDisplayName(), + $method->getName(), + ))->identifier('method.visibility')->nonIgnorable()->build(), ]; } diff --git a/src/Rules/Methods/MissingMagicSerializationMethodsRule.php b/src/Rules/Methods/MissingMagicSerializationMethodsRule.php index 0580c6a9368..a169d867948 100644 --- a/src/Rules/Methods/MissingMagicSerializationMethodsRule.php +++ b/src/Rules/Methods/MissingMagicSerializationMethodsRule.php @@ -19,13 +19,8 @@ class MissingMagicSerializationMethodsRule implements Rule { - /** - * @var PhpVersion - */ - private $phpversion; - public function __construct(PhpVersion $phpversion) + public function __construct(private PhpVersion $phpversion) { - $this->phpversion = $phpversion; } public function getNodeType(): string @@ -50,7 +45,7 @@ public function processNode(Node $node, Scope $scope): array try { $nativeMethods = $classReflection->getNativeReflection()->getMethods(); - } catch (IdentifierNotFound $e) { + } catch (IdentifierNotFound) { return []; } @@ -68,13 +63,19 @@ public function processNode(Node $node, Scope $scope): array } if ($missingMagicSerialize) { - $messages[] = RuleErrorBuilder::message(sprintf('Non-abstract class %s implements the Serializable interface, but does not implement __serialize().', $classReflection->getDisplayName())) + $messages[] = RuleErrorBuilder::message(sprintf( + 'Non-abstract class %s implements the Serializable interface, but does not implement __serialize().', + $classReflection->getDisplayName(), + )) ->tip('See https://wiki.php.net/rfc/phase_out_serializable') ->identifier('class.serializable') ->build(); } if ($missingMagicUnserialize) { - $messages[] = RuleErrorBuilder::message(sprintf('Non-abstract class %s implements the Serializable interface, but does not implement __unserialize().', $classReflection->getDisplayName())) + $messages[] = RuleErrorBuilder::message(sprintf( + 'Non-abstract class %s implements the Serializable interface, but does not implement __unserialize().', + $classReflection->getDisplayName(), + )) ->tip('See https://wiki.php.net/rfc/phase_out_serializable') ->identifier('class.serializable') ->build(); diff --git a/src/Rules/Methods/MissingMethodImplementationRule.php b/src/Rules/Methods/MissingMethodImplementationRule.php index 5712736f278..e7b6d2c3bb8 100644 --- a/src/Rules/Methods/MissingMethodImplementationRule.php +++ b/src/Rules/Methods/MissingMethodImplementationRule.php @@ -35,7 +35,7 @@ public function processNode(Node $node, Scope $scope): array try { $nativeMethods = $classReflection->getNativeReflection()->getMethods(); - } catch (IdentifierNotFound $e) { + } catch (IdentifierNotFound) { return []; } foreach ($nativeMethods as $method) { @@ -50,7 +50,14 @@ public function processNode(Node $node, Scope $scope): array $classLikeDescription = 'Enum'; } - $messages[] = RuleErrorBuilder::message(sprintf('%s %s contains abstract method %s() from %s %s.', $classLikeDescription, $classReflection->getDisplayName(), $method->getName(), $declaringClass->isInterface() ? 'interface' : 'class', $declaringClass->getName()))->nonIgnorable()->identifier('method.abstract')->build(); + $messages[] = RuleErrorBuilder::message(sprintf( + '%s %s contains abstract method %s() from %s %s.', + $classLikeDescription, + $classReflection->getDisplayName(), + $method->getName(), + $declaringClass->isInterface() ? 'interface' : 'class', + $declaringClass->getName(), + ))->nonIgnorable()->identifier('method.abstract')->build(); } return $messages; diff --git a/src/Rules/Methods/MissingMethodParameterTypehintRule.php b/src/Rules/Methods/MissingMethodParameterTypehintRule.php index 37a0546d46b..7b2ffe290ea 100644 --- a/src/Rules/Methods/MissingMethodParameterTypehintRule.php +++ b/src/Rules/Methods/MissingMethodParameterTypehintRule.php @@ -23,13 +23,8 @@ final class MissingMethodParameterTypehintRule implements Rule { - /** - * @var MissingTypehintCheck - */ - private $missingTypehintCheck; - public function __construct(MissingTypehintCheck $missingTypehintCheck) + public function __construct(private MissingTypehintCheck $missingTypehintCheck) { - $this->missingTypehintCheck = $missingTypehintCheck; } public function getNodeType(): string @@ -60,28 +55,52 @@ private function checkMethodParameter(MethodReflection $methodReflection, Parame if ($parameterType instanceof MixedType && !$parameterType->isExplicitMixed()) { return [ - RuleErrorBuilder::message(sprintf('Method %s::%s() has parameter $%s with no type specified.', $methodReflection->getDeclaringClass()->getDisplayName(), $methodReflection->getName(), $parameterReflection->getName()))->identifier('missingType.parameter')->build(), + RuleErrorBuilder::message(sprintf( + 'Method %s::%s() has parameter $%s with no type specified.', + $methodReflection->getDeclaringClass()->getDisplayName(), + $methodReflection->getName(), + $parameterReflection->getName(), + ))->identifier('missingType.parameter')->build(), ]; } $messages = []; foreach ($this->missingTypehintCheck->getIterableTypesWithMissingValueTypehint($parameterType) as $iterableType) { $iterableTypeDescription = $iterableType->describe(VerbosityLevel::typeOnly()); - $messages[] = RuleErrorBuilder::message(sprintf('Method %s::%s() has parameter $%s with no value type specified in iterable type %s.', $methodReflection->getDeclaringClass()->getDisplayName(), $methodReflection->getName(), $parameterReflection->getName(), $iterableTypeDescription)) + $messages[] = RuleErrorBuilder::message(sprintf( + 'Method %s::%s() has parameter $%s with no value type specified in iterable type %s.', + $methodReflection->getDeclaringClass()->getDisplayName(), + $methodReflection->getName(), + $parameterReflection->getName(), + $iterableTypeDescription, + )) ->tip(MissingTypehintCheck::MISSING_ITERABLE_VALUE_TYPE_TIP) ->identifier('missingType.iterableValue') ->build(); } foreach ($this->missingTypehintCheck->getNonGenericObjectTypesWithGenericClass($parameterType) as [$name, $genericTypeNames]) { - $messages[] = RuleErrorBuilder::message(sprintf('Method %s::%s() has parameter $%s with generic %s but does not specify its types: %s', $methodReflection->getDeclaringClass()->getDisplayName(), $methodReflection->getName(), $parameterReflection->getName(), $name, implode(', ', $genericTypeNames))) + $messages[] = RuleErrorBuilder::message(sprintf( + 'Method %s::%s() has parameter $%s with generic %s but does not specify its types: %s', + $methodReflection->getDeclaringClass()->getDisplayName(), + $methodReflection->getName(), + $parameterReflection->getName(), + $name, + implode(', ', $genericTypeNames), + )) ->tip(MissingTypehintCheck::TURN_OFF_NON_GENERIC_CHECK_TIP) ->identifier('missingType.generics') ->build(); } foreach ($this->missingTypehintCheck->getCallablesWithMissingSignature($parameterType) as $callableType) { - $messages[] = RuleErrorBuilder::message(sprintf('Method %s::%s() has parameter $%s with no signature specified for %s.', $methodReflection->getDeclaringClass()->getDisplayName(), $methodReflection->getName(), $parameterReflection->getName(), $callableType->describe(VerbosityLevel::typeOnly())))->identifier('missingType.callable')->build(); + $messages[] = RuleErrorBuilder::message(sprintf( + 'Method %s::%s() has parameter $%s with no signature specified for %s.', + $methodReflection->getDeclaringClass()->getDisplayName(), + $methodReflection->getName(), + $parameterReflection->getName(), + $callableType->describe(VerbosityLevel::typeOnly()), + ))->identifier('missingType.callable')->build(); } return $messages; diff --git a/src/Rules/Methods/MissingMethodReturnTypehintRule.php b/src/Rules/Methods/MissingMethodReturnTypehintRule.php index 88da9ab255a..64e08269087 100644 --- a/src/Rules/Methods/MissingMethodReturnTypehintRule.php +++ b/src/Rules/Methods/MissingMethodReturnTypehintRule.php @@ -20,13 +20,8 @@ final class MissingMethodReturnTypehintRule implements Rule { - /** - * @var MissingTypehintCheck - */ - private $missingTypehintCheck; - public function __construct(MissingTypehintCheck $missingTypehintCheck) + public function __construct(private MissingTypehintCheck $missingTypehintCheck) { - $this->missingTypehintCheck = $missingTypehintCheck; } public function getNodeType(): string @@ -48,28 +43,48 @@ public function processNode(Node $node, Scope $scope): array if ($returnType instanceof MixedType && !$returnType->isExplicitMixed()) { return [ - RuleErrorBuilder::message(sprintf('Method %s::%s() has no return type specified.', $methodReflection->getDeclaringClass()->getDisplayName(), $methodReflection->getName()))->identifier('missingType.return')->build(), + RuleErrorBuilder::message(sprintf( + 'Method %s::%s() has no return type specified.', + $methodReflection->getDeclaringClass()->getDisplayName(), + $methodReflection->getName(), + ))->identifier('missingType.return')->build(), ]; } $messages = []; foreach ($this->missingTypehintCheck->getIterableTypesWithMissingValueTypehint($returnType) as $iterableType) { $iterableTypeDescription = $iterableType->describe(VerbosityLevel::typeOnly()); - $messages[] = RuleErrorBuilder::message(sprintf('Method %s::%s() return type has no value type specified in iterable type %s.', $methodReflection->getDeclaringClass()->getDisplayName(), $methodReflection->getName(), $iterableTypeDescription)) + $messages[] = RuleErrorBuilder::message(sprintf( + 'Method %s::%s() return type has no value type specified in iterable type %s.', + $methodReflection->getDeclaringClass()->getDisplayName(), + $methodReflection->getName(), + $iterableTypeDescription, + )) ->tip(MissingTypehintCheck::MISSING_ITERABLE_VALUE_TYPE_TIP) ->identifier('missingType.iterableValue') ->build(); } foreach ($this->missingTypehintCheck->getNonGenericObjectTypesWithGenericClass($returnType) as [$name, $genericTypeNames]) { - $messages[] = RuleErrorBuilder::message(sprintf('Method %s::%s() return type with generic %s does not specify its types: %s', $methodReflection->getDeclaringClass()->getDisplayName(), $methodReflection->getName(), $name, implode(', ', $genericTypeNames))) + $messages[] = RuleErrorBuilder::message(sprintf( + 'Method %s::%s() return type with generic %s does not specify its types: %s', + $methodReflection->getDeclaringClass()->getDisplayName(), + $methodReflection->getName(), + $name, + implode(', ', $genericTypeNames), + )) ->tip(MissingTypehintCheck::TURN_OFF_NON_GENERIC_CHECK_TIP) ->identifier('missingType.generics') ->build(); } foreach ($this->missingTypehintCheck->getCallablesWithMissingSignature($returnType) as $callableType) { - $messages[] = RuleErrorBuilder::message(sprintf('Method %s::%s() return type has no signature specified for %s.', $methodReflection->getDeclaringClass()->getDisplayName(), $methodReflection->getName(), $callableType->describe(VerbosityLevel::typeOnly())))->identifier('missingType.callable')->build(); + $messages[] = RuleErrorBuilder::message(sprintf( + 'Method %s::%s() return type has no signature specified for %s.', + $methodReflection->getDeclaringClass()->getDisplayName(), + $methodReflection->getName(), + $callableType->describe(VerbosityLevel::typeOnly()), + ))->identifier('missingType.callable')->build(); } return $messages; diff --git a/src/Rules/Methods/OverridingMethodRule.php b/src/Rules/Methods/OverridingMethodRule.php index ed7e2457d91..17c4f09990a 100644 --- a/src/Rules/Methods/OverridingMethodRule.php +++ b/src/Rules/Methods/OverridingMethodRule.php @@ -32,49 +32,19 @@ class OverridingMethodRule implements Rule { - /** - * @var PhpVersion - */ - private $phpVersion; - /** - * @var MethodSignatureRule - */ - private $methodSignatureRule; - /** - * @var bool - */ - private $checkPhpDocMethodSignatures; - /** - * @var MethodParameterComparisonHelper - */ - private $methodParameterComparisonHelper; - /** - * @var PhpClassReflectionExtension - */ - private $phpClassReflectionExtension; - /** - * @var bool - */ - private $genericPrototypeMessage; - /** - * @var bool - */ - private $finalByPhpDoc; - /** - * @var bool - */ - private $checkMissingOverrideMethodAttribute; - public function __construct(PhpVersion $phpVersion, MethodSignatureRule $methodSignatureRule, bool $checkPhpDocMethodSignatures, MethodParameterComparisonHelper $methodParameterComparisonHelper, PhpClassReflectionExtension $phpClassReflectionExtension, bool $genericPrototypeMessage, bool $finalByPhpDoc, bool $checkMissingOverrideMethodAttribute) + public function __construct( + private PhpVersion $phpVersion, + private MethodSignatureRule $methodSignatureRule, + private bool $checkPhpDocMethodSignatures, + private MethodParameterComparisonHelper $methodParameterComparisonHelper, + private PhpClassReflectionExtension $phpClassReflectionExtension, + private bool $genericPrototypeMessage, + private bool $finalByPhpDoc, + private bool $checkMissingOverrideMethodAttribute, + ) { - $this->phpVersion = $phpVersion; - $this->methodSignatureRule = $methodSignatureRule; - $this->checkPhpDocMethodSignatures = $checkPhpDocMethodSignatures; - $this->methodParameterComparisonHelper = $methodParameterComparisonHelper; - $this->phpClassReflectionExtension = $phpClassReflectionExtension; - $this->genericPrototypeMessage = $genericPrototypeMessage; - $this->finalByPhpDoc = $finalByPhpDoc; - $this->checkMissingOverrideMethodAttribute = $checkMissingOverrideMethodAttribute; } + public function getNodeType(): string { return InClassMethodNode::class; @@ -91,7 +61,13 @@ public function processNode(Node $node, Scope $scope): array $parentConstructor = $parent->getConstructor(); if ($parentConstructor->isFinalByKeyword()->yes()) { return $this->addErrors([ - RuleErrorBuilder::message(sprintf('Method %s::%s() overrides final method %s::%s().', $method->getDeclaringClass()->getDisplayName(), $method->getName(), $parent->getDisplayName($this->genericPrototypeMessage), $parentConstructor->getName())) + RuleErrorBuilder::message(sprintf( + 'Method %s::%s() overrides final method %s::%s().', + $method->getDeclaringClass()->getDisplayName(), + $method->getName(), + $parent->getDisplayName($this->genericPrototypeMessage), + $parentConstructor->getName(), + )) ->nonIgnorable() ->identifier('method.parentMethodFinal') ->build(), @@ -99,7 +75,13 @@ public function processNode(Node $node, Scope $scope): array } if ($parentConstructor->isFinal()->yes() && $this->finalByPhpDoc) { return $this->addErrors([ - RuleErrorBuilder::message(sprintf('Method %s::%s() overrides @final method %s::%s().', $method->getDeclaringClass()->getDisplayName(), $method->getName(), $parent->getDisplayName($this->genericPrototypeMessage), $parentConstructor->getName()))->identifier('method.parentMethodFinalByPhpDoc') + RuleErrorBuilder::message(sprintf( + 'Method %s::%s() overrides @final method %s::%s().', + $method->getDeclaringClass()->getDisplayName(), + $method->getName(), + $parent->getDisplayName($this->genericPrototypeMessage), + $parentConstructor->getName(), + ))->identifier('method.parentMethodFinalByPhpDoc') ->build(), ], $node, $scope); } @@ -108,7 +90,11 @@ public function processNode(Node $node, Scope $scope): array if ($this->phpVersion->supportsOverrideAttribute() && $this->hasOverrideAttribute($node->getOriginalNode())) { return [ - RuleErrorBuilder::message(sprintf('Method %s::%s() has #[\Override] attribute but does not override any method.', $method->getDeclaringClass()->getDisplayName(), $method->getName())) + RuleErrorBuilder::message(sprintf( + 'Method %s::%s() has #[\Override] attribute but does not override any method.', + $method->getDeclaringClass()->getDisplayName(), + $method->getName(), + )) ->nonIgnorable() ->identifier('method.override') ->build(), @@ -126,27 +112,57 @@ public function processNode(Node $node, Scope $scope): array && $this->checkMissingOverrideMethodAttribute && !$this->hasOverrideAttribute($node->getOriginalNode()) ) { - $messages[] = RuleErrorBuilder::message(sprintf('Method %s::%s() overrides method %s::%s() but is missing the #[\Override] attribute.', $method->getDeclaringClass()->getDisplayName(), $method->getName(), $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), $prototype->getName()))->identifier('method.missingOverride')->build(); + $messages[] = RuleErrorBuilder::message(sprintf( + 'Method %s::%s() overrides method %s::%s() but is missing the #[\Override] attribute.', + $method->getDeclaringClass()->getDisplayName(), + $method->getName(), + $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), + $prototype->getName(), + ))->identifier('method.missingOverride')->build(); } if ($prototype->isFinalByKeyword()->yes()) { - $messages[] = RuleErrorBuilder::message(sprintf('Method %s::%s() overrides final method %s::%s().', $method->getDeclaringClass()->getDisplayName(), $method->getName(), $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), $prototype->getName())) + $messages[] = RuleErrorBuilder::message(sprintf( + 'Method %s::%s() overrides final method %s::%s().', + $method->getDeclaringClass()->getDisplayName(), + $method->getName(), + $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), + $prototype->getName(), + )) ->nonIgnorable() ->identifier('method.parentMethodFinal') ->build(); } elseif ($prototype->isFinal()->yes() && $this->finalByPhpDoc) { - $messages[] = RuleErrorBuilder::message(sprintf('Method %s::%s() overrides @final method %s::%s().', $method->getDeclaringClass()->getDisplayName(), $method->getName(), $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), $prototype->getName()))->identifier('method.parentMethodFinalByPhpDoc') + $messages[] = RuleErrorBuilder::message(sprintf( + 'Method %s::%s() overrides @final method %s::%s().', + $method->getDeclaringClass()->getDisplayName(), + $method->getName(), + $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), + $prototype->getName(), + ))->identifier('method.parentMethodFinalByPhpDoc') ->build(); } if ($prototype->isStatic()) { if (!$method->isStatic()) { - $messages[] = RuleErrorBuilder::message(sprintf('Non-static method %s::%s() overrides static method %s::%s().', $method->getDeclaringClass()->getDisplayName(), $method->getName(), $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), $prototype->getName())) + $messages[] = RuleErrorBuilder::message(sprintf( + 'Non-static method %s::%s() overrides static method %s::%s().', + $method->getDeclaringClass()->getDisplayName(), + $method->getName(), + $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), + $prototype->getName(), + )) ->nonIgnorable() ->identifier('method.nonStatic') ->build(); } } elseif ($method->isStatic()) { - $messages[] = RuleErrorBuilder::message(sprintf('Static method %s::%s() overrides non-static method %s::%s().', $method->getDeclaringClass()->getDisplayName(), $method->getName(), $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), $prototype->getName())) + $messages[] = RuleErrorBuilder::message(sprintf( + 'Static method %s::%s() overrides non-static method %s::%s().', + $method->getDeclaringClass()->getDisplayName(), + $method->getName(), + $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), + $prototype->getName(), + )) ->nonIgnorable() ->identifier('method.static') ->build(); @@ -155,13 +171,26 @@ public function processNode(Node $node, Scope $scope): array if ($checkVisibility) { if ($prototype->isPublic()) { if (!$method->isPublic()) { - $messages[] = RuleErrorBuilder::message(sprintf('%s method %s::%s() overriding public method %s::%s() should also be public.', $method->isPrivate() ? 'Private' : 'Protected', $method->getDeclaringClass()->getDisplayName(), $method->getName(), $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), $prototype->getName())) + $messages[] = RuleErrorBuilder::message(sprintf( + '%s method %s::%s() overriding public method %s::%s() should also be public.', + $method->isPrivate() ? 'Private' : 'Protected', + $method->getDeclaringClass()->getDisplayName(), + $method->getName(), + $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), + $prototype->getName(), + )) ->nonIgnorable() ->identifier('method.visibility') ->build(); } } elseif ($method->isPrivate()) { - $messages[] = RuleErrorBuilder::message(sprintf('Private method %s::%s() overriding protected method %s::%s() should be protected or public.', $method->getDeclaringClass()->getDisplayName(), $method->getName(), $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), $prototype->getName())) + $messages[] = RuleErrorBuilder::message(sprintf( + 'Private method %s::%s() overriding protected method %s::%s() should be protected or public.', + $method->getDeclaringClass()->getDisplayName(), + $method->getName(), + $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), + $prototype->getName(), + )) ->nonIgnorable() ->identifier('method.visibility') ->build(); @@ -188,7 +217,15 @@ public function processNode(Node $node, Scope $scope): array && count($prototypeDeclaringClass->getNativeReflection()->getMethod($prototype->getName())->getAttributes('ReturnTypeWillChange')) === 0 ) { if (!$this->methodParameterComparisonHelper->isReturnTypeCompatible($realPrototype->getTentativeReturnType(), $methodVariant->getNativeReturnType(), true)) { - $messages[] = RuleErrorBuilder::message(sprintf('Return type %s of method %s::%s() is not covariant with tentative return type %s of method %s::%s().', $methodReturnType->describe(VerbosityLevel::typeOnly()), $method->getDeclaringClass()->getDisplayName(), $method->getName(), $realPrototype->getTentativeReturnType()->describe(VerbosityLevel::typeOnly()), $realPrototype->getDeclaringClass()->getDisplayName($this->genericPrototypeMessage), $realPrototype->getName())) + $messages[] = RuleErrorBuilder::message(sprintf( + 'Return type %s of method %s::%s() is not covariant with tentative return type %s of method %s::%s().', + $methodReturnType->describe(VerbosityLevel::typeOnly()), + $method->getDeclaringClass()->getDisplayName(), + $method->getName(), + $realPrototype->getTentativeReturnType()->describe(VerbosityLevel::typeOnly()), + $realPrototype->getDeclaringClass()->getDisplayName($this->genericPrototypeMessage), + $realPrototype->getName(), + )) ->tip('Make it covariant, or use the #[\ReturnTypeWillChange] attribute to temporarily suppress the error.') ->nonIgnorable() ->identifier('method.tentativeReturnType') @@ -230,12 +267,28 @@ public function processNode(Node $node, Scope $scope): array && !$this->methodParameterComparisonHelper->isReturnTypeCompatible($prototypeReturnType, $methodReturnType, $this->phpVersion->supportsReturnCovariance()) ) { if ($this->phpVersion->supportsReturnCovariance()) { - $messages[] = RuleErrorBuilder::message(sprintf('Return type %s of method %s::%s() is not covariant with return type %s of method %s::%s().', $methodReturnType->describe(VerbosityLevel::typeOnly()), $method->getDeclaringClass()->getDisplayName(), $method->getName(), $prototypeReturnType->describe(VerbosityLevel::typeOnly()), $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), $prototype->getName())) + $messages[] = RuleErrorBuilder::message(sprintf( + 'Return type %s of method %s::%s() is not covariant with return type %s of method %s::%s().', + $methodReturnType->describe(VerbosityLevel::typeOnly()), + $method->getDeclaringClass()->getDisplayName(), + $method->getName(), + $prototypeReturnType->describe(VerbosityLevel::typeOnly()), + $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), + $prototype->getName(), + )) ->nonIgnorable() ->identifier('method.childReturnType') ->build(); } else { - $messages[] = RuleErrorBuilder::message(sprintf('Return type %s of method %s::%s() is not compatible with return type %s of method %s::%s().', $methodReturnType->describe(VerbosityLevel::typeOnly()), $method->getDeclaringClass()->getDisplayName(), $method->getName(), $prototypeReturnType->describe(VerbosityLevel::typeOnly()), $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), $prototype->getName())) + $messages[] = RuleErrorBuilder::message(sprintf( + 'Return type %s of method %s::%s() is not compatible with return type %s of method %s::%s().', + $methodReturnType->describe(VerbosityLevel::typeOnly()), + $method->getDeclaringClass()->getDisplayName(), + $method->getName(), + $prototypeReturnType->describe(VerbosityLevel::typeOnly()), + $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), + $prototype->getName(), + )) ->nonIgnorable() ->identifier('method.childReturnType') ->build(); @@ -249,14 +302,20 @@ public function processNode(Node $node, Scope $scope): array * @param list $errors * @return list */ - private function addErrors(array $errors, InClassMethodNode $classMethod, Scope $scope) : array + private function addErrors( + array $errors, + InClassMethodNode $classMethod, + Scope $scope, + ): array { if (count($errors) > 0) { return $errors; } + if (!$this->checkPhpDocMethodSignatures) { return $errors; } + return $this->methodSignatureRule->processNode($classMethod, $scope); } @@ -310,7 +369,12 @@ private function findPrototype(ClassReflection $classReflection, string $methodN if ($isAbstract) { $declaringTrait = $trait->getNativeMethod($methodName)->getDeclaringClass(); return [ - $this->phpClassReflectionExtension->createUserlandMethodReflection($trait, $classReflection, new NativeBuiltinMethodReflection($methodReflection), $declaringTrait->getName()), + $this->phpClassReflectionExtension->createUserlandMethodReflection( + $trait, + $classReflection, + new NativeBuiltinMethodReflection($methodReflection), + $declaringTrait->getName(), + ), $declaringTrait, false, ]; diff --git a/src/Rules/Methods/ReturnTypeRule.php b/src/Rules/Methods/ReturnTypeRule.php index ead90128a03..d1140961a5b 100644 --- a/src/Rules/Methods/ReturnTypeRule.php +++ b/src/Rules/Methods/ReturnTypeRule.php @@ -29,13 +29,8 @@ class ReturnTypeRule implements Rule { - /** - * @var FunctionReturnTypeCheck - */ - private $returnTypeCheck; - public function __construct(FunctionReturnTypeCheck $returnTypeCheck) + public function __construct(private FunctionReturnTypeCheck $returnTypeCheck) { - $this->returnTypeCheck = $returnTypeCheck; } public function getNodeType(): string @@ -59,7 +54,33 @@ public function processNode(Node $node, Scope $scope): array } $returnType = ParametersAcceptorSelector::selectSingle($method->getVariants())->getReturnType(); - $errors = $this->returnTypeCheck->checkReturnType($scope, $returnType, $node->expr, $node, sprintf('Method %s::%s() should return %%s but empty return statement found.', $method->getDeclaringClass()->getDisplayName(), $method->getName()), sprintf('Method %s::%s() with return type void returns %%s but should not return anything.', $method->getDeclaringClass()->getDisplayName(), $method->getName()), sprintf('Method %s::%s() should return %%s but returns %%s.', $method->getDeclaringClass()->getDisplayName(), $method->getName()), sprintf('Method %s::%s() should never return but return statement found.', $method->getDeclaringClass()->getDisplayName(), $method->getName()), $method->isGenerator()); + $errors = $this->returnTypeCheck->checkReturnType( + $scope, + $returnType, + $node->expr, + $node, + sprintf( + 'Method %s::%s() should return %%s but empty return statement found.', + $method->getDeclaringClass()->getDisplayName(), + $method->getName(), + ), + sprintf( + 'Method %s::%s() with return type void returns %%s but should not return anything.', + $method->getDeclaringClass()->getDisplayName(), + $method->getName(), + ), + sprintf( + 'Method %s::%s() should return %%s but returns %%s.', + $method->getDeclaringClass()->getDisplayName(), + $method->getName(), + ), + sprintf( + 'Method %s::%s() should never return but return statement found.', + $method->getDeclaringClass()->getDisplayName(), + $method->getName(), + ), + $method->isGenerator(), + ); if ( count($errors) === 1 diff --git a/src/Rules/Methods/StaticMethodCallCheck.php b/src/Rules/Methods/StaticMethodCallCheck.php index fd5c13552a8..e970886bc05 100644 --- a/src/Rules/Methods/StaticMethodCallCheck.php +++ b/src/Rules/Methods/StaticMethodCallCheck.php @@ -34,212 +34,268 @@ class StaticMethodCallCheck { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - /** - * @var RuleLevelHelper - */ - private $ruleLevelHelper; - /** - * @var ClassCaseSensitivityCheck - */ - private $classCaseSensitivityCheck; - /** - * @var bool - */ - private $checkFunctionNameCase; - /** - * @var bool - */ - private $reportMagicMethods; - public function __construct(ReflectionProvider $reflectionProvider, RuleLevelHelper $ruleLevelHelper, ClassCaseSensitivityCheck $classCaseSensitivityCheck, bool $checkFunctionNameCase, bool $reportMagicMethods) - { - $this->reflectionProvider = $reflectionProvider; - $this->ruleLevelHelper = $ruleLevelHelper; - $this->classCaseSensitivityCheck = $classCaseSensitivityCheck; - $this->checkFunctionNameCase = $checkFunctionNameCase; - $this->reportMagicMethods = $reportMagicMethods; + + public function __construct( + private ReflectionProvider $reflectionProvider, + private RuleLevelHelper $ruleLevelHelper, + private ClassCaseSensitivityCheck $classCaseSensitivityCheck, + private bool $checkFunctionNameCase, + private bool $reportMagicMethods, + ) + { + } + + /** + * @param Name|Expr $class + * @return array{list, ExtendedMethodReflection|null} + */ + public function check( + Scope $scope, + string $methodName, + $class, + ): array + { + $errors = []; + $isAbstract = false; + if ($class instanceof Name) { + $classStringType = $scope->getType(new Expr\ClassConstFetch($class, 'class')); + if ($classStringType->hasMethod($methodName)->yes()) { + return [[], null]; + } + + $className = (string) $class; + $lowercasedClassName = strtolower($className); + if (in_array($lowercasedClassName, ['self', 'static'], true)) { + if (!$scope->isInClass()) { + return [ + [ + RuleErrorBuilder::message(sprintf( + 'Calling %s::%s() outside of class scope.', + $className, + $methodName, + ))->identifier(sprintf('outOfClass.%s', $lowercasedClassName))->build(), + ], + null, + ]; + } + $classType = $scope->resolveTypeByName($class); + } elseif ($lowercasedClassName === 'parent') { + if (!$scope->isInClass()) { + return [ + [ + RuleErrorBuilder::message(sprintf( + 'Calling %s::%s() outside of class scope.', + $className, + $methodName, + ))->identifier(sprintf('outOfClass.parent'))->build(), + ], + null, + ]; + } + $currentClassReflection = $scope->getClassReflection(); + if ($currentClassReflection->getParentClass() === null) { + return [ + [ + RuleErrorBuilder::message(sprintf( + '%s::%s() calls parent::%s() but %s does not extend any class.', + $scope->getClassReflection()->getDisplayName(), + $scope->getFunctionName(), + $methodName, + $scope->getClassReflection()->getDisplayName(), + ))->identifier('class.noParent')->build(), + ], + null, + ]; + } + + if ($scope->getFunctionName() === null) { + throw new ShouldNotHappenException(); + } + + $classType = $scope->resolveTypeByName($class); + } else { + if (!$this->reflectionProvider->hasClass($className)) { + if ($scope->isInClassExists($className)) { + return [[], null]; + } + + return [ + [ + RuleErrorBuilder::message(sprintf( + 'Call to static method %s() on an unknown class %s.', + $methodName, + $className, + ))->identifier('class.notFound')->discoveringSymbolsTip()->build(), + ], + null, + ]; + } + + $errors = $this->classCaseSensitivityCheck->checkClassNames([new ClassNameNodePair($className, $class)]); + + $classType = $scope->resolveTypeByName($class); + } + + $classReflection = $classType->getClassReflection(); + if ($classReflection !== null && $classReflection->hasNativeMethod($methodName) && $lowercasedClassName !== 'static') { + $nativeMethodReflection = $classReflection->getNativeMethod($methodName); + if ($nativeMethodReflection instanceof PhpMethodReflection || $nativeMethodReflection instanceof NativeMethodReflection) { + $isAbstract = $nativeMethodReflection->isAbstract(); + if ($isAbstract instanceof TrinaryLogic) { + $isAbstract = $isAbstract->yes(); + } + } + } + } else { + $classTypeResult = $this->ruleLevelHelper->findTypeToCheck( + $scope, + NullsafeOperatorHelper::getNullsafeShortcircuitedExprRespectingScope($scope, $class), + sprintf('Call to static method %s() on an unknown class %%s.', SprintfHelper::escapeFormatString($methodName)), + static fn (Type $type): bool => $type->canCallMethods()->yes() && $type->hasMethod($methodName)->yes(), + ); + $classType = $classTypeResult->getType(); + if ($classType instanceof ErrorType) { + return [$classTypeResult->getUnknownClassErrors(), null]; + } + } + + if ($classType instanceof GenericClassStringType) { + $classType = $classType->getGenericType(); + if (!$classType->isObject()->yes()) { + return [[], null]; + } + } elseif ($classType->isString()->yes()) { + return [[], null]; + } + + $typeForDescribe = $classType; + if ($classType instanceof ThisType) { + $typeForDescribe = $classType->getStaticObjectType(); + } + $classType = TypeCombinator::remove($classType, new StringType()); + + if (!$classType->canCallMethods()->yes()) { + return [ + array_merge($errors, [ + RuleErrorBuilder::message(sprintf( + 'Cannot call static method %s() on %s.', + $methodName, + $typeForDescribe->describe(VerbosityLevel::typeOnly()), + ))->identifier('staticMethod.nonObject')->build(), + ]), + null, + ]; + } + + if (!$classType->hasMethod($methodName)->yes()) { + if (!$this->reportMagicMethods) { + foreach ($classType->getObjectClassNames() as $className) { + if (!$this->reflectionProvider->hasClass($className)) { + continue; + } + + $classReflection = $this->reflectionProvider->getClass($className); + if ($classReflection->hasNativeMethod('__callStatic')) { + return [[], null]; + } } - /** - * @param Name|Expr $class - * @return array{list, ExtendedMethodReflection|null} - */ - public function check(Scope $scope, string $methodName, $class) : array - { - $errors = []; - $isAbstract = false; - if ($class instanceof Name) { - $classStringType = $scope->getType(new Expr\ClassConstFetch($class, 'class')); - if ($classStringType->hasMethod($methodName)->yes()) { - return [[], null]; - } - - $className = (string) $class; - $lowercasedClassName = strtolower($className); - if (in_array($lowercasedClassName, ['self', 'static'], true)) { - if (!$scope->isInClass()) { - return [ - [ - RuleErrorBuilder::message(sprintf('Calling %s::%s() outside of class scope.', $className, $methodName))->identifier(sprintf('outOfClass.%s', $lowercasedClassName))->build(), - ], - null, - ]; - } - $classType = $scope->resolveTypeByName($class); - } elseif ($lowercasedClassName === 'parent') { - if (!$scope->isInClass()) { - return [ - [ - RuleErrorBuilder::message(sprintf('Calling %s::%s() outside of class scope.', $className, $methodName))->identifier(sprintf('outOfClass.parent'))->build(), - ], - null, - ]; - } - $currentClassReflection = $scope->getClassReflection(); - if ($currentClassReflection->getParentClass() === null) { - return [ - [ - RuleErrorBuilder::message(sprintf('%s::%s() calls parent::%s() but %s does not extend any class.', $scope->getClassReflection()->getDisplayName(), $scope->getFunctionName(), $methodName, $scope->getClassReflection()->getDisplayName()))->identifier('class.noParent')->build(), - ], - null, - ]; - } - - if ($scope->getFunctionName() === null) { - throw new ShouldNotHappenException(); - } - - $classType = $scope->resolveTypeByName($class); - } else { - if (!$this->reflectionProvider->hasClass($className)) { - if ($scope->isInClassExists($className)) { - return [[], null]; - } - - return [ - [ - RuleErrorBuilder::message(sprintf('Call to static method %s() on an unknown class %s.', $methodName, $className))->identifier('class.notFound')->discoveringSymbolsTip()->build(), - ], - null, - ]; - } - - $errors = $this->classCaseSensitivityCheck->checkClassNames([new ClassNameNodePair($className, $class)]); - - $classType = $scope->resolveTypeByName($class); - } - - $classReflection = $classType->getClassReflection(); - if ($classReflection !== null && $classReflection->hasNativeMethod($methodName) && $lowercasedClassName !== 'static') { - $nativeMethodReflection = $classReflection->getNativeMethod($methodName); - if ($nativeMethodReflection instanceof PhpMethodReflection || $nativeMethodReflection instanceof NativeMethodReflection) { - $isAbstract = $nativeMethodReflection->isAbstract(); - if ($isAbstract instanceof TrinaryLogic) { - $isAbstract = $isAbstract->yes(); - } - } - } - } else { - $classTypeResult = $this->ruleLevelHelper->findTypeToCheck($scope, NullsafeOperatorHelper::getNullsafeShortcircuitedExprRespectingScope($scope, $class), sprintf('Call to static method %s() on an unknown class %%s.', SprintfHelper::escapeFormatString($methodName)), static function (Type $type) use($methodName) : bool { - return $type->canCallMethods()->yes() && $type->hasMethod($methodName)->yes(); - }); - $classType = $classTypeResult->getType(); - if ($classType instanceof ErrorType) { - return [$classTypeResult->getUnknownClassErrors(), null]; - } - } - if ($classType instanceof GenericClassStringType) { - $classType = $classType->getGenericType(); - if (!$classType->isObject()->yes()) { - return [[], null]; - } - } elseif ($classType->isString()->yes()) { - return [[], null]; - } - $typeForDescribe = $classType; - if ($classType instanceof ThisType) { - $typeForDescribe = $classType->getStaticObjectType(); - } - $classType = TypeCombinator::remove($classType, new StringType()); - if (!$classType->canCallMethods()->yes()) { - return [ - array_merge($errors, [ - RuleErrorBuilder::message(sprintf('Cannot call static method %s() on %s.', $methodName, $typeForDescribe->describe(VerbosityLevel::typeOnly())))->identifier('staticMethod.nonObject')->build(), - ]), - null, - ]; - } - if (!$classType->hasMethod($methodName)->yes()) { - if (!$this->reportMagicMethods) { - foreach ($classType->getObjectClassNames() as $className) { - if (!$this->reflectionProvider->hasClass($className)) { - continue; - } - - $classReflection = $this->reflectionProvider->getClass($className); - if ($classReflection->hasNativeMethod('__callStatic')) { - return [[], null]; - } - } - } - - return [ - array_merge($errors, [ - RuleErrorBuilder::message(sprintf('Call to an undefined static method %s::%s().', $typeForDescribe->describe(VerbosityLevel::typeOnly()), $methodName))->identifier('staticMethod.notFound')->build(), - ]), - null, - ]; - } - $method = $classType->getMethod($methodName, $scope); - if (!$method->isStatic()) { - $function = $scope->getFunction(); - - $scopeIsInMethodClassOrSubClass = TrinaryLogic::createFromBoolean($scope->isInClass())->lazyAnd($classType->getObjectClassNames(), static function (string $objectClassName) use($scope) { - return TrinaryLogic::createFromBoolean($scope->isInClass() - && ($scope->getClassReflection()->getName() === $objectClassName || $scope->getClassReflection()->isSubclassOf($objectClassName))); - }); - if ( - !$function instanceof MethodReflection - || $function->isStatic() - || $scopeIsInMethodClassOrSubClass->no() - ) { - // per php-src docs, this method can be called statically, even if declared non-static - if (strtolower($method->getName()) === 'loadhtml' && $method->getDeclaringClass()->getName() === DOMDocument::class) { - return [[], null]; - } - - return [ - array_merge($errors, [ - RuleErrorBuilder::message(sprintf('Static call to instance method %s::%s().', $method->getDeclaringClass()->getDisplayName(), $method->getName()))->identifier('method.staticCall')->build(), - ]), - $method, - ]; - } - } - if (!$scope->canCallMethod($method)) { - $errors = array_merge($errors, [ - RuleErrorBuilder::message(sprintf('Call to %s %s %s() of class %s.', $method->isPrivate() ? 'private' : 'protected', $method->isStatic() ? 'static method' : 'method', $method->getName(), $method->getDeclaringClass()->getDisplayName())) - ->identifier(sprintf('staticMethod.%s', $method->isPrivate() ? 'private' : 'protected')) - ->build(), - ]); - } - if ($isAbstract) { - return [ - [ - RuleErrorBuilder::message(sprintf('Cannot call abstract%s method %s::%s().', $method->isStatic() ? ' static' : '', $method->getDeclaringClass()->getDisplayName(), $method->getName()))->identifier(sprintf('%s.callToAbstract', $method->isStatic() ? 'staticMethod' : 'method'))->build(), - ], - $method, - ]; - } - $lowercasedMethodName = SprintfHelper::escapeFormatString(sprintf('%s %s', $method->isStatic() ? 'static method' : 'method', $method->getDeclaringClass()->getDisplayName() . '::' . $method->getName() . '()')); - if ( - $this->checkFunctionNameCase - && $method->getName() !== $methodName - ) { - $errors[] = RuleErrorBuilder::message(sprintf('Call to %s with incorrect case: %s', $lowercasedMethodName, $methodName))->identifier('staticMethod.nameCase')->build(); - } - return [$errors, $method]; + } + + return [ + array_merge($errors, [ + RuleErrorBuilder::message(sprintf( + 'Call to an undefined static method %s::%s().', + $typeForDescribe->describe(VerbosityLevel::typeOnly()), + $methodName, + ))->identifier('staticMethod.notFound')->build(), + ]), + null, + ]; + } + + $method = $classType->getMethod($methodName, $scope); + if (!$method->isStatic()) { + $function = $scope->getFunction(); + + $scopeIsInMethodClassOrSubClass = TrinaryLogic::createFromBoolean($scope->isInClass())->lazyAnd( + $classType->getObjectClassNames(), + static fn (string $objectClassName) => TrinaryLogic::createFromBoolean( + $scope->isInClass() + && ($scope->getClassReflection()->getName() === $objectClassName || $scope->getClassReflection()->isSubclassOf($objectClassName)), + ), + ); + if ( + !$function instanceof MethodReflection + || $function->isStatic() + || $scopeIsInMethodClassOrSubClass->no() + ) { + // per php-src docs, this method can be called statically, even if declared non-static + if (strtolower($method->getName()) === 'loadhtml' && $method->getDeclaringClass()->getName() === DOMDocument::class) { + return [[], null]; } + + return [ + array_merge($errors, [ + RuleErrorBuilder::message(sprintf( + 'Static call to instance method %s::%s().', + $method->getDeclaringClass()->getDisplayName(), + $method->getName(), + ))->identifier('method.staticCall')->build(), + ]), + $method, + ]; + } + } + + if (!$scope->canCallMethod($method)) { + $errors = array_merge($errors, [ + RuleErrorBuilder::message(sprintf( + 'Call to %s %s %s() of class %s.', + $method->isPrivate() ? 'private' : 'protected', + $method->isStatic() ? 'static method' : 'method', + $method->getName(), + $method->getDeclaringClass()->getDisplayName(), + )) + ->identifier(sprintf('staticMethod.%s', $method->isPrivate() ? 'private' : 'protected')) + ->build(), + ]); + } + + if ($isAbstract) { + return [ + [ + RuleErrorBuilder::message(sprintf( + 'Cannot call abstract%s method %s::%s().', + $method->isStatic() ? ' static' : '', + $method->getDeclaringClass()->getDisplayName(), + $method->getName(), + ))->identifier(sprintf( + '%s.callToAbstract', + $method->isStatic() ? 'staticMethod' : 'method', + ))->build(), + ], + $method, + ]; + } + + $lowercasedMethodName = SprintfHelper::escapeFormatString(sprintf( + '%s %s', + $method->isStatic() ? 'static method' : 'method', + $method->getDeclaringClass()->getDisplayName() . '::' . $method->getName() . '()', + )); + + if ( + $this->checkFunctionNameCase + && $method->getName() !== $methodName + ) { + $errors[] = RuleErrorBuilder::message(sprintf( + 'Call to %s with incorrect case: %s', + $lowercasedMethodName, + $methodName, + ))->identifier('staticMethod.nameCase')->build(); + } + + return [$errors, $method]; + } + } diff --git a/src/Rules/Methods/StaticMethodCallableRule.php b/src/Rules/Methods/StaticMethodCallableRule.php index 7c713386f88..a9bae8d9d55 100644 --- a/src/Rules/Methods/StaticMethodCallableRule.php +++ b/src/Rules/Methods/StaticMethodCallableRule.php @@ -17,18 +17,8 @@ class StaticMethodCallableRule implements Rule { - /** - * @var StaticMethodCallCheck - */ - private $methodCallCheck; - /** - * @var PhpVersion - */ - private $phpVersion; - public function __construct(StaticMethodCallCheck $methodCallCheck, PhpVersion $phpVersion) + public function __construct(private StaticMethodCallCheck $methodCallCheck, private PhpVersion $phpVersion) { - $this->methodCallCheck = $methodCallCheck; - $this->phpVersion = $phpVersion; } public function getNodeType(): string diff --git a/src/Rules/Missing/MissingReturnRule.php b/src/Rules/Missing/MissingReturnRule.php index ad09abb348a..71102e4f235 100644 --- a/src/Rules/Missing/MissingReturnRule.php +++ b/src/Rules/Missing/MissingReturnRule.php @@ -27,19 +27,13 @@ class MissingReturnRule implements Rule { - /** - * @var bool - */ - private $checkExplicitMixedMissingReturn; - /** - * @var bool - */ - private $checkPhpDocMissingReturn; - public function __construct(bool $checkExplicitMixedMissingReturn, bool $checkPhpDocMissingReturn) + public function __construct( + private bool $checkExplicitMixedMissingReturn, + private bool $checkPhpDocMissingReturn, + ) { - $this->checkExplicitMixedMissingReturn = $checkExplicitMixedMissingReturn; - $this->checkPhpDocMissingReturn = $checkPhpDocMissingReturn; } + public function getNodeType(): string { return ExecutionEndNode::class; @@ -88,7 +82,9 @@ public function processNode(Node $node, Scope $scope): array } if (!$returnType instanceof MixedType) { return [ - RuleErrorBuilder::message(sprintf('%s should return %s but return statement is missing.', $description, $returnType->describe(VerbosityLevel::typeOnly()))) + RuleErrorBuilder::message( + sprintf('%s should return %s but return statement is missing.', $description, $returnType->describe(VerbosityLevel::typeOnly())), + ) ->line($node->getNode()->getStartLine()) ->identifier('return.missing') ->build(), @@ -133,7 +129,9 @@ public function processNode(Node $node, Scope $scope): array return []; } - $errorBuilder = RuleErrorBuilder::message(sprintf('%s should return %s but return statement is missing.', $description, $returnType->describe(VerbosityLevel::typeOnly())))->line($node->getNode()->getStartLine()); + $errorBuilder = RuleErrorBuilder::message( + sprintf('%s should return %s but return statement is missing.', $description, $returnType->describe(VerbosityLevel::typeOnly())), + )->line($node->getNode()->getStartLine()); if ($node->hasNativeReturnTypehint()) { $errorBuilder->nonIgnorable(); diff --git a/src/Rules/MissingTypehintCheck.php b/src/Rules/MissingTypehintCheck.php index cd8d5ca68b6..489ed146997 100644 --- a/src/Rules/MissingTypehintCheck.php +++ b/src/Rules/MissingTypehintCheck.php @@ -29,26 +29,6 @@ class MissingTypehintCheck { - /** - * @var bool - */ - private $disableCheckMissingIterableValueType; - /** - * @var bool - */ - private $checkMissingIterableValueType; - /** - * @var bool - */ - private $checkGenericClassInNonGenericObjectType; - /** - * @var bool - */ - private $checkMissingCallableSignature; - /** - * @var string[] - */ - private $skipCheckGenericClasses; public const MISSING_ITERABLE_VALUE_TYPE_TIP = 'See: https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type'; public const TURN_OFF_NON_GENERIC_CHECK_TIP = 'You can turn this off by setting checkGenericClassInNonGenericObjectType: false in your %configurationFile%.'; @@ -63,13 +43,14 @@ class MissingTypehintCheck /** * @param string[] $skipCheckGenericClasses */ - public function __construct(bool $disableCheckMissingIterableValueType, bool $checkMissingIterableValueType, bool $checkGenericClassInNonGenericObjectType, bool $checkMissingCallableSignature, array $skipCheckGenericClasses) + public function __construct( + private bool $disableCheckMissingIterableValueType, + private bool $checkMissingIterableValueType, + private bool $checkGenericClassInNonGenericObjectType, + private bool $checkMissingCallableSignature, + private array $skipCheckGenericClasses, + ) { - $this->disableCheckMissingIterableValueType = $disableCheckMissingIterableValueType; - $this->checkMissingIterableValueType = $checkMissingIterableValueType; - $this->checkGenericClassInNonGenericObjectType = $checkGenericClassInNonGenericObjectType; - $this->checkMissingCallableSignature = $checkMissingCallableSignature; - $this->skipCheckGenericClasses = $skipCheckGenericClasses; } /** @@ -92,7 +73,11 @@ public function getIterableTypesWithMissingValueTypehint(Type $type): array return $type; } if ($type instanceof ConditionalType || $type instanceof ConditionalTypeForParameter) { - $iterablesWithMissingValueTypehint = array_merge($iterablesWithMissingValueTypehint, $this->getIterableTypesWithMissingValueTypehint($type->getIf()), $this->getIterableTypesWithMissingValueTypehint($type->getElse())); + $iterablesWithMissingValueTypehint = array_merge( + $iterablesWithMissingValueTypehint, + $this->getIterableTypesWithMissingValueTypehint($type->getIf()), + $this->getIterableTypesWithMissingValueTypehint($type->getElse()), + ); return $type; } diff --git a/src/Rules/Names/UsedNamesRule.php b/src/Rules/Names/UsedNamesRule.php index d3c8bc3e71a..a1afbb742b5 100644 --- a/src/Rules/Names/UsedNamesRule.php +++ b/src/Rules/Names/UsedNamesRule.php @@ -94,7 +94,11 @@ private function findErrorsForNode(Node $node, string $namespace, array &$usedNa $name = $node->name->toLowerString(); if (in_array($name, $usedNames[$lowerNamespace] ?? [], true)) { return [ - RuleErrorBuilder::message(sprintf('Cannot declare %s %s because the name is already in use.', $type, $namespace !== '' ? $namespace . '\\' . $node->name->toString() : $node->name->toString())) + RuleErrorBuilder::message(sprintf( + 'Cannot declare %s %s because the name is already in use.', + $type, + $namespace !== '' ? $namespace . '\\' . $node->name->toString() : $node->name->toString(), + )) ->identifier(sprintf('%s.nameInUse', $type)) ->line($node->getLine()) ->nonIgnorable() @@ -122,7 +126,11 @@ private function findErrorsInUses(array $uses, string $useGroupPrefix, string $l } $useAlias = $use->getAlias()->toLowerString(); if (in_array($useAlias, $usedNames[$lowerNamespace] ?? [], true)) { - $errors[] = RuleErrorBuilder::message(sprintf('Cannot use %s as %s because the name is already in use.', $useGroupPrefix !== '' ? $useGroupPrefix . '\\' . $use->name->toString() : $use->name->toString(), $use->getAlias()->toString())) + $errors[] = RuleErrorBuilder::message(sprintf( + 'Cannot use %s as %s because the name is already in use.', + $useGroupPrefix !== '' ? $useGroupPrefix . '\\' . $use->name->toString() : $use->name->toString(), + $use->getAlias()->toString(), + )) ->identifier('use.nameInUse') ->line($use->getLine()) ->nonIgnorable() @@ -134,10 +142,7 @@ private function findErrorsInUses(array $uses, string $useGroupPrefix, string $l return $errors; } - /** - * @param Use_|GroupUse|UseUse $use - */ - private function shouldBeIgnored($use): bool + private function shouldBeIgnored(Use_|GroupUse|UseUse $use): bool { return in_array($use->type, [Use_::TYPE_FUNCTION, Use_::TYPE_CONSTANT], true); } diff --git a/src/Rules/Namespaces/ExistingNamesInGroupUseRule.php b/src/Rules/Namespaces/ExistingNamesInGroupUseRule.php index c0c02bc598d..a05be7c5cc9 100644 --- a/src/Rules/Namespaces/ExistingNamesInGroupUseRule.php +++ b/src/Rules/Namespaces/ExistingNamesInGroupUseRule.php @@ -22,24 +22,14 @@ class ExistingNamesInGroupUseRule implements Rule { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - /** - * @var ClassCaseSensitivityCheck - */ - private $classCaseSensitivityCheck; - /** - * @var bool - */ - private $checkFunctionNameCase; - public function __construct(ReflectionProvider $reflectionProvider, ClassCaseSensitivityCheck $classCaseSensitivityCheck, bool $checkFunctionNameCase) + public function __construct( + private ReflectionProvider $reflectionProvider, + private ClassCaseSensitivityCheck $classCaseSensitivityCheck, + private bool $checkFunctionNameCase, + ) { - $this->reflectionProvider = $reflectionProvider; - $this->classCaseSensitivityCheck = $classCaseSensitivityCheck; - $this->checkFunctionNameCase = $checkFunctionNameCase; } + public function getNodeType(): string { return Node\Stmt\GroupUse::class; @@ -110,7 +100,11 @@ private function checkFunction(Node\Name $name): ?IdentifierRuleError strtolower($realName) === strtolower($usedName) && $realName !== $usedName ) { - return RuleErrorBuilder::message(sprintf('Function %s used with incorrect case: %s.', $realName, $usedName)) + return RuleErrorBuilder::message(sprintf( + 'Function %s used with incorrect case: %s.', + $realName, + $usedName, + )) ->line($name->getStartLine()) ->identifier('function.nameCase') ->build(); diff --git a/src/Rules/Namespaces/ExistingNamesInUseRule.php b/src/Rules/Namespaces/ExistingNamesInUseRule.php index 5f616c77ccd..104ad6d21eb 100644 --- a/src/Rules/Namespaces/ExistingNamesInUseRule.php +++ b/src/Rules/Namespaces/ExistingNamesInUseRule.php @@ -21,24 +21,14 @@ class ExistingNamesInUseRule implements Rule { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - /** - * @var ClassCaseSensitivityCheck - */ - private $classCaseSensitivityCheck; - /** - * @var bool - */ - private $checkFunctionNameCase; - public function __construct(ReflectionProvider $reflectionProvider, ClassCaseSensitivityCheck $classCaseSensitivityCheck, bool $checkFunctionNameCase) + public function __construct( + private ReflectionProvider $reflectionProvider, + private ClassCaseSensitivityCheck $classCaseSensitivityCheck, + private bool $checkFunctionNameCase, + ) { - $this->reflectionProvider = $reflectionProvider; - $this->classCaseSensitivityCheck = $classCaseSensitivityCheck; - $this->checkFunctionNameCase = $checkFunctionNameCase; } + public function getNodeType(): string { return Node\Stmt\Use_::class; @@ -111,7 +101,11 @@ private function checkFunctions(array $uses): array strtolower($realName) === strtolower($usedName) && $realName !== $usedName ) { - $errors[] = RuleErrorBuilder::message(sprintf('Function %s used with incorrect case: %s.', $realName, $usedName)) + $errors[] = RuleErrorBuilder::message(sprintf( + 'Function %s used with incorrect case: %s.', + $realName, + $usedName, + )) ->line($use->name->getStartLine()) ->identifier('function.nameCase') ->build(); @@ -128,9 +122,9 @@ private function checkFunctions(array $uses): array */ private function checkClasses(array $uses): array { - return $this->classCaseSensitivityCheck->checkClassNames(array_map(static function (Node\Stmt\UseUse $use) : ClassNameNodePair { - return new ClassNameNodePair((string) $use->name, $use->name); - }, $uses)); + return $this->classCaseSensitivityCheck->checkClassNames( + array_map(static fn (Node\Stmt\UseUse $use): ClassNameNodePair => new ClassNameNodePair((string) $use->name, $use->name), $uses), + ); } } diff --git a/src/Rules/Operators/InvalidAssignVarRule.php b/src/Rules/Operators/InvalidAssignVarRule.php index 175c5f0f228..4f6e564849f 100644 --- a/src/Rules/Operators/InvalidAssignVarRule.php +++ b/src/Rules/Operators/InvalidAssignVarRule.php @@ -18,13 +18,8 @@ class InvalidAssignVarRule implements Rule { - /** - * @var NullsafeCheck - */ - private $nullsafeCheck; - public function __construct(NullsafeCheck $nullsafeCheck) + public function __construct(private NullsafeCheck $nullsafeCheck) { - $this->nullsafeCheck = $nullsafeCheck; } public function getNodeType(): string diff --git a/src/Rules/Operators/InvalidBinaryOperationRule.php b/src/Rules/Operators/InvalidBinaryOperationRule.php index 484ec281700..4fb2167030c 100644 --- a/src/Rules/Operators/InvalidBinaryOperationRule.php +++ b/src/Rules/Operators/InvalidBinaryOperationRule.php @@ -23,19 +23,13 @@ class InvalidBinaryOperationRule implements Rule { - /** - * @var ExprPrinter - */ - private $exprPrinter; - /** - * @var RuleLevelHelper - */ - private $ruleLevelHelper; - public function __construct(ExprPrinter $exprPrinter, RuleLevelHelper $ruleLevelHelper) + public function __construct( + private ExprPrinter $exprPrinter, + private RuleLevelHelper $ruleLevelHelper, + ) { - $this->exprPrinter = $exprPrinter; - $this->ruleLevelHelper = $ruleLevelHelper; } + public function getNodeType(): string { return Node\Expr::class; @@ -74,21 +68,27 @@ public function processNode(Node $node, Scope $scope): array } if ($node instanceof Node\Expr\AssignOp\Concat || $node instanceof Node\Expr\BinaryOp\Concat) { - $callback = static function (Type $type) : bool { - return !$type->toString() instanceof ErrorType; - }; + $callback = static fn (Type $type): bool => !$type->toString() instanceof ErrorType; } else { - $callback = static function (Type $type) : bool { - return !$type->toNumber() instanceof ErrorType; - }; + $callback = static fn (Type $type): bool => !$type->toNumber() instanceof ErrorType; } - $leftType = $this->ruleLevelHelper->findTypeToCheck($scope, $left, '', $callback)->getType(); + $leftType = $this->ruleLevelHelper->findTypeToCheck( + $scope, + $left, + '', + $callback, + )->getType(); if ($leftType instanceof ErrorType) { return []; } - $rightType = $this->ruleLevelHelper->findTypeToCheck($scope, $right, '', $callback)->getType(); + $rightType = $this->ruleLevelHelper->findTypeToCheck( + $scope, + $right, + '', + $callback, + )->getType(); if ($rightType instanceof ErrorType) { return []; } @@ -106,7 +106,12 @@ public function processNode(Node $node, Scope $scope): array } return [ - RuleErrorBuilder::message(sprintf('Binary operation "%s" between %s and %s results in an error.', substr(substr($this->exprPrinter->printExpr($newNode), strlen($leftName) + 2), 0, -(strlen($rightName) + 2)), $scope->getType($left)->describe(VerbosityLevel::value()), $scope->getType($right)->describe(VerbosityLevel::value()))) + RuleErrorBuilder::message(sprintf( + 'Binary operation "%s" between %s and %s results in an error.', + substr(substr($this->exprPrinter->printExpr($newNode), strlen($leftName) + 2), 0, -(strlen($rightName) + 2)), + $scope->getType($left)->describe(VerbosityLevel::value()), + $scope->getType($right)->describe(VerbosityLevel::value()), + )) ->line($left->getStartLine()) ->identifier(sprintf('%s.invalid', $identifier)) ->build(), diff --git a/src/Rules/Operators/InvalidComparisonOperationRule.php b/src/Rules/Operators/InvalidComparisonOperationRule.php index 3bb58757f07..43b87605035 100644 --- a/src/Rules/Operators/InvalidComparisonOperationRule.php +++ b/src/Rules/Operators/InvalidComparisonOperationRule.php @@ -26,13 +26,8 @@ class InvalidComparisonOperationRule implements Rule { - /** - * @var RuleLevelHelper - */ - private $ruleLevelHelper; - public function __construct(RuleLevelHelper $ruleLevelHelper) + public function __construct(private RuleLevelHelper $ruleLevelHelper) { - $this->ruleLevelHelper = $ruleLevelHelper; } public function getNodeType(): string @@ -93,7 +88,12 @@ public function processNode(Node $node, Scope $scope): array } return [ - RuleErrorBuilder::message(sprintf('Comparison operation "%s" between %s and %s results in an error.', $node->getOperatorSigil(), $scope->getType($node->left)->describe(VerbosityLevel::value()), $scope->getType($node->right)->describe(VerbosityLevel::value()))) + RuleErrorBuilder::message(sprintf( + 'Comparison operation "%s" between %s and %s results in an error.', + $node->getOperatorSigil(), + $scope->getType($node->left)->describe(VerbosityLevel::value()), + $scope->getType($node->right)->describe(VerbosityLevel::value()), + )) ->line($node->left->getStartLine()) ->identifier(sprintf('%s.invalid', $nodeType)) ->build(), @@ -106,9 +106,7 @@ public function processNode(Node $node, Scope $scope): array private function isNumberType(Scope $scope, Node\Expr $expr): bool { $acceptedType = new UnionType([new IntegerType(), new FloatType()]); - $onlyNumber = static function (Type $type) use($acceptedType) : bool { - return $acceptedType->isSuperTypeOf($type)->yes(); - }; + $onlyNumber = static fn (Type $type): bool => $acceptedType->isSuperTypeOf($type)->yes(); $type = $this->ruleLevelHelper->findTypeToCheck($scope, $expr, '', $onlyNumber)->getType(); @@ -127,9 +125,12 @@ private function isPossiblyNullableObjectType(Scope $scope, Node\Expr $expr): bo { $acceptedType = new ObjectWithoutClassType(); - $type = $this->ruleLevelHelper->findTypeToCheck($scope, $expr, '', static function (Type $type) use($acceptedType) : bool { - return $acceptedType->isSuperTypeOf($type)->yes(); - })->getType(); + $type = $this->ruleLevelHelper->findTypeToCheck( + $scope, + $expr, + '', + static fn (Type $type): bool => $acceptedType->isSuperTypeOf($type)->yes(), + )->getType(); if ($type instanceof ErrorType) { return false; @@ -149,9 +150,12 @@ private function isPossiblyNullableObjectType(Scope $scope, Node\Expr $expr): bo private function isPossiblyNullableArrayType(Scope $scope, Node\Expr $expr): bool { - $type = $this->ruleLevelHelper->findTypeToCheck($scope, $expr, '', static function (Type $type) : bool { - return $type->isArray()->yes(); - })->getType(); + $type = $this->ruleLevelHelper->findTypeToCheck( + $scope, + $expr, + '', + static fn (Type $type): bool => $type->isArray()->yes(), + )->getType(); if (TypeCombinator::containsNull($type) && !$type->isNull()->yes()) { $type = TypeCombinator::removeNull($type); diff --git a/src/Rules/Operators/InvalidIncDecOperationRule.php b/src/Rules/Operators/InvalidIncDecOperationRule.php index 8aee588cf5c..b3e4a29263f 100644 --- a/src/Rules/Operators/InvalidIncDecOperationRule.php +++ b/src/Rules/Operators/InvalidIncDecOperationRule.php @@ -18,13 +18,8 @@ class InvalidIncDecOperationRule implements Rule { - /** - * @var bool - */ - private $checkThisOnly; - public function __construct(bool $checkThisOnly) + public function __construct(private bool $checkThisOnly) { - $this->checkThisOnly = $checkThisOnly; } public function getNodeType(): string @@ -69,7 +64,10 @@ public function processNode(Node $node, Scope $scope): array && !$node->var instanceof Node\Expr\StaticPropertyFetch ) { return [ - RuleErrorBuilder::message(sprintf('Cannot use %s on a non-variable.', $operatorString)) + RuleErrorBuilder::message(sprintf( + 'Cannot use %s on a non-variable.', + $operatorString, + )) ->line($node->var->getStartLine()) ->identifier(sprintf('%s.expr', $nodeType)) ->build(), @@ -86,7 +84,11 @@ public function processNode(Node $node, Scope $scope): array } return [ - RuleErrorBuilder::message(sprintf('Cannot use %s on %s.', $operatorString, $varType->describe(VerbosityLevel::value()))) + RuleErrorBuilder::message(sprintf( + 'Cannot use %s on %s.', + $operatorString, + $varType->describe(VerbosityLevel::value()), + )) ->line($node->var->getStartLine()) ->identifier(sprintf('%s.type', $nodeType)) ->build(), diff --git a/src/Rules/Operators/InvalidUnaryOperationRule.php b/src/Rules/Operators/InvalidUnaryOperationRule.php index 5d045cb566e..000b0529f24 100644 --- a/src/Rules/Operators/InvalidUnaryOperationRule.php +++ b/src/Rules/Operators/InvalidUnaryOperationRule.php @@ -41,7 +41,11 @@ public function processNode(Node $node, Scope $scope): array $operator = '~'; } return [ - RuleErrorBuilder::message(sprintf('Unary operation "%s" on %s results in an error.', $operator, $scope->getType($node->expr)->describe(VerbosityLevel::value()))) + RuleErrorBuilder::message(sprintf( + 'Unary operation "%s" on %s results in an error.', + $operator, + $scope->getType($node->expr)->describe(VerbosityLevel::value()), + )) ->line($node->expr->getStartLine()) ->identifier('unaryOp.invalid') ->build(), diff --git a/src/Rules/PhpDoc/AssertRuleHelper.php b/src/Rules/PhpDoc/AssertRuleHelper.php index 40332777a23..6026b18a310 100644 --- a/src/Rules/PhpDoc/AssertRuleHelper.php +++ b/src/Rules/PhpDoc/AssertRuleHelper.php @@ -20,20 +20,14 @@ class AssertRuleHelper { - /** - * @var InitializerExprTypeResolver - */ - private $initializerExprTypeResolver; - public function __construct(InitializerExprTypeResolver $initializerExprTypeResolver) + public function __construct(private InitializerExprTypeResolver $initializerExprTypeResolver) { - $this->initializerExprTypeResolver = $initializerExprTypeResolver; } /** * @return list - * @param ExtendedMethodReflection|FunctionReflection $reflection */ - public function check($reflection, ParametersAcceptor $acceptor): array + public function check(ExtendedMethodReflection|FunctionReflection $reflection, ParametersAcceptor $acceptor): array { $parametersByName = []; foreach ($acceptor->getParameters() as $parameter) { @@ -73,9 +67,21 @@ public function check($reflection, ParametersAcceptor $acceptor): array $assertedExprString = $assert->getParameter()->describe(); if ($assert->isNegated() ? $isSuperType->yes() : $isSuperType->no()) { - $errors[] = RuleErrorBuilder::message(sprintf('Asserted %stype %s for %s with type %s can never happen.', $assert->isNegated() ? 'negated ' : '', $assertedType->describe(VerbosityLevel::precise()), $assertedExprString, $assertedExprType->describe(VerbosityLevel::precise())))->identifier('assert.impossibleType')->build(); + $errors[] = RuleErrorBuilder::message(sprintf( + 'Asserted %stype %s for %s with type %s can never happen.', + $assert->isNegated() ? 'negated ' : '', + $assertedType->describe(VerbosityLevel::precise()), + $assertedExprString, + $assertedExprType->describe(VerbosityLevel::precise()), + ))->identifier('assert.impossibleType')->build(); } elseif ($assert->isNegated() ? $isSuperType->no() : $isSuperType->yes()) { - $errors[] = RuleErrorBuilder::message(sprintf('Asserted %stype %s for %s with type %s does not narrow down the type.', $assert->isNegated() ? 'negated ' : '', $assertedType->describe(VerbosityLevel::precise()), $assertedExprString, $assertedExprType->describe(VerbosityLevel::precise())))->identifier('assert.alreadyNarrowedType')->build(); + $errors[] = RuleErrorBuilder::message(sprintf( + 'Asserted %stype %s for %s with type %s does not narrow down the type.', + $assert->isNegated() ? 'negated ' : '', + $assertedType->describe(VerbosityLevel::precise()), + $assertedExprString, + $assertedExprType->describe(VerbosityLevel::precise()), + ))->identifier('assert.alreadyNarrowedType')->build(); } } diff --git a/src/Rules/PhpDoc/ConditionalReturnTypeRuleHelper.php b/src/Rules/PhpDoc/ConditionalReturnTypeRuleHelper.php index 7f8154d5d80..e970ba377de 100644 --- a/src/Rules/PhpDoc/ConditionalReturnTypeRuleHelper.php +++ b/src/Rules/PhpDoc/ConditionalReturnTypeRuleHelper.php @@ -89,9 +89,13 @@ public function check(ParametersAcceptor $acceptor): array $verbosity = VerbosityLevel::getRecommendedLevelByType($subjectType, $targetType); - $errors[] = RuleErrorBuilder::message(sprintf('Condition "%s" in conditional return type is always %s.', sprintf('%s %s %s', $subjectType->describe($verbosity), $conditionalType->isNegated() ? 'is not' : 'is', $targetType->describe($verbosity)), $conditionalType->isNegated() + $errors[] = RuleErrorBuilder::message(sprintf( + 'Condition "%s" in conditional return type is always %s.', + sprintf('%s %s %s', $subjectType->describe($verbosity), $conditionalType->isNegated() ? 'is not' : 'is', $targetType->describe($verbosity)), + $conditionalType->isNegated() ? ($isTargetSuperType->yes() ? 'false' : 'true') - : ($isTargetSuperType->yes() ? 'true' : 'false'))) + : ($isTargetSuperType->yes() ? 'true' : 'false'), + )) ->identifier(sprintf('conditionalType.always%s', $conditionalType->isNegated() ? ($isTargetSuperType->yes() ? 'False' : 'True') : ($isTargetSuperType->yes() ? 'True' : 'False'))) diff --git a/src/Rules/PhpDoc/FunctionAssertRule.php b/src/Rules/PhpDoc/FunctionAssertRule.php index 133a253895a..0995b7574a9 100644 --- a/src/Rules/PhpDoc/FunctionAssertRule.php +++ b/src/Rules/PhpDoc/FunctionAssertRule.php @@ -14,13 +14,8 @@ class FunctionAssertRule implements Rule { - /** - * @var AssertRuleHelper - */ - private $helper; - public function __construct(AssertRuleHelper $helper) + public function __construct(private AssertRuleHelper $helper) { - $this->helper = $helper; } public function getNodeType(): string diff --git a/src/Rules/PhpDoc/FunctionConditionalReturnTypeRule.php b/src/Rules/PhpDoc/FunctionConditionalReturnTypeRule.php index eeb9b29e92f..5610c04925e 100644 --- a/src/Rules/PhpDoc/FunctionConditionalReturnTypeRule.php +++ b/src/Rules/PhpDoc/FunctionConditionalReturnTypeRule.php @@ -14,13 +14,8 @@ class FunctionConditionalReturnTypeRule implements Rule { - /** - * @var ConditionalReturnTypeRuleHelper - */ - private $helper; - public function __construct(ConditionalReturnTypeRuleHelper $helper) + public function __construct(private ConditionalReturnTypeRuleHelper $helper) { - $this->helper = $helper; } public function getNodeType(): string diff --git a/src/Rules/PhpDoc/IncompatibleClassConstantPhpDocTypeRule.php b/src/Rules/PhpDoc/IncompatibleClassConstantPhpDocTypeRule.php index a0598e258f3..3b89aea5c3f 100644 --- a/src/Rules/PhpDoc/IncompatibleClassConstantPhpDocTypeRule.php +++ b/src/Rules/PhpDoc/IncompatibleClassConstantPhpDocTypeRule.php @@ -23,19 +23,13 @@ class IncompatibleClassConstantPhpDocTypeRule implements Rule { - /** - * @var GenericObjectTypeCheck - */ - private $genericObjectTypeCheck; - /** - * @var UnresolvableTypeHelper - */ - private $unresolvableTypeHelper; - public function __construct(GenericObjectTypeCheck $genericObjectTypeCheck, UnresolvableTypeHelper $unresolvableTypeHelper) + public function __construct( + private GenericObjectTypeCheck $genericObjectTypeCheck, + private UnresolvableTypeHelper $unresolvableTypeHelper, + ) { - $this->genericObjectTypeCheck = $genericObjectTypeCheck; - $this->unresolvableTypeHelper = $unresolvableTypeHelper; } + public function getNodeType(): string { return Node\Stmt\ClassConst::class; @@ -76,21 +70,69 @@ private function processSingleConstant(ClassReflection $classReflection, ?Type $ if ( $this->unresolvableTypeHelper->containsUnresolvableType($phpDocType) ) { - $errors[] = RuleErrorBuilder::message(sprintf('PHPDoc tag @var for constant %s::%s contains unresolvable type.', $constantReflection->getDeclaringClass()->getName(), $constantName))->identifier('classConstant.unresolvableType')->build(); + $errors[] = RuleErrorBuilder::message(sprintf( + 'PHPDoc tag @var for constant %s::%s contains unresolvable type.', + $constantReflection->getDeclaringClass()->getName(), + $constantName, + ))->identifier('classConstant.unresolvableType')->build(); } elseif ($nativeType !== null) { $isSuperType = $nativeType->isSuperTypeOf($phpDocType); if ($isSuperType->no()) { - $errors[] = RuleErrorBuilder::message(sprintf('PHPDoc tag @var for constant %s::%s with type %s is incompatible with native type %s.', $constantReflection->getDeclaringClass()->getDisplayName(), $constantName, $phpDocType->describe(VerbosityLevel::typeOnly()), $nativeType->describe(VerbosityLevel::typeOnly())))->identifier('classConstant.phpDocType')->build(); + $errors[] = RuleErrorBuilder::message(sprintf( + 'PHPDoc tag @var for constant %s::%s with type %s is incompatible with native type %s.', + $constantReflection->getDeclaringClass()->getDisplayName(), + $constantName, + $phpDocType->describe(VerbosityLevel::typeOnly()), + $nativeType->describe(VerbosityLevel::typeOnly()), + ))->identifier('classConstant.phpDocType')->build(); } elseif ($isSuperType->maybe()) { - $errors[] = RuleErrorBuilder::message(sprintf('PHPDoc tag @var for constant %s::%s with type %s is not subtype of native type %s.', $constantReflection->getDeclaringClass()->getDisplayName(), $constantName, $phpDocType->describe(VerbosityLevel::typeOnly()), $nativeType->describe(VerbosityLevel::typeOnly())))->identifier('classConstant.phpDocType')->build(); + $errors[] = RuleErrorBuilder::message(sprintf( + 'PHPDoc tag @var for constant %s::%s with type %s is not subtype of native type %s.', + $constantReflection->getDeclaringClass()->getDisplayName(), + $constantName, + $phpDocType->describe(VerbosityLevel::typeOnly()), + $nativeType->describe(VerbosityLevel::typeOnly()), + ))->identifier('classConstant.phpDocType')->build(); } } $className = SprintfHelper::escapeFormatString($constantReflection->getDeclaringClass()->getDisplayName()); $escapedConstantName = SprintfHelper::escapeFormatString($constantName); - return array_merge($errors, $this->genericObjectTypeCheck->check($phpDocType, sprintf('PHPDoc tag @var for constant %s::%s contains generic type %%s but %%s %%s is not generic.', $className, $escapedConstantName), sprintf('Generic type %%s in PHPDoc tag @var for constant %s::%s does not specify all template types of %%s %%s: %%s', $className, $escapedConstantName), sprintf('Generic type %%s in PHPDoc tag @var for constant %s::%s specifies %%d template types, but %%s %%s supports only %%d: %%s', $className, $escapedConstantName), sprintf('Type %%s in generic type %%s in PHPDoc tag @var for constant %s::%s is not subtype of template type %%s of %%s %%s.', $className, $escapedConstantName), sprintf('Call-site variance of %%s in generic type %%s in PHPDoc tag @var for constant %s::%s is in conflict with %%s template type %%s of %%s %%s.', $className, $escapedConstantName), sprintf('Call-site variance of %%s in generic type %%s in PHPDoc tag @var for constant %s::%s is redundant, template type %%s of %%s %%s has the same variance.', $className, $escapedConstantName))); + return array_merge($errors, $this->genericObjectTypeCheck->check( + $phpDocType, + sprintf( + 'PHPDoc tag @var for constant %s::%s contains generic type %%s but %%s %%s is not generic.', + $className, + $escapedConstantName, + ), + sprintf( + 'Generic type %%s in PHPDoc tag @var for constant %s::%s does not specify all template types of %%s %%s: %%s', + $className, + $escapedConstantName, + ), + sprintf( + 'Generic type %%s in PHPDoc tag @var for constant %s::%s specifies %%d template types, but %%s %%s supports only %%d: %%s', + $className, + $escapedConstantName, + ), + sprintf( + 'Type %%s in generic type %%s in PHPDoc tag @var for constant %s::%s is not subtype of template type %%s of %%s %%s.', + $className, + $escapedConstantName, + ), + sprintf( + 'Call-site variance of %%s in generic type %%s in PHPDoc tag @var for constant %s::%s is in conflict with %%s template type %%s of %%s %%s.', + $className, + $escapedConstantName, + ), + sprintf( + 'Call-site variance of %%s in generic type %%s in PHPDoc tag @var for constant %s::%s is redundant, template type %%s of %%s %%s has the same variance.', + $className, + $escapedConstantName, + ), + )); } } diff --git a/src/Rules/PhpDoc/IncompatiblePhpDocTypeRule.php b/src/Rules/PhpDoc/IncompatiblePhpDocTypeRule.php index 04f4a7e8f60..39b16ef750d 100644 --- a/src/Rules/PhpDoc/IncompatiblePhpDocTypeRule.php +++ b/src/Rules/PhpDoc/IncompatiblePhpDocTypeRule.php @@ -27,24 +27,14 @@ class IncompatiblePhpDocTypeRule implements Rule { - /** - * @var FileTypeMapper - */ - private $fileTypeMapper; - /** - * @var GenericObjectTypeCheck - */ - private $genericObjectTypeCheck; - /** - * @var UnresolvableTypeHelper - */ - private $unresolvableTypeHelper; - public function __construct(FileTypeMapper $fileTypeMapper, GenericObjectTypeCheck $genericObjectTypeCheck, UnresolvableTypeHelper $unresolvableTypeHelper) + public function __construct( + private FileTypeMapper $fileTypeMapper, + private GenericObjectTypeCheck $genericObjectTypeCheck, + private UnresolvableTypeHelper $unresolvableTypeHelper, + ) { - $this->fileTypeMapper = $fileTypeMapper; - $this->genericObjectTypeCheck = $genericObjectTypeCheck; - $this->unresolvableTypeHelper = $unresolvableTypeHelper; } + public function getNodeType(): string { return Node\FunctionLike::class; @@ -65,7 +55,13 @@ public function processNode(Node $node, Scope $scope): array return []; } - $resolvedPhpDoc = $this->fileTypeMapper->getResolvedPhpDoc($scope->getFile(), $scope->isInClass() ? $scope->getClassReflection()->getName() : null, $scope->isInTrait() ? $scope->getTraitReflection()->getName() : null, $functionName, $docComment->getText()); + $resolvedPhpDoc = $this->fileTypeMapper->getResolvedPhpDoc( + $scope->getFile(), + $scope->isInClass() ? $scope->getClassReflection()->getName() : null, + $scope->isInTrait() ? $scope->getTraitReflection()->getName() : null, + $functionName, + $docComment->getText(), + ); $nativeParameterTypes = $this->getNativeParameterTypes($node, $scope); $byRefParameters = $this->getByRefParameters($node); @@ -77,12 +73,20 @@ public function processNode(Node $node, Scope $scope): array $tagName = $phpDocParamTag instanceof ParamTag ? '@param' : '@param-out'; if (!isset($nativeParameterTypes[$parameterName])) { - $errors[] = RuleErrorBuilder::message(sprintf('PHPDoc tag %s references unknown parameter: $%s', $tagName, $parameterName))->identifier('parameter.notFound')->build(); + $errors[] = RuleErrorBuilder::message(sprintf( + 'PHPDoc tag %s references unknown parameter: $%s', + $tagName, + $parameterName, + ))->identifier('parameter.notFound')->build(); } elseif ( $this->unresolvableTypeHelper->containsUnresolvableType($phpDocParamType) ) { - $errors[] = RuleErrorBuilder::message(sprintf('PHPDoc tag %s for parameter $%s contains unresolvable type.', $tagName, $parameterName))->identifier('parameter.unresolvableType')->build(); + $errors[] = RuleErrorBuilder::message(sprintf( + 'PHPDoc tag %s for parameter $%s contains unresolvable type.', + $tagName, + $parameterName, + ))->identifier('parameter.unresolvableType')->build(); } else { $nativeParamType = $nativeParameterTypes[$parameterName]; @@ -99,21 +103,69 @@ public function processNode(Node $node, Scope $scope): array $escapedParameterName = SprintfHelper::escapeFormatString($parameterName); $escapedTagName = SprintfHelper::escapeFormatString($tagName); - $errors = array_merge($errors, $this->genericObjectTypeCheck->check($phpDocParamType, sprintf('PHPDoc tag %s for parameter $%s contains generic type %%s but %%s %%s is not generic.', $escapedTagName, $escapedParameterName), sprintf('Generic type %%s in PHPDoc tag %s for parameter $%s does not specify all template types of %%s %%s: %%s', $escapedTagName, $escapedParameterName), sprintf('Generic type %%s in PHPDoc tag %s for parameter $%s specifies %%d template types, but %%s %%s supports only %%d: %%s', $escapedTagName, $escapedParameterName), sprintf('Type %%s in generic type %%s in PHPDoc tag %s for parameter $%s is not subtype of template type %%s of %%s %%s.', $escapedTagName, $escapedParameterName), sprintf('Call-site variance of %%s in generic type %%s in PHPDoc tag %s for parameter $%s is in conflict with %%s template type %%s of %%s %%s.', $escapedTagName, $escapedParameterName), sprintf('Call-site variance of %%s in generic type %%s in PHPDoc tag %s for parameter $%s is redundant, template type %%s of %%s %%s has the same variance.', $escapedTagName, $escapedParameterName))); + $errors = array_merge($errors, $this->genericObjectTypeCheck->check( + $phpDocParamType, + sprintf( + 'PHPDoc tag %s for parameter $%s contains generic type %%s but %%s %%s is not generic.', + $escapedTagName, + $escapedParameterName, + ), + sprintf( + 'Generic type %%s in PHPDoc tag %s for parameter $%s does not specify all template types of %%s %%s: %%s', + $escapedTagName, + $escapedParameterName, + ), + sprintf( + 'Generic type %%s in PHPDoc tag %s for parameter $%s specifies %%d template types, but %%s %%s supports only %%d: %%s', + $escapedTagName, + $escapedParameterName, + ), + sprintf( + 'Type %%s in generic type %%s in PHPDoc tag %s for parameter $%s is not subtype of template type %%s of %%s %%s.', + $escapedTagName, + $escapedParameterName, + ), + sprintf( + 'Call-site variance of %%s in generic type %%s in PHPDoc tag %s for parameter $%s is in conflict with %%s template type %%s of %%s %%s.', + $escapedTagName, + $escapedParameterName, + ), + sprintf( + 'Call-site variance of %%s in generic type %%s in PHPDoc tag %s for parameter $%s is redundant, template type %%s of %%s %%s has the same variance.', + $escapedTagName, + $escapedParameterName, + ), + )); if ($phpDocParamTag instanceof ParamOutTag) { if (!$byRefParameters[$parameterName]) { - $errors[] = RuleErrorBuilder::message(sprintf('Parameter $%s for PHPDoc tag %s is not passed by reference.', $parameterName, $tagName))->identifier('parameter.notByRef')->build(); + $errors[] = RuleErrorBuilder::message(sprintf( + 'Parameter $%s for PHPDoc tag %s is not passed by reference.', + $parameterName, + $tagName, + ))->identifier('parameter.notByRef')->build(); } continue; } if ($isParamSuperType->no()) { - $errors[] = RuleErrorBuilder::message(sprintf('PHPDoc tag %s for parameter $%s with type %s is incompatible with native type %s.', $tagName, $parameterName, $phpDocParamType->describe(VerbosityLevel::typeOnly()), $nativeParamType->describe(VerbosityLevel::typeOnly())))->identifier('parameter.phpDocType')->build(); + $errors[] = RuleErrorBuilder::message(sprintf( + 'PHPDoc tag %s for parameter $%s with type %s is incompatible with native type %s.', + $tagName, + $parameterName, + $phpDocParamType->describe(VerbosityLevel::typeOnly()), + $nativeParamType->describe(VerbosityLevel::typeOnly()), + ))->identifier('parameter.phpDocType')->build(); } elseif ($isParamSuperType->maybe()) { - $errorBuilder = RuleErrorBuilder::message(sprintf('PHPDoc tag %s for parameter $%s with type %s is not subtype of native type %s.', $tagName, $parameterName, $phpDocParamType->describe(VerbosityLevel::typeOnly()), $nativeParamType->describe(VerbosityLevel::typeOnly())))->identifier('parameter.phpDocType'); + $errorBuilder = RuleErrorBuilder::message(sprintf( + 'PHPDoc tag %s for parameter $%s with type %s is not subtype of native type %s.', + $tagName, + $parameterName, + $phpDocParamType->describe(VerbosityLevel::typeOnly()), + $nativeParamType->describe(VerbosityLevel::typeOnly()), + ))->identifier('parameter.phpDocType'); if ($phpDocParamType instanceof TemplateType) { $errorBuilder->tip(sprintf('Write @template %s of %s to fix this.', $phpDocParamType->getName(), $nativeParamType->describe(VerbosityLevel::typeOnly()))); } @@ -135,12 +187,28 @@ public function processNode(Node $node, Scope $scope): array } else { $nativeReturnType = $this->getNativeReturnType($node, $scope); $isReturnSuperType = $nativeReturnType->isSuperTypeOf($phpDocReturnType); - $errors = array_merge($errors, $this->genericObjectTypeCheck->check($phpDocReturnType, 'PHPDoc tag @return contains generic type %s but %s %s is not generic.', 'Generic type %s in PHPDoc tag @return does not specify all template types of %s %s: %s', 'Generic type %s in PHPDoc tag @return specifies %d template types, but %s %s supports only %d: %s', 'Type %s in generic type %s in PHPDoc tag @return is not subtype of template type %s of %s %s.', 'Call-site variance of %s in generic type %s in PHPDoc tag @return is in conflict with %s template type %s of %s %s.', 'Call-site variance of %s in generic type %s in PHPDoc tag @return is redundant, template type %s of %s %s has the same variance.')); + $errors = array_merge($errors, $this->genericObjectTypeCheck->check( + $phpDocReturnType, + 'PHPDoc tag @return contains generic type %s but %s %s is not generic.', + 'Generic type %s in PHPDoc tag @return does not specify all template types of %s %s: %s', + 'Generic type %s in PHPDoc tag @return specifies %d template types, but %s %s supports only %d: %s', + 'Type %s in generic type %s in PHPDoc tag @return is not subtype of template type %s of %s %s.', + 'Call-site variance of %s in generic type %s in PHPDoc tag @return is in conflict with %s template type %s of %s %s.', + 'Call-site variance of %s in generic type %s in PHPDoc tag @return is redundant, template type %s of %s %s has the same variance.', + )); if ($isReturnSuperType->no()) { - $errors[] = RuleErrorBuilder::message(sprintf('PHPDoc tag @return with type %s is incompatible with native type %s.', $phpDocReturnType->describe(VerbosityLevel::typeOnly()), $nativeReturnType->describe(VerbosityLevel::typeOnly())))->identifier('return.phpDocType')->build(); + $errors[] = RuleErrorBuilder::message(sprintf( + 'PHPDoc tag @return with type %s is incompatible with native type %s.', + $phpDocReturnType->describe(VerbosityLevel::typeOnly()), + $nativeReturnType->describe(VerbosityLevel::typeOnly()), + ))->identifier('return.phpDocType')->build(); } elseif ($isReturnSuperType->maybe()) { - $errorBuilder = RuleErrorBuilder::message(sprintf('PHPDoc tag @return with type %s is not subtype of native type %s.', $phpDocReturnType->describe(VerbosityLevel::typeOnly()), $nativeReturnType->describe(VerbosityLevel::typeOnly())))->identifier('return.phpDocType'); + $errorBuilder = RuleErrorBuilder::message(sprintf( + 'PHPDoc tag @return with type %s is not subtype of native type %s.', + $phpDocReturnType->describe(VerbosityLevel::typeOnly()), + $nativeReturnType->describe(VerbosityLevel::typeOnly()), + ))->identifier('return.phpDocType'); if ($phpDocReturnType instanceof TemplateType) { $errorBuilder->tip(sprintf('Write @template %s of %s to fix this.', $phpDocReturnType->getName(), $nativeReturnType->describe(VerbosityLevel::typeOnly()))); } @@ -164,7 +232,11 @@ private function getNativeParameterTypes(Node\FunctionLike $node, Scope $scope): if (!$parameter->var instanceof Variable || !is_string($parameter->var->name)) { throw new ShouldNotHappenException(); } - $nativeParameterTypes[$parameter->var->name] = $scope->getFunctionType($parameter->type, $isNullable, false); + $nativeParameterTypes[$parameter->var->name] = $scope->getFunctionType( + $parameter->type, + $isNullable, + false, + ); } return $nativeParameterTypes; diff --git a/src/Rules/PhpDoc/IncompatiblePropertyPhpDocTypeRule.php b/src/Rules/PhpDoc/IncompatiblePropertyPhpDocTypeRule.php index 75664063e01..cbb82ee889f 100644 --- a/src/Rules/PhpDoc/IncompatiblePropertyPhpDocTypeRule.php +++ b/src/Rules/PhpDoc/IncompatiblePropertyPhpDocTypeRule.php @@ -21,19 +21,13 @@ class IncompatiblePropertyPhpDocTypeRule implements Rule { - /** - * @var GenericObjectTypeCheck - */ - private $genericObjectTypeCheck; - /** - * @var UnresolvableTypeHelper - */ - private $unresolvableTypeHelper; - public function __construct(GenericObjectTypeCheck $genericObjectTypeCheck, UnresolvableTypeHelper $unresolvableTypeHelper) + public function __construct( + private GenericObjectTypeCheck $genericObjectTypeCheck, + private UnresolvableTypeHelper $unresolvableTypeHelper, + ) { - $this->genericObjectTypeCheck = $genericObjectTypeCheck; - $this->unresolvableTypeHelper = $unresolvableTypeHelper; } + public function getNodeType(): string { return ClassPropertyNode::class; @@ -59,16 +53,35 @@ public function processNode(Node $node, Scope $scope): array if ( $this->unresolvableTypeHelper->containsUnresolvableType($phpDocType) ) { - $messages[] = RuleErrorBuilder::message(sprintf('%s for property %s::$%s contains unresolvable type.', $description, $classReflection->getDisplayName(), $propertyName))->identifier('property.unresolvableType')->build(); + $messages[] = RuleErrorBuilder::message(sprintf( + '%s for property %s::$%s contains unresolvable type.', + $description, + $classReflection->getDisplayName(), + $propertyName, + ))->identifier('property.unresolvableType')->build(); } $nativeType = ParserNodeTypeToPHPStanType::resolve($node->getNativeType(), $classReflection); $isSuperType = $nativeType->isSuperTypeOf($phpDocType); if ($isSuperType->no()) { - $messages[] = RuleErrorBuilder::message(sprintf('%s for property %s::$%s with type %s is incompatible with native type %s.', $description, $classReflection->getDisplayName(), $propertyName, $phpDocType->describe(VerbosityLevel::typeOnly()), $nativeType->describe(VerbosityLevel::typeOnly())))->identifier('property.phpDocType')->build(); + $messages[] = RuleErrorBuilder::message(sprintf( + '%s for property %s::$%s with type %s is incompatible with native type %s.', + $description, + $classReflection->getDisplayName(), + $propertyName, + $phpDocType->describe(VerbosityLevel::typeOnly()), + $nativeType->describe(VerbosityLevel::typeOnly()), + ))->identifier('property.phpDocType')->build(); } elseif ($isSuperType->maybe()) { - $errorBuilder = RuleErrorBuilder::message(sprintf('%s for property %s::$%s with type %s is not subtype of native type %s.', $description, $classReflection->getDisplayName(), $propertyName, $phpDocType->describe(VerbosityLevel::typeOnly()), $nativeType->describe(VerbosityLevel::typeOnly())))->identifier('property.phpDocType'); + $errorBuilder = RuleErrorBuilder::message(sprintf( + '%s for property %s::$%s with type %s is not subtype of native type %s.', + $description, + $classReflection->getDisplayName(), + $propertyName, + $phpDocType->describe(VerbosityLevel::typeOnly()), + $nativeType->describe(VerbosityLevel::typeOnly()), + ))->identifier('property.phpDocType'); if ($phpDocType instanceof TemplateType) { $errorBuilder->tip(sprintf('Write @template %s of %s to fix this.', $phpDocType->getName(), $nativeType->describe(VerbosityLevel::typeOnly()))); @@ -80,7 +93,45 @@ public function processNode(Node $node, Scope $scope): array $className = SprintfHelper::escapeFormatString($classReflection->getDisplayName()); $escapedPropertyName = SprintfHelper::escapeFormatString($propertyName); - $messages = array_merge($messages, $this->genericObjectTypeCheck->check($phpDocType, sprintf('%s for property %s::$%s contains generic type %%s but %%s %%s is not generic.', $description, $className, $escapedPropertyName), sprintf('Generic type %%s in %s for property %s::$%s does not specify all template types of %%s %%s: %%s', $description, $className, $escapedPropertyName), sprintf('Generic type %%s in %s for property %s::$%s specifies %%d template types, but %%s %%s supports only %%d: %%s', $description, $className, $escapedPropertyName), sprintf('Type %%s in generic type %%s in %s for property %s::$%s is not subtype of template type %%s of %%s %%s.', $description, $className, $escapedPropertyName), sprintf('Call-site variance of %%s in generic type %%s in %s for property %s::$%s is in conflict with %%s template type %%s of %%s %%s.', $description, $className, $escapedPropertyName), sprintf('Call-site variance of %%s in generic type %%s in %s for property %s::$%s is redundant, template type %%s of %%s %%s has the same variance.', $description, $className, $escapedPropertyName))); + $messages = array_merge($messages, $this->genericObjectTypeCheck->check( + $phpDocType, + sprintf( + '%s for property %s::$%s contains generic type %%s but %%s %%s is not generic.', + $description, + $className, + $escapedPropertyName, + ), + sprintf( + 'Generic type %%s in %s for property %s::$%s does not specify all template types of %%s %%s: %%s', + $description, + $className, + $escapedPropertyName, + ), + sprintf( + 'Generic type %%s in %s for property %s::$%s specifies %%d template types, but %%s %%s supports only %%d: %%s', + $description, + $className, + $escapedPropertyName, + ), + sprintf( + 'Type %%s in generic type %%s in %s for property %s::$%s is not subtype of template type %%s of %%s %%s.', + $description, + $className, + $escapedPropertyName, + ), + sprintf( + 'Call-site variance of %%s in generic type %%s in %s for property %s::$%s is in conflict with %%s template type %%s of %%s %%s.', + $description, + $className, + $escapedPropertyName, + ), + sprintf( + 'Call-site variance of %%s in generic type %%s in %s for property %s::$%s is redundant, template type %%s of %%s %%s has the same variance.', + $description, + $className, + $escapedPropertyName, + ), + )); return $messages; } diff --git a/src/Rules/PhpDoc/IncompatibleSelfOutTypeRule.php b/src/Rules/PhpDoc/IncompatibleSelfOutTypeRule.php index 619ea4456a8..22be14246c3 100644 --- a/src/Rules/PhpDoc/IncompatibleSelfOutTypeRule.php +++ b/src/Rules/PhpDoc/IncompatibleSelfOutTypeRule.php @@ -39,7 +39,13 @@ public function processNode(Node $node, Scope $scope): array } return [ - RuleErrorBuilder::message(sprintf('Self-out type %s of method %s::%s is not subtype of %s.', $selfOutType->describe(VerbosityLevel::precise()), $classReflection->getName(), $method->getName(), $classType->describe(VerbosityLevel::precise())))->identifier('selfOut.type')->build(), + RuleErrorBuilder::message(sprintf( + 'Self-out type %s of method %s::%s is not subtype of %s.', + $selfOutType->describe(VerbosityLevel::precise()), + $classReflection->getName(), + $method->getName(), + $classType->describe(VerbosityLevel::precise()), + ))->identifier('selfOut.type')->build(), ]; } diff --git a/src/Rules/PhpDoc/InvalidPHPStanDocTagRule.php b/src/Rules/PhpDoc/InvalidPHPStanDocTagRule.php index 2734ea0e1b1..c57b26b18f5 100644 --- a/src/Rules/PhpDoc/InvalidPHPStanDocTagRule.php +++ b/src/Rules/PhpDoc/InvalidPHPStanDocTagRule.php @@ -20,18 +20,6 @@ class InvalidPHPStanDocTagRule implements Rule { - /** - * @var Lexer - */ - private $phpDocLexer; - /** - * @var PhpDocParser - */ - private $phpDocParser; - /** - * @var bool - */ - private $checkAllInvalidPhpDocs; private const POSSIBLE_PHPSTAN_TAGS = [ '@phpstan-param', '@phpstan-param-out', @@ -69,11 +57,12 @@ class InvalidPHPStanDocTagRule implements Rule '@phpstan-require-implements', ]; - public function __construct(Lexer $phpDocLexer, PhpDocParser $phpDocParser, bool $checkAllInvalidPhpDocs) + public function __construct( + private Lexer $phpDocLexer, + private PhpDocParser $phpDocParser, + private bool $checkAllInvalidPhpDocs, + ) { - $this->phpDocLexer = $phpDocLexer; - $this->phpDocParser = $phpDocParser; - $this->checkAllInvalidPhpDocs = $checkAllInvalidPhpDocs; } public function getNodeType(): string @@ -125,7 +114,10 @@ public function processNode(Node $node, Scope $scope): array continue; } - $errors[] = RuleErrorBuilder::message(sprintf('Unknown PHPDoc tag: %s', $phpDocTag->name)) + $errors[] = RuleErrorBuilder::message(sprintf( + 'Unknown PHPDoc tag: %s', + $phpDocTag->name, + )) ->line(PhpDocLineHelper::detectLine($node, $phpDocTag)) ->identifier('phpDoc.phpstanTag')->build(); } diff --git a/src/Rules/PhpDoc/InvalidPhpDocTagValueRule.php b/src/Rules/PhpDoc/InvalidPhpDocTagValueRule.php index 21258ce20ea..5b5ee77fb94 100644 --- a/src/Rules/PhpDoc/InvalidPhpDocTagValueRule.php +++ b/src/Rules/PhpDoc/InvalidPhpDocTagValueRule.php @@ -23,29 +23,15 @@ class InvalidPhpDocTagValueRule implements Rule { - /** - * @var Lexer - */ - private $phpDocLexer; - /** - * @var PhpDocParser - */ - private $phpDocParser; - /** - * @var bool - */ - private $checkAllInvalidPhpDocs; - /** - * @var bool - */ - private $invalidPhpDocTagLine; - public function __construct(Lexer $phpDocLexer, PhpDocParser $phpDocParser, bool $checkAllInvalidPhpDocs, bool $invalidPhpDocTagLine) + public function __construct( + private Lexer $phpDocLexer, + private PhpDocParser $phpDocParser, + private bool $checkAllInvalidPhpDocs, + private bool $invalidPhpDocTagLine, + ) { - $this->phpDocLexer = $phpDocLexer; - $this->phpDocParser = $phpDocParser; - $this->checkAllInvalidPhpDocs = $checkAllInvalidPhpDocs; - $this->invalidPhpDocTagLine = $invalidPhpDocTagLine; } + public function getNodeType(): string { return Node::class; @@ -99,7 +85,12 @@ public function processNode(Node $node, Scope $scope): array continue; } - $errors[] = RuleErrorBuilder::message(sprintf('PHPDoc tag %s %s has invalid value: %s', $phpDocTag->name, $phpDocTag->value->alias, $this->trimExceptionMessage($phpDocTag->value->type->getException()->getMessage()))) + $errors[] = RuleErrorBuilder::message(sprintf( + 'PHPDoc tag %s %s has invalid value: %s', + $phpDocTag->name, + $phpDocTag->value->alias, + $this->trimExceptionMessage($phpDocTag->value->type->getException()->getMessage()), + )) ->line(PhpDocLineHelper::detectLine($node, $phpDocTag)) ->identifier('phpDoc.parseError')->build(); @@ -108,7 +99,12 @@ public function processNode(Node $node, Scope $scope): array continue; } - $errors[] = RuleErrorBuilder::message(sprintf('PHPDoc tag %s has invalid value (%s): %s', $phpDocTag->name, $phpDocTag->value->value, $this->trimExceptionMessage($phpDocTag->value->exception->getMessage()))) + $errors[] = RuleErrorBuilder::message(sprintf( + 'PHPDoc tag %s has invalid value (%s): %s', + $phpDocTag->name, + $phpDocTag->value->value, + $this->trimExceptionMessage($phpDocTag->value->exception->getMessage()), + )) ->line(PhpDocLineHelper::detectLine($node, $phpDocTag)) ->identifier('phpDoc.parseError')->build(); } diff --git a/src/Rules/PhpDoc/InvalidPhpDocVarTagTypeRule.php b/src/Rules/PhpDoc/InvalidPhpDocVarTagTypeRule.php index 1c4a96a5f18..8c8ff51e5e9 100644 --- a/src/Rules/PhpDoc/InvalidPhpDocVarTagTypeRule.php +++ b/src/Rules/PhpDoc/InvalidPhpDocVarTagTypeRule.php @@ -26,49 +26,19 @@ class InvalidPhpDocVarTagTypeRule implements Rule { - /** - * @var FileTypeMapper - */ - private $fileTypeMapper; - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - /** - * @var ClassCaseSensitivityCheck - */ - private $classCaseSensitivityCheck; - /** - * @var GenericObjectTypeCheck - */ - private $genericObjectTypeCheck; - /** - * @var MissingTypehintCheck - */ - private $missingTypehintCheck; - /** - * @var UnresolvableTypeHelper - */ - private $unresolvableTypeHelper; - /** - * @var bool - */ - private $checkClassCaseSensitivity; - /** - * @var bool - */ - private $checkMissingVarTagTypehint; - public function __construct(FileTypeMapper $fileTypeMapper, ReflectionProvider $reflectionProvider, ClassCaseSensitivityCheck $classCaseSensitivityCheck, GenericObjectTypeCheck $genericObjectTypeCheck, MissingTypehintCheck $missingTypehintCheck, UnresolvableTypeHelper $unresolvableTypeHelper, bool $checkClassCaseSensitivity, bool $checkMissingVarTagTypehint) + public function __construct( + private FileTypeMapper $fileTypeMapper, + private ReflectionProvider $reflectionProvider, + private ClassCaseSensitivityCheck $classCaseSensitivityCheck, + private GenericObjectTypeCheck $genericObjectTypeCheck, + private MissingTypehintCheck $missingTypehintCheck, + private UnresolvableTypeHelper $unresolvableTypeHelper, + private bool $checkClassCaseSensitivity, + private bool $checkMissingVarTagTypehint, + ) { - $this->fileTypeMapper = $fileTypeMapper; - $this->reflectionProvider = $reflectionProvider; - $this->classCaseSensitivityCheck = $classCaseSensitivityCheck; - $this->genericObjectTypeCheck = $genericObjectTypeCheck; - $this->missingTypehintCheck = $missingTypehintCheck; - $this->unresolvableTypeHelper = $unresolvableTypeHelper; - $this->checkClassCaseSensitivity = $checkClassCaseSensitivity; - $this->checkMissingVarTagTypehint = $checkMissingVarTagTypehint; } + public function getNodeType(): string { return Node\Stmt::class; @@ -91,7 +61,13 @@ public function processNode(Node $node, Scope $scope): array } $function = $scope->getFunction(); - $resolvedPhpDoc = $this->fileTypeMapper->getResolvedPhpDoc($scope->getFile(), $scope->isInClass() ? $scope->getClassReflection()->getName() : null, $scope->isInTrait() ? $scope->getTraitReflection()->getName() : null, $function !== null ? $function->getName() : null, $docComment->getText()); + $resolvedPhpDoc = $this->fileTypeMapper->getResolvedPhpDoc( + $scope->getFile(), + $scope->isInClass() ? $scope->getClassReflection()->getName() : null, + $scope->isInTrait() ? $scope->getTraitReflection()->getName() : null, + $function !== null ? $function->getName() : null, + $docComment->getText(), + ); $errors = []; foreach ($resolvedPhpDoc->getVarTags() as $name => $varTag) { @@ -113,7 +89,11 @@ public function processNode(Node $node, Scope $scope): array if ($this->checkMissingVarTagTypehint) { foreach ($this->missingTypehintCheck->getIterableTypesWithMissingValueTypehint($varTagType) as $iterableType) { $iterableTypeDescription = $iterableType->describe(VerbosityLevel::typeOnly()); - $errors[] = RuleErrorBuilder::message(sprintf('%s has no value type specified in iterable type %s.', $identifier, $iterableTypeDescription)) + $errors[] = RuleErrorBuilder::message(sprintf( + '%s has no value type specified in iterable type %s.', + $identifier, + $iterableTypeDescription, + )) ->tip(MissingTypehintCheck::MISSING_ITERABLE_VALUE_TYPE_TIP) ->identifier('missingType.iterableValue') ->build(); @@ -121,10 +101,23 @@ public function processNode(Node $node, Scope $scope): array } $escapedIdentifier = SprintfHelper::escapeFormatString($identifier); - $errors = array_merge($errors, $this->genericObjectTypeCheck->check($varTagType, sprintf('%s contains generic type %%s but %%s %%s is not generic.', $escapedIdentifier), sprintf('Generic type %%s in %s does not specify all template types of %%s %%s: %%s', $escapedIdentifier), sprintf('Generic type %%s in %s specifies %%d template types, but %%s %%s supports only %%d: %%s', $escapedIdentifier), sprintf('Type %%s in generic type %%s in %s is not subtype of template type %%s of %%s %%s.', $escapedIdentifier), sprintf('Call-site variance of %%s in generic type %%s in %s is in conflict with %%s template type %%s of %%s %%s.', $escapedIdentifier), sprintf('Call-site variance of %%s in generic type %%s in %s is redundant, template type %%s of %%s %%s has the same variance.', $escapedIdentifier))); + $errors = array_merge($errors, $this->genericObjectTypeCheck->check( + $varTagType, + sprintf('%s contains generic type %%s but %%s %%s is not generic.', $escapedIdentifier), + sprintf('Generic type %%s in %s does not specify all template types of %%s %%s: %%s', $escapedIdentifier), + sprintf('Generic type %%s in %s specifies %%d template types, but %%s %%s supports only %%d: %%s', $escapedIdentifier), + sprintf('Type %%s in generic type %%s in %s is not subtype of template type %%s of %%s %%s.', $escapedIdentifier), + sprintf('Call-site variance of %%s in generic type %%s in %s is in conflict with %%s template type %%s of %%s %%s.', $escapedIdentifier), + sprintf('Call-site variance of %%s in generic type %%s in %s is redundant, template type %%s of %%s %%s has the same variance.', $escapedIdentifier), + )); foreach ($this->missingTypehintCheck->getNonGenericObjectTypesWithGenericClass($varTagType) as [$innerName, $genericTypeNames]) { - $errors[] = RuleErrorBuilder::message(sprintf('%s contains generic %s but does not specify its types: %s', $identifier, $innerName, implode(', ', $genericTypeNames))) + $errors[] = RuleErrorBuilder::message(sprintf( + '%s contains generic %s but does not specify its types: %s', + $identifier, + $innerName, + implode(', ', $genericTypeNames), + )) ->tip(MissingTypehintCheck::TURN_OFF_NON_GENERIC_CHECK_TIP) ->identifier('missingType.generics') ->build(); @@ -134,7 +127,10 @@ public function processNode(Node $node, Scope $scope): array foreach ($referencedClasses as $referencedClass) { if ($this->reflectionProvider->hasClass($referencedClass)) { if ($this->reflectionProvider->getClass($referencedClass)->isTrait()) { - $errors[] = RuleErrorBuilder::message(sprintf(sprintf('%s has invalid type %%s.', $identifier), $referencedClass))->identifier('varTag.trait')->build(); + $errors[] = RuleErrorBuilder::message(sprintf( + sprintf('%s has invalid type %%s.', $identifier), + $referencedClass, + ))->identifier('varTag.trait')->build(); } continue; } @@ -143,7 +139,10 @@ public function processNode(Node $node, Scope $scope): array continue; } - $errors[] = RuleErrorBuilder::message(sprintf(sprintf('%s contains unknown class %%s.', $identifier), $referencedClass)) + $errors[] = RuleErrorBuilder::message(sprintf( + sprintf('%s contains unknown class %%s.', $identifier), + $referencedClass, + )) ->identifier('class.notFound') ->discoveringSymbolsTip() ->build(); @@ -153,9 +152,10 @@ public function processNode(Node $node, Scope $scope): array continue; } - $errors = array_merge($errors, $this->classCaseSensitivityCheck->checkClassNames(array_map(static function (string $class) use($node) : ClassNameNodePair { - return new ClassNameNodePair($class, $node); - }, $referencedClasses))); + $errors = array_merge( + $errors, + $this->classCaseSensitivityCheck->checkClassNames(array_map(static fn (string $class): ClassNameNodePair => new ClassNameNodePair($class, $node), $referencedClasses)), + ); } return $errors; diff --git a/src/Rules/PhpDoc/InvalidThrowsPhpDocValueRule.php b/src/Rules/PhpDoc/InvalidThrowsPhpDocValueRule.php index dc84b71b4b6..1efb15ffaa4 100644 --- a/src/Rules/PhpDoc/InvalidThrowsPhpDocValueRule.php +++ b/src/Rules/PhpDoc/InvalidThrowsPhpDocValueRule.php @@ -21,13 +21,8 @@ class InvalidThrowsPhpDocValueRule implements Rule { - /** - * @var FileTypeMapper - */ - private $fileTypeMapper; - public function __construct(FileTypeMapper $fileTypeMapper) + public function __construct(private FileTypeMapper $fileTypeMapper) { - $this->fileTypeMapper = $fileTypeMapper; } public function getNodeType(): string @@ -51,7 +46,13 @@ public function processNode(Node $node, Scope $scope): array $functionName = $scope->getFunction()->getName(); } - $resolvedPhpDoc = $this->fileTypeMapper->getResolvedPhpDoc($scope->getFile(), $scope->isInClass() ? $scope->getClassReflection()->getName() : null, $scope->isInTrait() ? $scope->getTraitReflection()->getName() : null, $functionName, $docComment->getText()); + $resolvedPhpDoc = $this->fileTypeMapper->getResolvedPhpDoc( + $scope->getFile(), + $scope->isInClass() ? $scope->getClassReflection()->getName() : null, + $scope->isInTrait() ? $scope->getTraitReflection()->getName() : null, + $functionName, + $docComment->getText(), + ); if ($resolvedPhpDoc->getThrowsTag() === null) { return []; @@ -67,7 +68,10 @@ public function processNode(Node $node, Scope $scope): array } return [ - RuleErrorBuilder::message(sprintf('PHPDoc tag @throws with type %s is not subtype of Throwable', $phpDocThrowsType->describe(VerbosityLevel::typeOnly())))->identifier('throws.notThrowable')->build(), + RuleErrorBuilder::message(sprintf( + 'PHPDoc tag @throws with type %s is not subtype of Throwable', + $phpDocThrowsType->describe(VerbosityLevel::typeOnly()), + ))->identifier('throws.notThrowable')->build(), ]; } @@ -94,7 +98,9 @@ private function isThrowsValid(Type $phpDocThrowsType): bool } } - return $throwType->isSuperTypeOf(TypeCombinator::intersect($phpDocThrowsType, ...$toIntersectWith))->yes(); + return $throwType->isSuperTypeOf( + TypeCombinator::intersect($phpDocThrowsType, ...$toIntersectWith), + )->yes(); } } diff --git a/src/Rules/PhpDoc/MethodAssertRule.php b/src/Rules/PhpDoc/MethodAssertRule.php index 409a8c23e51..5c24f9bca8a 100644 --- a/src/Rules/PhpDoc/MethodAssertRule.php +++ b/src/Rules/PhpDoc/MethodAssertRule.php @@ -14,13 +14,8 @@ class MethodAssertRule implements Rule { - /** - * @var AssertRuleHelper - */ - private $helper; - public function __construct(AssertRuleHelper $helper) + public function __construct(private AssertRuleHelper $helper) { - $this->helper = $helper; } public function getNodeType(): string diff --git a/src/Rules/PhpDoc/MethodConditionalReturnTypeRule.php b/src/Rules/PhpDoc/MethodConditionalReturnTypeRule.php index 2b0ba4bd38a..6925576665e 100644 --- a/src/Rules/PhpDoc/MethodConditionalReturnTypeRule.php +++ b/src/Rules/PhpDoc/MethodConditionalReturnTypeRule.php @@ -14,13 +14,8 @@ class MethodConditionalReturnTypeRule implements Rule { - /** - * @var ConditionalReturnTypeRuleHelper - */ - private $helper; - public function __construct(ConditionalReturnTypeRuleHelper $helper) + public function __construct(private ConditionalReturnTypeRuleHelper $helper) { - $this->helper = $helper; } public function getNodeType(): string diff --git a/src/Rules/PhpDoc/RequireExtendsCheck.php b/src/Rules/PhpDoc/RequireExtendsCheck.php index 5f02f67a8e9..90851fbeff5 100644 --- a/src/Rules/PhpDoc/RequireExtendsCheck.php +++ b/src/Rules/PhpDoc/RequireExtendsCheck.php @@ -18,19 +18,13 @@ final class RequireExtendsCheck { - /** - * @var ClassCaseSensitivityCheck - */ - private $classCaseSensitivityCheck; - /** - * @var bool - */ - private $checkClassCaseSensitivity; - public function __construct(ClassCaseSensitivityCheck $classCaseSensitivityCheck, bool $checkClassCaseSensitivity) + public function __construct( + private ClassCaseSensitivityCheck $classCaseSensitivityCheck, + private bool $checkClassCaseSensitivity, + ) { - $this->classCaseSensitivityCheck = $classCaseSensitivityCheck; - $this->checkClassCaseSensitivity = $checkClassCaseSensitivity; } + /** * @param array $extendsTags * @return list @@ -74,9 +68,12 @@ public function checkExtendsTags(Node $node, array $extendsTags): array ->identifier('requireExtends.finalClass') ->build(); } elseif ($this->checkClassCaseSensitivity) { - $errors = array_merge($errors, $this->classCaseSensitivityCheck->checkClassNames([ + $errors = array_merge( + $errors, + $this->classCaseSensitivityCheck->checkClassNames([ new ClassNameNodePair($class, $node), - ])); + ]), + ); } } diff --git a/src/Rules/PhpDoc/RequireExtendsDefinitionClassRule.php b/src/Rules/PhpDoc/RequireExtendsDefinitionClassRule.php index b1645b61a3a..27d8b3d6a35 100644 --- a/src/Rules/PhpDoc/RequireExtendsDefinitionClassRule.php +++ b/src/Rules/PhpDoc/RequireExtendsDefinitionClassRule.php @@ -16,14 +16,12 @@ class RequireExtendsDefinitionClassRule implements Rule { - /** - * @var RequireExtendsCheck - */ - private $requireExtendsCheck; - public function __construct(RequireExtendsCheck $requireExtendsCheck) + public function __construct( + private RequireExtendsCheck $requireExtendsCheck, + ) { - $this->requireExtendsCheck = $requireExtendsCheck; } + public function getNodeType(): string { return InClassNode::class; diff --git a/src/Rules/PhpDoc/RequireExtendsDefinitionTraitRule.php b/src/Rules/PhpDoc/RequireExtendsDefinitionTraitRule.php index ed569fcb9ac..174e7c9385e 100644 --- a/src/Rules/PhpDoc/RequireExtendsDefinitionTraitRule.php +++ b/src/Rules/PhpDoc/RequireExtendsDefinitionTraitRule.php @@ -13,19 +13,13 @@ class RequireExtendsDefinitionTraitRule implements Rule { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - /** - * @var RequireExtendsCheck - */ - private $requireExtendsCheck; - public function __construct(ReflectionProvider $reflectionProvider, RequireExtendsCheck $requireExtendsCheck) + public function __construct( + private ReflectionProvider $reflectionProvider, + private RequireExtendsCheck $requireExtendsCheck, + ) { - $this->reflectionProvider = $reflectionProvider; - $this->requireExtendsCheck = $requireExtendsCheck; } + public function getNodeType(): string { return Node\Stmt\Trait_::class; diff --git a/src/Rules/PhpDoc/RequireImplementsDefinitionTraitRule.php b/src/Rules/PhpDoc/RequireImplementsDefinitionTraitRule.php index f257bc26f6e..4dbf2b463a0 100644 --- a/src/Rules/PhpDoc/RequireImplementsDefinitionTraitRule.php +++ b/src/Rules/PhpDoc/RequireImplementsDefinitionTraitRule.php @@ -21,24 +21,14 @@ class RequireImplementsDefinitionTraitRule implements Rule { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - /** - * @var ClassCaseSensitivityCheck - */ - private $classCaseSensitivityCheck; - /** - * @var bool - */ - private $checkClassCaseSensitivity; - public function __construct(ReflectionProvider $reflectionProvider, ClassCaseSensitivityCheck $classCaseSensitivityCheck, bool $checkClassCaseSensitivity) + public function __construct( + private ReflectionProvider $reflectionProvider, + private ClassCaseSensitivityCheck $classCaseSensitivityCheck, + private bool $checkClassCaseSensitivity, + ) { - $this->reflectionProvider = $reflectionProvider; - $this->classCaseSensitivityCheck = $classCaseSensitivityCheck; - $this->checkClassCaseSensitivity = $checkClassCaseSensitivity; } + public function getNodeType(): string { return Node\Stmt\Trait_::class; @@ -81,9 +71,12 @@ public function processNode(Node $node, Scope $scope): array ->identifier(sprintf('requireImplements.%s', strtolower($referencedClassReflection->getClassTypeDescription()))) ->build(); } elseif ($this->checkClassCaseSensitivity) { - $errors = array_merge($errors, $this->classCaseSensitivityCheck->checkClassNames([ + $errors = array_merge( + $errors, + $this->classCaseSensitivityCheck->checkClassNames([ new ClassNameNodePair($class, $node), - ])); + ]), + ); } } diff --git a/src/Rules/PhpDoc/VarTagChangedExpressionTypeRule.php b/src/Rules/PhpDoc/VarTagChangedExpressionTypeRule.php index fd111f1d31c..3968f05792b 100644 --- a/src/Rules/PhpDoc/VarTagChangedExpressionTypeRule.php +++ b/src/Rules/PhpDoc/VarTagChangedExpressionTypeRule.php @@ -13,13 +13,8 @@ class VarTagChangedExpressionTypeRule implements Rule { - /** - * @var VarTagTypeRuleHelper - */ - private $varTagTypeRuleHelper; - public function __construct(VarTagTypeRuleHelper $varTagTypeRuleHelper) + public function __construct(private VarTagTypeRuleHelper $varTagTypeRuleHelper) { - $this->varTagTypeRuleHelper = $varTagTypeRuleHelper; } public function getNodeType(): string diff --git a/src/Rules/PhpDoc/VarTagTypeRuleHelper.php b/src/Rules/PhpDoc/VarTagTypeRuleHelper.php index 9ec36bd8ed5..90fe8cb7b44 100644 --- a/src/Rules/PhpDoc/VarTagTypeRuleHelper.php +++ b/src/Rules/PhpDoc/VarTagTypeRuleHelper.php @@ -24,13 +24,8 @@ class VarTagTypeRuleHelper { - /** - * @var bool - */ - private $checkTypeAgainstPhpDocType; - public function __construct(bool $checkTypeAgainstPhpDocType) + public function __construct(private bool $checkTypeAgainstPhpDocType) { - $this->checkTypeAgainstPhpDocType = $checkTypeAgainstPhpDocType; } /** @@ -83,7 +78,11 @@ public function checkExprType(Scope $scope, Node\Expr $expr, Type $varTagType): $containsPhpStanType = $this->containsPhpStanType($varTagType); if ($this->shouldVarTagTypeBeReported($expr, $exprNativeType, $varTagType)) { $verbosity = VerbosityLevel::getRecommendedLevelByType($exprNativeType, $varTagType); - $errors[] = RuleErrorBuilder::message(sprintf('PHPDoc tag @var with type %s is not subtype of native type %s.', $varTagType->describe($verbosity), $exprNativeType->describe($verbosity)))->identifier('varTag.nativeType')->build(); + $errors[] = RuleErrorBuilder::message(sprintf( + 'PHPDoc tag @var with type %s is not subtype of native type %s.', + $varTagType->describe($verbosity), + $exprNativeType->describe($verbosity), + ))->identifier('varTag.nativeType')->build(); } else { $exprType = $scope->getType($expr); if ( @@ -91,7 +90,11 @@ public function checkExprType(Scope $scope, Node\Expr $expr, Type $varTagType): && ($this->checkTypeAgainstPhpDocType || $containsPhpStanType) ) { $verbosity = VerbosityLevel::getRecommendedLevelByType($exprType, $varTagType); - $errors[] = RuleErrorBuilder::message(sprintf('PHPDoc tag @var with type %s is not subtype of type %s.', $varTagType->describe($verbosity), $exprType->describe($verbosity)))->identifier('varTag.type')->build(); + $errors[] = RuleErrorBuilder::message(sprintf( + 'PHPDoc tag @var with type %s is not subtype of type %s.', + $varTagType->describe($verbosity), + $exprType->describe($verbosity), + ))->identifier('varTag.type')->build(); } } @@ -99,7 +102,11 @@ public function checkExprType(Scope $scope, Node\Expr $expr, Type $varTagType): $exprType = $scope->getType($expr); if (!$exprType->equals($varTagType)) { $verbosity = VerbosityLevel::getRecommendedLevelByType($exprType, $varTagType); - $errors[] = RuleErrorBuilder::message(sprintf('PHPDoc tag @var assumes the expression with type %s is always %s but it\'s error-prone and dangerous.', $exprType->describe($verbosity), $varTagType->describe($verbosity)))->identifier('phpstanApi.varTagAssumption')->build(); + $errors[] = RuleErrorBuilder::message(sprintf( + 'PHPDoc tag @var assumes the expression with type %s is always %s but it\'s error-prone and dangerous.', + $exprType->describe($verbosity), + $varTagType->describe($verbosity), + ))->identifier('phpstanApi.varTagAssumption')->build(); } } diff --git a/src/Rules/PhpDoc/WrongVariableNameInVarTagRule.php b/src/Rules/PhpDoc/WrongVariableNameInVarTagRule.php index b61826b2352..031edf17433 100644 --- a/src/Rules/PhpDoc/WrongVariableNameInVarTagRule.php +++ b/src/Rules/PhpDoc/WrongVariableNameInVarTagRule.php @@ -34,24 +34,14 @@ class WrongVariableNameInVarTagRule implements Rule { - /** - * @var FileTypeMapper - */ - private $fileTypeMapper; - /** - * @var VarTagTypeRuleHelper - */ - private $varTagTypeRuleHelper; - /** - * @var bool - */ - private $checkTypeAgainstNativeType; - public function __construct(FileTypeMapper $fileTypeMapper, VarTagTypeRuleHelper $varTagTypeRuleHelper, bool $checkTypeAgainstNativeType) + public function __construct( + private FileTypeMapper $fileTypeMapper, + private VarTagTypeRuleHelper $varTagTypeRuleHelper, + private bool $checkTypeAgainstNativeType, + ) { - $this->fileTypeMapper = $fileTypeMapper; - $this->varTagTypeRuleHelper = $varTagTypeRuleHelper; - $this->checkTypeAgainstNativeType = $checkTypeAgainstNativeType; } + public function getNodeType(): string { return Node\Stmt::class; @@ -75,7 +65,13 @@ public function processNode(Node $node, Scope $scope): array if (!$comment instanceof Doc) { continue; } - $resolvedPhpDoc = $this->fileTypeMapper->getResolvedPhpDoc($scope->getFile(), $scope->isInClass() ? $scope->getClassReflection()->getName() : null, $scope->isInTrait() ? $scope->getTraitReflection()->getName() : null, $function !== null ? $function->getName() : null, $comment->getText()); + $resolvedPhpDoc = $this->fileTypeMapper->getResolvedPhpDoc( + $scope->getFile(), + $scope->isInClass() ? $scope->getClassReflection()->getName() : null, + $scope->isInTrait() ? $scope->getTraitReflection()->getName() : null, + $function !== null ? $function->getName() : null, + $comment->getText(), + ); foreach ($resolvedPhpDoc->getVarTags() as $key => $varTag) { $varTags[$key] = $varTag; } @@ -121,7 +117,10 @@ public function processNode(Node $node, Scope $scope): array } return [ - RuleErrorBuilder::message(sprintf('PHPDoc tag @var above %s has no effect.', $description))->identifier('varTag.misplaced')->build(), + RuleErrorBuilder::message(sprintf( + 'PHPDoc tag @var above %s has no effect.', + $description, + ))->identifier('varTag.misplaced')->build(), ]; } @@ -152,7 +151,9 @@ private function processAssign(Scope $scope, Node\Expr $var, Node\Expr $expr, ar $hasMultipleMessage = true; } } elseif (count($assignedVariables) !== 1) { - $errors[] = RuleErrorBuilder::message('PHPDoc tag @var above assignment does not specify variable name.')->identifier('varTag.noVariable')->build(); + $errors[] = RuleErrorBuilder::message( + 'PHPDoc tag @var above assignment does not specify variable name.', + )->identifier('varTag.noVariable')->build(); } continue; } @@ -166,7 +167,11 @@ private function processAssign(Scope $scope, Node\Expr $var, Node\Expr $expr, ar } if (count($assignedVariables) === 1 && count($varTags) === 1) { - $errors[] = RuleErrorBuilder::message(sprintf('Variable $%s in PHPDoc tag @var does not match assigned variable $%s.', $key, $assignedVariables[0]))->identifier('varTag.differentVariable')->build(); + $errors[] = RuleErrorBuilder::message(sprintf( + 'Variable $%s in PHPDoc tag @var does not match assigned variable $%s.', + $key, + $assignedVariables[0], + ))->identifier('varTag.differentVariable')->build(); } else { $errors[] = RuleErrorBuilder::message(sprintf('Variable $%s in PHPDoc tag @var does not exist.', $key)) ->identifier('varTag.variableNotFound') @@ -227,7 +232,9 @@ private function processForeach(Scope $scope, Node\Expr $iterateeExpr, ?Node\Exp if (count($variableNames) === 1) { continue; } - $errors[] = RuleErrorBuilder::message('PHPDoc tag @var above foreach loop does not specify variable name.')->identifier('varTag.noVariable')->build(); + $errors[] = RuleErrorBuilder::message( + 'PHPDoc tag @var above foreach loop does not specify variable name.', + )->identifier('varTag.noVariable')->build(); continue; } @@ -235,9 +242,11 @@ private function processForeach(Scope $scope, Node\Expr $iterateeExpr, ?Node\Exp continue; } - $errors[] = RuleErrorBuilder::message(sprintf('Variable $%s in PHPDoc tag @var does not match any variable in the foreach loop: %s', $name, implode(', ', array_map(static function (string $name) : string { - return sprintf('$%s', $name); - }, $variableNames))))->identifier('varTag.differentVariable')->build(); + $errors[] = RuleErrorBuilder::message(sprintf( + 'Variable $%s in PHPDoc tag @var does not match any variable in the foreach loop: %s', + $name, + implode(', ', array_map(static fn (string $name): string => sprintf('$%s', $name), $variableNames)), + ))->identifier('varTag.differentVariable')->build(); } if ($this->checkTypeAgainstNativeType) { @@ -293,7 +302,9 @@ private function processStatic(Scope $scope, array $vars, array $varTags): array continue; } - $errors[] = RuleErrorBuilder::message('PHPDoc tag @var above multiple static variables does not specify variable name.')->identifier('varTag.noVariable')->build(); + $errors[] = RuleErrorBuilder::message( + 'PHPDoc tag @var above multiple static variables does not specify variable name.', + )->identifier('varTag.noVariable')->build(); continue; } @@ -301,9 +312,11 @@ private function processStatic(Scope $scope, array $vars, array $varTags): array continue; } - $errors[] = RuleErrorBuilder::message(sprintf('Variable $%s in PHPDoc tag @var does not match any static variable: %s', $name, implode(', ', array_map(static function (string $name) : string { - return sprintf('$%s', $name); - }, $variableNames))))->identifier('varTag.differentVariable')->build(); + $errors[] = RuleErrorBuilder::message(sprintf( + 'Variable $%s in PHPDoc tag @var does not match any static variable: %s', + $name, + implode(', ', array_map(static fn (string $name): string => sprintf('$%s', $name), $variableNames)), + ))->identifier('varTag.differentVariable')->build(); } if ($this->checkTypeAgainstNativeType) { @@ -380,7 +393,9 @@ private function processGlobal(Scope $scope, Node\Stmt\Global_ $node, array $var continue; } - $errors[] = RuleErrorBuilder::message('PHPDoc tag @var above multiple global variables does not specify variable name.')->identifier('varTag.noVariable')->build(); + $errors[] = RuleErrorBuilder::message( + 'PHPDoc tag @var above multiple global variables does not specify variable name.', + )->identifier('varTag.noVariable')->build(); continue; } @@ -388,9 +403,11 @@ private function processGlobal(Scope $scope, Node\Stmt\Global_ $node, array $var continue; } - $errors[] = RuleErrorBuilder::message(sprintf('Variable $%s in PHPDoc tag @var does not match any global variable: %s', $name, implode(', ', array_map(static function (string $name) : string { - return sprintf('$%s', $name); - }, array_keys($variableNames)))))->identifier('varTag.differentVariable')->build(); + $errors[] = RuleErrorBuilder::message(sprintf( + 'Variable $%s in PHPDoc tag @var does not match any global variable: %s', + $name, + implode(', ', array_map(static fn (string $name): string => sprintf('$%s', $name), array_keys($variableNames))), + ))->identifier('varTag.differentVariable')->build(); } return $errors; diff --git a/src/Rules/Playground/FunctionNeverRule.php b/src/Rules/Playground/FunctionNeverRule.php index 004d59d024c..94171408dd4 100644 --- a/src/Rules/Playground/FunctionNeverRule.php +++ b/src/Rules/Playground/FunctionNeverRule.php @@ -17,13 +17,8 @@ class FunctionNeverRule implements Rule { - /** - * @var NeverRuleHelper - */ - private $helper; - public function __construct(NeverRuleHelper $helper) + public function __construct(private NeverRuleHelper $helper) { - $this->helper = $helper; } public function getNodeType(): string @@ -46,7 +41,11 @@ public function processNode(Node $node, Scope $scope): array } return [ - RuleErrorBuilder::message(sprintf('Function %s() always %s, it should have return type "never".', $function->getName(), count($helperResult) === 0 ? 'throws an exception' : 'terminates script execution'))->identifier('phpstanPlayground.never')->build(), + RuleErrorBuilder::message(sprintf( + 'Function %s() always %s, it should have return type "never".', + $function->getName(), + count($helperResult) === 0 ? 'throws an exception' : 'terminates script execution', + ))->identifier('phpstanPlayground.never')->build(), ]; } diff --git a/src/Rules/Playground/MethodNeverRule.php b/src/Rules/Playground/MethodNeverRule.php index 81b878549b9..443a31112ff 100644 --- a/src/Rules/Playground/MethodNeverRule.php +++ b/src/Rules/Playground/MethodNeverRule.php @@ -17,13 +17,8 @@ class MethodNeverRule implements Rule { - /** - * @var NeverRuleHelper - */ - private $helper; - public function __construct(NeverRuleHelper $helper) + public function __construct(private NeverRuleHelper $helper) { - $this->helper = $helper; } public function getNodeType(): string @@ -46,7 +41,12 @@ public function processNode(Node $node, Scope $scope): array } return [ - RuleErrorBuilder::message(sprintf('Method %s::%s() always %s, it should have return type "never".', $method->getDeclaringClass()->getDisplayName(), $method->getName(), count($helperResult) === 0 ? 'throws an exception' : 'terminates script execution'))->identifier('phpstanPlayground.never')->build(), + RuleErrorBuilder::message(sprintf( + 'Method %s::%s() always %s, it should have return type "never".', + $method->getDeclaringClass()->getDisplayName(), + $method->getName(), + count($helperResult) === 0 ? 'throws an exception' : 'terminates script execution', + ))->identifier('phpstanPlayground.never')->build(), ]; } diff --git a/src/Rules/Playground/NeverRuleHelper.php b/src/Rules/Playground/NeverRuleHelper.php index 75115df985e..9da99b88e90 100644 --- a/src/Rules/Playground/NeverRuleHelper.php +++ b/src/Rules/Playground/NeverRuleHelper.php @@ -13,7 +13,7 @@ class NeverRuleHelper /** * @return list|false */ - public function shouldReturnNever(ReturnStatementsNode $node, Type $returnType) + public function shouldReturnNever(ReturnStatementsNode $node, Type $returnType): array|false { if ($returnType instanceof NeverType && $returnType->isExplicit()) { return false; diff --git a/src/Rules/Playground/NotAnalysedTraitRule.php b/src/Rules/Playground/NotAnalysedTraitRule.php index b3dc4f0536d..7efa8044424 100644 --- a/src/Rules/Playground/NotAnalysedTraitRule.php +++ b/src/Rules/Playground/NotAnalysedTraitRule.php @@ -45,7 +45,10 @@ public function processNode(Node $node, Scope $scope): array $errors = []; foreach ($declaredTraits as [$file, $name, $line]) { - $errors[] = RuleErrorBuilder::message(sprintf('Trait %s is used zero times and is not analysed.', $name)) + $errors[] = RuleErrorBuilder::message(sprintf( + 'Trait %s is used zero times and is not analysed.', + $name, + )) ->identifier('phpstanPlayground.traitUnused') ->file($file) ->line($line) diff --git a/src/Rules/Properties/AccessPrivatePropertyThroughStaticRule.php b/src/Rules/Properties/AccessPrivatePropertyThroughStaticRule.php index 34ec250f088..d68fca010a1 100644 --- a/src/Rules/Properties/AccessPrivatePropertyThroughStaticRule.php +++ b/src/Rules/Properties/AccessPrivatePropertyThroughStaticRule.php @@ -53,7 +53,11 @@ public function processNode(Node $node, Scope $scope): array } return [ - RuleErrorBuilder::message(sprintf('Unsafe access to private property %s::$%s through static::.', $property->getDeclaringClass()->getDisplayName(), $propertyName))->identifier('staticClassAccess.privateProperty')->build(), + RuleErrorBuilder::message(sprintf( + 'Unsafe access to private property %s::$%s through static::.', + $property->getDeclaringClass()->getDisplayName(), + $propertyName, + ))->identifier('staticClassAccess.privateProperty')->build(), ]; } diff --git a/src/Rules/Properties/AccessPropertiesInAssignRule.php b/src/Rules/Properties/AccessPropertiesInAssignRule.php index 68af6be0418..e5d3d08b4ed 100644 --- a/src/Rules/Properties/AccessPropertiesInAssignRule.php +++ b/src/Rules/Properties/AccessPropertiesInAssignRule.php @@ -13,13 +13,8 @@ class AccessPropertiesInAssignRule implements Rule { - /** - * @var AccessPropertiesRule - */ - private $accessPropertiesRule; - public function __construct(AccessPropertiesRule $accessPropertiesRule) + public function __construct(private AccessPropertiesRule $accessPropertiesRule) { - $this->accessPropertiesRule = $accessPropertiesRule; } public function getNodeType(): string diff --git a/src/Rules/Properties/AccessPropertiesRule.php b/src/Rules/Properties/AccessPropertiesRule.php index 1e8dbe10466..d3dfbdde08c 100644 --- a/src/Rules/Properties/AccessPropertiesRule.php +++ b/src/Rules/Properties/AccessPropertiesRule.php @@ -28,29 +28,15 @@ class AccessPropertiesRule implements Rule { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - /** - * @var RuleLevelHelper - */ - private $ruleLevelHelper; - /** - * @var bool - */ - private $reportMagicProperties; - /** - * @var bool - */ - private $checkDynamicProperties; - public function __construct(ReflectionProvider $reflectionProvider, RuleLevelHelper $ruleLevelHelper, bool $reportMagicProperties, bool $checkDynamicProperties) + public function __construct( + private ReflectionProvider $reflectionProvider, + private RuleLevelHelper $ruleLevelHelper, + private bool $reportMagicProperties, + private bool $checkDynamicProperties, + ) { - $this->reflectionProvider = $reflectionProvider; - $this->ruleLevelHelper = $ruleLevelHelper; - $this->reportMagicProperties = $reportMagicProperties; - $this->checkDynamicProperties = $checkDynamicProperties; } + public function getNodeType(): string { return PropertyFetch::class; @@ -61,9 +47,7 @@ public function processNode(Node $node, Scope $scope): array if ($node->name instanceof Identifier) { $names = [$node->name->name]; } else { - $names = array_map(static function (ConstantStringType $type) : string { - return $type->getValue(); - }, $scope->getType($node->name)->getConstantStrings()); + $names = array_map(static fn (ConstantStringType $type): string => $type->getValue(), $scope->getType($node->name)->getConstantStrings()); } $errors = []; @@ -79,9 +63,12 @@ public function processNode(Node $node, Scope $scope): array */ private function processSingleProperty(Scope $scope, PropertyFetch $node, string $name): array { - $typeResult = $this->ruleLevelHelper->findTypeToCheck($scope, NullsafeOperatorHelper::getNullsafeShortcircuitedExprRespectingScope($scope, $node->var), sprintf('Access to property $%s on an unknown class %%s.', SprintfHelper::escapeFormatString($name)), static function (Type $type) use($name) : bool { - return $type->canAccessProperties()->yes() && $type->hasProperty($name)->yes(); - }); + $typeResult = $this->ruleLevelHelper->findTypeToCheck( + $scope, + NullsafeOperatorHelper::getNullsafeShortcircuitedExprRespectingScope($scope, $node->var), + sprintf('Access to property $%s on an unknown class %%s.', SprintfHelper::escapeFormatString($name)), + static fn (Type $type): bool => $type->canAccessProperties()->yes() && $type->hasProperty($name)->yes(), + ); $type = $typeResult->getType(); if ($type instanceof ErrorType) { return $typeResult->getUnknownClassErrors(); @@ -93,7 +80,11 @@ private function processSingleProperty(Scope $scope, PropertyFetch $node, string if ($type->canAccessProperties()->no() || $type->canAccessProperties()->maybe() && !$scope->isUndefinedExpressionAllowed($node)) { return [ - RuleErrorBuilder::message(sprintf('Cannot access property $%s on %s.', $name, $type->describe(VerbosityLevel::typeOnly())))->identifier('property.nonObject')->build(), + RuleErrorBuilder::message(sprintf( + 'Cannot access property $%s on %s.', + $name, + $type->describe(VerbosityLevel::typeOnly()), + ))->identifier('property.nonObject')->build(), ]; } @@ -133,7 +124,11 @@ private function processSingleProperty(Scope $scope, PropertyFetch $node, string return []; } return [ - RuleErrorBuilder::message(sprintf('Access to private property $%s of parent class %s.', $name, $parentClassReflection->getDisplayName()))->identifier('property.private')->build(), + RuleErrorBuilder::message(sprintf( + 'Access to private property $%s of parent class %s.', + $name, + $parentClassReflection->getDisplayName(), + ))->identifier('property.private')->build(), ]; } @@ -141,7 +136,11 @@ private function processSingleProperty(Scope $scope, PropertyFetch $node, string } } - $ruleErrorBuilder = RuleErrorBuilder::message(sprintf('Access to an undefined property %s::$%s.', $type->describe(VerbosityLevel::typeOnly()), $name))->identifier('property.notFound'); + $ruleErrorBuilder = RuleErrorBuilder::message(sprintf( + 'Access to an undefined property %s::$%s.', + $type->describe(VerbosityLevel::typeOnly()), + $name, + ))->identifier('property.notFound'); if ($typeResult->getTip() !== null) { $ruleErrorBuilder->tip($typeResult->getTip()); } else { @@ -156,7 +155,12 @@ private function processSingleProperty(Scope $scope, PropertyFetch $node, string $propertyReflection = $type->getProperty($name, $scope); if (!$scope->canAccessProperty($propertyReflection)) { return [ - RuleErrorBuilder::message(sprintf('Access to %s property %s::$%s.', $propertyReflection->isPrivate() ? 'private' : 'protected', $type->describe(VerbosityLevel::typeOnly()), $name))->identifier(sprintf('property.%s', $propertyReflection->isPrivate() ? 'private' : 'protected'))->build(), + RuleErrorBuilder::message(sprintf( + 'Access to %s property %s::$%s.', + $propertyReflection->isPrivate() ? 'private' : 'protected', + $type->describe(VerbosityLevel::typeOnly()), + $name, + ))->identifier(sprintf('property.%s', $propertyReflection->isPrivate() ? 'private' : 'protected'))->build(), ]; } diff --git a/src/Rules/Properties/AccessStaticPropertiesInAssignRule.php b/src/Rules/Properties/AccessStaticPropertiesInAssignRule.php index 1fd2892d6e7..21d6ff3e1ff 100644 --- a/src/Rules/Properties/AccessStaticPropertiesInAssignRule.php +++ b/src/Rules/Properties/AccessStaticPropertiesInAssignRule.php @@ -13,13 +13,8 @@ class AccessStaticPropertiesInAssignRule implements Rule { - /** - * @var AccessStaticPropertiesRule - */ - private $accessStaticPropertiesRule; - public function __construct(AccessStaticPropertiesRule $accessStaticPropertiesRule) + public function __construct(private AccessStaticPropertiesRule $accessStaticPropertiesRule) { - $this->accessStaticPropertiesRule = $accessStaticPropertiesRule; } public function getNodeType(): string diff --git a/src/Rules/Properties/AccessStaticPropertiesRule.php b/src/Rules/Properties/AccessStaticPropertiesRule.php index 1973ab9cf06..2f58060b5ad 100644 --- a/src/Rules/Properties/AccessStaticPropertiesRule.php +++ b/src/Rules/Properties/AccessStaticPropertiesRule.php @@ -37,24 +37,14 @@ class AccessStaticPropertiesRule implements Rule { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - /** - * @var RuleLevelHelper - */ - private $ruleLevelHelper; - /** - * @var ClassCaseSensitivityCheck - */ - private $classCaseSensitivityCheck; - public function __construct(ReflectionProvider $reflectionProvider, RuleLevelHelper $ruleLevelHelper, ClassCaseSensitivityCheck $classCaseSensitivityCheck) + public function __construct( + private ReflectionProvider $reflectionProvider, + private RuleLevelHelper $ruleLevelHelper, + private ClassCaseSensitivityCheck $classCaseSensitivityCheck, + ) { - $this->reflectionProvider = $reflectionProvider; - $this->ruleLevelHelper = $ruleLevelHelper; - $this->classCaseSensitivityCheck = $classCaseSensitivityCheck; } + public function getNodeType(): string { return StaticPropertyFetch::class; @@ -65,9 +55,7 @@ public function processNode(Node $node, Scope $scope): array if ($node->name instanceof Node\VarLikeIdentifier) { $names = [$node->name->name]; } else { - $names = array_map(static function (ConstantStringType $type) : string { - return $type->getValue(); - }, $scope->getType($node->name)->getConstantStrings()); + $names = array_map(static fn (ConstantStringType $type): string => $type->getValue(), $scope->getType($node->name)->getConstantStrings()); } $errors = []; @@ -90,19 +78,33 @@ private function processSingleProperty(Scope $scope, StaticPropertyFetch $node, if (in_array($lowercasedClass, ['self', 'static'], true)) { if (!$scope->isInClass()) { return [ - RuleErrorBuilder::message(sprintf('Accessing %s::$%s outside of class scope.', $class, $name))->identifier(sprintf('outOfClass.%s', $lowercasedClass))->build(), + RuleErrorBuilder::message(sprintf( + 'Accessing %s::$%s outside of class scope.', + $class, + $name, + ))->identifier(sprintf('outOfClass.%s', $lowercasedClass))->build(), ]; } $classType = $scope->resolveTypeByName($node->class); } elseif ($lowercasedClass === 'parent') { if (!$scope->isInClass()) { return [ - RuleErrorBuilder::message(sprintf('Accessing %s::$%s outside of class scope.', $class, $name))->identifier('outOfClass.parent')->build(), + RuleErrorBuilder::message(sprintf( + 'Accessing %s::$%s outside of class scope.', + $class, + $name, + ))->identifier('outOfClass.parent')->build(), ]; } if ($scope->getClassReflection()->getParentClass() === null) { return [ - RuleErrorBuilder::message(sprintf('%s::%s() accesses parent::$%s but %s does not extend any class.', $scope->getClassReflection()->getDisplayName(), $scope->getFunctionName(), $name, $scope->getClassReflection()->getDisplayName()))->identifier('class.noParent')->build(), + RuleErrorBuilder::message(sprintf( + '%s::%s() accesses parent::$%s but %s does not extend any class.', + $scope->getClassReflection()->getDisplayName(), + $scope->getFunctionName(), + $name, + $scope->getClassReflection()->getDisplayName(), + ))->identifier('class.noParent')->build(), ]; } @@ -124,7 +126,11 @@ private function processSingleProperty(Scope $scope, StaticPropertyFetch $node, } return [ - RuleErrorBuilder::message(sprintf('Access to static property $%s on an unknown class %s.', $name, $class)) + RuleErrorBuilder::message(sprintf( + 'Access to static property $%s on an unknown class %s.', + $name, + $class, + )) ->discoveringSymbolsTip() ->identifier('class.notFound') ->build(), @@ -136,9 +142,12 @@ private function processSingleProperty(Scope $scope, StaticPropertyFetch $node, $classType = $scope->resolveTypeByName($node->class); } } else { - $classTypeResult = $this->ruleLevelHelper->findTypeToCheck($scope, NullsafeOperatorHelper::getNullsafeShortcircuitedExprRespectingScope($scope, $node->class), sprintf('Access to static property $%s on an unknown class %%s.', SprintfHelper::escapeFormatString($name)), static function (Type $type) use($name) : bool { - return $type->canAccessProperties()->yes() && $type->hasProperty($name)->yes(); - }); + $classTypeResult = $this->ruleLevelHelper->findTypeToCheck( + $scope, + NullsafeOperatorHelper::getNullsafeShortcircuitedExprRespectingScope($scope, $node->class), + sprintf('Access to static property $%s on an unknown class %%s.', SprintfHelper::escapeFormatString($name)), + static fn (Type $type): bool => $type->canAccessProperties()->yes() && $type->hasProperty($name)->yes(), + ); $classType = $classTypeResult->getType(); if ($classType instanceof ErrorType) { return $classTypeResult->getUnknownClassErrors(); @@ -161,7 +170,11 @@ private function processSingleProperty(Scope $scope, StaticPropertyFetch $node, if ($classType->canAccessProperties()->no() || $classType->canAccessProperties()->maybe() && !$scope->isUndefinedExpressionAllowed($node)) { return array_merge($messages, [ - RuleErrorBuilder::message(sprintf('Cannot access static property $%s on %s.', $name, $typeForDescribe->describe(VerbosityLevel::typeOnly())))->identifier('staticProperty.nonObject')->build(), + RuleErrorBuilder::message(sprintf( + 'Cannot access static property $%s on %s.', + $name, + $typeForDescribe->describe(VerbosityLevel::typeOnly()), + ))->identifier('staticProperty.nonObject')->build(), ]); } @@ -186,7 +199,11 @@ private function processSingleProperty(Scope $scope, StaticPropertyFetch $node, return []; } return [ - RuleErrorBuilder::message(sprintf('Access to private static property $%s of parent class %s.', $name, $parentClassReflection->getDisplayName()))->identifier('staticProperty.private')->build(), + RuleErrorBuilder::message(sprintf( + 'Access to private static property $%s of parent class %s.', + $name, + $parentClassReflection->getDisplayName(), + ))->identifier('staticProperty.private')->build(), ]; } @@ -195,7 +212,11 @@ private function processSingleProperty(Scope $scope, StaticPropertyFetch $node, } return array_merge($messages, [ - RuleErrorBuilder::message(sprintf('Access to an undefined static property %s::$%s.', $typeForDescribe->describe(VerbosityLevel::typeOnly()), $name))->identifier('staticProperty.notFound')->build(), + RuleErrorBuilder::message(sprintf( + 'Access to an undefined static property %s::$%s.', + $typeForDescribe->describe(VerbosityLevel::typeOnly()), + $name, + ))->identifier('staticProperty.notFound')->build(), ]); } @@ -209,13 +230,22 @@ private function processSingleProperty(Scope $scope, StaticPropertyFetch $node, } return array_merge($messages, [ - RuleErrorBuilder::message(sprintf('Static access to instance property %s::$%s.', $property->getDeclaringClass()->getDisplayName(), $name))->identifier('property.staticAccess')->build(), + RuleErrorBuilder::message(sprintf( + 'Static access to instance property %s::$%s.', + $property->getDeclaringClass()->getDisplayName(), + $name, + ))->identifier('property.staticAccess')->build(), ]); } if (!$scope->canAccessProperty($property)) { return array_merge($messages, [ - RuleErrorBuilder::message(sprintf('Access to %s property $%s of class %s.', $property->isPrivate() ? 'private' : 'protected', $name, $property->getDeclaringClass()->getDisplayName()))->identifier(sprintf('staticProperty.%s', $property->isPrivate() ? 'private' : 'protected'))->build(), + RuleErrorBuilder::message(sprintf( + 'Access to %s property $%s of class %s.', + $property->isPrivate() ? 'private' : 'protected', + $name, + $property->getDeclaringClass()->getDisplayName(), + ))->identifier(sprintf('staticProperty.%s', $property->isPrivate() ? 'private' : 'protected'))->build(), ]); } diff --git a/src/Rules/Properties/DefaultValueTypesAssignedToPropertiesRule.php b/src/Rules/Properties/DefaultValueTypesAssignedToPropertiesRule.php index 9f41f3d8c97..ad0d4badc7e 100644 --- a/src/Rules/Properties/DefaultValueTypesAssignedToPropertiesRule.php +++ b/src/Rules/Properties/DefaultValueTypesAssignedToPropertiesRule.php @@ -18,13 +18,8 @@ class DefaultValueTypesAssignedToPropertiesRule implements Rule { - /** - * @var RuleLevelHelper - */ - private $ruleLevelHelper; - public function __construct(RuleLevelHelper $ruleLevelHelper) + public function __construct(private RuleLevelHelper $ruleLevelHelper) { - $this->ruleLevelHelper = $ruleLevelHelper; } public function getNodeType(): string @@ -57,7 +52,14 @@ public function processNode(Node $node, Scope $scope): array $verbosityLevel = VerbosityLevel::getRecommendedLevelByType($propertyType, $defaultValueType); return [ - RuleErrorBuilder::message(sprintf('%s %s::$%s (%s) does not accept default value of type %s.', $node->isStatic() ? 'Static property' : 'Property', $classReflection->getDisplayName(), $node->getName(), $propertyType->describe($verbosityLevel), $defaultValueType->describe($verbosityLevel))) + RuleErrorBuilder::message(sprintf( + '%s %s::$%s (%s) does not accept default value of type %s.', + $node->isStatic() ? 'Static property' : 'Property', + $classReflection->getDisplayName(), + $node->getName(), + $propertyType->describe($verbosityLevel), + $defaultValueType->describe($verbosityLevel), + )) ->identifier('property.defaultValue') ->acceptsReasonsTip($accepts->reasons) ->build(), diff --git a/src/Rules/Properties/DirectReadWritePropertiesExtensionProvider.php b/src/Rules/Properties/DirectReadWritePropertiesExtensionProvider.php index b03d79f6ac7..6ce75189d7f 100644 --- a/src/Rules/Properties/DirectReadWritePropertiesExtensionProvider.php +++ b/src/Rules/Properties/DirectReadWritePropertiesExtensionProvider.php @@ -5,16 +5,11 @@ class DirectReadWritePropertiesExtensionProvider implements ReadWritePropertiesExtensionProvider { - /** - * @var ReadWritePropertiesExtension[] - */ - private $extensions; /** * @param ReadWritePropertiesExtension[] $extensions */ - public function __construct(array $extensions) + public function __construct(private array $extensions) { - $this->extensions = $extensions; } /** diff --git a/src/Rules/Properties/ExistingClassesInPropertiesRule.php b/src/Rules/Properties/ExistingClassesInPropertiesRule.php index f250af34e55..e87973d2974 100644 --- a/src/Rules/Properties/ExistingClassesInPropertiesRule.php +++ b/src/Rules/Properties/ExistingClassesInPropertiesRule.php @@ -22,39 +22,17 @@ class ExistingClassesInPropertiesRule implements Rule { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - /** - * @var ClassCaseSensitivityCheck - */ - private $classCaseSensitivityCheck; - /** - * @var UnresolvableTypeHelper - */ - private $unresolvableTypeHelper; - /** - * @var PhpVersion - */ - private $phpVersion; - /** - * @var bool - */ - private $checkClassCaseSensitivity; - /** - * @var bool - */ - private $checkThisOnly; - public function __construct(ReflectionProvider $reflectionProvider, ClassCaseSensitivityCheck $classCaseSensitivityCheck, UnresolvableTypeHelper $unresolvableTypeHelper, PhpVersion $phpVersion, bool $checkClassCaseSensitivity, bool $checkThisOnly) + public function __construct( + private ReflectionProvider $reflectionProvider, + private ClassCaseSensitivityCheck $classCaseSensitivityCheck, + private UnresolvableTypeHelper $unresolvableTypeHelper, + private PhpVersion $phpVersion, + private bool $checkClassCaseSensitivity, + private bool $checkThisOnly, + ) { - $this->reflectionProvider = $reflectionProvider; - $this->classCaseSensitivityCheck = $classCaseSensitivityCheck; - $this->unresolvableTypeHelper = $unresolvableTypeHelper; - $this->phpVersion = $phpVersion; - $this->checkClassCaseSensitivity = $checkClassCaseSensitivity; - $this->checkThisOnly = $checkThisOnly; } + public function getNodeType(): string { return ClassPropertyNode::class; @@ -66,32 +44,50 @@ public function processNode(Node $node, Scope $scope): array if ($this->checkThisOnly) { $referencedClasses = $propertyReflection->getNativeType()->getReferencedClasses(); } else { - $referencedClasses = array_merge($propertyReflection->getNativeType()->getReferencedClasses(), $propertyReflection->getPhpDocType()->getReferencedClasses()); + $referencedClasses = array_merge( + $propertyReflection->getNativeType()->getReferencedClasses(), + $propertyReflection->getPhpDocType()->getReferencedClasses(), + ); } $errors = []; foreach ($referencedClasses as $referencedClass) { if ($this->reflectionProvider->hasClass($referencedClass)) { if ($this->reflectionProvider->getClass($referencedClass)->isTrait()) { - $errors[] = RuleErrorBuilder::message(sprintf('Property %s::$%s has invalid type %s.', $propertyReflection->getDeclaringClass()->getDisplayName(), $node->getName(), $referencedClass))->identifier('property.trait')->build(); + $errors[] = RuleErrorBuilder::message(sprintf( + 'Property %s::$%s has invalid type %s.', + $propertyReflection->getDeclaringClass()->getDisplayName(), + $node->getName(), + $referencedClass, + ))->identifier('property.trait')->build(); } continue; } - $errors[] = RuleErrorBuilder::message(sprintf('Property %s::$%s has unknown class %s as its type.', $propertyReflection->getDeclaringClass()->getDisplayName(), $node->getName(), $referencedClass))->identifier('class.notFound')->discoveringSymbolsTip()->build(); + $errors[] = RuleErrorBuilder::message(sprintf( + 'Property %s::$%s has unknown class %s as its type.', + $propertyReflection->getDeclaringClass()->getDisplayName(), + $node->getName(), + $referencedClass, + ))->identifier('class.notFound')->discoveringSymbolsTip()->build(); } if ($this->checkClassCaseSensitivity) { - $errors = array_merge($errors, $this->classCaseSensitivityCheck->checkClassNames(array_map(static function (string $class) use($node) : ClassNameNodePair { - return new ClassNameNodePair($class, $node); - }, $referencedClasses))); + $errors = array_merge( + $errors, + $this->classCaseSensitivityCheck->checkClassNames(array_map(static fn (string $class): ClassNameNodePair => new ClassNameNodePair($class, $node), $referencedClasses)), + ); } if ( $this->phpVersion->supportsPureIntersectionTypes() && $this->unresolvableTypeHelper->containsUnresolvableType($propertyReflection->getNativeType()) ) { - $errors[] = RuleErrorBuilder::message(sprintf('Property %s::$%s has unresolvable native type.', $propertyReflection->getDeclaringClass()->getDisplayName(), $node->getName()))->identifier('property.unresolvableNativeType')->build(); + $errors[] = RuleErrorBuilder::message(sprintf( + 'Property %s::$%s has unresolvable native type.', + $propertyReflection->getDeclaringClass()->getDisplayName(), + $node->getName(), + ))->identifier('property.unresolvableNativeType')->build(); } return $errors; diff --git a/src/Rules/Properties/FoundPropertyReflection.php b/src/Rules/Properties/FoundPropertyReflection.php index 6992699ba49..0132ac0d3bf 100644 --- a/src/Rules/Properties/FoundPropertyReflection.php +++ b/src/Rules/Properties/FoundPropertyReflection.php @@ -13,34 +13,16 @@ class FoundPropertyReflection implements PropertyReflection { - /** - * @var PropertyReflection - */ - private $originalPropertyReflection; - /** - * @var Scope - */ - private $scope; - /** - * @var string - */ - private $propertyName; - /** - * @var Type - */ - private $readableType; - /** - * @var Type - */ - private $writableType; - public function __construct(PropertyReflection $originalPropertyReflection, Scope $scope, string $propertyName, Type $readableType, Type $writableType) - { - $this->originalPropertyReflection = $originalPropertyReflection; - $this->scope = $scope; - $this->propertyName = $propertyName; - $this->readableType = $readableType; - $this->writableType = $writableType; + public function __construct( + private PropertyReflection $originalPropertyReflection, + private Scope $scope, + private string $propertyName, + private Type $readableType, + private Type $writableType, + ) + { } + public function getScope(): Scope { return $this->scope; diff --git a/src/Rules/Properties/InvalidCallablePropertyTypeRule.php b/src/Rules/Properties/InvalidCallablePropertyTypeRule.php index 7b1e68b8222..2a8ed41bd89 100644 --- a/src/Rules/Properties/InvalidCallablePropertyTypeRule.php +++ b/src/Rules/Properties/InvalidCallablePropertyTypeRule.php @@ -54,7 +54,11 @@ public function processNode(Node $node, Scope $scope): array } return [ - RuleErrorBuilder::message(sprintf('Property %s::$%s cannot have callable in its type declaration.', $classReflection->getDisplayName(), $node->getName()))->identifier('property.callableType')->nonIgnorable()->build(), + RuleErrorBuilder::message(sprintf( + 'Property %s::$%s cannot have callable in its type declaration.', + $classReflection->getDisplayName(), + $node->getName(), + ))->identifier('property.callableType')->nonIgnorable()->build(), ]; } diff --git a/src/Rules/Properties/LazyReadWritePropertiesExtensionProvider.php b/src/Rules/Properties/LazyReadWritePropertiesExtensionProvider.php index d99af8bbfe2..3f61fd0fb8f 100644 --- a/src/Rules/Properties/LazyReadWritePropertiesExtensionProvider.php +++ b/src/Rules/Properties/LazyReadWritePropertiesExtensionProvider.php @@ -7,16 +7,11 @@ class LazyReadWritePropertiesExtensionProvider implements ReadWritePropertiesExtensionProvider { - /** - * @var Container - */ - private $container; /** @var ReadWritePropertiesExtension[]|null */ - private $extensions = null; + private ?array $extensions = null; - public function __construct(Container $container) + public function __construct(private Container $container) { - $this->container = $container; } public function getExtensions(): array diff --git a/src/Rules/Properties/MissingPropertyTypehintRule.php b/src/Rules/Properties/MissingPropertyTypehintRule.php index faa96fadd61..f103d9752a5 100644 --- a/src/Rules/Properties/MissingPropertyTypehintRule.php +++ b/src/Rules/Properties/MissingPropertyTypehintRule.php @@ -19,13 +19,8 @@ final class MissingPropertyTypehintRule implements Rule { - /** - * @var MissingTypehintCheck - */ - private $missingTypehintCheck; - public function __construct(MissingTypehintCheck $missingTypehintCheck) + public function __construct(private MissingTypehintCheck $missingTypehintCheck) { - $this->missingTypehintCheck = $missingTypehintCheck; } public function getNodeType(): string @@ -45,28 +40,48 @@ public function processNode(Node $node, Scope $scope): array if ($propertyType instanceof MixedType && !$propertyType->isExplicitMixed()) { return [ - RuleErrorBuilder::message(sprintf('Property %s::$%s has no type specified.', $propertyReflection->getDeclaringClass()->getDisplayName(), $node->getName()))->identifier('missingType.property')->build(), + RuleErrorBuilder::message(sprintf( + 'Property %s::$%s has no type specified.', + $propertyReflection->getDeclaringClass()->getDisplayName(), + $node->getName(), + ))->identifier('missingType.property')->build(), ]; } $messages = []; foreach ($this->missingTypehintCheck->getIterableTypesWithMissingValueTypehint($propertyType) as $iterableType) { $iterableTypeDescription = $iterableType->describe(VerbosityLevel::typeOnly()); - $messages[] = RuleErrorBuilder::message(sprintf('Property %s::$%s type has no value type specified in iterable type %s.', $propertyReflection->getDeclaringClass()->getDisplayName(), $node->getName(), $iterableTypeDescription)) + $messages[] = RuleErrorBuilder::message(sprintf( + 'Property %s::$%s type has no value type specified in iterable type %s.', + $propertyReflection->getDeclaringClass()->getDisplayName(), + $node->getName(), + $iterableTypeDescription, + )) ->tip(MissingTypehintCheck::MISSING_ITERABLE_VALUE_TYPE_TIP) ->identifier('missingType.iterableValue') ->build(); } foreach ($this->missingTypehintCheck->getNonGenericObjectTypesWithGenericClass($propertyType) as [$name, $genericTypeNames]) { - $messages[] = RuleErrorBuilder::message(sprintf('Property %s::$%s with generic %s does not specify its types: %s', $propertyReflection->getDeclaringClass()->getDisplayName(), $node->getName(), $name, implode(', ', $genericTypeNames))) + $messages[] = RuleErrorBuilder::message(sprintf( + 'Property %s::$%s with generic %s does not specify its types: %s', + $propertyReflection->getDeclaringClass()->getDisplayName(), + $node->getName(), + $name, + implode(', ', $genericTypeNames), + )) ->tip(MissingTypehintCheck::TURN_OFF_NON_GENERIC_CHECK_TIP) ->identifier('missingType.generics') ->build(); } foreach ($this->missingTypehintCheck->getCallablesWithMissingSignature($propertyType) as $callableType) { - $messages[] = RuleErrorBuilder::message(sprintf('Property %s::$%s type has no signature specified for %s.', $propertyReflection->getDeclaringClass()->getDisplayName(), $node->getName(), $callableType->describe(VerbosityLevel::typeOnly())))->identifier('missingType.callable')->build(); + $messages[] = RuleErrorBuilder::message(sprintf( + 'Property %s::$%s type has no signature specified for %s.', + $propertyReflection->getDeclaringClass()->getDisplayName(), + $node->getName(), + $callableType->describe(VerbosityLevel::typeOnly()), + ))->identifier('missingType.callable')->build(); } return $messages; diff --git a/src/Rules/Properties/MissingReadOnlyByPhpDocPropertyAssignRule.php b/src/Rules/Properties/MissingReadOnlyByPhpDocPropertyAssignRule.php index 410e0d0fed3..72b30052e6b 100644 --- a/src/Rules/Properties/MissingReadOnlyByPhpDocPropertyAssignRule.php +++ b/src/Rules/Properties/MissingReadOnlyByPhpDocPropertyAssignRule.php @@ -16,14 +16,12 @@ class MissingReadOnlyByPhpDocPropertyAssignRule implements Rule { - /** - * @var ConstructorsHelper - */ - private $constructorsHelper; - public function __construct(ConstructorsHelper $constructorsHelper) + public function __construct( + private ConstructorsHelper $constructorsHelper, + ) { - $this->constructorsHelper = $constructorsHelper; } + public function getNodeType(): string { return ClassPropertiesNode::class; @@ -39,7 +37,11 @@ public function processNode(Node $node, Scope $scope): array if (!$propertyNode->isReadOnlyByPhpDoc() || $propertyNode->isReadOnly()) { continue; } - $errors[] = RuleErrorBuilder::message(sprintf('Class %s has an uninitialized @readonly property $%s. Assign it in the constructor.', $classReflection->getDisplayName(), $propertyName)) + $errors[] = RuleErrorBuilder::message(sprintf( + 'Class %s has an uninitialized @readonly property $%s. Assign it in the constructor.', + $classReflection->getDisplayName(), + $propertyName, + )) ->line($propertyNode->getStartLine()) ->identifier('property.uninitializedReadonlyByPhpDoc') ->build(); @@ -49,7 +51,11 @@ public function processNode(Node $node, Scope $scope): array if (!$propertyNode->isReadOnlyByPhpDoc() || $propertyNode->isReadOnly()) { continue; } - $errors[] = RuleErrorBuilder::message(sprintf('Access to an uninitialized @readonly property %s::$%s.', $classReflection->getDisplayName(), $propertyName)) + $errors[] = RuleErrorBuilder::message(sprintf( + 'Access to an uninitialized @readonly property %s::$%s.', + $classReflection->getDisplayName(), + $propertyName, + )) ->identifier('property.uninitializedReadonlyByPhpDoc') ->line($line) ->file($file, $fileDescription) @@ -60,7 +66,11 @@ public function processNode(Node $node, Scope $scope): array if (!$propertyNode->isReadOnlyByPhpDoc() || $propertyNode->isReadOnly()) { continue; } - $errors[] = RuleErrorBuilder::message(sprintf('@readonly property %s::$%s is already assigned.', $classReflection->getDisplayName(), $propertyName))->identifier('assign.readOnlyPropertyByPhpDoc')->line($line)->build(); + $errors[] = RuleErrorBuilder::message(sprintf( + '@readonly property %s::$%s is already assigned.', + $classReflection->getDisplayName(), + $propertyName, + ))->identifier('assign.readOnlyPropertyByPhpDoc')->line($line)->build(); } return $errors; diff --git a/src/Rules/Properties/MissingReadOnlyPropertyAssignRule.php b/src/Rules/Properties/MissingReadOnlyPropertyAssignRule.php index 465e84382fb..54d64878adf 100644 --- a/src/Rules/Properties/MissingReadOnlyPropertyAssignRule.php +++ b/src/Rules/Properties/MissingReadOnlyPropertyAssignRule.php @@ -16,14 +16,12 @@ class MissingReadOnlyPropertyAssignRule implements Rule { - /** - * @var ConstructorsHelper - */ - private $constructorsHelper; - public function __construct(ConstructorsHelper $constructorsHelper) + public function __construct( + private ConstructorsHelper $constructorsHelper, + ) { - $this->constructorsHelper = $constructorsHelper; } + public function getNodeType(): string { return ClassPropertiesNode::class; @@ -39,7 +37,11 @@ public function processNode(Node $node, Scope $scope): array if (!$propertyNode->isReadOnly()) { continue; } - $errors[] = RuleErrorBuilder::message(sprintf('Class %s has an uninitialized readonly property $%s. Assign it in the constructor.', $classReflection->getDisplayName(), $propertyName)) + $errors[] = RuleErrorBuilder::message(sprintf( + 'Class %s has an uninitialized readonly property $%s. Assign it in the constructor.', + $classReflection->getDisplayName(), + $propertyName, + )) ->line($propertyNode->getStartLine()) ->identifier('property.uninitializedReadonly') ->build(); @@ -49,7 +51,11 @@ public function processNode(Node $node, Scope $scope): array if (!$propertyNode->isReadOnly()) { continue; } - $errors[] = RuleErrorBuilder::message(sprintf('Access to an uninitialized readonly property %s::$%s.', $classReflection->getDisplayName(), $propertyName)) + $errors[] = RuleErrorBuilder::message(sprintf( + 'Access to an uninitialized readonly property %s::$%s.', + $classReflection->getDisplayName(), + $propertyName, + )) ->line($line) ->file($file, $fileDescription) ->identifier('property.uninitializedReadonly') @@ -60,7 +66,11 @@ public function processNode(Node $node, Scope $scope): array if (!$propertyNode->isReadOnly()) { continue; } - $errors[] = RuleErrorBuilder::message(sprintf('Readonly property %s::$%s is already assigned.', $classReflection->getDisplayName(), $propertyName)) + $errors[] = RuleErrorBuilder::message(sprintf( + 'Readonly property %s::$%s is already assigned.', + $classReflection->getDisplayName(), + $propertyName, + )) ->line($line) ->identifier('assign.readOnlyProperty') ->build(); diff --git a/src/Rules/Properties/OverridingPropertyRule.php b/src/Rules/Properties/OverridingPropertyRule.php index 49c551d5ade..ca10cd44348 100644 --- a/src/Rules/Properties/OverridingPropertyRule.php +++ b/src/Rules/Properties/OverridingPropertyRule.php @@ -21,19 +21,13 @@ class OverridingPropertyRule implements Rule { - /** - * @var bool - */ - private $checkPhpDocMethodSignatures; - /** - * @var bool - */ - private $reportMaybes; - public function __construct(bool $checkPhpDocMethodSignatures, bool $reportMaybes) + public function __construct( + private bool $checkPhpDocMethodSignatures, + private bool $reportMaybes, + ) { - $this->checkPhpDocMethodSignatures = $checkPhpDocMethodSignatures; - $this->reportMaybes = $reportMaybes; } + public function getNodeType(): string { return ClassPropertyNode::class; @@ -50,40 +44,100 @@ public function processNode(Node $node, Scope $scope): array $errors = []; if ($prototype->isStatic()) { if (!$node->isStatic()) { - $errors[] = RuleErrorBuilder::message(sprintf('Non-static property %s::$%s overrides static property %s::$%s.', $classReflection->getDisplayName(), $node->getName(), $prototype->getDeclaringClass()->getDisplayName(), $node->getName()))->identifier('property.nonStatic')->nonIgnorable()->build(); + $errors[] = RuleErrorBuilder::message(sprintf( + 'Non-static property %s::$%s overrides static property %s::$%s.', + $classReflection->getDisplayName(), + $node->getName(), + $prototype->getDeclaringClass()->getDisplayName(), + $node->getName(), + ))->identifier('property.nonStatic')->nonIgnorable()->build(); } } elseif ($node->isStatic()) { - $errors[] = RuleErrorBuilder::message(sprintf('Static property %s::$%s overrides non-static property %s::$%s.', $classReflection->getDisplayName(), $node->getName(), $prototype->getDeclaringClass()->getDisplayName(), $node->getName()))->identifier('property.static')->nonIgnorable()->build(); + $errors[] = RuleErrorBuilder::message(sprintf( + 'Static property %s::$%s overrides non-static property %s::$%s.', + $classReflection->getDisplayName(), + $node->getName(), + $prototype->getDeclaringClass()->getDisplayName(), + $node->getName(), + ))->identifier('property.static')->nonIgnorable()->build(); } if ($prototype->isReadOnly()) { if (!$node->isReadOnly()) { - $errors[] = RuleErrorBuilder::message(sprintf('Readwrite property %s::$%s overrides readonly property %s::$%s.', $classReflection->getDisplayName(), $node->getName(), $prototype->getDeclaringClass()->getDisplayName(), $node->getName()))->identifier('property.readWrite')->nonIgnorable()->build(); + $errors[] = RuleErrorBuilder::message(sprintf( + 'Readwrite property %s::$%s overrides readonly property %s::$%s.', + $classReflection->getDisplayName(), + $node->getName(), + $prototype->getDeclaringClass()->getDisplayName(), + $node->getName(), + ))->identifier('property.readWrite')->nonIgnorable()->build(); } } elseif ($node->isReadOnly()) { - $errors[] = RuleErrorBuilder::message(sprintf('Readonly property %s::$%s overrides readwrite property %s::$%s.', $classReflection->getDisplayName(), $node->getName(), $prototype->getDeclaringClass()->getDisplayName(), $node->getName()))->identifier('property.readOnly')->nonIgnorable()->build(); + $errors[] = RuleErrorBuilder::message(sprintf( + 'Readonly property %s::$%s overrides readwrite property %s::$%s.', + $classReflection->getDisplayName(), + $node->getName(), + $prototype->getDeclaringClass()->getDisplayName(), + $node->getName(), + ))->identifier('property.readOnly')->nonIgnorable()->build(); } if ($prototype->isPublic()) { if (!$node->isPublic()) { - $errors[] = RuleErrorBuilder::message(sprintf('%s property %s::$%s overriding public property %s::$%s should also be public.', $node->isPrivate() ? 'Private' : 'Protected', $classReflection->getDisplayName(), $node->getName(), $prototype->getDeclaringClass()->getDisplayName(), $node->getName()))->identifier('property.visibility')->nonIgnorable()->build(); + $errors[] = RuleErrorBuilder::message(sprintf( + '%s property %s::$%s overriding public property %s::$%s should also be public.', + $node->isPrivate() ? 'Private' : 'Protected', + $classReflection->getDisplayName(), + $node->getName(), + $prototype->getDeclaringClass()->getDisplayName(), + $node->getName(), + ))->identifier('property.visibility')->nonIgnorable()->build(); } } elseif ($node->isPrivate()) { - $errors[] = RuleErrorBuilder::message(sprintf('Private property %s::$%s overriding protected property %s::$%s should be protected or public.', $classReflection->getDisplayName(), $node->getName(), $prototype->getDeclaringClass()->getDisplayName(), $node->getName()))->identifier('property.visibility')->nonIgnorable()->build(); + $errors[] = RuleErrorBuilder::message(sprintf( + 'Private property %s::$%s overriding protected property %s::$%s should be protected or public.', + $classReflection->getDisplayName(), + $node->getName(), + $prototype->getDeclaringClass()->getDisplayName(), + $node->getName(), + ))->identifier('property.visibility')->nonIgnorable()->build(); } $typeErrors = []; if ($prototype->hasNativeType()) { if ($node->getNativeType() === null) { - $typeErrors[] = RuleErrorBuilder::message(sprintf('Property %s::$%s overriding property %s::$%s (%s) should also have native type %s.', $classReflection->getDisplayName(), $node->getName(), $prototype->getDeclaringClass()->getDisplayName(), $node->getName(), $prototype->getNativeType()->describe(VerbosityLevel::typeOnly()), $prototype->getNativeType()->describe(VerbosityLevel::typeOnly())))->identifier('property.missingNativeType')->nonIgnorable()->build(); + $typeErrors[] = RuleErrorBuilder::message(sprintf( + 'Property %s::$%s overriding property %s::$%s (%s) should also have native type %s.', + $classReflection->getDisplayName(), + $node->getName(), + $prototype->getDeclaringClass()->getDisplayName(), + $node->getName(), + $prototype->getNativeType()->describe(VerbosityLevel::typeOnly()), + $prototype->getNativeType()->describe(VerbosityLevel::typeOnly()), + ))->identifier('property.missingNativeType')->nonIgnorable()->build(); } else { $nativeType = ParserNodeTypeToPHPStanType::resolve($node->getNativeType(), $classReflection); if (!$prototype->getNativeType()->equals($nativeType)) { - $typeErrors[] = RuleErrorBuilder::message(sprintf('Type %s of property %s::$%s is not the same as type %s of overridden property %s::$%s.', $nativeType->describe(VerbosityLevel::typeOnly()), $classReflection->getDisplayName(), $node->getName(), $prototype->getNativeType()->describe(VerbosityLevel::typeOnly()), $prototype->getDeclaringClass()->getDisplayName(), $node->getName()))->identifier('property.nativeType')->nonIgnorable()->build(); + $typeErrors[] = RuleErrorBuilder::message(sprintf( + 'Type %s of property %s::$%s is not the same as type %s of overridden property %s::$%s.', + $nativeType->describe(VerbosityLevel::typeOnly()), + $classReflection->getDisplayName(), + $node->getName(), + $prototype->getNativeType()->describe(VerbosityLevel::typeOnly()), + $prototype->getDeclaringClass()->getDisplayName(), + $node->getName(), + ))->identifier('property.nativeType')->nonIgnorable()->build(); } } } elseif ($node->getNativeType() !== null) { - $typeErrors[] = RuleErrorBuilder::message(sprintf('Property %s::$%s (%s) overriding property %s::$%s should not have a native type.', $classReflection->getDisplayName(), $node->getName(), ParserNodeTypeToPHPStanType::resolve($node->getNativeType(), $classReflection)->describe(VerbosityLevel::typeOnly()), $prototype->getDeclaringClass()->getDisplayName(), $node->getName()))->identifier('property.extraNativeType')->nonIgnorable()->build(); + $typeErrors[] = RuleErrorBuilder::message(sprintf( + 'Property %s::$%s (%s) overriding property %s::$%s should not have a native type.', + $classReflection->getDisplayName(), + $node->getName(), + ParserNodeTypeToPHPStanType::resolve($node->getNativeType(), $classReflection)->describe(VerbosityLevel::typeOnly()), + $prototype->getDeclaringClass()->getDisplayName(), + $node->getName(), + ))->identifier('property.extraNativeType')->nonIgnorable()->build(); } $errors = array_merge($errors, $typeErrors); @@ -103,8 +157,32 @@ public function processNode(Node $node, Scope $scope): array $verbosity = VerbosityLevel::getRecommendedLevelByType($prototype->getReadableType(), $propertyReflection->getReadableType()); $isSuperType = $prototype->getReadableType()->isSuperTypeOf($propertyReflection->getReadableType()); - $canBeTurnedOffError = RuleErrorBuilder::message(sprintf('PHPDoc type %s of property %s::$%s is not the same as PHPDoc type %s of overridden property %s::$%s.', $propertyReflection->getReadableType()->describe($verbosity), $classReflection->getDisplayName(), $node->getName(), $prototype->getReadableType()->describe($verbosity), $prototype->getDeclaringClass()->getDisplayName(), $node->getName()))->identifier('property.phpDocType')->tip(sprintf("You can fix 3rd party PHPDoc types with stub files:\n %s\n This error can be turned off by setting\n %s", 'https://phpstan.org/user-guide/stub-files', 'reportMaybesInPropertyPhpDocTypes: false in your %configurationFile%.'))->build(); - $cannotBeTurnedOffError = RuleErrorBuilder::message(sprintf('PHPDoc type %s of property %s::$%s is %s PHPDoc type %s of overridden property %s::$%s.', $propertyReflection->getReadableType()->describe($verbosity), $classReflection->getDisplayName(), $node->getName(), $this->reportMaybes ? 'not the same as' : 'not covariant with', $prototype->getReadableType()->describe($verbosity), $prototype->getDeclaringClass()->getDisplayName(), $node->getName()))->identifier('property.phpDocType')->tip(sprintf("You can fix 3rd party PHPDoc types with stub files:\n %s", 'https://phpstan.org/user-guide/stub-files'))->build(); + $canBeTurnedOffError = RuleErrorBuilder::message(sprintf( + 'PHPDoc type %s of property %s::$%s is not the same as PHPDoc type %s of overridden property %s::$%s.', + $propertyReflection->getReadableType()->describe($verbosity), + $classReflection->getDisplayName(), + $node->getName(), + $prototype->getReadableType()->describe($verbosity), + $prototype->getDeclaringClass()->getDisplayName(), + $node->getName(), + ))->identifier('property.phpDocType')->tip(sprintf( + "You can fix 3rd party PHPDoc types with stub files:\n %s\n This error can be turned off by setting\n %s", + 'https://phpstan.org/user-guide/stub-files', + 'reportMaybesInPropertyPhpDocTypes: false in your %configurationFile%.', + ))->build(); + $cannotBeTurnedOffError = RuleErrorBuilder::message(sprintf( + 'PHPDoc type %s of property %s::$%s is %s PHPDoc type %s of overridden property %s::$%s.', + $propertyReflection->getReadableType()->describe($verbosity), + $classReflection->getDisplayName(), + $node->getName(), + $this->reportMaybes ? 'not the same as' : 'not covariant with', + $prototype->getReadableType()->describe($verbosity), + $prototype->getDeclaringClass()->getDisplayName(), + $node->getName(), + ))->identifier('property.phpDocType')->tip(sprintf( + "You can fix 3rd party PHPDoc types with stub files:\n %s", + 'https://phpstan.org/user-guide/stub-files', + ))->build(); if ($this->reportMaybes) { if (!$isSuperType->yes()) { $errors[] = $cannotBeTurnedOffError; diff --git a/src/Rules/Properties/PropertyAttributesRule.php b/src/Rules/Properties/PropertyAttributesRule.php index 0c08a43d070..b0d9cf2812b 100644 --- a/src/Rules/Properties/PropertyAttributesRule.php +++ b/src/Rules/Properties/PropertyAttributesRule.php @@ -14,13 +14,8 @@ class PropertyAttributesRule implements Rule { - /** - * @var AttributesCheck - */ - private $attributesCheck; - public function __construct(AttributesCheck $attributesCheck) + public function __construct(private AttributesCheck $attributesCheck) { - $this->attributesCheck = $attributesCheck; } public function getNodeType(): string @@ -30,7 +25,12 @@ public function getNodeType(): string public function processNode(Node $node, Scope $scope): array { - return $this->attributesCheck->check($scope, $node->attrGroups, Attribute::TARGET_PROPERTY, 'property'); + return $this->attributesCheck->check( + $scope, + $node->attrGroups, + Attribute::TARGET_PROPERTY, + 'property', + ); } } diff --git a/src/Rules/Properties/PropertyReflectionFinder.php b/src/Rules/Properties/PropertyReflectionFinder.php index c4e1f0ebf80..3f6cc8b000a 100644 --- a/src/Rules/Properties/PropertyReflectionFinder.php +++ b/src/Rules/Properties/PropertyReflectionFinder.php @@ -24,15 +24,20 @@ public function findPropertyReflectionsFromNode($propertyFetch, Scope $scope): a if ($propertyFetch->name instanceof Node\Identifier) { $names = [$propertyFetch->name->name]; } else { - $names = array_map(static function (ConstantStringType $name) : string { - return $name->getValue(); - }, $scope->getType($propertyFetch->name)->getConstantStrings()); + $names = array_map(static fn (ConstantStringType $name): string => $name->getValue(), $scope->getType($propertyFetch->name)->getConstantStrings()); } $reflections = []; $propertyHolderType = $scope->getType($propertyFetch->var); foreach ($names as $name) { - $reflection = $this->findPropertyReflection($propertyHolderType, $name, $propertyFetch->name instanceof Expr ? $scope->filterByTruthyValue(new Expr\BinaryOp\Identical($propertyFetch->name, new String_($name))) : $scope); + $reflection = $this->findPropertyReflection( + $propertyHolderType, + $name, + $propertyFetch->name instanceof Expr ? $scope->filterByTruthyValue(new Expr\BinaryOp\Identical( + $propertyFetch->name, + new String_($name), + )) : $scope, + ); if ($reflection === null) { continue; } @@ -52,14 +57,19 @@ public function findPropertyReflectionsFromNode($propertyFetch, Scope $scope): a if ($propertyFetch->name instanceof VarLikeIdentifier) { $names = [$propertyFetch->name->name]; } else { - $names = array_map(static function (ConstantStringType $name) : string { - return $name->getValue(); - }, $scope->getType($propertyFetch->name)->getConstantStrings()); + $names = array_map(static fn (ConstantStringType $name): string => $name->getValue(), $scope->getType($propertyFetch->name)->getConstantStrings()); } $reflections = []; foreach ($names as $name) { - $reflection = $this->findPropertyReflection($propertyHolderType, $name, $propertyFetch->name instanceof Expr ? $scope->filterByTruthyValue(new Expr\BinaryOp\Identical($propertyFetch->name, new String_($name))) : $scope); + $reflection = $this->findPropertyReflection( + $propertyHolderType, + $name, + $propertyFetch->name instanceof Expr ? $scope->filterByTruthyValue(new Expr\BinaryOp\Identical( + $propertyFetch->name, + new String_($name), + )) : $scope, + ); if ($reflection === null) { continue; } @@ -104,7 +114,13 @@ private function findPropertyReflection(Type $propertyHolderType, string $proper $originalProperty = $propertyHolderType->getProperty($propertyName, $scope); - return new FoundPropertyReflection($originalProperty, $scope, $propertyName, $originalProperty->getReadableType(), $originalProperty->getWritableType()); + return new FoundPropertyReflection( + $originalProperty, + $scope, + $propertyName, + $originalProperty->getReadableType(), + $originalProperty->getWritableType(), + ); } } diff --git a/src/Rules/Properties/ReadOnlyByPhpDocPropertyAssignRefRule.php b/src/Rules/Properties/ReadOnlyByPhpDocPropertyAssignRefRule.php index 6f6a2160a10..ce0b1d1f057 100644 --- a/src/Rules/Properties/ReadOnlyByPhpDocPropertyAssignRefRule.php +++ b/src/Rules/Properties/ReadOnlyByPhpDocPropertyAssignRefRule.php @@ -14,13 +14,8 @@ class ReadOnlyByPhpDocPropertyAssignRefRule implements Rule { - /** - * @var PropertyReflectionFinder - */ - private $propertyReflectionFinder; - public function __construct(PropertyReflectionFinder $propertyReflectionFinder) + public function __construct(private PropertyReflectionFinder $propertyReflectionFinder) { - $this->propertyReflectionFinder = $propertyReflectionFinder; } public function getNodeType(): string diff --git a/src/Rules/Properties/ReadOnlyByPhpDocPropertyAssignRule.php b/src/Rules/Properties/ReadOnlyByPhpDocPropertyAssignRule.php index cd2bff24858..9d72bb3895a 100644 --- a/src/Rules/Properties/ReadOnlyByPhpDocPropertyAssignRule.php +++ b/src/Rules/Properties/ReadOnlyByPhpDocPropertyAssignRule.php @@ -21,19 +21,13 @@ class ReadOnlyByPhpDocPropertyAssignRule implements Rule { - /** - * @var PropertyReflectionFinder - */ - private $propertyReflectionFinder; - /** - * @var ConstructorsHelper - */ - private $constructorsHelper; - public function __construct(PropertyReflectionFinder $propertyReflectionFinder, ConstructorsHelper $constructorsHelper) + public function __construct( + private PropertyReflectionFinder $propertyReflectionFinder, + private ConstructorsHelper $constructorsHelper, + ) { - $this->propertyReflectionFinder = $propertyReflectionFinder; - $this->constructorsHelper = $constructorsHelper; } + public function getNodeType(): string { return PropertyAssignNode::class; diff --git a/src/Rules/Properties/ReadOnlyPropertyAssignRefRule.php b/src/Rules/Properties/ReadOnlyPropertyAssignRefRule.php index 7e53f937964..b50e887e3b9 100644 --- a/src/Rules/Properties/ReadOnlyPropertyAssignRefRule.php +++ b/src/Rules/Properties/ReadOnlyPropertyAssignRefRule.php @@ -14,13 +14,8 @@ class ReadOnlyPropertyAssignRefRule implements Rule { - /** - * @var PropertyReflectionFinder - */ - private $propertyReflectionFinder; - public function __construct(PropertyReflectionFinder $propertyReflectionFinder) + public function __construct(private PropertyReflectionFinder $propertyReflectionFinder) { - $this->propertyReflectionFinder = $propertyReflectionFinder; } public function getNodeType(): string diff --git a/src/Rules/Properties/ReadOnlyPropertyAssignRule.php b/src/Rules/Properties/ReadOnlyPropertyAssignRule.php index d91704e7af6..47d132b6399 100644 --- a/src/Rules/Properties/ReadOnlyPropertyAssignRule.php +++ b/src/Rules/Properties/ReadOnlyPropertyAssignRule.php @@ -21,19 +21,13 @@ class ReadOnlyPropertyAssignRule implements Rule { - /** - * @var PropertyReflectionFinder - */ - private $propertyReflectionFinder; - /** - * @var ConstructorsHelper - */ - private $constructorsHelper; - public function __construct(PropertyReflectionFinder $propertyReflectionFinder, ConstructorsHelper $constructorsHelper) + public function __construct( + private PropertyReflectionFinder $propertyReflectionFinder, + private ConstructorsHelper $constructorsHelper, + ) { - $this->propertyReflectionFinder = $propertyReflectionFinder; - $this->constructorsHelper = $constructorsHelper; } + public function getNodeType(): string { return PropertyAssignNode::class; diff --git a/src/Rules/Properties/ReadOnlyPropertyRule.php b/src/Rules/Properties/ReadOnlyPropertyRule.php index ebbd647ab32..a622964ed5c 100644 --- a/src/Rules/Properties/ReadOnlyPropertyRule.php +++ b/src/Rules/Properties/ReadOnlyPropertyRule.php @@ -15,13 +15,8 @@ class ReadOnlyPropertyRule implements Rule { - /** - * @var PhpVersion - */ - private $phpVersion; - public function __construct(PhpVersion $phpVersion) + public function __construct(private PhpVersion $phpVersion) { - $this->phpVersion = $phpVersion; } public function getNodeType(): string diff --git a/src/Rules/Properties/ReadingWriteOnlyPropertiesRule.php b/src/Rules/Properties/ReadingWriteOnlyPropertiesRule.php index 01145c7279a..5e326c12a83 100644 --- a/src/Rules/Properties/ReadingWriteOnlyPropertiesRule.php +++ b/src/Rules/Properties/ReadingWriteOnlyPropertiesRule.php @@ -15,29 +15,15 @@ class ReadingWriteOnlyPropertiesRule implements Rule { - /** - * @var PropertyDescriptor - */ - private $propertyDescriptor; - /** - * @var PropertyReflectionFinder - */ - private $propertyReflectionFinder; - /** - * @var RuleLevelHelper - */ - private $ruleLevelHelper; - /** - * @var bool - */ - private $checkThisOnly; - public function __construct(PropertyDescriptor $propertyDescriptor, PropertyReflectionFinder $propertyReflectionFinder, RuleLevelHelper $ruleLevelHelper, bool $checkThisOnly) + public function __construct( + private PropertyDescriptor $propertyDescriptor, + private PropertyReflectionFinder $propertyReflectionFinder, + private RuleLevelHelper $ruleLevelHelper, + private bool $checkThisOnly, + ) { - $this->propertyDescriptor = $propertyDescriptor; - $this->propertyReflectionFinder = $propertyReflectionFinder; - $this->ruleLevelHelper = $ruleLevelHelper; - $this->checkThisOnly = $checkThisOnly; } + public function getNodeType(): string { return Node\Expr::class; @@ -76,7 +62,10 @@ public function processNode(Node $node, Scope $scope): array $propertyDescription = $this->propertyDescriptor->describeProperty($propertyReflection, $scope, $node); return [ - RuleErrorBuilder::message(sprintf('%s is not readable.', $propertyDescription)) + RuleErrorBuilder::message(sprintf( + '%s is not readable.', + $propertyDescription, + )) ->identifier('property.writeOnly') ->build(), ]; diff --git a/src/Rules/Properties/TypesAssignedToPropertiesRule.php b/src/Rules/Properties/TypesAssignedToPropertiesRule.php index cc924230541..9e15b0b33fd 100644 --- a/src/Rules/Properties/TypesAssignedToPropertiesRule.php +++ b/src/Rules/Properties/TypesAssignedToPropertiesRule.php @@ -20,19 +20,13 @@ class TypesAssignedToPropertiesRule implements Rule { - /** - * @var RuleLevelHelper - */ - private $ruleLevelHelper; - /** - * @var PropertyReflectionFinder - */ - private $propertyReflectionFinder; - public function __construct(RuleLevelHelper $ruleLevelHelper, PropertyReflectionFinder $propertyReflectionFinder) + public function __construct( + private RuleLevelHelper $ruleLevelHelper, + private PropertyReflectionFinder $propertyReflectionFinder, + ) { - $this->ruleLevelHelper = $ruleLevelHelper; - $this->propertyReflectionFinder = $propertyReflectionFinder; } + public function getNodeType(): string { return PropertyAssignNode::class; @@ -44,7 +38,10 @@ public function processNode(Node $node, Scope $scope): array $errors = []; foreach ($propertyReflections as $propertyReflection) { - $errors = array_merge($errors, $this->processSingleProperty($propertyReflection, $node->getAssignedExpr())); + $errors = array_merge($errors, $this->processSingleProperty( + $propertyReflection, + $node->getAssignedExpr(), + )); } return $errors; @@ -53,26 +50,37 @@ public function processNode(Node $node, Scope $scope): array /** * @return list */ - private function processSingleProperty(FoundPropertyReflection $propertyReflection, Node\Expr $assignedExpr) : array + private function processSingleProperty( + FoundPropertyReflection $propertyReflection, + Node\Expr $assignedExpr, + ): array { if (!$propertyReflection->isWritable()) { return []; } + $propertyType = $propertyReflection->getWritableType(); $scope = $propertyReflection->getScope(); $assignedValueType = $scope->getType($assignedExpr); + $accepts = $this->ruleLevelHelper->acceptsWithReason($propertyType, $assignedValueType, $scope->isDeclareStrictTypes()); if (!$accepts->result) { $propertyDescription = $this->describePropertyByName($propertyReflection, $propertyReflection->getName()); $verbosityLevel = VerbosityLevel::getRecommendedLevelByType($propertyType, $assignedValueType); return [ - RuleErrorBuilder::message(sprintf('%s (%s) does not accept %s.', $propertyDescription, $propertyType->describe($verbosityLevel), $assignedValueType->describe($verbosityLevel))) + RuleErrorBuilder::message(sprintf( + '%s (%s) does not accept %s.', + $propertyDescription, + $propertyType->describe($verbosityLevel), + $assignedValueType->describe($verbosityLevel), + )) ->identifier('assign.propertyType') ->acceptsReasonsTip($accepts->reasons) ->build(), ]; } + return []; } diff --git a/src/Rules/Properties/UninitializedPropertyRule.php b/src/Rules/Properties/UninitializedPropertyRule.php index a40d83c1763..a2995c38866 100644 --- a/src/Rules/Properties/UninitializedPropertyRule.php +++ b/src/Rules/Properties/UninitializedPropertyRule.php @@ -16,14 +16,12 @@ class UninitializedPropertyRule implements Rule { - /** - * @var ConstructorsHelper - */ - private $constructorsHelper; - public function __construct(ConstructorsHelper $constructorsHelper) + public function __construct( + private ConstructorsHelper $constructorsHelper, + ) { - $this->constructorsHelper = $constructorsHelper; } + public function getNodeType(): string { return ClassPropertiesNode::class; @@ -39,7 +37,11 @@ public function processNode(Node $node, Scope $scope): array if ($propertyNode->isReadOnly() || $propertyNode->isReadOnlyByPhpDoc()) { continue; } - $errors[] = RuleErrorBuilder::message(sprintf('Class %s has an uninitialized property $%s. Give it default value or assign it in the constructor.', $classReflection->getDisplayName(), $propertyName)) + $errors[] = RuleErrorBuilder::message(sprintf( + 'Class %s has an uninitialized property $%s. Give it default value or assign it in the constructor.', + $classReflection->getDisplayName(), + $propertyName, + )) ->line($propertyNode->getStartLine()) ->identifier('property.uninitialized') ->build(); @@ -49,7 +51,11 @@ public function processNode(Node $node, Scope $scope): array if ($propertyNode->isReadOnly() || $propertyNode->isReadOnlyByPhpDoc()) { continue; } - $errors[] = RuleErrorBuilder::message(sprintf('Access to an uninitialized property %s::$%s.', $classReflection->getDisplayName(), $propertyName)) + $errors[] = RuleErrorBuilder::message(sprintf( + 'Access to an uninitialized property %s::$%s.', + $classReflection->getDisplayName(), + $propertyName, + )) ->line($line) ->file($file, $fileDescription) ->identifier('property.uninitialized') diff --git a/src/Rules/Properties/WritingToReadOnlyPropertiesRule.php b/src/Rules/Properties/WritingToReadOnlyPropertiesRule.php index 8ff521c5b6a..5acc86ba91e 100644 --- a/src/Rules/Properties/WritingToReadOnlyPropertiesRule.php +++ b/src/Rules/Properties/WritingToReadOnlyPropertiesRule.php @@ -16,29 +16,15 @@ class WritingToReadOnlyPropertiesRule implements Rule { - /** - * @var RuleLevelHelper - */ - private $ruleLevelHelper; - /** - * @var PropertyDescriptor - */ - private $propertyDescriptor; - /** - * @var PropertyReflectionFinder - */ - private $propertyReflectionFinder; - /** - * @var bool - */ - private $checkThisOnly; - public function __construct(RuleLevelHelper $ruleLevelHelper, PropertyDescriptor $propertyDescriptor, PropertyReflectionFinder $propertyReflectionFinder, bool $checkThisOnly) + public function __construct( + private RuleLevelHelper $ruleLevelHelper, + private PropertyDescriptor $propertyDescriptor, + private PropertyReflectionFinder $propertyReflectionFinder, + private bool $checkThisOnly, + ) { - $this->ruleLevelHelper = $ruleLevelHelper; - $this->propertyDescriptor = $propertyDescriptor; - $this->propertyReflectionFinder = $propertyReflectionFinder; - $this->checkThisOnly = $checkThisOnly; } + public function getNodeType(): string { return PropertyAssignNode::class; @@ -68,7 +54,10 @@ public function processNode(Node $node, Scope $scope): array $propertyDescription = $this->propertyDescriptor->describeProperty($propertyReflection, $scope, $propertyFetch); return [ - RuleErrorBuilder::message(sprintf('%s is not writable.', $propertyDescription))->identifier('assign.propertyReadOnly')->build(), + RuleErrorBuilder::message(sprintf( + '%s is not writable.', + $propertyDescription, + ))->identifier('assign.propertyReadOnly')->build(), ]; } diff --git a/src/Rules/RuleErrorBuilder.php b/src/Rules/RuleErrorBuilder.php index df628441db2..35c4d4c2539 100644 --- a/src/Rules/RuleErrorBuilder.php +++ b/src/Rules/RuleErrorBuilder.php @@ -26,16 +26,13 @@ class RuleErrorBuilder private const TYPE_METADATA = 32; private const TYPE_NON_IGNORABLE = 64; - /** - * @var int - */ - private $type; + private int $type; /** @var mixed[] */ - private $properties; + private array $properties; /** @var list */ - private $tips = []; + private array $tips = []; private function __construct(string $message) { @@ -268,9 +265,7 @@ public function build(): RuleError if (count($this->tips) === 1) { $ruleError->tip = $this->tips[0]; } else { - $ruleError->tip = implode("\n", array_map(static function (string $tip) { - return sprintf('• %s', $tip); - }, $this->tips)); + $ruleError->tip = implode("\n", array_map(static fn (string $tip) => sprintf('• %s', $tip), $this->tips)); } } diff --git a/src/Rules/RuleErrors/RuleError1.php b/src/Rules/RuleErrors/RuleError1.php index 0da36157836..ef7771dea36 100644 --- a/src/Rules/RuleErrors/RuleError1.php +++ b/src/Rules/RuleErrors/RuleError1.php @@ -10,10 +10,7 @@ class RuleError1 implements RuleError { - /** - * @var string - */ - public $message; + public string $message; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError101.php b/src/Rules/RuleErrors/RuleError101.php index ca1c27b3d93..cd6a40afe39 100644 --- a/src/Rules/RuleErrors/RuleError101.php +++ b/src/Rules/RuleErrors/RuleError101.php @@ -13,23 +13,14 @@ class RuleError101 implements RuleError, FileRuleError, MetadataRuleError, NonIgnorableRuleError { - /** - * @var string - */ - public $message; + public string $message; - /** - * @var string - */ - public $file; + public string $file; - /** - * @var string - */ - public $fileDescription; + public string $fileDescription; /** @var mixed[] */ - public $metadata; + public array $metadata; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError103.php b/src/Rules/RuleErrors/RuleError103.php index 1a30615b045..a88780c2129 100644 --- a/src/Rules/RuleErrors/RuleError103.php +++ b/src/Rules/RuleErrors/RuleError103.php @@ -14,28 +14,16 @@ class RuleError103 implements RuleError, LineRuleError, FileRuleError, MetadataRuleError, NonIgnorableRuleError { - /** - * @var string - */ - public $message; + public string $message; - /** - * @var int - */ - public $line; + public int $line; - /** - * @var string - */ - public $file; + public string $file; - /** - * @var string - */ - public $fileDescription; + public string $fileDescription; /** @var mixed[] */ - public $metadata; + public array $metadata; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError105.php b/src/Rules/RuleErrors/RuleError105.php index f05c715c392..0fb7b8bc41a 100644 --- a/src/Rules/RuleErrors/RuleError105.php +++ b/src/Rules/RuleErrors/RuleError105.php @@ -13,18 +13,12 @@ class RuleError105 implements RuleError, TipRuleError, MetadataRuleError, NonIgnorableRuleError { - /** - * @var string - */ - public $message; + public string $message; - /** - * @var string - */ - public $tip; + public string $tip; /** @var mixed[] */ - public $metadata; + public array $metadata; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError107.php b/src/Rules/RuleErrors/RuleError107.php index 2ee98a65b14..35b081c092a 100644 --- a/src/Rules/RuleErrors/RuleError107.php +++ b/src/Rules/RuleErrors/RuleError107.php @@ -14,23 +14,14 @@ class RuleError107 implements RuleError, LineRuleError, TipRuleError, MetadataRuleError, NonIgnorableRuleError { - /** - * @var string - */ - public $message; + public string $message; - /** - * @var int - */ - public $line; + public int $line; - /** - * @var string - */ - public $tip; + public string $tip; /** @var mixed[] */ - public $metadata; + public array $metadata; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError109.php b/src/Rules/RuleErrors/RuleError109.php index e18b3e51584..22ddff6f250 100644 --- a/src/Rules/RuleErrors/RuleError109.php +++ b/src/Rules/RuleErrors/RuleError109.php @@ -14,28 +14,16 @@ class RuleError109 implements RuleError, FileRuleError, TipRuleError, MetadataRuleError, NonIgnorableRuleError { - /** - * @var string - */ - public $message; + public string $message; - /** - * @var string - */ - public $file; + public string $file; - /** - * @var string - */ - public $fileDescription; + public string $fileDescription; - /** - * @var string - */ - public $tip; + public string $tip; /** @var mixed[] */ - public $metadata; + public array $metadata; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError11.php b/src/Rules/RuleErrors/RuleError11.php index a531bbe7ab5..50d8bdb997a 100644 --- a/src/Rules/RuleErrors/RuleError11.php +++ b/src/Rules/RuleErrors/RuleError11.php @@ -12,20 +12,11 @@ class RuleError11 implements RuleError, LineRuleError, TipRuleError { - /** - * @var string - */ - public $message; - - /** - * @var int - */ - public $line; - - /** - * @var string - */ - public $tip; + public string $message; + + public int $line; + + public string $tip; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError111.php b/src/Rules/RuleErrors/RuleError111.php index a23470f3d16..3024d5fdf67 100644 --- a/src/Rules/RuleErrors/RuleError111.php +++ b/src/Rules/RuleErrors/RuleError111.php @@ -15,33 +15,18 @@ class RuleError111 implements RuleError, LineRuleError, FileRuleError, TipRuleError, MetadataRuleError, NonIgnorableRuleError { - /** - * @var string - */ - public $message; + public string $message; - /** - * @var int - */ - public $line; + public int $line; - /** - * @var string - */ - public $file; + public string $file; - /** - * @var string - */ - public $fileDescription; + public string $fileDescription; - /** - * @var string - */ - public $tip; + public string $tip; /** @var mixed[] */ - public $metadata; + public array $metadata; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError113.php b/src/Rules/RuleErrors/RuleError113.php index d28386fb153..ee74c1f0ace 100644 --- a/src/Rules/RuleErrors/RuleError113.php +++ b/src/Rules/RuleErrors/RuleError113.php @@ -13,18 +13,12 @@ class RuleError113 implements RuleError, IdentifierRuleError, MetadataRuleError, NonIgnorableRuleError { - /** - * @var string - */ - public $message; + public string $message; - /** - * @var string - */ - public $identifier; + public string $identifier; /** @var mixed[] */ - public $metadata; + public array $metadata; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError115.php b/src/Rules/RuleErrors/RuleError115.php index b5bbe048ff2..7b5f1af9e5b 100644 --- a/src/Rules/RuleErrors/RuleError115.php +++ b/src/Rules/RuleErrors/RuleError115.php @@ -14,23 +14,14 @@ class RuleError115 implements RuleError, LineRuleError, IdentifierRuleError, MetadataRuleError, NonIgnorableRuleError { - /** - * @var string - */ - public $message; + public string $message; - /** - * @var int - */ - public $line; + public int $line; - /** - * @var string - */ - public $identifier; + public string $identifier; /** @var mixed[] */ - public $metadata; + public array $metadata; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError117.php b/src/Rules/RuleErrors/RuleError117.php index f1af29a6167..24928027991 100644 --- a/src/Rules/RuleErrors/RuleError117.php +++ b/src/Rules/RuleErrors/RuleError117.php @@ -14,28 +14,16 @@ class RuleError117 implements RuleError, FileRuleError, IdentifierRuleError, MetadataRuleError, NonIgnorableRuleError { - /** - * @var string - */ - public $message; + public string $message; - /** - * @var string - */ - public $file; + public string $file; - /** - * @var string - */ - public $fileDescription; + public string $fileDescription; - /** - * @var string - */ - public $identifier; + public string $identifier; /** @var mixed[] */ - public $metadata; + public array $metadata; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError119.php b/src/Rules/RuleErrors/RuleError119.php index fe7a731b986..6d6fb6b7a94 100644 --- a/src/Rules/RuleErrors/RuleError119.php +++ b/src/Rules/RuleErrors/RuleError119.php @@ -15,33 +15,18 @@ class RuleError119 implements RuleError, LineRuleError, FileRuleError, IdentifierRuleError, MetadataRuleError, NonIgnorableRuleError { - /** - * @var string - */ - public $message; + public string $message; - /** - * @var int - */ - public $line; + public int $line; - /** - * @var string - */ - public $file; + public string $file; - /** - * @var string - */ - public $fileDescription; + public string $fileDescription; - /** - * @var string - */ - public $identifier; + public string $identifier; /** @var mixed[] */ - public $metadata; + public array $metadata; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError121.php b/src/Rules/RuleErrors/RuleError121.php index 3b347ffe4ce..2c8995a0b39 100644 --- a/src/Rules/RuleErrors/RuleError121.php +++ b/src/Rules/RuleErrors/RuleError121.php @@ -14,23 +14,14 @@ class RuleError121 implements RuleError, TipRuleError, IdentifierRuleError, MetadataRuleError, NonIgnorableRuleError { - /** - * @var string - */ - public $message; + public string $message; - /** - * @var string - */ - public $tip; + public string $tip; - /** - * @var string - */ - public $identifier; + public string $identifier; /** @var mixed[] */ - public $metadata; + public array $metadata; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError123.php b/src/Rules/RuleErrors/RuleError123.php index fc237c9ac2f..fedd8de5d96 100644 --- a/src/Rules/RuleErrors/RuleError123.php +++ b/src/Rules/RuleErrors/RuleError123.php @@ -15,28 +15,16 @@ class RuleError123 implements RuleError, LineRuleError, TipRuleError, IdentifierRuleError, MetadataRuleError, NonIgnorableRuleError { - /** - * @var string - */ - public $message; + public string $message; - /** - * @var int - */ - public $line; + public int $line; - /** - * @var string - */ - public $tip; + public string $tip; - /** - * @var string - */ - public $identifier; + public string $identifier; /** @var mixed[] */ - public $metadata; + public array $metadata; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError125.php b/src/Rules/RuleErrors/RuleError125.php index e5a3ea3ed5a..d64be7de954 100644 --- a/src/Rules/RuleErrors/RuleError125.php +++ b/src/Rules/RuleErrors/RuleError125.php @@ -15,33 +15,18 @@ class RuleError125 implements RuleError, FileRuleError, TipRuleError, IdentifierRuleError, MetadataRuleError, NonIgnorableRuleError { - /** - * @var string - */ - public $message; + public string $message; - /** - * @var string - */ - public $file; + public string $file; - /** - * @var string - */ - public $fileDescription; + public string $fileDescription; - /** - * @var string - */ - public $tip; + public string $tip; - /** - * @var string - */ - public $identifier; + public string $identifier; /** @var mixed[] */ - public $metadata; + public array $metadata; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError127.php b/src/Rules/RuleErrors/RuleError127.php index 719d06a2acb..dfb94ecc153 100644 --- a/src/Rules/RuleErrors/RuleError127.php +++ b/src/Rules/RuleErrors/RuleError127.php @@ -16,38 +16,20 @@ class RuleError127 implements RuleError, LineRuleError, FileRuleError, TipRuleError, IdentifierRuleError, MetadataRuleError, NonIgnorableRuleError { - /** - * @var string - */ - public $message; + public string $message; - /** - * @var int - */ - public $line; + public int $line; - /** - * @var string - */ - public $file; + public string $file; - /** - * @var string - */ - public $fileDescription; + public string $fileDescription; - /** - * @var string - */ - public $tip; + public string $tip; - /** - * @var string - */ - public $identifier; + public string $identifier; /** @var mixed[] */ - public $metadata; + public array $metadata; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError13.php b/src/Rules/RuleErrors/RuleError13.php index 407d300879a..3ecb8d62334 100644 --- a/src/Rules/RuleErrors/RuleError13.php +++ b/src/Rules/RuleErrors/RuleError13.php @@ -12,25 +12,13 @@ class RuleError13 implements RuleError, FileRuleError, TipRuleError { - /** - * @var string - */ - public $message; - - /** - * @var string - */ - public $file; - - /** - * @var string - */ - public $fileDescription; - - /** - * @var string - */ - public $tip; + public string $message; + + public string $file; + + public string $fileDescription; + + public string $tip; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError15.php b/src/Rules/RuleErrors/RuleError15.php index d300d22989d..956f7fe0f06 100644 --- a/src/Rules/RuleErrors/RuleError15.php +++ b/src/Rules/RuleErrors/RuleError15.php @@ -13,30 +13,15 @@ class RuleError15 implements RuleError, LineRuleError, FileRuleError, TipRuleError { - /** - * @var string - */ - public $message; + public string $message; - /** - * @var int - */ - public $line; + public int $line; - /** - * @var string - */ - public $file; + public string $file; - /** - * @var string - */ - public $fileDescription; + public string $fileDescription; - /** - * @var string - */ - public $tip; + public string $tip; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError17.php b/src/Rules/RuleErrors/RuleError17.php index d6922471efb..827f6a87247 100644 --- a/src/Rules/RuleErrors/RuleError17.php +++ b/src/Rules/RuleErrors/RuleError17.php @@ -11,15 +11,9 @@ class RuleError17 implements RuleError, IdentifierRuleError { - /** - * @var string - */ - public $message; - - /** - * @var string - */ - public $identifier; + public string $message; + + public string $identifier; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError19.php b/src/Rules/RuleErrors/RuleError19.php index 4dcb52d28ac..3732da9802a 100644 --- a/src/Rules/RuleErrors/RuleError19.php +++ b/src/Rules/RuleErrors/RuleError19.php @@ -12,20 +12,11 @@ class RuleError19 implements RuleError, LineRuleError, IdentifierRuleError { - /** - * @var string - */ - public $message; - - /** - * @var int - */ - public $line; - - /** - * @var string - */ - public $identifier; + public string $message; + + public int $line; + + public string $identifier; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError21.php b/src/Rules/RuleErrors/RuleError21.php index ead83c41cfa..3a6f7eb2d39 100644 --- a/src/Rules/RuleErrors/RuleError21.php +++ b/src/Rules/RuleErrors/RuleError21.php @@ -12,25 +12,13 @@ class RuleError21 implements RuleError, FileRuleError, IdentifierRuleError { - /** - * @var string - */ - public $message; - - /** - * @var string - */ - public $file; - - /** - * @var string - */ - public $fileDescription; - - /** - * @var string - */ - public $identifier; + public string $message; + + public string $file; + + public string $fileDescription; + + public string $identifier; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError23.php b/src/Rules/RuleErrors/RuleError23.php index f1e32abdd8e..911a7a05fe0 100644 --- a/src/Rules/RuleErrors/RuleError23.php +++ b/src/Rules/RuleErrors/RuleError23.php @@ -13,30 +13,15 @@ class RuleError23 implements RuleError, LineRuleError, FileRuleError, IdentifierRuleError { - /** - * @var string - */ - public $message; + public string $message; - /** - * @var int - */ - public $line; + public int $line; - /** - * @var string - */ - public $file; + public string $file; - /** - * @var string - */ - public $fileDescription; + public string $fileDescription; - /** - * @var string - */ - public $identifier; + public string $identifier; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError25.php b/src/Rules/RuleErrors/RuleError25.php index 100d662e891..1c5c6001e8d 100644 --- a/src/Rules/RuleErrors/RuleError25.php +++ b/src/Rules/RuleErrors/RuleError25.php @@ -12,20 +12,11 @@ class RuleError25 implements RuleError, TipRuleError, IdentifierRuleError { - /** - * @var string - */ - public $message; - - /** - * @var string - */ - public $tip; - - /** - * @var string - */ - public $identifier; + public string $message; + + public string $tip; + + public string $identifier; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError27.php b/src/Rules/RuleErrors/RuleError27.php index 418ce94606e..e592c0d98e2 100644 --- a/src/Rules/RuleErrors/RuleError27.php +++ b/src/Rules/RuleErrors/RuleError27.php @@ -13,25 +13,13 @@ class RuleError27 implements RuleError, LineRuleError, TipRuleError, IdentifierRuleError { - /** - * @var string - */ - public $message; - - /** - * @var int - */ - public $line; - - /** - * @var string - */ - public $tip; - - /** - * @var string - */ - public $identifier; + public string $message; + + public int $line; + + public string $tip; + + public string $identifier; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError29.php b/src/Rules/RuleErrors/RuleError29.php index 1165520694c..68f71ae5c7c 100644 --- a/src/Rules/RuleErrors/RuleError29.php +++ b/src/Rules/RuleErrors/RuleError29.php @@ -13,30 +13,15 @@ class RuleError29 implements RuleError, FileRuleError, TipRuleError, IdentifierRuleError { - /** - * @var string - */ - public $message; + public string $message; - /** - * @var string - */ - public $file; + public string $file; - /** - * @var string - */ - public $fileDescription; + public string $fileDescription; - /** - * @var string - */ - public $tip; + public string $tip; - /** - * @var string - */ - public $identifier; + public string $identifier; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError3.php b/src/Rules/RuleErrors/RuleError3.php index f54859c149b..ce5c8fffcc8 100644 --- a/src/Rules/RuleErrors/RuleError3.php +++ b/src/Rules/RuleErrors/RuleError3.php @@ -11,15 +11,9 @@ class RuleError3 implements RuleError, LineRuleError { - /** - * @var string - */ - public $message; - - /** - * @var int - */ - public $line; + public string $message; + + public int $line; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError31.php b/src/Rules/RuleErrors/RuleError31.php index 8be5d9f8751..6402df18874 100644 --- a/src/Rules/RuleErrors/RuleError31.php +++ b/src/Rules/RuleErrors/RuleError31.php @@ -14,35 +14,17 @@ class RuleError31 implements RuleError, LineRuleError, FileRuleError, TipRuleError, IdentifierRuleError { - /** - * @var string - */ - public $message; - - /** - * @var int - */ - public $line; - - /** - * @var string - */ - public $file; - - /** - * @var string - */ - public $fileDescription; - - /** - * @var string - */ - public $tip; - - /** - * @var string - */ - public $identifier; + public string $message; + + public int $line; + + public string $file; + + public string $fileDescription; + + public string $tip; + + public string $identifier; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError33.php b/src/Rules/RuleErrors/RuleError33.php index 35057175147..0f37cede7c8 100644 --- a/src/Rules/RuleErrors/RuleError33.php +++ b/src/Rules/RuleErrors/RuleError33.php @@ -11,13 +11,10 @@ class RuleError33 implements RuleError, MetadataRuleError { - /** - * @var string - */ - public $message; + public string $message; /** @var mixed[] */ - public $metadata; + public array $metadata; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError35.php b/src/Rules/RuleErrors/RuleError35.php index d66e1d00c04..65868071a83 100644 --- a/src/Rules/RuleErrors/RuleError35.php +++ b/src/Rules/RuleErrors/RuleError35.php @@ -12,18 +12,12 @@ class RuleError35 implements RuleError, LineRuleError, MetadataRuleError { - /** - * @var string - */ - public $message; + public string $message; - /** - * @var int - */ - public $line; + public int $line; /** @var mixed[] */ - public $metadata; + public array $metadata; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError37.php b/src/Rules/RuleErrors/RuleError37.php index bbcb734e282..fe0d25a3f57 100644 --- a/src/Rules/RuleErrors/RuleError37.php +++ b/src/Rules/RuleErrors/RuleError37.php @@ -12,23 +12,14 @@ class RuleError37 implements RuleError, FileRuleError, MetadataRuleError { - /** - * @var string - */ - public $message; + public string $message; - /** - * @var string - */ - public $file; + public string $file; - /** - * @var string - */ - public $fileDescription; + public string $fileDescription; /** @var mixed[] */ - public $metadata; + public array $metadata; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError39.php b/src/Rules/RuleErrors/RuleError39.php index 07e02fb3161..1a50b299fc3 100644 --- a/src/Rules/RuleErrors/RuleError39.php +++ b/src/Rules/RuleErrors/RuleError39.php @@ -13,28 +13,16 @@ class RuleError39 implements RuleError, LineRuleError, FileRuleError, MetadataRuleError { - /** - * @var string - */ - public $message; + public string $message; - /** - * @var int - */ - public $line; + public int $line; - /** - * @var string - */ - public $file; + public string $file; - /** - * @var string - */ - public $fileDescription; + public string $fileDescription; /** @var mixed[] */ - public $metadata; + public array $metadata; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError41.php b/src/Rules/RuleErrors/RuleError41.php index 80dee30e4ca..528a20c7317 100644 --- a/src/Rules/RuleErrors/RuleError41.php +++ b/src/Rules/RuleErrors/RuleError41.php @@ -12,18 +12,12 @@ class RuleError41 implements RuleError, TipRuleError, MetadataRuleError { - /** - * @var string - */ - public $message; + public string $message; - /** - * @var string - */ - public $tip; + public string $tip; /** @var mixed[] */ - public $metadata; + public array $metadata; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError43.php b/src/Rules/RuleErrors/RuleError43.php index aaed7a2af35..9992c86c9d3 100644 --- a/src/Rules/RuleErrors/RuleError43.php +++ b/src/Rules/RuleErrors/RuleError43.php @@ -13,23 +13,14 @@ class RuleError43 implements RuleError, LineRuleError, TipRuleError, MetadataRuleError { - /** - * @var string - */ - public $message; + public string $message; - /** - * @var int - */ - public $line; + public int $line; - /** - * @var string - */ - public $tip; + public string $tip; /** @var mixed[] */ - public $metadata; + public array $metadata; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError45.php b/src/Rules/RuleErrors/RuleError45.php index f01dce9d8be..d77f882c505 100644 --- a/src/Rules/RuleErrors/RuleError45.php +++ b/src/Rules/RuleErrors/RuleError45.php @@ -13,28 +13,16 @@ class RuleError45 implements RuleError, FileRuleError, TipRuleError, MetadataRuleError { - /** - * @var string - */ - public $message; + public string $message; - /** - * @var string - */ - public $file; + public string $file; - /** - * @var string - */ - public $fileDescription; + public string $fileDescription; - /** - * @var string - */ - public $tip; + public string $tip; /** @var mixed[] */ - public $metadata; + public array $metadata; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError47.php b/src/Rules/RuleErrors/RuleError47.php index 0ba18152e2a..3a1158c1761 100644 --- a/src/Rules/RuleErrors/RuleError47.php +++ b/src/Rules/RuleErrors/RuleError47.php @@ -14,33 +14,18 @@ class RuleError47 implements RuleError, LineRuleError, FileRuleError, TipRuleError, MetadataRuleError { - /** - * @var string - */ - public $message; + public string $message; - /** - * @var int - */ - public $line; + public int $line; - /** - * @var string - */ - public $file; + public string $file; - /** - * @var string - */ - public $fileDescription; + public string $fileDescription; - /** - * @var string - */ - public $tip; + public string $tip; /** @var mixed[] */ - public $metadata; + public array $metadata; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError49.php b/src/Rules/RuleErrors/RuleError49.php index 4abfa65c44e..6b8aa73a5bd 100644 --- a/src/Rules/RuleErrors/RuleError49.php +++ b/src/Rules/RuleErrors/RuleError49.php @@ -12,18 +12,12 @@ class RuleError49 implements RuleError, IdentifierRuleError, MetadataRuleError { - /** - * @var string - */ - public $message; + public string $message; - /** - * @var string - */ - public $identifier; + public string $identifier; /** @var mixed[] */ - public $metadata; + public array $metadata; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError5.php b/src/Rules/RuleErrors/RuleError5.php index 7554e2b7f8e..f8205fd24f7 100644 --- a/src/Rules/RuleErrors/RuleError5.php +++ b/src/Rules/RuleErrors/RuleError5.php @@ -11,20 +11,11 @@ class RuleError5 implements RuleError, FileRuleError { - /** - * @var string - */ - public $message; - - /** - * @var string - */ - public $file; - - /** - * @var string - */ - public $fileDescription; + public string $message; + + public string $file; + + public string $fileDescription; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError51.php b/src/Rules/RuleErrors/RuleError51.php index 0044897c102..a008143cd26 100644 --- a/src/Rules/RuleErrors/RuleError51.php +++ b/src/Rules/RuleErrors/RuleError51.php @@ -13,23 +13,14 @@ class RuleError51 implements RuleError, LineRuleError, IdentifierRuleError, MetadataRuleError { - /** - * @var string - */ - public $message; + public string $message; - /** - * @var int - */ - public $line; + public int $line; - /** - * @var string - */ - public $identifier; + public string $identifier; /** @var mixed[] */ - public $metadata; + public array $metadata; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError53.php b/src/Rules/RuleErrors/RuleError53.php index 958de0a31e6..cd8418f5b26 100644 --- a/src/Rules/RuleErrors/RuleError53.php +++ b/src/Rules/RuleErrors/RuleError53.php @@ -13,28 +13,16 @@ class RuleError53 implements RuleError, FileRuleError, IdentifierRuleError, MetadataRuleError { - /** - * @var string - */ - public $message; + public string $message; - /** - * @var string - */ - public $file; + public string $file; - /** - * @var string - */ - public $fileDescription; + public string $fileDescription; - /** - * @var string - */ - public $identifier; + public string $identifier; /** @var mixed[] */ - public $metadata; + public array $metadata; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError55.php b/src/Rules/RuleErrors/RuleError55.php index d3a44ae3a7c..4eb281839d1 100644 --- a/src/Rules/RuleErrors/RuleError55.php +++ b/src/Rules/RuleErrors/RuleError55.php @@ -14,33 +14,18 @@ class RuleError55 implements RuleError, LineRuleError, FileRuleError, IdentifierRuleError, MetadataRuleError { - /** - * @var string - */ - public $message; + public string $message; - /** - * @var int - */ - public $line; + public int $line; - /** - * @var string - */ - public $file; + public string $file; - /** - * @var string - */ - public $fileDescription; + public string $fileDescription; - /** - * @var string - */ - public $identifier; + public string $identifier; /** @var mixed[] */ - public $metadata; + public array $metadata; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError57.php b/src/Rules/RuleErrors/RuleError57.php index 47218c1d5cc..4fabd64eac3 100644 --- a/src/Rules/RuleErrors/RuleError57.php +++ b/src/Rules/RuleErrors/RuleError57.php @@ -13,23 +13,14 @@ class RuleError57 implements RuleError, TipRuleError, IdentifierRuleError, MetadataRuleError { - /** - * @var string - */ - public $message; + public string $message; - /** - * @var string - */ - public $tip; + public string $tip; - /** - * @var string - */ - public $identifier; + public string $identifier; /** @var mixed[] */ - public $metadata; + public array $metadata; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError59.php b/src/Rules/RuleErrors/RuleError59.php index 703dd6c72da..837c62602d9 100644 --- a/src/Rules/RuleErrors/RuleError59.php +++ b/src/Rules/RuleErrors/RuleError59.php @@ -14,28 +14,16 @@ class RuleError59 implements RuleError, LineRuleError, TipRuleError, IdentifierRuleError, MetadataRuleError { - /** - * @var string - */ - public $message; + public string $message; - /** - * @var int - */ - public $line; + public int $line; - /** - * @var string - */ - public $tip; + public string $tip; - /** - * @var string - */ - public $identifier; + public string $identifier; /** @var mixed[] */ - public $metadata; + public array $metadata; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError61.php b/src/Rules/RuleErrors/RuleError61.php index 596cd941ed6..a861ab2f51d 100644 --- a/src/Rules/RuleErrors/RuleError61.php +++ b/src/Rules/RuleErrors/RuleError61.php @@ -14,33 +14,18 @@ class RuleError61 implements RuleError, FileRuleError, TipRuleError, IdentifierRuleError, MetadataRuleError { - /** - * @var string - */ - public $message; + public string $message; - /** - * @var string - */ - public $file; + public string $file; - /** - * @var string - */ - public $fileDescription; + public string $fileDescription; - /** - * @var string - */ - public $tip; + public string $tip; - /** - * @var string - */ - public $identifier; + public string $identifier; /** @var mixed[] */ - public $metadata; + public array $metadata; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError63.php b/src/Rules/RuleErrors/RuleError63.php index 154256a7dca..919587a2166 100644 --- a/src/Rules/RuleErrors/RuleError63.php +++ b/src/Rules/RuleErrors/RuleError63.php @@ -15,38 +15,20 @@ class RuleError63 implements RuleError, LineRuleError, FileRuleError, TipRuleError, IdentifierRuleError, MetadataRuleError { - /** - * @var string - */ - public $message; + public string $message; - /** - * @var int - */ - public $line; + public int $line; - /** - * @var string - */ - public $file; + public string $file; - /** - * @var string - */ - public $fileDescription; + public string $fileDescription; - /** - * @var string - */ - public $tip; + public string $tip; - /** - * @var string - */ - public $identifier; + public string $identifier; /** @var mixed[] */ - public $metadata; + public array $metadata; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError65.php b/src/Rules/RuleErrors/RuleError65.php index 8a4178d8498..095f49475db 100644 --- a/src/Rules/RuleErrors/RuleError65.php +++ b/src/Rules/RuleErrors/RuleError65.php @@ -11,10 +11,7 @@ class RuleError65 implements RuleError, NonIgnorableRuleError { - /** - * @var string - */ - public $message; + public string $message; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError67.php b/src/Rules/RuleErrors/RuleError67.php index 0325a0a255a..08a214f997e 100644 --- a/src/Rules/RuleErrors/RuleError67.php +++ b/src/Rules/RuleErrors/RuleError67.php @@ -12,15 +12,9 @@ class RuleError67 implements RuleError, LineRuleError, NonIgnorableRuleError { - /** - * @var string - */ - public $message; - - /** - * @var int - */ - public $line; + public string $message; + + public int $line; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError69.php b/src/Rules/RuleErrors/RuleError69.php index 02abb6ff06d..75cd512c3ec 100644 --- a/src/Rules/RuleErrors/RuleError69.php +++ b/src/Rules/RuleErrors/RuleError69.php @@ -12,20 +12,11 @@ class RuleError69 implements RuleError, FileRuleError, NonIgnorableRuleError { - /** - * @var string - */ - public $message; - - /** - * @var string - */ - public $file; - - /** - * @var string - */ - public $fileDescription; + public string $message; + + public string $file; + + public string $fileDescription; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError7.php b/src/Rules/RuleErrors/RuleError7.php index b38ecd84257..af9559cfaa7 100644 --- a/src/Rules/RuleErrors/RuleError7.php +++ b/src/Rules/RuleErrors/RuleError7.php @@ -12,25 +12,13 @@ class RuleError7 implements RuleError, LineRuleError, FileRuleError { - /** - * @var string - */ - public $message; - - /** - * @var int - */ - public $line; - - /** - * @var string - */ - public $file; - - /** - * @var string - */ - public $fileDescription; + public string $message; + + public int $line; + + public string $file; + + public string $fileDescription; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError71.php b/src/Rules/RuleErrors/RuleError71.php index ac69e711199..652b0f1922a 100644 --- a/src/Rules/RuleErrors/RuleError71.php +++ b/src/Rules/RuleErrors/RuleError71.php @@ -13,25 +13,13 @@ class RuleError71 implements RuleError, LineRuleError, FileRuleError, NonIgnorableRuleError { - /** - * @var string - */ - public $message; - - /** - * @var int - */ - public $line; - - /** - * @var string - */ - public $file; - - /** - * @var string - */ - public $fileDescription; + public string $message; + + public int $line; + + public string $file; + + public string $fileDescription; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError73.php b/src/Rules/RuleErrors/RuleError73.php index fb514deeea8..8cdaeaa36dd 100644 --- a/src/Rules/RuleErrors/RuleError73.php +++ b/src/Rules/RuleErrors/RuleError73.php @@ -12,15 +12,9 @@ class RuleError73 implements RuleError, TipRuleError, NonIgnorableRuleError { - /** - * @var string - */ - public $message; - - /** - * @var string - */ - public $tip; + public string $message; + + public string $tip; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError75.php b/src/Rules/RuleErrors/RuleError75.php index 9e2cb99e885..3195db74542 100644 --- a/src/Rules/RuleErrors/RuleError75.php +++ b/src/Rules/RuleErrors/RuleError75.php @@ -13,20 +13,11 @@ class RuleError75 implements RuleError, LineRuleError, TipRuleError, NonIgnorableRuleError { - /** - * @var string - */ - public $message; - - /** - * @var int - */ - public $line; - - /** - * @var string - */ - public $tip; + public string $message; + + public int $line; + + public string $tip; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError77.php b/src/Rules/RuleErrors/RuleError77.php index 70540d2c3b2..09edd26a3de 100644 --- a/src/Rules/RuleErrors/RuleError77.php +++ b/src/Rules/RuleErrors/RuleError77.php @@ -13,25 +13,13 @@ class RuleError77 implements RuleError, FileRuleError, TipRuleError, NonIgnorableRuleError { - /** - * @var string - */ - public $message; - - /** - * @var string - */ - public $file; - - /** - * @var string - */ - public $fileDescription; - - /** - * @var string - */ - public $tip; + public string $message; + + public string $file; + + public string $fileDescription; + + public string $tip; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError79.php b/src/Rules/RuleErrors/RuleError79.php index e7bf0956a44..3c1fcf4d236 100644 --- a/src/Rules/RuleErrors/RuleError79.php +++ b/src/Rules/RuleErrors/RuleError79.php @@ -14,30 +14,15 @@ class RuleError79 implements RuleError, LineRuleError, FileRuleError, TipRuleError, NonIgnorableRuleError { - /** - * @var string - */ - public $message; + public string $message; - /** - * @var int - */ - public $line; + public int $line; - /** - * @var string - */ - public $file; + public string $file; - /** - * @var string - */ - public $fileDescription; + public string $fileDescription; - /** - * @var string - */ - public $tip; + public string $tip; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError81.php b/src/Rules/RuleErrors/RuleError81.php index 9a66320f878..1412335a8a5 100644 --- a/src/Rules/RuleErrors/RuleError81.php +++ b/src/Rules/RuleErrors/RuleError81.php @@ -12,15 +12,9 @@ class RuleError81 implements RuleError, IdentifierRuleError, NonIgnorableRuleError { - /** - * @var string - */ - public $message; - - /** - * @var string - */ - public $identifier; + public string $message; + + public string $identifier; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError83.php b/src/Rules/RuleErrors/RuleError83.php index f653d00d026..ceb21414561 100644 --- a/src/Rules/RuleErrors/RuleError83.php +++ b/src/Rules/RuleErrors/RuleError83.php @@ -13,20 +13,11 @@ class RuleError83 implements RuleError, LineRuleError, IdentifierRuleError, NonIgnorableRuleError { - /** - * @var string - */ - public $message; - - /** - * @var int - */ - public $line; - - /** - * @var string - */ - public $identifier; + public string $message; + + public int $line; + + public string $identifier; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError85.php b/src/Rules/RuleErrors/RuleError85.php index a738ad86ca3..a0d13d45def 100644 --- a/src/Rules/RuleErrors/RuleError85.php +++ b/src/Rules/RuleErrors/RuleError85.php @@ -13,25 +13,13 @@ class RuleError85 implements RuleError, FileRuleError, IdentifierRuleError, NonIgnorableRuleError { - /** - * @var string - */ - public $message; - - /** - * @var string - */ - public $file; - - /** - * @var string - */ - public $fileDescription; - - /** - * @var string - */ - public $identifier; + public string $message; + + public string $file; + + public string $fileDescription; + + public string $identifier; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError87.php b/src/Rules/RuleErrors/RuleError87.php index 8ca978ba98f..386b844a1be 100644 --- a/src/Rules/RuleErrors/RuleError87.php +++ b/src/Rules/RuleErrors/RuleError87.php @@ -14,30 +14,15 @@ class RuleError87 implements RuleError, LineRuleError, FileRuleError, IdentifierRuleError, NonIgnorableRuleError { - /** - * @var string - */ - public $message; + public string $message; - /** - * @var int - */ - public $line; + public int $line; - /** - * @var string - */ - public $file; + public string $file; - /** - * @var string - */ - public $fileDescription; + public string $fileDescription; - /** - * @var string - */ - public $identifier; + public string $identifier; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError89.php b/src/Rules/RuleErrors/RuleError89.php index d8101133361..3b207cf2ade 100644 --- a/src/Rules/RuleErrors/RuleError89.php +++ b/src/Rules/RuleErrors/RuleError89.php @@ -13,20 +13,11 @@ class RuleError89 implements RuleError, TipRuleError, IdentifierRuleError, NonIgnorableRuleError { - /** - * @var string - */ - public $message; - - /** - * @var string - */ - public $tip; - - /** - * @var string - */ - public $identifier; + public string $message; + + public string $tip; + + public string $identifier; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError9.php b/src/Rules/RuleErrors/RuleError9.php index 227773cdd8e..e93934d20b9 100644 --- a/src/Rules/RuleErrors/RuleError9.php +++ b/src/Rules/RuleErrors/RuleError9.php @@ -11,15 +11,9 @@ class RuleError9 implements RuleError, TipRuleError { - /** - * @var string - */ - public $message; - - /** - * @var string - */ - public $tip; + public string $message; + + public string $tip; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError91.php b/src/Rules/RuleErrors/RuleError91.php index ea1ac5c6bf8..a0fc78df5ad 100644 --- a/src/Rules/RuleErrors/RuleError91.php +++ b/src/Rules/RuleErrors/RuleError91.php @@ -14,25 +14,13 @@ class RuleError91 implements RuleError, LineRuleError, TipRuleError, IdentifierRuleError, NonIgnorableRuleError { - /** - * @var string - */ - public $message; - - /** - * @var int - */ - public $line; - - /** - * @var string - */ - public $tip; - - /** - * @var string - */ - public $identifier; + public string $message; + + public int $line; + + public string $tip; + + public string $identifier; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError93.php b/src/Rules/RuleErrors/RuleError93.php index 071b342b9bc..88b7282eb29 100644 --- a/src/Rules/RuleErrors/RuleError93.php +++ b/src/Rules/RuleErrors/RuleError93.php @@ -14,30 +14,15 @@ class RuleError93 implements RuleError, FileRuleError, TipRuleError, IdentifierRuleError, NonIgnorableRuleError { - /** - * @var string - */ - public $message; + public string $message; - /** - * @var string - */ - public $file; + public string $file; - /** - * @var string - */ - public $fileDescription; + public string $fileDescription; - /** - * @var string - */ - public $tip; + public string $tip; - /** - * @var string - */ - public $identifier; + public string $identifier; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError95.php b/src/Rules/RuleErrors/RuleError95.php index 8a9df3e2ad2..0fbb2a635b5 100644 --- a/src/Rules/RuleErrors/RuleError95.php +++ b/src/Rules/RuleErrors/RuleError95.php @@ -15,35 +15,17 @@ class RuleError95 implements RuleError, LineRuleError, FileRuleError, TipRuleError, IdentifierRuleError, NonIgnorableRuleError { - /** - * @var string - */ - public $message; - - /** - * @var int - */ - public $line; - - /** - * @var string - */ - public $file; - - /** - * @var string - */ - public $fileDescription; - - /** - * @var string - */ - public $tip; - - /** - * @var string - */ - public $identifier; + public string $message; + + public int $line; + + public string $file; + + public string $fileDescription; + + public string $tip; + + public string $identifier; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError97.php b/src/Rules/RuleErrors/RuleError97.php index 8824362eae8..da079022332 100644 --- a/src/Rules/RuleErrors/RuleError97.php +++ b/src/Rules/RuleErrors/RuleError97.php @@ -12,13 +12,10 @@ class RuleError97 implements RuleError, MetadataRuleError, NonIgnorableRuleError { - /** - * @var string - */ - public $message; + public string $message; /** @var mixed[] */ - public $metadata; + public array $metadata; public function getMessage(): string { diff --git a/src/Rules/RuleErrors/RuleError99.php b/src/Rules/RuleErrors/RuleError99.php index 7c5f80e6c5d..b26457a1e16 100644 --- a/src/Rules/RuleErrors/RuleError99.php +++ b/src/Rules/RuleErrors/RuleError99.php @@ -13,18 +13,12 @@ class RuleError99 implements RuleError, LineRuleError, MetadataRuleError, NonIgnorableRuleError { - /** - * @var string - */ - public $message; + public string $message; - /** - * @var int - */ - public $line; + public int $line; /** @var mixed[] */ - public $metadata; + public array $metadata; public function getMessage(): string { diff --git a/src/Rules/RuleLevelHelper.php b/src/Rules/RuleLevelHelper.php index b75dac02437..b3ee4cbe649 100644 --- a/src/Rules/RuleLevelHelper.php +++ b/src/Rules/RuleLevelHelper.php @@ -30,49 +30,19 @@ class RuleLevelHelper { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - /** - * @var bool - */ - private $checkNullables; - /** - * @var bool - */ - private $checkThisOnly; - /** - * @var bool - */ - private $checkUnionTypes; - /** - * @var bool - */ - private $checkExplicitMixed; - /** - * @var bool - */ - private $checkImplicitMixed; - /** - * @var bool - */ - private $newRuleLevelHelper; - /** - * @var bool - */ - private $checkBenevolentUnionTypes; - public function __construct(ReflectionProvider $reflectionProvider, bool $checkNullables, bool $checkThisOnly, bool $checkUnionTypes, bool $checkExplicitMixed, bool $checkImplicitMixed, bool $newRuleLevelHelper, bool $checkBenevolentUnionTypes) + public function __construct( + private ReflectionProvider $reflectionProvider, + private bool $checkNullables, + private bool $checkThisOnly, + private bool $checkUnionTypes, + private bool $checkExplicitMixed, + private bool $checkImplicitMixed, + private bool $newRuleLevelHelper, + private bool $checkBenevolentUnionTypes, + ) { - $this->reflectionProvider = $reflectionProvider; - $this->checkNullables = $checkNullables; - $this->checkThisOnly = $checkThisOnly; - $this->checkUnionTypes = $checkUnionTypes; - $this->checkExplicitMixed = $checkExplicitMixed; - $this->checkImplicitMixed = $checkImplicitMixed; - $this->newRuleLevelHelper = $newRuleLevelHelper; - $this->checkBenevolentUnionTypes = $checkBenevolentUnionTypes; } + /** @api */ public function isThis(Expr $expression): bool { @@ -127,11 +97,22 @@ private function transformAcceptedType(Type $acceptingType, Type $acceptedType): return new CallableType(null, null, $acceptedType->isVariadic()); } - return new CallableType($acceptedType->getParameters(), $traverse($this->transformCommonType($acceptedType->getReturnType())), $acceptedType->isVariadic()); + return new CallableType( + $acceptedType->getParameters(), + $traverse($this->transformCommonType($acceptedType->getReturnType())), + $acceptedType->isVariadic(), + ); } if ($acceptedType instanceof ClosureType) { - return new ClosureType($acceptedType->getParameters(), $traverse($this->transformCommonType($acceptedType->getReturnType())), $acceptedType->isVariadic(), $acceptedType->getTemplateTypeMap(), $acceptedType->getResolvedTemplateTypeMap(), $acceptedType->getCallSiteVarianceMap()); + return new ClosureType( + $acceptedType->getParameters(), + $traverse($this->transformCommonType($acceptedType->getReturnType())), + $acceptedType->isVariadic(), + $acceptedType->getTemplateTypeMap(), + $acceptedType->getResolvedTemplateTypeMap(), + $acceptedType->getCallSiteVarianceMap(), + ); } if ( @@ -164,7 +145,10 @@ public function acceptsWithReason(Type $acceptingType, Type $acceptedType, bool $accepts = $acceptingType->acceptsWithReason($acceptedType, $strictTypes); - return new RuleLevelHelperAcceptsResult($checkForUnion ? $accepts->yes() : !$accepts->no(), $accepts->reasons); + return new RuleLevelHelperAcceptsResult( + $checkForUnion ? $accepts->yes() : !$accepts->no(), + $accepts->reasons, + ); } $checkForUnion = $this->checkUnionTypes; @@ -261,7 +245,11 @@ public function acceptsWithReason(Type $acceptingType, Type $acceptedType, bool if ($acceptingType->isIterableAtLeastOnce()->yes() && !$acceptedType->isIterableAtLeastOnce()->yes()) { $verbosity = VerbosityLevel::getRecommendedLevelByType($acceptingType, $acceptedType); return new RuleLevelHelperAcceptsResult(false, [ - sprintf('%s %s empty.', $acceptedType->describe($verbosity), $acceptedType->isIterableAtLeastOnce()->no() ? 'is' : 'might be'), + sprintf( + '%s %s empty.', + $acceptedType->describe($verbosity), + $acceptedType->isIterableAtLeastOnce()->no() ? 'is' : 'might be', + ), ]); } @@ -274,22 +262,42 @@ public function acceptsWithReason(Type $acceptingType, Type $acceptedType, bool if ($report) { $verbosity = VerbosityLevel::getRecommendedLevelByType($acceptingType, $acceptedType); return new RuleLevelHelperAcceptsResult(false, [ - sprintf('%s %s a list.', $acceptedType->describe($verbosity), $acceptedType->isList()->no() ? 'is not' : 'might not be'), + sprintf( + '%s %s a list.', + $acceptedType->describe($verbosity), + $acceptedType->isList()->no() ? 'is not' : 'might not be', + ), ]); } } - return self::acceptsWithReason($acceptingType->getIterableKeyType(), $acceptedType->getIterableKeyType(), $strictTypes)->and(self::acceptsWithReason($acceptingType->getIterableValueType(), $acceptedType->getIterableValueType(), $strictTypes)); + return self::acceptsWithReason( + $acceptingType->getIterableKeyType(), + $acceptedType->getIterableKeyType(), + $strictTypes, + )->and(self::acceptsWithReason( + $acceptingType->getIterableValueType(), + $acceptedType->getIterableValueType(), + $strictTypes, + )); } - return new RuleLevelHelperAcceptsResult($checkForUnion ? $accepts->yes() : !$accepts->no(), $accepts->reasons); + return new RuleLevelHelperAcceptsResult( + $checkForUnion ? $accepts->yes() : !$accepts->no(), + $accepts->reasons, + ); } /** * @api * @param callable(Type $type): bool $unionTypeCriteriaCallback */ - public function findTypeToCheck(Scope $scope, Expr $var, string $unknownClassErrorPattern, callable $unionTypeCriteriaCallback) : FoundTypeResult + public function findTypeToCheck( + Scope $scope, + Expr $var, + string $unknownClassErrorPattern, + callable $unionTypeCriteriaCallback, + ): FoundTypeResult { if ($this->checkThisOnly && !$this->isThis($var)) { return new FoundTypeResult(new ErrorType(), [], [], null); @@ -298,15 +306,21 @@ public function findTypeToCheck(Scope $scope, Expr $var, string $unknownClassErr if (!$this->checkNullables && !$type->isNull()->yes()) { $type = TypeCombinator::removeNull($type); } + if ($this->newRuleLevelHelper) { if ( ($this->checkExplicitMixed || $this->checkImplicitMixed) && $type instanceof MixedType && ($type->isExplicitMixed() ? $this->checkExplicitMixed : $this->checkImplicitMixed) ) { - return new FoundTypeResult($type instanceof TemplateMixedType + return new FoundTypeResult( + $type instanceof TemplateMixedType ? $type->toStrictMixedType() - : new StrictMixedType(), [], [], null); + : new StrictMixedType(), + [], + [], + null, + ); } } else { if ( @@ -327,12 +341,14 @@ public function findTypeToCheck(Scope $scope, Expr $var, string $unknownClassErr return new FoundTypeResult(new StrictMixedType(), [], [], null); } } + if ($type instanceof MixedType || $type instanceof NeverType) { return new FoundTypeResult(new ErrorType(), [], [], null); } if ($type instanceof StaticType) { $type = $type->getStaticObjectType(); } + $errors = []; $directClassNames = $type->getObjectClassNames(); $hasClassExistsClass = false; @@ -355,12 +371,15 @@ public function findTypeToCheck(Scope $scope, Expr $var, string $unknownClassErr ->discoveringSymbolsTip() ->build(); } + if (count($errors) > 0 || $hasClassExistsClass) { return new FoundTypeResult(new ErrorType(), [], $errors, null); } + if (!$this->checkUnionTypes && $type instanceof ObjectWithoutClassType) { return new FoundTypeResult(new ErrorType(), [], [], null); } + if ( ( !$this->checkUnionTypes @@ -385,10 +404,12 @@ public function findTypeToCheck(Scope $scope, Expr $var, string $unknownClassErr return new FoundTypeResult(TypeCombinator::union(...$newTypes), $directClassNames, [], null); } } + $tip = null; if (str_contains($type->describe(VerbosityLevel::typeOnly()), 'PhpParser\\Node\\Arg|PhpParser\\Node\\VariadicPlaceholder') && !$unionTypeCriteriaCallback($type)) { $tip = 'Use ->getArgs() instead of ->args.'; } + return new FoundTypeResult($type, $directClassNames, [], $tip); } diff --git a/src/Rules/RuleLevelHelperAcceptsResult.php b/src/Rules/RuleLevelHelperAcceptsResult.php index d2dac255ec3..201408f8f5b 100644 --- a/src/Rules/RuleLevelHelperAcceptsResult.php +++ b/src/Rules/RuleLevelHelperAcceptsResult.php @@ -7,27 +7,22 @@ class RuleLevelHelperAcceptsResult { - /** - * @readonly - * @var bool - */ - public $result; - /** - * @readonly - * @var list - */ - public $reasons; /** * @param list $reasons */ - public function __construct(bool $result, array $reasons) + public function __construct( + public readonly bool $result, + public readonly array $reasons, + ) { - $this->result = $result; - $this->reasons = $reasons; } + public function and(self $other): self { - return new self($this->result && $other->result, array_merge($this->reasons, $other->reasons)); + return new self( + $this->result && $other->result, + array_merge($this->reasons, $other->reasons), + ); } /** diff --git a/src/Rules/TooWideTypehints/TooWideArrowFunctionReturnTypehintRule.php b/src/Rules/TooWideTypehints/TooWideArrowFunctionReturnTypehintRule.php index e31630a3541..2b5c809341a 100644 --- a/src/Rules/TooWideTypehints/TooWideArrowFunctionReturnTypehintRule.php +++ b/src/Rules/TooWideTypehints/TooWideArrowFunctionReturnTypehintRule.php @@ -49,7 +49,10 @@ public function processNode(Node $node, Scope $scope): array continue; } - $messages[] = RuleErrorBuilder::message(sprintf('Anonymous function never returns %s so it can be removed from the return type.', $type->describe(VerbosityLevel::getRecommendedLevelByType($type))))->identifier('return.unusedType')->build(); + $messages[] = RuleErrorBuilder::message(sprintf( + 'Anonymous function never returns %s so it can be removed from the return type.', + $type->describe(VerbosityLevel::getRecommendedLevelByType($type)), + ))->identifier('return.unusedType')->build(); } return $messages; diff --git a/src/Rules/TooWideTypehints/TooWideClosureReturnTypehintRule.php b/src/Rules/TooWideTypehints/TooWideClosureReturnTypehintRule.php index 1a8b886db35..77879f99a38 100644 --- a/src/Rules/TooWideTypehints/TooWideClosureReturnTypehintRule.php +++ b/src/Rules/TooWideTypehints/TooWideClosureReturnTypehintRule.php @@ -71,7 +71,10 @@ public function processNode(Node $node, Scope $scope): array continue; } - $messages[] = RuleErrorBuilder::message(sprintf('Anonymous function never returns %s so it can be removed from the return type.', $type->describe(VerbosityLevel::getRecommendedLevelByType($type))))->identifier('return.unusedType')->build(); + $messages[] = RuleErrorBuilder::message(sprintf( + 'Anonymous function never returns %s so it can be removed from the return type.', + $type->describe(VerbosityLevel::getRecommendedLevelByType($type)), + ))->identifier('return.unusedType')->build(); } return $messages; diff --git a/src/Rules/TooWideTypehints/TooWideFunctionReturnTypehintRule.php b/src/Rules/TooWideTypehints/TooWideFunctionReturnTypehintRule.php index bb766e350f4..db2d633fa54 100644 --- a/src/Rules/TooWideTypehints/TooWideFunctionReturnTypehintRule.php +++ b/src/Rules/TooWideTypehints/TooWideFunctionReturnTypehintRule.php @@ -75,7 +75,11 @@ public function processNode(Node $node, Scope $scope): array } } - $messages[] = RuleErrorBuilder::message(sprintf('Function %s() never returns %s so it can be removed from the return type.', $function->getName(), $type->describe(VerbosityLevel::getRecommendedLevelByType($type))))->identifier('return.unusedType')->build(); + $messages[] = RuleErrorBuilder::message(sprintf( + 'Function %s() never returns %s so it can be removed from the return type.', + $function->getName(), + $type->describe(VerbosityLevel::getRecommendedLevelByType($type)), + ))->identifier('return.unusedType')->build(); } return $messages; diff --git a/src/Rules/TooWideTypehints/TooWideMethodReturnTypehintRule.php b/src/Rules/TooWideTypehints/TooWideMethodReturnTypehintRule.php index d2506ea4e6f..2125bbbc151 100644 --- a/src/Rules/TooWideTypehints/TooWideMethodReturnTypehintRule.php +++ b/src/Rules/TooWideTypehints/TooWideMethodReturnTypehintRule.php @@ -21,18 +21,8 @@ class TooWideMethodReturnTypehintRule implements Rule { - /** - * @var bool - */ - private $checkProtectedAndPublicMethods; - /** - * @var bool - */ - private $alwaysCheckFinal; - public function __construct(bool $checkProtectedAndPublicMethods, bool $alwaysCheckFinal) + public function __construct(private bool $checkProtectedAndPublicMethods, private bool $alwaysCheckFinal) { - $this->checkProtectedAndPublicMethods = $checkProtectedAndPublicMethods; - $this->alwaysCheckFinal = $alwaysCheckFinal; } public function getNodeType(): string @@ -118,7 +108,12 @@ public function processNode(Node $node, Scope $scope): array } } - $messages[] = RuleErrorBuilder::message(sprintf('Method %s::%s() never returns %s so it can be removed from the return type.', $method->getDeclaringClass()->getDisplayName(), $method->getName(), $type->describe(VerbosityLevel::getRecommendedLevelByType($type))))->identifier('return.unusedType')->build(); + $messages[] = RuleErrorBuilder::message(sprintf( + 'Method %s::%s() never returns %s so it can be removed from the return type.', + $method->getDeclaringClass()->getDisplayName(), + $method->getName(), + $type->describe(VerbosityLevel::getRecommendedLevelByType($type)), + ))->identifier('return.unusedType')->build(); } return $messages; diff --git a/src/Rules/Traits/ConflictingTraitConstantsRule.php b/src/Rules/Traits/ConflictingTraitConstantsRule.php index 58fe01b5d4f..73612f30747 100644 --- a/src/Rules/Traits/ConflictingTraitConstantsRule.php +++ b/src/Rules/Traits/ConflictingTraitConstantsRule.php @@ -22,13 +22,8 @@ class ConflictingTraitConstantsRule implements Rule { - /** - * @var InitializerExprTypeResolver - */ - private $initializerExprTypeResolver; - public function __construct(InitializerExprTypeResolver $initializerExprTypeResolver) + public function __construct(private InitializerExprTypeResolver $initializerExprTypeResolver) { - $this->initializerExprTypeResolver = $initializerExprTypeResolver; } public function getNodeType(): string @@ -74,36 +69,72 @@ private function processSingleConstant(ClassReflection $classReflection, Reflect $errors = []; if ($traitConstant->isPublic()) { if ($classConst->isProtected()) { - $errors[] = RuleErrorBuilder::message(sprintf('Protected constant %s::%s overriding public constant %s::%s should also be public.', $classReflection->getDisplayName(), $traitConstant->getName(), $traitConstant->getDeclaringClass()->getName(), $traitConstant->getName())) + $errors[] = RuleErrorBuilder::message(sprintf( + 'Protected constant %s::%s overriding public constant %s::%s should also be public.', + $classReflection->getDisplayName(), + $traitConstant->getName(), + $traitConstant->getDeclaringClass()->getName(), + $traitConstant->getName(), + )) ->nonIgnorable() ->identifier('classConstant.visibility') ->build(); } elseif ($classConst->isPrivate()) { - $errors[] = RuleErrorBuilder::message(sprintf('Private constant %s::%s overriding public constant %s::%s should also be public.', $classReflection->getDisplayName(), $traitConstant->getName(), $traitConstant->getDeclaringClass()->getName(), $traitConstant->getName())) + $errors[] = RuleErrorBuilder::message(sprintf( + 'Private constant %s::%s overriding public constant %s::%s should also be public.', + $classReflection->getDisplayName(), + $traitConstant->getName(), + $traitConstant->getDeclaringClass()->getName(), + $traitConstant->getName(), + )) ->nonIgnorable() ->identifier('classConstant.visibility') ->build(); } } elseif ($traitConstant->isProtected()) { if ($classConst->isPublic()) { - $errors[] = RuleErrorBuilder::message(sprintf('Public constant %s::%s overriding protected constant %s::%s should also be protected.', $classReflection->getDisplayName(), $traitConstant->getName(), $traitConstant->getDeclaringClass()->getName(), $traitConstant->getName())) + $errors[] = RuleErrorBuilder::message(sprintf( + 'Public constant %s::%s overriding protected constant %s::%s should also be protected.', + $classReflection->getDisplayName(), + $traitConstant->getName(), + $traitConstant->getDeclaringClass()->getName(), + $traitConstant->getName(), + )) ->nonIgnorable() ->identifier('classConstant.visibility') ->build(); } elseif ($classConst->isPrivate()) { - $errors[] = RuleErrorBuilder::message(sprintf('Private constant %s::%s overriding protected constant %s::%s should also be protected.', $classReflection->getDisplayName(), $traitConstant->getName(), $traitConstant->getDeclaringClass()->getName(), $traitConstant->getName())) + $errors[] = RuleErrorBuilder::message(sprintf( + 'Private constant %s::%s overriding protected constant %s::%s should also be protected.', + $classReflection->getDisplayName(), + $traitConstant->getName(), + $traitConstant->getDeclaringClass()->getName(), + $traitConstant->getName(), + )) ->nonIgnorable() ->identifier('classConstant.visibility') ->build(); } } elseif ($traitConstant->isPrivate()) { if ($classConst->isPublic()) { - $errors[] = RuleErrorBuilder::message(sprintf('Public constant %s::%s overriding private constant %s::%s should also be private.', $classReflection->getDisplayName(), $traitConstant->getName(), $traitConstant->getDeclaringClass()->getName(), $traitConstant->getName())) + $errors[] = RuleErrorBuilder::message(sprintf( + 'Public constant %s::%s overriding private constant %s::%s should also be private.', + $classReflection->getDisplayName(), + $traitConstant->getName(), + $traitConstant->getDeclaringClass()->getName(), + $traitConstant->getName(), + )) ->nonIgnorable() ->identifier('classConstant.visibility') ->build(); } elseif ($classConst->isProtected()) { - $errors[] = RuleErrorBuilder::message(sprintf('Protected constant %s::%s overriding private constant %s::%s should also be private.', $classReflection->getDisplayName(), $traitConstant->getName(), $traitConstant->getDeclaringClass()->getName(), $traitConstant->getName())) + $errors[] = RuleErrorBuilder::message(sprintf( + 'Protected constant %s::%s overriding private constant %s::%s should also be private.', + $classReflection->getDisplayName(), + $traitConstant->getName(), + $traitConstant->getDeclaringClass()->getName(), + $traitConstant->getName(), + )) ->nonIgnorable() ->identifier('classConstant.visibility') ->build(); @@ -112,13 +143,25 @@ private function processSingleConstant(ClassReflection $classReflection, Reflect if ($traitConstant->isFinal()) { if (!$classConst->isFinal()) { - $errors[] = RuleErrorBuilder::message(sprintf('Non-final constant %s::%s overriding final constant %s::%s should also be final.', $classReflection->getDisplayName(), $traitConstant->getName(), $traitConstant->getDeclaringClass()->getName(), $traitConstant->getName())) + $errors[] = RuleErrorBuilder::message(sprintf( + 'Non-final constant %s::%s overriding final constant %s::%s should also be final.', + $classReflection->getDisplayName(), + $traitConstant->getName(), + $traitConstant->getDeclaringClass()->getName(), + $traitConstant->getName(), + )) ->nonIgnorable() ->identifier('classConstant.nonFinal') ->build(); } } elseif ($classConst->isFinal()) { - $errors[] = RuleErrorBuilder::message(sprintf('Final constant %s::%s overriding non-final constant %s::%s should also be non-final.', $classReflection->getDisplayName(), $traitConstant->getName(), $traitConstant->getDeclaringClass()->getName(), $traitConstant->getName())) + $errors[] = RuleErrorBuilder::message(sprintf( + 'Final constant %s::%s overriding non-final constant %s::%s should also be non-final.', + $classReflection->getDisplayName(), + $traitConstant->getName(), + $traitConstant->getDeclaringClass()->getName(), + $traitConstant->getName(), + )) ->nonIgnorable() ->identifier('classConstant.final') ->build(); @@ -130,14 +173,29 @@ private function processSingleConstant(ClassReflection $classReflection, Reflect if ($traitNativeType === null) { if ($constantNativeType !== null) { $constantNativeTypeType = ParserNodeTypeToPHPStanType::resolve($constantNativeType, $classReflection); - $errors[] = RuleErrorBuilder::message(sprintf('Constant %s::%s (%s) overriding constant %s::%s should not have a native type.', $classReflection->getDisplayName(), $traitConstant->getName(), $constantNativeTypeType->describe(VerbosityLevel::typeOnly()), $traitConstant->getDeclaringClass()->getName(), $traitConstant->getName())) + $errors[] = RuleErrorBuilder::message(sprintf( + 'Constant %s::%s (%s) overriding constant %s::%s should not have a native type.', + $classReflection->getDisplayName(), + $traitConstant->getName(), + $constantNativeTypeType->describe(VerbosityLevel::typeOnly()), + $traitConstant->getDeclaringClass()->getName(), + $traitConstant->getName(), + )) ->nonIgnorable() ->identifier('classConstant.nativeType') ->build(); } } elseif ($constantNativeType === null) { $traitNativeTypeType = TypehintHelper::decideTypeFromReflection($traitNativeType, null, $traitDeclaringClass->getName()); - $errors[] = RuleErrorBuilder::message(sprintf('Constant %s::%s overriding constant %s::%s (%s) should also have native type %s.', $classReflection->getDisplayName(), $traitConstant->getName(), $traitConstant->getDeclaringClass()->getName(), $traitConstant->getName(), $traitNativeTypeType->describe(VerbosityLevel::typeOnly()), $traitNativeTypeType->describe(VerbosityLevel::typeOnly()))) + $errors[] = RuleErrorBuilder::message(sprintf( + 'Constant %s::%s overriding constant %s::%s (%s) should also have native type %s.', + $classReflection->getDisplayName(), + $traitConstant->getName(), + $traitConstant->getDeclaringClass()->getName(), + $traitConstant->getName(), + $traitNativeTypeType->describe(VerbosityLevel::typeOnly()), + $traitNativeTypeType->describe(VerbosityLevel::typeOnly()), + )) ->nonIgnorable() ->identifier('classConstant.missingNativeType') ->build(); @@ -145,7 +203,16 @@ private function processSingleConstant(ClassReflection $classReflection, Reflect $traitNativeTypeType = TypehintHelper::decideTypeFromReflection($traitNativeType, null, $traitDeclaringClass->getName()); $constantNativeTypeType = ParserNodeTypeToPHPStanType::resolve($constantNativeType, $classReflection); if (!$traitNativeTypeType->equals($constantNativeTypeType)) { - $errors[] = RuleErrorBuilder::message(sprintf('Constant %s::%s (%s) overriding constant %s::%s (%s) should have the same native type %s.', $classReflection->getDisplayName(), $traitConstant->getName(), $constantNativeTypeType->describe(VerbosityLevel::typeOnly()), $traitConstant->getDeclaringClass()->getName(), $traitConstant->getName(), $traitNativeTypeType->describe(VerbosityLevel::typeOnly()), $traitNativeTypeType->describe(VerbosityLevel::typeOnly()))) + $errors[] = RuleErrorBuilder::message(sprintf( + 'Constant %s::%s (%s) overriding constant %s::%s (%s) should have the same native type %s.', + $classReflection->getDisplayName(), + $traitConstant->getName(), + $constantNativeTypeType->describe(VerbosityLevel::typeOnly()), + $traitConstant->getDeclaringClass()->getName(), + $traitConstant->getName(), + $traitNativeTypeType->describe(VerbosityLevel::typeOnly()), + $traitNativeTypeType->describe(VerbosityLevel::typeOnly()), + )) ->nonIgnorable() ->identifier('classConstant.nativeType') ->build(); @@ -153,9 +220,23 @@ private function processSingleConstant(ClassReflection $classReflection, Reflect } $classConstantValueType = $this->initializerExprTypeResolver->getType($valueExpr, InitializerExprContext::fromClassReflection($classReflection)); - $traitConstantValueType = $this->initializerExprTypeResolver->getType($traitConstant->getValueExpression(), InitializerExprContext::fromClass($traitDeclaringClass->getName(), $traitDeclaringClass->getFileName() !== false ? $traitDeclaringClass->getFileName() : null)); + $traitConstantValueType = $this->initializerExprTypeResolver->getType( + $traitConstant->getValueExpression(), + InitializerExprContext::fromClass( + $traitDeclaringClass->getName(), + $traitDeclaringClass->getFileName() !== false ? $traitDeclaringClass->getFileName() : null, + ), + ); if (!$classConstantValueType->equals($traitConstantValueType)) { - $errors[] = RuleErrorBuilder::message(sprintf('Constant %s::%s with value %s overriding constant %s::%s with different value %s should have the same value.', $classReflection->getDisplayName(), $traitConstant->getName(), $classConstantValueType->describe(VerbosityLevel::value()), $traitConstant->getDeclaringClass()->getName(), $traitConstant->getName(), $traitConstantValueType->describe(VerbosityLevel::value()))) + $errors[] = RuleErrorBuilder::message(sprintf( + 'Constant %s::%s with value %s overriding constant %s::%s with different value %s should have the same value.', + $classReflection->getDisplayName(), + $traitConstant->getName(), + $classConstantValueType->describe(VerbosityLevel::value()), + $traitConstant->getDeclaringClass()->getName(), + $traitConstant->getName(), + $traitConstantValueType->describe(VerbosityLevel::value()), + )) ->nonIgnorable() ->identifier('classConstant.value') ->build(); diff --git a/src/Rules/Traits/ConstantsInTraitsRule.php b/src/Rules/Traits/ConstantsInTraitsRule.php index c10279651d7..69485685401 100644 --- a/src/Rules/Traits/ConstantsInTraitsRule.php +++ b/src/Rules/Traits/ConstantsInTraitsRule.php @@ -14,13 +14,8 @@ class ConstantsInTraitsRule implements Rule { - /** - * @var PhpVersion - */ - private $phpVersion; - public function __construct(PhpVersion $phpVersion) + public function __construct(private PhpVersion $phpVersion) { - $this->phpVersion = $phpVersion; } public function getNodeType(): string @@ -42,7 +37,9 @@ public function processNode(Node $node, Scope $scope): array } return [ - RuleErrorBuilder::message('Constant is declared inside a trait but is only supported on PHP 8.2 and later.')->identifier('classConstant.inTrait')->nonIgnorable()->build(), + RuleErrorBuilder::message( + 'Constant is declared inside a trait but is only supported on PHP 8.2 and later.', + )->identifier('classConstant.inTrait')->nonIgnorable()->build(), ]; } diff --git a/src/Rules/Traits/NotAnalysedTraitRule.php b/src/Rules/Traits/NotAnalysedTraitRule.php index bb7dd0015b6..3ae9b74c461 100644 --- a/src/Rules/Traits/NotAnalysedTraitRule.php +++ b/src/Rules/Traits/NotAnalysedTraitRule.php @@ -47,7 +47,10 @@ public function processNode(Node $node, Scope $scope): array $errors = []; foreach ($declaredTraits as [$file, $name, $line]) { - $errors[] = RuleErrorBuilder::message(sprintf('Trait %s is used zero times and is not analysed.', $name)) + $errors[] = RuleErrorBuilder::message(sprintf( + 'Trait %s is used zero times and is not analysed.', + $name, + )) ->file($file) ->line($line) ->identifier('trait.unused') diff --git a/src/Rules/Traits/TraitUseCollector.php b/src/Rules/Traits/TraitUseCollector.php index a4eedb9b21d..1bd3f82cba3 100644 --- a/src/Rules/Traits/TraitUseCollector.php +++ b/src/Rules/Traits/TraitUseCollector.php @@ -21,9 +21,7 @@ public function getNodeType(): string public function processNode(Node $node, Scope $scope) { - return array_values(array_map(static function (Node\Name $traitName) { - return $traitName->toString(); - }, $node->traits)); + return array_values(array_map(static fn (Node\Name $traitName) => $traitName->toString(), $node->traits)); } } diff --git a/src/Rules/UnusedFunctionParametersCheck.php b/src/Rules/UnusedFunctionParametersCheck.php index ce6af6056d4..46f5d174be6 100644 --- a/src/Rules/UnusedFunctionParametersCheck.php +++ b/src/Rules/UnusedFunctionParametersCheck.php @@ -16,43 +16,47 @@ class UnusedFunctionParametersCheck { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - public function __construct(ReflectionProvider $reflectionProvider) - { - $this->reflectionProvider = $reflectionProvider; - } + public function __construct(private ReflectionProvider $reflectionProvider) + { + } /** - * @param string[] $parameterNames - * @param Node[] $statements - * @param 'constructor.unusedParameter'|'closure.unusedUse' $identifier - * @return list - */ - public function getUnusedParameters(Scope $scope, array $parameterNames, array $statements, string $unusedParameterMessage, string $identifier) : array - { - $unusedParameters = array_fill_keys($parameterNames, true); - foreach ($this->getUsedVariables($scope, $statements) as $variableName) { - if (!isset($unusedParameters[$variableName])) { - continue; - } - - unset($unusedParameters[$variableName]); - } - $errors = []; - foreach (array_keys($unusedParameters) as $name) { - $errors[] = RuleErrorBuilder::message(sprintf($unusedParameterMessage, $name))->identifier($identifier)->build(); - } - return $errors; + * @param string[] $parameterNames + * @param Node[] $statements + * @param 'constructor.unusedParameter'|'closure.unusedUse' $identifier + * @return list + */ + public function getUnusedParameters( + Scope $scope, + array $parameterNames, + array $statements, + string $unusedParameterMessage, + string $identifier, + ): array + { + $unusedParameters = array_fill_keys($parameterNames, true); + foreach ($this->getUsedVariables($scope, $statements) as $variableName) { + if (!isset($unusedParameters[$variableName])) { + continue; + } + + unset($unusedParameters[$variableName]); + } + $errors = []; + foreach (array_keys($unusedParameters) as $name) { + $errors[] = RuleErrorBuilder::message( + sprintf($unusedParameterMessage, $name), + )->identifier($identifier)->build(); } + return $errors; + } + /** - * @param Node[]|Node|scalar|null $node - * @return string[] - */ - private function getUsedVariables(Scope $scope, $node): array + * @param Node[]|Node|scalar|null $node + * @return string[] + */ + private function getUsedVariables(Scope $scope, $node): array { $variableNames = []; if ($node instanceof Node) { diff --git a/src/Rules/Variables/CompactVariablesRule.php b/src/Rules/Variables/CompactVariablesRule.php index b768f40dfb1..c6324f76787 100644 --- a/src/Rules/Variables/CompactVariablesRule.php +++ b/src/Rules/Variables/CompactVariablesRule.php @@ -19,13 +19,8 @@ final class CompactVariablesRule implements Rule { - /** - * @var bool - */ - private $checkMaybeUndefinedVariables; - public function __construct(bool $checkMaybeUndefinedVariables) + public function __construct(private bool $checkMaybeUndefinedVariables) { - $this->checkMaybeUndefinedVariables = $checkMaybeUndefinedVariables; } public function getNodeType(): string @@ -56,9 +51,13 @@ public function processNode(Node $node, Scope $scope): array $scopeHasVariable = $scope->hasVariableType($variableName); if ($scopeHasVariable->no()) { - $messages[] = RuleErrorBuilder::message(sprintf('Call to function compact() contains undefined variable $%s.', $variableName))->identifier('variable.undefined')->line($argument->getStartLine())->build(); + $messages[] = RuleErrorBuilder::message( + sprintf('Call to function compact() contains undefined variable $%s.', $variableName), + )->identifier('variable.undefined')->line($argument->getStartLine())->build(); } elseif ($this->checkMaybeUndefinedVariables && $scopeHasVariable->maybe()) { - $messages[] = RuleErrorBuilder::message(sprintf('Call to function compact() contains possibly undefined variable $%s.', $variableName))->identifier('variable.undefined')->line($argument->getStartLine())->build(); + $messages[] = RuleErrorBuilder::message( + sprintf('Call to function compact() contains possibly undefined variable $%s.', $variableName), + )->identifier('variable.undefined')->line($argument->getStartLine())->build(); } } } diff --git a/src/Rules/Variables/DefinedVariableRule.php b/src/Rules/Variables/DefinedVariableRule.php index cec266630fe..fbe15dcfbce 100644 --- a/src/Rules/Variables/DefinedVariableRule.php +++ b/src/Rules/Variables/DefinedVariableRule.php @@ -17,19 +17,13 @@ class DefinedVariableRule implements Rule { - /** - * @var bool - */ - private $cliArgumentsVariablesRegistered; - /** - * @var bool - */ - private $checkMaybeUndefinedVariables; - public function __construct(bool $cliArgumentsVariablesRegistered, bool $checkMaybeUndefinedVariables) + public function __construct( + private bool $cliArgumentsVariablesRegistered, + private bool $checkMaybeUndefinedVariables, + ) { - $this->cliArgumentsVariablesRegistered = $cliArgumentsVariablesRegistered; - $this->checkMaybeUndefinedVariables = $checkMaybeUndefinedVariables; } + public function getNodeType(): string { return Variable::class; diff --git a/src/Rules/Variables/EmptyRule.php b/src/Rules/Variables/EmptyRule.php index 17d10011bcc..ca588bd7111 100644 --- a/src/Rules/Variables/EmptyRule.php +++ b/src/Rules/Variables/EmptyRule.php @@ -14,13 +14,8 @@ class EmptyRule implements Rule { - /** - * @var IssetCheck - */ - private $issetCheck; - public function __construct(IssetCheck $issetCheck) + public function __construct(private IssetCheck $issetCheck) { - $this->issetCheck = $issetCheck; } public function getNodeType(): string diff --git a/src/Rules/Variables/IssetRule.php b/src/Rules/Variables/IssetRule.php index 6365428bb44..f5c59363fff 100644 --- a/src/Rules/Variables/IssetRule.php +++ b/src/Rules/Variables/IssetRule.php @@ -14,13 +14,8 @@ class IssetRule implements Rule { - /** - * @var IssetCheck - */ - private $issetCheck; - public function __construct(IssetCheck $issetCheck) + public function __construct(private IssetCheck $issetCheck) { - $this->issetCheck = $issetCheck; } public function getNodeType(): string diff --git a/src/Rules/Variables/NullCoalesceRule.php b/src/Rules/Variables/NullCoalesceRule.php index 0550a6895f3..ef289640e38 100644 --- a/src/Rules/Variables/NullCoalesceRule.php +++ b/src/Rules/Variables/NullCoalesceRule.php @@ -14,13 +14,8 @@ class NullCoalesceRule implements Rule { - /** - * @var IssetCheck - */ - private $issetCheck; - public function __construct(IssetCheck $issetCheck) + public function __construct(private IssetCheck $issetCheck) { - $this->issetCheck = $issetCheck; } public function getNodeType(): string diff --git a/src/Rules/Variables/ThrowTypeRule.php b/src/Rules/Variables/ThrowTypeRule.php index 7673a881377..7678406a9ed 100644 --- a/src/Rules/Variables/ThrowTypeRule.php +++ b/src/Rules/Variables/ThrowTypeRule.php @@ -20,14 +20,12 @@ class ThrowTypeRule implements Rule { - /** - * @var RuleLevelHelper - */ - private $ruleLevelHelper; - public function __construct(RuleLevelHelper $ruleLevelHelper) + public function __construct( + private RuleLevelHelper $ruleLevelHelper, + ) { - $this->ruleLevelHelper = $ruleLevelHelper; } + public function getNodeType(): string { return Node\Stmt\Throw_::class; @@ -36,9 +34,12 @@ public function getNodeType(): string public function processNode(Node $node, Scope $scope): array { $throwableType = new ObjectType(Throwable::class); - $typeResult = $this->ruleLevelHelper->findTypeToCheck($scope, $node->expr, 'Throwing object of an unknown class %s.', static function (Type $type) use($throwableType) : bool { - return $throwableType->isSuperTypeOf($type)->yes(); - }); + $typeResult = $this->ruleLevelHelper->findTypeToCheck( + $scope, + $node->expr, + 'Throwing object of an unknown class %s.', + static fn (Type $type): bool => $throwableType->isSuperTypeOf($type)->yes(), + ); $foundType = $typeResult->getType(); if ($foundType instanceof ErrorType) { @@ -51,7 +52,10 @@ public function processNode(Node $node, Scope $scope): array } return [ - RuleErrorBuilder::message(sprintf('Invalid type %s to throw.', $foundType->describe(VerbosityLevel::typeOnly())))->identifier('throw.notThrowable')->build(), + RuleErrorBuilder::message(sprintf( + 'Invalid type %s to throw.', + $foundType->describe(VerbosityLevel::typeOnly()), + ))->identifier('throw.notThrowable')->build(), ]; } diff --git a/src/Rules/Variables/UnsetRule.php b/src/Rules/Variables/UnsetRule.php index 4873409784d..43efa6646c2 100644 --- a/src/Rules/Variables/UnsetRule.php +++ b/src/Rules/Variables/UnsetRule.php @@ -44,7 +44,9 @@ private function canBeUnset(Node $node, Scope $scope): ?IdentifierRuleError if ($node instanceof Node\Expr\Variable && is_string($node->name)) { $hasVariable = $scope->hasVariableType($node->name); if ($hasVariable->no()) { - return RuleErrorBuilder::message(sprintf('Call to function unset() contains undefined variable $%s.', $node->name)) + return RuleErrorBuilder::message( + sprintf('Call to function unset() contains undefined variable $%s.', $node->name), + ) ->line($node->getStartLine()) ->identifier('unset.variable') ->build(); @@ -54,7 +56,13 @@ private function canBeUnset(Node $node, Scope $scope): ?IdentifierRuleError $dimType = $scope->getType($node->dim); if ($type->isOffsetAccessible()->no() || $type->hasOffsetValueType($dimType)->no()) { - return RuleErrorBuilder::message(sprintf('Cannot unset offset %s on %s.', $dimType->describe(VerbosityLevel::value()), $type->describe(VerbosityLevel::value()))) + return RuleErrorBuilder::message( + sprintf( + 'Cannot unset offset %s on %s.', + $dimType->describe(VerbosityLevel::value()), + $type->describe(VerbosityLevel::value()), + ), + ) ->line($node->getStartLine()) ->identifier('unset.offset') ->build(); diff --git a/src/Rules/Variables/VariableCloningRule.php b/src/Rules/Variables/VariableCloningRule.php index 7381b77acd3..89aca44aa98 100644 --- a/src/Rules/Variables/VariableCloningRule.php +++ b/src/Rules/Variables/VariableCloningRule.php @@ -21,13 +21,8 @@ class VariableCloningRule implements Rule { - /** - * @var RuleLevelHelper - */ - private $ruleLevelHelper; - public function __construct(RuleLevelHelper $ruleLevelHelper) + public function __construct(private RuleLevelHelper $ruleLevelHelper) { - $this->ruleLevelHelper = $ruleLevelHelper; } public function getNodeType(): string @@ -37,9 +32,12 @@ public function getNodeType(): string public function processNode(Node $node, Scope $scope): array { - $typeResult = $this->ruleLevelHelper->findTypeToCheck($scope, $node->expr, 'Cloning object of an unknown class %s.', static function (Type $type) : bool { - return $type->isCloneable()->yes(); - }); + $typeResult = $this->ruleLevelHelper->findTypeToCheck( + $scope, + $node->expr, + 'Cloning object of an unknown class %s.', + static fn (Type $type): bool => $type->isCloneable()->yes(), + ); $type = $typeResult->getType(); if ($type instanceof ErrorType) { return $typeResult->getUnknownClassErrors(); @@ -50,12 +48,19 @@ public function processNode(Node $node, Scope $scope): array if ($node->expr instanceof Variable && is_string($node->expr->name)) { return [ - RuleErrorBuilder::message(sprintf('Cannot clone non-object variable $%s of type %s.', $node->expr->name, $type->describe(VerbosityLevel::typeOnly())))->identifier('clone.nonObject')->build(), + RuleErrorBuilder::message(sprintf( + 'Cannot clone non-object variable $%s of type %s.', + $node->expr->name, + $type->describe(VerbosityLevel::typeOnly()), + ))->identifier('clone.nonObject')->build(), ]; } return [ - RuleErrorBuilder::message(sprintf('Cannot clone %s.', $type->describe(VerbosityLevel::typeOnly())))->identifier('clone.nonObject')->build(), + RuleErrorBuilder::message(sprintf( + 'Cannot clone %s.', + $type->describe(VerbosityLevel::typeOnly()), + ))->identifier('clone.nonObject')->build(), ]; } diff --git a/src/Rules/Whitespace/FileWhitespaceRule.php b/src/Rules/Whitespace/FileWhitespaceRule.php index 29e56b97342..7f3bcbdcfe1 100644 --- a/src/Rules/Whitespace/FileWhitespaceRule.php +++ b/src/Rules/Whitespace/FileWhitespaceRule.php @@ -42,7 +42,7 @@ public function processNode(Node $node, Scope $scope): array $visitor = new class () extends NodeVisitorAbstract { /** @var Node[] */ - private $lastNodes = []; + private array $lastNodes = []; /** * @return int|null diff --git a/src/Testing/ErrorFormatterTestCase.php b/src/Testing/ErrorFormatterTestCase.php index ce0ffe1c05e..04f5d316ad8 100644 --- a/src/Testing/ErrorFormatterTestCase.php +++ b/src/Testing/ErrorFormatterTestCase.php @@ -29,10 +29,10 @@ abstract class ErrorFormatterTestCase extends PHPStanTestCase private const KIND_PLAIN = 'plain'; /** @var array */ - private $outputStream = []; + private array $outputStream = []; /** @var array */ - private $output = []; + private array $output = []; private function getOutputStream(bool $decorated = false): StreamOutput { @@ -91,14 +91,23 @@ protected function getAnalysisResult(int $numFileErrors, int $numGenericErrors): 'second generic error', ], 0, $numGenericErrors); - return new AnalysisResult($fileErrors, $genericErrors, [], [], [], false, null, true, 0, false); + return new AnalysisResult( + $fileErrors, + $genericErrors, + [], + [], + [], + false, + null, + true, + 0, + false, + ); } private function rtrimMultiline(string $output): string { - $result = array_map(static function (string $line) : string { - return rtrim($line, " \r\n"); - }, explode("\n", $output)); + $result = array_map(static fn (string $line): string => rtrim($line, " \r\n"), explode("\n", $output)); return implode("\n", $result); } diff --git a/src/Testing/LevelsTestCase.php b/src/Testing/LevelsTestCase.php index 92d08a3a1d7..7d0b1998a96 100644 --- a/src/Testing/LevelsTestCase.php +++ b/src/Testing/LevelsTestCase.php @@ -51,19 +51,26 @@ protected function shouldAutoloadAnalysedFile(): bool /** * @dataProvider dataTopics */ - public function testLevels(string $topic) : void + public function testLevels( + string $topic, + ): void { $file = sprintf('%s' . DIRECTORY_SEPARATOR . '%s.php', $this->getDataPath(), $topic); $command = escapeshellcmd($this->getPhpStanExecutablePath()); $configPath = $this->getPhpStanConfigPath(); $fileHelper = new FileHelper(__DIR__ . '/../..'); + $previousMessages = []; + $exceptions = []; + exec(sprintf('%s %s clear-result-cache %s 2>&1', escapeshellarg(PHP_BINARY), $command, $configPath !== null ? '--configuration ' . escapeshellarg($configPath) : ''), $clearResultCacheOutputLines, $clearResultCacheExitCode); if ($clearResultCacheExitCode !== 0) { throw new ShouldNotHappenException('Could not clear result cache: ' . implode("\n", $clearResultCacheOutputLines)); } + putenv('__PHPSTAN_FORCE_VALIDATE_STUB_FILES=1'); + foreach (range(0, 9) as $level) { unset($outputLines); exec(sprintf('%s %s analyse --no-progress --error-format=prettyJson --level=%d %s %s %s', escapeshellarg(PHP_BINARY), $command, $level, $configPath !== null ? '--configuration ' . escapeshellarg($configPath) : '', $this->shouldAutoloadAnalysedFile() ? sprintf('--autoload-file %s', escapeshellarg($file)) : '', escapeshellarg($file)), $outputLines); @@ -72,7 +79,7 @@ public function testLevels(string $topic) : void try { $actualJson = Json::decode($output, Json::FORCE_ARRAY); - } catch (JsonException $e) { + } catch (JsonException) { throw new JsonException(sprintf('Cannot decode: %s', $output)); } if (count($actualJson['files']) > 0) { @@ -144,6 +151,7 @@ public function testLevels(string $topic) : void $exceptions[] = $exception; } + if (count($exceptions) > 0) { throw $exceptions[0]; } @@ -175,7 +183,10 @@ private function compareFiles(string $expectedJsonFile, array $expectedMessages) $actualOutput = Json::encode($expectedMessages, Json::PRETTY); try { - $this->assertJsonStringEqualsJsonFile($expectedJsonFile, $actualOutput); + $this->assertJsonStringEqualsJsonFile( + $expectedJsonFile, + $actualOutput, + ); } catch (AssertionFailedError $e) { FileWriter::write($expectedJsonFile, $actualOutput); return $e; diff --git a/src/Testing/PHPStanTestCase.php b/src/Testing/PHPStanTestCase.php index 6fd5f1ff84b..14efcc7480e 100644 --- a/src/Testing/PHPStanTestCase.php +++ b/src/Testing/PHPStanTestCase.php @@ -51,12 +51,11 @@ abstract class PHPStanTestCase extends TestCase { - /** @deprecated - *@var bool */ - public static $useStaticReflectionProvider = true; + /** @deprecated */ + public static bool $useStaticReflectionProvider = true; /** @var array */ - private static $containers = []; + private static array $containers = []; /** @api */ public static function getContainer(): Container @@ -169,7 +168,31 @@ public static function createScopeFactory(ReflectionProvider $reflectionProvider $reflectionProviderProvider = new DirectReflectionProviderProvider($reflectionProvider); $constantResolver = new ConstantResolver($reflectionProviderProvider, $dynamicConstantNames); - return new ScopeFactory(new DirectInternalScopeFactory(MutatingScope::class, $reflectionProvider, new InitializerExprTypeResolver($constantResolver, $reflectionProviderProvider, $container->getByType(PhpVersion::class), $container->getByType(OperatorTypeSpecifyingExtensionRegistryProvider::class), new OversizedArrayBuilder(), $container->getParameter('usePathConstantsAsConstantString')), $container->getByType(DynamicReturnTypeExtensionRegistryProvider::class), $container->getByType(ExpressionTypeResolverExtensionRegistryProvider::class), $container->getByType(ExprPrinter::class), $typeSpecifier, new PropertyReflectionFinder(), self::getParser(), $container->getByType(NodeScopeResolver::class), $container->getByType(PhpVersion::class), $container->getParameter('featureToggles')['explicitMixedInUnknownGenericNew'], $container->getParameter('featureToggles')['explicitMixedForGlobalVariables'], $constantResolver)); + return new ScopeFactory( + new DirectInternalScopeFactory( + MutatingScope::class, + $reflectionProvider, + new InitializerExprTypeResolver( + $constantResolver, + $reflectionProviderProvider, + $container->getByType(PhpVersion::class), + $container->getByType(OperatorTypeSpecifyingExtensionRegistryProvider::class), + new OversizedArrayBuilder(), + $container->getParameter('usePathConstantsAsConstantString'), + ), + $container->getByType(DynamicReturnTypeExtensionRegistryProvider::class), + $container->getByType(ExpressionTypeResolverExtensionRegistryProvider::class), + $container->getByType(ExprPrinter::class), + $typeSpecifier, + new PropertyReflectionFinder(), + self::getParser(), + $container->getByType(NodeScopeResolver::class), + $container->getByType(PhpVersion::class), + $container->getParameter('featureToggles')['explicitMixedInUnknownGenericNew'], + $container->getParameter('featureToggles')['explicitMixedForGlobalVariables'], + $constantResolver, + ), + ); } /** @@ -179,7 +202,12 @@ public static function createTypeAliasResolver(array $globalTypeAliases, Reflect { $container = self::getContainer(); - return new UsefulTypeAliasResolver($globalTypeAliases, $container->getByType(TypeStringResolver::class), $container->getByType(TypeNodeResolver::class), $reflectionProvider); + return new UsefulTypeAliasResolver( + $globalTypeAliases, + $container->getByType(TypeStringResolver::class), + $container->getByType(TypeNodeResolver::class), + $reflectionProvider, + ); } protected function shouldTreatPhpDocTypesAsCertain(): bool diff --git a/src/Testing/RuleTestCase.php b/src/Testing/RuleTestCase.php index ac20195945d..e4c548d4d40 100644 --- a/src/Testing/RuleTestCase.php +++ b/src/Testing/RuleTestCase.php @@ -39,10 +39,7 @@ abstract class RuleTestCase extends PHPStanTestCase { - /** - * @var ?Analyser - */ - private $analyser = null; + private ?Analyser $analyser = null; /** * @phpstan-return TRule @@ -82,9 +79,46 @@ private function getAnalyser(): Analyser $typeSpecifier = $this->getTypeSpecifier(); $readWritePropertiesExtensions = $this->getReadWritePropertiesExtensions(); - $nodeScopeResolver = new NodeScopeResolver($reflectionProvider, self::getContainer()->getByType(InitializerExprTypeResolver::class), self::getReflector(), self::getClassReflectionExtensionRegistryProvider(), $this->getParser(), self::getContainer()->getByType(FileTypeMapper::class), self::getContainer()->getByType(StubPhpDocProvider::class), self::getContainer()->getByType(PhpVersion::class), self::getContainer()->getByType(SignatureMapProvider::class), self::getContainer()->getByType(PhpDocInheritanceResolver::class), self::getContainer()->getByType(FileHelper::class), $typeSpecifier, self::getContainer()->getByType(DynamicThrowTypeExtensionProvider::class), $readWritePropertiesExtensions !== [] ? new DirectReadWritePropertiesExtensionProvider($readWritePropertiesExtensions) : self::getContainer()->getByType(ReadWritePropertiesExtensionProvider::class), self::createScopeFactory($reflectionProvider, $typeSpecifier), $this->shouldPolluteScopeWithLoopInitialAssignments(), $this->shouldPolluteScopeWithAlwaysIterableForeach(), [], [], self::getContainer()->getParameter('universalObjectCratesClasses'), self::getContainer()->getParameter('exceptions')['implicitThrows'], $this->shouldTreatPhpDocTypesAsCertain(), self::getContainer()->getParameter('featureToggles')['detectDeadTypeInMultiCatch']); - $fileAnalyser = new FileAnalyser($this->createScopeFactory($reflectionProvider, $typeSpecifier), $nodeScopeResolver, $this->getParser(), self::getContainer()->getByType(DependencyResolver::class), new RuleErrorTransformer(), true); - $this->analyser = new Analyser($fileAnalyser, $ruleRegistry, $collectorRegistry, $nodeScopeResolver, 50); + $nodeScopeResolver = new NodeScopeResolver( + $reflectionProvider, + self::getContainer()->getByType(InitializerExprTypeResolver::class), + self::getReflector(), + self::getClassReflectionExtensionRegistryProvider(), + $this->getParser(), + self::getContainer()->getByType(FileTypeMapper::class), + self::getContainer()->getByType(StubPhpDocProvider::class), + self::getContainer()->getByType(PhpVersion::class), + self::getContainer()->getByType(SignatureMapProvider::class), + self::getContainer()->getByType(PhpDocInheritanceResolver::class), + self::getContainer()->getByType(FileHelper::class), + $typeSpecifier, + self::getContainer()->getByType(DynamicThrowTypeExtensionProvider::class), + $readWritePropertiesExtensions !== [] ? new DirectReadWritePropertiesExtensionProvider($readWritePropertiesExtensions) : self::getContainer()->getByType(ReadWritePropertiesExtensionProvider::class), + self::createScopeFactory($reflectionProvider, $typeSpecifier), + $this->shouldPolluteScopeWithLoopInitialAssignments(), + $this->shouldPolluteScopeWithAlwaysIterableForeach(), + [], + [], + self::getContainer()->getParameter('universalObjectCratesClasses'), + self::getContainer()->getParameter('exceptions')['implicitThrows'], + $this->shouldTreatPhpDocTypesAsCertain(), + self::getContainer()->getParameter('featureToggles')['detectDeadTypeInMultiCatch'], + ); + $fileAnalyser = new FileAnalyser( + $this->createScopeFactory($reflectionProvider, $typeSpecifier), + $nodeScopeResolver, + $this->getParser(), + self::getContainer()->getByType(DependencyResolver::class), + new RuleErrorTransformer(), + true, + ); + $this->analyser = new Analyser( + $fileAnalyser, + $ruleRegistry, + $collectorRegistry, + $nodeScopeResolver, + 50, + ); } return $this->analyser; @@ -106,17 +140,21 @@ public function analyse(array $files, array $expectedErrors): void return $message; }; - $expectedErrors = array_map(static function (array $error) use($strictlyTypedSprintf) : string { - return $strictlyTypedSprintf($error[1], $error[0], $error[2] ?? null); - }, $expectedErrors); + $expectedErrors = array_map( + static fn (array $error): string => $strictlyTypedSprintf($error[1], $error[0], $error[2] ?? null), + $expectedErrors, + ); - $actualErrors = array_map(static function (Error $error) use ($strictlyTypedSprintf): string { + $actualErrors = array_map( + static function (Error $error) use ($strictlyTypedSprintf): string { $line = $error->getLine(); if ($line === null) { return $strictlyTypedSprintf(-1, $error->getMessage(), $error->getTip()); } return $strictlyTypedSprintf($line, $error->getMessage(), $error->getTip()); - }, $actualErrors); + }, + $actualErrors, + ); $this->assertSame(implode("\n", $expectedErrors) . "\n", implode("\n", $actualErrors) . "\n"); } @@ -128,7 +166,12 @@ public function analyse(array $files, array $expectedErrors): void public function gatherAnalyserErrors(array $files): array { $files = array_map([$this->getFileHelper(), 'normalizePath'], $files); - $analyserResult = $this->getAnalyser()->analyse($files, null, null, true); + $analyserResult = $this->getAnalyser()->analyse( + $files, + null, + null, + true, + ); if (count($analyserResult->getInternalErrors()) > 0) { $this->fail(implode("\n", $analyserResult->getInternalErrors())); } diff --git a/src/Testing/TestCaseSourceLocatorFactory.php b/src/Testing/TestCaseSourceLocatorFactory.php index 3a9c54a9040..fccedd9ec10 100644 --- a/src/Testing/TestCaseSourceLocatorFactory.php +++ b/src/Testing/TestCaseSourceLocatorFactory.php @@ -26,66 +26,27 @@ class TestCaseSourceLocatorFactory { - /** - * @var ComposerJsonAndInstalledJsonSourceLocatorMaker - */ - private $composerJsonAndInstalledJsonSourceLocatorMaker; - /** - * @var Parser - */ - private $phpParser; - /** - * @var Parser - */ - private $php8Parser; - /** - * @var FileNodesFetcher - */ - private $fileNodesFetcher; - /** - * @var PhpStormStubsSourceStubber - */ - private $phpstormStubsSourceStubber; - /** - * @var ReflectionSourceStubber - */ - private $reflectionSourceStubber; - /** - * @var PhpVersion - */ - private $phpVersion; - /** - * @var string[] - */ - private $fileExtensions; - /** - * @var string[] - */ - private $obsoleteExcludesAnalyse; - /** - * @var array{analyse?: array, analyseAndScan?: array}|null - */ - private $excludePaths; /** @var array> */ - private static $composerSourceLocatorsCache = []; + private static array $composerSourceLocatorsCache = []; /** * @param string[] $fileExtensions * @param string[] $obsoleteExcludesAnalyse * @param array{analyse?: array, analyseAndScan?: array}|null $excludePaths */ - public function __construct(ComposerJsonAndInstalledJsonSourceLocatorMaker $composerJsonAndInstalledJsonSourceLocatorMaker, Parser $phpParser, Parser $php8Parser, FileNodesFetcher $fileNodesFetcher, PhpStormStubsSourceStubber $phpstormStubsSourceStubber, ReflectionSourceStubber $reflectionSourceStubber, PhpVersion $phpVersion, array $fileExtensions, array $obsoleteExcludesAnalyse, ?array $excludePaths) + public function __construct( + private ComposerJsonAndInstalledJsonSourceLocatorMaker $composerJsonAndInstalledJsonSourceLocatorMaker, + private Parser $phpParser, + private Parser $php8Parser, + private FileNodesFetcher $fileNodesFetcher, + private PhpStormStubsSourceStubber $phpstormStubsSourceStubber, + private ReflectionSourceStubber $reflectionSourceStubber, + private PhpVersion $phpVersion, + private array $fileExtensions, + private array $obsoleteExcludesAnalyse, + private ?array $excludePaths, + ) { - $this->composerJsonAndInstalledJsonSourceLocatorMaker = $composerJsonAndInstalledJsonSourceLocatorMaker; - $this->phpParser = $phpParser; - $this->php8Parser = $php8Parser; - $this->fileNodesFetcher = $fileNodesFetcher; - $this->phpstormStubsSourceStubber = $phpstormStubsSourceStubber; - $this->reflectionSourceStubber = $reflectionSourceStubber; - $this->phpVersion = $phpVersion; - $this->fileExtensions = $fileExtensions; - $this->obsoleteExcludesAnalyse = $obsoleteExcludesAnalyse; - $this->excludePaths = $excludePaths; } public function create(): SourceLocator diff --git a/src/Testing/TypeInferenceTestCase.php b/src/Testing/TypeInferenceTestCase.php index a67c670e9d0..edfd4eabb91 100644 --- a/src/Testing/TypeInferenceTestCase.php +++ b/src/Testing/TypeInferenceTestCase.php @@ -37,25 +37,61 @@ abstract class TypeInferenceTestCase extends PHPStanTestCase * @param callable(Node , Scope ): void $callback * @param string[] $dynamicConstantNames */ - public static function processFile(string $file, callable $callback, array $dynamicConstantNames = []) : void + public static function processFile( + string $file, + callable $callback, + array $dynamicConstantNames = [], + ): void { $reflectionProvider = self::createReflectionProvider(); $typeSpecifier = self::getContainer()->getService('typeSpecifier'); $fileHelper = self::getContainer()->getByType(FileHelper::class); - $resolver = new NodeScopeResolver($reflectionProvider, self::getContainer()->getByType(InitializerExprTypeResolver::class), self::getReflector(), self::getClassReflectionExtensionRegistryProvider(), self::getParser(), self::getContainer()->getByType(FileTypeMapper::class), self::getContainer()->getByType(StubPhpDocProvider::class), self::getContainer()->getByType(PhpVersion::class), self::getContainer()->getByType(SignatureMapProvider::class), self::getContainer()->getByType(PhpDocInheritanceResolver::class), self::getContainer()->getByType(FileHelper::class), $typeSpecifier, self::getContainer()->getByType(DynamicThrowTypeExtensionProvider::class), self::getContainer()->getByType(ReadWritePropertiesExtensionProvider::class), self::createScopeFactory($reflectionProvider, $typeSpecifier), true, true, static::getEarlyTerminatingMethodCalls(), static::getEarlyTerminatingFunctionCalls(), self::getContainer()->getParameter('universalObjectCratesClasses'), true, self::getContainer()->getParameter('treatPhpDocTypesAsCertain'), self::getContainer()->getParameter('featureToggles')['detectDeadTypeInMultiCatch']); - $resolver->setAnalysedFiles(array_map(static function (string $file) use($fileHelper) : string { - return $fileHelper->normalizePath($file); - }, array_merge([$file], static::getAdditionalAnalysedFiles()))); + $resolver = new NodeScopeResolver( + $reflectionProvider, + self::getContainer()->getByType(InitializerExprTypeResolver::class), + self::getReflector(), + self::getClassReflectionExtensionRegistryProvider(), + self::getParser(), + self::getContainer()->getByType(FileTypeMapper::class), + self::getContainer()->getByType(StubPhpDocProvider::class), + self::getContainer()->getByType(PhpVersion::class), + self::getContainer()->getByType(SignatureMapProvider::class), + self::getContainer()->getByType(PhpDocInheritanceResolver::class), + self::getContainer()->getByType(FileHelper::class), + $typeSpecifier, + self::getContainer()->getByType(DynamicThrowTypeExtensionProvider::class), + self::getContainer()->getByType(ReadWritePropertiesExtensionProvider::class), + self::createScopeFactory($reflectionProvider, $typeSpecifier), + true, + true, + static::getEarlyTerminatingMethodCalls(), + static::getEarlyTerminatingFunctionCalls(), + self::getContainer()->getParameter('universalObjectCratesClasses'), + true, + self::getContainer()->getParameter('treatPhpDocTypesAsCertain'), + self::getContainer()->getParameter('featureToggles')['detectDeadTypeInMultiCatch'], + ); + $resolver->setAnalysedFiles(array_map(static fn (string $file): string => $fileHelper->normalizePath($file), array_merge([$file], static::getAdditionalAnalysedFiles()))); + $scopeFactory = self::createScopeFactory($reflectionProvider, $typeSpecifier, $dynamicConstantNames); $scope = $scopeFactory->create(ScopeContext::create($file)); - $resolver->processNodes(self::getParser()->parseFile($file), $scope, $callback); + + $resolver->processNodes( + self::getParser()->parseFile($file), + $scope, + $callback, + ); } /** * @api * @param mixed ...$args */ - public function assertFileAsserts(string $assertType, string $file, ...$args) : void + public function assertFileAsserts( + string $assertType, + string $file, + ...$args, + ): void { if ($assertType === 'type') { $expectedType = $args[0]; @@ -63,12 +99,19 @@ public function assertFileAsserts(string $assertType, string $file, ...$args) : $expected = $expectedType->getValue(); $actualType = $args[1]; $actual = $actualType->describe(VerbosityLevel::precise()); - $this->assertSame($expected, $actual, sprintf('Expected type %s, got type %s in %s on line %d.', $expected, $actual, $file, $args[2])); + $this->assertSame( + $expected, + $actual, + sprintf('Expected type %s, got type %s in %s on line %d.', $expected, $actual, $file, $args[2]), + ); } elseif ($assertType === 'variableCertainty') { $expectedCertainty = $args[0]; $actualCertainty = $args[1]; $variableName = $args[2]; - $this->assertTrue($expectedCertainty->equals($actualCertainty), sprintf('Expected %s, actual certainty of variable $%s is %s in %s on line %d.', $expectedCertainty->describe(), $variableName, $actualCertainty->describe(), $file, $args[3])); + $this->assertTrue( + $expectedCertainty->equals($actualCertainty), + sprintf('Expected %s, actual certainty of variable $%s is %s in %s on line %d.', $expectedCertainty->describe(), $variableName, $actualCertainty->describe(), $file, $args[3]), + ); } } @@ -91,7 +134,11 @@ public static function gatherAssertTypes(string $file): array $functionName = $nameNode->toString(); if (in_array(strtolower($functionName), ['asserttype', 'assertnativetype', 'assertvariablecertainty'], true)) { - self::fail(sprintf('Missing use statement for %s() on line %d.', $functionName, $node->getStartLine())); + self::fail(sprintf( + 'Missing use statement for %s() on line %d.', + $functionName, + $node->getStartLine(), + )); } elseif ($functionName === 'PHPStan\\Testing\\assertType') { $expectedType = $scope->getType($node->getArgs()[0]->value); $actualType = $scope->getType($node->getArgs()[1]->value); @@ -149,11 +196,20 @@ public static function gatherAssertTypes(string $file): array return; } - self::fail(sprintf('Function %s imported with wrong namespace %s called on line %d.', $correctFunction, $functionName, $node->getStartLine())); + self::fail(sprintf( + 'Function %s imported with wrong namespace %s called on line %d.', + $correctFunction, + $functionName, + $node->getStartLine(), + )); } if (count($node->getArgs()) !== 2) { - self::fail(sprintf('ERROR: Wrong %s() call on line %d.', $functionName, $node->getStartLine())); + self::fail(sprintf( + 'ERROR: Wrong %s() call on line %d.', + $functionName, + $node->getStartLine(), + )); } $asserts[$file . ':' . $node->getStartLine()] = $assert; diff --git a/src/TrinaryLogic.php b/src/TrinaryLogic.php index 81265e05a22..df4e9f5218a 100644 --- a/src/TrinaryLogic.php +++ b/src/TrinaryLogic.php @@ -15,46 +15,41 @@ class TrinaryLogic { - /** - * @var int - */ - private $value; private const YES = 1; private const MAYBE = 0; private const NO = -1; /** @var self[] */ - private static $registry = []; + private static array $registry = []; - private function __construct(int $value) + private function __construct(private int $value) { - $this->value = $value; } public static function createYes(): self { - return self::$registry[self::YES] = self::$registry[self::YES] ?? new self(self::YES); + return self::$registry[self::YES] ??= new self(self::YES); } public static function createNo(): self { - return self::$registry[self::NO] = self::$registry[self::NO] ?? new self(self::NO); + return self::$registry[self::NO] ??= new self(self::NO); } public static function createMaybe(): self { - return self::$registry[self::MAYBE] = self::$registry[self::MAYBE] ?? new self(self::MAYBE); + return self::$registry[self::MAYBE] ??= new self(self::MAYBE); } public static function createFromBoolean(bool $value): self { $yesNo = $value ? self::YES : self::NO; - return self::$registry[$yesNo] = self::$registry[$yesNo] ?? new self($yesNo); + return self::$registry[$yesNo] ??= new self($yesNo); } private static function create(int $value): self { - self::$registry[$value] = self::$registry[$value] ?? new self($value); + self::$registry[$value] ??= new self($value); return self::$registry[$value]; } @@ -94,11 +89,15 @@ public function and(self ...$operands): self * @param T[] $objects * @param callable(T): self $callback */ - public function lazyAnd(array $objects, callable $callback) : self + public function lazyAnd( + array $objects, + callable $callback, + ): self { if ($this->no()) { return $this; } + $results = []; foreach ($objects as $object) { $result = $callback($object); @@ -108,6 +107,7 @@ public function lazyAnd(array $objects, callable $callback) : self $results[] = $result; } + return $this->and(...$results); } @@ -123,11 +123,15 @@ public function or(self ...$operands): self * @param T[] $objects * @param callable(T): self $callback */ - public function lazyOr(array $objects, callable $callback) : self + public function lazyOr( + array $objects, + callable $callback, + ): self { if ($this->yes()) { return $this; } + $results = []; foreach ($objects as $object) { $result = $callback($object); @@ -137,6 +141,7 @@ public function lazyOr(array $objects, callable $callback) : self $results[] = $result; } + return $this->or(...$results); } @@ -156,11 +161,15 @@ public static function extremeIdentity(self ...$operands): self * @param T[] $objects * @param callable(T): self $callback */ - public static function lazyExtremeIdentity(array $objects, callable $callback) : self + public static function lazyExtremeIdentity( + array $objects, + callable $callback, + ): self { if ($objects === []) { throw new ShouldNotHappenException(); } + $lastResult = null; foreach ($objects as $object) { $result = $callback($object); @@ -174,6 +183,7 @@ public static function lazyExtremeIdentity(array $objects, callable $callback) : return self::createMaybe(); } + return $lastResult; } @@ -191,7 +201,10 @@ public static function maxMin(self ...$operands): self * @param T[] $objects * @param callable(T): self $callback */ - public static function lazyMaxMin(array $objects, callable $callback) : self + public static function lazyMaxMin( + array $objects, + callable $callback, + ): self { $results = []; foreach ($objects as $object) { @@ -202,6 +215,7 @@ public static function lazyMaxMin(array $objects, callable $callback) : self $results[] = $result; } + return self::maxMin(...$results); } diff --git a/src/Type/AcceptsResult.php b/src/Type/AcceptsResult.php index 07b91f758b0..fd30d8badd8 100644 --- a/src/Type/AcceptsResult.php +++ b/src/Type/AcceptsResult.php @@ -13,24 +13,16 @@ class AcceptsResult { - /** - * @readonly - * @var TrinaryLogic - */ - public $result; - /** - * @readonly - * @var list - */ - public $reasons; /** * @param list $reasons */ - public function __construct(TrinaryLogic $result, array $reasons) + public function __construct( + public readonly TrinaryLogic $result, + public readonly array $reasons, + ) { - $this->result = $result; - $this->reasons = $reasons; } + public function yes(): bool { return $this->result->yes(); @@ -68,12 +60,18 @@ public static function createFromBoolean(bool $value): self public function and(self $other): self { - return new self($this->result->and($other->result), array_values(array_unique(array_merge($this->reasons, $other->reasons)))); + return new self( + $this->result->and($other->result), + array_values(array_unique(array_merge($this->reasons, $other->reasons))), + ); } public function or(self $other): self { - return new self($this->result->or($other->result), array_values(array_unique(array_merge($this->reasons, $other->reasons)))); + return new self( + $this->result->or($other->result), + array_values(array_unique(array_merge($this->reasons, $other->reasons))), + ); } /** @@ -95,9 +93,7 @@ public static function extremeIdentity(self ...$operands): self throw new ShouldNotHappenException(); } - $result = TrinaryLogic::extremeIdentity(...array_map(static function (self $result) { - return $result->result; - }, $operands)); + $result = TrinaryLogic::extremeIdentity(...array_map(static fn (self $result) => $result->result, $operands)); $reasons = []; foreach ($operands as $operand) { foreach ($operand->reasons as $reason) { @@ -114,9 +110,7 @@ public static function maxMin(self ...$operands): self throw new ShouldNotHappenException(); } - $result = TrinaryLogic::maxMin(...array_map(static function (self $result) { - return $result->result; - }, $operands)); + $result = TrinaryLogic::maxMin(...array_map(static fn (self $result) => $result->result, $operands)); $reasons = []; foreach ($operands as $operand) { foreach ($operand->reasons as $reason) { diff --git a/src/Type/Accessory/AccessoryArrayListType.php b/src/Type/Accessory/AccessoryArrayListType.php index fe00dfc15c2..bad40674cb2 100644 --- a/src/Type/Accessory/AccessoryArrayListType.php +++ b/src/Type/Accessory/AccessoryArrayListType.php @@ -39,10 +39,7 @@ class AccessoryArrayListType implements CompoundType, AccessoryType use NonRemoveableTypeTrait; use NonGeneralizableTypeTrait; - /** - * @var bool - */ - private static $enabled = false; + private static bool $enabled = false; public function __construct() { @@ -399,12 +396,18 @@ public function toNumber(): Type public function toInteger(): Type { - return TypeCombinator::union(new ConstantIntegerType(0), new ConstantIntegerType(1)); + return TypeCombinator::union( + new ConstantIntegerType(0), + new ConstantIntegerType(1), + ); } public function toFloat(): Type { - return TypeCombinator::union(new ConstantFloatType(0.0), new ConstantFloatType(1.0)); + return TypeCombinator::union( + new ConstantFloatType(0.0), + new ConstantFloatType(1.0), + ); } public function toString(): Type diff --git a/src/Type/Accessory/AccessoryLiteralStringType.php b/src/Type/Accessory/AccessoryLiteralStringType.php index aba7f7c9ab2..13e98c7bd3e 100644 --- a/src/Type/Accessory/AccessoryLiteralStringType.php +++ b/src/Type/Accessory/AccessoryLiteralStringType.php @@ -183,7 +183,13 @@ public function toBoolean(): BooleanType public function toArray(): Type { - return new ConstantArrayType([new ConstantIntegerType(0)], [$this], [1], [], TrinaryLogic::createYes()); + return new ConstantArrayType( + [new ConstantIntegerType(0)], + [$this], + [1], + [], + TrinaryLogic::createYes(), + ); } public function toArrayKey(): Type diff --git a/src/Type/Accessory/AccessoryNonEmptyStringType.php b/src/Type/Accessory/AccessoryNonEmptyStringType.php index 3427488876d..504e1b91b82 100644 --- a/src/Type/Accessory/AccessoryNonEmptyStringType.php +++ b/src/Type/Accessory/AccessoryNonEmptyStringType.php @@ -184,7 +184,13 @@ public function toString(): Type public function toArray(): Type { - return new ConstantArrayType([new ConstantIntegerType(0)], [$this], [1], [], TrinaryLogic::createYes()); + return new ConstantArrayType( + [new ConstantIntegerType(0)], + [$this], + [1], + [], + TrinaryLogic::createYes(), + ); } public function toArrayKey(): Type diff --git a/src/Type/Accessory/AccessoryNonFalsyStringType.php b/src/Type/Accessory/AccessoryNonFalsyStringType.php index 63a7c170ca0..9da8d9fc863 100644 --- a/src/Type/Accessory/AccessoryNonFalsyStringType.php +++ b/src/Type/Accessory/AccessoryNonFalsyStringType.php @@ -184,7 +184,13 @@ public function toString(): Type public function toArray(): Type { - return new ConstantArrayType([new ConstantIntegerType(0)], [$this], [1], [], TrinaryLogic::createYes()); + return new ConstantArrayType( + [new ConstantIntegerType(0)], + [$this], + [1], + [], + TrinaryLogic::createYes(), + ); } public function toArrayKey(): Type diff --git a/src/Type/Accessory/AccessoryNumericStringType.php b/src/Type/Accessory/AccessoryNumericStringType.php index 2c9302e2c09..29fb36ce459 100644 --- a/src/Type/Accessory/AccessoryNumericStringType.php +++ b/src/Type/Accessory/AccessoryNumericStringType.php @@ -186,7 +186,13 @@ public function toString(): Type public function toArray(): Type { - return new ConstantArrayType([new ConstantIntegerType(0)], [$this], [1], [], TrinaryLogic::createYes()); + return new ConstantArrayType( + [new ConstantIntegerType(0)], + [$this], + [1], + [], + TrinaryLogic::createYes(), + ); } public function toArrayKey(): Type diff --git a/src/Type/Accessory/HasMethodType.php b/src/Type/Accessory/HasMethodType.php index dc09fb4313e..070f8533290 100644 --- a/src/Type/Accessory/HasMethodType.php +++ b/src/Type/Accessory/HasMethodType.php @@ -30,10 +30,6 @@ class HasMethodType implements AccessoryType, CompoundType { - /** - * @var string - */ - private $methodName; use ObjectTypeTrait; use NonGenericTypeTrait; use UndecidedComparisonCompoundTypeTrait; @@ -41,9 +37,8 @@ class HasMethodType implements AccessoryType, CompoundType use NonGeneralizableTypeTrait; /** @api */ - public function __construct(string $methodName) + public function __construct(private string $methodName) { - $this->methodName = $methodName; } public function getReferencedClasses(): array @@ -142,9 +137,12 @@ public function getMethod(string $methodName, ClassMemberAccessAnswerer $scope): public function getUnresolvedMethodPrototype(string $methodName, ClassMemberAccessAnswerer $scope): UnresolvedMethodPrototypeReflection { $method = new DummyMethodReflection($this->methodName); - return new CallbackUnresolvedMethodPrototypeReflection($method, $method->getDeclaringClass(), false, static function (Type $type) : Type { - return $type; - }); + return new CallbackUnresolvedMethodPrototypeReflection( + $method, + $method->getDeclaringClass(), + false, + static fn (Type $type): Type => $type, + ); } public function isCallable(): TrinaryLogic diff --git a/src/Type/Accessory/HasOffsetType.php b/src/Type/Accessory/HasOffsetType.php index 8d967caf219..829b46c7759 100644 --- a/src/Type/Accessory/HasOffsetType.php +++ b/src/Type/Accessory/HasOffsetType.php @@ -32,10 +32,6 @@ class HasOffsetType implements CompoundType, AccessoryType { - /** - * @var ConstantStringType|ConstantIntegerType - */ - private $offsetType; use MaybeArrayTypeTrait; use MaybeCallableTypeTrait; use MaybeIterableTypeTrait; @@ -50,9 +46,8 @@ class HasOffsetType implements CompoundType, AccessoryType * @api * @param ConstantStringType|ConstantIntegerType $offsetType */ - public function __construct(Type $offsetType) + public function __construct(private Type $offsetType) { - $this->offsetType = $offsetType; } /** diff --git a/src/Type/Accessory/HasOffsetValueType.php b/src/Type/Accessory/HasOffsetValueType.php index d3c006840a5..2dd2984b1e7 100644 --- a/src/Type/Accessory/HasOffsetValueType.php +++ b/src/Type/Accessory/HasOffsetValueType.php @@ -34,14 +34,6 @@ class HasOffsetValueType implements CompoundType, AccessoryType { - /** - * @var ConstantStringType|ConstantIntegerType - */ - private $offsetType; - /** - * @var Type - */ - private $valueType; use MaybeArrayTypeTrait; use MaybeCallableTypeTrait; use MaybeIterableTypeTrait; @@ -52,19 +44,11 @@ class HasOffsetValueType implements CompoundType, AccessoryType use NonRemoveableTypeTrait; use NonGeneralizableTypeTrait; - /** - * @param ConstantStringType|ConstantIntegerType $offsetType - */ - public function __construct($offsetType, Type $valueType) + public function __construct(private ConstantStringType|ConstantIntegerType $offsetType, private Type $valueType) { - $this->offsetType = $offsetType; - $this->valueType = $valueType; } - /** - * @return ConstantStringType|ConstantIntegerType - */ - public function getOffsetType() + public function getOffsetType(): ConstantStringType|ConstantIntegerType { return $this->offsetType; } @@ -105,9 +89,12 @@ public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult return $type->isAcceptedWithReasonBy($this, $strictTypes); } - return new AcceptsResult($type->isOffsetAccessible() + return new AcceptsResult( + $type->isOffsetAccessible() ->and($type->hasOffsetValueType($this->offsetType)) - ->and($this->valueType->accepts($type->getOffsetValueType($this->offsetType), $strictTypes)), []); + ->and($this->valueType->accepts($type->getOffsetValueType($this->offsetType), $strictTypes)), + [], + ); } public function isSuperTypeOf(Type $type): TrinaryLogic diff --git a/src/Type/Accessory/HasPropertyType.php b/src/Type/Accessory/HasPropertyType.php index c32cdba866b..53170faac3f 100644 --- a/src/Type/Accessory/HasPropertyType.php +++ b/src/Type/Accessory/HasPropertyType.php @@ -24,10 +24,6 @@ class HasPropertyType implements AccessoryType, CompoundType { - /** - * @var string - */ - private $propertyName; use ObjectTypeTrait; use NonGenericTypeTrait; use UndecidedComparisonCompoundTypeTrait; @@ -35,9 +31,8 @@ class HasPropertyType implements AccessoryType, CompoundType use NonGeneralizableTypeTrait; /** @api */ - public function __construct(string $propertyName) + public function __construct(private string $propertyName) { - $this->propertyName = $propertyName; } /** diff --git a/src/Type/ArrayType.php b/src/Type/ArrayType.php index 0cca7cb2514..cec0f88390a 100644 --- a/src/Type/ArrayType.php +++ b/src/Type/ArrayType.php @@ -37,26 +37,18 @@ class ArrayType implements Type { - /** - * @var Type - */ - private $itemType; - use MaybeCallableTypeTrait; + use MaybeCallableTypeTrait; use NonObjectTypeTrait; use UndecidedBooleanTypeTrait; use UndecidedComparisonTypeTrait; use NonGeneralizableTypeTrait; - /** - * @var Type - */ - private $keyType; + private Type $keyType; /** @api */ - public function __construct(Type $keyType, Type $itemType) + public function __construct(Type $keyType, private Type $itemType) { - $this->itemType = $itemType; - if ($keyType->describe(VerbosityLevel::value()) === '(int|string)') { + if ($keyType->describe(VerbosityLevel::value()) === '(int|string)') { $keyType = new MixedType(); } $this->keyType = $keyType; @@ -73,11 +65,14 @@ public function getItemType(): Type } /** - * @return string[] - */ - public function getReferencedClasses(): array + * @return string[] + */ + public function getReferencedClasses(): array { - return array_merge($this->keyType->getReferencedClasses(), $this->getItemType()->getReferencedClasses()); + return array_merge( + $this->keyType->getReferencedClasses(), + $this->getItemType()->getReferencedClasses(), + ); } public function getObjectClassNames(): array @@ -172,7 +167,10 @@ public function describe(VerbosityLevel $level): string return sprintf('array<%s, %s>', $this->keyType->describe($level), $this->itemType->describe($level)); }; - return $level->handle($valueHandler, $valueHandler, function () use ($level, $isMixedKeyType, $isMixedItemType): string { + return $level->handle( + $valueHandler, + $valueHandler, + function () use ($level, $isMixedKeyType, $isMixedItemType): string { if ($isMixedKeyType) { if ($isMixedItemType) { return 'array'; @@ -182,13 +180,14 @@ public function describe(VerbosityLevel $level): string } return sprintf('array<%s, %s>', $this->keyType->describe($level), $this->itemType->describe($level)); - }); + }, + ); } /** - * @deprecated - */ - public function generalizeKeys(): self + * @deprecated + */ + public function generalizeKeys(): self { return new self($this->keyType->generalize(GeneralizePrecision::lessSpecific()), $this->itemType); } @@ -459,10 +458,23 @@ public function setOffsetValueType(?Type $offsetType, Type $valueType, bool $uni return $builder->getArray(); } - return TypeCombinator::intersect(new self(TypeCombinator::union($this->keyType, $offsetType), TypeCombinator::union($this->itemType, $valueType)), new HasOffsetValueType($offsetType, $valueType), new NonEmptyArrayType()); + return TypeCombinator::intersect( + new self( + TypeCombinator::union($this->keyType, $offsetType), + TypeCombinator::union($this->itemType, $valueType), + ), + new HasOffsetValueType($offsetType, $valueType), + new NonEmptyArrayType(), + ); } - return TypeCombinator::intersect(new self(TypeCombinator::union($this->keyType, $offsetType), $unionValues ? TypeCombinator::union($this->itemType, $valueType) : $valueType), new NonEmptyArrayType()); + return TypeCombinator::intersect( + new self( + TypeCombinator::union($this->keyType, $offsetType), + $unionValues ? TypeCombinator::union($this->itemType, $valueType) : $valueType, + ), + new NonEmptyArrayType(), + ); } public function unsetOffset(Type $offsetType): Type @@ -546,9 +558,9 @@ public function isCallable(): TrinaryLogic } /** - * @return ParametersAcceptor[] - */ - public function getCallableParametersAcceptors(ClassMemberAccessAnswerer $scope): array + * @return ParametersAcceptor[] + */ + public function getCallableParametersAcceptors(ClassMemberAccessAnswerer $scope): array { if ($this->isCallable()->no()) { throw new ShouldNotHappenException(); @@ -569,12 +581,18 @@ public function toString(): Type public function toInteger(): Type { - return TypeCombinator::union(new ConstantIntegerType(0), new ConstantIntegerType(1)); + return TypeCombinator::union( + new ConstantIntegerType(0), + new ConstantIntegerType(1), + ); } public function toFloat(): Type { - return TypeCombinator::union(new ConstantFloatType(0.0), new ConstantFloatType(1.0)); + return TypeCombinator::union( + new ConstantFloatType(0.0), + new ConstantFloatType(1.0), + ); } public function toArray(): Type @@ -588,13 +606,13 @@ public function toArrayKey(): Type } /** @deprecated Use getArraySize() instead */ - public function count(): Type + public function count(): Type { return $this->getArraySize(); } /** @deprecated Use $offsetType->toArrayKey() instead */ - public static function castToArrayKeyType(Type $offsetType): Type + public static function castToArrayKeyType(Type $offsetType): Type { return $offsetType->toArrayKey(); } @@ -619,7 +637,10 @@ public function getReferencedTemplateTypes(TemplateTypeVariance $positionVarianc { $variance = $positionVariance->compose(TemplateTypeVariance::createCovariant()); - return array_merge($this->getKeyType()->getReferencedTemplateTypes($variance), $this->getItemType()->getReferencedTemplateTypes($variance)); + return array_merge( + $this->getKeyType()->getReferencedTemplateTypes($variance), + $this->getItemType()->getReferencedTemplateTypes($variance), + ); } public function traverse(callable $cb): Type @@ -648,15 +669,21 @@ public function toPhpDocNode(): TypeNode return new IdentifierTypeNode('array'); } - return new GenericTypeNode(new IdentifierTypeNode('array'), [ + return new GenericTypeNode( + new IdentifierTypeNode('array'), + [ $this->itemType->toPhpDocNode(), - ]); + ], + ); } - return new GenericTypeNode(new IdentifierTypeNode('array'), [ + return new GenericTypeNode( + new IdentifierTypeNode('array'), + [ $this->keyType->toPhpDocNode(), $this->itemType->toPhpDocNode(), - ]); + ], + ); } public function traverseSimultaneously(Type $right, callable $cb): Type @@ -707,11 +734,14 @@ public function getFiniteTypes(): array } /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): Type - { - return new self($properties['keyType'], $properties['itemType']); + * @param mixed[] $properties + */ + public static function __set_state(array $properties): Type + { + return new self( + $properties['keyType'], + $properties['itemType'], + ); } } diff --git a/src/Type/BitwiseFlagHelper.php b/src/Type/BitwiseFlagHelper.php index 8929bf42997..9b7175cd3f2 100644 --- a/src/Type/BitwiseFlagHelper.php +++ b/src/Type/BitwiseFlagHelper.php @@ -14,13 +14,8 @@ final class BitwiseFlagHelper { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - public function __construct(ReflectionProvider $reflectionProvider) + public function __construct(private ReflectionProvider $reflectionProvider) { - $this->reflectionProvider = $reflectionProvider; } public function bitwiseOrContainsConstant(Expr $expr, Scope $scope, string $constName): TrinaryLogic diff --git a/src/Type/BooleanType.php b/src/Type/BooleanType.php index 44f29a3b895..c0ac5b59203 100644 --- a/src/Type/BooleanType.php +++ b/src/Type/BooleanType.php @@ -58,22 +58,37 @@ public function toNumber(): Type public function toString(): Type { - return TypeCombinator::union(new ConstantStringType(''), new ConstantStringType('1')); + return TypeCombinator::union( + new ConstantStringType(''), + new ConstantStringType('1'), + ); } public function toInteger(): Type { - return TypeCombinator::union(new ConstantIntegerType(0), new ConstantIntegerType(1)); + return TypeCombinator::union( + new ConstantIntegerType(0), + new ConstantIntegerType(1), + ); } public function toFloat(): Type { - return TypeCombinator::union(new ConstantFloatType(0.0), new ConstantFloatType(1.0)); + return TypeCombinator::union( + new ConstantFloatType(0.0), + new ConstantFloatType(1.0), + ); } public function toArray(): Type { - return new ConstantArrayType([new ConstantIntegerType(0)], [$this], [1], [], TrinaryLogic::createYes()); + return new ConstantArrayType( + [new ConstantIntegerType(0)], + [$this], + [1], + [], + TrinaryLogic::createYes(), + ); } public function toArrayKey(): Type diff --git a/src/Type/CallableType.php b/src/Type/CallableType.php index 899b9a1953d..698e5b72507 100644 --- a/src/Type/CallableType.php +++ b/src/Type/CallableType.php @@ -38,10 +38,6 @@ class CallableType implements CompoundType, ParametersAcceptor { - /** - * @var bool - */ - private $variadic; use MaybeArrayTypeTrait; use MaybeIterableTypeTrait; use MaybeObjectTypeTrait; @@ -52,25 +48,22 @@ class CallableType implements CompoundType, ParametersAcceptor use NonGeneralizableTypeTrait; /** @var array */ - private $parameters; + private array $parameters; - /** - * @var Type - */ - private $returnType; + private Type $returnType; - /** - * @var bool - */ - private $isCommonCallable; + private bool $isCommonCallable; /** * @api * @param array|null $parameters */ - public function __construct(?array $parameters = null, ?Type $returnType = null, bool $variadic = true) + public function __construct( + ?array $parameters = null, + ?Type $returnType = null, + private bool $variadic = true, + ) { - $this->variadic = $variadic; $this->parameters = $parameters ?? []; $this->returnType = $returnType ?? new MixedType(); $this->isCommonCallable = $parameters === null && $returnType === null; @@ -183,16 +176,26 @@ public function equals(Type $type): bool public function describe(VerbosityLevel $level): string { - return $level->handle(static function () : string { - return 'callable'; - }, function (): string { + return $level->handle( + static fn (): string => 'callable', + function (): string { $printer = new Printer(); - $selfWithoutParameterNames = new self(array_map(static function (ParameterReflection $p) : ParameterReflection { - return new DummyParameter('', $p->getType(), $p->isOptional() && !$p->isVariadic(), PassedByReference::createNo(), $p->isVariadic(), $p->getDefaultValue()); - }, $this->parameters), $this->returnType, $this->variadic); + $selfWithoutParameterNames = new self( + array_map(static fn (ParameterReflection $p): ParameterReflection => new DummyParameter( + '', + $p->getType(), + $p->isOptional() && !$p->isVariadic(), + PassedByReference::createNo(), + $p->isVariadic(), + $p->getDefaultValue(), + ), $this->parameters), + $this->returnType, + $this->variadic, + ); return $printer->print($selfWithoutParameterNames->toPhpDocNode()); - }); + }, + ); } public function isCallable(): TrinaryLogic @@ -316,7 +319,9 @@ private function inferTemplateTypesOnParametersAcceptor(ParametersAcceptor $para public function getReferencedTemplateTypes(TemplateTypeVariance $positionVariance): array { - $references = $this->getReturnType()->getReferencedTemplateTypes($positionVariance->compose(TemplateTypeVariance::createCovariant())); + $references = $this->getReturnType()->getReferencedTemplateTypes( + $positionVariance->compose(TemplateTypeVariance::createCovariant()), + ); $paramVariance = $positionVariance->compose(TemplateTypeVariance::createContravariant()); @@ -337,10 +342,21 @@ public function traverse(callable $cb): Type $parameters = array_map(static function (ParameterReflection $param) use ($cb): NativeParameterReflection { $defaultValue = $param->getDefaultValue(); - return new NativeParameterReflection($param->getName(), $param->isOptional(), $cb($param->getType()), $param->passedByReference(), $param->isVariadic(), $defaultValue !== null ? $cb($defaultValue) : null); + return new NativeParameterReflection( + $param->getName(), + $param->isOptional(), + $cb($param->getType()), + $param->passedByReference(), + $param->isVariadic(), + $defaultValue !== null ? $cb($defaultValue) : null, + ); }, $this->getParameters()); - return new self($parameters, $cb($this->getReturnType()), $this->isVariadic()); + return new self( + $parameters, + $cb($this->getReturnType()), + $this->isVariadic(), + ); } public function traverseSimultaneously(Type $right, callable $cb): Type @@ -372,10 +388,21 @@ public function traverseSimultaneously(Type $right, callable $cb): Type if ($leftDefaultValue !== null && $rightDefaultValue !== null) { $defaultValue = $cb($leftDefaultValue, $rightDefaultValue); } - $parameters[] = new NativeParameterReflection($leftParam->getName(), $leftParam->isOptional(), $cb($leftParam->getType(), $rightParam->getType()), $leftParam->passedByReference(), $leftParam->isVariadic(), $defaultValue); + $parameters[] = new NativeParameterReflection( + $leftParam->getName(), + $leftParam->isOptional(), + $cb($leftParam->getType(), $rightParam->getType()), + $leftParam->passedByReference(), + $leftParam->isVariadic(), + $defaultValue, + ); } - return new self($parameters, $cb($this->getReturnType(), $rightAcceptors[0]->getReturnType()), $this->isVariadic()); + return new self( + $parameters, + $cb($this->getReturnType(), $rightAcceptors[0]->getReturnType()), + $this->isVariadic(), + ); } public function isOversizedArray(): TrinaryLogic @@ -516,10 +543,20 @@ public function toPhpDocNode(): TypeNode $parameters = []; foreach ($this->parameters as $parameter) { - $parameters[] = new CallableTypeParameterNode($parameter->getType()->toPhpDocNode(), !$parameter->passedByReference()->no(), $parameter->isVariadic(), $parameter->getName() === '' ? '' : '$' . $parameter->getName(), $parameter->isOptional()); + $parameters[] = new CallableTypeParameterNode( + $parameter->getType()->toPhpDocNode(), + !$parameter->passedByReference()->no(), + $parameter->isVariadic(), + $parameter->getName() === '' ? '' : '$' . $parameter->getName(), + $parameter->isOptional(), + ); } - return new CallableTypeNode(new IdentifierTypeNode('callable'), $parameters, $this->returnType->toPhpDocNode()); + return new CallableTypeNode( + new IdentifierTypeNode('callable'), + $parameters, + $this->returnType->toPhpDocNode(), + ); } /** @@ -527,7 +564,11 @@ public function toPhpDocNode(): TypeNode */ public static function __set_state(array $properties): Type { - return new self((bool) $properties['isCommonCallable'] ? null : $properties['parameters'], (bool) $properties['isCommonCallable'] ? null : $properties['returnType'], $properties['variadic']); + return new self( + (bool) $properties['isCommonCallable'] ? null : $properties['parameters'], + (bool) $properties['isCommonCallable'] ? null : $properties['returnType'], + $properties['variadic'], + ); } } diff --git a/src/Type/CallableTypeHelper.php b/src/Type/CallableTypeHelper.php index a37dc948c82..e90675d0111 100644 --- a/src/Type/CallableTypeHelper.php +++ b/src/Type/CallableTypeHelper.php @@ -12,10 +12,15 @@ class CallableTypeHelper { - public static function isParametersAcceptorSuperTypeOf(ParametersAcceptor $ours, ParametersAcceptor $theirs, bool $treatMixedAsAny) : AcceptsResult + public static function isParametersAcceptorSuperTypeOf( + ParametersAcceptor $ours, + ParametersAcceptor $theirs, + bool $treatMixedAsAny, + ): AcceptsResult { $theirParameters = $theirs->getParameters(); $ourParameters = $ours->getParameters(); + $lastParameter = null; foreach ($theirParameters as $theirParameter) { $lastParameter = $theirParameter; @@ -32,6 +37,7 @@ public static function isParametersAcceptorSuperTypeOf(ParametersAcceptor $ours, $theirParameters[] = $lastParameter; } } + $result = null; foreach ($theirParameters as $i => $theirParameter) { $parameterDescription = $theirParameter->getName() === '' ? sprintf('#%d', $i + 1) : sprintf('#%d $%s', $i + 1, $theirParameter->getName()); @@ -41,7 +47,10 @@ public static function isParametersAcceptorSuperTypeOf(ParametersAcceptor $ours, } $accepts = new AcceptsResult(TrinaryLogic::createNo(), [ - sprintf('Parameter %s of passed callable is required but accepting callable does not have that parameter. It will be called without it.', $parameterDescription), + sprintf( + 'Parameter %s of passed callable is required but accepting callable does not have that parameter. It will be called without it.', + $parameterDescription, + ), ]); if ($result === null) { $result = $accepts; @@ -56,7 +65,10 @@ public static function isParametersAcceptorSuperTypeOf(ParametersAcceptor $ours, if ($ourParameter->isOptional() && !$theirParameter->isOptional()) { $accepts = new AcceptsResult(TrinaryLogic::createNo(), [ - sprintf('Parameter %s of passed callable is required but the parameter of accepting callable is optional. It might be called without it.', $parameterDescription), + sprintf( + 'Parameter %s of passed callable is required but the parameter of accepting callable is optional. It might be called without it.', + $parameterDescription, + ), ]); if ($result === null) { $result = $accepts; @@ -74,7 +86,12 @@ public static function isParametersAcceptorSuperTypeOf(ParametersAcceptor $ours, if ($isSuperType->maybe()) { $verbosity = VerbosityLevel::getRecommendedLevelByType($theirParameter->getType(), $ourParameterType); $isSuperType = new AcceptsResult($isSuperType->result, array_merge($isSuperType->reasons, [ - sprintf('Type %s of parameter %s of passed callable needs to be same or wider than parameter type %s of accepting callable.', $theirParameter->getType()->describe($verbosity), $parameterDescription, $ourParameterType->describe($verbosity)), + sprintf( + 'Type %s of parameter %s of passed callable needs to be same or wider than parameter type %s of accepting callable.', + $theirParameter->getType()->describe($verbosity), + $parameterDescription, + $ourParameterType->describe($verbosity), + ), ])); } @@ -84,17 +101,20 @@ public static function isParametersAcceptorSuperTypeOf(ParametersAcceptor $ours, $result = $result->and($isSuperType); } } + $theirReturnType = $theirs->getReturnType(); if ($treatMixedAsAny) { $isReturnTypeSuperType = $ours->getReturnType()->acceptsWithReason($theirReturnType, true); } else { $isReturnTypeSuperType = new AcceptsResult($ours->getReturnType()->isSuperTypeOf($theirReturnType), []); } + if ($result === null) { $result = $isReturnTypeSuperType; } else { $result = $result->and($isReturnTypeSuperType); } + return $result; } diff --git a/src/Type/ClosureType.php b/src/Type/ClosureType.php index 8bb750395f8..ff872ed7ae9 100644 --- a/src/Type/ClosureType.php +++ b/src/Type/ClosureType.php @@ -46,18 +46,6 @@ class ClosureType implements TypeWithClassName, ParametersAcceptor { - /** - * @var array - */ - private $parameters; - /** - * @var Type - */ - private $returnType; - /** - * @var bool - */ - private $variadic; use NonArrayTypeTrait; use NonGenericTypeTrait; use NonIterableTypeTrait; @@ -66,35 +54,27 @@ class ClosureType implements TypeWithClassName, ParametersAcceptor use NonRemoveableTypeTrait; use NonGeneralizableTypeTrait; - /** - * @var ObjectType - */ - private $objectType; + private ObjectType $objectType; - /** - * @var TemplateTypeMap - */ - private $templateTypeMap; + private TemplateTypeMap $templateTypeMap; - /** - * @var TemplateTypeMap - */ - private $resolvedTemplateTypeMap; + private TemplateTypeMap $resolvedTemplateTypeMap; - /** - * @var TemplateTypeVarianceMap - */ - private $callSiteVarianceMap; + private TemplateTypeVarianceMap $callSiteVarianceMap; /** * @api * @param array $parameters */ - public function __construct(array $parameters, Type $returnType, bool $variadic, ?TemplateTypeMap $templateTypeMap = null, ?TemplateTypeMap $resolvedTemplateTypeMap = null, ?TemplateTypeVarianceMap $callSiteVarianceMap = null) + public function __construct( + private array $parameters, + private Type $returnType, + private bool $variadic, + ?TemplateTypeMap $templateTypeMap = null, + ?TemplateTypeMap $resolvedTemplateTypeMap = null, + ?TemplateTypeVarianceMap $callSiteVarianceMap = null, + ) { - $this->parameters = $parameters; - $this->returnType = $returnType; - $this->variadic = $variadic; $this->objectType = new ObjectType(Closure::class); $this->templateTypeMap = $templateTypeMap ?? TemplateTypeMap::createEmpty(); $this->resolvedTemplateTypeMap = $resolvedTemplateTypeMap ?? TemplateTypeMap::createEmpty(); @@ -169,7 +149,11 @@ public function isSuperTypeOf(Type $type): TrinaryLogic private function isSuperTypeOfInternal(Type $type, bool $treatMixedAsAny): AcceptsResult { if ($type instanceof self) { - return CallableTypeHelper::isParametersAcceptorSuperTypeOf($this, $type, $treatMixedAsAny); + return CallableTypeHelper::isParametersAcceptorSuperTypeOf( + $this, + $type, + $treatMixedAsAny, + ); } if ($type->getObjectClassNames() === [Closure::class]) { @@ -190,16 +174,29 @@ public function equals(Type $type): bool public function describe(VerbosityLevel $level): string { - return $level->handle(static function () : string { - return 'Closure'; - }, function (): string { + return $level->handle( + static fn (): string => 'Closure', + function (): string { $printer = new Printer(); - $selfWithoutParameterNames = new self(array_map(static function (ParameterReflection $p) : ParameterReflection { - return new DummyParameter('', $p->getType(), $p->isOptional() && !$p->isVariadic(), PassedByReference::createNo(), $p->isVariadic(), $p->getDefaultValue()); - }, $this->parameters), $this->returnType, $this->variadic, $this->templateTypeMap, $this->resolvedTemplateTypeMap, $this->callSiteVarianceMap); + $selfWithoutParameterNames = new self( + array_map(static fn (ParameterReflection $p): ParameterReflection => new DummyParameter( + '', + $p->getType(), + $p->isOptional() && !$p->isVariadic(), + PassedByReference::createNo(), + $p->isVariadic(), + $p->getDefaultValue(), + ), $this->parameters), + $this->returnType, + $this->variadic, + $this->templateTypeMap, + $this->resolvedTemplateTypeMap, + $this->callSiteVarianceMap, + ); return $printer->print($selfWithoutParameterNames->toPhpDocNode()); - }); + }, + ); } public function isObject(): TrinaryLogic @@ -255,7 +252,10 @@ public function getMethod(string $methodName, ClassMemberAccessAnswerer $scope): public function getUnresolvedMethodPrototype(string $methodName, ClassMemberAccessAnswerer $scope): UnresolvedMethodPrototypeReflection { if ($methodName === 'call') { - return new ClosureCallUnresolvedMethodPrototypeReflection($this->objectType->getUnresolvedMethodPrototype($methodName, $scope), $this); + return new ClosureCallUnresolvedMethodPrototypeReflection( + $this->objectType->getUnresolvedMethodPrototype($methodName, $scope), + $this, + ); } return $this->objectType->getUnresolvedMethodPrototype($methodName, $scope); @@ -341,7 +341,13 @@ public function toString(): Type public function toArray(): Type { - return new ConstantArrayType([new ConstantIntegerType(0)], [$this], [1], [], TrinaryLogic::createYes()); + return new ConstantArrayType( + [new ConstantIntegerType(0)], + [$this], + [1], + [], + TrinaryLogic::createYes(), + ); } public function toArrayKey(): Type @@ -427,10 +433,24 @@ private function inferTemplateTypesOnParametersAcceptor(ParametersAcceptor $para public function traverse(callable $cb): Type { - return new self(array_map(static function (ParameterReflection $param) use ($cb): NativeParameterReflection { + return new self( + array_map(static function (ParameterReflection $param) use ($cb): NativeParameterReflection { $defaultValue = $param->getDefaultValue(); - return new NativeParameterReflection($param->getName(), $param->isOptional(), $cb($param->getType()), $param->passedByReference(), $param->isVariadic(), $defaultValue !== null ? $cb($defaultValue) : null); - }, $this->getParameters()), $cb($this->getReturnType()), $this->isVariadic(), $this->templateTypeMap, $this->resolvedTemplateTypeMap, $this->callSiteVarianceMap); + return new NativeParameterReflection( + $param->getName(), + $param->isOptional(), + $cb($param->getType()), + $param->passedByReference(), + $param->isVariadic(), + $defaultValue !== null ? $cb($defaultValue) : null, + ); + }, $this->getParameters()), + $cb($this->getReturnType()), + $this->isVariadic(), + $this->templateTypeMap, + $this->resolvedTemplateTypeMap, + $this->callSiteVarianceMap, + ); } public function traverseSimultaneously(Type $right, callable $cb): Type @@ -453,10 +473,21 @@ public function traverseSimultaneously(Type $right, callable $cb): Type if ($leftDefaultValue !== null && $rightDefaultValue !== null) { $defaultValue = $cb($leftDefaultValue, $rightDefaultValue); } - $parameters[] = new NativeParameterReflection($leftParam->getName(), $leftParam->isOptional(), $cb($leftParam->getType(), $rightParam->getType()), $leftParam->passedByReference(), $leftParam->isVariadic(), $defaultValue); + $parameters[] = new NativeParameterReflection( + $leftParam->getName(), + $leftParam->isOptional(), + $cb($leftParam->getType(), $rightParam->getType()), + $leftParam->passedByReference(), + $leftParam->isVariadic(), + $defaultValue, + ); } - return new self($parameters, $cb($this->getReturnType(), $right->getReturnType()), $this->isVariadic()); + return new self( + $parameters, + $cb($this->getReturnType(), $right->getReturnType()), + $this->isVariadic(), + ); } public function isNull(): TrinaryLogic @@ -578,10 +609,20 @@ public function toPhpDocNode(): TypeNode { $parameters = []; foreach ($this->parameters as $parameter) { - $parameters[] = new CallableTypeParameterNode($parameter->getType()->toPhpDocNode(), !$parameter->passedByReference()->no(), $parameter->isVariadic(), $parameter->getName() === '' ? '' : '$' . $parameter->getName(), $parameter->isOptional()); + $parameters[] = new CallableTypeParameterNode( + $parameter->getType()->toPhpDocNode(), + !$parameter->passedByReference()->no(), + $parameter->isVariadic(), + $parameter->getName() === '' ? '' : '$' . $parameter->getName(), + $parameter->isOptional(), + ); } - return new CallableTypeNode(new IdentifierTypeNode('Closure'), $parameters, $this->returnType->toPhpDocNode()); + return new CallableTypeNode( + new IdentifierTypeNode('Closure'), + $parameters, + $this->returnType->toPhpDocNode(), + ); } /** @@ -589,7 +630,14 @@ public function toPhpDocNode(): TypeNode */ public static function __set_state(array $properties): Type { - return new self($properties['parameters'], $properties['returnType'], $properties['variadic'], $properties['templateTypeMap'], $properties['resolvedTemplateTypeMap'], $properties['callSiteVarianceMap']); + return new self( + $properties['parameters'], + $properties['returnType'], + $properties['variadic'], + $properties['templateTypeMap'], + $properties['resolvedTemplateTypeMap'], + $properties['callSiteVarianceMap'], + ); } } diff --git a/src/Type/ClosureTypeFactory.php b/src/Type/ClosureTypeFactory.php index 7e15586404f..07a395a5fef 100644 --- a/src/Type/ClosureTypeFactory.php +++ b/src/Type/ClosureTypeFactory.php @@ -27,29 +27,15 @@ class ClosureTypeFactory { - /** - * @var InitializerExprTypeResolver - */ - private $initializerExprTypeResolver; - /** - * @var ReflectionSourceStubber - */ - private $reflectionSourceStubber; - /** - * @var Reflector - */ - private $reflector; - /** - * @var Parser - */ - private $parser; - public function __construct(InitializerExprTypeResolver $initializerExprTypeResolver, ReflectionSourceStubber $reflectionSourceStubber, Reflector $reflector, Parser $parser) + public function __construct( + private InitializerExprTypeResolver $initializerExprTypeResolver, + private ReflectionSourceStubber $reflectionSourceStubber, + private Reflector $reflector, + private Parser $parser, + ) { - $this->initializerExprTypeResolver = $initializerExprTypeResolver; - $this->reflectionSourceStubber = $reflectionSourceStubber; - $this->reflector = $reflector; - $this->parser = $parser; } + /** * @param Closure(): mixed $closure */ @@ -76,65 +62,53 @@ public function fromClosureObject(Closure $closure): ClosureType $betterReflectionFunction = $reflections[0]; - $parameters = array_map(function (BetterReflectionParameter $parameter) { - return new class($parameter, $this->initializerExprTypeResolver) implements ParameterReflection { - - /** - * @var BetterReflectionParameter - */ - private $reflection; - /** - * @var InitializerExprTypeResolver - */ - private $initializerExprTypeResolver; - public function __construct(BetterReflectionParameter $reflection, InitializerExprTypeResolver $initializerExprTypeResolver) - { - $this->reflection = $reflection; - $this->initializerExprTypeResolver = $initializerExprTypeResolver; + $parameters = array_map(fn (BetterReflectionParameter $parameter) => new class($parameter, $this->initializerExprTypeResolver) implements ParameterReflection { + + public function __construct(private BetterReflectionParameter $reflection, private InitializerExprTypeResolver $initializerExprTypeResolver) + { + } + + public function getName(): string + { + return $this->reflection->getName(); + } + + public function isOptional(): bool + { + return $this->reflection->isOptional(); + } + + public function getType(): Type + { + return TypehintHelper::decideTypeFromReflection(ReflectionType::fromTypeOrNull($this->reflection->getType()), null, null, $this->reflection->isVariadic()); + } + + public function passedByReference(): PassedByReference + { + return $this->reflection->isPassedByReference() + ? PassedByReference::createCreatesNewVariable() + : PassedByReference::createNo(); + } + + public function isVariadic(): bool + { + return $this->reflection->isVariadic(); + } + + public function getDefaultValue(): ?Type + { + if (! $this->reflection->isDefaultValueAvailable()) { + return null; + } + + $defaultExpr = $this->reflection->getDefaultValueExpression(); + if ($defaultExpr === null) { + return null; } - - public function getName(): string - { - return $this->reflection->getName(); - } - - public function isOptional(): bool - { - return $this->reflection->isOptional(); - } - - public function getType(): Type - { - return TypehintHelper::decideTypeFromReflection(ReflectionType::fromTypeOrNull($this->reflection->getType()), null, null, $this->reflection->isVariadic()); - } - - public function passedByReference(): PassedByReference - { - return $this->reflection->isPassedByReference() - ? PassedByReference::createCreatesNewVariable() - : PassedByReference::createNo(); - } - - public function isVariadic(): bool - { - return $this->reflection->isVariadic(); - } - - public function getDefaultValue(): ?Type - { - if (! $this->reflection->isDefaultValueAvailable()) { - return null; - } - - $defaultExpr = $this->reflection->getDefaultValueExpression(); - if ($defaultExpr === null) { - return null; - } - - return $this->initializerExprTypeResolver->getType($defaultExpr, InitializerExprContext::fromReflectionParameter(new ReflectionParameter($this->reflection))); - } - - }; + + return $this->initializerExprTypeResolver->getType($defaultExpr, InitializerExprContext::fromReflectionParameter(new ReflectionParameter($this->reflection))); + } + }, $betterReflectionFunction->getParameters()); return new ClosureType($parameters, TypehintHelper::decideTypeFromReflection(ReflectionType::fromTypeOrNull($betterReflectionFunction->getReturnType())), $betterReflectionFunction->isVariadic()); diff --git a/src/Type/ConditionalType.php b/src/Type/ConditionalType.php index b71fe298fd4..8543e388598 100644 --- a/src/Type/ConditionalType.php +++ b/src/Type/ConditionalType.php @@ -15,36 +15,17 @@ final class ConditionalType implements CompoundType, LateResolvableType { - /** - * @var Type - */ - private $subject; - /** - * @var Type - */ - private $target; - /** - * @var Type - */ - private $if; - /** - * @var Type - */ - private $else; - /** - * @var bool - */ - private $negated; use LateResolvableTypeTrait; use NonGeneralizableTypeTrait; - public function __construct(Type $subject, Type $target, Type $if, Type $else, bool $negated) + public function __construct( + private Type $subject, + private Type $target, + private Type $if, + private Type $else, + private bool $negated, + ) { - $this->subject = $subject; - $this->target = $target; - $this->if = $if; - $this->else = $else; - $this->negated = $negated; } public function getSubject(): Type @@ -84,12 +65,22 @@ public function isSuperTypeOf(Type $type): TrinaryLogic public function getReferencedClasses(): array { - return array_merge($this->subject->getReferencedClasses(), $this->target->getReferencedClasses(), $this->if->getReferencedClasses(), $this->else->getReferencedClasses()); + return array_merge( + $this->subject->getReferencedClasses(), + $this->target->getReferencedClasses(), + $this->if->getReferencedClasses(), + $this->else->getReferencedClasses(), + ); } public function getReferencedTemplateTypes(TemplateTypeVariance $positionVariance): array { - return array_merge($this->subject->getReferencedTemplateTypes($positionVariance), $this->target->getReferencedTemplateTypes($positionVariance), $this->if->getReferencedTemplateTypes($positionVariance), $this->else->getReferencedTemplateTypes($positionVariance)); + return array_merge( + $this->subject->getReferencedTemplateTypes($positionVariance), + $this->target->getReferencedTemplateTypes($positionVariance), + $this->if->getReferencedTemplateTypes($positionVariance), + $this->else->getReferencedTemplateTypes($positionVariance), + ); } public function equals(Type $type): bool @@ -103,7 +94,14 @@ public function equals(Type $type): bool public function describe(VerbosityLevel $level): string { - return sprintf('(%s %s %s ? %s : %s)', $this->subject->describe($level), $this->negated ? 'is not' : 'is', $this->target->describe($level), $this->if->describe($level), $this->else->describe($level)); + return sprintf( + '(%s %s %s ? %s : %s)', + $this->subject->describe($level), + $this->negated ? 'is not' : 'is', + $this->target->describe($level), + $this->if->describe($level), + $this->else->describe($level), + ); } public function isResolvable(): bool @@ -118,16 +116,14 @@ protected function getResult(): Type $intersectedType = TypeCombinator::intersect($this->subject, $this->target); $removedType = TypeCombinator::remove($this->subject, $this->target); - $yesType = function () use($intersectedType, $removedType) { - return TypeTraverser::map(!$this->negated ? $this->if : $this->else, function (Type $type, callable $traverse) use($intersectedType, $removedType) { - return $type === $this->subject ? (!$this->negated ? $intersectedType : $removedType) : $traverse($type); - }); - }; - $noType = function () use($removedType, $intersectedType) { - return TypeTraverser::map(!$this->negated ? $this->else : $this->if, function (Type $type, callable $traverse) use($removedType, $intersectedType) { - return $type === $this->subject ? (!$this->negated ? $removedType : $intersectedType) : $traverse($type); - }); - }; + $yesType = fn () => TypeTraverser::map( + !$this->negated ? $this->if : $this->else, + fn (Type $type, callable $traverse) => $type === $this->subject ? (!$this->negated ? $intersectedType : $removedType) : $traverse($type), + ); + $noType = fn () => TypeTraverser::map( + !$this->negated ? $this->else : $this->if, + fn (Type $type, callable $traverse) => $type === $this->subject ? (!$this->negated ? $removedType : $intersectedType) : $traverse($type), + ); if ($isSuperType->yes()) { return $yesType(); @@ -174,7 +170,13 @@ public function traverseSimultaneously(Type $right, callable $cb): Type public function toPhpDocNode(): TypeNode { - return new ConditionalTypeNode($this->subject->toPhpDocNode(), $this->target->toPhpDocNode(), $this->if->toPhpDocNode(), $this->else->toPhpDocNode(), $this->negated); + return new ConditionalTypeNode( + $this->subject->toPhpDocNode(), + $this->target->toPhpDocNode(), + $this->if->toPhpDocNode(), + $this->else->toPhpDocNode(), + $this->negated, + ); } /** @@ -182,7 +184,13 @@ public function toPhpDocNode(): TypeNode */ public static function __set_state(array $properties): Type { - return new self($properties['subject'], $properties['target'], $properties['if'], $properties['else'], $properties['negated']); + return new self( + $properties['subject'], + $properties['target'], + $properties['if'], + $properties['else'], + $properties['negated'], + ); } } diff --git a/src/Type/ConditionalTypeForParameter.php b/src/Type/ConditionalTypeForParameter.php index 3d5a0a9a0db..57c2fe5d8d2 100644 --- a/src/Type/ConditionalTypeForParameter.php +++ b/src/Type/ConditionalTypeForParameter.php @@ -15,36 +15,17 @@ final class ConditionalTypeForParameter implements CompoundType, LateResolvableType { - /** - * @var string - */ - private $parameterName; - /** - * @var Type - */ - private $target; - /** - * @var Type - */ - private $if; - /** - * @var Type - */ - private $else; - /** - * @var bool - */ - private $negated; use LateResolvableTypeTrait; use NonGeneralizableTypeTrait; - public function __construct(string $parameterName, Type $target, Type $if, Type $else, bool $negated) + public function __construct( + private string $parameterName, + private Type $target, + private Type $if, + private Type $else, + private bool $negated, + ) { - $this->parameterName = $parameterName; - $this->target = $target; - $this->if = $if; - $this->else = $else; - $this->negated = $negated; } public function getParameterName(): string @@ -74,12 +55,24 @@ public function isNegated(): bool public function changeParameterName(string $parameterName): self { - return new self($parameterName, $this->target, $this->if, $this->else, $this->negated); + return new self( + $parameterName, + $this->target, + $this->if, + $this->else, + $this->negated, + ); } public function toConditional(Type $subject): Type { - return new ConditionalType($subject, $this->target, $this->if, $this->else, $this->negated); + return new ConditionalType( + $subject, + $this->target, + $this->if, + $this->else, + $this->negated, + ); } public function isSuperTypeOf(Type $type): TrinaryLogic @@ -94,12 +87,20 @@ public function isSuperTypeOf(Type $type): TrinaryLogic public function getReferencedClasses(): array { - return array_merge($this->target->getReferencedClasses(), $this->if->getReferencedClasses(), $this->else->getReferencedClasses()); + return array_merge( + $this->target->getReferencedClasses(), + $this->if->getReferencedClasses(), + $this->else->getReferencedClasses(), + ); } public function getReferencedTemplateTypes(TemplateTypeVariance $positionVariance): array { - return array_merge($this->target->getReferencedTemplateTypes($positionVariance), $this->if->getReferencedTemplateTypes($positionVariance), $this->else->getReferencedTemplateTypes($positionVariance)); + return array_merge( + $this->target->getReferencedTemplateTypes($positionVariance), + $this->if->getReferencedTemplateTypes($positionVariance), + $this->else->getReferencedTemplateTypes($positionVariance), + ); } public function equals(Type $type): bool @@ -113,7 +114,14 @@ public function equals(Type $type): bool public function describe(VerbosityLevel $level): string { - return sprintf('(%s %s %s ? %s : %s)', $this->parameterName, $this->negated ? 'is not' : 'is', $this->target->describe($level), $this->if->describe($level), $this->else->describe($level)); + return sprintf( + '(%s %s %s ? %s : %s)', + $this->parameterName, + $this->negated ? 'is not' : 'is', + $this->target->describe($level), + $this->if->describe($level), + $this->else->describe($level), + ); } public function isResolvable(): bool @@ -158,7 +166,13 @@ public function traverseSimultaneously(Type $right, callable $cb): Type public function toPhpDocNode(): TypeNode { - return new ConditionalTypeForParameterNode($this->parameterName, $this->target->toPhpDocNode(), $this->if->toPhpDocNode(), $this->else->toPhpDocNode(), $this->negated); + return new ConditionalTypeForParameterNode( + $this->parameterName, + $this->target->toPhpDocNode(), + $this->if->toPhpDocNode(), + $this->else->toPhpDocNode(), + $this->negated, + ); } /** @@ -166,7 +180,13 @@ public function toPhpDocNode(): TypeNode */ public static function __set_state(array $properties): Type { - return new self($properties['parameterName'], $properties['target'], $properties['if'], $properties['else'], $properties['negated']); + return new self( + $properties['parameterName'], + $properties['target'], + $properties['if'], + $properties['else'], + $properties['negated'], + ); } } diff --git a/src/Type/Constant/ConstantArrayType.php b/src/Type/Constant/ConstantArrayType.php index 25211910c0f..c09ec00d8c2 100644 --- a/src/Type/Constant/ConstantArrayType.php +++ b/src/Type/Constant/ConstantArrayType.php @@ -74,64 +74,59 @@ class ConstantArrayType extends ArrayType implements ConstantType { - /** - * @var array - */ - private $keyTypes; - /** - * @var array - */ - private $valueTypes; - /** - * @var int[] - */ - private $optionalKeys; - private const DESCRIBE_LIMIT = 8; + private const DESCRIBE_LIMIT = 8; - /** - * @var TrinaryLogic - */ - private $isList; + private TrinaryLogic $isList; /** @var self[]|null */ - private $allArrays = null; + private ?array $allArrays = null; /** @var non-empty-list */ - private $nextAutoIndexes; + private array $nextAutoIndexes; /** - * @api - * @param array $keyTypes - * @param array $valueTypes - * @param non-empty-list|int $nextAutoIndexes - * @param int[] $optionalKeys - * @param bool|TrinaryLogic $isList - */ - public function __construct(array $keyTypes, array $valueTypes, $nextAutoIndexes = [0], array $optionalKeys = [], $isList = false) - { - $this->keyTypes = $keyTypes; - $this->valueTypes = $valueTypes; - $this->optionalKeys = $optionalKeys; - assert(count($keyTypes) === count($valueTypes)); - if (is_int($nextAutoIndexes)) { - $nextAutoIndexes = [$nextAutoIndexes]; - } - $this->nextAutoIndexes = $nextAutoIndexes; - $keyTypesCount = count($this->keyTypes); - if ($keyTypesCount === 0) { - $keyType = new NeverType(true); - $isList = TrinaryLogic::createYes(); - } elseif ($keyTypesCount === 1) { - $keyType = $this->keyTypes[0]; - } else { - $keyType = new UnionType($this->keyTypes); - } - if (is_bool($isList)) { - $isList = TrinaryLogic::createFromBoolean($isList); - } - $this->isList = $isList; - parent::__construct($keyType, count($valueTypes) > 0 ? TypeCombinator::union(...$valueTypes) : new NeverType(true)); - } + * @api + * @param array $keyTypes + * @param array $valueTypes + * @param non-empty-list|int $nextAutoIndexes + * @param int[] $optionalKeys + */ + public function __construct( + private array $keyTypes, + private array $valueTypes, + int|array $nextAutoIndexes = [0], + private array $optionalKeys = [], + bool|TrinaryLogic $isList = false, + ) + { + assert(count($keyTypes) === count($valueTypes)); + + if (is_int($nextAutoIndexes)) { + $nextAutoIndexes = [$nextAutoIndexes]; + } + + $this->nextAutoIndexes = $nextAutoIndexes; + + $keyTypesCount = count($this->keyTypes); + if ($keyTypesCount === 0) { + $keyType = new NeverType(true); + $isList = TrinaryLogic::createYes(); + } elseif ($keyTypesCount === 1) { + $keyType = $this->keyTypes[0]; + } else { + $keyType = new UnionType($this->keyTypes); + } + + if (is_bool($isList)) { + $isList = TrinaryLogic::createFromBoolean($isList); + } + $this->isList = $isList; + + parent::__construct( + $keyType, + count($valueTypes) > 0 ? TypeCombinator::union(...$valueTypes) : new NeverType(true), + ); + } public function getConstantArrays(): array { @@ -144,39 +139,39 @@ public function isConstantValue(): TrinaryLogic } /** @deprecated Use isIterableAtLeastOnce()->no() instead */ - public function isEmpty(): bool + public function isEmpty(): bool { return count($this->keyTypes) === 0; } /** - * @return non-empty-list - */ - public function getNextAutoIndexes(): array + * @return non-empty-list + */ + public function getNextAutoIndexes(): array { return $this->nextAutoIndexes; } /** - * @deprecated - */ - public function getNextAutoIndex(): int + * @deprecated + */ + public function getNextAutoIndex(): int { return $this->nextAutoIndexes[count($this->nextAutoIndexes) - 1]; } /** - * @return int[] - */ - public function getOptionalKeys(): array + * @return int[] + */ + public function getOptionalKeys(): array { return $this->optionalKeys; } /** - * @return self[] - */ - public function getAllArrays(): array + * @return self[] + */ + public function getAllArrays(): array { if ($this->allArrays !== null) { return $this->allArrays; @@ -225,11 +220,11 @@ public function getAllArrays(): array } /** - * @template T - * @param T[] $in - * @return T[][] - */ - private function powerSet(array $in): array + * @template T + * @param T[] $in + * @return T[][] + */ + private function powerSet(array $in): array { $count = count($in); $members = pow(2, $count); @@ -251,41 +246,41 @@ private function powerSet(array $in): array } /** - * @return array - */ - public function getKeyTypes(): array + * @return array + */ + public function getKeyTypes(): array { return $this->keyTypes; } /** @deprecated Use getFirstIterableKeyType() instead */ - public function getFirstKeyType(): Type + public function getFirstKeyType(): Type { return $this->getFirstIterableKeyType(); } /** @deprecated Use getLastIterableKeyType() instead */ - public function getLastKeyType(): Type + public function getLastKeyType(): Type { return $this->getLastIterableKeyType(); } /** - * @return array - */ - public function getValueTypes(): array + * @return array + */ + public function getValueTypes(): array { return $this->valueTypes; } /** @deprecated Use getFirstIterableValueType() instead */ - public function getFirstValueType(): Type + public function getFirstValueType(): Type { return $this->getFirstIterableValueType(); } /** @deprecated Use getLastIterableValueType() instead */ - public function getLastValueType(): Type + public function getLastValueType(): Type { return $this->getLastIterableValueType(); } @@ -314,7 +309,10 @@ public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult foreach ($this->keyTypes as $i => $keyType) { $valueType = $this->valueTypes[$i]; $hasOffsetValueType = $type->hasOffsetValueType($keyType); - $hasOffset = new AcceptsResult($hasOffsetValueType, $hasOffsetValueType->yes() || !$type->isConstantArray()->yes() ? [] : [sprintf('Array %s have offset %s.', $hasOffsetValueType->no() ? 'does not' : 'might not', $keyType->describe(VerbosityLevel::value()))]); + $hasOffset = new AcceptsResult( + $hasOffsetValueType, + $hasOffsetValueType->yes() || !$type->isConstantArray()->yes() ? [] : [sprintf('Array %s have offset %s.', $hasOffsetValueType->no() ? 'does not' : 'might not', $keyType->describe(VerbosityLevel::value()))], + ); if ($hasOffset->no()) { if ($this->isOptionalKey($i)) { continue; @@ -328,12 +326,23 @@ public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult $result = $result->and($hasOffset); $otherValueType = $type->getOffsetValueType($keyType); $verbosity = VerbosityLevel::getRecommendedLevelByType($valueType, $otherValueType); - $acceptsValue = $valueType->acceptsWithReason($otherValueType, $strictTypes)->decorateReasons(static function (string $reason) use($keyType, $valueType, $verbosity, $otherValueType) { - return sprintf('Offset %s (%s) does not accept type %s: %s', $keyType->describe(VerbosityLevel::value()), $valueType->describe($verbosity), $otherValueType->describe($verbosity), $reason); - }); + $acceptsValue = $valueType->acceptsWithReason($otherValueType, $strictTypes)->decorateReasons( + static fn (string $reason) => sprintf( + 'Offset %s (%s) does not accept type %s: %s', + $keyType->describe(VerbosityLevel::value()), + $valueType->describe($verbosity), + $otherValueType->describe($verbosity), + $reason, + ), + ); if (!$acceptsValue->yes() && count($acceptsValue->reasons) === 0 && $type->isConstantArray()->yes()) { $acceptsValue = new AcceptsResult($acceptsValue->result, [ - sprintf('Offset %s (%s) does not accept type %s.', $keyType->describe(VerbosityLevel::value()), $valueType->describe($verbosity), $otherValueType->describe($verbosity)), + sprintf( + 'Offset %s (%s) does not accept type %s.', + $keyType->describe(VerbosityLevel::value()), + $valueType->describe($verbosity), + $otherValueType->describe($verbosity), + ), ]); } if ($acceptsValue->no()) { @@ -455,17 +464,18 @@ public function isCallable(): TrinaryLogic return TrinaryLogic::createNo(); } - $results = array_map(static function (ConstantArrayTypeAndMethod $typeAndMethod) : TrinaryLogic { - return $typeAndMethod->getCertainty(); - }, $typeAndMethods); + $results = array_map( + static fn (ConstantArrayTypeAndMethod $typeAndMethod): TrinaryLogic => $typeAndMethod->getCertainty(), + $typeAndMethods, + ); return TrinaryLogic::createYes()->and(...$results); } /** - * @return ParametersAcceptor[] - */ - public function getCallableParametersAcceptors(ClassMemberAccessAnswerer $scope): array + * @return ParametersAcceptor[] + */ + public function getCallableParametersAcceptors(ClassMemberAccessAnswerer $scope): array { $typeAndMethodNames = $this->findTypeAndMethodNames(); if ($typeAndMethodNames === []) { @@ -494,9 +504,9 @@ public function getCallableParametersAcceptors(ClassMemberAccessAnswerer $scope) } /** - * @return array{Type, Type}|array{} - */ - private function getClassOrObjectAndMethods(): array + * @return array{Type, Type}|array{} + */ + private function getClassOrObjectAndMethods(): array { if (count($this->keyTypes) !== 2) { return []; @@ -525,7 +535,7 @@ private function getClassOrObjectAndMethods(): array } /** @deprecated Use findTypeAndMethodNames() instead */ - public function findTypeAndMethodName(): ?ConstantArrayTypeAndMethod + public function findTypeAndMethodName(): ?ConstantArrayTypeAndMethod { $callableArray = $this->getClassOrObjectAndMethods(); if ($callableArray === []) { @@ -555,7 +565,7 @@ public function findTypeAndMethodName(): ?ConstantArrayTypeAndMethod } /** @return ConstantArrayTypeAndMethod[] */ - public function findTypeAndMethodNames(): array + public function findTypeAndMethodNames(): array { $callableArray = $this->getClassOrObjectAndMethods(); if ($callableArray === []) { @@ -774,7 +784,11 @@ public function flipArray(): Type foreach ($this->keyTypes as $i => $keyType) { $valueType = $this->valueTypes[$i]; - $builder->setOffsetValueType($valueType->toArrayKey(), $keyType, $this->isOptionalKey($i)); + $builder->setOffsetValueType( + $valueType->toArrayKey(), + $keyType, + $this->isOptionalKey($i), + ); } return $builder->getArray(); @@ -948,13 +962,13 @@ public function isList(): TrinaryLogic } /** @deprecated Use popArray() instead */ - public function removeLast(): self + public function removeLast(): self { return $this->removeLastElements(1); } /** @param positive-int $length */ - private function removeLastElements(int $length): self + private function removeLastElements(int $length): self { $keyTypesCount = count($this->keyTypes); if ($keyTypesCount === 0) { @@ -998,17 +1012,23 @@ private function removeLastElements(int $length): self $optionalKeysRemoved--; } - return new self($keyTypes, $valueTypes, $nextAutoindex, array_values($optionalKeys), $this->isList); + return new self( + $keyTypes, + $valueTypes, + $nextAutoindex, + array_values($optionalKeys), + $this->isList, + ); } /** @deprecated Use shiftArray() instead */ - public function removeFirst(): self + public function removeFirst(): self { return $this->removeFirstElements(1); } /** @param positive-int $length */ - private function removeFirstElements(int $length, bool $reindex = true): self + private function removeFirstElements(int $length, bool $reindex = true): self { $builder = ConstantArrayTypeBuilder::createEmpty(); @@ -1050,7 +1070,7 @@ public function slice(int $offset, ?int $limit, bool $preserveKeys = false): sel return $this; } - $limit = $limit ?? $keyTypesCount; + $limit ??= $keyTypesCount; if ($limit < 0) { // Negative limits prevent access to the most right n elements return $this->removeLastElements($limit * -1) @@ -1125,9 +1145,7 @@ public function reverse(bool $preserveKeys = false): self $keyTypesReversed = array_reverse($this->keyTypes, true); $keyTypes = array_values($keyTypesReversed); $keyTypesReversedKeys = array_keys($keyTypesReversed); - $optionalKeys = array_map(static function (int $optionalKey) use($keyTypesReversedKeys) : int { - return $keyTypesReversedKeys[$optionalKey]; - }, $this->optionalKeys); + $optionalKeys = array_map(static fn (int $optionalKey): int => $keyTypesReversedKeys[$optionalKey], $this->optionalKeys); $reversed = new self($keyTypes, array_reverse($this->valueTypes), $this->nextAutoIndexes, $optionalKeys, TrinaryLogic::createNo()); @@ -1135,7 +1153,7 @@ public function reverse(bool $preserveKeys = false): self } /** @param positive-int $length */ - public function chunk(int $length, bool $preserveKeys = false): self + public function chunk(int $length, bool $preserveKeys = false): self { $builder = ConstantArrayTypeBuilder::createEmpty(); @@ -1193,12 +1211,13 @@ public function generalize(GeneralizePrecision $precision): Type } if ($precision->isTemplateArgument()) { - return $this->traverse(static function (Type $type) use($precision) { - return $type->generalize($precision); - }); + return $this->traverse(static fn (Type $type) => $type->generalize($precision)); } - $arrayType = new ArrayType($this->getKeyType()->generalize($precision), $this->getItemType()->generalize($precision)); + $arrayType = new ArrayType( + $this->getKeyType()->generalize($precision), + $this->getItemType()->generalize($precision), + ); $keyTypesCount = count($this->keyTypes); $optionalKeysCount = count($this->optionalKeys); @@ -1228,9 +1247,9 @@ public function generalize(GeneralizePrecision $precision): Type } /** - * @return self - */ - public function generalizeValues(): ArrayType + * @return self + */ + public function generalizeValues(): ArrayType { $valueTypes = []; foreach ($this->valueTypes as $valueType) { @@ -1241,7 +1260,7 @@ public function generalizeValues(): ArrayType } /** @deprecated */ - public function generalizeToArray(): Type + public function generalizeToArray(): Type { $isIterableAtLeastOnce = $this->isIterableAtLeastOnce(); if ($isIterableAtLeastOnce->no()) { @@ -1261,25 +1280,25 @@ public function generalizeToArray(): Type } /** - * @return self - */ - public function getKeysArray(): Type + * @return self + */ + public function getKeysArray(): Type { return $this->getKeysOrValuesArray($this->keyTypes); } /** - * @return self - */ - public function getValuesArray(): Type + * @return self + */ + public function getValuesArray(): Type { return $this->getKeysOrValuesArray($this->valueTypes); } /** - * @param array $types - */ - private function getKeysOrValuesArray(array $types): self + * @param array $types + */ + private function getKeysOrValuesArray(array $types): self { $count = count($types); $autoIndexes = range($count - count($this->optionalKeys), $count); @@ -1287,9 +1306,10 @@ private function getKeysOrValuesArray(array $types): self if ($this->isList->yes()) { // Optimized version for lists: Assume that if a later key exists, then earlier keys also exist. - $keyTypes = array_map(static function (int $i) : ConstantIntegerType { - return new ConstantIntegerType($i); - }, array_keys($types)); + $keyTypes = array_map( + static fn (int $i): ConstantIntegerType => new ConstantIntegerType($i), + array_keys($types), + ); return new self($keyTypes, $types, $autoIndexes, $this->optionalKeys, TrinaryLogic::createYes()); } @@ -1323,7 +1343,7 @@ private function getKeysOrValuesArray(array $types): self } /** @deprecated Use getArraySize() instead */ - public function count(): Type + public function count(): Type { return $this->getArraySize(); } @@ -1366,15 +1386,17 @@ public function describe(VerbosityLevel $level): string $append = ', ...'; } - return sprintf('array{%s%s}', implode(', ', $exportValuesOnly ? $values : $items), $append); + return sprintf( + 'array{%s%s}', + implode(', ', $exportValuesOnly ? $values : $items), + $append, + ); }; - return $level->handle(function () use($level) : string { - return parent::describe($level); - }, static function () use($describeValue) : string { - return $describeValue(true); - }, static function () use($describeValue) : string { - return $describeValue(false); - }); + return $level->handle( + fn (): string => parent::describe($level), + static fn (): string => $describeValue(true), + static fn (): string => $describeValue(false), + ); } public function inferTemplateTypes(Type $receivedType): TemplateTypeMap @@ -1546,18 +1568,18 @@ public function mergeWith(self $otherArray): self } /** - * @param ConstantIntegerType|ConstantStringType $otherKeyType - */ - private function getKeyIndex($otherKeyType): ?int + * @param ConstantIntegerType|ConstantStringType $otherKeyType + */ + private function getKeyIndex($otherKeyType): ?int { return self::findKeyIndex($otherKeyType, $this->keyTypes); } /** - * @param ConstantIntegerType|ConstantStringType $otherKeyType - * @param array $keyTypes - */ - private static function findKeyIndex($otherKeyType, array $keyTypes): ?int + * @param ConstantIntegerType|ConstantStringType $otherKeyType + * @param array $keyTypes + */ + private static function findKeyIndex($otherKeyType, array $keyTypes): ?int { foreach ($keyTypes as $i => $keyType) { if ($keyType->equals($otherKeyType)) { @@ -1618,8 +1640,16 @@ public function toPhpDocNode(): TypeNode if ($isOptional) { $exportValuesOnly = false; } - $items[] = new ArrayShapeItemNode($keyNode, $isOptional, $valueType->toPhpDocNode()); - $values[] = new ArrayShapeItemNode(null, $isOptional, $valueType->toPhpDocNode()); + $items[] = new ArrayShapeItemNode( + $keyNode, + $isOptional, + $valueType->toPhpDocNode(), + ); + $values[] = new ArrayShapeItemNode( + null, + $isOptional, + $valueType->toPhpDocNode(), + ); } return new ArrayShapeNode($exportValuesOnly ? $values : $items); @@ -1672,9 +1702,9 @@ public function getFiniteTypes(): array } /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): Type + * @param mixed[] $properties + */ + public static function __set_state(array $properties): Type { return new self($properties['keyTypes'], $properties['valueTypes'], $properties['nextAutoIndexes'] ?? $properties['nextAutoIndex'], $properties['optionalKeys'] ?? [], $properties['isList'] ?? TrinaryLogic::createNo()); } diff --git a/src/Type/Constant/ConstantArrayTypeAndMethod.php b/src/Type/Constant/ConstantArrayTypeAndMethod.php index 453cfed6196..e5bd1caf7b3 100644 --- a/src/Type/Constant/ConstantArrayTypeAndMethod.php +++ b/src/Type/Constant/ConstantArrayTypeAndMethod.php @@ -10,32 +10,27 @@ class ConstantArrayTypeAndMethod { - /** - * @var ?Type - */ - private $type; - /** - * @var ?string - */ - private $method; - /** - * @var TrinaryLogic - */ - private $certainty; - private function __construct(?Type $type, ?string $method, TrinaryLogic $certainty) - { - $this->type = $type; - $this->method = $method; - $this->certainty = $certainty; - } - public static function createConcrete(Type $type, string $method, TrinaryLogic $certainty) : self - { - if ($certainty->no()) { - throw new ShouldNotHappenException(); - } - return new self($type, $method, $certainty); + private function __construct( + private ?Type $type, + private ?string $method, + private TrinaryLogic $certainty, + ) + { + } + + public static function createConcrete( + Type $type, + string $method, + TrinaryLogic $certainty, + ): self + { + if ($certainty->no()) { + throw new ShouldNotHappenException(); } - public static function createUnknown(): self + return new self($type, $method, $certainty); + } + + public static function createUnknown(): self { return new self(null, null, TrinaryLogic::createMaybe()); } diff --git a/src/Type/Constant/ConstantArrayTypeBuilder.php b/src/Type/Constant/ConstantArrayTypeBuilder.php index 08b844a8cff..8547fa39a92 100644 --- a/src/Type/Constant/ConstantArrayTypeBuilder.php +++ b/src/Type/Constant/ConstantArrayTypeBuilder.php @@ -26,37 +26,11 @@ class ConstantArrayTypeBuilder { - /** - * @var array - */ - private $keyTypes; - /** - * @var array - */ - private $valueTypes; - /** - * @var non-empty-list - */ - private $nextAutoIndexes; - /** - * @var array - */ - private $optionalKeys; - /** - * @var TrinaryLogic - */ - private $isList; public const ARRAY_COUNT_LIMIT = 256; - /** - * @var bool - */ - private $degradeToGeneralArray = false; + private bool $degradeToGeneralArray = false; - /** - * @var bool - */ - private $oversized = false; + private bool $oversized = false; /** * @param array $keyTypes @@ -64,13 +38,14 @@ class ConstantArrayTypeBuilder * @param non-empty-list $nextAutoIndexes * @param array $optionalKeys */ - private function __construct(array $keyTypes, array $valueTypes, array $nextAutoIndexes, array $optionalKeys, TrinaryLogic $isList) + private function __construct( + private array $keyTypes, + private array $valueTypes, + private array $nextAutoIndexes, + private array $optionalKeys, + private TrinaryLogic $isList, + ) { - $this->keyTypes = $keyTypes; - $this->valueTypes = $valueTypes; - $this->nextAutoIndexes = $nextAutoIndexes; - $this->optionalKeys = $optionalKeys; - $this->isList = $isList; } public static function createEmpty(): self @@ -80,7 +55,13 @@ public static function createEmpty(): self public static function createFromConstantArray(ConstantArrayType $startArrayType): self { - $builder = new self($startArrayType->getKeyTypes(), $startArrayType->getValueTypes(), $startArrayType->getNextAutoIndexes(), $startArrayType->getOptionalKeys(), $startArrayType->isList()); + $builder = new self( + $startArrayType->getKeyTypes(), + $startArrayType->getValueTypes(), + $startArrayType->getNextAutoIndexes(), + $startArrayType->getOptionalKeys(), + $startArrayType->isList(), + ); if (count($startArrayType->getKeyTypes()) > self::ARRAY_COUNT_LIMIT) { $builder->degradeToGeneralArray(true); @@ -111,9 +92,7 @@ public function setOffsetValueType(?Type $offsetType, Type $valueType, bool $opt $this->valueTypes[$i] = TypeCombinator::union($this->valueTypes[$i], $valueType); if (!$hasOptional && !$optional) { - $this->optionalKeys = array_values(array_filter($this->optionalKeys, static function (int $index) use($i) : bool { - return $index !== $i; - })); + $this->optionalKeys = array_values(array_filter($this->optionalKeys, static fn (int $index): bool => $index !== $i)); } /** @var int|float $newAutoIndex */ @@ -165,13 +144,9 @@ public function setOffsetValueType(?Type $offsetType, Type $valueType, bool $opt $this->valueTypes[$i] = $valueType; if (!$optional) { - $this->optionalKeys = array_values(array_filter($this->optionalKeys, static function (int $index) use($i) : bool { - return $index !== $i; - })); + $this->optionalKeys = array_values(array_filter($this->optionalKeys, static fn (int $index): bool => $index !== $i)); if ($keyType instanceof ConstantIntegerType) { - $nextAutoIndexes = array_values(array_filter($this->nextAutoIndexes, static function (int $index) use($keyType) { - return $index > $keyType->getValue(); - })); + $nextAutoIndexes = array_values(array_filter($this->nextAutoIndexes, static fn (int $index) => $index > $keyType->getValue())); if (count($nextAutoIndexes) === 0) { throw new ShouldNotHappenException(); } @@ -282,9 +257,7 @@ public function setOffsetValueType(?Type $offsetType, Type $valueType, bool $opt } if ($offsetType === null) { - $offsetType = TypeCombinator::union(...array_map(static function (int $index) { - return new ConstantIntegerType($index); - }, $this->nextAutoIndexes)); + $offsetType = TypeCombinator::union(...array_map(static fn (int $index) => new ConstantIntegerType($index), $this->nextAutoIndexes)); } else { $this->isList = TrinaryLogic::createNo(); } @@ -316,7 +289,10 @@ public function getArray(): Type return new ConstantArrayType($keyTypes, $this->valueTypes, $this->nextAutoIndexes, $this->optionalKeys, $this->isList); } - $array = new ArrayType(TypeCombinator::union(...$this->keyTypes), TypeCombinator::union(...$this->valueTypes)); + $array = new ArrayType( + TypeCombinator::union(...$this->keyTypes), + TypeCombinator::union(...$this->valueTypes), + ); if (count($this->optionalKeys) < $keyTypesCount) { $array = TypeCombinator::intersect($array, new NonEmptyArrayType()); diff --git a/src/Type/Constant/ConstantBooleanType.php b/src/Type/Constant/ConstantBooleanType.php index efb0af8e060..88b7822f6aa 100644 --- a/src/Type/Constant/ConstantBooleanType.php +++ b/src/Type/Constant/ConstantBooleanType.php @@ -20,18 +20,13 @@ class ConstantBooleanType extends BooleanType implements ConstantScalarType { - /** - * @var bool - */ - private $value; use ConstantScalarTypeTrait { looseCompare as private scalarLooseCompare; } /** @api */ - public function __construct(bool $value) + public function __construct(private bool $value) { - $this->value = $value; parent::__construct(); } diff --git a/src/Type/Constant/ConstantFloatType.php b/src/Type/Constant/ConstantFloatType.php index 6055c87f318..229bf6696f2 100644 --- a/src/Type/Constant/ConstantFloatType.php +++ b/src/Type/Constant/ConstantFloatType.php @@ -25,18 +25,13 @@ class ConstantFloatType extends FloatType implements ConstantScalarType { - /** - * @var float - */ - private $value; use ConstantScalarTypeTrait; use ConstantScalarToBooleanTrait; use ConstantNumericComparisonTypeTrait; /** @api */ - public function __construct(float $value) + public function __construct(private float $value) { - $this->value = $value; parent::__construct(); } @@ -68,11 +63,10 @@ private function castFloatToString(float $value): string public function describe(VerbosityLevel $level): string { - return $level->handle(static function () : string { - return 'float'; - }, function () : string { - return $this->castFloatToString($this->value); - }); + return $level->handle( + static fn (): string => 'float', + fn (): string => $this->castFloatToString($this->value), + ); } public function isSuperTypeOf(Type $type): TrinaryLogic diff --git a/src/Type/Constant/ConstantIntegerType.php b/src/Type/Constant/ConstantIntegerType.php index d321e067934..ae3d0511a88 100644 --- a/src/Type/Constant/ConstantIntegerType.php +++ b/src/Type/Constant/ConstantIntegerType.php @@ -21,18 +21,13 @@ class ConstantIntegerType extends IntegerType implements ConstantScalarType { - /** - * @var int - */ - private $value; use ConstantScalarTypeTrait; use ConstantScalarToBooleanTrait; use ConstantNumericComparisonTypeTrait; /** @api */ - public function __construct(int $value) + public function __construct(private int $value) { - $this->value = $value; parent::__construct(); } @@ -70,11 +65,10 @@ public function isSuperTypeOf(Type $type): TrinaryLogic public function describe(VerbosityLevel $level): string { - return $level->handle(static function () : string { - return 'int'; - }, function () : string { - return sprintf('%s', $this->value); - }); + return $level->handle( + static fn (): string => 'int', + fn (): string => sprintf('%s', $this->value), + ); } public function toFloat(): Type diff --git a/src/Type/Constant/ConstantStringType.php b/src/Type/Constant/ConstantStringType.php index e47ede523a4..1b957df3612 100644 --- a/src/Type/Constant/ConstantStringType.php +++ b/src/Type/Constant/ConstantStringType.php @@ -54,34 +54,18 @@ class ConstantStringType extends StringType implements ConstantScalarType { - /** - * @var string - */ - private $value; - /** - * @var bool - */ - private $isClassString; private const DESCRIBE_LIMIT = 20; use ConstantScalarTypeTrait; use ConstantScalarToBooleanTrait; - /** - * @var ?ObjectType - */ - private $objectType = null; + private ?ObjectType $objectType = null; - /** - * @var ?Type - */ - private $arrayKeyType = null; + private ?Type $arrayKeyType = null; /** @api */ - public function __construct(string $value, bool $isClassString = false) + public function __construct(private string $value, private bool $isClassString = false) { - $this->value = $value; - $this->isClassString = $isClassString; parent::__construct(); } @@ -130,23 +114,23 @@ public function isClassString(): bool public function describe(VerbosityLevel $level): string { - return $level->handle(static function () : string { - return 'string'; - }, function (): string { + return $level->handle( + static fn (): string => 'string', + function (): string { $value = $this->value; if (!$this->isClassString) { try { $value = Strings::truncate($value, self::DESCRIBE_LIMIT); - } catch (RegexpException $e) { + } catch (RegexpException) { $value = substr($value, 0, self::DESCRIBE_LIMIT) . "\u{2026}"; } } return self::export($value); - }, function () : string { - return self::export($this->value); - }); + }, + fn (): string => self::export($this->value), + ); } private function export(string $value): string @@ -354,7 +338,9 @@ public function isLiteralString(): TrinaryLogic public function hasOffsetValueType(Type $offsetType): TrinaryLogic { if ($offsetType instanceof ConstantIntegerType) { - return TrinaryLogic::createFromBoolean($offsetType->getValue() < strlen($this->value)); + return TrinaryLogic::createFromBoolean( + $offsetType->getValue() < strlen($this->value), + ); } return parent::hasOffsetValueType($offsetType); @@ -517,7 +503,7 @@ public function getConstant(string $constantName): ConstantReflection private function getObjectType(): ObjectType { - return $this->objectType = $this->objectType ?? new ObjectType($this->value); + return $this->objectType ??= new ObjectType($this->value); } public function toPhpDocNode(): TypeNode diff --git a/src/Type/Constant/OversizedArrayBuilder.php b/src/Type/Constant/OversizedArrayBuilder.php index b9a8a6db16c..663f1c15130 100644 --- a/src/Type/Constant/OversizedArrayBuilder.php +++ b/src/Type/Constant/OversizedArrayBuilder.php @@ -50,10 +50,16 @@ public function build(Array_ $expr, callable $getTypeCallback): Type } else { $keyExpr = new TypeExpr($innerKeyType); } - array_splice($items, $i++, 0, [new Expr\ArrayItem(new TypeExpr($innerValueType), $keyExpr)]); + array_splice($items, $i++, 0, [new Expr\ArrayItem( + new TypeExpr($innerValueType), + $keyExpr, + )]); } } else { - array_splice($items, $i, 1, [new Expr\ArrayItem(new TypeExpr($valueType->getIterableValueType()), new TypeExpr($valueType->getIterableKeyType()))]); + array_splice($items, $i, 1, [new Expr\ArrayItem( + new TypeExpr($valueType->getIterableValueType()), + new TypeExpr($valueType->getIterableKeyType()), + )]); } } foreach ($items as $item) { diff --git a/src/Type/DirectTypeAliasResolverProvider.php b/src/Type/DirectTypeAliasResolverProvider.php index c3ba9b5d4a1..b64fe8f46da 100644 --- a/src/Type/DirectTypeAliasResolverProvider.php +++ b/src/Type/DirectTypeAliasResolverProvider.php @@ -5,13 +5,8 @@ class DirectTypeAliasResolverProvider implements TypeAliasResolverProvider { - /** - * @var TypeAliasResolver - */ - private $typeAliasResolver; - public function __construct(TypeAliasResolver $typeAliasResolver) + public function __construct(private TypeAliasResolver $typeAliasResolver) { - $this->typeAliasResolver = $typeAliasResolver; } public function getTypeAliasResolver(): TypeAliasResolver diff --git a/src/Type/DynamicReturnTypeExtensionRegistry.php b/src/Type/DynamicReturnTypeExtensionRegistry.php index db5247bddd6..ea3c27a13c6 100644 --- a/src/Type/DynamicReturnTypeExtensionRegistry.php +++ b/src/Type/DynamicReturnTypeExtensionRegistry.php @@ -11,52 +11,38 @@ class DynamicReturnTypeExtensionRegistry { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - /** - * @var DynamicMethodReturnTypeExtension[] - */ - private $dynamicMethodReturnTypeExtensions; - /** - * @var DynamicStaticMethodReturnTypeExtension[] - */ - private $dynamicStaticMethodReturnTypeExtensions; - /** - * @var DynamicFunctionReturnTypeExtension[] - */ - private $dynamicFunctionReturnTypeExtensions; - /** @var DynamicMethodReturnTypeExtension[][]|null */ - private $dynamicMethodReturnTypeExtensionsByClass = null; + /** @var DynamicMethodReturnTypeExtension[][]|null */ + private ?array $dynamicMethodReturnTypeExtensionsByClass = null; /** @var DynamicStaticMethodReturnTypeExtension[][]|null */ - private $dynamicStaticMethodReturnTypeExtensionsByClass = null; + private ?array $dynamicStaticMethodReturnTypeExtensionsByClass = null; /** - * @param DynamicMethodReturnTypeExtension[] $dynamicMethodReturnTypeExtensions - * @param DynamicStaticMethodReturnTypeExtension[] $dynamicStaticMethodReturnTypeExtensions - * @param DynamicFunctionReturnTypeExtension[] $dynamicFunctionReturnTypeExtensions - */ - public function __construct(Broker $broker, ReflectionProvider $reflectionProvider, array $dynamicMethodReturnTypeExtensions, array $dynamicStaticMethodReturnTypeExtensions, array $dynamicFunctionReturnTypeExtensions) - { - $this->reflectionProvider = $reflectionProvider; - $this->dynamicMethodReturnTypeExtensions = $dynamicMethodReturnTypeExtensions; - $this->dynamicStaticMethodReturnTypeExtensions = $dynamicStaticMethodReturnTypeExtensions; - $this->dynamicFunctionReturnTypeExtensions = $dynamicFunctionReturnTypeExtensions; - foreach (array_merge($dynamicMethodReturnTypeExtensions, $dynamicStaticMethodReturnTypeExtensions, $dynamicFunctionReturnTypeExtensions) as $extension) { - if (!($extension instanceof BrokerAwareExtension)) { - continue; - } - - $extension->setBroker($broker); - } + * @param DynamicMethodReturnTypeExtension[] $dynamicMethodReturnTypeExtensions + * @param DynamicStaticMethodReturnTypeExtension[] $dynamicStaticMethodReturnTypeExtensions + * @param DynamicFunctionReturnTypeExtension[] $dynamicFunctionReturnTypeExtensions + */ + public function __construct( + Broker $broker, + private ReflectionProvider $reflectionProvider, + private array $dynamicMethodReturnTypeExtensions, + private array $dynamicStaticMethodReturnTypeExtensions, + private array $dynamicFunctionReturnTypeExtensions, + ) + { + foreach (array_merge($dynamicMethodReturnTypeExtensions, $dynamicStaticMethodReturnTypeExtensions, $dynamicFunctionReturnTypeExtensions) as $extension) { + if (!($extension instanceof BrokerAwareExtension)) { + continue; } + $extension->setBroker($broker); + } + } + /** - * @return DynamicMethodReturnTypeExtension[] - */ - public function getDynamicMethodReturnTypeExtensionsForClass(string $className): array + * @return DynamicMethodReturnTypeExtension[] + */ + public function getDynamicMethodReturnTypeExtensionsForClass(string $className): array { if ($this->dynamicMethodReturnTypeExtensionsByClass === null) { $byClass = []; @@ -70,9 +56,9 @@ public function getDynamicMethodReturnTypeExtensionsForClass(string $className): } /** - * @return DynamicStaticMethodReturnTypeExtension[] - */ - public function getDynamicStaticMethodReturnTypeExtensionsForClass(string $className): array + * @return DynamicStaticMethodReturnTypeExtension[] + */ + public function getDynamicStaticMethodReturnTypeExtensionsForClass(string $className): array { if ($this->dynamicStaticMethodReturnTypeExtensionsByClass === null) { $byClass = []; @@ -86,10 +72,10 @@ public function getDynamicStaticMethodReturnTypeExtensionsForClass(string $class } /** - * @param DynamicMethodReturnTypeExtension[][]|DynamicStaticMethodReturnTypeExtension[][] $extensions - * @return mixed[] - */ - private function getDynamicExtensionsForType(array $extensions, string $className): array + * @param DynamicMethodReturnTypeExtension[][]|DynamicStaticMethodReturnTypeExtension[][] $extensions + * @return mixed[] + */ + private function getDynamicExtensionsForType(array $extensions, string $className): array { if (!$this->reflectionProvider->hasClass($className)) { return []; @@ -110,9 +96,9 @@ private function getDynamicExtensionsForType(array $extensions, string $classNam } /** - * @return DynamicFunctionReturnTypeExtension[] - */ - public function getDynamicFunctionReturnTypeExtensions(): array + * @return DynamicFunctionReturnTypeExtension[] + */ + public function getDynamicFunctionReturnTypeExtensions(): array { return $this->dynamicFunctionReturnTypeExtensions; } diff --git a/src/Type/Enum/EnumCaseObjectType.php b/src/Type/Enum/EnumCaseObjectType.php index 423be3ac52f..4589f8e4c2c 100644 --- a/src/Type/Enum/EnumCaseObjectType.php +++ b/src/Type/Enum/EnumCaseObjectType.php @@ -25,16 +25,16 @@ class EnumCaseObjectType extends ObjectType { - /** - * @var string - */ - private $enumCaseName; /** @api */ - public function __construct(string $className, string $enumCaseName, ?ClassReflection $classReflection = null) + public function __construct( + string $className, + private string $enumCaseName, + ?ClassReflection $classReflection = null, + ) { - $this->enumCaseName = $enumCaseName; parent::__construct($className, null, $classReflection); } + public function getEnumCaseName(): string { return $this->enumCaseName; @@ -70,8 +70,10 @@ public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult public function isSuperTypeOf(Type $type): TrinaryLogic { if ($type instanceof self) { - return TrinaryLogic::createFromBoolean($this->getClassName() === $type->getClassName() - && $this->enumCaseName === $type->enumCaseName); + return TrinaryLogic::createFromBoolean( + $this->getClassName() === $type->getClassName() + && $this->enumCaseName === $type->enumCaseName, + ); } if ($type instanceof CompoundType) { @@ -120,7 +122,9 @@ public function getUnresolvedPropertyPrototype(string $propertyName, ClassMember } if ($propertyName === 'name') { - return new EnumUnresolvedPropertyPrototypeReflection(new EnumPropertyReflection($classReflection, new ConstantStringType($this->enumCaseName))); + return new EnumUnresolvedPropertyPrototypeReflection( + new EnumPropertyReflection($classReflection, new ConstantStringType($this->enumCaseName)), + ); } if ($classReflection->isBackedEnum() && $propertyName === 'value') { @@ -131,7 +135,9 @@ public function getUnresolvedPropertyPrototype(string $propertyName, ClassMember throw new ShouldNotHappenException(); } - return new EnumUnresolvedPropertyPrototypeReflection(new EnumPropertyReflection($classReflection, $valueType)); + return new EnumUnresolvedPropertyPrototypeReflection( + new EnumPropertyReflection($classReflection, $valueType), + ); } } @@ -180,7 +186,12 @@ public function getEnumCases(): array public function toPhpDocNode(): TypeNode { - return new ConstTypeNode(new ConstFetchNode($this->getClassName(), $this->getEnumCaseName())); + return new ConstTypeNode( + new ConstFetchNode( + $this->getClassName(), + $this->getEnumCaseName(), + ), + ); } /** diff --git a/src/Type/ErrorType.php b/src/Type/ErrorType.php index 8509692d562..345465b306b 100644 --- a/src/Type/ErrorType.php +++ b/src/Type/ErrorType.php @@ -14,13 +14,11 @@ public function __construct() public function describe(VerbosityLevel $level): string { - return $level->handle(function () use($level) : string { - return parent::describe($level); - }, function () use($level) : string { - return parent::describe($level); - }, static function () : string { - return '*ERROR*'; - }); + return $level->handle( + fn (): string => parent::describe($level), + fn (): string => parent::describe($level), + static fn (): string => '*ERROR*', + ); } public function getIterableKeyType(): Type diff --git a/src/Type/ExpressionTypeResolverExtensionRegistry.php b/src/Type/ExpressionTypeResolverExtensionRegistry.php index 98edce4435c..75c0d0b5ec9 100644 --- a/src/Type/ExpressionTypeResolverExtensionRegistry.php +++ b/src/Type/ExpressionTypeResolverExtensionRegistry.php @@ -5,17 +5,15 @@ class ExpressionTypeResolverExtensionRegistry { - /** - * @var array - */ - private $extensions; /** * @param array $extensions */ - public function __construct(array $extensions) + public function __construct( + private array $extensions, + ) { - $this->extensions = $extensions; } + /** * @return array */ diff --git a/src/Type/FileTypeMapper.php b/src/Type/FileTypeMapper.php index 4f5ed18cda4..7886d40e7e6 100644 --- a/src/Type/FileTypeMapper.php +++ b/src/Type/FileTypeMapper.php @@ -41,108 +41,101 @@ class FileTypeMapper { - /** - * @var ReflectionProviderProvider - */ - private $reflectionProviderProvider; - /** - * @var Parser - */ - private $phpParser; - /** - * @var PhpDocStringResolver - */ - private $phpDocStringResolver; - /** - * @var PhpDocNodeResolver - */ - private $phpDocNodeResolver; - /** - * @var AnonymousClassNameHelper - */ - private $anonymousClassNameHelper; - /** - * @var FileHelper - */ - private $fileHelper; - private const SKIP_NODE = 1; + private const SKIP_NODE = 1; private const POP_TYPE_MAP_STACK = 2; /** @var NameScope[][] */ - private $memoryCache = []; + private array $memoryCache = []; - /** - * @var int - */ - private $memoryCacheCount = 0; + private int $memoryCacheCount = 0; /** @var (true|callable(): NameScope|NameScope)[][] */ - private $inProcess = []; + private array $inProcess = []; /** @var array */ - private $resolvedPhpDocBlockCache = []; + private array $resolvedPhpDocBlockCache = []; + + private int $resolvedPhpDocBlockCacheCount = 0; + + public function __construct( + private ReflectionProviderProvider $reflectionProviderProvider, + private Parser $phpParser, + private PhpDocStringResolver $phpDocStringResolver, + private PhpDocNodeResolver $phpDocNodeResolver, + private AnonymousClassNameHelper $anonymousClassNameHelper, + private FileHelper $fileHelper, + ) + { + } - /** - * @var int - */ - private $resolvedPhpDocBlockCacheCount = 0; - - public function __construct(ReflectionProviderProvider $reflectionProviderProvider, Parser $phpParser, PhpDocStringResolver $phpDocStringResolver, PhpDocNodeResolver $phpDocNodeResolver, AnonymousClassNameHelper $anonymousClassNameHelper, FileHelper $fileHelper) - { - $this->reflectionProviderProvider = $reflectionProviderProvider; - $this->phpParser = $phpParser; - $this->phpDocStringResolver = $phpDocStringResolver; - $this->phpDocNodeResolver = $phpDocNodeResolver; - $this->anonymousClassNameHelper = $anonymousClassNameHelper; - $this->fileHelper = $fileHelper; + /** @api */ + public function getResolvedPhpDoc( + ?string $fileName, + ?string $className, + ?string $traitName, + ?string $functionName, + string $docComment, + ): ResolvedPhpDocBlock + { + if ($className === null && $traitName !== null) { + throw new ShouldNotHappenException(); } - /** @api */ - public function getResolvedPhpDoc(?string $fileName, ?string $className, ?string $traitName, ?string $functionName, string $docComment) : ResolvedPhpDocBlock - { - if ($className === null && $traitName !== null) { - throw new ShouldNotHappenException(); - } - if ($docComment === '') { - return ResolvedPhpDocBlock::createEmpty(); - } - if ($fileName !== null) { - $fileName = $this->fileHelper->normalizePath($fileName); - } - $nameScopeKey = $this->getNameScopeKey($fileName, $className, $traitName, $functionName); - $phpDocKey = md5(sprintf('%s-%s', $nameScopeKey, $docComment)); - if (isset($this->resolvedPhpDocBlockCache[$phpDocKey])) { - return $this->resolvedPhpDocBlockCache[$phpDocKey]; - } - if ($fileName === null) { - return $this->createResolvedPhpDocBlock($phpDocKey, new NameScope(null, []), $docComment, null); - } - $nameScopeMap = []; - if (!isset($this->inProcess[$fileName])) { - $nameScopeMap = $this->getNameScopeMap($fileName); - } - if (isset($nameScopeMap[$nameScopeKey])) { - return $this->createResolvedPhpDocBlock($phpDocKey, $nameScopeMap[$nameScopeKey], $docComment, $fileName); - } - if (!isset($this->inProcess[$fileName][$nameScopeKey])) { // wrong $fileName due to traits - return ResolvedPhpDocBlock::createEmpty(); - } - if ($this->inProcess[$fileName][$nameScopeKey] === true) { // PHPDoc has cyclic dependency - return ResolvedPhpDocBlock::createEmpty(); - } - if (is_callable($this->inProcess[$fileName][$nameScopeKey])) { - $resolveCallback = $this->inProcess[$fileName][$nameScopeKey]; - $this->inProcess[$fileName][$nameScopeKey] = true; - $this->inProcess[$fileName][$nameScopeKey] = $resolveCallback(); - } - return $this->createResolvedPhpDocBlock($phpDocKey, $this->inProcess[$fileName][$nameScopeKey], $docComment, $fileName); + if ($docComment === '') { + return ResolvedPhpDocBlock::createEmpty(); + } + + if ($fileName !== null) { + $fileName = $this->fileHelper->normalizePath($fileName); + } + + $nameScopeKey = $this->getNameScopeKey($fileName, $className, $traitName, $functionName); + $phpDocKey = md5(sprintf('%s-%s', $nameScopeKey, $docComment)); + if (isset($this->resolvedPhpDocBlockCache[$phpDocKey])) { + return $this->resolvedPhpDocBlockCache[$phpDocKey]; + } + + if ($fileName === null) { + return $this->createResolvedPhpDocBlock($phpDocKey, new NameScope(null, []), $docComment, null); + } + + $nameScopeMap = []; + + if (!isset($this->inProcess[$fileName])) { + $nameScopeMap = $this->getNameScopeMap($fileName); + } + + if (isset($nameScopeMap[$nameScopeKey])) { + return $this->createResolvedPhpDocBlock($phpDocKey, $nameScopeMap[$nameScopeKey], $docComment, $fileName); + } + + if (!isset($this->inProcess[$fileName][$nameScopeKey])) { // wrong $fileName due to traits + return ResolvedPhpDocBlock::createEmpty(); + } + + if ($this->inProcess[$fileName][$nameScopeKey] === true) { // PHPDoc has cyclic dependency + return ResolvedPhpDocBlock::createEmpty(); + } + + if (is_callable($this->inProcess[$fileName][$nameScopeKey])) { + $resolveCallback = $this->inProcess[$fileName][$nameScopeKey]; + $this->inProcess[$fileName][$nameScopeKey] = true; + $this->inProcess[$fileName][$nameScopeKey] = $resolveCallback(); } + return $this->createResolvedPhpDocBlock($phpDocKey, $this->inProcess[$fileName][$nameScopeKey], $docComment, $fileName); + } + private function createResolvedPhpDocBlock(string $phpDocKey, NameScope $nameScope, string $phpDocString, ?string $fileName): ResolvedPhpDocBlock { $phpDocNode = $this->phpDocStringResolver->resolve($phpDocString); if ($this->resolvedPhpDocBlockCacheCount >= 2048) { - $this->resolvedPhpDocBlockCache = array_slice($this->resolvedPhpDocBlockCache, 1, null, true); + $this->resolvedPhpDocBlockCache = array_slice( + $this->resolvedPhpDocBlockCache, + 1, + null, + true, + ); $this->resolvedPhpDocBlockCacheCount--; } @@ -158,21 +151,35 @@ private function createResolvedPhpDocBlock(string $phpDocKey, NameScope $nameSco $phpDocTemplateTypes[$name] = $templateType; } - $this->resolvedPhpDocBlockCache[$phpDocKey] = ResolvedPhpDocBlock::create($phpDocNode, $phpDocString, $fileName, $nameScope, new TemplateTypeMap($phpDocTemplateTypes), $templateTags, $this->phpDocNodeResolver, $this->reflectionProviderProvider->getReflectionProvider()); + $this->resolvedPhpDocBlockCache[$phpDocKey] = ResolvedPhpDocBlock::create( + $phpDocNode, + $phpDocString, + $fileName, + $nameScope, + new TemplateTypeMap($phpDocTemplateTypes), + $templateTags, + $this->phpDocNodeResolver, + $this->reflectionProviderProvider->getReflectionProvider(), + ); $this->resolvedPhpDocBlockCacheCount++; return $this->resolvedPhpDocBlockCache[$phpDocKey]; } /** - * @return NameScope[] - */ - private function getNameScopeMap(string $fileName): array + * @return NameScope[] + */ + private function getNameScopeMap(string $fileName): array { if (!isset($this->memoryCache[$fileName])) { $map = $this->createResolvedPhpDocMap($fileName); if ($this->memoryCacheCount >= 2048) { - $this->memoryCache = array_slice($this->memoryCache, 1, null, true); + $this->memoryCache = array_slice( + $this->memoryCache, + 1, + null, + true, + ); $this->memoryCacheCount--; } @@ -184,9 +191,9 @@ private function getNameScopeMap(string $fileName): array } /** - * @return NameScope[] - */ - private function createResolvedPhpDocMap(string $fileName): array + * @return NameScope[] + */ + private function createResolvedPhpDocMap(string $fileName): array { $phpDocNodeMap = $this->createPhpDocNodeMap($fileName, null, $fileName, [], $fileName); $nameScopeMap = $this->createNameScopeMap($fileName, null, null, [], $fileName, $phpDocNodeMap); @@ -209,10 +216,10 @@ private function createResolvedPhpDocMap(string $fileName): array } /** - * @param array $traitMethodAliases - * @return array - */ - private function createPhpDocNodeMap(string $fileName, ?string $lookForTrait, ?string $traitUseClass, array $traitMethodAliases, string $originalClassFileName): array + * @param array $traitMethodAliases + * @return array + */ + private function createPhpDocNodeMap(string $fileName, ?string $lookForTrait, ?string $traitUseClass, array $traitMethodAliases, string $originalClassFileName): array { /** @var array $phpDocNodeMap */ $phpDocNodeMap = []; @@ -228,7 +235,9 @@ private function createPhpDocNodeMap(string $fileName, ?string $lookForTrait, ?s /** @var array $functionStack */ $functionStack = []; - $this->processNodes($this->phpParser->parseFile($fileName), function (Node $node) use ($fileName, $lookForTrait, &$traitFound, $traitMethodAliases, $originalClassFileName, &$phpDocNodeMap, &$classStack, &$namespace, &$functionStack): ?int { + $this->processNodes( + $this->phpParser->parseFile($fileName), + function (Node $node) use ($fileName, $lookForTrait, &$traitFound, $traitMethodAliases, $originalClassFileName, &$phpDocNodeMap, &$classStack, &$namespace, &$functionStack): ?int { if ($node instanceof Node\Stmt\ClassLike) { if ($traitFound && $fileName === $originalClassFileName) { return self::SKIP_NODE; @@ -335,12 +344,19 @@ private function createPhpDocNodeMap(string $fileName, ?string $lookForTrait, ?s throw new ShouldNotHappenException(); } - $phpDocNodeMap = array_merge($phpDocNodeMap, $this->createPhpDocNodeMap($traitReflection->getFileName(), $traitName, $className, $traitMethodAliases[$traitName] ?? [], $originalClassFileName)); + $phpDocNodeMap = array_merge($phpDocNodeMap, $this->createPhpDocNodeMap( + $traitReflection->getFileName(), + $traitName, + $className, + $traitMethodAliases[$traitName] ?? [], + $originalClassFileName, + )); } } return null; - }, static function (Node $node) use (&$namespace, &$functionStack, &$classStack): void { + }, + static function (Node $node) use (&$namespace, &$functionStack, &$classStack): void { if ($node instanceof Node\Stmt\ClassLike) { if (count($classStack) === 0) { throw new ShouldNotHappenException(); @@ -361,37 +377,52 @@ private function createPhpDocNodeMap(string $fileName, ?string $lookForTrait, ?s array_pop($functionStack); } - }); + }, + ); return $phpDocNodeMap; } /** - * @param array $traitMethodAliases - * @param array $phpDocNodeMap - * @return (callable(): NameScope)[] - */ - private function createNameScopeMap(string $fileName, ?string $lookForTrait, ?string $traitUseClass, array $traitMethodAliases, string $originalClassFileName, array $phpDocNodeMap) : array - { - /** @var (callable(): NameScope)[] $nameScopeMap */ - $nameScopeMap = []; - /** @var (callable(): TemplateTypeMap)[] $typeMapStack */ - $typeMapStack = []; - /** @var array> $typeAliasStack */ - $typeAliasStack = []; - /** @var string[] $classStack */ - $classStack = []; - if ($lookForTrait !== null && $traitUseClass !== null) { - $classStack[] = $traitUseClass; - $typeAliasStack[] = []; - } - $namespace = null; - $traitFound = false; - /** @var array $functionStack */ - $functionStack = []; - $uses = []; - $constUses = []; - $this->processNodes($this->phpParser->parseFile($fileName), function (Node $node) use ($fileName, $lookForTrait, $phpDocNodeMap, &$traitFound, $traitMethodAliases, $originalClassFileName, &$nameScopeMap, &$classStack, &$typeAliasStack, &$namespace, &$functionStack, &$uses, &$typeMapStack, &$constUses): ?int { + * @param array $traitMethodAliases + * @param array $phpDocNodeMap + * @return (callable(): NameScope)[] + */ + private function createNameScopeMap( + string $fileName, + ?string $lookForTrait, + ?string $traitUseClass, + array $traitMethodAliases, + string $originalClassFileName, + array $phpDocNodeMap, + ): array + { + /** @var (callable(): NameScope)[] $nameScopeMap */ + $nameScopeMap = []; + + /** @var (callable(): TemplateTypeMap)[] $typeMapStack */ + $typeMapStack = []; + + /** @var array> $typeAliasStack */ + $typeAliasStack = []; + + /** @var string[] $classStack */ + $classStack = []; + if ($lookForTrait !== null && $traitUseClass !== null) { + $classStack[] = $traitUseClass; + $typeAliasStack[] = []; + } + $namespace = null; + + $traitFound = false; + + /** @var array $functionStack */ + $functionStack = []; + $uses = []; + $constUses = []; + $this->processNodes( + $this->phpParser->parseFile($fileName), + function (Node $node) use ($fileName, $lookForTrait, $phpDocNodeMap, &$traitFound, $traitMethodAliases, $originalClassFileName, &$nameScopeMap, &$classStack, &$typeAliasStack, &$namespace, &$functionStack, &$uses, &$typeMapStack, &$constUses): ?int { if ($node instanceof Node\Stmt\ClassLike) { if ($traitFound && $fileName === $originalClassFileName) { return self::SKIP_NODE; @@ -464,16 +495,15 @@ private function createNameScopeMap(string $fileName, ?string $lookForTrait, ?st if ($templateTypeScope === null) { throw new ShouldNotHappenException(); } - $templateTypeMap = new TemplateTypeMap(array_map(static function (TemplateTag $tag) use($templateTypeScope) : Type { - return TemplateTypeFactory::fromTemplateTag($templateTypeScope, $tag); - }, $templateTags)); + $templateTypeMap = new TemplateTypeMap(array_map(static fn (TemplateTag $tag): Type => TemplateTypeFactory::fromTemplateTag($templateTypeScope, $tag), $templateTags)); $nameScope = $nameScope->withTemplateTypeMap($templateTypeMap); $templateTags = $this->phpDocNodeResolver->resolveTemplateTags($phpDocNode, $nameScope); - $templateTypeMap = new TemplateTypeMap(array_map(static function (TemplateTag $tag) use($templateTypeScope) : Type { - return TemplateTypeFactory::fromTemplateTag($templateTypeScope, $tag); - }, $templateTags)); + $templateTypeMap = new TemplateTypeMap(array_map(static fn (TemplateTag $tag): Type => TemplateTypeFactory::fromTemplateTag($templateTypeScope, $tag), $templateTags)); - return new TemplateTypeMap(array_merge($currentTypeMap !== null ? $currentTypeMap->getTypes() : [], $templateTypeMap->getTypes())); + return new TemplateTypeMap(array_merge( + $currentTypeMap !== null ? $currentTypeMap->getTypes() : [], + $templateTypeMap->getTypes(), + )); }; } } @@ -495,9 +525,17 @@ private function createNameScopeMap(string $fileName, ?string $lookForTrait, ?st && !($node instanceof Node\Stmt\Expression && $node->expr instanceof Node\Expr\Include_) && !array_key_exists($nameScopeKey, $nameScopeMap) ) { - $nameScopeMap[$nameScopeKey] = static function () use($namespace, $uses, $className, $functionName, $typeMapCb, $typeAliasesMap, $constUses, $lookForTrait) : NameScope { - return new NameScope($namespace, $uses, $className, $functionName, ($typeMapCb !== null ? $typeMapCb() : TemplateTypeMap::createEmpty()), $typeAliasesMap, false, $constUses, $lookForTrait); - }; + $nameScopeMap[$nameScopeKey] = static fn (): NameScope => new NameScope( + $namespace, + $uses, + $className, + $functionName, + ($typeMapCb !== null ? $typeMapCb() : TemplateTypeMap::createEmpty()), + $typeAliasesMap, + false, + $constUses, + $lookForTrait, + ); } if ($node instanceof Node\Stmt\ClassLike || $node instanceof Node\Stmt\ClassMethod || $node instanceof Node\Stmt\Function_) { @@ -582,7 +620,14 @@ private function createNameScopeMap(string $fileName, ?string $lookForTrait, ?st throw new ShouldNotHappenException(); } - $traitPhpDocMap = $this->createNameScopeMap($traitReflection->getFileName(), $traitName, $className, $traitMethodAliases[$traitName] ?? [], $originalClassFileName, $phpDocNodeMap); + $traitPhpDocMap = $this->createNameScopeMap( + $traitReflection->getFileName(), + $traitName, + $className, + $traitMethodAliases[$traitName] ?? [], + $originalClassFileName, + $phpDocNodeMap, + ); $finalTraitPhpDocMap = []; foreach ($traitPhpDocMap as $nameScopeTraitKey => $callback) { $finalTraitPhpDocMap[$nameScopeTraitKey] = function () use ($callback, $traitReflection, $fileName, $className, $lookForTrait, $useDocComment): NameScope { @@ -596,7 +641,13 @@ private function createNameScopeMap(string $fileName, ?string $lookForTrait, ?st $useType = null; if ($useDocComment !== null) { - $useTags = $this->getResolvedPhpDoc($fileName, $className, $lookForTrait, null, $useDocComment)->getUsesTags(); + $useTags = $this->getResolvedPhpDoc( + $fileName, + $className, + $lookForTrait, + null, + $useDocComment, + )->getUsesTags(); foreach ($useTags as $useTag) { $useTagType = $useTag->getType(); if (!$useTagType instanceof GenericObjectType) { @@ -618,9 +669,7 @@ private function createNameScopeMap(string $fileName, ?string $lookForTrait, ?st $transformedTraitTypeMap = $traitReflection->typeMapFromList($useType->getTypes()); - return $original->withTemplateTypeMap($traitTemplateTypeMap->map(static function (string $name, Type $type) use($transformedTraitTypeMap) : Type { - return TemplateTypeHelper::resolveTemplateTypes($type, $transformedTraitTypeMap, TemplateTypeVarianceMap::createEmpty(), TemplateTypeVariance::createStatic()); - })); + return $original->withTemplateTypeMap($traitTemplateTypeMap->map(static fn (string $name, Type $type): Type => TemplateTypeHelper::resolveTemplateTypes($type, $transformedTraitTypeMap, TemplateTypeVarianceMap::createEmpty(), TemplateTypeVariance::createStatic()))); }; } $nameScopeMap = array_merge($nameScopeMap, $finalTraitPhpDocMap); @@ -628,7 +677,8 @@ private function createNameScopeMap(string $fileName, ?string $lookForTrait, ?st } return null; - }, static function (Node $node, $callbackResult) use (&$namespace, &$functionStack, &$classStack, &$typeAliasStack, &$uses, &$typeMapStack, &$constUses): void { + }, + static function (Node $node, $callbackResult) use (&$namespace, &$functionStack, &$classStack, &$typeAliasStack, &$uses, &$typeMapStack, &$constUses): void { if ($node instanceof Node\Stmt\ClassLike) { if (count($classStack) === 0) { throw new ShouldNotHappenException(); @@ -665,17 +715,20 @@ private function createNameScopeMap(string $fileName, ?string $lookForTrait, ?st throw new ShouldNotHappenException(); } array_pop($typeMapStack); - }); - if (count($typeMapStack) > 0) { - throw new ShouldNotHappenException(); - } - return $nameScopeMap; + }, + ); + + if (count($typeMapStack) > 0) { + throw new ShouldNotHappenException(); } + return $nameScopeMap; + } + /** - * @return array - */ - private function getTypeAliasesMap(PhpDocNode $phpDocNode): array + * @return array + */ + private function getTypeAliasesMap(PhpDocNode $phpDocNode): array { $nameScope = new NameScope(null, []); @@ -692,11 +745,11 @@ private function getTypeAliasesMap(PhpDocNode $phpDocNode): array } /** - * @param Node[]|Node|scalar|null $node - * @param Closure(Node $node): mixed $nodeCallback - * @param Closure(Node $node, mixed $callbackResult): void $endNodeCallback - */ - private function processNodes($node, Closure $nodeCallback, Closure $endNodeCallback): void + * @param Node[]|Node|scalar|null $node + * @param Closure(Node $node): mixed $nodeCallback + * @param Closure(Node $node, mixed $callbackResult): void $endNodeCallback + */ + private function processNodes($node, Closure $nodeCallback, Closure $endNodeCallback): void { if ($node instanceof Node) { $callbackResult = $nodeCallback($node); @@ -715,15 +768,22 @@ private function processNodes($node, Closure $nodeCallback, Closure $endNodeCall } } - private function getNameScopeKey(?string $file, ?string $class, ?string $trait, ?string $function) : string - { - if ($class === null && $trait === null && $function === null) { - return md5(sprintf('%s', $file ?? 'no-file')); - } - if ($class !== null && str_contains($class, 'class@anonymous')) { - throw new ShouldNotHappenException('Wrong anonymous class name, FilTypeMapper should be called with ClassReflection::getName().'); - } - return md5(sprintf('%s-%s-%s-%s', $file ?? 'no-file', $class, $trait, $function)); + private function getNameScopeKey( + ?string $file, + ?string $class, + ?string $trait, + ?string $function, + ): string + { + if ($class === null && $trait === null && $function === null) { + return md5(sprintf('%s', $file ?? 'no-file')); + } + + if ($class !== null && str_contains($class, 'class@anonymous')) { + throw new ShouldNotHappenException('Wrong anonymous class name, FilTypeMapper should be called with ClassReflection::getName().'); } + return md5(sprintf('%s-%s-%s-%s', $file ?? 'no-file', $class, $trait, $function)); + } + } diff --git a/src/Type/FloatType.php b/src/Type/FloatType.php index 6c0e66f030a..c82a50e4e72 100644 --- a/src/Type/FloatType.php +++ b/src/Type/FloatType.php @@ -130,7 +130,13 @@ public function toString(): Type public function toArray(): Type { - return new ConstantArrayType([new ConstantIntegerType(0)], [$this], [1], [], TrinaryLogic::createYes()); + return new ConstantArrayType( + [new ConstantIntegerType(0)], + [$this], + [1], + [], + TrinaryLogic::createYes(), + ); } public function toArrayKey(): Type diff --git a/src/Type/GeneralizePrecision.php b/src/Type/GeneralizePrecision.php index 8ac8b059b50..0cce10ed32b 100644 --- a/src/Type/GeneralizePrecision.php +++ b/src/Type/GeneralizePrecision.php @@ -5,25 +5,20 @@ class GeneralizePrecision { - /** - * @var int - */ - private $value; private const LESS_SPECIFIC = 1; private const MORE_SPECIFIC = 2; private const TEMPLATE_ARGUMENT = 3; /** @var self[] */ - private static $registry; + private static array $registry; - private function __construct(int $value) + private function __construct(private int $value) { - $this->value = $value; } private static function create(int $value): self { - self::$registry[$value] = self::$registry[$value] ?? new self($value); + self::$registry[$value] ??= new self($value); return self::$registry[$value]; } diff --git a/src/Type/Generic/GenericClassStringType.php b/src/Type/Generic/GenericClassStringType.php index 097976a2da3..fd6ecd5f03d 100644 --- a/src/Type/Generic/GenericClassStringType.php +++ b/src/Type/Generic/GenericClassStringType.php @@ -29,14 +29,9 @@ class GenericClassStringType extends ClassStringType { - /** - * @var Type - */ - private $type; /** @api */ - public function __construct(Type $type) + public function __construct(private Type $type) { - $this->type = $type; parent::__construct(); } @@ -210,9 +205,12 @@ public static function __set_state(array $properties): Type public function toPhpDocNode(): TypeNode { - return new GenericTypeNode(new IdentifierTypeNode('class-string'), [ + return new GenericTypeNode( + new IdentifierTypeNode('class-string'), + [ $this->type->toPhpDocNode(), - ]); + ], + ); } public function tryRemove(Type $typeToRemove): ?Type diff --git a/src/Type/Generic/GenericObjectType.php b/src/Type/Generic/GenericObjectType.php index 76fc152008e..775134aab6b 100644 --- a/src/Type/Generic/GenericObjectType.php +++ b/src/Type/Generic/GenericObjectType.php @@ -32,35 +32,33 @@ class GenericObjectType extends ObjectType { - /** - * @var array - */ - private $types; - /** - * @var ?ClassReflection - */ - private $classReflection; - /** - * @var array - */ - private $variances; /** * @api * @param array $types * @param array $variances */ - public function __construct(string $mainType, array $types, ?Type $subtractedType = null, ?ClassReflection $classReflection = null, array $variances = []) + public function __construct( + string $mainType, + private array $types, + ?Type $subtractedType = null, + private ?ClassReflection $classReflection = null, + private array $variances = [], + ) { - $this->types = $types; - $this->classReflection = $classReflection; - $this->variances = $variances; parent::__construct($mainType, $subtractedType, $classReflection); } + public function describe(VerbosityLevel $level): string { - return sprintf('%s<%s>', parent::describe($level), implode(', ', array_map(static function (Type $type, ?TemplateTypeVariance $variance = null) use($level) : string { - return TypeProjectionHelper::describe($type, $variance, $level); - }, $this->types, $this->variances))); + return sprintf( + '%s<%s>', + parent::describe($level), + implode(', ', array_map( + static fn (Type $type, ?TemplateTypeVariance $variance = null): string => TypeProjectionHelper::describe($type, $variance, $level), + $this->types, + $this->variances, + )), + ); } public function equals(Type $type): bool @@ -375,7 +373,13 @@ public function traverseSimultaneously(Type $right, callable $cb): Type */ protected function recreate(string $className, array $types, ?Type $subtractedType, array $variances = []): self { - return new self($className, $types, $subtractedType, null, $variances); + return new self( + $className, + $types, + $subtractedType, + null, + $variances, + ); } public function changeSubtractedType(?Type $subtractedType): Type @@ -387,11 +391,11 @@ public function toPhpDocNode(): TypeNode { /** @var IdentifierTypeNode $parent */ $parent = parent::toPhpDocNode(); - return new GenericTypeNode($parent, array_map(static function (Type $type) { - return $type->toPhpDocNode(); - }, $this->types), array_map(static function (TemplateTypeVariance $variance) { - return $variance->toPhpDocNodeVariance(); - }, $this->variances)); + return new GenericTypeNode( + $parent, + array_map(static fn (Type $type) => $type->toPhpDocNode(), $this->types), + array_map(static fn (TemplateTypeVariance $variance) => $variance->toPhpDocNodeVariance(), $this->variances), + ); } /** @@ -399,7 +403,13 @@ public function toPhpDocNode(): TypeNode */ public static function __set_state(array $properties): Type { - return new self($properties['className'], $properties['types'], $properties['subtractedType'] ?? null, null, $properties['variances'] ?? []); + return new self( + $properties['className'], + $properties['types'], + $properties['subtractedType'] ?? null, + null, + $properties['variances'] ?? [], + ); } } diff --git a/src/Type/Generic/TemplateArrayType.php b/src/Type/Generic/TemplateArrayType.php index 644d6001a83..696deb7f04f 100644 --- a/src/Type/Generic/TemplateArrayType.php +++ b/src/Type/Generic/TemplateArrayType.php @@ -13,7 +13,13 @@ final class TemplateArrayType extends ArrayType implements TemplateType use TemplateTypeTrait; use UndecidedComparisonCompoundTypeTrait; - public function __construct(TemplateTypeScope $scope, TemplateTypeStrategy $templateTypeStrategy, TemplateTypeVariance $templateTypeVariance, string $name, ArrayType $bound) + public function __construct( + TemplateTypeScope $scope, + TemplateTypeStrategy $templateTypeStrategy, + TemplateTypeVariance $templateTypeVariance, + string $name, + ArrayType $bound, + ) { parent::__construct($bound->getKeyType(), $bound->getItemType()); $this->scope = $scope; diff --git a/src/Type/Generic/TemplateBenevolentUnionType.php b/src/Type/Generic/TemplateBenevolentUnionType.php index afbfb5e0b63..9150bd44802 100644 --- a/src/Type/Generic/TemplateBenevolentUnionType.php +++ b/src/Type/Generic/TemplateBenevolentUnionType.php @@ -12,9 +12,16 @@ final class TemplateBenevolentUnionType extends BenevolentUnionType implements T /** @use TemplateTypeTrait */ use TemplateTypeTrait; - public function __construct(TemplateTypeScope $scope, TemplateTypeStrategy $templateTypeStrategy, TemplateTypeVariance $templateTypeVariance, string $name, BenevolentUnionType $bound) + public function __construct( + TemplateTypeScope $scope, + TemplateTypeStrategy $templateTypeStrategy, + TemplateTypeVariance $templateTypeVariance, + string $name, + BenevolentUnionType $bound, + ) { parent::__construct($bound->getTypes()); + $this->scope = $scope; $this->strategy = $templateTypeStrategy; $this->variance = $templateTypeVariance; @@ -25,7 +32,13 @@ public function __construct(TemplateTypeScope $scope, TemplateTypeStrategy $temp /** @param Type[] $types */ public function withTypes(array $types): self { - return new self($this->scope, $this->strategy, $this->variance, $this->name, new BenevolentUnionType($types)); + return new self( + $this->scope, + $this->strategy, + $this->variance, + $this->name, + new BenevolentUnionType($types), + ); } } diff --git a/src/Type/Generic/TemplateBooleanType.php b/src/Type/Generic/TemplateBooleanType.php index 24f6a48081c..7962d50d0eb 100644 --- a/src/Type/Generic/TemplateBooleanType.php +++ b/src/Type/Generic/TemplateBooleanType.php @@ -13,7 +13,13 @@ final class TemplateBooleanType extends BooleanType implements TemplateType use TemplateTypeTrait; use UndecidedComparisonCompoundTypeTrait; - public function __construct(TemplateTypeScope $scope, TemplateTypeStrategy $templateTypeStrategy, TemplateTypeVariance $templateTypeVariance, string $name, BooleanType $bound) + public function __construct( + TemplateTypeScope $scope, + TemplateTypeStrategy $templateTypeStrategy, + TemplateTypeVariance $templateTypeVariance, + string $name, + BooleanType $bound, + ) { parent::__construct(); $this->scope = $scope; diff --git a/src/Type/Generic/TemplateConstantArrayType.php b/src/Type/Generic/TemplateConstantArrayType.php index 7d12bea47fd..8bb8aa696d0 100644 --- a/src/Type/Generic/TemplateConstantArrayType.php +++ b/src/Type/Generic/TemplateConstantArrayType.php @@ -13,7 +13,13 @@ final class TemplateConstantArrayType extends ConstantArrayType implements Templ use TemplateTypeTrait; use UndecidedComparisonCompoundTypeTrait; - public function __construct(TemplateTypeScope $scope, TemplateTypeStrategy $templateTypeStrategy, TemplateTypeVariance $templateTypeVariance, string $name, ConstantArrayType $bound) + public function __construct( + TemplateTypeScope $scope, + TemplateTypeStrategy $templateTypeStrategy, + TemplateTypeVariance $templateTypeVariance, + string $name, + ConstantArrayType $bound, + ) { parent::__construct($bound->getKeyTypes(), $bound->getValueTypes(), $bound->getNextAutoIndexes(), $bound->getOptionalKeys(), $bound->isList()); $this->scope = $scope; diff --git a/src/Type/Generic/TemplateConstantIntegerType.php b/src/Type/Generic/TemplateConstantIntegerType.php index 457f0fb4d11..4aa00d78053 100644 --- a/src/Type/Generic/TemplateConstantIntegerType.php +++ b/src/Type/Generic/TemplateConstantIntegerType.php @@ -13,7 +13,13 @@ final class TemplateConstantIntegerType extends ConstantIntegerType implements T use TemplateTypeTrait; use UndecidedComparisonCompoundTypeTrait; - public function __construct(TemplateTypeScope $scope, TemplateTypeStrategy $templateTypeStrategy, TemplateTypeVariance $templateTypeVariance, string $name, ConstantIntegerType $bound) + public function __construct( + TemplateTypeScope $scope, + TemplateTypeStrategy $templateTypeStrategy, + TemplateTypeVariance $templateTypeVariance, + string $name, + ConstantIntegerType $bound, + ) { parent::__construct($bound->getValue()); $this->scope = $scope; diff --git a/src/Type/Generic/TemplateConstantStringType.php b/src/Type/Generic/TemplateConstantStringType.php index a785578fc06..85c871e2772 100644 --- a/src/Type/Generic/TemplateConstantStringType.php +++ b/src/Type/Generic/TemplateConstantStringType.php @@ -13,7 +13,13 @@ final class TemplateConstantStringType extends ConstantStringType implements Tem use TemplateTypeTrait; use UndecidedComparisonCompoundTypeTrait; - public function __construct(TemplateTypeScope $scope, TemplateTypeStrategy $templateTypeStrategy, TemplateTypeVariance $templateTypeVariance, string $name, ConstantStringType $bound) + public function __construct( + TemplateTypeScope $scope, + TemplateTypeStrategy $templateTypeStrategy, + TemplateTypeVariance $templateTypeVariance, + string $name, + ConstantStringType $bound, + ) { parent::__construct($bound->getValue()); $this->scope = $scope; diff --git a/src/Type/Generic/TemplateFloatType.php b/src/Type/Generic/TemplateFloatType.php index 7c41424b20a..f7e2210e86d 100644 --- a/src/Type/Generic/TemplateFloatType.php +++ b/src/Type/Generic/TemplateFloatType.php @@ -13,7 +13,13 @@ final class TemplateFloatType extends FloatType implements TemplateType use TemplateTypeTrait; use UndecidedComparisonCompoundTypeTrait; - public function __construct(TemplateTypeScope $scope, TemplateTypeStrategy $templateTypeStrategy, TemplateTypeVariance $templateTypeVariance, string $name, FloatType $bound) + public function __construct( + TemplateTypeScope $scope, + TemplateTypeStrategy $templateTypeStrategy, + TemplateTypeVariance $templateTypeVariance, + string $name, + FloatType $bound, + ) { parent::__construct(); $this->scope = $scope; diff --git a/src/Type/Generic/TemplateGenericObjectType.php b/src/Type/Generic/TemplateGenericObjectType.php index b0c6e27d220..485781aacaa 100644 --- a/src/Type/Generic/TemplateGenericObjectType.php +++ b/src/Type/Generic/TemplateGenericObjectType.php @@ -13,9 +13,16 @@ final class TemplateGenericObjectType extends GenericObjectType implements Templ /** @use TemplateTypeTrait */ use TemplateTypeTrait; - public function __construct(TemplateTypeScope $scope, TemplateTypeStrategy $templateTypeStrategy, TemplateTypeVariance $templateTypeVariance, string $name, GenericObjectType $bound) + public function __construct( + TemplateTypeScope $scope, + TemplateTypeStrategy $templateTypeStrategy, + TemplateTypeVariance $templateTypeVariance, + string $name, + GenericObjectType $bound, + ) { parent::__construct($bound->getClassName(), $bound->getTypes(), null, null, $bound->getVariances()); + $this->scope = $scope; $this->strategy = $templateTypeStrategy; $this->variance = $templateTypeVariance; @@ -25,7 +32,13 @@ public function __construct(TemplateTypeScope $scope, TemplateTypeStrategy $temp protected function recreate(string $className, array $types, ?Type $subtractedType, array $variances = []): GenericObjectType { - return new self($this->scope, $this->strategy, $this->variance, $this->name, $this->getBound()); + return new self( + $this->scope, + $this->strategy, + $this->variance, + $this->name, + $this->getBound(), + ); } } diff --git a/src/Type/Generic/TemplateIntegerType.php b/src/Type/Generic/TemplateIntegerType.php index f7ed370eefc..62222f6b8ec 100644 --- a/src/Type/Generic/TemplateIntegerType.php +++ b/src/Type/Generic/TemplateIntegerType.php @@ -13,7 +13,13 @@ final class TemplateIntegerType extends IntegerType implements TemplateType use TemplateTypeTrait; use UndecidedComparisonCompoundTypeTrait; - public function __construct(TemplateTypeScope $scope, TemplateTypeStrategy $templateTypeStrategy, TemplateTypeVariance $templateTypeVariance, string $name, IntegerType $bound) + public function __construct( + TemplateTypeScope $scope, + TemplateTypeStrategy $templateTypeStrategy, + TemplateTypeVariance $templateTypeVariance, + string $name, + IntegerType $bound, + ) { parent::__construct(); $this->scope = $scope; diff --git a/src/Type/Generic/TemplateIntersectionType.php b/src/Type/Generic/TemplateIntersectionType.php index 0e2d642fb1b..805739874a3 100644 --- a/src/Type/Generic/TemplateIntersectionType.php +++ b/src/Type/Generic/TemplateIntersectionType.php @@ -11,9 +11,16 @@ final class TemplateIntersectionType extends IntersectionType implements Templat /** @use TemplateTypeTrait */ use TemplateTypeTrait; - public function __construct(TemplateTypeScope $scope, TemplateTypeStrategy $templateTypeStrategy, TemplateTypeVariance $templateTypeVariance, string $name, IntersectionType $bound) + public function __construct( + TemplateTypeScope $scope, + TemplateTypeStrategy $templateTypeStrategy, + TemplateTypeVariance $templateTypeVariance, + string $name, + IntersectionType $bound, + ) { parent::__construct($bound->getTypes()); + $this->scope = $scope; $this->strategy = $templateTypeStrategy; $this->variance = $templateTypeVariance; diff --git a/src/Type/Generic/TemplateKeyOfType.php b/src/Type/Generic/TemplateKeyOfType.php index 1d624398a15..003de6f4319 100644 --- a/src/Type/Generic/TemplateKeyOfType.php +++ b/src/Type/Generic/TemplateKeyOfType.php @@ -14,7 +14,13 @@ final class TemplateKeyOfType extends KeyOfType implements TemplateType use TemplateTypeTrait; use UndecidedComparisonCompoundTypeTrait; - public function __construct(TemplateTypeScope $scope, TemplateTypeStrategy $templateTypeStrategy, TemplateTypeVariance $templateTypeVariance, string $name, KeyOfType $bound) + public function __construct( + TemplateTypeScope $scope, + TemplateTypeStrategy $templateTypeStrategy, + TemplateTypeVariance $templateTypeVariance, + string $name, + KeyOfType $bound, + ) { parent::__construct($bound->getType()); $this->scope = $scope; @@ -28,7 +34,13 @@ protected function getResult(): Type { $result = $this->getBound()->getResult(); - return TemplateTypeFactory::create($this->getScope(), $this->getName(), $result, $this->getVariance(), $this->getStrategy()); + return TemplateTypeFactory::create( + $this->getScope(), + $this->getName(), + $result, + $this->getVariance(), + $this->getStrategy(), + ); } protected function shouldGeneralizeInferredType(): bool diff --git a/src/Type/Generic/TemplateMixedType.php b/src/Type/Generic/TemplateMixedType.php index 4541ffb948b..11af221db4c 100644 --- a/src/Type/Generic/TemplateMixedType.php +++ b/src/Type/Generic/TemplateMixedType.php @@ -15,9 +15,16 @@ final class TemplateMixedType extends MixedType implements TemplateType /** @use TemplateTypeTrait */ use TemplateTypeTrait; - public function __construct(TemplateTypeScope $scope, TemplateTypeStrategy $templateTypeStrategy, TemplateTypeVariance $templateTypeVariance, string $name, MixedType $bound) + public function __construct( + TemplateTypeScope $scope, + TemplateTypeStrategy $templateTypeStrategy, + TemplateTypeVariance $templateTypeVariance, + string $name, + MixedType $bound, + ) { parent::__construct(true); + $this->scope = $scope; $this->strategy = $templateTypeStrategy; $this->variance = $templateTypeVariance; @@ -46,7 +53,13 @@ public function isAcceptedWithReasonBy(Type $acceptingType, bool $strictTypes): public function toStrictMixedType(): TemplateStrictMixedType { - return new TemplateStrictMixedType($this->scope, $this->strategy, $this->variance, $this->name, new StrictMixedType()); + return new TemplateStrictMixedType( + $this->scope, + $this->strategy, + $this->variance, + $this->name, + new StrictMixedType(), + ); } } diff --git a/src/Type/Generic/TemplateObjectShapeType.php b/src/Type/Generic/TemplateObjectShapeType.php index 588820784fc..7fe78cbdbd6 100644 --- a/src/Type/Generic/TemplateObjectShapeType.php +++ b/src/Type/Generic/TemplateObjectShapeType.php @@ -13,7 +13,13 @@ final class TemplateObjectShapeType extends ObjectShapeType implements TemplateT use TemplateTypeTrait; use UndecidedComparisonCompoundTypeTrait; - public function __construct(TemplateTypeScope $scope, TemplateTypeStrategy $templateTypeStrategy, TemplateTypeVariance $templateTypeVariance, string $name, ObjectShapeType $bound) + public function __construct( + TemplateTypeScope $scope, + TemplateTypeStrategy $templateTypeStrategy, + TemplateTypeVariance $templateTypeVariance, + string $name, + ObjectShapeType $bound, + ) { parent::__construct($bound->getProperties(), $bound->getOptionalProperties()); $this->scope = $scope; diff --git a/src/Type/Generic/TemplateObjectType.php b/src/Type/Generic/TemplateObjectType.php index 411184aba7a..ef2c76ef7fd 100644 --- a/src/Type/Generic/TemplateObjectType.php +++ b/src/Type/Generic/TemplateObjectType.php @@ -13,9 +13,16 @@ final class TemplateObjectType extends ObjectType implements TemplateType /** @use TemplateTypeTrait */ use TemplateTypeTrait; - public function __construct(TemplateTypeScope $scope, TemplateTypeStrategy $templateTypeStrategy, TemplateTypeVariance $templateTypeVariance, string $name, ObjectType $bound) + public function __construct( + TemplateTypeScope $scope, + TemplateTypeStrategy $templateTypeStrategy, + TemplateTypeVariance $templateTypeVariance, + string $name, + ObjectType $bound, + ) { parent::__construct($bound->getClassName()); + $this->scope = $scope; $this->strategy = $templateTypeStrategy; $this->variance = $templateTypeVariance; diff --git a/src/Type/Generic/TemplateObjectWithoutClassType.php b/src/Type/Generic/TemplateObjectWithoutClassType.php index 337517010e7..1f9b0fe0ced 100644 --- a/src/Type/Generic/TemplateObjectWithoutClassType.php +++ b/src/Type/Generic/TemplateObjectWithoutClassType.php @@ -13,9 +13,16 @@ class TemplateObjectWithoutClassType extends ObjectWithoutClassType implements T /** @use TemplateTypeTrait */ use TemplateTypeTrait; - public function __construct(TemplateTypeScope $scope, TemplateTypeStrategy $templateTypeStrategy, TemplateTypeVariance $templateTypeVariance, string $name, ObjectWithoutClassType $bound) + public function __construct( + TemplateTypeScope $scope, + TemplateTypeStrategy $templateTypeStrategy, + TemplateTypeVariance $templateTypeVariance, + string $name, + ObjectWithoutClassType $bound, + ) { parent::__construct(); + $this->scope = $scope; $this->strategy = $templateTypeStrategy; $this->variance = $templateTypeVariance; diff --git a/src/Type/Generic/TemplateStrictMixedType.php b/src/Type/Generic/TemplateStrictMixedType.php index a71a51fabbd..8949142920f 100644 --- a/src/Type/Generic/TemplateStrictMixedType.php +++ b/src/Type/Generic/TemplateStrictMixedType.php @@ -15,7 +15,13 @@ final class TemplateStrictMixedType extends StrictMixedType implements TemplateT /** @use TemplateTypeTrait */ use TemplateTypeTrait; - public function __construct(TemplateTypeScope $scope, TemplateTypeStrategy $templateTypeStrategy, TemplateTypeVariance $templateTypeVariance, string $name, StrictMixedType $bound) + public function __construct( + TemplateTypeScope $scope, + TemplateTypeStrategy $templateTypeStrategy, + TemplateTypeVariance $templateTypeVariance, + string $name, + StrictMixedType $bound, + ) { $this->scope = $scope; $this->strategy = $templateTypeStrategy; diff --git a/src/Type/Generic/TemplateStringType.php b/src/Type/Generic/TemplateStringType.php index 049ca0babc1..17cec7dc55d 100644 --- a/src/Type/Generic/TemplateStringType.php +++ b/src/Type/Generic/TemplateStringType.php @@ -13,7 +13,13 @@ final class TemplateStringType extends StringType implements TemplateType use TemplateTypeTrait; use UndecidedComparisonCompoundTypeTrait; - public function __construct(TemplateTypeScope $scope, TemplateTypeStrategy $templateTypeStrategy, TemplateTypeVariance $templateTypeVariance, string $name, StringType $bound) + public function __construct( + TemplateTypeScope $scope, + TemplateTypeStrategy $templateTypeStrategy, + TemplateTypeVariance $templateTypeVariance, + string $name, + StringType $bound, + ) { parent::__construct(); $this->scope = $scope; diff --git a/src/Type/Generic/TemplateTypeArgumentStrategy.php b/src/Type/Generic/TemplateTypeArgumentStrategy.php index a640f38d862..414ffc12aad 100644 --- a/src/Type/Generic/TemplateTypeArgumentStrategy.php +++ b/src/Type/Generic/TemplateTypeArgumentStrategy.php @@ -26,7 +26,11 @@ public function accepts(TemplateType $left, Type $right, bool $strictTypes): Acc $verbosity = VerbosityLevel::getRecommendedLevelByType($left, $right); return new AcceptsResult($accepts->result, array_merge($accepts->reasons, [ - sprintf('Type %s is not always the same as %s. It breaks the contract for some argument types, typically subtypes.', $right->describe($verbosity), $left->getName()), + sprintf( + 'Type %s is not always the same as %s. It breaks the contract for some argument types, typically subtypes.', + $right->describe($verbosity), + $left->getName(), + ), ])); } } diff --git a/src/Type/Generic/TemplateTypeFactory.php b/src/Type/Generic/TemplateTypeFactory.php index 0172a8c65b2..6d71e1dea58 100644 --- a/src/Type/Generic/TemplateTypeFactory.php +++ b/src/Type/Generic/TemplateTypeFactory.php @@ -27,7 +27,7 @@ final class TemplateTypeFactory public static function create(TemplateTypeScope $scope, string $name, ?Type $bound, TemplateTypeVariance $variance, ?TemplateTypeStrategy $strategy = null): TemplateType { - $strategy = $strategy ?? new TemplateTypeParameterStrategy(); + $strategy ??= new TemplateTypeParameterStrategy(); if ($bound === null) { return new TemplateMixedType($scope, $strategy, $variance, $name, new MixedType(true)); diff --git a/src/Type/Generic/TemplateTypeHelper.php b/src/Type/Generic/TemplateTypeHelper.php index 29bb1aba406..1653b03415d 100644 --- a/src/Type/Generic/TemplateTypeHelper.php +++ b/src/Type/Generic/TemplateTypeHelper.php @@ -15,9 +15,16 @@ class TemplateTypeHelper /** * Replaces template types with standin types */ - public static function resolveTemplateTypes(Type $type, TemplateTypeMap $standins, TemplateTypeVarianceMap $callSiteVariances, TemplateTypeVariance $positionVariance, bool $keepErrorTypes = false) : Type + public static function resolveTemplateTypes( + Type $type, + TemplateTypeMap $standins, + TemplateTypeVarianceMap $callSiteVariances, + TemplateTypeVariance $positionVariance, + bool $keepErrorTypes = false, + ): Type { $references = $type->getReferencedTemplateTypes($positionVariance); + return TypeTraverser::map($type, static function (Type $type, callable $traverse) use ($standins, $references, $callSiteVariances, $keepErrorTypes): Type { if ($type instanceof TemplateType && !$type->isArgument()) { $newType = $standins->getType($type->getName()); diff --git a/src/Type/Generic/TemplateTypeMap.php b/src/Type/Generic/TemplateTypeMap.php index c97a29521db..f807e3d65e2 100644 --- a/src/Type/Generic/TemplateTypeMap.php +++ b/src/Type/Generic/TemplateTypeMap.php @@ -13,33 +13,17 @@ class TemplateTypeMap { - /** - * @var array - */ - private $types; - /** - * @var array - */ - private $lowerBoundTypes; - /** - * @var ?TemplateTypeMap - */ - private static $empty = null; + private static ?TemplateTypeMap $empty = null; - /** - * @var ?TemplateTypeMap - */ - private $resolvedToBounds = null; + private ?TemplateTypeMap $resolvedToBounds = null; /** * @api * @param array $types * @param array $lowerBoundTypes */ - public function __construct(array $types, array $lowerBoundTypes = []) + public function __construct(private array $types, private array $lowerBoundTypes = []) { - $this->types = $types; - $this->lowerBoundTypes = $lowerBoundTypes; } public function convertToLowerBoundTypes(): self @@ -224,9 +208,7 @@ public function resolveToBounds(): self if ($this->resolvedToBounds !== null) { return $this->resolvedToBounds; } - return $this->resolvedToBounds = $this->map(static function (string $name, Type $type) : Type { - return TemplateTypeHelper::resolveToBounds($type); - }); + return $this->resolvedToBounds = $this->map(static fn (string $name, Type $type): Type => TemplateTypeHelper::resolveToBounds($type)); } /** @@ -234,7 +216,10 @@ public function resolveToBounds(): self */ public static function __set_state(array $properties): self { - return new self($properties['types'], $properties['lowerBoundTypes'] ?? []); + return new self( + $properties['types'], + $properties['lowerBoundTypes'] ?? [], + ); } } diff --git a/src/Type/Generic/TemplateTypeReference.php b/src/Type/Generic/TemplateTypeReference.php index 4b3c584b71a..260abd3d939 100644 --- a/src/Type/Generic/TemplateTypeReference.php +++ b/src/Type/Generic/TemplateTypeReference.php @@ -5,18 +5,8 @@ class TemplateTypeReference { - /** - * @var TemplateType - */ - private $type; - /** - * @var TemplateTypeVariance - */ - private $positionVariance; - public function __construct(TemplateType $type, TemplateTypeVariance $positionVariance) + public function __construct(private TemplateType $type, private TemplateTypeVariance $positionVariance) { - $this->type = $type; - $this->positionVariance = $positionVariance; } public function getType(): TemplateType diff --git a/src/Type/Generic/TemplateTypeScope.php b/src/Type/Generic/TemplateTypeScope.php index 873d4e719c2..f9a76257202 100644 --- a/src/Type/Generic/TemplateTypeScope.php +++ b/src/Type/Generic/TemplateTypeScope.php @@ -7,14 +7,6 @@ class TemplateTypeScope { - /** - * @var ?string - */ - private $className; - /** - * @var ?string - */ - private $functionName; public static function createWithFunction(string $functionName): self { return new self(null, $functionName); @@ -30,10 +22,8 @@ public static function createWithClass(string $className): self return new self($className, null); } - private function __construct(?string $className, ?string $functionName) + private function __construct(private ?string $className, private ?string $functionName) { - $this->className = $className; - $this->functionName = $functionName; } /** @api */ @@ -74,7 +64,10 @@ public function describe(): string */ public static function __set_state(array $properties): self { - return new self($properties['className'], $properties['functionName']); + return new self( + $properties['className'], + $properties['functionName'], + ); } } diff --git a/src/Type/Generic/TemplateTypeTrait.php b/src/Type/Generic/TemplateTypeTrait.php index d6e7a77e2c3..803ec31348e 100644 --- a/src/Type/Generic/TemplateTypeTrait.php +++ b/src/Type/Generic/TemplateTypeTrait.php @@ -25,28 +25,16 @@ trait TemplateTypeTrait { - /** - * @var string - */ - private $name; + private string $name; - /** - * @var TemplateTypeScope - */ - private $scope; + private TemplateTypeScope $scope; - /** - * @var TemplateTypeStrategy - */ - private $strategy; + private TemplateTypeStrategy $strategy; - /** - * @var TemplateTypeVariance - */ - private $variance; + private TemplateTypeVariance $variance; /** @var TBound */ - private $bound; + private Type $bound; public function getName(): string { @@ -73,12 +61,18 @@ public function describe(VerbosityLevel $level): string } else { $boundDescription = sprintf(' of %s', $this->bound->describe($level)); } - return sprintf('%s%s', $this->name, $boundDescription); + return sprintf( + '%s%s', + $this->name, + $boundDescription, + ); }; - return $level->handle($basicDescription, $basicDescription, function () use($basicDescription) : string { - return sprintf('%s (%s, %s)', $basicDescription(), $this->scope->describe(), $this->isArgument() ? 'argument' : 'parameter'); - }); + return $level->handle( + $basicDescription, + $basicDescription, + fn (): string => sprintf('%s (%s, %s)', $basicDescription(), $this->scope->describe(), $this->isArgument() ? 'argument' : 'parameter'), + ); } public function isArgument(): bool @@ -88,7 +82,13 @@ public function isArgument(): bool public function toArgument(): TemplateType { - return new self($this->scope, new TemplateTypeArgumentStrategy(), $this->variance, $this->name, TemplateTypeHelper::toArgument($this->getBound())); + return new self( + $this->scope, + new TemplateTypeArgumentStrategy(), + $this->variance, + $this->name, + TemplateTypeHelper::toArgument($this->getBound()), + ); } public function isValidVariance(Type $a, Type $b): TrinaryLogic @@ -104,7 +104,13 @@ public function isValidVarianceWithReason(Type $a, Type $b): AcceptsResult public function subtract(Type $typeToRemove): Type { $removedBound = TypeCombinator::remove($this->getBound(), $typeToRemove); - return TemplateTypeFactory::create($this->getScope(), $this->getName(), $removedBound, $this->getVariance(), $this->getStrategy()); + return TemplateTypeFactory::create( + $this->getScope(), + $this->getName(), + $removedBound, + $this->getVariance(), + $this->getStrategy(), + ); } public function getTypeWithoutSubtractedType(): Type @@ -114,7 +120,13 @@ public function getTypeWithoutSubtractedType(): Type return $this; } - return TemplateTypeFactory::create($this->getScope(), $this->getName(), $bound->getTypeWithoutSubtractedType(), $this->getVariance(), $this->getStrategy()); + return TemplateTypeFactory::create( + $this->getScope(), + $this->getName(), + $bound->getTypeWithoutSubtractedType(), + $this->getVariance(), + $this->getStrategy(), + ); } public function changeSubtractedType(?Type $subtractedType): Type @@ -124,7 +136,13 @@ public function changeSubtractedType(?Type $subtractedType): Type return $this; } - return TemplateTypeFactory::create($this->getScope(), $this->getName(), $bound->changeSubtractedType($subtractedType), $this->getVariance(), $this->getStrategy()); + return TemplateTypeFactory::create( + $this->getScope(), + $this->getName(), + $bound->changeSubtractedType($subtractedType), + $this->getVariance(), + $this->getStrategy(), + ); } public function getSubtractedType(): ?Type @@ -241,7 +259,12 @@ public function inferTemplateTypes(Type $receivedType): TemplateTypeMap } $map = $this->getBound()->inferTemplateTypes($receivedType); - $resolvedBound = TypeUtils::resolveLateResolvableTypes(TemplateTypeHelper::resolveTemplateTypes($this->getBound(), $map, TemplateTypeVarianceMap::createEmpty(), TemplateTypeVariance::createStatic())); + $resolvedBound = TypeUtils::resolveLateResolvableTypes(TemplateTypeHelper::resolveTemplateTypes( + $this->getBound(), + $map, + TemplateTypeVarianceMap::createEmpty(), + TemplateTypeVariance::createStatic(), + )); if ($resolvedBound->isSuperTypeOf($receivedType)->yes()) { if (!BleedingEdgeToggle::isBleedingEdge() && $this->shouldGeneralizeInferredType()) { $generalizedType = $receivedType->generalize(GeneralizePrecision::templateArgument()); @@ -285,7 +308,13 @@ public function traverse(callable $cb): Type return $this; } - return TemplateTypeFactory::create($this->getScope(), $this->getName(), $bound, $this->getVariance(), $this->getStrategy()); + return TemplateTypeFactory::create( + $this->getScope(), + $this->getName(), + $bound, + $this->getVariance(), + $this->getStrategy(), + ); } public function traverseSimultaneously(Type $right, callable $cb): Type @@ -299,7 +328,13 @@ public function traverseSimultaneously(Type $right, callable $cb): Type return $this; } - return TemplateTypeFactory::create($this->getScope(), $this->getName(), $bound, $this->getVariance(), $this->getStrategy()); + return TemplateTypeFactory::create( + $this->getScope(), + $this->getName(), + $bound, + $this->getVariance(), + $this->getStrategy(), + ); } public function tryRemove(Type $typeToRemove): ?Type @@ -309,7 +344,13 @@ public function tryRemove(Type $typeToRemove): ?Type return null; } - return TemplateTypeFactory::create($this->getScope(), $this->getName(), $bound, $this->getVariance(), $this->getStrategy()); + return TemplateTypeFactory::create( + $this->getScope(), + $this->getName(), + $bound, + $this->getVariance(), + $this->getStrategy(), + ); } public function toPhpDocNode(): TypeNode @@ -322,7 +363,13 @@ public function toPhpDocNode(): TypeNode */ public static function __set_state(array $properties): Type { - return new self($properties['scope'], $properties['strategy'], $properties['variance'], $properties['name'], $properties['bound']); + return new self( + $properties['scope'], + $properties['strategy'], + $properties['variance'], + $properties['name'], + $properties['bound'], + ); } } diff --git a/src/Type/Generic/TemplateTypeVariance.php b/src/Type/Generic/TemplateTypeVariance.php index 3cf416d19f5..a3ab7a04bd2 100644 --- a/src/Type/Generic/TemplateTypeVariance.php +++ b/src/Type/Generic/TemplateTypeVariance.php @@ -16,10 +16,6 @@ class TemplateTypeVariance { - /** - * @var int - */ - private $value; private const INVARIANT = 1; private const COVARIANT = 2; private const CONTRAVARIANT = 3; @@ -27,21 +23,17 @@ class TemplateTypeVariance private const BIVARIANT = 5; /** @var self[] */ - private static $registry; + private static array $registry; - /** - * @var bool - */ - private static $invarianceCompositionEnabled = false; + private static bool $invarianceCompositionEnabled = false; - private function __construct(int $value) + private function __construct(private int $value) { - $this->value = $value; } private static function create(int $value): self { - self::$registry[$value] = self::$registry[$value] ?? new self($value); + self::$registry[$value] ??= new self($value); return self::$registry[$value]; } @@ -174,7 +166,11 @@ public function isValidVarianceWithReason(?TemplateType $templateType, Type $a, && $templateType->getScope()->getClassName() !== null && $a->isSuperTypeOf($b)->yes() ) { - $reasons[] = sprintf('Template type %s on class %s is not covariant. Learn more: https://phpstan.org/blog/whats-up-with-template-covariant', $templateType->getName(), $templateType->getScope()->getClassName()); + $reasons[] = sprintf( + 'Template type %s on class %s is not covariant. Learn more: https://phpstan.org/blog/whats-up-with-template-covariant', + $templateType->getName(), + $templateType->getScope()->getClassName(), + ); } } diff --git a/src/Type/Generic/TemplateTypeVarianceMap.php b/src/Type/Generic/TemplateTypeVarianceMap.php index 680c159e909..55d3a18aa31 100644 --- a/src/Type/Generic/TemplateTypeVarianceMap.php +++ b/src/Type/Generic/TemplateTypeVarianceMap.php @@ -8,22 +8,14 @@ class TemplateTypeVarianceMap { - /** - * @var array - */ - private $variances; - /** - * @var ?TemplateTypeVarianceMap - */ - private static $empty = null; + private static ?TemplateTypeVarianceMap $empty = null; /** * @api * @param array $variances */ - public function __construct(array $variances) + public function __construct(private array $variances) { - $this->variances = $variances; } public static function createEmpty(): self diff --git a/src/Type/Generic/TemplateUnionType.php b/src/Type/Generic/TemplateUnionType.php index 5b71bd2f38d..8e3bf90f5d6 100644 --- a/src/Type/Generic/TemplateUnionType.php +++ b/src/Type/Generic/TemplateUnionType.php @@ -11,9 +11,16 @@ final class TemplateUnionType extends UnionType implements TemplateType /** @use TemplateTypeTrait */ use TemplateTypeTrait; - public function __construct(TemplateTypeScope $scope, TemplateTypeStrategy $templateTypeStrategy, TemplateTypeVariance $templateTypeVariance, string $name, UnionType $bound) + public function __construct( + TemplateTypeScope $scope, + TemplateTypeStrategy $templateTypeStrategy, + TemplateTypeVariance $templateTypeVariance, + string $name, + UnionType $bound, + ) { parent::__construct($bound->getTypes()); + $this->scope = $scope; $this->strategy = $templateTypeStrategy; $this->variance = $templateTypeVariance; diff --git a/src/Type/Generic/TypeProjectionHelper.php b/src/Type/Generic/TypeProjectionHelper.php index 8e120ec4f26..217103bd099 100644 --- a/src/Type/Generic/TypeProjectionHelper.php +++ b/src/Type/Generic/TypeProjectionHelper.php @@ -9,15 +9,22 @@ class TypeProjectionHelper { - public static function describe(Type $type, ?TemplateTypeVariance $variance, VerbosityLevel $level) : string + public static function describe( + Type $type, + ?TemplateTypeVariance $variance, + VerbosityLevel $level, + ): string { $describedType = $type->describe($level); + if ($variance === null || $variance->invariant()) { return $describedType; } + if ($variance->bivariant()) { return '*'; } + return sprintf('%s %s', $variance->describe(), $describedType); } diff --git a/src/Type/GenericTypeVariableResolver.php b/src/Type/GenericTypeVariableResolver.php index 74ccb54e2c5..4f13c5eec97 100644 --- a/src/Type/GenericTypeVariableResolver.php +++ b/src/Type/GenericTypeVariableResolver.php @@ -11,7 +11,11 @@ class GenericTypeVariableResolver /** * @deprecated Use Type::getTemplateType() instead. */ - public static function getType(TypeWithClassName $type, string $genericClassName, string $typeVariableName) : ?Type + public static function getType( + TypeWithClassName $type, + string $genericClassName, + string $typeVariableName, + ): ?Type { $classReflection = $type->getClassReflection(); if ($classReflection === null) { @@ -21,7 +25,9 @@ public static function getType(TypeWithClassName $type, string $genericClassName if ($ancestorClassReflection === null) { return null; } + $activeTemplateTypeMap = $ancestorClassReflection->getPossiblyIncompleteActiveTemplateTypeMap(); + $type = $activeTemplateTypeMap->getType($typeVariableName); if ($type instanceof ErrorType) { $templateTypeMap = $ancestorClassReflection->getTemplateTypeMap(); @@ -37,6 +43,7 @@ public static function getType(TypeWithClassName $type, string $genericClassName return $bound; } + return $type; } diff --git a/src/Type/Helper/GetTemplateTypeType.php b/src/Type/Helper/GetTemplateTypeType.php index 3bb3389ce66..12e03fe1b0d 100644 --- a/src/Type/Helper/GetTemplateTypeType.php +++ b/src/Type/Helper/GetTemplateTypeType.php @@ -21,29 +21,14 @@ final class GetTemplateTypeType implements CompoundType, LateResolvableType { - /** - * @var Type - */ - private $type; - /** - * @var class-string - */ - private $ancestorClassName; - /** - * @var string - */ - private $templateTypeName; use LateResolvableTypeTrait; use NonGeneralizableTypeTrait; /** * @param class-string $ancestorClassName */ - public function __construct(Type $type, string $ancestorClassName, string $templateTypeName) + public function __construct(private Type $type, private string $ancestorClassName, private string $templateTypeName) { - $this->type = $type; - $this->ancestorClassName = $ancestorClassName; - $this->templateTypeName = $templateTypeName; } public function getReferencedClasses(): array @@ -108,11 +93,14 @@ public function traverseSimultaneously(Type $right, callable $cb): Type public function toPhpDocNode(): TypeNode { - return new GenericTypeNode(new IdentifierTypeNode('template-type'), [ + return new GenericTypeNode( + new IdentifierTypeNode('template-type'), + [ $this->type->toPhpDocNode(), new IdentifierTypeNode($this->ancestorClassName), new ConstTypeNode(new QuoteAwareConstExprStringNode($this->templateTypeName, QuoteAwareConstExprStringNode::SINGLE_QUOTED)), - ]); + ], + ); } /** @@ -120,7 +108,11 @@ public function toPhpDocNode(): TypeNode */ public static function __set_state(array $properties): Type { - return new self($properties['type'], $properties['ancestorClassName'], $properties['templateTypeName']); + return new self( + $properties['type'], + $properties['ancestorClassName'], + $properties['templateTypeName'], + ); } } diff --git a/src/Type/IntegerRangeType.php b/src/Type/IntegerRangeType.php index 62bc4029203..1779cb41ad9 100644 --- a/src/Type/IntegerRangeType.php +++ b/src/Type/IntegerRangeType.php @@ -29,18 +29,8 @@ class IntegerRangeType extends IntegerType implements CompoundType { - /** - * @var ?int - */ - private $min; - /** - * @var ?int - */ - private $max; - private function __construct(?int $min, ?int $max) + private function __construct(private ?int $min, private ?int $max) { - $this->min = $min; - $this->max = $max; parent::__construct(); assert($min === null || $max === null || $min <= $max); assert($min !== null || $max !== null); @@ -282,18 +272,17 @@ public function isSubTypeOf(Type $otherType): TrinaryLogic private function isSubTypeOfUnion(UnionType $otherType): TrinaryLogic { if ($this->min !== null && $this->max !== null) { - $matchingConstantIntegers = array_filter($otherType->getTypes(), function (Type $type) : bool { - return $type instanceof ConstantIntegerType && $type->getValue() >= $this->min && $type->getValue() <= $this->max; - }); + $matchingConstantIntegers = array_filter( + $otherType->getTypes(), + fn (Type $type): bool => $type instanceof ConstantIntegerType && $type->getValue() >= $this->min && $type->getValue() <= $this->max, + ); if (count($matchingConstantIntegers) === ($this->max - $this->min + 1)) { return TrinaryLogic::createYes(); } } - return TrinaryLogic::createNo()->lazyOr($otherType->getTypes(), function (Type $innerType) { - return $this->isSubTypeOf($innerType); - }); + return TrinaryLogic::createNo()->lazyOr($otherType->getTypes(), fn (Type $innerType) => $this->isSubTypeOf($innerType)); } public function isAcceptedBy(Type $acceptingType, bool $strictTypes): TrinaryLogic @@ -475,7 +464,10 @@ public function tryUnion(Type $otherType): ?Type return null; } - return self::fromInterval($this->min !== null && $otherMin !== null ? min($this->min, $otherMin) : null, $this->max !== null && $otherMax !== null ? max($this->max, $otherMax) : null); + return self::fromInterval( + $this->min !== null && $otherMin !== null ? min($this->min, $otherMin) : null, + $this->max !== null && $otherMax !== null ? max($this->max, $otherMax) : null, + ); } if (get_class($otherType) === parent::class) { diff --git a/src/Type/IntegerType.php b/src/Type/IntegerType.php index fb02a776a40..5e81e005190 100644 --- a/src/Type/IntegerType.php +++ b/src/Type/IntegerType.php @@ -82,7 +82,13 @@ public function toString(): Type public function toArray(): Type { - return new ConstantArrayType([new ConstantIntegerType(0)], [$this], [1], [], TrinaryLogic::createYes()); + return new ConstantArrayType( + [new ConstantIntegerType(0)], + [$this], + [1], + [], + TrinaryLogic::createYes(), + ); } public function toArrayKey(): Type diff --git a/src/Type/IntersectionType.php b/src/Type/IntersectionType.php index b8737ae4988..3fe932552a0 100644 --- a/src/Type/IntersectionType.php +++ b/src/Type/IntersectionType.php @@ -50,44 +50,38 @@ class IntersectionType implements CompoundType { - /** - * @var Type[] - */ - private $types; - use NonRemoveableTypeTrait; + use NonRemoveableTypeTrait; use NonGeneralizableTypeTrait; - /** - * @var bool - */ - private $sortedTypes = false; + private bool $sortedTypes = false; /** - * @api - * @param Type[] $types - */ - public function __construct(array $types) - { - $this->types = $types; - if (count($types) < 2) { - throw new ShouldNotHappenException(sprintf('Cannot create %s with: %s', self::class, implode(', ', array_map(static function (Type $type) : string { - return $type->describe(VerbosityLevel::value()); - }, $types)))); + * @api + * @param Type[] $types + */ + public function __construct(private array $types) + { + if (count($types) < 2) { + throw new ShouldNotHappenException(sprintf( + 'Cannot create %s with: %s', + self::class, + implode(', ', array_map(static fn (Type $type): string => $type->describe(VerbosityLevel::value()), $types)), + )); } } /** - * @return Type[] - */ - public function getTypes(): array + * @return Type[] + */ + public function getTypes(): array { return $this->types; } /** - * @return Type[] - */ - private function getSortedTypes(): array + * @return Type[] + */ + private function getSortedTypes(): array { if ($this->sortedTypes) { return $this->types; @@ -200,12 +194,20 @@ public function acceptsWithReason(Type $otherType, bool $strictTypes): AcceptsRe $reasons = $result->reasons; $verbosity = VerbosityLevel::getRecommendedLevelByType($this, $otherType); if ($this->isList()->yes() && !$isList->yes()) { - $reasons[] = sprintf('%s %s a list.', $otherType->describe($verbosity), $isList->no() ? 'is not' : 'might not be'); + $reasons[] = sprintf( + '%s %s a list.', + $otherType->describe($verbosity), + $isList->no() ? 'is not' : 'might not be', + ); } $isNonEmpty = $otherType->isIterableAtLeastOnce(); if ($this->isIterableAtLeastOnce()->yes() && !$isNonEmpty->yes()) { - $reasons[] = sprintf('%s %s empty.', $otherType->describe($verbosity), $isNonEmpty->no() ? 'is' : 'might be'); + $reasons[] = sprintf( + '%s %s empty.', + $otherType->describe($verbosity), + $isNonEmpty->no() ? 'is' : 'might be', + ); } if (count($reasons) > 0) { @@ -226,9 +228,7 @@ public function isSuperTypeOf(Type $otherType): TrinaryLogic return TrinaryLogic::createYes(); } - return TrinaryLogic::createYes()->lazyAnd($this->getTypes(), static function (Type $innerType) use($otherType) { - return $innerType->isSuperTypeOf($otherType); - }); + return TrinaryLogic::createYes()->lazyAnd($this->getTypes(), static fn (Type $innerType) => $innerType->isSuperTypeOf($otherType)); } public function isSubTypeOf(Type $otherType): TrinaryLogic @@ -237,9 +237,7 @@ public function isSubTypeOf(Type $otherType): TrinaryLogic return $otherType->isSuperTypeOf($this); } - $result = TrinaryLogic::lazyMaxMin($this->getTypes(), static function (Type $innerType) use($otherType) { - return $otherType->isSuperTypeOf($innerType); - }); + $result = TrinaryLogic::lazyMaxMin($this->getTypes(), static fn (Type $innerType) => $otherType->isSuperTypeOf($innerType)); if ($this->isOversizedArray()->yes()) { if (!$result->no()) { return TrinaryLogic::createYes(); @@ -256,9 +254,7 @@ public function isAcceptedBy(Type $acceptingType, bool $strictTypes): TrinaryLog public function isAcceptedWithReasonBy(Type $acceptingType, bool $strictTypes): AcceptsResult { - $result = AcceptsResult::maxMin(...array_map(static function (Type $innerType) use($acceptingType, $strictTypes) { - return $acceptingType->acceptsWithReason($innerType, $strictTypes); - }, $this->types)); + $result = AcceptsResult::maxMin(...array_map(static fn (Type $innerType) => $acceptingType->acceptsWithReason($innerType, $strictTypes), $this->types)); if ($this->isOversizedArray()->yes()) { if (!$result->no()) { return AcceptsResult::createYes(); @@ -301,7 +297,8 @@ public function equals(Type $type): bool public function describe(VerbosityLevel $level): string { - return $level->handle(function () use ($level): string { + return $level->handle( + function () use ($level): string { $typeNames = []; foreach ($this->getSortedTypes() as $type) { if ($type instanceof AccessoryType) { @@ -311,11 +308,10 @@ public function describe(VerbosityLevel $level): string } return implode('&', $typeNames); - }, function () use($level) : string { - return $this->describeItself($level, true); - }, function () use($level) : string { - return $this->describeItself($level, false); - }); + }, + fn (): string => $this->describeItself($level, true), + fn (): string => $this->describeItself($level, false), + ); } private function describeItself(VerbosityLevel $level, bool $skipAccessoryTypes): string @@ -440,37 +436,27 @@ private function describeItself(VerbosityLevel $level, bool $skipAccessoryTypes) public function getTemplateType(string $ancestorClassName, string $templateTypeName): Type { - return $this->intersectTypes(static function (Type $type) use($ancestorClassName, $templateTypeName) : Type { - return $type->getTemplateType($ancestorClassName, $templateTypeName); - }); + return $this->intersectTypes(static fn (Type $type): Type => $type->getTemplateType($ancestorClassName, $templateTypeName)); } public function isObject(): TrinaryLogic { - return $this->intersectResults(static function (Type $type) : TrinaryLogic { - return $type->isObject(); - }); + return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->isObject()); } public function isEnum(): TrinaryLogic { - return $this->intersectResults(static function (Type $type) : TrinaryLogic { - return $type->isEnum(); - }); + return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->isEnum()); } public function canAccessProperties(): TrinaryLogic { - return $this->intersectResults(static function (Type $type) : TrinaryLogic { - return $type->canAccessProperties(); - }); + return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->canAccessProperties()); } public function hasProperty(string $propertyName): TrinaryLogic { - return $this->intersectResults(static function (Type $type) use($propertyName) : TrinaryLogic { - return $type->hasProperty($propertyName); - }); + return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->hasProperty($propertyName)); } public function getProperty(string $propertyName, ClassMemberAccessAnswerer $scope): PropertyReflection @@ -503,16 +489,12 @@ public function getUnresolvedPropertyPrototype(string $propertyName, ClassMember public function canCallMethods(): TrinaryLogic { - return $this->intersectResults(static function (Type $type) : TrinaryLogic { - return $type->canCallMethods(); - }); + return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->canCallMethods()); } public function hasMethod(string $methodName): TrinaryLogic { - return $this->intersectResults(static function (Type $type) use($methodName) : TrinaryLogic { - return $type->hasMethod($methodName); - }); + return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->hasMethod($methodName)); } public function getMethod(string $methodName, ClassMemberAccessAnswerer $scope): ExtendedMethodReflection @@ -545,16 +527,12 @@ public function getUnresolvedMethodPrototype(string $methodName, ClassMemberAcce public function canAccessConstants(): TrinaryLogic { - return $this->intersectResults(static function (Type $type) : TrinaryLogic { - return $type->canAccessConstants(); - }); + return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->canAccessConstants()); } public function hasConstant(string $constantName): TrinaryLogic { - return $this->intersectResults(static function (Type $type) use($constantName) : TrinaryLogic { - return $type->hasConstant($constantName); - }); + return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->hasConstant($constantName)); } public function getConstant(string $constantName): ConstantReflection @@ -570,163 +548,117 @@ public function getConstant(string $constantName): ConstantReflection public function isIterable(): TrinaryLogic { - return $this->intersectResults(static function (Type $type) : TrinaryLogic { - return $type->isIterable(); - }); + return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->isIterable()); } public function isIterableAtLeastOnce(): TrinaryLogic { - return $this->intersectResults(static function (Type $type) : TrinaryLogic { - return $type->isIterableAtLeastOnce(); - }); + return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->isIterableAtLeastOnce()); } public function getArraySize(): Type { - return $this->intersectTypes(static function (Type $type) : Type { - return $type->getArraySize(); - }); + return $this->intersectTypes(static fn (Type $type): Type => $type->getArraySize()); } public function getIterableKeyType(): Type { - return $this->intersectTypes(static function (Type $type) : Type { - return $type->getIterableKeyType(); - }); + return $this->intersectTypes(static fn (Type $type): Type => $type->getIterableKeyType()); } public function getFirstIterableKeyType(): Type { - return $this->intersectTypes(static function (Type $type) : Type { - return $type->getFirstIterableKeyType(); - }); + return $this->intersectTypes(static fn (Type $type): Type => $type->getFirstIterableKeyType()); } public function getLastIterableKeyType(): Type { - return $this->intersectTypes(static function (Type $type) : Type { - return $type->getLastIterableKeyType(); - }); + return $this->intersectTypes(static fn (Type $type): Type => $type->getLastIterableKeyType()); } public function getIterableValueType(): Type { - return $this->intersectTypes(static function (Type $type) : Type { - return $type->getIterableValueType(); - }); + return $this->intersectTypes(static fn (Type $type): Type => $type->getIterableValueType()); } public function getFirstIterableValueType(): Type { - return $this->intersectTypes(static function (Type $type) : Type { - return $type->getFirstIterableValueType(); - }); + return $this->intersectTypes(static fn (Type $type): Type => $type->getFirstIterableValueType()); } public function getLastIterableValueType(): Type { - return $this->intersectTypes(static function (Type $type) : Type { - return $type->getLastIterableValueType(); - }); + return $this->intersectTypes(static fn (Type $type): Type => $type->getLastIterableValueType()); } public function isArray(): TrinaryLogic { - return $this->intersectResults(static function (Type $type) : TrinaryLogic { - return $type->isArray(); - }); + return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->isArray()); } public function isConstantArray(): TrinaryLogic { - return $this->intersectResults(static function (Type $type) : TrinaryLogic { - return $type->isConstantArray(); - }); + return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->isConstantArray()); } public function isOversizedArray(): TrinaryLogic { - return $this->intersectResults(static function (Type $type) : TrinaryLogic { - return $type->isOversizedArray(); - }); + return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->isOversizedArray()); } public function isList(): TrinaryLogic { - return $this->intersectResults(static function (Type $type) : TrinaryLogic { - return $type->isList(); - }); + return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->isList()); } public function isString(): TrinaryLogic { - return $this->intersectResults(static function (Type $type) : TrinaryLogic { - return $type->isString(); - }); + return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->isString()); } public function isNumericString(): TrinaryLogic { - return $this->intersectResults(static function (Type $type) : TrinaryLogic { - return $type->isNumericString(); - }); + return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->isNumericString()); } public function isNonEmptyString(): TrinaryLogic { - return $this->intersectResults(static function (Type $type) : TrinaryLogic { - return $type->isNonEmptyString(); - }); + return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->isNonEmptyString()); } public function isNonFalsyString(): TrinaryLogic { - return $this->intersectResults(static function (Type $type) : TrinaryLogic { - return $type->isNonFalsyString(); - }); + return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->isNonFalsyString()); } public function isLiteralString(): TrinaryLogic { - return $this->intersectResults(static function (Type $type) : TrinaryLogic { - return $type->isLiteralString(); - }); + return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->isLiteralString()); } public function isClassStringType(): TrinaryLogic { - return $this->intersectResults(static function (Type $type) : TrinaryLogic { - return $type->isClassStringType(); - }); + return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->isClassStringType()); } public function getClassStringObjectType(): Type { - return $this->intersectTypes(static function (Type $type) : Type { - return $type->getClassStringObjectType(); - }); + return $this->intersectTypes(static fn (Type $type): Type => $type->getClassStringObjectType()); } public function getObjectTypeOrClassStringObjectType(): Type { - return $this->intersectTypes(static function (Type $type) : Type { - return $type->getObjectTypeOrClassStringObjectType(); - }); + return $this->intersectTypes(static fn (Type $type): Type => $type->getObjectTypeOrClassStringObjectType()); } public function isVoid(): TrinaryLogic { - return $this->intersectResults(static function (Type $type) : TrinaryLogic { - return $type->isVoid(); - }); + return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->isVoid()); } public function isScalar(): TrinaryLogic { - return $this->intersectResults(static function (Type $type) : TrinaryLogic { - return $type->isScalar(); - }); + return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->isScalar()); } public function looseCompare(Type $type, PhpVersion $phpVersion): BooleanType @@ -736,23 +668,17 @@ public function looseCompare(Type $type, PhpVersion $phpVersion): BooleanType public function isOffsetAccessible(): TrinaryLogic { - return $this->intersectResults(static function (Type $type) : TrinaryLogic { - return $type->isOffsetAccessible(); - }); + return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->isOffsetAccessible()); } public function hasOffsetValueType(Type $offsetType): TrinaryLogic { - return $this->intersectResults(static function (Type $type) use($offsetType) : TrinaryLogic { - return $type->hasOffsetValueType($offsetType); - }); + return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->hasOffsetValueType($offsetType)); } public function getOffsetValueType(Type $offsetType): Type { - $result = $this->intersectTypes(static function (Type $type) use($offsetType) : Type { - return $type->getOffsetValueType($offsetType); - }); + $result = $this->intersectTypes(static fn (Type $type): Type => $type->getOffsetValueType($offsetType)); if ($this->isOversizedArray()->yes()) { return TypeUtils::toBenevolentUnion($result); } @@ -762,79 +688,57 @@ public function getOffsetValueType(Type $offsetType): Type public function setOffsetValueType(?Type $offsetType, Type $valueType, bool $unionValues = true): Type { - return $this->intersectTypes(static function (Type $type) use($offsetType, $valueType, $unionValues) : Type { - return $type->setOffsetValueType($offsetType, $valueType, $unionValues); - }); + return $this->intersectTypes(static fn (Type $type): Type => $type->setOffsetValueType($offsetType, $valueType, $unionValues)); } public function unsetOffset(Type $offsetType): Type { - return $this->intersectTypes(static function (Type $type) use($offsetType) : Type { - return $type->unsetOffset($offsetType); - }); + return $this->intersectTypes(static fn (Type $type): Type => $type->unsetOffset($offsetType)); } public function getKeysArray(): Type { - return $this->intersectTypes(static function (Type $type) : Type { - return $type->getKeysArray(); - }); + return $this->intersectTypes(static fn (Type $type): Type => $type->getKeysArray()); } public function getValuesArray(): Type { - return $this->intersectTypes(static function (Type $type) : Type { - return $type->getValuesArray(); - }); + return $this->intersectTypes(static fn (Type $type): Type => $type->getValuesArray()); } public function fillKeysArray(Type $valueType): Type { - return $this->intersectTypes(static function (Type $type) use($valueType) : Type { - return $type->fillKeysArray($valueType); - }); + return $this->intersectTypes(static fn (Type $type): Type => $type->fillKeysArray($valueType)); } public function flipArray(): Type { - return $this->intersectTypes(static function (Type $type) : Type { - return $type->flipArray(); - }); + return $this->intersectTypes(static fn (Type $type): Type => $type->flipArray()); } public function intersectKeyArray(Type $otherArraysType): Type { - return $this->intersectTypes(static function (Type $type) use($otherArraysType) : Type { - return $type->intersectKeyArray($otherArraysType); - }); + return $this->intersectTypes(static fn (Type $type): Type => $type->intersectKeyArray($otherArraysType)); } public function popArray(): Type { - return $this->intersectTypes(static function (Type $type) : Type { - return $type->popArray(); - }); + return $this->intersectTypes(static fn (Type $type): Type => $type->popArray()); } public function searchArray(Type $needleType): Type { - return $this->intersectTypes(static function (Type $type) use($needleType) : Type { - return $type->searchArray($needleType); - }); + return $this->intersectTypes(static fn (Type $type): Type => $type->searchArray($needleType)); } public function shiftArray(): Type { - return $this->intersectTypes(static function (Type $type) : Type { - return $type->shiftArray(); - }); + return $this->intersectTypes(static fn (Type $type): Type => $type->shiftArray()); } public function shuffleArray(): Type { - return $this->intersectTypes(static function (Type $type) : Type { - return $type->shuffleArray(); - }); + return $this->intersectTypes(static fn (Type $type): Type => $type->shuffleArray()); } public function getEnumCases(): array @@ -853,15 +757,13 @@ public function getEnumCases(): array public function isCallable(): TrinaryLogic { - return $this->intersectResults(static function (Type $type) : TrinaryLogic { - return $type->isCallable(); - }); + return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->isCallable()); } /** - * @return ParametersAcceptor[] - */ - public function getCallableParametersAcceptors(ClassMemberAccessAnswerer $scope): array + * @return ParametersAcceptor[] + */ + public function getCallableParametersAcceptors(ClassMemberAccessAnswerer $scope): array { if ($this->isCallable()->no()) { throw new ShouldNotHappenException(); @@ -872,44 +774,32 @@ public function getCallableParametersAcceptors(ClassMemberAccessAnswerer $scope) public function isCloneable(): TrinaryLogic { - return $this->intersectResults(static function (Type $type) : TrinaryLogic { - return $type->isCloneable(); - }); + return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->isCloneable()); } public function isSmallerThan(Type $otherType): TrinaryLogic { - return $this->intersectResults(static function (Type $type) use($otherType) : TrinaryLogic { - return $type->isSmallerThan($otherType); - }); + return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->isSmallerThan($otherType)); } public function isSmallerThanOrEqual(Type $otherType): TrinaryLogic { - return $this->intersectResults(static function (Type $type) use($otherType) : TrinaryLogic { - return $type->isSmallerThanOrEqual($otherType); - }); + return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->isSmallerThanOrEqual($otherType)); } public function isNull(): TrinaryLogic { - return $this->intersectResults(static function (Type $type) : TrinaryLogic { - return $type->isNull(); - }); + return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->isNull()); } public function isConstantValue(): TrinaryLogic { - return $this->intersectResults(static function (Type $type) : TrinaryLogic { - return $type->isConstantValue(); - }); + return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->isConstantValue()); } public function isConstantScalarValue(): TrinaryLogic { - return $this->intersectResults(static function (Type $type) : TrinaryLogic { - return $type->isConstantScalarValue(); - }); + return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->isConstantScalarValue()); } public function getConstantScalarTypes(): array @@ -938,86 +828,62 @@ public function getConstantScalarValues(): array public function isTrue(): TrinaryLogic { - return $this->intersectResults(static function (Type $type) : TrinaryLogic { - return $type->isTrue(); - }); + return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->isTrue()); } public function isFalse(): TrinaryLogic { - return $this->intersectResults(static function (Type $type) : TrinaryLogic { - return $type->isFalse(); - }); + return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->isFalse()); } public function isBoolean(): TrinaryLogic { - return $this->intersectResults(static function (Type $type) : TrinaryLogic { - return $type->isBoolean(); - }); + return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->isBoolean()); } public function isFloat(): TrinaryLogic { - return $this->intersectResults(static function (Type $type) : TrinaryLogic { - return $type->isFloat(); - }); + return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->isFloat()); } public function isInteger(): TrinaryLogic { - return $this->intersectResults(static function (Type $type) : TrinaryLogic { - return $type->isInteger(); - }); + return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->isInteger()); } public function isGreaterThan(Type $otherType): TrinaryLogic { - return $this->intersectResults(static function (Type $type) use($otherType) : TrinaryLogic { - return $otherType->isSmallerThan($type); - }); + return $this->intersectResults(static fn (Type $type): TrinaryLogic => $otherType->isSmallerThan($type)); } public function isGreaterThanOrEqual(Type $otherType): TrinaryLogic { - return $this->intersectResults(static function (Type $type) use($otherType) : TrinaryLogic { - return $otherType->isSmallerThanOrEqual($type); - }); + return $this->intersectResults(static fn (Type $type): TrinaryLogic => $otherType->isSmallerThanOrEqual($type)); } public function getSmallerType(): Type { - return $this->intersectTypes(static function (Type $type) : Type { - return $type->getSmallerType(); - }); + return $this->intersectTypes(static fn (Type $type): Type => $type->getSmallerType()); } public function getSmallerOrEqualType(): Type { - return $this->intersectTypes(static function (Type $type) : Type { - return $type->getSmallerOrEqualType(); - }); + return $this->intersectTypes(static fn (Type $type): Type => $type->getSmallerOrEqualType()); } public function getGreaterType(): Type { - return $this->intersectTypes(static function (Type $type) : Type { - return $type->getGreaterType(); - }); + return $this->intersectTypes(static fn (Type $type): Type => $type->getGreaterType()); } public function getGreaterOrEqualType(): Type { - return $this->intersectTypes(static function (Type $type) : Type { - return $type->getGreaterOrEqualType(); - }); + return $this->intersectTypes(static fn (Type $type): Type => $type->getGreaterOrEqualType()); } public function toBoolean(): BooleanType { - $type = $this->intersectTypes(static function (Type $type) : BooleanType { - return $type->toBoolean(); - }); + $type = $this->intersectTypes(static fn (Type $type): BooleanType => $type->toBoolean()); if (!$type instanceof BooleanType) { return new BooleanType(); @@ -1028,45 +894,35 @@ public function toBoolean(): BooleanType public function toNumber(): Type { - $type = $this->intersectTypes(static function (Type $type) : Type { - return $type->toNumber(); - }); + $type = $this->intersectTypes(static fn (Type $type): Type => $type->toNumber()); return $type; } public function toString(): Type { - $type = $this->intersectTypes(static function (Type $type) : Type { - return $type->toString(); - }); + $type = $this->intersectTypes(static fn (Type $type): Type => $type->toString()); return $type; } public function toInteger(): Type { - $type = $this->intersectTypes(static function (Type $type) : Type { - return $type->toInteger(); - }); + $type = $this->intersectTypes(static fn (Type $type): Type => $type->toInteger()); return $type; } public function toFloat(): Type { - $type = $this->intersectTypes(static function (Type $type) : Type { - return $type->toFloat(); - }); + $type = $this->intersectTypes(static fn (Type $type): Type => $type->toFloat()); return $type; } public function toArray(): Type { - $type = $this->intersectTypes(static function (Type $type) : Type { - return $type->toArray(); - }); + $type = $this->intersectTypes(static fn (Type $type): Type => $type->toArray()); return $type; } @@ -1081,9 +937,7 @@ public function toArrayKey(): Type return $this; } - return $this->intersectTypes(static function (Type $type) : Type { - return $type->toArrayKey(); - }); + return $this->intersectTypes(static fn (Type $type): Type => $type->toArrayKey()); } public function inferTemplateTypes(Type $receivedType): TemplateTypeMap @@ -1161,16 +1015,12 @@ public function traverseSimultaneously(Type $right, callable $cb): Type public function tryRemove(Type $typeToRemove): ?Type { - return $this->intersectTypes(static function (Type $type) use($typeToRemove) : Type { - return TypeCombinator::remove($type, $typeToRemove); - }); + return $this->intersectTypes(static fn (Type $type): Type => TypeCombinator::remove($type, $typeToRemove)); } public function exponentiate(Type $exponent): Type { - return $this->intersectTypes(static function (Type $type) use($exponent) : Type { - return $type->exponentiate($exponent); - }); + return $this->intersectTypes(static fn (Type $type): Type => $type->exponentiate($exponent)); } public function getFiniteTypes(): array @@ -1194,25 +1044,25 @@ public function getFiniteTypes(): array } /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): Type + * @param mixed[] $properties + */ + public static function __set_state(array $properties): Type { return new self($properties['types']); } /** - * @param callable(Type $type): TrinaryLogic $getResult - */ - private function intersectResults(callable $getResult): TrinaryLogic + * @param callable(Type $type): TrinaryLogic $getResult + */ + private function intersectResults(callable $getResult): TrinaryLogic { return TrinaryLogic::lazyMaxMin($this->types, $getResult); } /** - * @param callable(Type $type): Type $getType - */ - private function intersectTypes(callable $getType): Type + * @param callable(Type $type): Type $getType + */ + private function intersectTypes(callable $getType): Type { $operands = array_map($getType, $this->types); return TypeCombinator::intersect(...$operands); @@ -1297,7 +1147,10 @@ public function toPhpDocNode(): TypeNode $typeName = 'non-empty-' . $typeName; } - $describedTypes[$i] = new GenericTypeNode(new IdentifierTypeNode($typeName), $typeNode->genericTypes); + $describedTypes[$i] = new GenericTypeNode( + new IdentifierTypeNode($typeName), + $typeNode->genericTypes, + ); continue; } diff --git a/src/Type/IterableType.php b/src/Type/IterableType.php index 82c2452f2a8..c675aff51d8 100644 --- a/src/Type/IterableType.php +++ b/src/Type/IterableType.php @@ -26,14 +26,6 @@ class IterableType implements CompoundType { - /** - * @var Type - */ - private $keyType; - /** - * @var Type - */ - private $itemType; use MaybeArrayTypeTrait; use MaybeCallableTypeTrait; use MaybeObjectTypeTrait; @@ -43,10 +35,11 @@ class IterableType implements CompoundType use NonGeneralizableTypeTrait; /** @api */ - public function __construct(Type $keyType, Type $itemType) + public function __construct( + private Type $keyType, + private Type $itemType, + ) { - $this->keyType = $keyType; - $this->itemType = $itemType; } public function getKeyType(): Type @@ -64,7 +57,10 @@ public function getItemType(): Type */ public function getReferencedClasses(): array { - return array_merge($this->keyType->getReferencedClasses(), $this->getItemType()->getReferencedClasses()); + return array_merge( + $this->keyType->getReferencedClasses(), + $this->getItemType()->getReferencedClasses(), + ); } public function getObjectClassNames(): array @@ -165,7 +161,11 @@ public function isSubTypeOf(Type $otherType): TrinaryLogic return TrinaryLogic::createMaybe(); } - return $limit->and($otherType->isIterable(), $otherType->getIterableValueType()->isSuperTypeOf($this->itemType), $otherType->getIterableKeyType()->isSuperTypeOf($this->keyType)); + return $limit->and( + $otherType->isIterable(), + $otherType->getIterableValueType()->isSuperTypeOf($this->itemType), + $otherType->getIterableKeyType()->isSuperTypeOf($this->keyType), + ); } public function isAcceptedBy(Type $acceptingType, bool $strictTypes): TrinaryLogic @@ -417,7 +417,10 @@ public function getReferencedTemplateTypes(TemplateTypeVariance $positionVarianc { $variance = $positionVariance->compose(TemplateTypeVariance::createCovariant()); - return array_merge($this->getIterableKeyType()->getReferencedTemplateTypes($variance), $this->getIterableValueType()->getReferencedTemplateTypes($variance)); + return array_merge( + $this->getIterableKeyType()->getReferencedTemplateTypes($variance), + $this->getIterableValueType()->getReferencedTemplateTypes($variance), + ); } public function traverse(callable $cb): Type @@ -482,15 +485,21 @@ public function toPhpDocNode(): TypeNode return new IdentifierTypeNode('iterable'); } - return new GenericTypeNode(new IdentifierTypeNode('iterable'), [ + return new GenericTypeNode( + new IdentifierTypeNode('iterable'), + [ $this->itemType->toPhpDocNode(), - ]); + ], + ); } - return new GenericTypeNode(new IdentifierTypeNode('iterable'), [ + return new GenericTypeNode( + new IdentifierTypeNode('iterable'), + [ $this->keyType->toPhpDocNode(), $this->itemType->toPhpDocNode(), - ]); + ], + ); } /** diff --git a/src/Type/KeyOfType.php b/src/Type/KeyOfType.php index cb7226ad023..32eab8b0192 100644 --- a/src/Type/KeyOfType.php +++ b/src/Type/KeyOfType.php @@ -14,16 +14,11 @@ class KeyOfType implements CompoundType, LateResolvableType { - /** - * @var Type - */ - private $type; use LateResolvableTypeTrait; use NonGeneralizableTypeTrait; - public function __construct(Type $type) + public function __construct(private Type $type) { - $this->type = $type; } public function getType(): Type @@ -101,7 +96,9 @@ public function toPhpDocNode(): TypeNode */ public static function __set_state(array $properties): Type { - return new self($properties['type']); + return new self( + $properties['type'], + ); } } diff --git a/src/Type/LazyTypeAliasResolverProvider.php b/src/Type/LazyTypeAliasResolverProvider.php index ca70791eff8..d270e691f27 100644 --- a/src/Type/LazyTypeAliasResolverProvider.php +++ b/src/Type/LazyTypeAliasResolverProvider.php @@ -7,13 +7,8 @@ class LazyTypeAliasResolverProvider implements TypeAliasResolverProvider { - /** - * @var Container - */ - private $container; - public function __construct(Container $container) + public function __construct(private Container $container) { - $this->container = $container; } public function getTypeAliasResolver(): TypeAliasResolver diff --git a/src/Type/MixedType.php b/src/Type/MixedType.php index 72a868b34ff..749994cf6e9 100644 --- a/src/Type/MixedType.php +++ b/src/Type/MixedType.php @@ -39,33 +39,29 @@ class MixedType implements CompoundType, SubtractableType { - /** - * @var bool - */ - private $isExplicitMixed; - use NonGenericTypeTrait; + use NonGenericTypeTrait; use UndecidedComparisonCompoundTypeTrait; use NonGeneralizableTypeTrait; - /** - * @var ?Type - */ - private $subtractedType; + private ?Type $subtractedType; /** @api */ - public function __construct(bool $isExplicitMixed = false, ?Type $subtractedType = null) - { - $this->isExplicitMixed = $isExplicitMixed; - if ($subtractedType instanceof NeverType) { - $subtractedType = null; - } - $this->subtractedType = $subtractedType; - } + public function __construct( + private bool $isExplicitMixed = false, + ?Type $subtractedType = null, + ) + { + if ($subtractedType instanceof NeverType) { + $subtractedType = null; + } + + $this->subtractedType = $subtractedType; + } /** - * @return string[] - */ - public function getReferencedClasses(): array + * @return string[] + */ + public function getReferencedClasses(): array { return []; } @@ -269,9 +265,9 @@ public function getEnumCases(): array } /** - * @return ParametersAcceptor[] - */ - public function getCallableParametersAcceptors(ClassMemberAccessAnswerer $scope): array + * @return ParametersAcceptor[] + */ + public function getCallableParametersAcceptors(ClassMemberAccessAnswerer $scope): array { return [new TrivialParametersAcceptor()]; } @@ -370,9 +366,12 @@ public function getProperty(string $propertyName, ClassMemberAccessAnswerer $sco public function getUnresolvedPropertyPrototype(string $propertyName, ClassMemberAccessAnswerer $scope): UnresolvedPropertyPrototypeReflection { $property = new DummyPropertyReflection(); - return new CallbackUnresolvedPropertyPrototypeReflection($property, $property->getDeclaringClass(), false, static function (Type $type) : Type { - return $type; - }); + return new CallbackUnresolvedPropertyPrototypeReflection( + $property, + $property->getDeclaringClass(), + false, + static fn (Type $type): Type => $type, + ); } public function canCallMethods(): TrinaryLogic @@ -393,9 +392,12 @@ public function getMethod(string $methodName, ClassMemberAccessAnswerer $scope): public function getUnresolvedMethodPrototype(string $methodName, ClassMemberAccessAnswerer $scope): UnresolvedMethodPrototypeReflection { $method = new DummyMethodReflection($methodName); - return new CallbackUnresolvedMethodPrototypeReflection($method, $method->getDeclaringClass(), false, static function (Type $type) : Type { - return $type; - }); + return new CallbackUnresolvedMethodPrototypeReflection( + $method, + $method->getDeclaringClass(), + false, + static fn (Type $type): Type => $type, + ); } public function canAccessConstants(): TrinaryLogic @@ -420,18 +422,18 @@ public function isCloneable(): TrinaryLogic public function describe(VerbosityLevel $level): string { - return $level->handle(static function () : string { - return 'mixed'; - }, static function () : string { - return 'mixed'; - }, function () use ($level): string { + return $level->handle( + static fn (): string => 'mixed', + static fn (): string => 'mixed', + function () use ($level): string { $description = 'mixed'; if ($this->subtractedType !== null) { $description .= sprintf('~%s', $this->subtractedType->describe($level)); } return $description; - }, function () use ($level): string { + }, + function () use ($level): string { $description = 'mixed'; if ($this->subtractedType !== null) { $description .= sprintf('~%s', $this->subtractedType->describe($level)); @@ -444,7 +446,8 @@ public function describe(VerbosityLevel $level): string } return $description; - }); + }, + ); } public function toBoolean(): BooleanType @@ -637,7 +640,10 @@ public function isConstantArray(): TrinaryLogic public function isOversizedArray(): TrinaryLogic { if ($this->subtractedType !== null) { - $oversizedArray = TypeCombinator::intersect(new ArrayType(new MixedType(), new MixedType()), new OversizedArrayType()); + $oversizedArray = TypeCombinator::intersect( + new ArrayType(new MixedType(), new MixedType()), + new OversizedArrayType(), + ); if ($this->subtractedType->isSuperTypeOf($oversizedArray)->yes()) { return TrinaryLogic::createNo(); @@ -650,7 +656,10 @@ public function isOversizedArray(): TrinaryLogic public function isList(): TrinaryLogic { if ($this->subtractedType !== null) { - $list = TypeCombinator::intersect(new ArrayType(new IntegerType(), new MixedType()), new AccessoryArrayListType()); + $list = TypeCombinator::intersect( + new ArrayType(new IntegerType(), new MixedType()), + new AccessoryArrayListType(), + ); if ($this->subtractedType->isSuperTypeOf($list)->yes()) { return TrinaryLogic::createNo(); @@ -759,7 +768,10 @@ public function isString(): TrinaryLogic public function isNumericString(): TrinaryLogic { if ($this->subtractedType !== null) { - $numericString = TypeCombinator::intersect(new StringType(), new AccessoryNumericStringType()); + $numericString = TypeCombinator::intersect( + new StringType(), + new AccessoryNumericStringType(), + ); if ($this->subtractedType->isSuperTypeOf($numericString)->yes()) { return TrinaryLogic::createNo(); @@ -772,7 +784,10 @@ public function isNumericString(): TrinaryLogic public function isNonEmptyString(): TrinaryLogic { if ($this->subtractedType !== null) { - $nonEmptyString = TypeCombinator::intersect(new StringType(), new AccessoryNonEmptyStringType()); + $nonEmptyString = TypeCombinator::intersect( + new StringType(), + new AccessoryNonEmptyStringType(), + ); if ($this->subtractedType->isSuperTypeOf($nonEmptyString)->yes()) { return TrinaryLogic::createNo(); @@ -785,7 +800,10 @@ public function isNonEmptyString(): TrinaryLogic public function isNonFalsyString(): TrinaryLogic { if ($this->subtractedType !== null) { - $nonFalsyString = TypeCombinator::intersect(new StringType(), new AccessoryNonFalsyStringType()); + $nonFalsyString = TypeCombinator::intersect( + new StringType(), + new AccessoryNonFalsyStringType(), + ); if ($this->subtractedType->isSuperTypeOf($nonFalsyString)->yes()) { return TrinaryLogic::createNo(); @@ -798,7 +816,10 @@ public function isNonFalsyString(): TrinaryLogic public function isLiteralString(): TrinaryLogic { if ($this->subtractedType !== null) { - $literalString = TypeCombinator::intersect(new StringType(), new AccessoryLiteralStringType()); + $literalString = TypeCombinator::intersect( + new StringType(), + new AccessoryLiteralStringType(), + ); if ($this->subtractedType->isSuperTypeOf($literalString)->yes()) { return TrinaryLogic::createNo(); @@ -899,11 +920,14 @@ public function toPhpDocNode(): TypeNode } /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): Type - { - return new self($properties['isExplicitMixed'], $properties['subtractedType'] ?? null); + * @param mixed[] $properties + */ + public static function __set_state(array $properties): Type + { + return new self( + $properties['isExplicitMixed'], + $properties['subtractedType'] ?? null, + ); } } diff --git a/src/Type/NeverType.php b/src/Type/NeverType.php index 9a660b77f8a..18b5c2ba21f 100644 --- a/src/Type/NeverType.php +++ b/src/Type/NeverType.php @@ -25,10 +25,6 @@ class NeverType implements CompoundType { - /** - * @var bool - */ - private $isExplicit; use UndecidedBooleanTypeTrait; use NonGenericTypeTrait; use UndecidedComparisonCompoundTypeTrait; @@ -36,9 +32,8 @@ class NeverType implements CompoundType use NonGeneralizableTypeTrait; /** @api */ - public function __construct(bool $isExplicit = false) + public function __construct(private bool $isExplicit = false) { - $this->isExplicit = $isExplicit; } public function isExplicit(): bool diff --git a/src/Type/NullType.php b/src/Type/NullType.php index 05dbf6087fa..a796c70e126 100644 --- a/src/Type/NullType.php +++ b/src/Type/NullType.php @@ -362,10 +362,12 @@ public function getFiniteTypes(): array public function exponentiate(Type $exponent): Type { - return new UnionType([ + return new UnionType( + [ new ConstantIntegerType(0), new ConstantIntegerType(1), - ]); + ], + ); } public function toPhpDocNode(): TypeNode diff --git a/src/Type/ObjectShapePropertyReflection.php b/src/Type/ObjectShapePropertyReflection.php index bcf100966bd..a79f9244176 100644 --- a/src/Type/ObjectShapePropertyReflection.php +++ b/src/Type/ObjectShapePropertyReflection.php @@ -11,13 +11,8 @@ class ObjectShapePropertyReflection implements PropertyReflection { - /** - * @var Type - */ - private $type; - public function __construct(Type $type) + public function __construct(private Type $type) { - $this->type = $type; } public function getDeclaringClass(): ClassReflection diff --git a/src/Type/ObjectShapeType.php b/src/Type/ObjectShapeType.php index 0514563da02..17bffaa7bbd 100644 --- a/src/Type/ObjectShapeType.php +++ b/src/Type/ObjectShapeType.php @@ -39,14 +39,6 @@ class ObjectShapeType implements Type { - /** - * @var array - */ - private $properties; - /** - * @var list - */ - private $optionalProperties; use ObjectTypeTrait; use UndecidedComparisonTypeTrait; use NonGeneralizableTypeTrait; @@ -56,10 +48,8 @@ class ObjectShapeType implements Type * @param array $properties * @param list $optionalProperties */ - public function __construct(array $properties, array $optionalProperties) + public function __construct(private array $properties, private array $optionalProperties) { - $this->properties = $properties; - $this->optionalProperties = $optionalProperties; } /** @@ -125,9 +115,12 @@ public function getUnresolvedPropertyPrototype(string $propertyName, ClassMember } $property = new ObjectShapePropertyReflection($this->properties[$propertyName]); - return new CallbackUnresolvedPropertyPrototypeReflection($property, $property->getDeclaringClass(), false, static function (Type $type) : Type { - return $type; - }); + return new CallbackUnresolvedPropertyPrototypeReflection( + $property, + $property->getDeclaringClass(), + false, + static fn (Type $type): Type => $type, + ); } public function accepts(Type $type, bool $strictTypes): TrinaryLogic @@ -143,7 +136,11 @@ public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult $reflectionProvider = ReflectionProviderStaticAccessor::getInstance(); foreach ($type->getObjectClassReflections() as $classReflection) { - if (!UniversalObjectCratesClassReflectionExtension::isUniversalObjectCrate($reflectionProvider, Broker::getInstance()->getUniversalObjectCratesClasses(), $classReflection)) { + if (!UniversalObjectCratesClassReflectionExtension::isUniversalObjectCrate( + $reflectionProvider, + Broker::getInstance()->getUniversalObjectCratesClasses(), + $classReflection, + )) { continue; } @@ -154,9 +151,17 @@ public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult $scope = new OutOfClassScope(); foreach ($this->properties as $propertyName => $propertyType) { $typeHasProperty = $type->hasProperty($propertyName); - $hasProperty = new AcceptsResult($typeHasProperty, $typeHasProperty->yes() ? [] : [ - sprintf('%s %s have property $%s.', $type->describe(VerbosityLevel::typeOnly()), $typeHasProperty->no() ? 'does not' : 'might not', $propertyName), - ]); + $hasProperty = new AcceptsResult( + $typeHasProperty, + $typeHasProperty->yes() ? [] : [ + sprintf( + '%s %s have property $%s.', + $type->describe(VerbosityLevel::typeOnly()), + $typeHasProperty->no() ? 'does not' : 'might not', + $propertyName, + ), + ], + ); if ($hasProperty->no()) { if (in_array($propertyName, $this->optionalProperties, true)) { continue; @@ -171,10 +176,18 @@ public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult try { $otherProperty = $type->getProperty($propertyName, $scope); - } catch (MissingPropertyFromReflectionException $e) { - return new AcceptsResult($result->result, [ - sprintf('%s %s not have property $%s.', $type->describe(VerbosityLevel::typeOnly()), $result->no() ? 'does' : 'might', $propertyName), - ]); + } catch (MissingPropertyFromReflectionException) { + return new AcceptsResult( + $result->result, + [ + sprintf( + '%s %s not have property $%s.', + $type->describe(VerbosityLevel::typeOnly()), + $result->no() ? 'does' : 'might', + $propertyName, + ), + ], + ); } if (!$otherProperty->isPublic()) { return new AcceptsResult(TrinaryLogic::createNo(), [ @@ -196,12 +209,23 @@ public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult $otherPropertyType = $otherProperty->getReadableType(); $verbosity = VerbosityLevel::getRecommendedLevelByType($propertyType, $otherPropertyType); - $acceptsValue = $propertyType->acceptsWithReason($otherPropertyType, $strictTypes)->decorateReasons(static function (string $reason) use($propertyName, $propertyType, $verbosity, $otherPropertyType) { - return sprintf('Property ($%s) type %s does not accept type %s: %s', $propertyName, $propertyType->describe($verbosity), $otherPropertyType->describe($verbosity), $reason); - }); + $acceptsValue = $propertyType->acceptsWithReason($otherPropertyType, $strictTypes)->decorateReasons( + static fn (string $reason) => sprintf( + 'Property ($%s) type %s does not accept type %s: %s', + $propertyName, + $propertyType->describe($verbosity), + $otherPropertyType->describe($verbosity), + $reason, + ), + ); if (!$acceptsValue->yes() && count($acceptsValue->reasons) === 0) { $acceptsValue = new AcceptsResult($acceptsValue->result, [ - sprintf('Property ($%s) type %s does not accept type %s.', $propertyName, $propertyType->describe($verbosity), $otherPropertyType->describe($verbosity)), + sprintf( + 'Property ($%s) type %s does not accept type %s.', + $propertyName, + $propertyType->describe($verbosity), + $otherPropertyType->describe($verbosity), + ), ]); } if ($acceptsValue->no()) { @@ -225,7 +249,11 @@ public function isSuperTypeOf(Type $type): TrinaryLogic $reflectionProvider = ReflectionProviderStaticAccessor::getInstance(); foreach ($type->getObjectClassReflections() as $classReflection) { - if (!UniversalObjectCratesClassReflectionExtension::isUniversalObjectCrate($reflectionProvider, Broker::getInstance()->getUniversalObjectCratesClasses(), $classReflection)) { + if (!UniversalObjectCratesClassReflectionExtension::isUniversalObjectCrate( + $reflectionProvider, + Broker::getInstance()->getUniversalObjectCratesClasses(), + $classReflection, + )) { continue; } @@ -250,7 +278,7 @@ public function isSuperTypeOf(Type $type): TrinaryLogic try { $otherProperty = $type->getProperty($propertyName, $scope); - } catch (MissingPropertyFromReflectionException $e) { + } catch (MissingPropertyFromReflectionException) { return $result; } @@ -317,9 +345,7 @@ public function tryRemove(Type $typeToRemove): ?Type if ($typeToRemove instanceof HasPropertyType) { $properties = $this->properties; unset($properties[$typeToRemove->getPropertyName()]); - $optionalProperties = array_values(array_filter($this->optionalProperties, static function (string $propertyName) use($typeToRemove) { - return $propertyName !== $typeToRemove->getPropertyName(); - })); + $optionalProperties = array_values(array_filter($this->optionalProperties, static fn (string $propertyName) => $propertyName !== $typeToRemove->getPropertyName())); return new self($properties, $optionalProperties); } @@ -330,9 +356,7 @@ public function tryRemove(Type $typeToRemove): ?Type public function makePropertyRequired(string $propertyName): self { if (array_key_exists($propertyName, $this->properties)) { - $optionalProperties = array_values(array_filter($this->optionalProperties, static function (string $currentPropertyName) use($propertyName) { - return $currentPropertyName !== $propertyName; - })); + $optionalProperties = array_values(array_filter($this->optionalProperties, static fn (string $currentPropertyName) => $currentPropertyName !== $propertyName)); return new self($this->properties, $optionalProperties); } @@ -356,7 +380,7 @@ public function inferTemplateTypes(Type $receivedType): TemplateTypeMap try { $receivedProperty = $receivedType->getProperty($name, $scope); - } catch (MissingPropertyFromReflectionException $e) { + } catch (MissingPropertyFromReflectionException) { continue; } if (!$receivedProperty->isPublic()) { @@ -398,7 +422,10 @@ public function describe(VerbosityLevel $level): string } return sprintf('object{%s}', implode(', ', $items)); }; - return $level->handle($callback, $callback); + return $level->handle( + $callback, + $callback, + ); } public function getEnumCases(): array @@ -488,7 +515,11 @@ public function toPhpDocNode(): TypeNode /** @var ConstExprStringNode $keyNode */ $keyNode = $keyPhpDocNode->constExpr; } - $items[] = new ObjectShapeItemNode($keyNode, in_array($name, $this->optionalProperties, true), $type->toPhpDocNode()); + $items[] = new ObjectShapeItemNode( + $keyNode, + in_array($name, $this->optionalProperties, true), + $type->toPhpDocNode(), + ); } return new ObjectShapeNode($items); diff --git a/src/Type/ObjectType.php b/src/Type/ObjectType.php index 7dcdec5087f..1fd22360872 100644 --- a/src/Type/ObjectType.php +++ b/src/Type/ObjectType.php @@ -61,15 +61,7 @@ class ObjectType implements TypeWithClassName, SubtractableType { - /** - * @var string - */ - private $className; - /** - * @var ?ClassReflection - */ - private $classReflection; - use MaybeIterableTypeTrait; + use MaybeIterableTypeTrait; use NonArrayTypeTrait; use NonGenericTypeTrait; use UndecidedComparisonTypeTrait; @@ -77,49 +69,43 @@ class ObjectType implements TypeWithClassName, SubtractableType private const EXTRA_OFFSET_CLASSES = ['SimpleXMLElement', 'DOMNodeList', 'Threaded']; - /** - * @var ?Type - */ - private $subtractedType; + private ?Type $subtractedType; /** @var array> */ - private static $superTypes = []; + private static array $superTypes = []; - /** - * @var ?self - */ - private $cachedParent = null; + private ?self $cachedParent = null; /** @var self[]|null */ - private $cachedInterfaces = null; + private ?array $cachedInterfaces = null; /** @var array>> */ - private static $methods = []; + private static array $methods = []; /** @var array>> */ - private static $properties = []; + private static array $properties = []; /** @var array> */ - private static $ancestors = []; + private static array $ancestors = []; /** @var array */ - private $currentAncestors = []; + private array $currentAncestors = []; - /** - * @var ?string - */ - private $cachedDescription = null; + private ?string $cachedDescription = null; /** @api */ - public function __construct(string $className, ?Type $subtractedType = null, ?ClassReflection $classReflection = null) - { - $this->className = $className; - $this->classReflection = $classReflection; - if ($subtractedType instanceof NeverType) { - $subtractedType = null; - } - $this->subtractedType = $subtractedType; - } + public function __construct( + private string $className, + ?Type $subtractedType = null, + private ?ClassReflection $classReflection = null, + ) + { + if ($subtractedType instanceof NeverType) { + $subtractedType = null; + } + + $this->subtractedType = $subtractedType; + } public static function resetCaches(): void { @@ -135,7 +121,13 @@ private static function createFromReflection(ClassReflection $reflection): self return new ObjectType($reflection->getName()); } - return new GenericObjectType($reflection->getName(), $reflection->typeMapToList($reflection->getActiveTemplateTypeMap()), null, null, $reflection->varianceMapToList($reflection->getCallSiteVarianceMap())); + return new GenericObjectType( + $reflection->getName(), + $reflection->typeMapToList($reflection->getActiveTemplateTypeMap()), + null, + null, + $reflection->varianceMapToList($reflection->getCallSiteVarianceMap()), + ); } public function getClassName(): string @@ -230,7 +222,12 @@ public function getUnresolvedPropertyPrototype(string $propertyName, ClassMember $resolvedClassReflection = $property->getDeclaringClass(); } - return self::$properties[$description][$propertyName][$canAccessProperty] = new CalledOnTypeUnresolvedPropertyPrototypeReflection($property, $resolvedClassReflection, true, $this); + return self::$properties[$description][$propertyName][$canAccessProperty] = new CalledOnTypeUnresolvedPropertyPrototypeReflection( + $property, + $resolvedClassReflection, + true, + $this, + ); } public function getPropertyWithoutTransformingStatic(string $propertyName, ClassMemberAccessAnswerer $scope): PropertyReflection @@ -252,9 +249,9 @@ public function getPropertyWithoutTransformingStatic(string $propertyName, Class } /** - * @return string[] - */ - public function getReferencedClasses(): array + * @return string[] + */ + public function getReferencedClasses(): array { return [$this->className]; } @@ -346,18 +343,14 @@ public function isSuperTypeOf(Type $type): TrinaryLogic return self::$superTypes[$thisDescription][$description] = TrinaryLogic::createMaybe(); } - $transformResult = static function (TrinaryLogic $result) { - return $result; - }; + $transformResult = static fn (TrinaryLogic $result) => $result; if ($this->subtractedType !== null) { $isSuperType = $this->subtractedType->isSuperTypeOf($type); if ($isSuperType->yes()) { return self::$superTypes[$thisDescription][$description] = TrinaryLogic::createNo(); } if ($isSuperType->maybe()) { - $transformResult = static function (TrinaryLogic $result) { - return $result->and(TrinaryLogic::createMaybe()); - }; + $transformResult = static fn (TrinaryLogic $result) => $result->and(TrinaryLogic::createMaybe()); } } @@ -462,10 +455,14 @@ private function checkSubclassAcceptability(string $thatClass): AcceptsResult } if ($thisReflection->isInterface() && $thatReflection->isInterface()) { - return AcceptsResult::createFromBoolean($thatReflection->implementsInterface($thisReflection->getName())); + return AcceptsResult::createFromBoolean( + $thatReflection->implementsInterface($thisReflection->getName()), + ); } - return AcceptsResult::createFromBoolean($thatReflection->isSubclassOf($thisReflection->getName())); + return AcceptsResult::createFromBoolean( + $thatReflection->isSubclassOf($thisReflection->getName()), + ); } public function describe(VerbosityLevel $level): string @@ -488,7 +485,11 @@ public function describe(VerbosityLevel $level): string return $description; }; - return $level->handle($preciseNameCallback, $preciseNameCallback, $preciseWithSubtracted, function () use ($preciseWithSubtracted): string { + return $level->handle( + $preciseNameCallback, + $preciseNameCallback, + $preciseWithSubtracted, + function () use ($preciseWithSubtracted): string { $reflection = $this->classReflection; $line = ''; if ($reflection !== null) { @@ -498,7 +499,8 @@ public function describe(VerbosityLevel $level): string } return $preciseWithSubtracted() . '-' . static::class . '-' . $line . $this->describeAdditionalCacheKey(); - }); + }, + ); } protected function describeAdditionalCacheKey(): string @@ -599,7 +601,11 @@ public function toArray(): Type if ( !$classReflection->getNativeReflection()->isUserDefined() - || UniversalObjectCratesClassReflectionExtension::isUniversalObjectCrate($reflectionProvider, Broker::getInstance()->getUniversalObjectCratesClasses(), $classReflection) + || UniversalObjectCratesClassReflectionExtension::isUniversalObjectCrate( + $reflectionProvider, + Broker::getInstance()->getUniversalObjectCratesClasses(), + $classReflection, + ) ) { return new ArrayType(new MixedType(), new MixedType()); } @@ -619,9 +625,16 @@ public function toArray(): Type $keyName = $nativeProperty->getName(); if ($nativeProperty->isPrivate()) { - $keyName = sprintf("\0%s\0%s", $declaringClass->getName(), $keyName); + $keyName = sprintf( + "\0%s\0%s", + $declaringClass->getName(), + $keyName, + ); } elseif ($nativeProperty->isProtected()) { - $keyName = sprintf("\0*\0%s", $keyName); + $keyName = sprintf( + "\0*\0%s", + $keyName, + ); } $arrayKeys[] = new ConstantStringType($keyName); @@ -743,7 +756,12 @@ public function getUnresolvedMethodPrototype(string $methodName, ClassMemberAcce $resolvedClassReflection = $method->getDeclaringClass(); } - return self::$methods[$description][$methodName][$canCallMethod] = new CalledOnTypeUnresolvedMethodPrototypeReflection($method, $resolvedClassReflection, true, $this); + return self::$methods[$description][$methodName][$canCallMethod] = new CalledOnTypeUnresolvedMethodPrototypeReflection( + $method, + $resolvedClassReflection, + true, + $this, + ); } public function canAccessConstants(): TrinaryLogic @@ -758,7 +776,9 @@ public function hasConstant(string $constantName): TrinaryLogic return TrinaryLogic::createNo(); } - return TrinaryLogic::createFromBoolean($class->hasConstant($constantName)); + return TrinaryLogic::createFromBoolean( + $class->hasConstant($constantName), + ); } public function getConstant(string $constantName): ConstantReflection @@ -835,9 +855,9 @@ public function getIterableKeyType(): Type { $isTraversable = false; if ($this->isInstanceOf(IteratorAggregate::class)->yes()) { - $keyType = RecursionGuard::run($this, function () : Type { - return ParametersAcceptorSelector::selectSingle($this->getMethod('getIterator', new OutOfClassScope())->getVariants())->getReturnType()->getIterableKeyType(); - }); + $keyType = RecursionGuard::run($this, fn (): Type => ParametersAcceptorSelector::selectSingle( + $this->getMethod('getIterator', new OutOfClassScope())->getVariants(), + )->getReturnType()->getIterableKeyType()); $isTraversable = true; if (!$keyType instanceof MixedType || $keyType->isExplicitMixed()) { return $keyType; @@ -856,9 +876,9 @@ public function getIterableKeyType(): Type } if ($this->isInstanceOf(Iterator::class)->yes()) { - return RecursionGuard::run($this, function () : Type { - return ParametersAcceptorSelector::selectSingle($this->getMethod('key', new OutOfClassScope())->getVariants())->getReturnType(); - }); + return RecursionGuard::run($this, fn (): Type => ParametersAcceptorSelector::selectSingle( + $this->getMethod('key', new OutOfClassScope())->getVariants(), + )->getReturnType()); } if ($extraOffsetAccessible) { @@ -886,9 +906,9 @@ public function getIterableValueType(): Type { $isTraversable = false; if ($this->isInstanceOf(IteratorAggregate::class)->yes()) { - $valueType = RecursionGuard::run($this, function () : Type { - return ParametersAcceptorSelector::selectSingle($this->getMethod('getIterator', new OutOfClassScope())->getVariants())->getReturnType()->getIterableValueType(); - }); + $valueType = RecursionGuard::run($this, fn (): Type => ParametersAcceptorSelector::selectSingle( + $this->getMethod('getIterator', new OutOfClassScope())->getVariants(), + )->getReturnType()->getIterableValueType()); $isTraversable = true; if (!$valueType instanceof MixedType || $valueType->isExplicitMixed()) { return $valueType; @@ -907,9 +927,9 @@ public function getIterableValueType(): Type } if ($this->isInstanceOf(Iterator::class)->yes()) { - return RecursionGuard::run($this, function () : Type { - return ParametersAcceptorSelector::selectSingle($this->getMethod('current', new OutOfClassScope())->getVariants())->getReturnType(); - }); + return RecursionGuard::run($this, fn (): Type => ParametersAcceptorSelector::selectSingle( + $this->getMethod('current', new OutOfClassScope())->getVariants(), + )->getReturnType()); } if ($extraOffsetAccessible) { @@ -1073,7 +1093,9 @@ private function isExtraOffsetAccessibleClass(): TrinaryLogic public function isOffsetAccessible(): TrinaryLogic { - return $this->isInstanceOf(ArrayAccess::class)->or($this->isExtraOffsetAccessibleClass()); + return $this->isInstanceOf(ArrayAccess::class)->or( + $this->isExtraOffsetAccessibleClass(), + ); } public function hasOffsetValueType(Type $offsetType): TrinaryLogic @@ -1082,7 +1104,11 @@ public function hasOffsetValueType(Type $offsetType): TrinaryLogic $acceptedOffsetType = RecursionGuard::run($this, function (): Type { $parameters = ParametersAcceptorSelector::selectSingle($this->getMethod('offsetSet', new OutOfClassScope())->getVariants())->getParameters(); if (count($parameters) < 2) { - throw new ShouldNotHappenException(sprintf('Method %s::%s() has less than 2 parameters.', $this->className, 'offsetSet')); + throw new ShouldNotHappenException(sprintf( + 'Method %s::%s() has less than 2 parameters.', + $this->className, + 'offsetSet', + )); } $offsetParameter = $parameters[0]; @@ -1108,9 +1134,7 @@ public function getOffsetValueType(Type $offsetType): Type } if ($this->isInstanceOf(ArrayAccess::class)->yes()) { - return RecursionGuard::run($this, function () : Type { - return ParametersAcceptorSelector::selectSingle($this->getMethod('offsetGet', new OutOfClassScope())->getVariants())->getReturnType(); - }); + return RecursionGuard::run($this, fn (): Type => ParametersAcceptorSelector::selectSingle($this->getMethod('offsetGet', new OutOfClassScope())->getVariants())->getReturnType()); } return new ErrorType(); @@ -1127,7 +1151,11 @@ public function setOffsetValueType(?Type $offsetType, Type $valueType, bool $uni $acceptedOffsetType = RecursionGuard::run($this, function () use (&$acceptedValueType): Type { $parameters = ParametersAcceptorSelector::selectSingle($this->getMethod('offsetSet', new OutOfClassScope())->getVariants())->getParameters(); if (count($parameters) < 2) { - throw new ShouldNotHappenException(sprintf('Method %s::%s() has less than 2 parameters.', $this->className, 'offsetSet')); + throw new ShouldNotHappenException(sprintf( + 'Method %s::%s() has less than 2 parameters.', + $this->className, + 'offsetSet', + )); } $offsetParameter = $parameters[0]; @@ -1208,9 +1236,9 @@ public function isCallable(): TrinaryLogic } /** - * @return ParametersAcceptor[] - */ - public function getCallableParametersAcceptors(ClassMemberAccessAnswerer $scope): array + * @return ParametersAcceptor[] + */ + public function getCallableParametersAcceptors(ClassMemberAccessAnswerer $scope): array { if ($this->className === Closure::class) { return [new TrivialParametersAcceptor()]; @@ -1224,9 +1252,9 @@ public function getCallableParametersAcceptors(ClassMemberAccessAnswerer $scope) } /** - * @return ParametersAcceptor[]|null - */ - private function findCallableParametersAcceptors(): ?array + * @return ParametersAcceptor[]|null + */ + private function findCallableParametersAcceptors(): ?array { $classReflection = $this->getClassReflection(); if ($classReflection === null) { @@ -1250,11 +1278,14 @@ public function isCloneable(): TrinaryLogic } /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): Type + * @param mixed[] $properties + */ + public static function __set_state(array $properties): Type { - return new self($properties['className'], $properties['subtractedType'] ?? null); + return new self( + $properties['className'], + $properties['subtractedType'] ?? null, + ); } public function isInstanceOf(string $className): TrinaryLogic @@ -1368,7 +1399,10 @@ public function traverse(callable $cb): Type $subtractedType = $this->subtractedType !== null ? $cb($this->subtractedType) : null; if ($subtractedType !== $this->subtractedType) { - return new self($this->className, $subtractedType); + return new self( + $this->className, + $subtractedType, + ); } return $this; @@ -1410,18 +1444,16 @@ public function getClassReflection(): ?ClassReflection $classReflection = $reflectionProvider->getClass($this->className); if ($classReflection->isGeneric()) { - return $classReflection->withTypes(array_values($classReflection->getTemplateTypeMap()->map(static function () : Type { - return new ErrorType(); - })->getTypes())); + return $classReflection->withTypes(array_values($classReflection->getTemplateTypeMap()->map(static fn (): Type => new ErrorType())->getTypes())); } return $classReflection; } /** - * @return self|null - */ - public function getAncestorWithClassName(string $className): ?TypeWithClassName + * @return self|null + */ + public function getAncestorWithClassName(string $className): ?TypeWithClassName { if ($this->className === $className) { return $this; @@ -1494,7 +1526,7 @@ private function getParent(): ?ObjectType } /** @return ObjectType[] */ - private function getInterfaces(): array + private function getInterfaces(): array { if ($this->cachedInterfaces !== null) { return $this->cachedInterfaces; @@ -1504,9 +1536,7 @@ private function getInterfaces(): array return $this->cachedInterfaces = []; } - return $this->cachedInterfaces = array_map(static function (ClassReflection $interfaceReflection) : self { - return self::createFromReflection($interfaceReflection); - }, $thisReflection->getInterfaces()); + return $this->cachedInterfaces = array_map(static fn (ClassReflection $interfaceReflection): self => self::createFromReflection($interfaceReflection), $thisReflection->getInterfaces()); } public function tryRemove(Type $typeToRemove): ?Type diff --git a/src/Type/ObjectWithoutClassType.php b/src/Type/ObjectWithoutClassType.php index 6fda1c6e960..51a3d07937d 100644 --- a/src/Type/ObjectWithoutClassType.php +++ b/src/Type/ObjectWithoutClassType.php @@ -20,17 +20,17 @@ class ObjectWithoutClassType implements SubtractableType use UndecidedComparisonTypeTrait; use NonGeneralizableTypeTrait; - /** - * @var ?Type - */ - private $subtractedType; + private ?Type $subtractedType; /** @api */ - public function __construct(?Type $subtractedType = null) + public function __construct( + ?Type $subtractedType = null, + ) { if ($subtractedType instanceof NeverType) { $subtractedType = null; } + $this->subtractedType = $subtractedType; } @@ -63,7 +63,9 @@ public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult return $type->isAcceptedWithReasonBy($this, $strictTypes); } - return AcceptsResult::createFromBoolean($type instanceof self || $type instanceof ObjectShapeType || $type->getObjectClassNames() !== []); + return AcceptsResult::createFromBoolean( + $type instanceof self || $type instanceof ObjectShapeType || $type->getObjectClassNames() !== [], + ); } public function isSuperTypeOf(Type $type): TrinaryLogic @@ -124,18 +126,18 @@ public function equals(Type $type): bool public function describe(VerbosityLevel $level): string { - return $level->handle(static function () : string { - return 'object'; - }, static function () : string { - return 'object'; - }, function () use ($level): string { + return $level->handle( + static fn (): string => 'object', + static fn (): string => 'object', + function () use ($level): string { $description = 'object'; if ($this->subtractedType !== null) { $description .= sprintf('~%s', $this->subtractedType->describe($level)); } return $description; - }); + }, + ); } public function getEnumCases(): array diff --git a/src/Type/OffsetAccessType.php b/src/Type/OffsetAccessType.php index ce66ddaf604..430d38332c9 100644 --- a/src/Type/OffsetAccessType.php +++ b/src/Type/OffsetAccessType.php @@ -14,26 +14,22 @@ final class OffsetAccessType implements CompoundType, LateResolvableType { - /** - * @var Type - */ - private $type; - /** - * @var Type - */ - private $offset; use LateResolvableTypeTrait; use NonGeneralizableTypeTrait; - public function __construct(Type $type, Type $offset) + public function __construct( + private Type $type, + private Type $offset, + ) { - $this->type = $type; - $this->offset = $offset; } public function getReferencedClasses(): array { - return array_merge($this->type->getReferencedClasses(), $this->offset->getReferencedClasses()); + return array_merge( + $this->type->getReferencedClasses(), + $this->offset->getReferencedClasses(), + ); } public function getObjectClassNames(): array @@ -48,7 +44,10 @@ public function getObjectClassReflections(): array public function getReferencedTemplateTypes(TemplateTypeVariance $positionVariance): array { - return array_merge($this->type->getReferencedTemplateTypes($positionVariance), $this->offset->getReferencedTemplateTypes($positionVariance)); + return array_merge( + $this->type->getReferencedTemplateTypes($positionVariance), + $this->offset->getReferencedTemplateTypes($positionVariance), + ); } public function equals(Type $type): bool @@ -109,7 +108,10 @@ public function traverseSimultaneously(Type $right, callable $cb): Type public function toPhpDocNode(): TypeNode { - return new OffsetAccessTypeNode($this->type->toPhpDocNode(), $this->offset->toPhpDocNode()); + return new OffsetAccessTypeNode( + $this->type->toPhpDocNode(), + $this->offset->toPhpDocNode(), + ); } /** @@ -117,7 +119,10 @@ public function toPhpDocNode(): TypeNode */ public static function __set_state(array $properties): Type { - return new self($properties['type'], $properties['offset']); + return new self( + $properties['type'], + $properties['offset'], + ); } } diff --git a/src/Type/OperatorTypeSpecifyingExtensionRegistry.php b/src/Type/OperatorTypeSpecifyingExtensionRegistry.php index 88a7a5673fc..654d7a1ea8e 100644 --- a/src/Type/OperatorTypeSpecifyingExtensionRegistry.php +++ b/src/Type/OperatorTypeSpecifyingExtensionRegistry.php @@ -11,34 +11,32 @@ class OperatorTypeSpecifyingExtensionRegistry { /** - * @var OperatorTypeSpecifyingExtension[] - */ - private $extensions; - /** - * @param OperatorTypeSpecifyingExtension[] $extensions - */ - public function __construct(?Broker $broker, array $extensions) - { - $this->extensions = $extensions; - if ($broker === null) { - return; - } - foreach ($extensions as $extension) { - if (!$extension instanceof BrokerAwareExtension) { - continue; - } - - $extension->setBroker($broker); - } + * @param OperatorTypeSpecifyingExtension[] $extensions + */ + public function __construct( + ?Broker $broker, + private array $extensions, + ) + { + if ($broker === null) { + return; + } + + foreach ($extensions as $extension) { + if (!$extension instanceof BrokerAwareExtension) { + continue; } - /** - * @return OperatorTypeSpecifyingExtension[] - */ - public function getOperatorTypeSpecifyingExtensions(string $operator, Type $leftType, Type $rightType): array + + $extension->setBroker($broker); + } + } + + /** + * @return OperatorTypeSpecifyingExtension[] + */ + public function getOperatorTypeSpecifyingExtensions(string $operator, Type $leftType, Type $rightType): array { - return array_values(array_filter($this->extensions, static function (OperatorTypeSpecifyingExtension $extension) use($operator, $leftType, $rightType) : bool { - return $extension->isOperatorSupported($operator, $leftType, $rightType); - })); + return array_values(array_filter($this->extensions, static fn (OperatorTypeSpecifyingExtension $extension): bool => $extension->isOperatorSupported($operator, $leftType, $rightType))); } } diff --git a/src/Type/Php/ArgumentBasedFunctionReturnTypeExtension.php b/src/Type/Php/ArgumentBasedFunctionReturnTypeExtension.php index e65e2c4d3a7..c4ab9e8b9c3 100644 --- a/src/Type/Php/ArgumentBasedFunctionReturnTypeExtension.php +++ b/src/Type/Php/ArgumentBasedFunctionReturnTypeExtension.php @@ -58,7 +58,10 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, $argumentValueType = $argumentValueType->getIterableValueType()->generalize(GeneralizePrecision::moreSpecific()); } - $array = new ArrayType($argumentKeyType, $argumentValueType); + $array = new ArrayType( + $argumentKeyType, + $argumentValueType, + ); if ($functionReflection->getName() === 'array_unique' && $argumentType->isIterableAtLeastOnce()->yes()) { $array = TypeCombinator::intersect($array, new NonEmptyArrayType()); } diff --git a/src/Type/Php/ArrayChunkFunctionReturnTypeExtension.php b/src/Type/Php/ArrayChunkFunctionReturnTypeExtension.php index 50244dec76c..1c8530ec3bb 100644 --- a/src/Type/Php/ArrayChunkFunctionReturnTypeExtension.php +++ b/src/Type/Php/ArrayChunkFunctionReturnTypeExtension.php @@ -23,15 +23,10 @@ final class ArrayChunkFunctionReturnTypeExtension implements DynamicFunctionReturnTypeExtension { - /** - * @var PhpVersion - */ - private $phpVersion; private const FINITE_TYPES_LIMIT = 5; - public function __construct(PhpVersion $phpVersion) + public function __construct(private PhpVersion $phpVersion) { - $this->phpVersion = $phpVersion; } public function isFunctionSupported(FunctionReflection $functionReflection): bool diff --git a/src/Type/Php/ArrayColumnFunctionReturnTypeExtension.php b/src/Type/Php/ArrayColumnFunctionReturnTypeExtension.php index 06d4840715d..a7edf8777c9 100644 --- a/src/Type/Php/ArrayColumnFunctionReturnTypeExtension.php +++ b/src/Type/Php/ArrayColumnFunctionReturnTypeExtension.php @@ -24,13 +24,8 @@ class ArrayColumnFunctionReturnTypeExtension implements DynamicFunctionReturnTypeExtension { - /** - * @var PhpVersion - */ - private $phpVersion; - public function __construct(PhpVersion $phpVersion) + public function __construct(private PhpVersion $phpVersion) { - $this->phpVersion = $phpVersion; } public function isFunctionSupported(FunctionReflection $functionReflection): bool diff --git a/src/Type/Php/ArrayCombineFunctionReturnTypeExtension.php b/src/Type/Php/ArrayCombineFunctionReturnTypeExtension.php index 51352d68b7a..62e1d8435b7 100644 --- a/src/Type/Php/ArrayCombineFunctionReturnTypeExtension.php +++ b/src/Type/Php/ArrayCombineFunctionReturnTypeExtension.php @@ -25,13 +25,8 @@ class ArrayCombineFunctionReturnTypeExtension implements DynamicFunctionReturnTypeExtension { - /** - * @var PhpVersion - */ - private $phpVersion; - public function __construct(PhpVersion $phpVersion) + public function __construct(private PhpVersion $phpVersion) { - $this->phpVersion = $phpVersion; } public function isFunctionSupported(FunctionReflection $functionReflection): bool @@ -67,7 +62,11 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, $keyTypes = $this->sanitizeConstantArrayKeyTypes($keyTypes); if ($keyTypes !== null) { - return new ConstantArrayType($keyTypes, $valueTypes, $keysParamType->getNextAutoIndexes()); + return new ConstantArrayType( + $keyTypes, + $valueTypes, + $keysParamType->getNextAutoIndexes(), + ); } } @@ -87,7 +86,10 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, $keyType = new MixedType(); } - $arrayType = new ArrayType($keyType, $valuesParamType->isArray()->yes() ? $valuesParamType->getIterableValueType() : new MixedType()); + $arrayType = new ArrayType( + $keyType, + $valuesParamType->isArray()->yes() ? $valuesParamType->getIterableValueType() : new MixedType(), + ); if ($keysParamType->isIterableAtLeastOnce()->yes() && $valuesParamType->isIterableAtLeastOnce()->yes()) { $arrayType = TypeCombinator::intersect($arrayType, new NonEmptyArrayType()); diff --git a/src/Type/Php/ArrayFillFunctionReturnTypeExtension.php b/src/Type/Php/ArrayFillFunctionReturnTypeExtension.php index 9052d3a3288..2e85f590998 100644 --- a/src/Type/Php/ArrayFillFunctionReturnTypeExtension.php +++ b/src/Type/Php/ArrayFillFunctionReturnTypeExtension.php @@ -23,15 +23,10 @@ class ArrayFillFunctionReturnTypeExtension implements DynamicFunctionReturnTypeExtension { - /** - * @var PhpVersion - */ - private $phpVersion; private const MAX_SIZE_USE_CONSTANT_ARRAY = 100; - public function __construct(PhpVersion $phpVersion) + public function __construct(private PhpVersion $phpVersion) { - $this->phpVersion = $phpVersion; } public function isFunctionSupported(FunctionReflection $functionReflection): bool @@ -67,7 +62,10 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, $arrayBuilder = ConstantArrayTypeBuilder::createEmpty(); $nextIndex = $startIndexType->getValue(); for ($i = 0; $i < $numberType->getValue(); $i++) { - $arrayBuilder->setOffsetValueType(new ConstantIntegerType($nextIndex), $valueType); + $arrayBuilder->setOffsetValueType( + new ConstantIntegerType($nextIndex), + $valueType, + ); if ($nextIndex < 0) { $nextIndex = 0; } else { diff --git a/src/Type/Php/ArrayFillKeysFunctionReturnTypeExtension.php b/src/Type/Php/ArrayFillKeysFunctionReturnTypeExtension.php index c51f31c6d09..785991b2c11 100644 --- a/src/Type/Php/ArrayFillKeysFunctionReturnTypeExtension.php +++ b/src/Type/Php/ArrayFillKeysFunctionReturnTypeExtension.php @@ -15,13 +15,8 @@ class ArrayFillKeysFunctionReturnTypeExtension implements DynamicFunctionReturnTypeExtension { - /** - * @var PhpVersion - */ - private $phpVersion; - public function __construct(PhpVersion $phpVersion) + public function __construct(private PhpVersion $phpVersion) { - $this->phpVersion = $phpVersion; } public function isFunctionSupported(FunctionReflection $functionReflection): bool diff --git a/src/Type/Php/ArrayFilterFunctionReturnTypeReturnTypeExtension.php b/src/Type/Php/ArrayFilterFunctionReturnTypeReturnTypeExtension.php index cf30fbe06d3..73d0f31e363 100644 --- a/src/Type/Php/ArrayFilterFunctionReturnTypeReturnTypeExtension.php +++ b/src/Type/Php/ArrayFilterFunctionReturnTypeReturnTypeExtension.php @@ -71,7 +71,9 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, } if ($callbackArg === null || ($callbackArg instanceof ConstFetch && strtolower($callbackArg->name->getParts()[0]) === 'null')) { - return TypeCombinator::union(...array_map([$this, 'removeFalsey'], $arrayArgType->getArrays())); + return TypeCombinator::union( + ...array_map([$this, 'removeFalsey'], $arrayArgType->getArrays()), + ); } if ($flagArg === null) { @@ -163,11 +165,7 @@ public function removeFalsey(Type $type): Type return new ArrayType($keyType, $valueType); } - /** - * @param Error|Variable|null $itemVar - * @param Error|Variable|null $keyVar - */ - private function filterByTruthyValue(Scope $scope, $itemVar, Type $arrayType, $keyVar, Expr $expr): Type + private function filterByTruthyValue(Scope $scope, Error|Variable|null $itemVar, Type $arrayType, Error|Variable|null $keyVar, Expr $expr): Type { if (!$scope instanceof MutatingScope) { throw new ShouldNotHappenException(); @@ -209,10 +207,8 @@ private function filterByTruthyValue(Scope $scope, $itemVar, Type $arrayType, $k /** * @return array{Type, Type, bool} - * @param Error|Variable|null $itemVar - * @param Error|Variable|null $keyVar */ - private function processKeyAndItemType(MutatingScope $scope, Type $keyType, Type $itemType, $itemVar, $keyVar, Expr $expr): array + private function processKeyAndItemType(MutatingScope $scope, Type $keyType, Type $itemType, Error|Variable|null $itemVar, Error|Variable|null $keyVar, Expr $expr): array { $itemVarName = null; if ($itemVar !== null) { diff --git a/src/Type/Php/ArrayFlipFunctionReturnTypeExtension.php b/src/Type/Php/ArrayFlipFunctionReturnTypeExtension.php index a820673cdc6..1beb76de40f 100644 --- a/src/Type/Php/ArrayFlipFunctionReturnTypeExtension.php +++ b/src/Type/Php/ArrayFlipFunctionReturnTypeExtension.php @@ -15,13 +15,8 @@ class ArrayFlipFunctionReturnTypeExtension implements DynamicFunctionReturnTypeExtension { - /** - * @var PhpVersion - */ - private $phpVersion; - public function __construct(PhpVersion $phpVersion) + public function __construct(private PhpVersion $phpVersion) { - $this->phpVersion = $phpVersion; } public function isFunctionSupported(FunctionReflection $functionReflection): bool diff --git a/src/Type/Php/ArrayIntersectKeyFunctionReturnTypeExtension.php b/src/Type/Php/ArrayIntersectKeyFunctionReturnTypeExtension.php index d6362606ed8..10335fa3e80 100644 --- a/src/Type/Php/ArrayIntersectKeyFunctionReturnTypeExtension.php +++ b/src/Type/Php/ArrayIntersectKeyFunctionReturnTypeExtension.php @@ -17,13 +17,8 @@ class ArrayIntersectKeyFunctionReturnTypeExtension implements DynamicFunctionReturnTypeExtension { - /** - * @var PhpVersion - */ - private $phpVersion; - public function __construct(PhpVersion $phpVersion) + public function __construct(private PhpVersion $phpVersion) { - $this->phpVersion = $phpVersion; } public function isFunctionSupported(FunctionReflection $functionReflection): bool diff --git a/src/Type/Php/ArrayKeyExistsFunctionTypeSpecifyingExtension.php b/src/Type/Php/ArrayKeyExistsFunctionTypeSpecifyingExtension.php index 3507f5acfce..d2d5ed8360d 100644 --- a/src/Type/Php/ArrayKeyExistsFunctionTypeSpecifyingExtension.php +++ b/src/Type/Php/ArrayKeyExistsFunctionTypeSpecifyingExtension.php @@ -26,23 +26,29 @@ class ArrayKeyExistsFunctionTypeSpecifyingExtension implements FunctionTypeSpecifyingExtension, TypeSpecifierAwareExtension { - /** - * @var TypeSpecifier - */ - private $typeSpecifier; + private TypeSpecifier $typeSpecifier; public function setTypeSpecifier(TypeSpecifier $typeSpecifier): void { $this->typeSpecifier = $typeSpecifier; } - public function isFunctionSupported(FunctionReflection $functionReflection, FuncCall $node, TypeSpecifierContext $context) : bool + public function isFunctionSupported( + FunctionReflection $functionReflection, + FuncCall $node, + TypeSpecifierContext $context, + ): bool { return in_array($functionReflection->getName(), ['array_key_exists', 'key_exists'], true) && !$context->null(); } - public function specifyTypes(FunctionReflection $functionReflection, FuncCall $node, Scope $scope, TypeSpecifierContext $context) : SpecifiedTypes + public function specifyTypes( + FunctionReflection $functionReflection, + FuncCall $node, + Scope $scope, + TypeSpecifierContext $context, + ): SpecifiedTypes { if (count($node->getArgs()) < 2) { return new SpecifiedTypes(); @@ -51,6 +57,7 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n $array = $node->getArgs()[1]->value; $keyType = $scope->getType($key); $arrayType = $scope->getType($array); + if (!$keyType instanceof ConstantIntegerType && !$keyType instanceof ConstantStringType && !$arrayType->isIterableAtLeastOnce()->no()) { @@ -62,21 +69,48 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n $arrayKeyType = TypeCombinator::union($arrayKeyType, $arrayKeyType->toString()); } - $specifiedTypes = $this->typeSpecifier->create($key, $arrayKeyType, $context, false, $scope); + $specifiedTypes = $this->typeSpecifier->create( + $key, + $arrayKeyType, + $context, + false, + $scope, + ); - $arrayDimFetch = new ArrayDimFetch($array, $key); + $arrayDimFetch = new ArrayDimFetch( + $array, + $key, + ); - return $specifiedTypes->unionWith($this->typeSpecifier->create($arrayDimFetch, $arrayType->getIterableValueType(), $context, false, $scope, new Identical($arrayDimFetch, new ConstFetch(new Name('__PHPSTAN_FAUX_CONSTANT'))))); + return $specifiedTypes->unionWith($this->typeSpecifier->create( + $arrayDimFetch, + $arrayType->getIterableValueType(), + $context, + false, + $scope, + new Identical($arrayDimFetch, new ConstFetch(new Name('__PHPSTAN_FAUX_CONSTANT'))), + )); } return new SpecifiedTypes(); } + if ($context->true()) { - $type = TypeCombinator::intersect(new ArrayType(new MixedType(), new MixedType()), new HasOffsetType($keyType)); + $type = TypeCombinator::intersect( + new ArrayType(new MixedType(), new MixedType()), + new HasOffsetType($keyType), + ); } else { $type = new HasOffsetType($keyType); } - return $this->typeSpecifier->create($array, $type, $context, false, $scope); + + return $this->typeSpecifier->create( + $array, + $type, + $context, + false, + $scope, + ); } } diff --git a/src/Type/Php/ArrayKeysFunctionDynamicReturnTypeExtension.php b/src/Type/Php/ArrayKeysFunctionDynamicReturnTypeExtension.php index 73e14f7da39..2139222a9af 100644 --- a/src/Type/Php/ArrayKeysFunctionDynamicReturnTypeExtension.php +++ b/src/Type/Php/ArrayKeysFunctionDynamicReturnTypeExtension.php @@ -16,13 +16,8 @@ class ArrayKeysFunctionDynamicReturnTypeExtension implements DynamicFunctionReturnTypeExtension { - /** - * @var PhpVersion - */ - private $phpVersion; - public function __construct(PhpVersion $phpVersion) + public function __construct(private PhpVersion $phpVersion) { - $this->phpVersion = $phpVersion; } public function isFunctionSupported(FunctionReflection $functionReflection): bool diff --git a/src/Type/Php/ArrayMapFunctionReturnTypeExtension.php b/src/Type/Php/ArrayMapFunctionReturnTypeExtension.php index f6393bfbca0..0e17d33c35d 100644 --- a/src/Type/Php/ArrayMapFunctionReturnTypeExtension.php +++ b/src/Type/Php/ArrayMapFunctionReturnTypeExtension.php @@ -46,7 +46,10 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, } elseif ($callableIsNull) { $arrayBuilder = ConstantArrayTypeBuilder::createEmpty(); foreach (array_slice($functionCall->getArgs(), 1) as $index => $arg) { - $arrayBuilder->setOffsetValueType(new ConstantIntegerType($index), $scope->getType($arg->value)->getIterableValueType()); + $arrayBuilder->setOffsetValueType( + new ConstantIntegerType($index), + $scope->getType($arg->value)->getIterableValueType(), + ); } $valueType = $arrayBuilder->getArray(); } else { @@ -65,7 +68,11 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, foreach ($constantArrays as $constantArray) { $returnedArrayBuilder = ConstantArrayTypeBuilder::createEmpty(); foreach ($constantArray->getKeyTypes() as $i => $keyType) { - $returnedArrayBuilder->setOffsetValueType($keyType, $valueType, $constantArray->isOptionalKey($i)); + $returnedArrayBuilder->setOffsetValueType( + $keyType, + $valueType, + $constantArray->isOptionalKey($i), + ); } $returnedArray = $returnedArrayBuilder->getArray(); if ($constantArray->isList()->yes()) { @@ -76,12 +83,21 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, $mappedArrayType = TypeCombinator::union(...$arrayTypes); } elseif ($arrayType->isArray()->yes()) { - $mappedArrayType = TypeCombinator::intersect(new ArrayType($arrayType->getIterableKeyType(), $valueType), ...TypeUtils::getAccessoryTypes($arrayType)); + $mappedArrayType = TypeCombinator::intersect(new ArrayType( + $arrayType->getIterableKeyType(), + $valueType, + ), ...TypeUtils::getAccessoryTypes($arrayType)); } else { - $mappedArrayType = new ArrayType(new MixedType(), $valueType); + $mappedArrayType = new ArrayType( + new MixedType(), + $valueType, + ); } } else { - $mappedArrayType = TypeCombinator::intersect(new ArrayType(new IntegerType(), $valueType), ...TypeUtils::getAccessoryTypes($arrayType)); + $mappedArrayType = TypeCombinator::intersect(new ArrayType( + new IntegerType(), + $valueType, + ), ...TypeUtils::getAccessoryTypes($arrayType)); } if ($arrayType->isIterableAtLeastOnce()->yes()) { diff --git a/src/Type/Php/ArrayMergeFunctionDynamicReturnTypeExtension.php b/src/Type/Php/ArrayMergeFunctionDynamicReturnTypeExtension.php index 2d7adf5a873..5bde2a454e0 100644 --- a/src/Type/Php/ArrayMergeFunctionDynamicReturnTypeExtension.php +++ b/src/Type/Php/ArrayMergeFunctionDynamicReturnTypeExtension.php @@ -87,7 +87,11 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, foreach ($keyTypes as $k => $keyType) { $isOptional = in_array($k, $optionalKeys, true); - $newArrayBuilder->setOffsetValueType($keyType instanceof ConstantIntegerType ? null : $keyType, $valueTypes[$k], $isOptional); + $newArrayBuilder->setOffsetValueType( + $keyType instanceof ConstantIntegerType ? null : $keyType, + $valueTypes[$k], + $isOptional, + ); } } @@ -119,7 +123,10 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, return new ConstantArrayType([], []); } - $arrayType = new ArrayType($keyType, TypeCombinator::union(...$valueTypes)); + $arrayType = new ArrayType( + $keyType, + TypeCombinator::union(...$valueTypes), + ); if ($nonEmpty) { $arrayType = TypeCombinator::intersect($arrayType, new NonEmptyArrayType()); diff --git a/src/Type/Php/ArrayPointerFunctionsDynamicReturnTypeExtension.php b/src/Type/Php/ArrayPointerFunctionsDynamicReturnTypeExtension.php index d1dfe37e848..cd12f678d17 100644 --- a/src/Type/Php/ArrayPointerFunctionsDynamicReturnTypeExtension.php +++ b/src/Type/Php/ArrayPointerFunctionsDynamicReturnTypeExtension.php @@ -16,7 +16,7 @@ class ArrayPointerFunctionsDynamicReturnTypeExtension implements DynamicFunction { /** @var string[] */ - private $functions = [ + private array $functions = [ 'reset', 'end', ]; @@ -26,22 +26,29 @@ public function isFunctionSupported(FunctionReflection $functionReflection): boo return in_array($functionReflection->getName(), $this->functions, true); } - public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope) : ?Type + public function getTypeFromFunctionCall( + FunctionReflection $functionReflection, + FuncCall $functionCall, + Scope $scope, + ): ?Type { if (count($functionCall->getArgs()) === 0) { return null; } + $argType = $scope->getType($functionCall->getArgs()[0]->value); $iterableAtLeastOnce = $argType->isIterableAtLeastOnce(); if ($iterableAtLeastOnce->no()) { return new ConstantBooleanType(false); } + $itemType = $functionReflection->getName() === 'reset' ? $argType->getFirstIterableValueType() : $argType->getLastIterableValueType(); if ($iterableAtLeastOnce->yes()) { return $itemType; } + return TypeCombinator::union($itemType, new ConstantBooleanType(false)); } diff --git a/src/Type/Php/ArrayReduceFunctionReturnTypeExtension.php b/src/Type/Php/ArrayReduceFunctionReturnTypeExtension.php index 22ea481709c..80bd5866ec4 100644 --- a/src/Type/Php/ArrayReduceFunctionReturnTypeExtension.php +++ b/src/Type/Php/ArrayReduceFunctionReturnTypeExtension.php @@ -32,7 +32,11 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, return null; } - $callbackReturnType = ParametersAcceptorSelector::selectFromArgs($scope, $functionCall->getArgs(), $callbackType->getCallableParametersAcceptors($scope))->getReturnType(); + $callbackReturnType = ParametersAcceptorSelector::selectFromArgs( + $scope, + $functionCall->getArgs(), + $callbackType->getCallableParametersAcceptors($scope), + )->getReturnType(); if (isset($functionCall->getArgs()[2])) { $initialType = $scope->getType($functionCall->getArgs()[2]->value); diff --git a/src/Type/Php/ArraySearchFunctionDynamicReturnTypeExtension.php b/src/Type/Php/ArraySearchFunctionDynamicReturnTypeExtension.php index 8e8d35bfb79..8560faf5a9b 100644 --- a/src/Type/Php/ArraySearchFunctionDynamicReturnTypeExtension.php +++ b/src/Type/Php/ArraySearchFunctionDynamicReturnTypeExtension.php @@ -17,13 +17,8 @@ final class ArraySearchFunctionDynamicReturnTypeExtension implements DynamicFunctionReturnTypeExtension { - /** - * @var PhpVersion - */ - private $phpVersion; - public function __construct(PhpVersion $phpVersion) + public function __construct(private PhpVersion $phpVersion) { - $this->phpVersion = $phpVersion; } public function isFunctionSupported(FunctionReflection $functionReflection): bool diff --git a/src/Type/Php/ArraySearchFunctionTypeSpecifyingExtension.php b/src/Type/Php/ArraySearchFunctionTypeSpecifyingExtension.php index 06f23c7a5a7..8571c82ed33 100644 --- a/src/Type/Php/ArraySearchFunctionTypeSpecifyingExtension.php +++ b/src/Type/Php/ArraySearchFunctionTypeSpecifyingExtension.php @@ -19,24 +19,37 @@ class ArraySearchFunctionTypeSpecifyingExtension implements FunctionTypeSpecifyingExtension, TypeSpecifierAwareExtension { - /** - * @var TypeSpecifier - */ - private $typeSpecifier; + private TypeSpecifier $typeSpecifier; - public function isFunctionSupported(FunctionReflection $functionReflection, FuncCall $node, TypeSpecifierContext $context) : bool + public function isFunctionSupported( + FunctionReflection $functionReflection, + FuncCall $node, + TypeSpecifierContext $context, + ): bool { return strtolower($functionReflection->getName()) === 'array_search' && $context->true(); } - public function specifyTypes(FunctionReflection $functionReflection, FuncCall $node, Scope $scope, TypeSpecifierContext $context) : SpecifiedTypes + public function specifyTypes( + FunctionReflection $functionReflection, + FuncCall $node, + Scope $scope, + TypeSpecifierContext $context, + ): SpecifiedTypes { $arrayArg = $node->getArgs()[1]->value ?? null; if ($arrayArg === null) { return new SpecifiedTypes(); } - return $this->typeSpecifier->create($arrayArg, TypeCombinator::intersect(new ArrayType(new MixedType(), new MixedType()), new NonEmptyArrayType()), $context, false, $scope); + + return $this->typeSpecifier->create( + $arrayArg, + TypeCombinator::intersect(new ArrayType(new MixedType(), new MixedType()), new NonEmptyArrayType()), + $context, + false, + $scope, + ); } public function setTypeSpecifier(TypeSpecifier $typeSpecifier): void diff --git a/src/Type/Php/ArraySpliceFunctionReturnTypeExtension.php b/src/Type/Php/ArraySpliceFunctionReturnTypeExtension.php index 1ea25aa2abe..45cff582a21 100644 --- a/src/Type/Php/ArraySpliceFunctionReturnTypeExtension.php +++ b/src/Type/Php/ArraySpliceFunctionReturnTypeExtension.php @@ -17,12 +17,18 @@ public function isFunctionSupported(FunctionReflection $functionReflection): boo return $functionReflection->getName() === 'array_splice'; } - public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope) : ?Type + public function getTypeFromFunctionCall( + FunctionReflection $functionReflection, + FuncCall $functionCall, + Scope $scope, + ): ?Type { if (!isset($functionCall->getArgs()[0])) { return null; } + $arrayArg = $scope->getType($functionCall->getArgs()[0]->value); + return new ArrayType($arrayArg->getIterableKeyType(), $arrayArg->getIterableValueType()); } diff --git a/src/Type/Php/ArrayValuesFunctionDynamicReturnTypeExtension.php b/src/Type/Php/ArrayValuesFunctionDynamicReturnTypeExtension.php index a2aea7821c1..4573e7d89dd 100644 --- a/src/Type/Php/ArrayValuesFunctionDynamicReturnTypeExtension.php +++ b/src/Type/Php/ArrayValuesFunctionDynamicReturnTypeExtension.php @@ -16,13 +16,8 @@ class ArrayValuesFunctionDynamicReturnTypeExtension implements DynamicFunctionReturnTypeExtension { - /** - * @var PhpVersion - */ - private $phpVersion; - public function __construct(PhpVersion $phpVersion) + public function __construct(private PhpVersion $phpVersion) { - $this->phpVersion = $phpVersion; } public function isFunctionSupported(FunctionReflection $functionReflection): bool diff --git a/src/Type/Php/AssertFunctionTypeSpecifyingExtension.php b/src/Type/Php/AssertFunctionTypeSpecifyingExtension.php index ec7c5a6ed66..413a1635355 100644 --- a/src/Type/Php/AssertFunctionTypeSpecifyingExtension.php +++ b/src/Type/Php/AssertFunctionTypeSpecifyingExtension.php @@ -14,10 +14,7 @@ class AssertFunctionTypeSpecifyingExtension implements FunctionTypeSpecifyingExtension, TypeSpecifierAwareExtension { - /** - * @var TypeSpecifier - */ - private $typeSpecifier; + private TypeSpecifier $typeSpecifier; public function isFunctionSupported(FunctionReflection $functionReflection, FuncCall $node, TypeSpecifierContext $context): bool { diff --git a/src/Type/Php/Base64DecodeDynamicFunctionReturnTypeExtension.php b/src/Type/Php/Base64DecodeDynamicFunctionReturnTypeExtension.php index 965a9200c83..bb1ef074309 100644 --- a/src/Type/Php/Base64DecodeDynamicFunctionReturnTypeExtension.php +++ b/src/Type/Php/Base64DecodeDynamicFunctionReturnTypeExtension.php @@ -21,15 +21,22 @@ public function isFunctionSupported(FunctionReflection $functionReflection): boo return $functionReflection->getName() === 'base64_decode'; } - public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope) : Type + public function getTypeFromFunctionCall( + FunctionReflection $functionReflection, + FuncCall $functionCall, + Scope $scope, + ): Type { if (!isset($functionCall->getArgs()[1])) { return new StringType(); } + $argType = $scope->getType($functionCall->getArgs()[1]->value); + if ($argType instanceof MixedType) { return new BenevolentUnionType([new StringType(), new ConstantBooleanType(false)]); } + $isTrueType = $argType->isTrue(); $isFalseType = $argType->isFalse(); $compareTypes = $isTrueType->compareTo($isFalseType); @@ -39,10 +46,12 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, if ($compareTypes === $isFalseType) { return new StringType(); } + // second argument could be interpreted as true if (!$isTrueType->no()) { return new UnionType([new StringType(), new ConstantBooleanType(false)]); } + return new StringType(); } diff --git a/src/Type/Php/BcMathStringOrNullReturnTypeExtension.php b/src/Type/Php/BcMathStringOrNullReturnTypeExtension.php index 507a0c25e66..c10cbe2e580 100644 --- a/src/Type/Php/BcMathStringOrNullReturnTypeExtension.php +++ b/src/Type/Php/BcMathStringOrNullReturnTypeExtension.php @@ -24,13 +24,8 @@ class BcMathStringOrNullReturnTypeExtension implements DynamicFunctionReturnTypeExtension { - /** - * @var PhpVersion - */ - private $phpVersion; - public function __construct(PhpVersion $phpVersion) + public function __construct(private PhpVersion $phpVersion) { - $this->phpVersion = $phpVersion; } public function isFunctionSupported(FunctionReflection $functionReflection): bool diff --git a/src/Type/Php/ClassExistsFunctionTypeSpecifyingExtension.php b/src/Type/Php/ClassExistsFunctionTypeSpecifyingExtension.php index 15307ecbcb0..9367e20b1b7 100644 --- a/src/Type/Php/ClassExistsFunctionTypeSpecifyingExtension.php +++ b/src/Type/Php/ClassExistsFunctionTypeSpecifyingExtension.php @@ -24,12 +24,13 @@ class ClassExistsFunctionTypeSpecifyingExtension implements FunctionTypeSpecifyingExtension, TypeSpecifierAwareExtension { - /** - * @var TypeSpecifier - */ - private $typeSpecifier; + private TypeSpecifier $typeSpecifier; - public function isFunctionSupported(FunctionReflection $functionReflection, FuncCall $node, TypeSpecifierContext $context) : bool + public function isFunctionSupported( + FunctionReflection $functionReflection, + FuncCall $node, + TypeSpecifierContext $context, + ): bool { return in_array($functionReflection->getName(), [ 'class_exists', @@ -43,9 +44,15 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n { $argType = $scope->getType($node->getArgs()[0]->value); if ($argType instanceof ConstantStringType) { - return $this->typeSpecifier->create(new FuncCall(new FullyQualified('class_exists'), [ + return $this->typeSpecifier->create( + new FuncCall(new FullyQualified('class_exists'), [ new Arg(new String_(ltrim($argType->getValue(), '\\'))), - ]), new ConstantBooleanType(true), $context, false, $scope); + ]), + new ConstantBooleanType(true), + $context, + false, + $scope, + ); } $narrowedType = new ClassStringType(); @@ -53,7 +60,13 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n $narrowedType = new GenericClassStringType(new ObjectType('UnitEnum')); } - return $this->typeSpecifier->create($node->getArgs()[0]->value, $narrowedType, $context, false, $scope); + return $this->typeSpecifier->create( + $node->getArgs()[0]->value, + $narrowedType, + $context, + false, + $scope, + ); } public function setTypeSpecifier(TypeSpecifier $typeSpecifier): void diff --git a/src/Type/Php/ClassImplementsFunctionReturnTypeExtension.php b/src/Type/Php/ClassImplementsFunctionReturnTypeExtension.php index 582135fbd49..754ac737c81 100644 --- a/src/Type/Php/ClassImplementsFunctionReturnTypeExtension.php +++ b/src/Type/Php/ClassImplementsFunctionReturnTypeExtension.php @@ -23,7 +23,11 @@ class ClassImplementsFunctionReturnTypeExtension implements DynamicFunctionRetur public function isFunctionSupported(FunctionReflection $functionReflection): bool { - return in_array($functionReflection->getName(), ['class_implements', 'class_uses', 'class_parents'], true); + return in_array( + $functionReflection->getName(), + ['class_implements', 'class_uses', 'class_parents'], + true, + ); } public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope): ?Type diff --git a/src/Type/Php/ClosureFromCallableDynamicReturnTypeExtension.php b/src/Type/Php/ClosureFromCallableDynamicReturnTypeExtension.php index bc2d1818dfc..ed2bd20acd3 100644 --- a/src/Type/Php/ClosureFromCallableDynamicReturnTypeExtension.php +++ b/src/Type/Php/ClosureFromCallableDynamicReturnTypeExtension.php @@ -41,7 +41,14 @@ public function getTypeFromStaticMethodCall(MethodReflection $methodReflection, $closureTypes = []; foreach ($callableType->getCallableParametersAcceptors($scope) as $variant) { $parameters = $variant->getParameters(); - $closureTypes[] = new ClosureType($parameters, $variant->getReturnType(), $variant->isVariadic(), $variant->getTemplateTypeMap(), $variant->getResolvedTemplateTypeMap(), $variant instanceof ParametersAcceptorWithPhpDocs ? $variant->getCallSiteVarianceMap() : TemplateTypeVarianceMap::createEmpty()); + $closureTypes[] = new ClosureType( + $parameters, + $variant->getReturnType(), + $variant->isVariadic(), + $variant->getTemplateTypeMap(), + $variant->getResolvedTemplateTypeMap(), + $variant instanceof ParametersAcceptorWithPhpDocs ? $variant->getCallSiteVarianceMap() : TemplateTypeVarianceMap::createEmpty(), + ); } return TypeCombinator::union(...$closureTypes); diff --git a/src/Type/Php/CompactFunctionReturnTypeExtension.php b/src/Type/Php/CompactFunctionReturnTypeExtension.php index 49f70e65b50..4c634ad0d15 100644 --- a/src/Type/Php/CompactFunctionReturnTypeExtension.php +++ b/src/Type/Php/CompactFunctionReturnTypeExtension.php @@ -16,13 +16,8 @@ class CompactFunctionReturnTypeExtension implements DynamicFunctionReturnTypeExtension { - /** - * @var bool - */ - private $checkMaybeUndefinedVariables; - public function __construct(bool $checkMaybeUndefinedVariables) + public function __construct(private bool $checkMaybeUndefinedVariables) { - $this->checkMaybeUndefinedVariables = $checkMaybeUndefinedVariables; } public function isFunctionSupported(FunctionReflection $functionReflection): bool @@ -30,14 +25,20 @@ public function isFunctionSupported(FunctionReflection $functionReflection): boo return $functionReflection->getName() === 'compact'; } - public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope) : ?Type + public function getTypeFromFunctionCall( + FunctionReflection $functionReflection, + FuncCall $functionCall, + Scope $scope, + ): ?Type { if (count($functionCall->getArgs()) === 0) { return null; } + if ($scope->canAnyVariableExist() && !$this->checkMaybeUndefinedVariables) { return null; } + $array = ConstantArrayTypeBuilder::createEmpty(); foreach ($functionCall->getArgs() as $arg) { $type = $scope->getType($arg->value); @@ -54,6 +55,7 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, $array->setOffsetValueType($constantString, $scope->getVariableType($constantString->getValue()), $has->maybe()); } } + return $array->getArray(); } diff --git a/src/Type/Php/ConstantFunctionReturnTypeExtension.php b/src/Type/Php/ConstantFunctionReturnTypeExtension.php index 07fee375c22..3c32b6c3609 100644 --- a/src/Type/Php/ConstantFunctionReturnTypeExtension.php +++ b/src/Type/Php/ConstantFunctionReturnTypeExtension.php @@ -13,13 +13,8 @@ class ConstantFunctionReturnTypeExtension implements DynamicFunctionReturnTypeExtension { - /** - * @var ConstantHelper - */ - private $constantHelper; - public function __construct(ConstantHelper $constantHelper) + public function __construct(private ConstantHelper $constantHelper) { - $this->constantHelper = $constantHelper; } public function isFunctionSupported(FunctionReflection $functionReflection): bool @@ -27,19 +22,27 @@ public function isFunctionSupported(FunctionReflection $functionReflection): boo return $functionReflection->getName() === 'constant'; } - public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope) : ?Type + public function getTypeFromFunctionCall( + FunctionReflection $functionReflection, + FuncCall $functionCall, + Scope $scope, + ): ?Type { if (count($functionCall->getArgs()) < 1) { return null; } + $nameType = $scope->getType($functionCall->getArgs()[0]->value); + $results = []; foreach ($nameType->getConstantStrings() as $constantName) { $results[] = $scope->getType($this->constantHelper->createExprFromConstantName($constantName->getValue())); } + if (count($results) > 0) { return TypeCombinator::union(...$results); } + return null; } diff --git a/src/Type/Php/CountFunctionReturnTypeExtension.php b/src/Type/Php/CountFunctionReturnTypeExtension.php index 8d8f8123b3f..d4c995f933e 100644 --- a/src/Type/Php/CountFunctionReturnTypeExtension.php +++ b/src/Type/Php/CountFunctionReturnTypeExtension.php @@ -20,17 +20,23 @@ public function isFunctionSupported(FunctionReflection $functionReflection): boo return in_array($functionReflection->getName(), ['sizeof', 'count'], true); } - public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope) : ?Type + public function getTypeFromFunctionCall( + FunctionReflection $functionReflection, + FuncCall $functionCall, + Scope $scope, + ): ?Type { if (count($functionCall->getArgs()) < 1) { return null; } + if (count($functionCall->getArgs()) > 1) { $mode = $scope->getType($functionCall->getArgs()[1]->value); if ($mode->isSuperTypeOf(new ConstantIntegerType(COUNT_RECURSIVE))->yes()) { return null; } } + return $scope->getType($functionCall->getArgs()[0]->value)->getArraySize(); } diff --git a/src/Type/Php/CountFunctionTypeSpecifyingExtension.php b/src/Type/Php/CountFunctionTypeSpecifyingExtension.php index 2844a87faa3..5940c2d8033 100644 --- a/src/Type/Php/CountFunctionTypeSpecifyingExtension.php +++ b/src/Type/Php/CountFunctionTypeSpecifyingExtension.php @@ -17,23 +17,30 @@ class CountFunctionTypeSpecifyingExtension implements FunctionTypeSpecifyingExtension, TypeSpecifierAwareExtension { - /** - * @var TypeSpecifier - */ - private $typeSpecifier; + private TypeSpecifier $typeSpecifier; - public function isFunctionSupported(FunctionReflection $functionReflection, FuncCall $node, TypeSpecifierContext $context) : bool + public function isFunctionSupported( + FunctionReflection $functionReflection, + FuncCall $node, + TypeSpecifierContext $context, + ): bool { return !$context->null() && count($node->getArgs()) >= 1 && in_array($functionReflection->getName(), ['sizeof', 'count'], true); } - public function specifyTypes(FunctionReflection $functionReflection, FuncCall $node, Scope $scope, TypeSpecifierContext $context) : SpecifiedTypes + public function specifyTypes( + FunctionReflection $functionReflection, + FuncCall $node, + Scope $scope, + TypeSpecifierContext $context, + ): SpecifiedTypes { if (!$scope->getType($node->getArgs()[0]->value)->isArray()->yes()) { return new SpecifiedTypes([], []); } + return $this->typeSpecifier->create($node->getArgs()[0]->value, new NonEmptyArrayType(), $context, false, $scope); } diff --git a/src/Type/Php/CtypeDigitFunctionTypeSpecifyingExtension.php b/src/Type/Php/CtypeDigitFunctionTypeSpecifyingExtension.php index 029ab035715..112ed30292f 100644 --- a/src/Type/Php/CtypeDigitFunctionTypeSpecifyingExtension.php +++ b/src/Type/Php/CtypeDigitFunctionTypeSpecifyingExtension.php @@ -24,10 +24,7 @@ class CtypeDigitFunctionTypeSpecifyingExtension implements FunctionTypeSpecifyingExtension, TypeSpecifierAwareExtension { - /** - * @var TypeSpecifier - */ - private $typeSpecifier; + private TypeSpecifier $typeSpecifier; public function isFunctionSupported(FunctionReflection $functionReflection, FuncCall $node, TypeSpecifierContext $context): bool { @@ -73,7 +70,9 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n ]), new ConstantBooleanType(true), ]); - $specifiedTypes = $specifiedTypes->unionWith($this->typeSpecifier->create($exprArg->expr, $castedType, $context, false, $scope)); + $specifiedTypes = $specifiedTypes->unionWith( + $this->typeSpecifier->create($exprArg->expr, $castedType, $context, false, $scope), + ); } return $specifiedTypes; diff --git a/src/Type/Php/CurlGetinfoFunctionDynamicReturnTypeExtension.php b/src/Type/Php/CurlGetinfoFunctionDynamicReturnTypeExtension.php index a6c6d80af1f..b5de9de5f1f 100644 --- a/src/Type/Php/CurlGetinfoFunctionDynamicReturnTypeExtension.php +++ b/src/Type/Php/CurlGetinfoFunctionDynamicReturnTypeExtension.php @@ -25,14 +25,12 @@ final class CurlGetinfoFunctionDynamicReturnTypeExtension implements DynamicFunctionReturnTypeExtension { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - public function __construct(ReflectionProvider $reflectionProvider) + public function __construct( + private ReflectionProvider $reflectionProvider, + ) { - $this->reflectionProvider = $reflectionProvider; } + public function isFunctionSupported(FunctionReflection $functionReflection): bool { return $functionReflection->getName() === 'curl_getinfo'; diff --git a/src/Type/Php/CurlInitReturnTypeExtension.php b/src/Type/Php/CurlInitReturnTypeExtension.php index 1660dceea1d..e9564278fee 100644 --- a/src/Type/Php/CurlInitReturnTypeExtension.php +++ b/src/Type/Php/CurlInitReturnTypeExtension.php @@ -20,13 +20,18 @@ public function isFunctionSupported(FunctionReflection $functionReflection): boo return $functionReflection->getName() === 'curl_init'; } - public function getTypeFromFunctionCall(FunctionReflection $functionReflection, Node\Expr\FuncCall $functionCall, Scope $scope) : Type + public function getTypeFromFunctionCall( + FunctionReflection $functionReflection, + Node\Expr\FuncCall $functionCall, + Scope $scope, + ): Type { $argsCount = count($functionCall->getArgs()); $returnType = ParametersAcceptorSelector::selectSingle($functionReflection->getVariants())->getReturnType(); if ($argsCount === 0) { return TypeCombinator::remove($returnType, new ConstantBooleanType(false)); } + return $returnType; } diff --git a/src/Type/Php/DateFormatFunctionReturnTypeExtension.php b/src/Type/Php/DateFormatFunctionReturnTypeExtension.php index fcd219d50a4..b926ed181d0 100644 --- a/src/Type/Php/DateFormatFunctionReturnTypeExtension.php +++ b/src/Type/Php/DateFormatFunctionReturnTypeExtension.php @@ -19,14 +19,21 @@ public function isFunctionSupported(FunctionReflection $functionReflection): boo return $functionReflection->getName() === 'date_format'; } - public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope) : Type + public function getTypeFromFunctionCall( + FunctionReflection $functionReflection, + FuncCall $functionCall, + Scope $scope, + ): Type { if (count($functionCall->getArgs()) < 2) { return new StringType(); } - return $scope->getType(new FuncCall(new FullyQualified('date'), [ + + return $scope->getType( + new FuncCall(new FullyQualified('date'), [ $functionCall->getArgs()[1], - ])); + ]), + ); } } diff --git a/src/Type/Php/DateFormatMethodReturnTypeExtension.php b/src/Type/Php/DateFormatMethodReturnTypeExtension.php index c6bd15a2e95..f6b71786bcc 100644 --- a/src/Type/Php/DateFormatMethodReturnTypeExtension.php +++ b/src/Type/Php/DateFormatMethodReturnTypeExtension.php @@ -32,9 +32,11 @@ public function getTypeFromMethodCall(MethodReflection $methodReflection, Method return new StringType(); } - return $scope->getType(new FuncCall(new FullyQualified('date'), [ + return $scope->getType( + new FuncCall(new FullyQualified('date'), [ $methodCall->getArgs()[0], - ])); + ]), + ); } } diff --git a/src/Type/Php/DateFunctionReturnTypeExtension.php b/src/Type/Php/DateFunctionReturnTypeExtension.php index 5aeceebdb32..2147fd1b80b 100644 --- a/src/Type/Php/DateFunctionReturnTypeExtension.php +++ b/src/Type/Php/DateFunctionReturnTypeExtension.php @@ -27,16 +27,22 @@ public function isFunctionSupported(FunctionReflection $functionReflection): boo return $functionReflection->getName() === 'date'; } - public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope) : Type + public function getTypeFromFunctionCall( + FunctionReflection $functionReflection, + FuncCall $functionCall, + Scope $scope, + ): Type { if (count($functionCall->getArgs()) === 0) { return new StringType(); } $argType = $scope->getType($functionCall->getArgs()[0]->value); $constantStrings = $argType->getConstantStrings(); + if (count($constantStrings) === 0) { return new StringType(); } + if (count($constantStrings) === 1) { $constantString = $constantStrings[0]->getValue(); @@ -70,10 +76,12 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, return $this->buildNumericRangeType(0, 1, false); } } + $types = []; foreach ($constantStrings as $constantString) { $types[] = new ConstantStringType(date($constantString->getValue())); } + $type = TypeCombinator::union(...$types); if ($type->isNumericString()->yes()) { return new IntersectionType([ @@ -81,21 +89,25 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, new AccessoryNumericStringType(), ]); } + if ($type->isNonFalsyString()->yes()) { return new IntersectionType([ new StringType(), new AccessoryNonFalsyStringType(), ]); } + if ($type->isNonEmptyString()->yes()) { return new IntersectionType([ new StringType(), new AccessoryNonEmptyStringType(), ]); } + if ($type->isNonEmptyString()->no()) { return new ConstantStringType(''); } + return new StringType(); } diff --git a/src/Type/Php/DateIntervalDynamicReturnTypeExtension.php b/src/Type/Php/DateIntervalDynamicReturnTypeExtension.php index 08be961eb01..1fdcbf49376 100644 --- a/src/Type/Php/DateIntervalDynamicReturnTypeExtension.php +++ b/src/Type/Php/DateIntervalDynamicReturnTypeExtension.php @@ -42,7 +42,7 @@ public function getTypeFromStaticMethodCall(MethodReflection $methodReflection, foreach ($strings as $string) { try { $result = @DateInterval::createFromDateString($string->getValue()); - } catch (Throwable $e) { + } catch (Throwable) { $possibleReturnTypes[] = false; continue; } diff --git a/src/Type/Php/DateTimeModifyReturnTypeExtension.php b/src/Type/Php/DateTimeModifyReturnTypeExtension.php index 2fe7598ba5f..17359ba45c3 100644 --- a/src/Type/Php/DateTimeModifyReturnTypeExtension.php +++ b/src/Type/Php/DateTimeModifyReturnTypeExtension.php @@ -52,7 +52,7 @@ public function getTypeFromMethodCall(MethodReflection $methodReflection, Method foreach ($constantStrings as $constantString) { try { $result = @(new DateTime())->modify($constantString->getValue()); - } catch (Throwable $e) { + } catch (Throwable) { $hasFalse = true; $valueType = TypeCombinator::remove($valueType, $constantString); continue; diff --git a/src/Type/Php/DefineConstantTypeSpecifyingExtension.php b/src/Type/Php/DefineConstantTypeSpecifyingExtension.php index 2e42ecefb17..5f996c55e1a 100644 --- a/src/Type/Php/DefineConstantTypeSpecifyingExtension.php +++ b/src/Type/Php/DefineConstantTypeSpecifyingExtension.php @@ -17,24 +17,30 @@ class DefineConstantTypeSpecifyingExtension implements FunctionTypeSpecifyingExtension, TypeSpecifierAwareExtension { - /** - * @var TypeSpecifier - */ - private $typeSpecifier; + private TypeSpecifier $typeSpecifier; public function setTypeSpecifier(TypeSpecifier $typeSpecifier): void { $this->typeSpecifier = $typeSpecifier; } - public function isFunctionSupported(FunctionReflection $functionReflection, FuncCall $node, TypeSpecifierContext $context) : bool + public function isFunctionSupported( + FunctionReflection $functionReflection, + FuncCall $node, + TypeSpecifierContext $context, + ): bool { return $functionReflection->getName() === 'define' && $context->null() && count($node->getArgs()) >= 2; } - public function specifyTypes(FunctionReflection $functionReflection, FuncCall $node, Scope $scope, TypeSpecifierContext $context) : SpecifiedTypes + public function specifyTypes( + FunctionReflection $functionReflection, + FuncCall $node, + Scope $scope, + TypeSpecifierContext $context, + ): SpecifiedTypes { $constantName = $scope->getType($node->getArgs()[0]->value); if ( @@ -43,7 +49,16 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n ) { return new SpecifiedTypes([], []); } - return $this->typeSpecifier->create(new Node\Expr\ConstFetch(new Node\Name\FullyQualified($constantName->getValue())), $scope->getType($node->getArgs()[1]->value), TypeSpecifierContext::createTruthy(), true, $scope); + + return $this->typeSpecifier->create( + new Node\Expr\ConstFetch( + new Node\Name\FullyQualified($constantName->getValue()), + ), + $scope->getType($node->getArgs()[1]->value), + TypeSpecifierContext::createTruthy(), + true, + $scope, + ); } } diff --git a/src/Type/Php/DefinedConstantTypeSpecifyingExtension.php b/src/Type/Php/DefinedConstantTypeSpecifyingExtension.php index 1ec9319acd3..43ab4c48dbd 100644 --- a/src/Type/Php/DefinedConstantTypeSpecifyingExtension.php +++ b/src/Type/Php/DefinedConstantTypeSpecifyingExtension.php @@ -17,18 +17,10 @@ class DefinedConstantTypeSpecifyingExtension implements FunctionTypeSpecifyingExtension, TypeSpecifierAwareExtension { - /** - * @var ConstantHelper - */ - private $constantHelper; - /** - * @var TypeSpecifier - */ - private $typeSpecifier; - - public function __construct(ConstantHelper $constantHelper) + private TypeSpecifier $typeSpecifier; + + public function __construct(private ConstantHelper $constantHelper) { - $this->constantHelper = $constantHelper; } public function setTypeSpecifier(TypeSpecifier $typeSpecifier): void @@ -36,14 +28,23 @@ public function setTypeSpecifier(TypeSpecifier $typeSpecifier): void $this->typeSpecifier = $typeSpecifier; } - public function isFunctionSupported(FunctionReflection $functionReflection, FuncCall $node, TypeSpecifierContext $context) : bool + public function isFunctionSupported( + FunctionReflection $functionReflection, + FuncCall $node, + TypeSpecifierContext $context, + ): bool { return $functionReflection->getName() === 'defined' && count($node->getArgs()) >= 1 && $context->true(); } - public function specifyTypes(FunctionReflection $functionReflection, FuncCall $node, Scope $scope, TypeSpecifierContext $context) : SpecifiedTypes + public function specifyTypes( + FunctionReflection $functionReflection, + FuncCall $node, + Scope $scope, + TypeSpecifierContext $context, + ): SpecifiedTypes { $constantName = $scope->getType($node->getArgs()[0]->value); if ( @@ -52,7 +53,14 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n ) { return new SpecifiedTypes([], []); } - return $this->typeSpecifier->create($this->constantHelper->createExprFromConstantName($constantName->getValue()), new MixedType(), $context, false, $scope); + + return $this->typeSpecifier->create( + $this->constantHelper->createExprFromConstantName($constantName->getValue()), + new MixedType(), + $context, + false, + $scope, + ); } } diff --git a/src/Type/Php/ExplodeFunctionDynamicReturnTypeExtension.php b/src/Type/Php/ExplodeFunctionDynamicReturnTypeExtension.php index 3158f72bfa2..498904c5282 100644 --- a/src/Type/Php/ExplodeFunctionDynamicReturnTypeExtension.php +++ b/src/Type/Php/ExplodeFunctionDynamicReturnTypeExtension.php @@ -26,13 +26,8 @@ class ExplodeFunctionDynamicReturnTypeExtension implements DynamicFunctionReturnTypeExtension { - /** - * @var PhpVersion - */ - private $phpVersion; - public function __construct(PhpVersion $phpVersion) + public function __construct(private PhpVersion $phpVersion) { - $this->phpVersion = $phpVersion; } public function isFunctionSupported(FunctionReflection $functionReflection): bool @@ -40,11 +35,16 @@ public function isFunctionSupported(FunctionReflection $functionReflection): boo return $functionReflection->getName() === 'explode'; } - public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope) : ?Type + public function getTypeFromFunctionCall( + FunctionReflection $functionReflection, + FuncCall $functionCall, + Scope $scope, + ): ?Type { if (count($functionCall->getArgs()) < 2) { return null; } + $delimiterType = $scope->getType($functionCall->getArgs()[0]->value); $isSuperset = (new ConstantStringType(''))->isSuperTypeOf($delimiterType); if ($isSuperset->yes()) { @@ -63,10 +63,12 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, return $arrayType; } + $returnType = ParametersAcceptorSelector::selectSingle($functionReflection->getVariants())->getReturnType(); if ($delimiterType instanceof MixedType) { return TypeUtils::toBenevolentUnion($returnType); } + return $returnType; } diff --git a/src/Type/Php/FilterFunctionReturnTypeHelper.php b/src/Type/Php/FilterFunctionReturnTypeHelper.php index acc73294b78..a2ed6c792bf 100644 --- a/src/Type/Php/FilterFunctionReturnTypeHelper.php +++ b/src/Type/Php/FilterFunctionReturnTypeHelper.php @@ -37,37 +37,21 @@ final class FilterFunctionReturnTypeHelper { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - /** - * @var PhpVersion - */ - private $phpVersion; /** All validation filters match 0x100. */ private const VALIDATION_FILTER_BITMASK = 0x100; - /** - * @var ConstantStringType - */ - private $flagsString; + private ConstantStringType $flagsString; /** @var array|null */ - private $filterTypeMap = null; + private ?array $filterTypeMap = null; /** @var array>|null */ - private $filterTypeOptions = null; + private ?array $filterTypeOptions = null; - /** - * @var ?Type - */ - private $supportedFilterInputTypes = null; + private ?Type $supportedFilterInputTypes = null; - public function __construct(ReflectionProvider $reflectionProvider, PhpVersion $phpVersion) + public function __construct(private ReflectionProvider $reflectionProvider, private PhpVersion $phpVersion) { - $this->reflectionProvider = $reflectionProvider; - $this->phpVersion = $phpVersion; $this->flagsString = new ConstantStringType('flags'); } @@ -91,7 +75,13 @@ public function getOffsetValueType(Type $inputType, Type $offsetType, ?Type $fil public function getInputType(Type $typeType, Type $varNameType, ?Type $filterType, ?Type $flagsType): Type { - $this->supportedFilterInputTypes = $this->supportedFilterInputTypes ?? TypeCombinator::union($this->reflectionProvider->getConstant(new Node\Name('INPUT_GET'), null)->getValueType(), $this->reflectionProvider->getConstant(new Node\Name('INPUT_POST'), null)->getValueType(), $this->reflectionProvider->getConstant(new Node\Name('INPUT_COOKIE'), null)->getValueType(), $this->reflectionProvider->getConstant(new Node\Name('INPUT_SERVER'), null)->getValueType(), $this->reflectionProvider->getConstant(new Node\Name('INPUT_ENV'), null)->getValueType()); + $this->supportedFilterInputTypes ??= TypeCombinator::union( + $this->reflectionProvider->getConstant(new Node\Name('INPUT_GET'), null)->getValueType(), + $this->reflectionProvider->getConstant(new Node\Name('INPUT_POST'), null)->getValueType(), + $this->reflectionProvider->getConstant(new Node\Name('INPUT_COOKIE'), null)->getValueType(), + $this->reflectionProvider->getConstant(new Node\Name('INPUT_SERVER'), null)->getValueType(), + $this->reflectionProvider->getConstant(new Node\Name('INPUT_ENV'), null)->getValueType(), + ); if (!$typeType->isInteger()->yes() || $this->supportedFilterInputTypes->isSuperTypeOf($typeType)->no()) { if ($this->phpVersion->throwsTypeErrorForInternalFunctions()) { diff --git a/src/Type/Php/FilterInputDynamicReturnTypeExtension.php b/src/Type/Php/FilterInputDynamicReturnTypeExtension.php index 26e92df082a..0dd934cd321 100644 --- a/src/Type/Php/FilterInputDynamicReturnTypeExtension.php +++ b/src/Type/Php/FilterInputDynamicReturnTypeExtension.php @@ -12,13 +12,8 @@ class FilterInputDynamicReturnTypeExtension implements DynamicFunctionReturnTypeExtension { - /** - * @var FilterFunctionReturnTypeHelper - */ - private $filterFunctionReturnTypeHelper; - public function __construct(FilterFunctionReturnTypeHelper $filterFunctionReturnTypeHelper) + public function __construct(private FilterFunctionReturnTypeHelper $filterFunctionReturnTypeHelper) { - $this->filterFunctionReturnTypeHelper = $filterFunctionReturnTypeHelper; } public function isFunctionSupported(FunctionReflection $functionReflection): bool @@ -32,7 +27,12 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, return null; } - return $this->filterFunctionReturnTypeHelper->getInputType($scope->getType($functionCall->getArgs()[0]->value), $scope->getType($functionCall->getArgs()[1]->value), isset($functionCall->getArgs()[2]) ? $scope->getType($functionCall->getArgs()[2]->value) : null, isset($functionCall->getArgs()[3]) ? $scope->getType($functionCall->getArgs()[3]->value) : null); + return $this->filterFunctionReturnTypeHelper->getInputType( + $scope->getType($functionCall->getArgs()[0]->value), + $scope->getType($functionCall->getArgs()[1]->value), + isset($functionCall->getArgs()[2]) ? $scope->getType($functionCall->getArgs()[2]->value) : null, + isset($functionCall->getArgs()[3]) ? $scope->getType($functionCall->getArgs()[3]->value) : null, + ); } } diff --git a/src/Type/Php/FilterVarArrayDynamicReturnTypeExtension.php b/src/Type/Php/FilterVarArrayDynamicReturnTypeExtension.php index 9668f4e325d..caaca73501f 100644 --- a/src/Type/Php/FilterVarArrayDynamicReturnTypeExtension.php +++ b/src/Type/Php/FilterVarArrayDynamicReturnTypeExtension.php @@ -29,18 +29,8 @@ class FilterVarArrayDynamicReturnTypeExtension implements DynamicFunctionReturnTypeExtension { - /** - * @var FilterFunctionReturnTypeHelper - */ - private $filterFunctionReturnTypeHelper; - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - public function __construct(FilterFunctionReturnTypeHelper $filterFunctionReturnTypeHelper, ReflectionProvider $reflectionProvider) + public function __construct(private FilterFunctionReturnTypeHelper $filterFunctionReturnTypeHelper, private ReflectionProvider $reflectionProvider) { - $this->filterFunctionReturnTypeHelper = $filterFunctionReturnTypeHelper; - $this->reflectionProvider = $reflectionProvider; } public function isFunctionSupported(FunctionReflection $functionReflection): bool @@ -64,7 +54,13 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, $inputConstantArrayType = $inputArgType->getConstantArrays()[0] ?? null; } elseif ($functionName === 'filter_input_array') { - $supportedTypes = TypeCombinator::union($this->reflectionProvider->getConstant(new Node\Name('INPUT_GET'), null)->getValueType(), $this->reflectionProvider->getConstant(new Node\Name('INPUT_POST'), null)->getValueType(), $this->reflectionProvider->getConstant(new Node\Name('INPUT_COOKIE'), null)->getValueType(), $this->reflectionProvider->getConstant(new Node\Name('INPUT_SERVER'), null)->getValueType(), $this->reflectionProvider->getConstant(new Node\Name('INPUT_ENV'), null)->getValueType()); + $supportedTypes = TypeCombinator::union( + $this->reflectionProvider->getConstant(new Node\Name('INPUT_GET'), null)->getValueType(), + $this->reflectionProvider->getConstant(new Node\Name('INPUT_POST'), null)->getValueType(), + $this->reflectionProvider->getConstant(new Node\Name('INPUT_COOKIE'), null)->getValueType(), + $this->reflectionProvider->getConstant(new Node\Name('INPUT_SERVER'), null)->getValueType(), + $this->reflectionProvider->getConstant(new Node\Name('INPUT_ENV'), null)->getValueType(), + ); if (!$inputArgType->isInteger()->yes() || $supportedTypes->isSuperTypeOf($inputArgType)->no()) { return null; @@ -85,7 +81,11 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, if ($filterArgType instanceof ConstantIntegerType) { if ($inputConstantArrayType === null) { $isList = $inputArgType->isList()->yes(); - $valueType = $this->filterFunctionReturnTypeHelper->getType($inputArgType->getIterableValueType(), $filterArgType, null); + $valueType = $this->filterFunctionReturnTypeHelper->getType( + $inputArgType->getIterableValueType(), + $filterArgType, + null, + ); $arrayType = new ArrayType($inputArgType->getIterableKeyType(), $valueType); return $isList ? AccessoryArrayListType::intersectWith($arrayType) : $arrayType; @@ -95,9 +95,7 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, $addEmpty = false; $keysType = $inputConstantArrayType; - $inputKeysList = array_map(static function ($type) { - return $type->getValue(); - }, $inputConstantArrayType->getKeyTypes()); + $inputKeysList = array_map(static fn ($type) => $type->getValue(), $inputConstantArrayType->getKeyTypes()); $filterTypesMap = array_fill_keys($inputKeysList, $filterArgType); $inputTypesMap = array_combine($inputKeysList, $inputConstantArrayType->getValueTypes()); $optionalKeys = []; @@ -113,7 +111,10 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, $isList = $inputArgType->isList()->yes(); $valueType = $this->filterFunctionReturnTypeHelper->getType($inputArgType, $filterArgType, null); - $arrayType = new ArrayType($inputArgType->getIterableKeyType(), $addEmpty ? TypeCombinator::addNull($valueType) : $valueType); + $arrayType = new ArrayType( + $inputArgType->getIterableKeyType(), + $addEmpty ? TypeCombinator::addNull($valueType) : $valueType, + ); return $isList ? AccessoryArrayListType::intersectWith($arrayType) : $arrayType; } @@ -122,15 +123,11 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, } else { $keysType = $filterConstantArrayType; $filterKeyTypes = $filterConstantArrayType->getKeyTypes(); - $filterKeysList = array_map(static function ($type) { - return $type->getValue(); - }, $filterKeyTypes); + $filterKeysList = array_map(static fn ($type) => $type->getValue(), $filterKeyTypes); $filterTypesMap = array_combine($filterKeysList, $keysType->getValueTypes()); if ($inputConstantArrayType !== null) { - $inputKeysList = array_map(static function ($type) { - return $type->getValue(); - }, $inputConstantArrayType->getKeyTypes()); + $inputKeysList = array_map(static fn ($type) => $type->getValue(), $inputConstantArrayType->getKeyTypes()); $inputTypesMap = array_combine($inputKeysList, $inputConstantArrayType->getValueTypes()); $optionalKeys = []; diff --git a/src/Type/Php/FilterVarDynamicReturnTypeExtension.php b/src/Type/Php/FilterVarDynamicReturnTypeExtension.php index a81fdc1d822..438d6440e97 100644 --- a/src/Type/Php/FilterVarDynamicReturnTypeExtension.php +++ b/src/Type/Php/FilterVarDynamicReturnTypeExtension.php @@ -13,13 +13,8 @@ class FilterVarDynamicReturnTypeExtension implements DynamicFunctionReturnTypeExtension { - /** - * @var FilterFunctionReturnTypeHelper - */ - private $filterFunctionReturnTypeHelper; - public function __construct(FilterFunctionReturnTypeHelper $filterFunctionReturnTypeHelper) + public function __construct(private FilterFunctionReturnTypeHelper $filterFunctionReturnTypeHelper) { - $this->filterFunctionReturnTypeHelper = $filterFunctionReturnTypeHelper; } public function isFunctionSupported(FunctionReflection $functionReflection): bool diff --git a/src/Type/Php/FunctionExistsFunctionTypeSpecifyingExtension.php b/src/Type/Php/FunctionExistsFunctionTypeSpecifyingExtension.php index 333b24212aa..de7e8dfe408 100644 --- a/src/Type/Php/FunctionExistsFunctionTypeSpecifyingExtension.php +++ b/src/Type/Php/FunctionExistsFunctionTypeSpecifyingExtension.php @@ -21,12 +21,13 @@ class FunctionExistsFunctionTypeSpecifyingExtension implements FunctionTypeSpecifyingExtension, TypeSpecifierAwareExtension { - /** - * @var TypeSpecifier - */ - private $typeSpecifier; + private TypeSpecifier $typeSpecifier; - public function isFunctionSupported(FunctionReflection $functionReflection, FuncCall $node, TypeSpecifierContext $context) : bool + public function isFunctionSupported( + FunctionReflection $functionReflection, + FuncCall $node, + TypeSpecifierContext $context, + ): bool { return $functionReflection->getName() === 'function_exists' && isset($node->getArgs()[0]) && $context->true(); } @@ -35,12 +36,24 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n { $argType = $scope->getType($node->getArgs()[0]->value); if ($argType instanceof ConstantStringType) { - return $this->typeSpecifier->create(new FuncCall(new FullyQualified('function_exists'), [ + return $this->typeSpecifier->create( + new FuncCall(new FullyQualified('function_exists'), [ new Arg(new String_(ltrim($argType->getValue(), '\\'))), - ]), new ConstantBooleanType(true), $context, false, $scope); + ]), + new ConstantBooleanType(true), + $context, + false, + $scope, + ); } - return $this->typeSpecifier->create($node->getArgs()[0]->value, new CallableType(), $context, false, $scope); + return $this->typeSpecifier->create( + $node->getArgs()[0]->value, + new CallableType(), + $context, + false, + $scope, + ); } public function setTypeSpecifier(TypeSpecifier $typeSpecifier): void diff --git a/src/Type/Php/GetClassDynamicReturnTypeExtension.php b/src/Type/Php/GetClassDynamicReturnTypeExtension.php index e0ce54d8333..a6c2fdfdb59 100644 --- a/src/Type/Php/GetClassDynamicReturnTypeExtension.php +++ b/src/Type/Php/GetClassDynamicReturnTypeExtension.php @@ -53,7 +53,9 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, return new ClassStringType(); } - return TypeTraverser::map($argType, static function (Type $type, callable $traverse): Type { + return TypeTraverser::map( + $argType, + static function (Type $type, callable $traverse): Type { if ($type instanceof UnionType || $type instanceof IntersectionType) { return $traverse($type); } @@ -86,7 +88,8 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, } return new ConstantBooleanType(false); - }); + }, + ); } } diff --git a/src/Type/Php/GetParentClassDynamicFunctionReturnTypeExtension.php b/src/Type/Php/GetParentClassDynamicFunctionReturnTypeExtension.php index 177eeedc52c..3dc2dbba5be 100644 --- a/src/Type/Php/GetParentClassDynamicFunctionReturnTypeExtension.php +++ b/src/Type/Php/GetParentClassDynamicFunctionReturnTypeExtension.php @@ -21,51 +21,54 @@ class GetParentClassDynamicFunctionReturnTypeExtension implements DynamicFunctionReturnTypeExtension { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - public function __construct(ReflectionProvider $reflectionProvider) - { - $this->reflectionProvider = $reflectionProvider; + public function __construct(private ReflectionProvider $reflectionProvider) + { + } + + public function isFunctionSupported( + FunctionReflection $functionReflection, + ): bool + { + return $functionReflection->getName() === 'get_parent_class'; + } + + public function getTypeFromFunctionCall( + FunctionReflection $functionReflection, + FuncCall $functionCall, + Scope $scope, + ): ?Type + { + if (count($functionCall->getArgs()) === 0) { + if ($scope->isInTrait()) { + return null; + } + if ($scope->isInClass()) { + return $this->findParentClassType( + $scope->getClassReflection(), + ); + } + + return new ConstantBooleanType(false); } - public function isFunctionSupported(FunctionReflection $functionReflection) : bool - { - return $functionReflection->getName() === 'get_parent_class'; + $argType = $scope->getType($functionCall->getArgs()[0]->value); + if ($scope->isInTrait() && TypeUtils::findThisType($argType) !== null) { + return null; } - public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope) : ?Type - { - if (count($functionCall->getArgs()) === 0) { - if ($scope->isInTrait()) { - return null; - } - if ($scope->isInClass()) { - return $this->findParentClassType($scope->getClassReflection()); - } - - return new ConstantBooleanType(false); - } - $argType = $scope->getType($functionCall->getArgs()[0]->value); - if ($scope->isInTrait() && TypeUtils::findThisType($argType) !== null) { - return null; - } - $constantStrings = $argType->getConstantStrings(); - if (count($constantStrings) > 0) { - return TypeCombinator::union(...array_map(function (ConstantStringType $stringType) : Type { - return $this->findParentClassNameType($stringType->getValue()); - }, $constantStrings)); - } - $classNames = $argType->getObjectClassNames(); - if (count($classNames) > 0) { - return TypeCombinator::union(...array_map(function (string $classNames) : Type { - return $this->findParentClassNameType($classNames); - }, $classNames)); - } - return null; + $constantStrings = $argType->getConstantStrings(); + if (count($constantStrings) > 0) { + return TypeCombinator::union(...array_map(fn (ConstantStringType $stringType): Type => $this->findParentClassNameType($stringType->getValue()), $constantStrings)); } + $classNames = $argType->getObjectClassNames(); + if (count($classNames) > 0) { + return TypeCombinator::union(...array_map(fn (string $classNames): Type => $this->findParentClassNameType($classNames), $classNames)); + } + + return null; + } + private function findParentClassNameType(string $className): Type { if (!$this->reflectionProvider->hasClass($className)) { @@ -86,13 +89,16 @@ private function findParentClassNameType(string $className): Type return $this->findParentClassType($classReflection); } - private function findParentClassType(ClassReflection $classReflection) : Type - { - $parentClass = $classReflection->getParentClass(); - if ($parentClass === null) { - return new ConstantBooleanType(false); - } - return new ConstantStringType($parentClass->getName(), true); + private function findParentClassType( + ClassReflection $classReflection, + ): Type + { + $parentClass = $classReflection->getParentClass(); + if ($parentClass === null) { + return new ConstantBooleanType(false); } + return new ConstantStringType($parentClass->getName(), true); + } + } diff --git a/src/Type/Php/GettypeFunctionReturnTypeExtension.php b/src/Type/Php/GettypeFunctionReturnTypeExtension.php index 3e927fa5cff..566faa3243b 100644 --- a/src/Type/Php/GettypeFunctionReturnTypeExtension.php +++ b/src/Type/Php/GettypeFunctionReturnTypeExtension.php @@ -72,7 +72,18 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, return new ConstantStringType('object'); } - return TypeCombinator::union(new ConstantStringType('string'), new ConstantStringType('array'), new ConstantStringType('boolean'), new ConstantStringType('resource'), new ConstantStringType('resource (closed)'), new ConstantStringType('integer'), new ConstantStringType('double'), new ConstantStringType('NULL'), new ConstantStringType('object'), new ConstantStringType('unknown type')); + return TypeCombinator::union( + new ConstantStringType('string'), + new ConstantStringType('array'), + new ConstantStringType('boolean'), + new ConstantStringType('resource'), + new ConstantStringType('resource (closed)'), + new ConstantStringType('integer'), + new ConstantStringType('double'), + new ConstantStringType('NULL'), + new ConstantStringType('object'), + new ConstantStringType('unknown type'), + ); }); } diff --git a/src/Type/Php/HashFunctionsReturnTypeExtension.php b/src/Type/Php/HashFunctionsReturnTypeExtension.php index 3c4465be574..72b26d3dd50 100644 --- a/src/Type/Php/HashFunctionsReturnTypeExtension.php +++ b/src/Type/Php/HashFunctionsReturnTypeExtension.php @@ -26,10 +26,6 @@ final class HashFunctionsReturnTypeExtension implements DynamicFunctionReturnTypeExtension { - /** - * @var PhpVersion - */ - private $phpVersion; private const SUPPORTED_FUNCTIONS = [ 'hash' => [ 'cryptographic' => false, @@ -77,11 +73,10 @@ final class HashFunctionsReturnTypeExtension implements DynamicFunctionReturnTyp ]; /** @var array */ - private $hashAlgorithms; + private array $hashAlgorithms; - public function __construct(PhpVersion $phpVersion) + public function __construct(private PhpVersion $phpVersion) { - $this->phpVersion = $phpVersion; $this->hashAlgorithms = hash_algos(); } @@ -120,7 +115,8 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, $invalidAlgorithmType = $this->phpVersion->throwsValueErrorForInternalFunctions() ? $neverType : $falseType; $functionData = self::SUPPORTED_FUNCTIONS[strtolower($functionReflection->getName())]; - $returnTypes = array_map(function (ConstantStringType $type) use ($functionData, $nonEmptyString, $invalidAlgorithmType) { + $returnTypes = array_map( + function (ConstantStringType $type) use ($functionData, $nonEmptyString, $invalidAlgorithmType) { $algorithm = strtolower($type->getValue()); if (!in_array($algorithm, $this->hashAlgorithms, true)) { return $invalidAlgorithmType; @@ -129,7 +125,9 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, return $invalidAlgorithmType; } return $nonEmptyString; - }, $constantAlgorithmTypes); + }, + $constantAlgorithmTypes, + ); $returnType = TypeCombinator::union(...$returnTypes); diff --git a/src/Type/Php/ImplodeFunctionReturnTypeExtension.php b/src/Type/Php/ImplodeFunctionReturnTypeExtension.php index d8632187065..0daed61c52e 100644 --- a/src/Type/Php/ImplodeFunctionReturnTypeExtension.php +++ b/src/Type/Php/ImplodeFunctionReturnTypeExtension.php @@ -31,7 +31,11 @@ public function isFunctionSupported(FunctionReflection $functionReflection): boo ], true); } - public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope) : Type + public function getTypeFromFunctionCall( + FunctionReflection $functionReflection, + FuncCall $functionCall, + Scope $scope, + ): Type { $args = $functionCall->getArgs(); if (count($args) === 1) { @@ -40,11 +44,14 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, return $this->implode($argType, new ConstantStringType('')); } } + if (count($args) !== 2) { return new StringType(); } + $separatorType = $scope->getType($args[0]->value); $arrayType = $scope->getType($args[1]->value); + return $this->implode($arrayType, $separatorType); } diff --git a/src/Type/Php/InArrayFunctionTypeSpecifyingExtension.php b/src/Type/Php/InArrayFunctionTypeSpecifyingExtension.php index 85b219f5db6..b23663a9948 100644 --- a/src/Type/Php/InArrayFunctionTypeSpecifyingExtension.php +++ b/src/Type/Php/InArrayFunctionTypeSpecifyingExtension.php @@ -24,10 +24,7 @@ class InArrayFunctionTypeSpecifyingExtension implements FunctionTypeSpecifyingExtension, TypeSpecifierAwareExtension { - /** - * @var TypeSpecifier - */ - private $typeSpecifier; + private TypeSpecifier $typeSpecifier; public function setTypeSpecifier(TypeSpecifier $typeSpecifier): void { @@ -104,9 +101,21 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n ) ) ) { - $specifiedTypes = $this->typeSpecifier->create($needleExpr, $arrayValueType, $context, false, $scope); + $specifiedTypes = $this->typeSpecifier->create( + $needleExpr, + $arrayValueType, + $context, + false, + $scope, + ); if ($needleExpr instanceof AlwaysRememberedExpr) { - $specifiedTypes = $specifiedTypes->unionWith($this->typeSpecifier->create($needleExpr->getExpr(), $arrayValueType, $context, false, $scope)); + $specifiedTypes = $specifiedTypes->unionWith($this->typeSpecifier->create( + $needleExpr->getExpr(), + $arrayValueType, + $context, + false, + $scope, + )); } } @@ -126,11 +135,23 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n $arrayValueType = TypeCombinator::remove($arrayValueType, $needleType); } - $specifiedTypes = $specifiedTypes->unionWith($this->typeSpecifier->create($node->getArgs()[1]->value, new ArrayType(new MixedType(), $arrayValueType), TypeSpecifierContext::createTrue(), false, $scope)); + $specifiedTypes = $specifiedTypes->unionWith($this->typeSpecifier->create( + $node->getArgs()[1]->value, + new ArrayType(new MixedType(), $arrayValueType), + TypeSpecifierContext::createTrue(), + false, + $scope, + )); } if ($context->true() && $arrayType->isArray()->yes()) { - $specifiedTypes = $specifiedTypes->unionWith($this->typeSpecifier->create($node->getArgs()[1]->value, TypeCombinator::intersect($arrayType, new NonEmptyArrayType()), $context, false, $scope)); + $specifiedTypes = $specifiedTypes->unionWith($this->typeSpecifier->create( + $node->getArgs()[1]->value, + TypeCombinator::intersect($arrayType, new NonEmptyArrayType()), + $context, + false, + $scope, + )); } return $specifiedTypes; diff --git a/src/Type/Php/IniGetReturnTypeExtension.php b/src/Type/Php/IniGetReturnTypeExtension.php index 6d0eaebfa0a..4e4de99bc4e 100644 --- a/src/Type/Php/IniGetReturnTypeExtension.php +++ b/src/Type/Php/IniGetReturnTypeExtension.php @@ -21,13 +21,21 @@ public function isFunctionSupported(FunctionReflection $functionReflection): boo return $functionReflection->getName() === 'ini_get'; } - public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope) : ?Type + public function getTypeFromFunctionCall( + FunctionReflection $functionReflection, + FuncCall $functionCall, + Scope $scope, + ): ?Type { $args = $functionCall->getArgs(); if (count($args) < 1) { return null; } - $numericString = TypeCombinator::intersect(new StringType(), new AccessoryNumericStringType()); + + $numericString = TypeCombinator::intersect( + new StringType(), + new AccessoryNumericStringType(), + ); $types = [ 'date.timezone' => new StringType(), 'memory_limit' => new StringType(), @@ -36,6 +44,7 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, 'default_socket_timeout' => $numericString, 'precision' => $numericString, ]; + $argType = $scope->getType($args[0]->value); $results = []; foreach ($argType->getConstantStrings() as $constantString) { @@ -44,9 +53,11 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, } $results[] = $types[$constantString->getValue()]; } + if (count($results) > 0) { return TypeCombinator::union(...$results); } + return null; } diff --git a/src/Type/Php/IsAFunctionTypeSpecifyingExtension.php b/src/Type/Php/IsAFunctionTypeSpecifyingExtension.php index 633f91e1dce..0eb26199df8 100644 --- a/src/Type/Php/IsAFunctionTypeSpecifyingExtension.php +++ b/src/Type/Php/IsAFunctionTypeSpecifyingExtension.php @@ -18,18 +18,12 @@ class IsAFunctionTypeSpecifyingExtension implements FunctionTypeSpecifyingExtension, TypeSpecifierAwareExtension { - /** - * @var IsAFunctionTypeSpecifyingHelper - */ - private $isAFunctionTypeSpecifyingHelper; - /** - * @var TypeSpecifier - */ - private $typeSpecifier; + private TypeSpecifier $typeSpecifier; - public function __construct(IsAFunctionTypeSpecifyingHelper $isAFunctionTypeSpecifyingHelper) + public function __construct( + private IsAFunctionTypeSpecifyingHelper $isAFunctionTypeSpecifyingHelper, + ) { - $this->isAFunctionTypeSpecifyingHelper = $isAFunctionTypeSpecifyingHelper; } public function isFunctionSupported(FunctionReflection $functionReflection, FuncCall $node, TypeSpecifierContext $context): bool @@ -53,7 +47,13 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n $allowStringType = isset($node->getArgs()[2]) ? $scope->getType($node->getArgs()[2]->value) : new ConstantBooleanType(false); $allowString = !$allowStringType->equals(new ConstantBooleanType(false)); - return $this->typeSpecifier->create($node->getArgs()[0]->value, $this->isAFunctionTypeSpecifyingHelper->determineType($objectOrClassType, $classType, $allowString, true), $context, false, $scope); + return $this->typeSpecifier->create( + $node->getArgs()[0]->value, + $this->isAFunctionTypeSpecifyingHelper->determineType($objectOrClassType, $classType, $allowString, true), + $context, + false, + $scope, + ); } public function setTypeSpecifier(TypeSpecifier $typeSpecifier): void diff --git a/src/Type/Php/IsAFunctionTypeSpecifyingHelper.php b/src/Type/Php/IsAFunctionTypeSpecifyingHelper.php index 442dc50edf5..d1f4a1bd82f 100644 --- a/src/Type/Php/IsAFunctionTypeSpecifyingHelper.php +++ b/src/Type/Php/IsAFunctionTypeSpecifyingHelper.php @@ -19,7 +19,12 @@ final class IsAFunctionTypeSpecifyingHelper { - public function determineType(Type $objectOrClassType, Type $classType, bool $allowString, bool $allowSameClass) : Type + public function determineType( + Type $objectOrClassType, + Type $classType, + bool $allowString, + bool $allowSameClass, + ): Type { $objectOrClassTypeClassNames = $objectOrClassType->getObjectClassNames(); if ($allowString) { @@ -28,7 +33,10 @@ public function determineType(Type $objectOrClassType, Type $classType, bool $al } $objectOrClassTypeClassNames = array_values(array_unique($objectOrClassTypeClassNames)); } - return TypeTraverser::map($classType, static function (Type $type, callable $traverse) use ($objectOrClassTypeClassNames, $allowString, $allowSameClass): Type { + + return TypeTraverser::map( + $classType, + static function (Type $type, callable $traverse) use ($objectOrClassTypeClassNames, $allowString, $allowSameClass): Type { if ($type instanceof UnionType || $type instanceof IntersectionType) { return $traverse($type); } @@ -37,24 +45,34 @@ public function determineType(Type $objectOrClassType, Type $classType, bool $al return new NeverType(); } if ($allowString) { - return TypeCombinator::union(new ObjectType($type->getValue()), new GenericClassStringType(new ObjectType($type->getValue()))); + return TypeCombinator::union( + new ObjectType($type->getValue()), + new GenericClassStringType(new ObjectType($type->getValue())), + ); } return new ObjectType($type->getValue()); } if ($type instanceof GenericClassStringType) { if ($allowString) { - return TypeCombinator::union($type->getGenericType(), $type); + return TypeCombinator::union( + $type->getGenericType(), + $type, + ); } return $type->getGenericType(); } if ($allowString) { - return TypeCombinator::union(new ObjectWithoutClassType(), new ClassStringType()); + return TypeCombinator::union( + new ObjectWithoutClassType(), + new ClassStringType(), + ); } return new ObjectWithoutClassType(); - }); + }, + ); } } diff --git a/src/Type/Php/IsArrayFunctionTypeSpecifyingExtension.php b/src/Type/Php/IsArrayFunctionTypeSpecifyingExtension.php index 12e118dde6a..d05b999422e 100644 --- a/src/Type/Php/IsArrayFunctionTypeSpecifyingExtension.php +++ b/src/Type/Php/IsArrayFunctionTypeSpecifyingExtension.php @@ -18,18 +18,10 @@ class IsArrayFunctionTypeSpecifyingExtension implements FunctionTypeSpecifyingExtension, TypeSpecifierAwareExtension { - /** - * @var bool - */ - private $explicitMixed; - /** - * @var TypeSpecifier - */ - private $typeSpecifier; - - public function __construct(bool $explicitMixed) + private TypeSpecifier $typeSpecifier; + + public function __construct(private bool $explicitMixed) { - $this->explicitMixed = $explicitMixed; } public function isFunctionSupported(FunctionReflection $functionReflection, FuncCall $node, TypeSpecifierContext $context): bool diff --git a/src/Type/Php/IsCallableFunctionTypeSpecifyingExtension.php b/src/Type/Php/IsCallableFunctionTypeSpecifyingExtension.php index 465e703b1a0..38bb1f3044f 100644 --- a/src/Type/Php/IsCallableFunctionTypeSpecifyingExtension.php +++ b/src/Type/Php/IsCallableFunctionTypeSpecifyingExtension.php @@ -21,18 +21,10 @@ class IsCallableFunctionTypeSpecifyingExtension implements FunctionTypeSpecifyingExtension, TypeSpecifierAwareExtension { - /** - * @var MethodExistsTypeSpecifyingExtension - */ - private $methodExistsExtension; - /** - * @var TypeSpecifier - */ - private $typeSpecifier; + private TypeSpecifier $typeSpecifier; - public function __construct(MethodExistsTypeSpecifyingExtension $methodExistsExtension) + public function __construct(private MethodExistsTypeSpecifyingExtension $methodExistsExtension) { - $this->methodExistsExtension = $methodExistsExtension; } public function isFunctionSupported(FunctionReflection $functionReflection, FuncCall $node, TypeSpecifierContext $context): bool diff --git a/src/Type/Php/IsIterableFunctionTypeSpecifyingExtension.php b/src/Type/Php/IsIterableFunctionTypeSpecifyingExtension.php index 808a337b4e6..470d1968941 100644 --- a/src/Type/Php/IsIterableFunctionTypeSpecifyingExtension.php +++ b/src/Type/Php/IsIterableFunctionTypeSpecifyingExtension.php @@ -18,10 +18,7 @@ class IsIterableFunctionTypeSpecifyingExtension implements FunctionTypeSpecifyingExtension, TypeSpecifierAwareExtension { - /** - * @var TypeSpecifier - */ - private $typeSpecifier; + private TypeSpecifier $typeSpecifier; public function isFunctionSupported(FunctionReflection $functionReflection, FuncCall $node, TypeSpecifierContext $context): bool { diff --git a/src/Type/Php/IsSubclassOfFunctionTypeSpecifyingExtension.php b/src/Type/Php/IsSubclassOfFunctionTypeSpecifyingExtension.php index 80e238befa2..3864db74e5a 100644 --- a/src/Type/Php/IsSubclassOfFunctionTypeSpecifyingExtension.php +++ b/src/Type/Php/IsSubclassOfFunctionTypeSpecifyingExtension.php @@ -18,18 +18,12 @@ class IsSubclassOfFunctionTypeSpecifyingExtension implements FunctionTypeSpecifyingExtension, TypeSpecifierAwareExtension { - /** - * @var IsAFunctionTypeSpecifyingHelper - */ - private $isAFunctionTypeSpecifyingHelper; - /** - * @var TypeSpecifier - */ - private $typeSpecifier; + private TypeSpecifier $typeSpecifier; - public function __construct(IsAFunctionTypeSpecifyingHelper $isAFunctionTypeSpecifyingHelper) + public function __construct( + private IsAFunctionTypeSpecifyingHelper $isAFunctionTypeSpecifyingHelper, + ) { - $this->isAFunctionTypeSpecifyingHelper = $isAFunctionTypeSpecifyingHelper; } public function isFunctionSupported(FunctionReflection $functionReflection, FuncCall $node, TypeSpecifierContext $context): bool @@ -54,7 +48,13 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n return new SpecifiedTypes([], []); } - return $this->typeSpecifier->create($node->getArgs()[0]->value, $this->isAFunctionTypeSpecifyingHelper->determineType($objectOrClassType, $classType, $allowString, false), $context, false, $scope); + return $this->typeSpecifier->create( + $node->getArgs()[0]->value, + $this->isAFunctionTypeSpecifyingHelper->determineType($objectOrClassType, $classType, $allowString, false), + $context, + false, + $scope, + ); } public function setTypeSpecifier(TypeSpecifier $typeSpecifier): void diff --git a/src/Type/Php/IteratorToArrayFunctionReturnTypeExtension.php b/src/Type/Php/IteratorToArrayFunctionReturnTypeExtension.php index 7d7f88e6bb5..3eba7891757 100644 --- a/src/Type/Php/IteratorToArrayFunctionReturnTypeExtension.php +++ b/src/Type/Php/IteratorToArrayFunctionReturnTypeExtension.php @@ -41,7 +41,10 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, } } - $arrayType = new ArrayType($arrayKeyType, $traversableType->getIterableValueType()); + $arrayType = new ArrayType( + $arrayKeyType, + $traversableType->getIterableValueType(), + ); if ($isList) { $arrayType = AccessoryArrayListType::intersectWith($arrayType); diff --git a/src/Type/Php/JsonThrowOnErrorDynamicReturnTypeExtension.php b/src/Type/Php/JsonThrowOnErrorDynamicReturnTypeExtension.php index 48b4fa88464..cf653e182e5 100644 --- a/src/Type/Php/JsonThrowOnErrorDynamicReturnTypeExtension.php +++ b/src/Type/Php/JsonThrowOnErrorDynamicReturnTypeExtension.php @@ -24,51 +24,55 @@ class JsonThrowOnErrorDynamicReturnTypeExtension implements DynamicFunctionReturnTypeExtension { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - /** - * @var BitwiseFlagHelper - */ - private $bitwiseFlagAnalyser; - /** @var array */ - private $argumentPositions = [ + /** @var array */ + private array $argumentPositions = [ 'json_encode' => 1, 'json_decode' => 3, ]; - public function __construct(ReflectionProvider $reflectionProvider, BitwiseFlagHelper $bitwiseFlagAnalyser) - { - $this->reflectionProvider = $reflectionProvider; - $this->bitwiseFlagAnalyser = $bitwiseFlagAnalyser; + public function __construct( + private ReflectionProvider $reflectionProvider, + private BitwiseFlagHelper $bitwiseFlagAnalyser, + ) + { + } + + public function isFunctionSupported( + FunctionReflection $functionReflection, + ): bool + { + if ($functionReflection->getName() === 'json_decode') { + return true; } - public function isFunctionSupported(FunctionReflection $functionReflection) : bool - { - if ($functionReflection->getName() === 'json_decode') { - return true; - } - return $this->reflectionProvider->hasConstant(new FullyQualified('JSON_THROW_ON_ERROR'), null) && $functionReflection->getName() === 'json_encode'; + return $this->reflectionProvider->hasConstant(new FullyQualified('JSON_THROW_ON_ERROR'), null) && $functionReflection->getName() === 'json_encode'; + } + + public function getTypeFromFunctionCall( + FunctionReflection $functionReflection, + FuncCall $functionCall, + Scope $scope, + ): Type + { + $argumentPosition = $this->argumentPositions[$functionReflection->getName()]; + $defaultReturnType = ParametersAcceptorSelector::selectSingle($functionReflection->getVariants())->getReturnType(); + + if ($functionReflection->getName() === 'json_decode') { + $defaultReturnType = $this->narrowTypeForJsonDecode($functionCall, $scope, $defaultReturnType); + } + + if (!isset($functionCall->getArgs()[$argumentPosition])) { + return $defaultReturnType; } - public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope) : Type - { - $argumentPosition = $this->argumentPositions[$functionReflection->getName()]; - $defaultReturnType = ParametersAcceptorSelector::selectSingle($functionReflection->getVariants())->getReturnType(); - if ($functionReflection->getName() === 'json_decode') { - $defaultReturnType = $this->narrowTypeForJsonDecode($functionCall, $scope, $defaultReturnType); - } - if (!isset($functionCall->getArgs()[$argumentPosition])) { - return $defaultReturnType; - } - $optionsExpr = $functionCall->getArgs()[$argumentPosition]->value; - if ($functionReflection->getName() === 'json_encode' && $this->bitwiseFlagAnalyser->bitwiseOrContainsConstant($optionsExpr, $scope, 'JSON_THROW_ON_ERROR')->yes()) { - return TypeCombinator::remove($defaultReturnType, new ConstantBooleanType(false)); - } - return $defaultReturnType; + $optionsExpr = $functionCall->getArgs()[$argumentPosition]->value; + if ($functionReflection->getName() === 'json_encode' && $this->bitwiseFlagAnalyser->bitwiseOrContainsConstant($optionsExpr, $scope, 'JSON_THROW_ON_ERROR')->yes()) { + return TypeCombinator::remove($defaultReturnType, new ConstantBooleanType(false)); } + return $defaultReturnType; + } + private function narrowTypeForJsonDecode(FuncCall $funcCall, Scope $scope, Type $fallbackType): Type { $args = $funcCall->getArgs(); @@ -90,9 +94,9 @@ private function narrowTypeForJsonDecode(FuncCall $funcCall, Scope $scope, Type } /** - * Is "json_decode(..., true)"? - */ - private function isForceArrayWithoutStdClass(FuncCall $funcCall, Scope $scope): bool + * Is "json_decode(..., true)"? + */ + private function isForceArrayWithoutStdClass(FuncCall $funcCall, Scope $scope): bool { $args = $funcCall->getArgs(); if (!isset($args[1])) { diff --git a/src/Type/Php/JsonThrowTypeExtension.php b/src/Type/Php/JsonThrowTypeExtension.php index 7e28758f6fe..e58f80d814d 100644 --- a/src/Type/Php/JsonThrowTypeExtension.php +++ b/src/Type/Php/JsonThrowTypeExtension.php @@ -16,44 +16,49 @@ class JsonThrowTypeExtension implements DynamicFunctionThrowTypeExtension { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - /** - * @var BitwiseFlagHelper - */ - private $bitwiseFlagAnalyser; - private const ARGUMENTS_POSITIONS = [ + private const ARGUMENTS_POSITIONS = [ 'json_encode' => 1, 'json_decode' => 3, ]; - public function __construct(ReflectionProvider $reflectionProvider, BitwiseFlagHelper $bitwiseFlagAnalyser) - { - $this->reflectionProvider = $reflectionProvider; - $this->bitwiseFlagAnalyser = $bitwiseFlagAnalyser; - } + public function __construct( + private ReflectionProvider $reflectionProvider, + private BitwiseFlagHelper $bitwiseFlagAnalyser, + ) + { + } - public function isFunctionSupported(FunctionReflection $functionReflection) : bool - { - return $this->reflectionProvider->hasConstant(new Name\FullyQualified('JSON_THROW_ON_ERROR'), null) && in_array($functionReflection->getName(), [ + public function isFunctionSupported( + FunctionReflection $functionReflection, + ): bool + { + return $this->reflectionProvider->hasConstant(new Name\FullyQualified('JSON_THROW_ON_ERROR'), null) && in_array( + $functionReflection->getName(), + [ 'json_encode', 'json_decode', - ], true); + ], + true, + ); + } + + public function getThrowTypeFromFunctionCall( + FunctionReflection $functionReflection, + FuncCall $functionCall, + Scope $scope, + ): ?Type + { + $argumentPosition = self::ARGUMENTS_POSITIONS[$functionReflection->getName()]; + if (!isset($functionCall->getArgs()[$argumentPosition])) { + return null; } - public function getThrowTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope) : ?Type - { - $argumentPosition = self::ARGUMENTS_POSITIONS[$functionReflection->getName()]; - if (!isset($functionCall->getArgs()[$argumentPosition])) { - return null; - } - $optionsExpr = $functionCall->getArgs()[$argumentPosition]->value; - if (!$this->bitwiseFlagAnalyser->bitwiseOrContainsConstant($optionsExpr, $scope, 'JSON_THROW_ON_ERROR')->no()) { - return new ObjectType('JsonException'); - } - return null; + $optionsExpr = $functionCall->getArgs()[$argumentPosition]->value; + if (!$this->bitwiseFlagAnalyser->bitwiseOrContainsConstant($optionsExpr, $scope, 'JSON_THROW_ON_ERROR')->no()) { + return new ObjectType('JsonException'); } + return null; + } + } diff --git a/src/Type/Php/MbConvertEncodingFunctionReturnTypeExtension.php b/src/Type/Php/MbConvertEncodingFunctionReturnTypeExtension.php index 50f52bbda1c..ae3aa752f99 100644 --- a/src/Type/Php/MbConvertEncodingFunctionReturnTypeExtension.php +++ b/src/Type/Php/MbConvertEncodingFunctionReturnTypeExtension.php @@ -19,11 +19,16 @@ public function isFunctionSupported(FunctionReflection $functionReflection): boo return $functionReflection->getName() === 'mb_convert_encoding'; } - public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope) : ?Type + public function getTypeFromFunctionCall( + FunctionReflection $functionReflection, + FuncCall $functionCall, + Scope $scope, + ): ?Type { if (!isset($functionCall->getArgs()[0])) { return null; } + $argType = $scope->getType($functionCall->getArgs()[0]->value); $isString = $argType->isString(); $isArray = $argType->isArray(); @@ -33,6 +38,7 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, } elseif ($compare === $isArray) { return new ArrayType(new IntegerType(), new StringType()); } + return null; } diff --git a/src/Type/Php/MbFunctionsReturnTypeExtension.php b/src/Type/Php/MbFunctionsReturnTypeExtension.php index f9087ad51bb..13f8d238b08 100644 --- a/src/Type/Php/MbFunctionsReturnTypeExtension.php +++ b/src/Type/Php/MbFunctionsReturnTypeExtension.php @@ -24,14 +24,10 @@ class MbFunctionsReturnTypeExtension implements DynamicFunctionReturnTypeExtension { - /** - * @var PhpVersion - */ - private $phpVersion; use MbFunctionsReturnTypeExtensionTrait; /** @var int[] */ - private $encodingPositionMap = [ + private array $encodingPositionMap = [ 'mb_http_output' => 1, 'mb_regex_encoding' => 1, 'mb_internal_encoding' => 1, @@ -40,9 +36,8 @@ class MbFunctionsReturnTypeExtension implements DynamicFunctionReturnTypeExtensi 'mb_ord' => 2, ]; - public function __construct(PhpVersion $phpVersion) + public function __construct(private PhpVersion $phpVersion) { - $this->phpVersion = $phpVersion; } public function isFunctionSupported(FunctionReflection $functionReflection): bool @@ -60,9 +55,7 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, } $strings = $scope->getType($functionCall->getArgs()[$positionEncodingParam - 1]->value)->getConstantStrings(); - $results = array_unique(array_map(function (ConstantStringType $encoding) : bool { - return $this->isSupportedEncoding($encoding->getValue()); - }, $strings)); + $results = array_unique(array_map(fn (ConstantStringType $encoding): bool => $this->isSupportedEncoding($encoding->getValue()), $strings)); if ($returnType->equals(new UnionType([new StringType(), new BooleanType()]))) { return count($results) === 1 ? new ConstantBooleanType($results[0]) : new BooleanType(); diff --git a/src/Type/Php/MbFunctionsReturnTypeExtensionTrait.php b/src/Type/Php/MbFunctionsReturnTypeExtensionTrait.php index cfbc85af098..64036c984b8 100644 --- a/src/Type/Php/MbFunctionsReturnTypeExtensionTrait.php +++ b/src/Type/Php/MbFunctionsReturnTypeExtensionTrait.php @@ -17,7 +17,7 @@ trait MbFunctionsReturnTypeExtensionTrait { /** @var string[]|null */ - private $supportedEncodings = null; + private ?array $supportedEncodings = null; private function isSupportedEncoding(string $encoding): bool { @@ -45,9 +45,10 @@ private function getSupportedEncodings(): array // PHP 7.3 and 7.4 claims 'pass' and its alias 'none' to be supported, but actually 'pass' was removed in 7.3 if (!$this->phpVersion->supportsPassNoneEncodings()) { - $this->supportedEncodings = array_filter($this->supportedEncodings, static function (string $enc) { - return !in_array($enc, ['PASS', 'NONE'], true); - }); + $this->supportedEncodings = array_filter( + $this->supportedEncodings, + static fn (string $enc) => !in_array($enc, ['PASS', 'NONE'], true), + ); } return $this->supportedEncodings; diff --git a/src/Type/Php/MbStrlenFunctionReturnTypeExtension.php b/src/Type/Php/MbStrlenFunctionReturnTypeExtension.php index 474408486ca..cb246f7e3d9 100644 --- a/src/Type/Php/MbStrlenFunctionReturnTypeExtension.php +++ b/src/Type/Php/MbStrlenFunctionReturnTypeExtension.php @@ -36,17 +36,12 @@ class MbStrlenFunctionReturnTypeExtension implements DynamicFunctionReturnTypeExtension { - /** - * @var PhpVersion - */ - private $phpVersion; private const UNSUPPORTED_ENCODING = 'unsupported'; use MbFunctionsReturnTypeExtensionTrait; - public function __construct(PhpVersion $phpVersion) + public function __construct(private PhpVersion $phpVersion) { - $this->phpVersion = $phpVersion; } public function isFunctionSupported(FunctionReflection $functionReflection): bool @@ -54,21 +49,29 @@ public function isFunctionSupported(FunctionReflection $functionReflection): boo return $functionReflection->getName() === 'mb_strlen'; } - public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope) : ?Type + public function getTypeFromFunctionCall( + FunctionReflection $functionReflection, + FuncCall $functionCall, + Scope $scope, + ): ?Type { $args = $functionCall->getArgs(); if (count($args) === 0) { return null; } + $encodings = []; + if (count($functionCall->getArgs()) === 1) { // there is a chance to get an unsupported encoding 'pass' or 'none' here on PHP 7.3-7.4 $encodings = [mb_internal_encoding()]; } elseif (count($functionCall->getArgs()) === 2) { // custom encoding is specified - $encodings = array_map(static function (ConstantStringType $t) { - return $t->getValue(); - }, $scope->getType($functionCall->getArgs()[1]->value)->getConstantStrings()); + $encodings = array_map( + static fn (ConstantStringType $t) => $t->getValue(), + $scope->getType($functionCall->getArgs()[1]->value)->getConstantStrings(), + ); } + if (count($encodings) > 0) { for ($i = 0; $i < count($encodings); $i++) { if ($this->isSupportedEncoding($encodings[$i])) { @@ -88,7 +91,9 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, } else { // if there aren't encoding constants, use all available encodings $encodings = array_merge($this->getSupportedEncodings(), [self::UNSUPPORTED_ENCODING]); } + $argType = $scope->getType($args[0]->value); + if ($argType->isSuperTypeOf(new BooleanType())->yes()) { $constantScalars = TypeCombinator::remove($argType, new BooleanType())->getConstantScalarTypes(); if (count($constantScalars) > 0) { @@ -98,6 +103,7 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, } else { $constantScalars = $argType->getConstantScalarTypes(); } + $lengths = []; foreach ($constantScalars as $constantScalar) { $stringScalar = $constantScalar->toString(); @@ -118,6 +124,7 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, $lengths[] = $length; } } + $isNonEmpty = $argType->isNonEmptyString(); $numeric = TypeCombinator::union(new IntegerType(), new FloatType()); if (count($lengths) > 0) { @@ -126,9 +133,7 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, if ($lengths === range(min($lengths), max($lengths))) { $range = IntegerRangeType::fromInterval(min($lengths), max($lengths)); } else { - $range = TypeCombinator::union(...array_map(static function ($l) { - return new ConstantIntegerType($l); - }, $lengths)); + $range = TypeCombinator::union(...array_map(static fn ($l) => new ConstantIntegerType($l), $lengths)); } } elseif ($argType->isBoolean()->yes()) { $range = IntegerRangeType::fromInterval(0, 1); @@ -141,8 +146,12 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, } elseif ($argType->isString()->yes() && $isNonEmpty->no()) { $range = new ConstantIntegerType(0); } else { - $range = TypeCombinator::remove(ParametersAcceptorSelector::selectSingle($functionReflection->getVariants())->getReturnType(), new ConstantBooleanType(false)); + $range = TypeCombinator::remove( + ParametersAcceptorSelector::selectSingle($functionReflection->getVariants())->getReturnType(), + new ConstantBooleanType(false), + ); } + if (!$this->phpVersion->throwsOnInvalidMbStringEncoding() && in_array(self::UNSUPPORTED_ENCODING, $encodings, true)) { return TypeCombinator::union($range, new ConstantBooleanType(false)); } diff --git a/src/Type/Php/MbSubstituteCharacterDynamicReturnTypeExtension.php b/src/Type/Php/MbSubstituteCharacterDynamicReturnTypeExtension.php index e588702785b..f5d0055d9b1 100644 --- a/src/Type/Php/MbSubstituteCharacterDynamicReturnTypeExtension.php +++ b/src/Type/Php/MbSubstituteCharacterDynamicReturnTypeExtension.php @@ -21,13 +21,8 @@ class MbSubstituteCharacterDynamicReturnTypeExtension implements DynamicFunctionReturnTypeExtension { - /** - * @var PhpVersion - */ - private $phpVersion; - public function __construct(PhpVersion $phpVersion) + public function __construct(private PhpVersion $phpVersion) { - $this->phpVersion = $phpVersion; } public function isFunctionSupported(FunctionReflection $functionReflection): bool @@ -50,7 +45,12 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, } if (!isset($functionCall->getArgs()[0])) { - return TypeCombinator::union(new ConstantStringType('none'), new ConstantStringType('long'), new ConstantStringType('entity'), ...$ranges); + return TypeCombinator::union( + new ConstantStringType('none'), + new ConstantStringType('long'), + new ConstantStringType('entity'), + ...$ranges, + ); } $argType = $scope->getType($functionCall->getArgs()[0]->value); diff --git a/src/Type/Php/MethodExistsTypeSpecifyingExtension.php b/src/Type/Php/MethodExistsTypeSpecifyingExtension.php index d3bf9505cfa..08a366a59b8 100644 --- a/src/Type/Php/MethodExistsTypeSpecifyingExtension.php +++ b/src/Type/Php/MethodExistsTypeSpecifyingExtension.php @@ -21,47 +21,67 @@ class MethodExistsTypeSpecifyingExtension implements FunctionTypeSpecifyingExtension, TypeSpecifierAwareExtension { - /** - * @var TypeSpecifier - */ - private $typeSpecifier; + private TypeSpecifier $typeSpecifier; public function setTypeSpecifier(TypeSpecifier $typeSpecifier): void { $this->typeSpecifier = $typeSpecifier; } - public function isFunctionSupported(FunctionReflection $functionReflection, FuncCall $node, TypeSpecifierContext $context) : bool + public function isFunctionSupported( + FunctionReflection $functionReflection, + FuncCall $node, + TypeSpecifierContext $context, + ): bool { return $functionReflection->getName() === 'method_exists' && $context->true() && count($node->getArgs()) >= 2; } - public function specifyTypes(FunctionReflection $functionReflection, FuncCall $node, Scope $scope, TypeSpecifierContext $context) : SpecifiedTypes + public function specifyTypes( + FunctionReflection $functionReflection, + FuncCall $node, + Scope $scope, + TypeSpecifierContext $context, + ): SpecifiedTypes { $methodNameType = $scope->getType($node->getArgs()[1]->value); if (!$methodNameType instanceof ConstantStringType) { return new SpecifiedTypes([], []); } + $objectType = $scope->getType($node->getArgs()[0]->value); if ($objectType->isString()->yes()) { if ($objectType->isClassStringType()->yes()) { - return $this->typeSpecifier->create($node->getArgs()[0]->value, new IntersectionType([ + return $this->typeSpecifier->create( + $node->getArgs()[0]->value, + new IntersectionType([ $objectType, new HasMethodType($methodNameType->getValue()), - ]), $context, false, $scope); + ]), + $context, + false, + $scope, + ); } return new SpecifiedTypes([], []); } - return $this->typeSpecifier->create($node->getArgs()[0]->value, new UnionType([ + + return $this->typeSpecifier->create( + $node->getArgs()[0]->value, + new UnionType([ new IntersectionType([ new ObjectWithoutClassType(), new HasMethodType($methodNameType->getValue()), ]), new ClassStringType(), - ]), $context, false, $scope); + ]), + $context, + false, + $scope, + ); } } diff --git a/src/Type/Php/MinMaxFunctionReturnTypeExtension.php b/src/Type/Php/MinMaxFunctionReturnTypeExtension.php index 43b65c40eba..e1633c0b642 100644 --- a/src/Type/Php/MinMaxFunctionReturnTypeExtension.php +++ b/src/Type/Php/MinMaxFunctionReturnTypeExtension.php @@ -23,14 +23,12 @@ class MinMaxFunctionReturnTypeExtension implements DynamicFunctionReturnTypeExtension { - /** - * @var PhpVersion - */ - private $phpVersion; - public function __construct(PhpVersion $phpVersion) + public function __construct( + private PhpVersion $phpVersion, + ) { - $this->phpVersion = $phpVersion; } + public function isFunctionSupported(FunctionReflection $functionReflection): bool { return in_array($functionReflection->getName(), ['min', 'max'], true); @@ -45,7 +43,10 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, if (count($functionCall->getArgs()) === 1) { $argType = $scope->getType($functionCall->getArgs()[0]->value); if ($argType->isArray()->yes()) { - return $this->processArrayType($functionReflection->getName(), $argType); + return $this->processArrayType( + $functionReflection->getName(), + $argType, + ); } return new ErrorType(); @@ -61,9 +62,17 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, if ($argType0->isArray()->no() && $argType1->isArray()->no()) { if ($functionName === 'min') { - return $scope->getType(new Ternary(new Smaller($args[0]->value, $args[1]->value), $args[0]->value, $args[1]->value)); + return $scope->getType(new Ternary( + new Smaller($args[0]->value, $args[1]->value), + $args[0]->value, + $args[1]->value, + )); } elseif ($functionName === 'max') { - return $scope->getType(new Ternary(new Smaller($args[0]->value, $args[1]->value), $args[1]->value, $args[0]->value)); + return $scope->getType(new Ternary( + new Smaller($args[0]->value, $args[1]->value), + $args[1]->value, + $args[0]->value, + )); } } } @@ -86,7 +95,10 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, $argumentTypes[] = $argType; } - return $this->processType($functionName, $argumentTypes); + return $this->processType( + $functionName, + $argumentTypes, + ); } private function processArrayType(string $functionName, Type $argType): Type @@ -133,7 +145,10 @@ private function processArrayType(string $functionName, Type $argType): Type /** * @param Type[] $types */ - private function processType(string $functionName, array $types) : Type + private function processType( + string $functionName, + array $types, + ): Type { $resultType = null; foreach ($types as $type) { @@ -157,13 +172,18 @@ private function processType(string $functionName, array $types) : Type } } } + if ($resultType === null) { return new ErrorType(); } + return $resultType; } - private function compareTypes(Type $firstType, Type $secondType) : ?Type + private function compareTypes( + Type $firstType, + Type $secondType, + ): ?Type { if ( $firstType->isConstantArray()->yes() @@ -171,12 +191,14 @@ private function compareTypes(Type $firstType, Type $secondType) : ?Type ) { return $secondType; } + if ( $firstType instanceof ConstantScalarType && $secondType->isConstantArray()->yes() ) { return $firstType; } + if ( $firstType instanceof ConstantArrayType && $secondType instanceof ConstantArrayType @@ -201,6 +223,7 @@ private function compareTypes(Type $firstType, Type $secondType) : ?Type return null; } + if ( $firstType instanceof ConstantScalarType && $secondType instanceof ConstantScalarType @@ -213,6 +236,7 @@ private function compareTypes(Type $firstType, Type $secondType) : ?Type return $firstType; } } + return null; } diff --git a/src/Type/Php/NonEmptyStringFunctionsReturnTypeExtension.php b/src/Type/Php/NonEmptyStringFunctionsReturnTypeExtension.php index 10bad993342..cb7cf0eb07f 100644 --- a/src/Type/Php/NonEmptyStringFunctionsReturnTypeExtension.php +++ b/src/Type/Php/NonEmptyStringFunctionsReturnTypeExtension.php @@ -34,12 +34,17 @@ public function isFunctionSupported(FunctionReflection $functionReflection): boo ], true); } - public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope) : ?Type + public function getTypeFromFunctionCall( + FunctionReflection $functionReflection, + FuncCall $functionCall, + Scope $scope, + ): ?Type { $args = $functionCall->getArgs(); if (count($args) === 0) { return null; } + $argType = $scope->getType($args[0]->value); if ($argType->isNonFalsyString()->yes()) { return new IntersectionType([ @@ -53,6 +58,7 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, new AccessoryNonEmptyStringType(), ]); } + return new StringType(); } diff --git a/src/Type/Php/ParseUrlFunctionDynamicReturnTypeExtension.php b/src/Type/Php/ParseUrlFunctionDynamicReturnTypeExtension.php index ce714e54f6a..a3e2ec18b80 100644 --- a/src/Type/Php/ParseUrlFunctionDynamicReturnTypeExtension.php +++ b/src/Type/Php/ParseUrlFunctionDynamicReturnTypeExtension.php @@ -32,15 +32,12 @@ final class ParseUrlFunctionDynamicReturnTypeExtension implements DynamicFunctio { /** @var array|null */ - private $componentTypesPairedConstants = null; + private ?array $componentTypesPairedConstants = null; /** @var array|null */ - private $componentTypesPairedStrings = null; + private ?array $componentTypesPairedStrings = null; - /** - * @var ?Type - */ - private $allComponentsTogetherType = null; + private ?Type $allComponentsTogetherType = null; public function isFunctionSupported(FunctionReflection $functionReflection): bool { @@ -77,7 +74,7 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, foreach ($urlType->getConstantStrings() as $constantString) { try { $result = @parse_url($constantString->getValue(), $componentType->getValue()); - } catch (ValueError $e) { + } catch (ValueError) { $types[] = new ConstantBooleanType(false); continue; } diff --git a/src/Type/Php/PathinfoFunctionDynamicReturnTypeExtension.php b/src/Type/Php/PathinfoFunctionDynamicReturnTypeExtension.php index 832f9860051..2139200e0b7 100644 --- a/src/Type/Php/PathinfoFunctionDynamicReturnTypeExtension.php +++ b/src/Type/Php/PathinfoFunctionDynamicReturnTypeExtension.php @@ -20,13 +20,8 @@ class PathinfoFunctionDynamicReturnTypeExtension implements DynamicFunctionReturnTypeExtension { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - public function __construct(ReflectionProvider $reflectionProvider) + public function __construct(private ReflectionProvider $reflectionProvider) { - $this->reflectionProvider = $reflectionProvider; } public function isFunctionSupported(FunctionReflection $functionReflection): bool @@ -34,22 +29,30 @@ public function isFunctionSupported(FunctionReflection $functionReflection): boo return $functionReflection->getName() === 'pathinfo'; } - public function getTypeFromFunctionCall(FunctionReflection $functionReflection, Node\Expr\FuncCall $functionCall, Scope $scope) : ?Type + public function getTypeFromFunctionCall( + FunctionReflection $functionReflection, + Node\Expr\FuncCall $functionCall, + Scope $scope, + ): ?Type { $argsCount = count($functionCall->getArgs()); if ($argsCount === 0) { return null; } + $pathType = $scope->getType($functionCall->getArgs()[0]->value); + $builder = ConstantArrayTypeBuilder::createEmpty(); $builder->setOffsetValueType(new ConstantStringType('dirname'), new StringType(), !$pathType->isNonEmptyString()->yes()); $builder->setOffsetValueType(new ConstantStringType('basename'), new StringType()); $builder->setOffsetValueType(new ConstantStringType('extension'), new StringType(), true); $builder->setOffsetValueType(new ConstantStringType('filename'), new StringType()); $arrayType = $builder->getArray(); + if ($argsCount === 1) { return $arrayType; } + $flagsType = $scope->getType($functionCall->getArgs()[1]->value); if ($flagsType instanceof ConstantIntegerType) { if ($flagsType->getValue() === $this->getConstant('PATHINFO_ALL')) { @@ -58,6 +61,7 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, return new StringType(); } + return TypeCombinator::union($arrayType, new StringType()); } diff --git a/src/Type/Php/PregSplitDynamicReturnTypeExtension.php b/src/Type/Php/PregSplitDynamicReturnTypeExtension.php index 060787f5f50..6300d6887d7 100644 --- a/src/Type/Php/PregSplitDynamicReturnTypeExtension.php +++ b/src/Type/Php/PregSplitDynamicReturnTypeExtension.php @@ -23,14 +23,12 @@ class PregSplitDynamicReturnTypeExtension implements DynamicFunctionReturnTypeExtension { - /** - * @var BitwiseFlagHelper - */ - private $bitwiseFlagAnalyser; - public function __construct(BitwiseFlagHelper $bitwiseFlagAnalyser) + public function __construct( + private BitwiseFlagHelper $bitwiseFlagAnalyser, + ) { - $this->bitwiseFlagAnalyser = $bitwiseFlagAnalyser; } + public function isFunctionSupported(FunctionReflection $functionReflection): bool { return strtolower($functionReflection->getName()) === 'preg_split'; @@ -41,7 +39,10 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, $flagsArg = $functionCall->getArgs()[3] ?? null; if ($flagsArg !== null && $this->bitwiseFlagAnalyser->bitwiseOrContainsConstant($flagsArg->value, $scope, 'PREG_SPLIT_OFFSET_CAPTURE')->yes()) { - $type = new ArrayType(new IntegerType(), new ConstantArrayType([new ConstantIntegerType(0), new ConstantIntegerType(1)], [new StringType(), IntegerRangeType::fromInterval(0, null)], [2], [], TrinaryLogic::createYes())); + $type = new ArrayType( + new IntegerType(), + new ConstantArrayType([new ConstantIntegerType(0), new ConstantIntegerType(1)], [new StringType(), IntegerRangeType::fromInterval(0, null)], [2], [], TrinaryLogic::createYes()), + ); return TypeCombinator::union(AccessoryArrayListType::intersectWith($type), new ConstantBooleanType(false)); } diff --git a/src/Type/Php/PropertyExistsTypeSpecifyingExtension.php b/src/Type/Php/PropertyExistsTypeSpecifyingExtension.php index 2a11e30991f..8907e48a661 100644 --- a/src/Type/Php/PropertyExistsTypeSpecifyingExtension.php +++ b/src/Type/Php/PropertyExistsTypeSpecifyingExtension.php @@ -22,18 +22,10 @@ class PropertyExistsTypeSpecifyingExtension implements FunctionTypeSpecifyingExtension, TypeSpecifierAwareExtension { - /** - * @var PropertyReflectionFinder - */ - private $propertyReflectionFinder; - /** - * @var TypeSpecifier - */ - private $typeSpecifier; + private TypeSpecifier $typeSpecifier; - public function __construct(PropertyReflectionFinder $propertyReflectionFinder) + public function __construct(private PropertyReflectionFinder $propertyReflectionFinder) { - $this->propertyReflectionFinder = $propertyReflectionFinder; } public function setTypeSpecifier(TypeSpecifier $typeSpecifier): void @@ -41,37 +33,58 @@ public function setTypeSpecifier(TypeSpecifier $typeSpecifier): void $this->typeSpecifier = $typeSpecifier; } - public function isFunctionSupported(FunctionReflection $functionReflection, FuncCall $node, TypeSpecifierContext $context) : bool + public function isFunctionSupported( + FunctionReflection $functionReflection, + FuncCall $node, + TypeSpecifierContext $context, + ): bool { return $functionReflection->getName() === 'property_exists' && $context->true() && count($node->getArgs()) >= 2; } - public function specifyTypes(FunctionReflection $functionReflection, FuncCall $node, Scope $scope, TypeSpecifierContext $context) : SpecifiedTypes + public function specifyTypes( + FunctionReflection $functionReflection, + FuncCall $node, + Scope $scope, + TypeSpecifierContext $context, + ): SpecifiedTypes { $propertyNameType = $scope->getType($node->getArgs()[1]->value); if (!$propertyNameType instanceof ConstantStringType) { return new SpecifiedTypes([], []); } + $objectType = $scope->getType($node->getArgs()[0]->value); if ($objectType instanceof ConstantStringType) { return new SpecifiedTypes([], []); } elseif ($objectType->isObject()->yes()) { - $propertyNode = new PropertyFetch($node->getArgs()[0]->value, new Identifier($propertyNameType->getValue())); + $propertyNode = new PropertyFetch( + $node->getArgs()[0]->value, + new Identifier($propertyNameType->getValue()), + ); } else { return new SpecifiedTypes([], []); } + $propertyReflection = $this->propertyReflectionFinder->findPropertyReflectionFromNode($propertyNode, $scope); if ($propertyReflection !== null) { if (!$propertyReflection->isNative()) { return new SpecifiedTypes([], []); } } - return $this->typeSpecifier->create($node->getArgs()[0]->value, new IntersectionType([ + + return $this->typeSpecifier->create( + $node->getArgs()[0]->value, + new IntersectionType([ new ObjectWithoutClassType(), new HasPropertyType($propertyNameType->getValue()), - ]), $context, false, $scope); + ]), + $context, + false, + $scope, + ); } } diff --git a/src/Type/Php/RandomIntFunctionReturnTypeExtension.php b/src/Type/Php/RandomIntFunctionReturnTypeExtension.php index c141b496038..e7e17b90f61 100644 --- a/src/Type/Php/RandomIntFunctionReturnTypeExtension.php +++ b/src/Type/Php/RandomIntFunctionReturnTypeExtension.php @@ -43,7 +43,8 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, private function createRange(Type $minType, Type $maxType): Type { - $minValues = array_map(static function (Type $type): ?int { + $minValues = array_map( + static function (Type $type): ?int { if ($type instanceof IntegerRangeType) { return $type->getMin(); } @@ -51,9 +52,12 @@ private function createRange(Type $minType, Type $maxType): Type return $type->getValue(); } return null; - }, $minType instanceof UnionType ? $minType->getTypes() : [$minType]); + }, + $minType instanceof UnionType ? $minType->getTypes() : [$minType], + ); - $maxValues = array_map(static function (Type $type): ?int { + $maxValues = array_map( + static function (Type $type): ?int { if ($type instanceof IntegerRangeType) { return $type->getMax(); } @@ -61,12 +65,17 @@ private function createRange(Type $minType, Type $maxType): Type return $type->getValue(); } return null; - }, $maxType instanceof UnionType ? $maxType->getTypes() : [$maxType]); + }, + $maxType instanceof UnionType ? $maxType->getTypes() : [$maxType], + ); assert(count($minValues) > 0); assert(count($maxValues) > 0); - return IntegerRangeType::fromInterval(in_array(null, $minValues, true) ? null : min($minValues), in_array(null, $maxValues, true) ? null : max($maxValues)); + return IntegerRangeType::fromInterval( + in_array(null, $minValues, true) ? null : min($minValues), + in_array(null, $maxValues, true) ? null : max($maxValues), + ); } } diff --git a/src/Type/Php/RangeFunctionReturnTypeExtension.php b/src/Type/Php/RangeFunctionReturnTypeExtension.php index edacbe73f6c..9d48e74c019 100644 --- a/src/Type/Php/RangeFunctionReturnTypeExtension.php +++ b/src/Type/Php/RangeFunctionReturnTypeExtension.php @@ -73,10 +73,25 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, $startConstant = $endConstant; $endConstant = $tmp; } - return AccessoryArrayListType::intersectWith(TypeCombinator::intersect(new ArrayType(new IntegerType(), IntegerRangeType::fromInterval($startConstant->getValue(), $endConstant->getValue())), new NonEmptyArrayType())); + return AccessoryArrayListType::intersectWith(TypeCombinator::intersect( + new ArrayType( + new IntegerType(), + IntegerRangeType::fromInterval($startConstant->getValue(), $endConstant->getValue()), + ), + new NonEmptyArrayType(), + )); } - return AccessoryArrayListType::intersectWith(TypeCombinator::intersect(new ArrayType(new IntegerType(), TypeCombinator::union($startConstant->generalize(GeneralizePrecision::moreSpecific()), $endConstant->generalize(GeneralizePrecision::moreSpecific()))), new NonEmptyArrayType())); + return AccessoryArrayListType::intersectWith(TypeCombinator::intersect( + new ArrayType( + new IntegerType(), + TypeCombinator::union( + $startConstant->generalize(GeneralizePrecision::moreSpecific()), + $endConstant->generalize(GeneralizePrecision::moreSpecific()), + ), + ), + new NonEmptyArrayType(), + )); } $arrayBuilder = ConstantArrayTypeBuilder::createEmpty(); foreach ($rangeValues as $value) { @@ -118,7 +133,10 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, return AccessoryArrayListType::intersectWith(new ArrayType(new IntegerType(), new StringType())); } - return AccessoryArrayListType::intersectWith(new ArrayType(new IntegerType(), new BenevolentUnionType([new IntegerType(), new FloatType(), new StringType()]))); + return AccessoryArrayListType::intersectWith(new ArrayType( + new IntegerType(), + new BenevolentUnionType([new IntegerType(), new FloatType(), new StringType()]), + )); } } diff --git a/src/Type/Php/ReflectionClassIsSubclassOfTypeSpecifyingExtension.php b/src/Type/Php/ReflectionClassIsSubclassOfTypeSpecifyingExtension.php index 40c5769a858..842821b1e2e 100644 --- a/src/Type/Php/ReflectionClassIsSubclassOfTypeSpecifyingExtension.php +++ b/src/Type/Php/ReflectionClassIsSubclassOfTypeSpecifyingExtension.php @@ -18,10 +18,7 @@ class ReflectionClassIsSubclassOfTypeSpecifyingExtension implements MethodTypeSpecifyingExtension, TypeSpecifierAwareExtension { - /** - * @var TypeSpecifier - */ - private $typeSpecifier; + private TypeSpecifier $typeSpecifier; public function setTypeSpecifier(TypeSpecifier $typeSpecifier): void { @@ -47,9 +44,15 @@ public function specifyTypes(MethodReflection $methodReflection, MethodCall $nod return new SpecifiedTypes([], []); } - return $this->typeSpecifier->create($node->var, new GenericObjectType(ReflectionClass::class, [ + return $this->typeSpecifier->create( + $node->var, + new GenericObjectType(ReflectionClass::class, [ new ObjectType($valueType->getValue()), - ]), $context, false, $scope); + ]), + $context, + false, + $scope, + ); } } diff --git a/src/Type/Php/ReflectionFunctionConstructorThrowTypeExtension.php b/src/Type/Php/ReflectionFunctionConstructorThrowTypeExtension.php index df95ddb2039..078301bb121 100644 --- a/src/Type/Php/ReflectionFunctionConstructorThrowTypeExtension.php +++ b/src/Type/Php/ReflectionFunctionConstructorThrowTypeExtension.php @@ -17,13 +17,8 @@ class ReflectionFunctionConstructorThrowTypeExtension implements DynamicStaticMethodThrowTypeExtension { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - public function __construct(ReflectionProvider $reflectionProvider) + public function __construct(private ReflectionProvider $reflectionProvider) { - $this->reflectionProvider = $reflectionProvider; } public function isStaticMethodSupported(MethodReflection $methodReflection): bool diff --git a/src/Type/Php/ReflectionGetAttributesMethodReturnTypeExtension.php b/src/Type/Php/ReflectionGetAttributesMethodReturnTypeExtension.php index 9994e3bd61e..bb11536c1be 100644 --- a/src/Type/Php/ReflectionGetAttributesMethodReturnTypeExtension.php +++ b/src/Type/Php/ReflectionGetAttributesMethodReturnTypeExtension.php @@ -16,16 +16,11 @@ class ReflectionGetAttributesMethodReturnTypeExtension implements DynamicMethodReturnTypeExtension { - /** - * @var class-string - */ - private $className; /** * @param class-string $className One of reflection classes: https://www.php.net/manual/en/book.reflection.php */ - public function __construct(string $className) + public function __construct(private string $className) { - $this->className = $className; } public function getClass(): string diff --git a/src/Type/Php/ReflectionMethodConstructorThrowTypeExtension.php b/src/Type/Php/ReflectionMethodConstructorThrowTypeExtension.php index c85e21ea0bf..e6aa5823f5b 100644 --- a/src/Type/Php/ReflectionMethodConstructorThrowTypeExtension.php +++ b/src/Type/Php/ReflectionMethodConstructorThrowTypeExtension.php @@ -19,13 +19,8 @@ class ReflectionMethodConstructorThrowTypeExtension implements DynamicStaticMethodThrowTypeExtension { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - public function __construct(ReflectionProvider $reflectionProvider) + public function __construct(private ReflectionProvider $reflectionProvider) { - $this->reflectionProvider = $reflectionProvider; } public function isStaticMethodSupported(MethodReflection $methodReflection): bool diff --git a/src/Type/Php/ReflectionPropertyConstructorThrowTypeExtension.php b/src/Type/Php/ReflectionPropertyConstructorThrowTypeExtension.php index 76576d6a700..098b3f1567e 100644 --- a/src/Type/Php/ReflectionPropertyConstructorThrowTypeExtension.php +++ b/src/Type/Php/ReflectionPropertyConstructorThrowTypeExtension.php @@ -16,13 +16,8 @@ class ReflectionPropertyConstructorThrowTypeExtension implements DynamicStaticMethodThrowTypeExtension { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - public function __construct(ReflectionProvider $reflectionProvider) + public function __construct(private ReflectionProvider $reflectionProvider) { - $this->reflectionProvider = $reflectionProvider; } public function isStaticMethodSupported(MethodReflection $methodReflection): bool diff --git a/src/Type/Php/ReplaceFunctionsDynamicReturnTypeExtension.php b/src/Type/Php/ReplaceFunctionsDynamicReturnTypeExtension.php index c9aa810b841..1da17b48d89 100644 --- a/src/Type/Php/ReplaceFunctionsDynamicReturnTypeExtension.php +++ b/src/Type/Php/ReplaceFunctionsDynamicReturnTypeExtension.php @@ -44,29 +44,51 @@ public function isFunctionSupported(FunctionReflection $functionReflection): boo return array_key_exists($functionReflection->getName(), self::FUNCTIONS_SUBJECT_POSITION); } - public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope) : Type + public function getTypeFromFunctionCall( + FunctionReflection $functionReflection, + FuncCall $functionCall, + Scope $scope, + ): Type { $type = $this->getPreliminarilyResolvedTypeFromFunctionCall($functionReflection, $functionCall, $scope); - $possibleTypes = ParametersAcceptorSelector::selectFromArgs($scope, $functionCall->getArgs(), $functionReflection->getVariants())->getReturnType(); + + $possibleTypes = ParametersAcceptorSelector::selectFromArgs( + $scope, + $functionCall->getArgs(), + $functionReflection->getVariants(), + )->getReturnType(); // resolve conditional return types $possibleTypes = TypeUtils::resolveLateResolvableTypes($possibleTypes); + if (TypeCombinator::containsNull($possibleTypes)) { $type = TypeCombinator::addNull($type); } + return $type; } - private function getPreliminarilyResolvedTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope) : Type + private function getPreliminarilyResolvedTypeFromFunctionCall( + FunctionReflection $functionReflection, + FuncCall $functionCall, + Scope $scope, + ): Type { $argumentPosition = self::FUNCTIONS_SUBJECT_POSITION[$functionReflection->getName()]; - $defaultReturnType = ParametersAcceptorSelector::selectFromArgs($scope, $functionCall->getArgs(), $functionReflection->getVariants())->getReturnType(); + $defaultReturnType = ParametersAcceptorSelector::selectFromArgs( + $scope, + $functionCall->getArgs(), + $functionReflection->getVariants(), + )->getReturnType(); + if (count($functionCall->getArgs()) <= $argumentPosition) { return $defaultReturnType; } + $subjectArgumentType = $scope->getType($functionCall->getArgs()[$argumentPosition]->value); if ($subjectArgumentType instanceof MixedType) { return TypeUtils::toBenevolentUnion($defaultReturnType); } + if ($subjectArgumentType->isNonEmptyString()->yes() && array_key_exists($functionReflection->getName(), self::FUNCTIONS_REPLACE_POSITION)) { $replaceArgumentPosition = self::FUNCTIONS_REPLACE_POSITION[$functionReflection->getName()]; @@ -81,6 +103,7 @@ private function getPreliminarilyResolvedTypeFromFunctionCall(FunctionReflection } } } + $isStringSuperType = $subjectArgumentType->isString(); $isArraySuperType = $subjectArgumentType->isArray(); $compareSuperTypes = $isStringSuperType->compareTo($isArraySuperType); @@ -97,6 +120,7 @@ private function getPreliminarilyResolvedTypeFromFunctionCall(FunctionReflection } return $subjectArgumentType; } + return $defaultReturnType; } diff --git a/src/Type/Php/RoundFunctionReturnTypeExtension.php b/src/Type/Php/RoundFunctionReturnTypeExtension.php index 29cea71cef9..839c5c15879 100644 --- a/src/Type/Php/RoundFunctionReturnTypeExtension.php +++ b/src/Type/Php/RoundFunctionReturnTypeExtension.php @@ -22,22 +22,21 @@ class RoundFunctionReturnTypeExtension implements DynamicFunctionReturnTypeExtension { - /** - * @var PhpVersion - */ - private $phpVersion; - public function __construct(PhpVersion $phpVersion) + public function __construct(private PhpVersion $phpVersion) { - $this->phpVersion = $phpVersion; } public function isFunctionSupported(FunctionReflection $functionReflection): bool { - return in_array($functionReflection->getName(), [ + return in_array( + $functionReflection->getName(), + [ 'round', 'ceil', 'floor', - ], true); + ], + true, + ); } public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope): Type @@ -68,7 +67,10 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, } if ($this->phpVersion->hasStricterRoundFunctions()) { - $allowed = TypeCombinator::union(new IntegerType(), new FloatType()); + $allowed = TypeCombinator::union( + new IntegerType(), + new FloatType(), + ); if ($allowed->isSuperTypeOf($firstArgType)->no()) { // PHP 8 fatals if the parameter is not an integer or float. return new NeverType(true); diff --git a/src/Type/Php/SprintfFunctionDynamicReturnTypeExtension.php b/src/Type/Php/SprintfFunctionDynamicReturnTypeExtension.php index 5afc0d78f2c..b6084178b37 100644 --- a/src/Type/Php/SprintfFunctionDynamicReturnTypeExtension.php +++ b/src/Type/Php/SprintfFunctionDynamicReturnTypeExtension.php @@ -33,12 +33,17 @@ public function isFunctionSupported(FunctionReflection $functionReflection): boo return in_array($functionReflection->getName(), ['sprintf', 'vsprintf'], true); } - public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope) : ?Type + public function getTypeFromFunctionCall( + FunctionReflection $functionReflection, + FuncCall $functionCall, + Scope $scope, + ): ?Type { $args = $functionCall->getArgs(); if (count($args) === 0) { return null; } + $formatType = $scope->getType($args[0]->value); if (count($formatType->getConstantStrings()) > 0) { $skip = false; @@ -64,6 +69,7 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, ]); } } + if ($formatType->isNonFalsyString()->yes()) { $returnType = new IntersectionType([ new StringType(), @@ -77,6 +83,7 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, } else { $returnType = new StringType(); } + $values = []; foreach ($args as $arg) { $argType = $scope->getType($arg->value); @@ -86,6 +93,7 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, $values[] = $argType->getConstantScalarValues(); } + $combinations = CombinationsHelper::combinations($values); $returnTypes = []; foreach ($combinations as $combination) { @@ -100,13 +108,15 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, } else { $returnTypes[] = $scope->getTypeFromValue(@vsprintf($format, $combination)); } - } catch (Throwable $e) { + } catch (Throwable) { return $returnType; } } + if (count($returnTypes) > InitializerExprTypeResolver::CALCULATE_SCALARS_LIMIT) { return $returnType; } + return TypeCombinator::union(...$returnTypes); } diff --git a/src/Type/Php/SscanfFunctionDynamicReturnTypeExtension.php b/src/Type/Php/SscanfFunctionDynamicReturnTypeExtension.php index a00d3776413..5939bf7ced3 100644 --- a/src/Type/Php/SscanfFunctionDynamicReturnTypeExtension.php +++ b/src/Type/Php/SscanfFunctionDynamicReturnTypeExtension.php @@ -29,16 +29,23 @@ public function isFunctionSupported(FunctionReflection $functionReflection): boo return in_array($functionReflection->getName(), ['sscanf', 'fscanf'], true); } - public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope) : ?Type + public function getTypeFromFunctionCall( + FunctionReflection $functionReflection, + FuncCall $functionCall, + Scope $scope, + ): ?Type { $args = $functionCall->getArgs(); if (count($args) !== 2) { return null; } + $formatType = $scope->getType($args[1]->value); + if (!$formatType instanceof ConstantStringType) { return null; } + if (preg_match_all('/%(\d*)(\[[^\]]+\]|[cdeEfosux]{1})/', $formatType->getValue(), $matches) > 0) { $arrayBuilder = ConstantArrayTypeBuilder::createEmpty(); @@ -75,6 +82,7 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, return TypeCombinator::addNull($arrayBuilder->getArray()); } + return null; } diff --git a/src/Type/Php/StrCaseFunctionsReturnTypeExtension.php b/src/Type/Php/StrCaseFunctionsReturnTypeExtension.php index a587f5f9ade..df1dfc88e97 100644 --- a/src/Type/Php/StrCaseFunctionsReturnTypeExtension.php +++ b/src/Type/Php/StrCaseFunctionsReturnTypeExtension.php @@ -44,36 +44,38 @@ public function isFunctionSupported(FunctionReflection $functionReflection): boo return isset(self::FUNCTIONS[$functionReflection->getName()]); } - public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope) : ?Type + public function getTypeFromFunctionCall( + FunctionReflection $functionReflection, + FuncCall $functionCall, + Scope $scope, + ): ?Type { $fnName = $functionReflection->getName(); $args = $functionCall->getArgs(); + if (count($args) < self::FUNCTIONS[$fnName]) { return null; } + $argType = $scope->getType($args[0]->value); if (!is_callable($fnName)) { return null; } + $modes = []; if ($fnName === 'mb_convert_case') { $modeType = $scope->getType($args[1]->value); - $modes = array_map(static function ($mode) { - return $mode->getValue(); - }, TypeUtils::getConstantIntegers($modeType)); + $modes = array_map(static fn ($mode) => $mode->getValue(), TypeUtils::getConstantIntegers($modeType)); } elseif (in_array($fnName, ['ucwords', 'mb_convert_kana'], true)) { if (count($args) >= 2) { $modeType = $scope->getType($args[1]->value); - $modes = array_map(static function ($mode) { - return $mode->getValue(); - }, $modeType->getConstantStrings()); + $modes = array_map(static fn ($mode) => $mode->getValue(), $modeType->getConstantStrings()); } else { $modes = $fnName === 'mb_convert_kana' ? ['KV'] : [" \t\r\n\f\v"]; } } - $constantStrings = array_map(static function ($type) { - return $type->getValue(); - }, $argType->getConstantStrings()); + + $constantStrings = array_map(static fn ($type) => $type->getValue(), $argType->getConstantStrings()); if (count($constantStrings) > 0 && mb_check_encoding($constantStrings, 'UTF-8')) { $strings = []; @@ -85,9 +87,7 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, } } } else { - $parameters = array_map(static function ($s) { - return [$s]; - }, $constantStrings); + $parameters = array_map(static fn ($s) => [$s], $constantStrings); } foreach ($parameters as $parameter) { @@ -95,29 +95,31 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, } if (count($strings) !== 0 && mb_check_encoding($strings, 'UTF-8')) { - return TypeCombinator::union(...array_map(static function ($s) { - return new ConstantStringType($s); - }, $strings)); + return TypeCombinator::union(...array_map(static fn ($s) => new ConstantStringType($s), $strings)); } } + if ($argType->isNumericString()->yes()) { return new IntersectionType([ new StringType(), new AccessoryNumericStringType(), ]); } + if ($argType->isNonFalsyString()->yes()) { return new IntersectionType([ new StringType(), new AccessoryNonFalsyStringType(), ]); } + if ($argType->isNonEmptyString()->yes()) { return new IntersectionType([ new StringType(), new AccessoryNonEmptyStringType(), ]); } + return new StringType(); } diff --git a/src/Type/Php/StrContainingTypeSpecifyingExtension.php b/src/Type/Php/StrContainingTypeSpecifyingExtension.php index f0a9ee4549c..f7745f2128d 100644 --- a/src/Type/Php/StrContainingTypeSpecifyingExtension.php +++ b/src/Type/Php/StrContainingTypeSpecifyingExtension.php @@ -40,10 +40,7 @@ final class StrContainingTypeSpecifyingExtension implements FunctionTypeSpecifyi 'strstr' => [0, 1], ]; - /** - * @var TypeSpecifier - */ - private $typeSpecifier; + private TypeSpecifier $typeSpecifier; public function setTypeSpecifier(TypeSpecifier $typeSpecifier): void { @@ -84,9 +81,22 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n $accessories[] = new AccessoryNumericStringType(); } - return $this->typeSpecifier->create($args[$hackstackArg]->value, new IntersectionType($accessories), $context, false, $scope, new BooleanAnd(new NotIdentical($args[$needleArg]->value, new String_('')), new FuncCall(new Name('FAUX_FUNCTION'), [ + return $this->typeSpecifier->create( + $args[$hackstackArg]->value, + new IntersectionType($accessories), + $context, + false, + $scope, + new BooleanAnd( + new NotIdentical( + $args[$needleArg]->value, + new String_(''), + ), + new FuncCall(new Name('FAUX_FUNCTION'), [ new Arg($args[$needleArg]->value), - ]))); + ]), + ), + ); } } diff --git a/src/Type/Php/StrIncrementDecrementFunctionReturnTypeExtension.php b/src/Type/Php/StrIncrementDecrementFunctionReturnTypeExtension.php index ecea5592d83..b739263e644 100644 --- a/src/Type/Php/StrIncrementDecrementFunctionReturnTypeExtension.php +++ b/src/Type/Php/StrIncrementDecrementFunctionReturnTypeExtension.php @@ -31,17 +31,24 @@ public function isFunctionSupported(FunctionReflection $functionReflection): boo return in_array($functionReflection->getName(), ['str_increment', 'str_decrement'], true); } - public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope) : ?Type + public function getTypeFromFunctionCall( + FunctionReflection $functionReflection, + FuncCall $functionCall, + Scope $scope, + ): ?Type { $fnName = $functionReflection->getName(); $args = $functionCall->getArgs(); + if (count($args) !== 1) { return null; } + $argType = $scope->getType($args[0]->value); if (count($argType->getConstantScalarValues()) === 0) { return null; } + $types = []; foreach ($argType->getConstantScalarValues() as $value) { if (!(is_string($value) || is_int($value) || is_float($value))) { @@ -66,6 +73,7 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, $types[] = new ConstantStringType($result); } + return count($types) === 0 ? new ErrorType() : TypeCombinator::union(...$types); diff --git a/src/Type/Php/StrPadFunctionReturnTypeExtension.php b/src/Type/Php/StrPadFunctionReturnTypeExtension.php index 5b8581ad5f3..3b11f5130e4 100644 --- a/src/Type/Php/StrPadFunctionReturnTypeExtension.php +++ b/src/Type/Php/StrPadFunctionReturnTypeExtension.php @@ -23,20 +23,27 @@ public function isFunctionSupported(FunctionReflection $functionReflection): boo return $functionReflection->getName() === 'str_pad'; } - public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope) : Type + public function getTypeFromFunctionCall( + FunctionReflection $functionReflection, + FuncCall $functionCall, + Scope $scope, + ): Type { $args = $functionCall->getArgs(); if (count($args) < 2) { return new StringType(); } + $inputType = $scope->getType($args[0]->value); $lengthType = $scope->getType($args[1]->value); + $accessoryTypes = []; if ($inputType->isNonFalsyString()->yes()) { $accessoryTypes[] = new AccessoryNonFalsyStringType(); } elseif ($inputType->isNonEmptyString()->yes() || IntegerRangeType::fromInterval(1, null)->isSuperTypeOf($lengthType)->yes()) { $accessoryTypes[] = new AccessoryNonEmptyStringType(); } + if ($inputType->isLiteralString()->yes()) { if (count($args) < 3) { $accessoryTypes[] = new AccessoryLiteralStringType(); @@ -47,10 +54,12 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, } } } + if (count($accessoryTypes) > 0) { $accessoryTypes[] = new StringType(); return new IntersectionType($accessoryTypes); } + return new StringType(); } diff --git a/src/Type/Php/StrRepeatFunctionReturnTypeExtension.php b/src/Type/Php/StrRepeatFunctionReturnTypeExtension.php index ab756fab65a..6bf696ac118 100644 --- a/src/Type/Php/StrRepeatFunctionReturnTypeExtension.php +++ b/src/Type/Php/StrRepeatFunctionReturnTypeExtension.php @@ -28,20 +28,28 @@ public function isFunctionSupported(FunctionReflection $functionReflection): boo return $functionReflection->getName() === 'str_repeat'; } - public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope) : Type + public function getTypeFromFunctionCall( + FunctionReflection $functionReflection, + FuncCall $functionCall, + Scope $scope, + ): Type { $args = $functionCall->getArgs(); if (count($args) < 2) { return new StringType(); } + $inputType = $scope->getType($args[0]->value); $multiplierType = $scope->getType($args[1]->value); + if ((new ConstantIntegerType(0))->isSuperTypeOf($multiplierType)->yes()) { return new ConstantStringType(''); } + if ($multiplierType instanceof ConstantIntegerType && $multiplierType->getValue() < 0) { return new NeverType(); } + if ( $inputType instanceof ConstantStringType && $multiplierType instanceof ConstantIntegerType @@ -50,6 +58,7 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, ) { return new ConstantStringType(str_repeat($inputType->getValue(), $multiplierType->getValue())); } + $accessoryTypes = []; if ($inputType->isNonEmptyString()->yes()) { if (IntegerRangeType::fromInterval(1, null)->isSuperTypeOf($multiplierType)->yes()) { @@ -60,13 +69,16 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, } } } + if ($inputType->isLiteralString()->yes()) { $accessoryTypes[] = new AccessoryLiteralStringType(); } + if (count($accessoryTypes) > 0) { $accessoryTypes[] = new StringType(); return new IntersectionType($accessoryTypes); } + return new StringType(); } diff --git a/src/Type/Php/StrSplitFunctionReturnTypeExtension.php b/src/Type/Php/StrSplitFunctionReturnTypeExtension.php index 1fe3a6b0ca6..34d58152dcd 100644 --- a/src/Type/Php/StrSplitFunctionReturnTypeExtension.php +++ b/src/Type/Php/StrSplitFunctionReturnTypeExtension.php @@ -32,15 +32,10 @@ final class StrSplitFunctionReturnTypeExtension implements DynamicFunctionReturnTypeExtension { - /** - * @var PhpVersion - */ - private $phpVersion; use MbFunctionsReturnTypeExtensionTrait; - public function __construct(PhpVersion $phpVersion) + public function __construct(private PhpVersion $phpVersion) { - $this->phpVersion = $phpVersion; } public function isFunctionSupported(FunctionReflection $functionReflection): bool @@ -70,9 +65,7 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, if ($functionReflection->getName() === 'mb_str_split') { if (count($functionCall->getArgs()) >= 3) { $strings = $scope->getType($functionCall->getArgs()[2]->value)->getConstantStrings(); - $values = array_unique(array_map(static function (ConstantStringType $encoding) : string { - return $encoding->getValue(); - }, $strings)); + $values = array_unique(array_map(static fn (ConstantStringType $encoding): string => $encoding->getValue(), $strings)); if (count($values) !== 1) { return null; diff --git a/src/Type/Php/StrWordCountFunctionDynamicReturnTypeExtension.php b/src/Type/Php/StrWordCountFunctionDynamicReturnTypeExtension.php index 14a29cc2a8b..96a532ceef3 100644 --- a/src/Type/Php/StrWordCountFunctionDynamicReturnTypeExtension.php +++ b/src/Type/Php/StrWordCountFunctionDynamicReturnTypeExtension.php @@ -24,7 +24,11 @@ public function isFunctionSupported(FunctionReflection $functionReflection): boo return $functionReflection->getName() === 'str_word_count'; } - public function getTypeFromFunctionCall(FunctionReflection $functionReflection, Node\Expr\FuncCall $functionCall, Scope $scope) : Type + public function getTypeFromFunctionCall( + FunctionReflection $functionReflection, + Node\Expr\FuncCall $functionCall, + Scope $scope, + ): Type { $argsCount = count($functionCall->getArgs()); if ($argsCount === 1) { @@ -53,6 +57,7 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, new ConstantBooleanType(false), ]); } + // else fatal error; too many or too few arguments return new ErrorType(); } diff --git a/src/Type/Php/StrlenFunctionReturnTypeExtension.php b/src/Type/Php/StrlenFunctionReturnTypeExtension.php index a3db713b9c8..fa2c1eb2ffe 100644 --- a/src/Type/Php/StrlenFunctionReturnTypeExtension.php +++ b/src/Type/Php/StrlenFunctionReturnTypeExtension.php @@ -26,13 +26,19 @@ public function isFunctionSupported(FunctionReflection $functionReflection): boo return $functionReflection->getName() === 'strlen'; } - public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope) : ?Type + public function getTypeFromFunctionCall( + FunctionReflection $functionReflection, + FuncCall $functionCall, + Scope $scope, + ): ?Type { $args = $functionCall->getArgs(); if (count($args) === 0) { return null; } + $argType = $scope->getType($args[0]->value); + if ($argType->isSuperTypeOf(new BooleanType())->yes()) { $constantScalars = TypeCombinator::remove($argType, new BooleanType())->getConstantScalarTypes(); if (count($constantScalars) > 0) { @@ -42,6 +48,7 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, } else { $constantScalars = $argType->getConstantScalarTypes(); } + $min = null; $max = null; foreach ($constantScalars as $constantScalar) { @@ -66,14 +73,17 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, $max = $len; } + // $max is always != null, when $min is != null if ($min !== null) { return IntegerRangeType::fromInterval($min, $max); } + $bool = new BooleanType(); if ($bool->isSuperTypeOf($argType)->yes()) { return IntegerRangeType::fromInterval(0, 1); } + $isNonEmpty = $argType->isNonEmptyString(); $numeric = TypeCombinator::union(new IntegerType(), new FloatType()); if ( @@ -83,9 +93,11 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, ) { return IntegerRangeType::fromInterval(1, null); } + if ($argType->isString()->yes() && $isNonEmpty->no()) { return new ConstantIntegerType(0); } + return null; } diff --git a/src/Type/Php/StrtotimeFunctionReturnTypeExtension.php b/src/Type/Php/StrtotimeFunctionReturnTypeExtension.php index a5062092ac6..ef5e1af7871 100644 --- a/src/Type/Php/StrtotimeFunctionReturnTypeExtension.php +++ b/src/Type/Php/StrtotimeFunctionReturnTypeExtension.php @@ -39,12 +39,8 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, if ($argType instanceof MixedType) { return TypeUtils::toBenevolentUnion($defaultReturnType); } - $results = array_unique(array_map(static function (ConstantStringType $string) { - return strtotime($string->getValue()); - }, $argType->getConstantStrings())); - $resultTypes = array_unique(array_map(static function ($value) : string { - return gettype($value); - }, $results)); + $results = array_unique(array_map(static fn (ConstantStringType $string): int|bool => strtotime($string->getValue()), $argType->getConstantStrings())); + $resultTypes = array_unique(array_map(static fn (int|bool $value): string => gettype($value), $results)); if (count($resultTypes) !== 1 || count($results) === 0) { return $defaultReturnType; diff --git a/src/Type/Php/StrvalFamilyFunctionReturnTypeExtension.php b/src/Type/Php/StrvalFamilyFunctionReturnTypeExtension.php index 38a1dd5e569..3328313d9a6 100644 --- a/src/Type/Php/StrvalFamilyFunctionReturnTypeExtension.php +++ b/src/Type/Php/StrvalFamilyFunctionReturnTypeExtension.php @@ -31,12 +31,18 @@ public function isFunctionSupported(FunctionReflection $functionReflection): boo return in_array($functionReflection->getName(), self::FUNCTIONS, true); } - public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope) : Type + public function getTypeFromFunctionCall( + FunctionReflection $functionReflection, + FuncCall $functionCall, + Scope $scope, + ): Type { if (count($functionCall->getArgs()) === 0) { return new NullType(); } + $argType = $scope->getType($functionCall->getArgs()[0]->value); + switch ($functionReflection->getName()) { case 'strval': return $argType->toString(); diff --git a/src/Type/Php/SubstrDynamicReturnTypeExtension.php b/src/Type/Php/SubstrDynamicReturnTypeExtension.php index 097818c816d..de54d526fb1 100644 --- a/src/Type/Php/SubstrDynamicReturnTypeExtension.php +++ b/src/Type/Php/SubstrDynamicReturnTypeExtension.php @@ -28,12 +28,17 @@ public function isFunctionSupported(FunctionReflection $functionReflection): boo return $functionReflection->getName() === 'substr'; } - public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope) : ?Type + public function getTypeFromFunctionCall( + FunctionReflection $functionReflection, + FuncCall $functionCall, + Scope $scope, + ): ?Type { $args = $functionCall->getArgs(); if (count($args) === 0) { return null; } + if (count($args) >= 2) { $string = $scope->getType($args[0]->value); $offset = $scope->getType($args[1]->value); @@ -57,9 +62,16 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, $results = []; foreach ($constantStrings as $constantString) { if ($length !== null) { - $substr = substr($constantString->getValue(), $offset->getValue(), $length->getValue()); + $substr = substr( + $constantString->getValue(), + $offset->getValue(), + $length->getValue(), + ); } else { - $substr = substr($constantString->getValue(), $offset->getValue()); + $substr = substr( + $constantString->getValue(), + $offset->getValue(), + ); } if (is_bool($substr)) { @@ -86,6 +98,7 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, ]); } } + return null; } diff --git a/src/Type/Php/TriggerErrorDynamicReturnTypeExtension.php b/src/Type/Php/TriggerErrorDynamicReturnTypeExtension.php index fe2f22ad1a5..1df3f180e5e 100644 --- a/src/Type/Php/TriggerErrorDynamicReturnTypeExtension.php +++ b/src/Type/Php/TriggerErrorDynamicReturnTypeExtension.php @@ -21,13 +21,8 @@ class TriggerErrorDynamicReturnTypeExtension implements DynamicFunctionReturnTypeExtension { - /** - * @var PhpVersion - */ - private $phpVersion; - public function __construct(PhpVersion $phpVersion) + public function __construct(private PhpVersion $phpVersion) { - $this->phpVersion = $phpVersion; } public function isFunctionSupported(FunctionReflection $functionReflection): bool diff --git a/src/Type/Php/TypeSpecifyingFunctionsDynamicReturnTypeExtension.php b/src/Type/Php/TypeSpecifyingFunctionsDynamicReturnTypeExtension.php index 74db8e51ea8..380cfb5b599 100644 --- a/src/Type/Php/TypeSpecifyingFunctionsDynamicReturnTypeExtension.php +++ b/src/Type/Php/TypeSpecifyingFunctionsDynamicReturnTypeExtension.php @@ -18,41 +18,15 @@ class TypeSpecifyingFunctionsDynamicReturnTypeExtension implements DynamicFunctionReturnTypeExtension, TypeSpecifierAwareExtension { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - /** - * @var bool - */ - private $treatPhpDocTypesAsCertain; - /** - * @var string[] - */ - private $universalObjectCratesClasses; - /** - * @var bool - */ - private $nullContextForVoidReturningFunctions; - /** - * @var TypeSpecifier - */ - private $typeSpecifier; + private TypeSpecifier $typeSpecifier; - /** - * @var ?ImpossibleCheckTypeHelper - */ - private $helper = null; + private ?ImpossibleCheckTypeHelper $helper = null; /** * @param string[] $universalObjectCratesClasses */ - public function __construct(ReflectionProvider $reflectionProvider, bool $treatPhpDocTypesAsCertain, array $universalObjectCratesClasses, bool $nullContextForVoidReturningFunctions) + public function __construct(private ReflectionProvider $reflectionProvider, private bool $treatPhpDocTypesAsCertain, private array $universalObjectCratesClasses, private bool $nullContextForVoidReturningFunctions) { - $this->reflectionProvider = $reflectionProvider; - $this->treatPhpDocTypesAsCertain = $treatPhpDocTypesAsCertain; - $this->universalObjectCratesClasses = $universalObjectCratesClasses; - $this->nullContextForVoidReturningFunctions = $nullContextForVoidReturningFunctions; } public function setTypeSpecifier(TypeSpecifier $typeSpecifier): void @@ -70,15 +44,24 @@ public function isFunctionSupported(FunctionReflection $functionReflection): boo ], true); } - public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope) : ?Type + public function getTypeFromFunctionCall( + FunctionReflection $functionReflection, + FuncCall $functionCall, + Scope $scope, + ): ?Type { if (count($functionCall->getArgs()) === 0) { return null; } - $isAlways = $this->getHelper()->findSpecifiedType($scope, $functionCall); + + $isAlways = $this->getHelper()->findSpecifiedType( + $scope, + $functionCall, + ); if ($isAlways === null) { return null; } + return new ConstantBooleanType($isAlways); } diff --git a/src/Type/Php/VersionCompareFunctionDynamicReturnTypeExtension.php b/src/Type/Php/VersionCompareFunctionDynamicReturnTypeExtension.php index 28d07c1e85f..b8a77540cb3 100644 --- a/src/Type/Php/VersionCompareFunctionDynamicReturnTypeExtension.php +++ b/src/Type/Php/VersionCompareFunctionDynamicReturnTypeExtension.php @@ -23,34 +23,43 @@ public function isFunctionSupported(FunctionReflection $functionReflection): boo return $functionReflection->getName() === 'version_compare'; } - public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope) : ?Type + public function getTypeFromFunctionCall( + FunctionReflection $functionReflection, + FuncCall $functionCall, + Scope $scope, + ): ?Type { if (count($functionCall->getArgs()) < 2) { return null; } + $version1Strings = $scope->getType($functionCall->getArgs()[0]->value)->getConstantStrings(); $version2Strings = $scope->getType($functionCall->getArgs()[1]->value)->getConstantStrings(); $counts = [ count($version1Strings), count($version2Strings), ]; + if (isset($functionCall->getArgs()[2])) { $operatorStrings = $scope->getType($functionCall->getArgs()[2]->value)->getConstantStrings(); $counts[] = count($operatorStrings); $returnType = new BooleanType(); } else { - $returnType = TypeCombinator::union(new ConstantIntegerType(-1), new ConstantIntegerType(0), new ConstantIntegerType(1)); + $returnType = TypeCombinator::union( + new ConstantIntegerType(-1), + new ConstantIntegerType(0), + new ConstantIntegerType(1), + ); } - if (count(array_filter($counts, static function (int $count) : bool { - return $count === 0; - })) > 0) { + + if (count(array_filter($counts, static fn (int $count): bool => $count === 0)) > 0) { return $returnType; // one of the arguments is not a constant string } - if (count(array_filter($counts, static function (int $count) : bool { - return $count > 1; - })) > 1) { + + if (count(array_filter($counts, static fn (int $count): bool => $count > 1)) > 1) { return $returnType; // more than one argument can have multiple possibilities, avoid combinatorial explosion } + $types = []; foreach ($version1Strings as $version1String) { foreach ($version2Strings as $version2String) { diff --git a/src/Type/RecursionGuard.php b/src/Type/RecursionGuard.php index d7b4e0245cf..2149fb1015d 100644 --- a/src/Type/RecursionGuard.php +++ b/src/Type/RecursionGuard.php @@ -6,7 +6,7 @@ class RecursionGuard { /** @var true[] */ - private static $context = []; + private static array $context = []; /** * @param callable(): Type $callback diff --git a/src/Type/ResourceType.php b/src/Type/ResourceType.php index c37fe08b7fa..0eee8cea5fe 100644 --- a/src/Type/ResourceType.php +++ b/src/Type/ResourceType.php @@ -72,7 +72,13 @@ public function toFloat(): Type public function toArray(): Type { - return new ConstantArrayType([new ConstantIntegerType(0)], [$this], [1], [], TrinaryLogic::createYes()); + return new ConstantArrayType( + [new ConstantIntegerType(0)], + [$this], + [1], + [], + TrinaryLogic::createYes(), + ); } public function toArrayKey(): Type diff --git a/src/Type/StaticType.php b/src/Type/StaticType.php index 0e028cd036a..80d324e3e46 100644 --- a/src/Type/StaticType.php +++ b/src/Type/StaticType.php @@ -29,41 +29,31 @@ class StaticType implements TypeWithClassName, SubtractableType { - /** - * @var ClassReflection - */ - private $classReflection; - use NonGenericTypeTrait; + use NonGenericTypeTrait; use UndecidedComparisonTypeTrait; use NonGeneralizableTypeTrait; - /** - * @var ?Type - */ - private $subtractedType; + private ?Type $subtractedType; - /** - * @var ?ObjectType - */ - private $staticObjectType = null; + private ?ObjectType $staticObjectType = null; - /** - * @var string - */ - private $baseClass; + private string $baseClass; /** - * @api - */ - public function __construct(ClassReflection $classReflection, ?Type $subtractedType = null) - { - $this->classReflection = $classReflection; - if ($subtractedType instanceof NeverType) { - $subtractedType = null; - } - $this->subtractedType = $subtractedType; - $this->baseClass = $classReflection->getName(); - } + * @api + */ + public function __construct( + private ClassReflection $classReflection, + ?Type $subtractedType = null, + ) + { + if ($subtractedType instanceof NeverType) { + $subtractedType = null; + } + + $this->subtractedType = $subtractedType; + $this->baseClass = $classReflection->getName(); + } public function getClassName(): string { @@ -94,11 +84,15 @@ public function getStaticObjectType(): ObjectType { if ($this->staticObjectType === null) { if ($this->classReflection->isGeneric()) { - $typeMap = $this->classReflection->getActiveTemplateTypeMap()->map(static function (string $name, Type $type) : Type { - return TemplateTypeHelper::toArgument($type); - }); + $typeMap = $this->classReflection->getActiveTemplateTypeMap()->map(static fn (string $name, Type $type): Type => TemplateTypeHelper::toArgument($type)); $varianceMap = $this->classReflection->getCallSiteVarianceMap(); - return $this->staticObjectType = new GenericObjectType($this->classReflection->getName(), $this->classReflection->typeMapToList($typeMap), $this->subtractedType, null, $this->classReflection->varianceMapToList($varianceMap)); + return $this->staticObjectType = new GenericObjectType( + $this->classReflection->getName(), + $this->classReflection->typeMapToList($typeMap), + $this->subtractedType, + null, + $this->classReflection->varianceMapToList($varianceMap), + ); } return $this->staticObjectType = new ObjectType($this->classReflection->getName(), $this->subtractedType, $this->classReflection); @@ -108,9 +102,9 @@ public function getStaticObjectType(): ObjectType } /** - * @return string[] - */ - public function getReferencedClasses(): array + * @return string[] + */ + public function getReferencedClasses(): array { return $this->getStaticObjectType()->getReferencedClasses(); } @@ -245,9 +239,12 @@ public function getUnresolvedPropertyPrototype(string $propertyName, ClassMember $classReflection = $nakedProperty->getDeclaringClass(); } - return new CallbackUnresolvedPropertyPrototypeReflection($nakedProperty, $classReflection, false, function (Type $type) use($scope) : Type { - return $this->transformStaticType($type, $scope); - }); + return new CallbackUnresolvedPropertyPrototypeReflection( + $nakedProperty, + $classReflection, + false, + fn (Type $type): Type => $this->transformStaticType($type, $scope), + ); } public function canCallMethods(): TrinaryLogic @@ -279,9 +276,12 @@ public function getUnresolvedMethodPrototype(string $methodName, ClassMemberAcce $classReflection = $nakedMethod->getDeclaringClass(); } - return new CallbackUnresolvedMethodPrototypeReflection($nakedMethod, $classReflection, false, function (Type $type) use($scope) : Type { - return $this->transformStaticType($type, $scope); - }); + return new CallbackUnresolvedMethodPrototypeReflection( + $nakedMethod, + $classReflection, + false, + fn (Type $type): Type => $this->transformStaticType($type, $scope), + ); } private function transformStaticType(Type $type, ClassMemberAccessAnswerer $scope): Type @@ -577,9 +577,9 @@ public function looseCompare(Type $type, PhpVersion $phpVersion): BooleanType } /** - * @return ParametersAcceptor[] - */ - public function getCallableParametersAcceptors(ClassMemberAccessAnswerer $scope): array + * @return ParametersAcceptor[] + */ + public function getCallableParametersAcceptors(ClassMemberAccessAnswerer $scope): array { return $this->getStaticObjectType()->getCallableParametersAcceptors($scope); } @@ -629,7 +629,10 @@ public function traverse(callable $cb): Type $subtractedType = $this->subtractedType !== null ? $cb($this->subtractedType) : null; if ($subtractedType !== $this->subtractedType) { - return new self($this->classReflection, $subtractedType); + return new self( + $this->classReflection, + $subtractedType, + ); } return $this; @@ -709,9 +712,9 @@ public function toPhpDocNode(): TypeNode } /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): Type + * @param mixed[] $properties + */ + public static function __set_state(array $properties): Type { $reflectionProvider = ReflectionProviderStaticAccessor::getInstance(); if ($reflectionProvider->hasClass($properties['baseClass'])) { diff --git a/src/Type/StrictMixedType.php b/src/Type/StrictMixedType.php index aa7e79e610a..71d93671a6f 100644 --- a/src/Type/StrictMixedType.php +++ b/src/Type/StrictMixedType.php @@ -102,15 +102,12 @@ public function equals(Type $type): bool public function describe(VerbosityLevel $level): string { - return $level->handle(static function () { - return 'mixed'; - }, static function () { - return 'mixed'; - }, static function () { - return 'mixed'; - }, static function () { - return 'strict-mixed'; - }); + return $level->handle( + static fn () => 'mixed', + static fn () => 'mixed', + static fn () => 'mixed', + static fn () => 'strict-mixed', + ); } public function getTemplateType(string $ancestorClassName, string $templateTypeName): Type diff --git a/src/Type/StringType.php b/src/Type/StringType.php index a63bc73420d..7e08d4063ba 100644 --- a/src/Type/StringType.php +++ b/src/Type/StringType.php @@ -123,7 +123,9 @@ public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult } $typeClass = $reflectionProvider->getClass($thatClassNames[0]); - return AcceptsResult::createFromBoolean($typeClass->hasNativeMethod('__toString')); + return AcceptsResult::createFromBoolean( + $typeClass->hasNativeMethod('__toString'), + ); } public function toNumber(): Type @@ -148,7 +150,13 @@ public function toString(): Type public function toArray(): Type { - return new ConstantArrayType([new ConstantIntegerType(0)], [$this], [1], [], TrinaryLogic::createYes()); + return new ConstantArrayType( + [new ConstantIntegerType(0)], + [$this], + [1], + [], + TrinaryLogic::createYes(), + ); } public function toArrayKey(): Type diff --git a/src/Type/ThisType.php b/src/Type/ThisType.php index 9ad13ca836e..963f98c1918 100644 --- a/src/Type/ThisType.php +++ b/src/Type/ThisType.php @@ -16,7 +16,10 @@ class ThisType extends StaticType /** * @api */ - public function __construct(ClassReflection $classReflection, ?Type $subtractedType = null) + public function __construct( + ClassReflection $classReflection, + ?Type $subtractedType = null, + ) { parent::__construct($classReflection, $subtractedType); } @@ -61,7 +64,10 @@ public function traverse(callable $cb): Type $subtractedType = $this->getSubtractedType() !== null ? $cb($this->getSubtractedType()) : null; if ($subtractedType !== $this->getSubtractedType()) { - return new self($this->getClassReflection(), $subtractedType); + return new self( + $this->getClassReflection(), + $subtractedType, + ); } return $this; diff --git a/src/Type/Traits/LateResolvableTypeTrait.php b/src/Type/Traits/LateResolvableTypeTrait.php index 14cb48853cf..144938fd618 100644 --- a/src/Type/Traits/LateResolvableTypeTrait.php +++ b/src/Type/Traits/LateResolvableTypeTrait.php @@ -21,10 +21,7 @@ trait LateResolvableTypeTrait { - /** - * @var ?Type - */ - private $result = null; + private ?Type $result = null; public function getObjectClassNames(): array { diff --git a/src/Type/Traits/MaybeObjectTypeTrait.php b/src/Type/Traits/MaybeObjectTypeTrait.php index 135bc369db0..b8097947b4e 100644 --- a/src/Type/Traits/MaybeObjectTypeTrait.php +++ b/src/Type/Traits/MaybeObjectTypeTrait.php @@ -53,9 +53,12 @@ public function getProperty(string $propertyName, ClassMemberAccessAnswerer $sco public function getUnresolvedPropertyPrototype(string $propertyName, ClassMemberAccessAnswerer $scope): UnresolvedPropertyPrototypeReflection { $property = new DummyPropertyReflection(); - return new CallbackUnresolvedPropertyPrototypeReflection($property, $property->getDeclaringClass(), false, static function (Type $type) : Type { - return $type; - }); + return new CallbackUnresolvedPropertyPrototypeReflection( + $property, + $property->getDeclaringClass(), + false, + static fn (Type $type): Type => $type, + ); } public function canCallMethods(): TrinaryLogic @@ -76,9 +79,12 @@ public function getMethod(string $methodName, ClassMemberAccessAnswerer $scope): public function getUnresolvedMethodPrototype(string $methodName, ClassMemberAccessAnswerer $scope): UnresolvedMethodPrototypeReflection { $method = new DummyMethodReflection($methodName); - return new CallbackUnresolvedMethodPrototypeReflection($method, $method->getDeclaringClass(), false, static function (Type $type) : Type { - return $type; - }); + return new CallbackUnresolvedMethodPrototypeReflection( + $method, + $method->getDeclaringClass(), + false, + static fn (Type $type): Type => $type, + ); } public function canAccessConstants(): TrinaryLogic diff --git a/src/Type/Traits/NonGeneralizableTypeTrait.php b/src/Type/Traits/NonGeneralizableTypeTrait.php index ef9edafae64..e943051c95c 100644 --- a/src/Type/Traits/NonGeneralizableTypeTrait.php +++ b/src/Type/Traits/NonGeneralizableTypeTrait.php @@ -10,9 +10,7 @@ trait NonGeneralizableTypeTrait public function generalize(GeneralizePrecision $precision): Type { - return $this->traverse(static function (Type $type) use($precision) { - return $type->generalize($precision); - }); + return $this->traverse(static fn (Type $type) => $type->generalize($precision)); } } diff --git a/src/Type/Traits/ObjectTypeTrait.php b/src/Type/Traits/ObjectTypeTrait.php index 79f16447d73..8105cd0555b 100644 --- a/src/Type/Traits/ObjectTypeTrait.php +++ b/src/Type/Traits/ObjectTypeTrait.php @@ -64,9 +64,12 @@ public function getProperty(string $propertyName, ClassMemberAccessAnswerer $sco public function getUnresolvedPropertyPrototype(string $propertyName, ClassMemberAccessAnswerer $scope): UnresolvedPropertyPrototypeReflection { $property = new DummyPropertyReflection(); - return new CallbackUnresolvedPropertyPrototypeReflection($property, $property->getDeclaringClass(), false, static function (Type $type) : Type { - return $type; - }); + return new CallbackUnresolvedPropertyPrototypeReflection( + $property, + $property->getDeclaringClass(), + false, + static fn (Type $type): Type => $type, + ); } public function canCallMethods(): TrinaryLogic @@ -87,9 +90,12 @@ public function getMethod(string $methodName, ClassMemberAccessAnswerer $scope): public function getUnresolvedMethodPrototype(string $methodName, ClassMemberAccessAnswerer $scope): UnresolvedMethodPrototypeReflection { $method = new DummyMethodReflection($methodName); - return new CallbackUnresolvedMethodPrototypeReflection($method, $method->getDeclaringClass(), false, static function (Type $type) : Type { - return $type; - }); + return new CallbackUnresolvedMethodPrototypeReflection( + $method, + $method->getDeclaringClass(), + false, + static fn (Type $type): Type => $type, + ); } public function canAccessConstants(): TrinaryLogic diff --git a/src/Type/TypeAlias.php b/src/Type/TypeAlias.php index 653b9eb7c84..10d6c099225 100644 --- a/src/Type/TypeAlias.php +++ b/src/Type/TypeAlias.php @@ -10,23 +10,13 @@ class TypeAlias { - /** - * @var TypeNode - */ - private $typeNode; - /** - * @var NameScope - */ - private $nameScope; - /** - * @var ?Type - */ - private $resolvedType = null; - - public function __construct(TypeNode $typeNode, NameScope $nameScope) + private ?Type $resolvedType = null; + + public function __construct( + private TypeNode $typeNode, + private NameScope $nameScope, + ) { - $this->typeNode = $typeNode; - $this->nameScope = $nameScope; } public static function invalid(): self @@ -39,7 +29,10 @@ public static function invalid(): self public function resolve(TypeNodeResolver $typeNodeResolver): Type { if ($this->resolvedType === null) { - $this->resolvedType = $typeNodeResolver->resolve($this->typeNode, $this->nameScope); + $this->resolvedType = $typeNodeResolver->resolve( + $this->typeNode, + $this->nameScope, + ); } return $this->resolvedType; diff --git a/src/Type/TypeCombinator.php b/src/Type/TypeCombinator.php index d6c3a196c20..5c8e461cfa6 100644 --- a/src/Type/TypeCombinator.php +++ b/src/Type/TypeCombinator.php @@ -271,7 +271,10 @@ public static function union(Type ...$types): Type $types = array_values($newTypes); } - $types = array_merge($types, self::processArrayTypes($arrayTypes)); + $types = array_merge( + $types, + self::processArrayTypes($arrayTypes), + ); $typesCount = count($types); // transform A | A to A @@ -398,7 +401,10 @@ private static function compareTypesInUnion(Type $a, Type $b): ?array // simplify string[] | int[] to (string|int)[] if ($a instanceof IterableType && $b instanceof IterableType) { return [ - new IterableType(self::union($a->getIterableKeyType(), $b->getIterableKeyType()), self::union($a->getIterableValueType(), $b->getIterableValueType())), + new IterableType( + self::union($a->getIterableKeyType(), $b->getIterableKeyType()), + self::union($a->getIterableValueType(), $b->getIterableValueType()), + ), null, ]; } @@ -480,11 +486,15 @@ private static function compareTypesInUnion(Type $a, Type $b): ?array return null; } - private static function unionWithSubtractedType(Type $type, ?Type $subtractedType) : Type + private static function unionWithSubtractedType( + Type $type, + ?Type $subtractedType, + ): Type { if ($subtractedType === null) { return $type; } + if ($type instanceof SubtractableType) { $subtractedType = $type->getSubtractedType() === null ? $subtractedType @@ -495,17 +505,23 @@ private static function unionWithSubtractedType(Type $type, ?Type $subtractedTyp return $type->changeSubtractedType($subtractedType); } + if ($subtractedType->isSuperTypeOf($type)->yes()) { return new NeverType(); } + return self::remove($type, $subtractedType); } - private static function intersectWithSubtractedType(SubtractableType $a, Type $b) : Type + private static function intersectWithSubtractedType( + SubtractableType $a, + Type $b, + ): Type { if ($a->getSubtractedType() === null) { return $a; } + if ($b instanceof IntersectionType) { $subtractableTypes = []; foreach ($b->getTypes() as $innerType) { @@ -547,10 +563,15 @@ private static function intersectWithSubtractedType(SubtractableType $a, Type $b } $subtractedType = new MixedType(false, $b); } - $subtractedType = self::intersect($a->getSubtractedType(), $subtractedType); + + $subtractedType = self::intersect( + $a->getSubtractedType(), + $subtractedType, + ); if ($subtractedType instanceof NeverType) { $subtractedType = null; } + return $a->changeSubtractedType($subtractedType); } @@ -690,11 +711,20 @@ private static function processArrayTypes(array $arrayTypes): array $scopes[$arrayType->getScope()->describe()] = $arrayType; } - $arrayType = new ArrayType(self::union(...$keyTypesForGeneralArray), self::union(...self::optimizeConstantArrays($valueTypesForGeneralArray))); + $arrayType = new ArrayType( + self::union(...$keyTypesForGeneralArray), + self::union(...self::optimizeConstantArrays($valueTypesForGeneralArray)), + ); if ($useTemplateArray && count($scopes) === 1) { $templateArray = array_values($scopes)[0]; - $arrayType = new TemplateArrayType($templateArray->getScope(), $templateArray->getStrategy(), $templateArray->getVariance(), $templateArray->getName(), $arrayType); + $arrayType = new TemplateArrayType( + $templateArray->getScope(), + $templateArray->getStrategy(), + $templateArray->getVariance(), + $templateArray->getName(), + $arrayType, + ); } return [ @@ -704,9 +734,10 @@ private static function processArrayTypes(array $arrayTypes): array $reducedArrayTypes = self::reduceArrays($arrayTypes); - return array_map(static function (Type $arrayType) use($accessoryTypes) { - return self::intersect($arrayType, ...$accessoryTypes); - }, self::optimizeConstantArrays($reducedArrayTypes)); + return array_map( + static fn (Type $arrayType) => self::intersect($arrayType, ...$accessoryTypes), + self::optimizeConstantArrays($reducedArrayTypes), + ); } /** @@ -832,7 +863,7 @@ private static function reduceArrays(array $constantArrays): array foreach ($arraysToProcessPerKey as $arrays) { for ($i = 0, $arraysCount = count($arrays); $i < $arraysCount - 1; $i++) { for ($j = $i + 1; $j < $arraysCount; $j++) { - $eligibleCombinations[$arrays[$i]][$arrays[$j]] = $eligibleCombinations[$arrays[$i]][$arrays[$j]] ?? 0; + $eligibleCombinations[$arrays[$i]][$arrays[$j]] ??= 0; $eligibleCombinations[$arrays[$i]][$arrays[$j]]++; } } @@ -917,7 +948,11 @@ public static function intersect(Type ...$types): Type $slice1 = array_slice($types, 0, $i); $slice2 = array_slice($types, $i + 1); foreach ($innerTypes as $innerUnionSubType) { - $topLevelUnionSubTypes[] = self::intersect($innerUnionSubType, ...$slice1, ...$slice2); + $topLevelUnionSubTypes[] = self::intersect( + $innerUnionSubType, + ...$slice1, + ...$slice2, + ); } $union = self::union(...$topLevelUnionSubTypes); @@ -930,7 +965,13 @@ public static function intersect(Type ...$types): Type } if ($type instanceof TemplateUnionType || $type instanceof TemplateBenevolentUnionType) { - $union = TemplateTypeFactory::create($type->getScope(), $type->getName(), $union, $type->getVariance(), $type->getStrategy()); + $union = TemplateTypeFactory::create( + $type->getScope(), + $type->getName(), + $union, + $type->getVariance(), + $type->getStrategy(), + ); } return $union; @@ -1127,7 +1168,11 @@ public static function intersect(Type ...$types): Type $newArray = ConstantArrayTypeBuilder::createEmpty(); $valueTypes = $types[$i]->getValueTypes(); foreach ($types[$i]->getKeyTypes() as $k => $keyType) { - $newArray->setOffsetValueType(self::intersect($keyType, $types[$j]->getIterableKeyType()), self::intersect($valueTypes[$k], $types[$j]->getIterableValueType()), $types[$i]->isOptionalKey($k) && !$types[$j]->hasOffsetValueType($keyType)->yes()); + $newArray->setOffsetValueType( + self::intersect($keyType, $types[$j]->getIterableKeyType()), + self::intersect($valueTypes[$k], $types[$j]->getIterableValueType()), + $types[$i]->isOptionalKey($k) && !$types[$j]->hasOffsetValueType($keyType)->yes(), + ); } $types[$i] = $newArray->getArray(); array_splice($types, $j--, 1); @@ -1139,7 +1184,11 @@ public static function intersect(Type ...$types): Type $newArray = ConstantArrayTypeBuilder::createEmpty(); $valueTypes = $types[$j]->getValueTypes(); foreach ($types[$j]->getKeyTypes() as $k => $keyType) { - $newArray->setOffsetValueType(self::intersect($keyType, $types[$i]->getIterableKeyType()), self::intersect($valueTypes[$k], $types[$i]->getIterableValueType()), $types[$j]->isOptionalKey($k) && !$types[$i]->hasOffsetValueType($keyType)->yes()); + $newArray->setOffsetValueType( + self::intersect($keyType, $types[$i]->getIterableKeyType()), + self::intersect($valueTypes[$k], $types[$i]->getIterableValueType()), + $types[$j]->isOptionalKey($k) && !$types[$i]->hasOffsetValueType($keyType)->yes(), + ); } $types[$j] = $newArray->getArray(); array_splice($types, $i--, 1); diff --git a/src/Type/TypeUtils.php b/src/Type/TypeUtils.php index 5860021b5a0..c16822e0a4f 100644 --- a/src/Type/TypeUtils.php +++ b/src/Type/TypeUtils.php @@ -212,11 +212,17 @@ public static function getOldConstantArrays(Type $type): array /** * @return mixed[] */ - private static function map(string $typeClass, Type $type, bool $inspectIntersections, bool $stopOnUnmatched = true) : array + private static function map( + string $typeClass, + Type $type, + bool $inspectIntersections, + bool $stopOnUnmatched = true, + ): array { if ($type instanceof $typeClass) { return [$type]; } + if ($type instanceof UnionType) { $matchingTypes = []; foreach ($type->getTypes() as $innerType) { @@ -237,6 +243,7 @@ private static function map(string $typeClass, Type $type, bool $inspectIntersec return $matchingTypes; } + if ($inspectIntersections && $type instanceof IntersectionType) { $matchingTypes = []; foreach ($type->getTypes() as $innerType) { @@ -253,6 +260,7 @@ private static function map(string $typeClass, Type $type, bool $inspectIntersec return $matchingTypes; } + return []; } @@ -275,7 +283,13 @@ public static function toBenevolentUnion(Type $type): Type public static function toStrictUnion(Type $type): Type { if ($type instanceof TemplateBenevolentUnionType) { - return new TemplateUnionType($type->getScope(), $type->getStrategy(), $type->getVariance(), $type->getName(), static::toStrictUnion($type->getBound())); + return new TemplateUnionType( + $type->getScope(), + $type->getStrategy(), + $type->getVariance(), + $type->getName(), + static::toStrictUnion($type->getBound()), + ); } if ($type instanceof BenevolentUnionType) { diff --git a/src/Type/TypehintHelper.php b/src/Type/TypehintHelper.php index 8120d11b6ef..03cc1c9d5f1 100644 --- a/src/Type/TypehintHelper.php +++ b/src/Type/TypehintHelper.php @@ -22,10 +22,7 @@ class TypehintHelper { - /** - * @param ClassReflection|string|null $selfClass - */ - private static function getTypeObjectFromTypehint(string $typeString, $selfClass): Type + private static function getTypeObjectFromTypehint(string $typeString, ClassReflection|string|null $selfClass): Type { switch (strtolower($typeString)) { case 'int': @@ -95,9 +92,13 @@ private static function getTypeObjectFromTypehint(string $typeString, $selfClass } } - /** @api - *@param ClassReflection|string|null $selfClass */ - public static function decideTypeFromReflection(?ReflectionType $reflectionType, ?Type $phpDocType = null, $selfClass = null, bool $isVariadic = false) : Type + /** @api */ + public static function decideTypeFromReflection( + ?ReflectionType $reflectionType, + ?Type $phpDocType = null, + ClassReflection|string|null $selfClass = null, + bool $isVariadic = false, + ): Type { if ($reflectionType === null) { if ($isVariadic && $phpDocType instanceof ArrayType) { @@ -105,13 +106,13 @@ public static function decideTypeFromReflection(?ReflectionType $reflectionType, } return $phpDocType ?? new MixedType(); } + if ($reflectionType instanceof ReflectionUnionType) { - $type = TypeCombinator::union(...array_map(static function (ReflectionType $type) use($selfClass) : Type { - return self::decideTypeFromReflection($type, null, $selfClass, false); - }, $reflectionType->getTypes())); + $type = TypeCombinator::union(...array_map(static fn (ReflectionType $type): Type => self::decideTypeFromReflection($type, null, $selfClass, false), $reflectionType->getTypes())); return self::decideType($type, $phpDocType); } + if ($reflectionType instanceof ReflectionIntersectionType) { $types = []; foreach ($reflectionType->getTypes() as $innerReflectionType) { @@ -125,9 +126,11 @@ public static function decideTypeFromReflection(?ReflectionType $reflectionType, return self::decideType(TypeCombinator::intersect(...$types), $phpDocType); } + if (!$reflectionType instanceof ReflectionNamedType) { throw new ShouldNotHappenException(sprintf('Unexpected type: %s', get_class($reflectionType))); } + $reflectionTypeString = $reflectionType->getName(); $loweredReflectionTypeString = strtolower($reflectionTypeString); if (str_ends_with($loweredReflectionTypeString, '\\object')) { @@ -143,20 +146,26 @@ public static function decideTypeFromReflection(?ReflectionType $reflectionType, } elseif (str_ends_with($loweredReflectionTypeString, '\\never')) { $reflectionTypeString = 'never'; } + $type = self::getTypeObjectFromTypehint($reflectionTypeString, $selfClass); if ($reflectionType->allowsNull()) { $type = TypeCombinator::addNull($type); } elseif ($phpDocType !== null) { $phpDocType = TypeCombinator::removeNull($phpDocType); } + return self::decideType($type, $phpDocType); } - public static function decideType(Type $type, ?Type $phpDocType = null) : Type + public static function decideType( + Type $type, + ?Type $phpDocType = null, + ): Type { if ($type instanceof BenevolentUnionType) { return $type; } + if ($phpDocType !== null && !$phpDocType instanceof ErrorType) { if ($phpDocType instanceof NeverType && $phpDocType->isExplicit()) { return $phpDocType; @@ -174,14 +183,20 @@ public static function decideType(Type $type, ?Type $phpDocType = null) : Type $innerTypes = []; foreach ($phpDocType->getTypes() as $innerType) { if ($innerType instanceof ArrayType) { - $innerTypes[] = new IterableType($innerType->getKeyType(), $innerType->getItemType()); + $innerTypes[] = new IterableType( + $innerType->getKeyType(), + $innerType->getItemType(), + ); } else { $innerTypes[] = $innerType; } } $phpDocType = new UnionType($innerTypes); } elseif ($phpDocType instanceof ArrayType) { - $phpDocType = new IterableType($phpDocType->getKeyType(), $phpDocType->getItemType()); + $phpDocType = new IterableType( + $phpDocType->getKeyType(), + $phpDocType->getItemType(), + ); } } @@ -215,6 +230,7 @@ public static function decideType(Type $type, ?Type $phpDocType = null) : Type $type = $resultType; } } + return $type; } diff --git a/src/Type/UnionType.php b/src/Type/UnionType.php index 3414fac27b5..f9c97c03aae 100644 --- a/src/Type/UnionType.php +++ b/src/Type/UnionType.php @@ -40,36 +40,25 @@ class UnionType implements CompoundType { - /** - * @var Type[] - */ - private $types; - /** - * @var bool - */ - private $normalized; - use NonGeneralizableTypeTrait; + use NonGeneralizableTypeTrait; - /** - * @var bool - */ - private $sortedTypes = false; + private bool $sortedTypes = false; /** @var array */ - private $cachedDescriptions = []; + private array $cachedDescriptions = []; /** - * @api - * @param Type[] $types - */ - public function __construct(array $types, bool $normalized = false) - { - $this->types = $types; - $this->normalized = $normalized; - $throwException = static function () use ($types): void { - throw new ShouldNotHappenException(sprintf('Cannot create %s with: %s', self::class, implode(', ', array_map(static function (Type $type) : string { - return $type->describe(VerbosityLevel::value()); - }, $types)))); + * @api + * @param Type[] $types + */ + public function __construct(private array $types, private bool $normalized = false) + { + $throwException = static function () use ($types): void { + throw new ShouldNotHappenException(sprintf( + 'Cannot create %s with: %s', + self::class, + implode(', ', array_map(static fn (Type $type): string => $type->describe(VerbosityLevel::value()), $types)), + )); }; if (count($types) < 2) { $throwException(); @@ -87,9 +76,9 @@ public function __construct(array $types, bool $normalized = false) } /** - * @return Type[] - */ - public function getTypes(): array + * @return Type[] + */ + public function getTypes(): array { return $this->types; } @@ -100,9 +89,9 @@ public function isNormalized(): bool } /** - * @return Type[] - */ - protected function getSortedTypes(): array + * @return Type[] + */ + protected function getSortedTypes(): array { if ($this->sortedTypes) { return $this->types; @@ -115,9 +104,9 @@ protected function getSortedTypes(): array } /** - * @return string[] - */ - public function getReferencedClasses(): array + * @return string[] + */ + public function getReferencedClasses(): array { $classes = []; foreach ($this->types as $type) { @@ -131,37 +120,27 @@ public function getReferencedClasses(): array public function getObjectClassNames(): array { - return array_values(array_unique($this->pickFromTypes(static function (Type $type) { - return $type->getObjectClassNames(); - }))); + return array_values(array_unique($this->pickFromTypes(static fn (Type $type) => $type->getObjectClassNames()))); } public function getObjectClassReflections(): array { - return $this->pickFromTypes(static function (Type $type) { - return $type->getObjectClassReflections(); - }); + return $this->pickFromTypes(static fn (Type $type) => $type->getObjectClassReflections()); } public function getArrays(): array { - return $this->pickFromTypes(static function (Type $type) { - return $type->getArrays(); - }); + return $this->pickFromTypes(static fn (Type $type) => $type->getArrays()); } public function getConstantArrays(): array { - return $this->pickFromTypes(static function (Type $type) { - return $type->getConstantArrays(); - }); + return $this->pickFromTypes(static fn (Type $type) => $type->getConstantArrays()); } public function getConstantStrings(): array { - return $this->pickFromTypes(static function (Type $type) { - return $type->getConstantStrings(); - }); + return $this->pickFromTypes(static fn (Type $type) => $type->getConstantStrings()); } public function accepts(Type $type, bool $strictTypes): TrinaryLogic @@ -173,7 +152,10 @@ public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult { if ( $type->equals(new ObjectType(DateTimeInterface::class)) - && $this->accepts(new UnionType([new ObjectType(DateTime::class), new ObjectType(DateTimeImmutable::class)]), $strictTypes)->yes() + && $this->accepts( + new UnionType([new ObjectType(DateTime::class), new ObjectType(DateTimeImmutable::class)]), + $strictTypes, + )->yes() ) { return AcceptsResult::createYes(); } @@ -184,9 +166,7 @@ public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult $result = AcceptsResult::createNo(); foreach ($this->getSortedTypes() as $i => $innerType) { - $result = $result->or($innerType->acceptsWithReason($type, $strictTypes)->decorateReasons(static function (string $reason) use($i) { - return sprintf('Type #%d from the union: %s', $i + 1, $reason); - })); + $result = $result->or($innerType->acceptsWithReason($type, $strictTypes)->decorateReasons(static fn (string $reason) => sprintf('Type #%d from the union: %s', $i + 1, $reason))); } if ($result->yes()) { return $result; @@ -219,9 +199,7 @@ public function isSuperTypeOf(Type $otherType): TrinaryLogic return $otherType->isSubTypeOf($this); } - $result = TrinaryLogic::createNo()->lazyOr($this->getTypes(), static function (Type $innerType) use($otherType) { - return $innerType->isSuperTypeOf($otherType); - }); + $result = TrinaryLogic::createNo()->lazyOr($this->getTypes(), static fn (Type $innerType) => $innerType->isSuperTypeOf($otherType)); if ($result->yes()) { return $result; } @@ -235,9 +213,7 @@ public function isSuperTypeOf(Type $otherType): TrinaryLogic public function isSubTypeOf(Type $otherType): TrinaryLogic { - return TrinaryLogic::lazyExtremeIdentity($this->getTypes(), static function (Type $innerType) use($otherType) { - return $otherType->isSuperTypeOf($innerType); - }); + return TrinaryLogic::lazyExtremeIdentity($this->getTypes(), static fn (Type $innerType) => $otherType->isSuperTypeOf($innerType)); } public function isAcceptedBy(Type $acceptingType, bool $strictTypes): TrinaryLogic @@ -247,9 +223,7 @@ public function isAcceptedBy(Type $acceptingType, bool $strictTypes): TrinaryLog public function isAcceptedWithReasonBy(Type $acceptingType, bool $strictTypes): AcceptsResult { - return AcceptsResult::extremeIdentity(...array_map(static function (Type $innerType) use($acceptingType, $strictTypes) { - return $acceptingType->acceptsWithReason($innerType, $strictTypes); - }, $this->types)); + return AcceptsResult::extremeIdentity(...array_map(static fn (Type $innerType) => $acceptingType->acceptsWithReason($innerType, $strictTypes), $this->types)); } public function equals(Type $type): bool @@ -320,7 +294,8 @@ public function describe(VerbosityLevel $level): string return implode('|', $typeNames); }; - return $this->cachedDescriptions[$level->getLevelValue()] = $level->handle(function () use ($joinTypes): string { + return $this->cachedDescriptions[$level->getLevelValue()] = $level->handle( + function () use ($joinTypes): string { $types = TypeCombinator::union(...array_map(static function (Type $type): Type { if ( $type->isConstantValue()->yes() @@ -337,90 +312,89 @@ public function describe(VerbosityLevel $level): string } return $joinTypes([$types]); - }, function () use($joinTypes) : string { - return $joinTypes($this->getSortedTypes()); - }); + }, + fn (): string => $joinTypes($this->getSortedTypes()), + ); } /** - * @param callable(Type $type): TrinaryLogic $canCallback - * @param callable(Type $type): TrinaryLogic $hasCallback - */ - private function hasInternal(callable $canCallback, callable $hasCallback) : TrinaryLogic - { - return TrinaryLogic::lazyExtremeIdentity($this->types, static function (Type $type) use ($canCallback, $hasCallback): TrinaryLogic { - if ($canCallback($type)->no()) { - return TrinaryLogic::createNo(); - } - - return $hasCallback($type); - }); + * @param callable(Type $type): TrinaryLogic $canCallback + * @param callable(Type $type): TrinaryLogic $hasCallback + */ + private function hasInternal( + callable $canCallback, + callable $hasCallback, + ): TrinaryLogic + { + return TrinaryLogic::lazyExtremeIdentity($this->types, static function (Type $type) use ($canCallback, $hasCallback): TrinaryLogic { + if ($canCallback($type)->no()) { + return TrinaryLogic::createNo(); } + return $hasCallback($type); + }); + } + /** - * @template TObject of object - * @param callable(Type $type): TrinaryLogic $hasCallback - * @param callable(Type $type): TObject $getCallback - * @return TObject - */ - private function getInternal(callable $hasCallback, callable $getCallback) : object - { - /** @var TrinaryLogic|null $result */ - $result = null; - /** @var TObject|null $object */ - $object = null; - foreach ($this->types as $type) { - $has = $hasCallback($type); - if (!$has->yes()) { - continue; - } - if ($result !== null && $result->compareTo($has) !== $has) { - continue; - } - - $get = $getCallback($type); - $result = $has; - $object = $get; - } - if ($object === null) { - throw new ShouldNotHappenException(); - } - return $object; + * @template TObject of object + * @param callable(Type $type): TrinaryLogic $hasCallback + * @param callable(Type $type): TObject $getCallback + * @return TObject + */ + private function getInternal( + callable $hasCallback, + callable $getCallback, + ): object + { + /** @var TrinaryLogic|null $result */ + $result = null; + + /** @var TObject|null $object */ + $object = null; + foreach ($this->types as $type) { + $has = $hasCallback($type); + if (!$has->yes()) { + continue; + } + if ($result !== null && $result->compareTo($has) !== $has) { + continue; } + $get = $getCallback($type); + $result = $has; + $object = $get; + } + + if ($object === null) { + throw new ShouldNotHappenException(); + } + + return $object; + } + public function getTemplateType(string $ancestorClassName, string $templateTypeName): Type { - return $this->unionTypes(static function (Type $type) use($ancestorClassName, $templateTypeName) : Type { - return $type->getTemplateType($ancestorClassName, $templateTypeName); - }); + return $this->unionTypes(static fn (Type $type): Type => $type->getTemplateType($ancestorClassName, $templateTypeName)); } public function isObject(): TrinaryLogic { - return $this->unionResults(static function (Type $type) : TrinaryLogic { - return $type->isObject(); - }); + return $this->unionResults(static fn (Type $type): TrinaryLogic => $type->isObject()); } public function isEnum(): TrinaryLogic { - return $this->unionResults(static function (Type $type) : TrinaryLogic { - return $type->isEnum(); - }); + return $this->unionResults(static fn (Type $type): TrinaryLogic => $type->isEnum()); } public function canAccessProperties(): TrinaryLogic { - return $this->unionResults(static function (Type $type) : TrinaryLogic { - return $type->canAccessProperties(); - }); + return $this->unionResults(static fn (Type $type): TrinaryLogic => $type->canAccessProperties()); } public function hasProperty(string $propertyName): TrinaryLogic { - return $this->unionResults(static function (Type $type) use($propertyName) : TrinaryLogic { - return $type->hasProperty($propertyName); - }); + return $this->unionResults(static fn (Type $type): TrinaryLogic => $type->hasProperty($propertyName)); } public function getProperty(string $propertyName, ClassMemberAccessAnswerer $scope): PropertyReflection @@ -453,16 +427,12 @@ public function getUnresolvedPropertyPrototype(string $propertyName, ClassMember public function canCallMethods(): TrinaryLogic { - return $this->unionResults(static function (Type $type) : TrinaryLogic { - return $type->canCallMethods(); - }); + return $this->unionResults(static fn (Type $type): TrinaryLogic => $type->canCallMethods()); } public function hasMethod(string $methodName): TrinaryLogic { - return $this->unionResults(static function (Type $type) use($methodName) : TrinaryLogic { - return $type->hasMethod($methodName); - }); + return $this->unionResults(static fn (Type $type): TrinaryLogic => $type->hasMethod($methodName)); } public function getMethod(string $methodName, ClassMemberAccessAnswerer $scope): ExtendedMethodReflection @@ -495,188 +465,138 @@ public function getUnresolvedMethodPrototype(string $methodName, ClassMemberAcce public function canAccessConstants(): TrinaryLogic { - return $this->unionResults(static function (Type $type) : TrinaryLogic { - return $type->canAccessConstants(); - }); + return $this->unionResults(static fn (Type $type): TrinaryLogic => $type->canAccessConstants()); } public function hasConstant(string $constantName): TrinaryLogic { - return $this->hasInternal(static function (Type $type) : TrinaryLogic { - return $type->canAccessConstants(); - }, static function (Type $type) use($constantName) : TrinaryLogic { - return $type->hasConstant($constantName); - }); + return $this->hasInternal( + static fn (Type $type): TrinaryLogic => $type->canAccessConstants(), + static fn (Type $type): TrinaryLogic => $type->hasConstant($constantName), + ); } public function getConstant(string $constantName): ConstantReflection { - return $this->getInternal(static function (Type $type) use($constantName) : TrinaryLogic { - return $type->hasConstant($constantName); - }, static function (Type $type) use($constantName) : ConstantReflection { - return $type->getConstant($constantName); - }); + return $this->getInternal( + static fn (Type $type): TrinaryLogic => $type->hasConstant($constantName), + static fn (Type $type): ConstantReflection => $type->getConstant($constantName), + ); } public function isIterable(): TrinaryLogic { - return $this->unionResults(static function (Type $type) : TrinaryLogic { - return $type->isIterable(); - }); + return $this->unionResults(static fn (Type $type): TrinaryLogic => $type->isIterable()); } public function isIterableAtLeastOnce(): TrinaryLogic { - return $this->unionResults(static function (Type $type) : TrinaryLogic { - return $type->isIterableAtLeastOnce(); - }); + return $this->unionResults(static fn (Type $type): TrinaryLogic => $type->isIterableAtLeastOnce()); } public function getArraySize(): Type { - return $this->unionTypes(static function (Type $type) : Type { - return $type->getArraySize(); - }); + return $this->unionTypes(static fn (Type $type): Type => $type->getArraySize()); } public function getIterableKeyType(): Type { - return $this->unionTypes(static function (Type $type) : Type { - return $type->getIterableKeyType(); - }); + return $this->unionTypes(static fn (Type $type): Type => $type->getIterableKeyType()); } public function getFirstIterableKeyType(): Type { - return $this->unionTypes(static function (Type $type) : Type { - return $type->getFirstIterableKeyType(); - }); + return $this->unionTypes(static fn (Type $type): Type => $type->getFirstIterableKeyType()); } public function getLastIterableKeyType(): Type { - return $this->unionTypes(static function (Type $type) : Type { - return $type->getLastIterableKeyType(); - }); + return $this->unionTypes(static fn (Type $type): Type => $type->getLastIterableKeyType()); } public function getIterableValueType(): Type { - return $this->unionTypes(static function (Type $type) : Type { - return $type->getIterableValueType(); - }); + return $this->unionTypes(static fn (Type $type): Type => $type->getIterableValueType()); } public function getFirstIterableValueType(): Type { - return $this->unionTypes(static function (Type $type) : Type { - return $type->getFirstIterableValueType(); - }); + return $this->unionTypes(static fn (Type $type): Type => $type->getFirstIterableValueType()); } public function getLastIterableValueType(): Type { - return $this->unionTypes(static function (Type $type) : Type { - return $type->getLastIterableValueType(); - }); + return $this->unionTypes(static fn (Type $type): Type => $type->getLastIterableValueType()); } public function isArray(): TrinaryLogic { - return $this->notBenevolentUnionResults(static function (Type $type) : TrinaryLogic { - return $type->isArray(); - }); + return $this->notBenevolentUnionResults(static fn (Type $type): TrinaryLogic => $type->isArray()); } public function isConstantArray(): TrinaryLogic { - return $this->notBenevolentUnionResults(static function (Type $type) : TrinaryLogic { - return $type->isConstantArray(); - }); + return $this->notBenevolentUnionResults(static fn (Type $type): TrinaryLogic => $type->isConstantArray()); } public function isOversizedArray(): TrinaryLogic { - return $this->notBenevolentUnionResults(static function (Type $type) : TrinaryLogic { - return $type->isOversizedArray(); - }); + return $this->notBenevolentUnionResults(static fn (Type $type): TrinaryLogic => $type->isOversizedArray()); } public function isList(): TrinaryLogic { - return $this->notBenevolentUnionResults(static function (Type $type) : TrinaryLogic { - return $type->isList(); - }); + return $this->notBenevolentUnionResults(static fn (Type $type): TrinaryLogic => $type->isList()); } public function isString(): TrinaryLogic { - return $this->notBenevolentUnionResults(static function (Type $type) : TrinaryLogic { - return $type->isString(); - }); + return $this->notBenevolentUnionResults(static fn (Type $type): TrinaryLogic => $type->isString()); } public function isNumericString(): TrinaryLogic { - return $this->notBenevolentUnionResults(static function (Type $type) : TrinaryLogic { - return $type->isNumericString(); - }); + return $this->notBenevolentUnionResults(static fn (Type $type): TrinaryLogic => $type->isNumericString()); } public function isNonEmptyString(): TrinaryLogic { - return $this->notBenevolentUnionResults(static function (Type $type) : TrinaryLogic { - return $type->isNonEmptyString(); - }); + return $this->notBenevolentUnionResults(static fn (Type $type): TrinaryLogic => $type->isNonEmptyString()); } public function isNonFalsyString(): TrinaryLogic { - return $this->notBenevolentUnionResults(static function (Type $type) : TrinaryLogic { - return $type->isNonFalsyString(); - }); + return $this->notBenevolentUnionResults(static fn (Type $type): TrinaryLogic => $type->isNonFalsyString()); } public function isLiteralString(): TrinaryLogic { - return $this->notBenevolentUnionResults(static function (Type $type) : TrinaryLogic { - return $type->isLiteralString(); - }); + return $this->notBenevolentUnionResults(static fn (Type $type): TrinaryLogic => $type->isLiteralString()); } public function isClassStringType(): TrinaryLogic { - return $this->notBenevolentUnionResults(static function (Type $type) : TrinaryLogic { - return $type->isClassStringType(); - }); + return $this->notBenevolentUnionResults(static fn (Type $type): TrinaryLogic => $type->isClassStringType()); } public function getClassStringObjectType(): Type { - return $this->unionTypes(static function (Type $type) : Type { - return $type->getClassStringObjectType(); - }); + return $this->unionTypes(static fn (Type $type): Type => $type->getClassStringObjectType()); } public function getObjectTypeOrClassStringObjectType(): Type { - return $this->unionTypes(static function (Type $type) : Type { - return $type->getObjectTypeOrClassStringObjectType(); - }); + return $this->unionTypes(static fn (Type $type): Type => $type->getObjectTypeOrClassStringObjectType()); } public function isVoid(): TrinaryLogic { - return $this->unionResults(static function (Type $type) : TrinaryLogic { - return $type->isVoid(); - }); + return $this->unionResults(static fn (Type $type): TrinaryLogic => $type->isVoid()); } public function isScalar(): TrinaryLogic { - return $this->unionResults(static function (Type $type) : TrinaryLogic { - return $type->isScalar(); - }); + return $this->unionResults(static fn (Type $type): TrinaryLogic => $type->isScalar()); } public function looseCompare(Type $type, PhpVersion $phpVersion): BooleanType @@ -686,16 +606,12 @@ public function looseCompare(Type $type, PhpVersion $phpVersion): BooleanType public function isOffsetAccessible(): TrinaryLogic { - return $this->unionResults(static function (Type $type) : TrinaryLogic { - return $type->isOffsetAccessible(); - }); + return $this->unionResults(static fn (Type $type): TrinaryLogic => $type->isOffsetAccessible()); } public function hasOffsetValueType(Type $offsetType): TrinaryLogic { - return $this->unionResults(static function (Type $type) use($offsetType) : TrinaryLogic { - return $type->hasOffsetValueType($offsetType); - }); + return $this->unionResults(static fn (Type $type): TrinaryLogic => $type->hasOffsetValueType($offsetType)); } public function getOffsetValueType(Type $offsetType): Type @@ -719,99 +635,73 @@ public function getOffsetValueType(Type $offsetType): Type public function setOffsetValueType(?Type $offsetType, Type $valueType, bool $unionValues = true): Type { - return $this->unionTypes(static function (Type $type) use($offsetType, $valueType, $unionValues) : Type { - return $type->setOffsetValueType($offsetType, $valueType, $unionValues); - }); + return $this->unionTypes(static fn (Type $type): Type => $type->setOffsetValueType($offsetType, $valueType, $unionValues)); } public function unsetOffset(Type $offsetType): Type { - return $this->unionTypes(static function (Type $type) use($offsetType) : Type { - return $type->unsetOffset($offsetType); - }); + return $this->unionTypes(static fn (Type $type): Type => $type->unsetOffset($offsetType)); } public function getKeysArray(): Type { - return $this->unionTypes(static function (Type $type) : Type { - return $type->getKeysArray(); - }); + return $this->unionTypes(static fn (Type $type): Type => $type->getKeysArray()); } public function getValuesArray(): Type { - return $this->unionTypes(static function (Type $type) : Type { - return $type->getValuesArray(); - }); + return $this->unionTypes(static fn (Type $type): Type => $type->getValuesArray()); } public function fillKeysArray(Type $valueType): Type { - return $this->unionTypes(static function (Type $type) use($valueType) : Type { - return $type->fillKeysArray($valueType); - }); + return $this->unionTypes(static fn (Type $type): Type => $type->fillKeysArray($valueType)); } public function flipArray(): Type { - return $this->unionTypes(static function (Type $type) : Type { - return $type->flipArray(); - }); + return $this->unionTypes(static fn (Type $type): Type => $type->flipArray()); } public function intersectKeyArray(Type $otherArraysType): Type { - return $this->unionTypes(static function (Type $type) use($otherArraysType) : Type { - return $type->intersectKeyArray($otherArraysType); - }); + return $this->unionTypes(static fn (Type $type): Type => $type->intersectKeyArray($otherArraysType)); } public function popArray(): Type { - return $this->unionTypes(static function (Type $type) : Type { - return $type->popArray(); - }); + return $this->unionTypes(static fn (Type $type): Type => $type->popArray()); } public function searchArray(Type $needleType): Type { - return $this->unionTypes(static function (Type $type) use($needleType) : Type { - return $type->searchArray($needleType); - }); + return $this->unionTypes(static fn (Type $type): Type => $type->searchArray($needleType)); } public function shiftArray(): Type { - return $this->unionTypes(static function (Type $type) : Type { - return $type->shiftArray(); - }); + return $this->unionTypes(static fn (Type $type): Type => $type->shiftArray()); } public function shuffleArray(): Type { - return $this->unionTypes(static function (Type $type) : Type { - return $type->shuffleArray(); - }); + return $this->unionTypes(static fn (Type $type): Type => $type->shuffleArray()); } public function getEnumCases(): array { - return $this->pickFromTypes(static function (Type $type) { - return $type->getEnumCases(); - }); + return $this->pickFromTypes(static fn (Type $type) => $type->getEnumCases()); } public function isCallable(): TrinaryLogic { - return $this->unionResults(static function (Type $type) : TrinaryLogic { - return $type->isCallable(); - }); + return $this->unionResults(static fn (Type $type): TrinaryLogic => $type->isCallable()); } /** - * @return ParametersAcceptor[] - */ - public function getCallableParametersAcceptors(ClassMemberAccessAnswerer $scope): array + * @return ParametersAcceptor[] + */ + public function getCallableParametersAcceptors(ClassMemberAccessAnswerer $scope): array { foreach ($this->types as $type) { if ($type->isCallable()->no()) { @@ -826,197 +716,145 @@ public function getCallableParametersAcceptors(ClassMemberAccessAnswerer $scope) public function isCloneable(): TrinaryLogic { - return $this->unionResults(static function (Type $type) : TrinaryLogic { - return $type->isCloneable(); - }); + return $this->unionResults(static fn (Type $type): TrinaryLogic => $type->isCloneable()); } public function isSmallerThan(Type $otherType): TrinaryLogic { - return $this->notBenevolentUnionResults(static function (Type $type) use($otherType) : TrinaryLogic { - return $type->isSmallerThan($otherType); - }); + return $this->notBenevolentUnionResults(static fn (Type $type): TrinaryLogic => $type->isSmallerThan($otherType)); } public function isSmallerThanOrEqual(Type $otherType): TrinaryLogic { - return $this->notBenevolentUnionResults(static function (Type $type) use($otherType) : TrinaryLogic { - return $type->isSmallerThanOrEqual($otherType); - }); + return $this->notBenevolentUnionResults(static fn (Type $type): TrinaryLogic => $type->isSmallerThanOrEqual($otherType)); } public function isNull(): TrinaryLogic { - return $this->notBenevolentUnionResults(static function (Type $type) : TrinaryLogic { - return $type->isNull(); - }); + return $this->notBenevolentUnionResults(static fn (Type $type): TrinaryLogic => $type->isNull()); } public function isConstantValue(): TrinaryLogic { - return $this->notBenevolentUnionResults(static function (Type $type) : TrinaryLogic { - return $type->isConstantValue(); - }); + return $this->notBenevolentUnionResults(static fn (Type $type): TrinaryLogic => $type->isConstantValue()); } public function isConstantScalarValue(): TrinaryLogic { - return $this->notBenevolentUnionResults(static function (Type $type) : TrinaryLogic { - return $type->isConstantScalarValue(); - }); + return $this->notBenevolentUnionResults(static fn (Type $type): TrinaryLogic => $type->isConstantScalarValue()); } public function getConstantScalarTypes(): array { - return $this->notBenevolentPickFromTypes(static function (Type $type) { - return $type->getConstantScalarTypes(); - }); + return $this->notBenevolentPickFromTypes(static fn (Type $type) => $type->getConstantScalarTypes()); } public function getConstantScalarValues(): array { - return $this->notBenevolentPickFromTypes(static function (Type $type) { - return $type->getConstantScalarValues(); - }); + return $this->notBenevolentPickFromTypes(static fn (Type $type) => $type->getConstantScalarValues()); } public function isTrue(): TrinaryLogic { - return $this->notBenevolentUnionResults(static function (Type $type) : TrinaryLogic { - return $type->isTrue(); - }); + return $this->notBenevolentUnionResults(static fn (Type $type): TrinaryLogic => $type->isTrue()); } public function isFalse(): TrinaryLogic { - return $this->notBenevolentUnionResults(static function (Type $type) : TrinaryLogic { - return $type->isFalse(); - }); + return $this->notBenevolentUnionResults(static fn (Type $type): TrinaryLogic => $type->isFalse()); } public function isBoolean(): TrinaryLogic { - return $this->notBenevolentUnionResults(static function (Type $type) : TrinaryLogic { - return $type->isBoolean(); - }); + return $this->notBenevolentUnionResults(static fn (Type $type): TrinaryLogic => $type->isBoolean()); } public function isFloat(): TrinaryLogic { - return $this->notBenevolentUnionResults(static function (Type $type) : TrinaryLogic { - return $type->isFloat(); - }); + return $this->notBenevolentUnionResults(static fn (Type $type): TrinaryLogic => $type->isFloat()); } public function isInteger(): TrinaryLogic { - return $this->notBenevolentUnionResults(static function (Type $type) : TrinaryLogic { - return $type->isInteger(); - }); + return $this->notBenevolentUnionResults(static fn (Type $type): TrinaryLogic => $type->isInteger()); } public function getSmallerType(): Type { - return $this->unionTypes(static function (Type $type) : Type { - return $type->getSmallerType(); - }); + return $this->unionTypes(static fn (Type $type): Type => $type->getSmallerType()); } public function getSmallerOrEqualType(): Type { - return $this->unionTypes(static function (Type $type) : Type { - return $type->getSmallerOrEqualType(); - }); + return $this->unionTypes(static fn (Type $type): Type => $type->getSmallerOrEqualType()); } public function getGreaterType(): Type { - return $this->unionTypes(static function (Type $type) : Type { - return $type->getGreaterType(); - }); + return $this->unionTypes(static fn (Type $type): Type => $type->getGreaterType()); } public function getGreaterOrEqualType(): Type { - return $this->unionTypes(static function (Type $type) : Type { - return $type->getGreaterOrEqualType(); - }); + return $this->unionTypes(static fn (Type $type): Type => $type->getGreaterOrEqualType()); } public function isGreaterThan(Type $otherType): TrinaryLogic { - return $this->notBenevolentUnionResults(static function (Type $type) use($otherType) : TrinaryLogic { - return $otherType->isSmallerThan($type); - }); + return $this->notBenevolentUnionResults(static fn (Type $type): TrinaryLogic => $otherType->isSmallerThan($type)); } public function isGreaterThanOrEqual(Type $otherType): TrinaryLogic { - return $this->notBenevolentUnionResults(static function (Type $type) use($otherType) : TrinaryLogic { - return $otherType->isSmallerThanOrEqual($type); - }); + return $this->notBenevolentUnionResults(static fn (Type $type): TrinaryLogic => $otherType->isSmallerThanOrEqual($type)); } public function toBoolean(): BooleanType { /** @var BooleanType $type */ - $type = $this->unionTypes(static function (Type $type) : BooleanType { - return $type->toBoolean(); - }); + $type = $this->unionTypes(static fn (Type $type): BooleanType => $type->toBoolean()); return $type; } public function toNumber(): Type { - $type = $this->unionTypes(static function (Type $type) : Type { - return $type->toNumber(); - }); + $type = $this->unionTypes(static fn (Type $type): Type => $type->toNumber()); return $type; } public function toString(): Type { - $type = $this->unionTypes(static function (Type $type) : Type { - return $type->toString(); - }); + $type = $this->unionTypes(static fn (Type $type): Type => $type->toString()); return $type; } public function toInteger(): Type { - $type = $this->unionTypes(static function (Type $type) : Type { - return $type->toInteger(); - }); + $type = $this->unionTypes(static fn (Type $type): Type => $type->toInteger()); return $type; } public function toFloat(): Type { - $type = $this->unionTypes(static function (Type $type) : Type { - return $type->toFloat(); - }); + $type = $this->unionTypes(static fn (Type $type): Type => $type->toFloat()); return $type; } public function toArray(): Type { - $type = $this->unionTypes(static function (Type $type) : Type { - return $type->toArray(); - }); + $type = $this->unionTypes(static fn (Type $type): Type => $type->toArray()); return $type; } public function toArrayKey(): Type { - return $this->unionTypes(static function (Type $type) : Type { - return $type->toArrayKey(); - }); + return $this->unionTypes(static fn (Type $type): Type => $type->toArrayKey()); } public function inferTemplateTypes(Type $receivedType): TemplateTypeMap @@ -1136,23 +974,17 @@ public function traverseSimultaneously(Type $right, callable $cb): Type public function tryRemove(Type $typeToRemove): ?Type { - return $this->unionTypes(static function (Type $type) use($typeToRemove) : Type { - return TypeCombinator::remove($type, $typeToRemove); - }); + return $this->unionTypes(static fn (Type $type): Type => TypeCombinator::remove($type, $typeToRemove)); } public function exponentiate(Type $exponent): Type { - return $this->unionTypes(static function (Type $type) use($exponent) : Type { - return $type->exponentiate($exponent); - }); + return $this->unionTypes(static fn (Type $type): Type => $type->exponentiate($exponent)); } public function getFiniteTypes(): array { - $types = $this->notBenevolentPickFromTypes(static function (Type $type) { - return $type->getFiniteTypes(); - }); + $types = $this->notBenevolentPickFromTypes(static fn (Type $type) => $type->getFiniteTypes()); $uniquedTypes = []; foreach ($types as $type) { $uniquedTypes[md5($type->describe(VerbosityLevel::cache()))] = $type; @@ -1166,55 +998,55 @@ public function getFiniteTypes(): array } /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): Type + * @param mixed[] $properties + */ + public static function __set_state(array $properties): Type { return new self($properties['types'], $properties['normalized']); } /** - * @param callable(Type $type): TrinaryLogic $getResult - */ - protected function unionResults(callable $getResult): TrinaryLogic + * @param callable(Type $type): TrinaryLogic $getResult + */ + protected function unionResults(callable $getResult): TrinaryLogic { return TrinaryLogic::lazyExtremeIdentity($this->types, $getResult); } /** - * @param callable(Type $type): TrinaryLogic $getResult - */ - private function notBenevolentUnionResults(callable $getResult): TrinaryLogic + * @param callable(Type $type): TrinaryLogic $getResult + */ + private function notBenevolentUnionResults(callable $getResult): TrinaryLogic { return TrinaryLogic::lazyExtremeIdentity($this->types, $getResult); } /** - * @param callable(Type $type): Type $getType - */ - protected function unionTypes(callable $getType): Type + * @param callable(Type $type): Type $getType + */ + protected function unionTypes(callable $getType): Type { return TypeCombinator::union(...array_map($getType, $this->types)); } /** - * @template T of Type - * @param callable(Type $type): list $getTypes - * @return list - * - * @deprecated Use pickFromTypes() instead. - */ - protected function pickTypes(callable $getTypes): array + * @template T of Type + * @param callable(Type $type): list $getTypes + * @return list + * + * @deprecated Use pickFromTypes() instead. + */ + protected function pickTypes(callable $getTypes): array { return $this->pickFromTypes($getTypes); } /** - * @template T - * @param callable(Type $type): list $getValues - * @return list - */ - protected function pickFromTypes(callable $getValues): array + * @template T + * @param callable(Type $type): list $getValues + * @return list + */ + protected function pickFromTypes(callable $getValues): array { $values = []; foreach ($this->types as $type) { @@ -1233,17 +1065,15 @@ protected function pickFromTypes(callable $getValues): array public function toPhpDocNode(): TypeNode { - return new UnionTypeNode(array_map(static function (Type $type) { - return $type->toPhpDocNode(); - }, $this->getSortedTypes())); + return new UnionTypeNode(array_map(static fn (Type $type) => $type->toPhpDocNode(), $this->getSortedTypes())); } /** - * @template T - * @param callable(Type $type): list $getValues - * @return list - */ - private function notBenevolentPickFromTypes(callable $getValues): array + * @template T + * @param callable(Type $type): list $getValues + * @return list + */ + private function notBenevolentPickFromTypes(callable $getValues): array { $values = []; foreach ($this->types as $type) { diff --git a/src/Type/UsefulTypeAliasResolver.php b/src/Type/UsefulTypeAliasResolver.php index 6e4b761bee4..191bad9794c 100644 --- a/src/Type/UsefulTypeAliasResolver.php +++ b/src/Type/UsefulTypeAliasResolver.php @@ -13,43 +13,28 @@ class UsefulTypeAliasResolver implements TypeAliasResolver { - /** - * @var array - */ - private $globalTypeAliases; - /** - * @var TypeStringResolver - */ - private $typeStringResolver; - /** - * @var TypeNodeResolver - */ - private $typeNodeResolver; - /** - * @var ReflectionProvider - */ - private $reflectionProvider; /** @var array */ - private $resolvedGlobalTypeAliases = []; + private array $resolvedGlobalTypeAliases = []; /** @var array */ - private $resolvedLocalTypeAliases = []; + private array $resolvedLocalTypeAliases = []; /** @var array */ - private $resolvingClassTypeAliases = []; + private array $resolvingClassTypeAliases = []; /** @var array */ - private $inProcess = []; + private array $inProcess = []; /** * @param array $globalTypeAliases */ - public function __construct(array $globalTypeAliases, TypeStringResolver $typeStringResolver, TypeNodeResolver $typeNodeResolver, ReflectionProvider $reflectionProvider) + public function __construct( + private array $globalTypeAliases, + private TypeStringResolver $typeStringResolver, + private TypeNodeResolver $typeNodeResolver, + private ReflectionProvider $reflectionProvider, + ) { - $this->globalTypeAliases = $globalTypeAliases; - $this->typeStringResolver = $typeStringResolver; - $this->typeNodeResolver = $typeNodeResolver; - $this->reflectionProvider = $reflectionProvider; } public function hasTypeAlias(string $aliasName, ?string $classNameScope): bool @@ -126,7 +111,7 @@ private function resolveLocalTypeAlias(string $aliasName, NameScope $nameScope): try { $unresolvedAlias = $localTypeAliases[$aliasName]; $resolvedAliasType = $unresolvedAlias->resolve($this->typeNodeResolver); - } catch (CircularTypeAliasDefinitionException $e) { + } catch (CircularTypeAliasDefinitionException) { $resolvedAliasType = new CircularTypeAliasErrorType(); } diff --git a/src/Type/ValueOfType.php b/src/Type/ValueOfType.php index 9cc2e64eba1..9df5411c471 100644 --- a/src/Type/ValueOfType.php +++ b/src/Type/ValueOfType.php @@ -14,16 +14,11 @@ final class ValueOfType implements CompoundType, LateResolvableType { - /** - * @var Type - */ - private $type; use LateResolvableTypeTrait; use NonGeneralizableTypeTrait; - public function __construct(Type $type) + public function __construct(private Type $type) { - $this->type = $type; } public function getReferencedClasses(): array @@ -110,7 +105,9 @@ public function toPhpDocNode(): TypeNode */ public static function __set_state(array $properties): Type { - return new self($properties['type']); + return new self( + $properties['type'], + ); } } diff --git a/src/Type/VerbosityLevel.php b/src/Type/VerbosityLevel.php index ab3deda4aac..7a1e8707f60 100644 --- a/src/Type/VerbosityLevel.php +++ b/src/Type/VerbosityLevel.php @@ -14,24 +14,19 @@ class VerbosityLevel { - /** - * @var self::* - */ - private $value; private const TYPE_ONLY = 1; private const VALUE = 2; private const PRECISE = 3; private const CACHE = 4; /** @var self[] */ - private static $registry; + private static array $registry; /** * @param self::* $value */ - private function __construct(int $value) + private function __construct(private int $value) { - $this->value = $value; } /** @@ -39,7 +34,7 @@ private function __construct(int $value) */ private static function create(int $value): self { - self::$registry[$value] = self::$registry[$value] ?? new self($value); + self::$registry[$value] ??= new self($value); return self::$registry[$value]; } @@ -167,14 +162,21 @@ public static function getRecommendedLevelByType(Type $acceptingType, ?Type $acc * @param callable(): string|null $preciseCallback * @param callable(): string|null $cacheCallback */ - public function handle(callable $typeOnlyCallback, callable $valueCallback, ?callable $preciseCallback = null, ?callable $cacheCallback = null) : string + public function handle( + callable $typeOnlyCallback, + callable $valueCallback, + ?callable $preciseCallback = null, + ?callable $cacheCallback = null, + ): string { if ($this->value === self::TYPE_ONLY) { return $typeOnlyCallback(); } + if ($this->value === self::VALUE) { return $valueCallback(); } + if ($this->value === self::PRECISE) { if ($preciseCallback !== null) { return $preciseCallback(); @@ -182,12 +184,15 @@ public function handle(callable $typeOnlyCallback, callable $valueCallback, ?cal return $valueCallback(); } + if ($cacheCallback !== null) { return $cacheCallback(); } + if ($preciseCallback !== null) { return $preciseCallback(); } + return $valueCallback(); } diff --git a/tests/PHPStan/Analyser/AnalyserIntegrationTest.php b/tests/PHPStan/Analyser/AnalyserIntegrationTest.php index 94133a9fb26..c998075acbc 100644 --- a/tests/PHPStan/Analyser/AnalyserIntegrationTest.php +++ b/tests/PHPStan/Analyser/AnalyserIntegrationTest.php @@ -384,7 +384,10 @@ public function testBug4288(): void $nativeProperty = $class->getNativeReflection()->getProperty('test'); $initializerExprTypeResolver = self::getContainer()->getByType(InitializerExprTypeResolver::class); - $defaultValueType = $initializerExprTypeResolver->getType($nativeProperty->getDefaultValueExpression(), InitializerExprContext::fromClassReflection($class->getNativeProperty('test')->getDeclaringClass())); + $defaultValueType = $initializerExprTypeResolver->getType( + $nativeProperty->getDefaultValueExpression(), + InitializerExprContext::fromClassReflection($class->getNativeProperty('test')->getDeclaringClass()), + ); $this->assertInstanceOf(ConstantIntegerType::class, $defaultValueType); $this->assertSame(10, $defaultValueType->getValue()); } @@ -521,11 +524,14 @@ public function testBug6494(): void public function testBug6253(): void { - $errors = $this->runAnalyse(__DIR__ . '/data/bug-6253.php', [ + $errors = $this->runAnalyse( + __DIR__ . '/data/bug-6253.php', + [ __DIR__ . '/data/bug-6253.php', __DIR__ . '/data/bug-6253-app-scope-trait.php', __DIR__ . '/data/bug-6253-collection-trait.php', - ]); + ], + ); $this->assertNoErrors($errors); } diff --git a/tests/PHPStan/Analyser/AnalyserTest.php b/tests/PHPStan/Analyser/AnalyserTest.php index e34d63aef5a..535afd7119a 100644 --- a/tests/PHPStan/Analyser/AnalyserTest.php +++ b/tests/PHPStan/Analyser/AnalyserTest.php @@ -620,28 +620,45 @@ public function testIgnoreErrorExplicitReportUnmatchedEnableMulti(): void * @param string|string[] $filePaths * @return string[]|Error[] */ - private function runAnalyser(array $ignoreErrors, bool $reportUnmatchedIgnoredErrors, $filePaths, bool $onlyFiles, bool $enableIgnoreErrorsWithinPhpDocs = true) : array + private function runAnalyser( + array $ignoreErrors, + bool $reportUnmatchedIgnoredErrors, + $filePaths, + bool $onlyFiles, + bool $enableIgnoreErrorsWithinPhpDocs = true, + ): array { $analyser = $this->createAnalyser($reportUnmatchedIgnoredErrors, $enableIgnoreErrorsWithinPhpDocs); + if (is_string($filePaths)) { $filePaths = [$filePaths]; } - $ignoredErrorHelper = new IgnoredErrorHelper($this->getFileHelper(), $ignoreErrors, $reportUnmatchedIgnoredErrors); + + $ignoredErrorHelper = new IgnoredErrorHelper( + $this->getFileHelper(), + $ignoreErrors, + $reportUnmatchedIgnoredErrors, + ); $ignoredErrorHelperResult = $ignoredErrorHelper->initialize(); if (count($ignoredErrorHelperResult->getErrors()) > 0) { return $ignoredErrorHelperResult->getErrors(); } - $normalizedFilePaths = array_map(function (string $path) : string { - return $this->getFileHelper()->normalizePath($path); - }, $filePaths); + + $normalizedFilePaths = array_map(fn (string $path): string => $this->getFileHelper()->normalizePath($path), $filePaths); + $analyserResult = $analyser->analyse($normalizedFilePaths); + $ignoredErrorHelperProcessedResult = $ignoredErrorHelperResult->process($analyserResult->getErrors(), $onlyFiles, $normalizedFilePaths, $analyserResult->hasReachedInternalErrorsCountLimit()); $errors = $ignoredErrorHelperProcessedResult->getNotIgnoredErrors(); $errors = array_merge($errors, $ignoredErrorHelperProcessedResult->getOtherIgnoreMessages()); if ($analyserResult->hasReachedInternalErrorsCountLimit()) { $errors[] = sprintf('Reached internal errors count limit of %d, exiting...', 50); } - return array_merge($errors, $analyserResult->getInternalErrors()); + + return array_merge( + $errors, + $analyserResult->getInternalErrors(), + ); } private function createAnalyser(bool $reportUnmatchedIgnoredErrors, bool $enableIgnoreErrorsWithinPhpDocs): Analyser @@ -658,11 +675,55 @@ private function createAnalyser(bool $reportUnmatchedIgnoredErrors, bool $enable $fileTypeMapper = self::getContainer()->getByType(FileTypeMapper::class); $phpDocInheritanceResolver = new PhpDocInheritanceResolver($fileTypeMapper, self::getContainer()->getByType(StubPhpDocProvider::class)); - $nodeScopeResolver = new NodeScopeResolver($reflectionProvider, self::getContainer()->getByType(InitializerExprTypeResolver::class), self::getReflector(), self::getClassReflectionExtensionRegistryProvider(), $this->getParser(), $fileTypeMapper, self::getContainer()->getByType(StubPhpDocProvider::class), self::getContainer()->getByType(PhpVersion::class), self::getContainer()->getByType(SignatureMapProvider::class), $phpDocInheritanceResolver, $fileHelper, $typeSpecifier, self::getContainer()->getByType(DynamicThrowTypeExtensionProvider::class), self::getContainer()->getByType(ReadWritePropertiesExtensionProvider::class), self::createScopeFactory($reflectionProvider, $typeSpecifier), false, true, [], [], [stdClass::class], true, $this->shouldTreatPhpDocTypesAsCertain(), self::getContainer()->getParameter('featureToggles')['detectDeadTypeInMultiCatch']); + $nodeScopeResolver = new NodeScopeResolver( + $reflectionProvider, + self::getContainer()->getByType(InitializerExprTypeResolver::class), + self::getReflector(), + self::getClassReflectionExtensionRegistryProvider(), + $this->getParser(), + $fileTypeMapper, + self::getContainer()->getByType(StubPhpDocProvider::class), + self::getContainer()->getByType(PhpVersion::class), + self::getContainer()->getByType(SignatureMapProvider::class), + $phpDocInheritanceResolver, + $fileHelper, + $typeSpecifier, + self::getContainer()->getByType(DynamicThrowTypeExtensionProvider::class), + self::getContainer()->getByType(ReadWritePropertiesExtensionProvider::class), + self::createScopeFactory($reflectionProvider, $typeSpecifier), + false, + true, + [], + [], + [stdClass::class], + true, + $this->shouldTreatPhpDocTypesAsCertain(), + self::getContainer()->getParameter('featureToggles')['detectDeadTypeInMultiCatch'], + ); $lexer = new Lexer(['usedAttributes' => ['comments', 'startLine', 'endLine', 'startTokenPos', 'endTokenPos']]); - $fileAnalyser = new FileAnalyser($this->createScopeFactory($reflectionProvider, $typeSpecifier), $nodeScopeResolver, new RichParser(new Php7($lexer), $lexer, new NameResolver(), self::getContainer(), new IgnoreLexer(), $enableIgnoreErrorsWithinPhpDocs), new DependencyResolver($fileHelper, $reflectionProvider, new ExportedNodeResolver($fileTypeMapper, new ExprPrinter(new Printer())), $fileTypeMapper), new RuleErrorTransformer(), $reportUnmatchedIgnoredErrors); - - return new Analyser($fileAnalyser, $ruleRegistry, $collectorRegistry, $nodeScopeResolver, 50); + $fileAnalyser = new FileAnalyser( + $this->createScopeFactory($reflectionProvider, $typeSpecifier), + $nodeScopeResolver, + new RichParser( + new Php7($lexer), + $lexer, + new NameResolver(), + self::getContainer(), + new IgnoreLexer(), + $enableIgnoreErrorsWithinPhpDocs, + ), + new DependencyResolver($fileHelper, $reflectionProvider, new ExportedNodeResolver($fileTypeMapper, new ExprPrinter(new Printer())), $fileTypeMapper), + new RuleErrorTransformer(), + $reportUnmatchedIgnoredErrors, + ); + + return new Analyser( + $fileAnalyser, + $ruleRegistry, + $collectorRegistry, + $nodeScopeResolver, + 50, + ); } } diff --git a/tests/PHPStan/Analyser/AnalyserTraitsIntegrationTest.php b/tests/PHPStan/Analyser/AnalyserTraitsIntegrationTest.php index 39aec5cbb58..023d00e9f44 100644 --- a/tests/PHPStan/Analyser/AnalyserTraitsIntegrationTest.php +++ b/tests/PHPStan/Analyser/AnalyserTraitsIntegrationTest.php @@ -14,10 +14,7 @@ class AnalyserTraitsIntegrationTest extends PHPStanTestCase { - /** - * @var FileHelper - */ - private $fileHelper; + private FileHelper $fileHelper; protected function setUp(): void { @@ -42,7 +39,10 @@ public function testMethodDoesNotExist(): void $this->assertCount(1, $errors); $error = $errors[0]; $this->assertSame('Call to an undefined method AnalyseTraits\Bar::doFoo().', $error->getMessage()); - $this->assertSame(sprintf('%s (in context of class AnalyseTraits\Bar)', $this->fileHelper->normalizePath(__DIR__ . '/traits/FooTrait.php')), $error->getFile()); + $this->assertSame( + sprintf('%s (in context of class AnalyseTraits\Bar)', $this->fileHelper->normalizePath(__DIR__ . '/traits/FooTrait.php')), + $error->getFile(), + ); $this->assertSame(10, $error->getLine()); } @@ -56,12 +56,18 @@ public function testNestedTraits(): void $this->assertCount(2, $errors); $firstError = $errors[0]; $this->assertSame('Call to an undefined method AnalyseTraits\NestedBar::doFoo().', $firstError->getMessage()); - $this->assertSame(sprintf('%s (in context of class AnalyseTraits\NestedBar)', $this->fileHelper->normalizePath(__DIR__ . '/traits/FooTrait.php')), $firstError->getFile()); + $this->assertSame( + sprintf('%s (in context of class AnalyseTraits\NestedBar)', $this->fileHelper->normalizePath(__DIR__ . '/traits/FooTrait.php')), + $firstError->getFile(), + ); $this->assertSame(10, $firstError->getLine()); $secondError = $errors[1]; $this->assertSame('Call to an undefined method AnalyseTraits\NestedBar::doNestedFoo().', $secondError->getMessage()); - $this->assertSame(sprintf('%s (in context of class AnalyseTraits\NestedBar)', $this->fileHelper->normalizePath(__DIR__ . '/traits/NestedFooTrait.php')), $secondError->getFile()); + $this->assertSame( + sprintf('%s (in context of class AnalyseTraits\NestedBar)', $this->fileHelper->normalizePath(__DIR__ . '/traits/NestedFooTrait.php')), + $secondError->getFile(), + ); $this->assertSame(12, $secondError->getLine()); } @@ -96,10 +102,12 @@ public function testFindErrorsInTrait(): void public function testTraitInAnonymousClass(): void { - $errors = $this->runAnalyse([ + $errors = $this->runAnalyse( + [ __DIR__ . '/traits/AnonymousClassUsingTrait.php', __DIR__ . '/traits/TraitWithTypeSpecification.php', - ]); + ], + ); $this->assertCount(1, $errors); $this->assertStringContainsString('Access to an undefined property', $errors[0]->getMessage()); $this->assertSame(18, $errors[0]->getLine()); @@ -116,11 +124,17 @@ public function testWrongPropertyType(): void $errors = $this->runAnalyse([__DIR__ . '/traits/wrongProperty/Foo.php']); $this->assertCount(2, $errors); $this->assertSame(15, $errors[0]->getLine()); - $this->assertSame($this->fileHelper->normalizePath(__DIR__ . '/traits/wrongProperty/Foo.php'), $errors[0]->getFile()); + $this->assertSame( + $this->fileHelper->normalizePath(__DIR__ . '/traits/wrongProperty/Foo.php'), + $errors[0]->getFile(), + ); $this->assertSame('Property TraitsWrongProperty\Foo::$id (int) does not accept string.', $errors[0]->getMessage()); $this->assertSame(17, $errors[1]->getLine()); - $this->assertSame($this->fileHelper->normalizePath(__DIR__ . '/traits/wrongProperty/Foo.php'), $errors[1]->getFile()); + $this->assertSame( + $this->fileHelper->normalizePath(__DIR__ . '/traits/wrongProperty/Foo.php'), + $errors[1]->getFile(), + ); $this->assertSame('Property TraitsWrongProperty\Foo::$bar (Ipsum) does not accept int.', $errors[1]->getMessage()); } @@ -166,9 +180,7 @@ public function testUnititializedReadonlyPropertyAccessedInTrait(): void __DIR__ . '/traits/uninitializedProperty/FooTrait.php', ]); $this->assertCount(3, $errors); - usort($errors, static function (Error $a, Error $b) { - return $a->getLine() <=> $b->getLine(); - }); + usort($errors, static fn (Error $a, Error $b) => $a->getLine() <=> $b->getLine()); $expectedFile = sprintf('%s (in context of class TraitsUnititializedProperty\FooClass)', $this->fileHelper->normalizePath(__DIR__ . '/traits/uninitializedProperty/FooTrait.php')); $error = $errors[0]; @@ -193,9 +205,7 @@ public function testUnititializedReadonlyPropertyAccessedInTrait(): void */ private function runAnalyse(array $files): array { - $files = array_map(function (string $file) : string { - return $this->getFileHelper()->normalizePath($file); - }, $files); + $files = array_map(fn (string $file): string => $this->getFileHelper()->normalizePath($file), $files); /** @var Analyser $analyser */ $analyser = self::getContainer()->getByType(Analyser::class); @@ -204,10 +214,15 @@ private function runAnalyse(array $files): array public static function getAdditionalConfigFiles(): array { - return array_unique(array_merge(parent::getAdditionalConfigFiles(), [ + return array_unique( + array_merge( + parent::getAdditionalConfigFiles(), + [ __DIR__ . '/../../../conf/bleedingEdge.neon', __DIR__ . '/traits-integration.neon', - ])); + ], + ), + ); } } diff --git a/tests/PHPStan/Analyser/AnonymousClassNameRule.php b/tests/PHPStan/Analyser/AnonymousClassNameRule.php index b08ac258c86..2c4f09e0eb8 100644 --- a/tests/PHPStan/Analyser/AnonymousClassNameRule.php +++ b/tests/PHPStan/Analyser/AnonymousClassNameRule.php @@ -15,13 +15,8 @@ class AnonymousClassNameRule implements Rule { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - public function __construct(ReflectionProvider $reflectionProvider) + public function __construct(private ReflectionProvider $reflectionProvider) { - $this->reflectionProvider = $reflectionProvider; } public function getNodeType(): string @@ -36,7 +31,7 @@ public function processNode(Node $node, Scope $scope): array : (string) $node->name; try { $this->reflectionProvider->getClass($className); - } catch (ClassNotFoundException $e) { + } catch (ClassNotFoundException) { return [ RuleErrorBuilder::message('not found') ->identifier('tests.anonymousClassName') diff --git a/tests/PHPStan/Analyser/ArgumentsNormalizerLegacyTest.php b/tests/PHPStan/Analyser/ArgumentsNormalizerLegacyTest.php index 958c111acf3..8d4f675a667 100644 --- a/tests/PHPStan/Analyser/ArgumentsNormalizerLegacyTest.php +++ b/tests/PHPStan/Analyser/ArgumentsNormalizerLegacyTest.php @@ -37,8 +37,20 @@ public function testArgumentReorderAllNamed(): void $parameterAcceptor = ParametersAcceptorSelector::selectSingle($functionReflection->getVariants()); $args = [ - new Arg(new LNumber(0), false, false, [], new Identifier('flags')), - new Arg(new String_('my json value'), false, false, [], new Identifier('value')), + new Arg( + new LNumber(0), + false, + false, + [], + new Identifier('flags'), + ), + new Arg( + new String_('my json value'), + false, + false, + [], + new Identifier('value'), + ), ]; $funcCall = new FuncCall($funcName, $args); @@ -75,8 +87,20 @@ public function testArgumentReorderAllNamedWithSkipped(): void $parameterAcceptor = ParametersAcceptorSelector::selectSingle($functionReflection->getVariants()); $args = [ - new Arg(new LNumber(128), false, false, [], new Identifier('depth')), - new Arg(new String_('my json value'), false, false, [], new Identifier('value')), + new Arg( + new LNumber(128), + false, + false, + [], + new Identifier('depth'), + ), + new Arg( + new String_('my json value'), + false, + false, + [], + new Identifier('value'), + ), ]; $funcCall = new FuncCall($funcName, $args); @@ -116,7 +140,13 @@ public function testMissingRequiredParameter(): void $parameterAcceptor = ParametersAcceptorSelector::selectSingle($functionReflection->getVariants()); $args = [ - new Arg(new LNumber(128), false, false, [], new Identifier('depth')), + new Arg( + new LNumber(128), + false, + false, + [], + new Identifier('depth'), + ), ]; $funcCall = new FuncCall($funcName, $args); @@ -134,8 +164,12 @@ public function testLeaveRegularCallAsIs(): void $parameterAcceptor = ParametersAcceptorSelector::selectSingle($functionReflection->getVariants()); $args = [ - new Arg(new String_('my json value')), - new Arg(new LNumber(0)), + new Arg( + new String_('my json value'), + ), + new Arg( + new LNumber(0), + ), ]; $funcCall = new FuncCall($funcName, $args); diff --git a/tests/PHPStan/Analyser/ArgumentsNormalizerTest.php b/tests/PHPStan/Analyser/ArgumentsNormalizerTest.php index 19eceeda885..311d189ca60 100644 --- a/tests/PHPStan/Analyser/ArgumentsNormalizerTest.php +++ b/tests/PHPStan/Analyser/ArgumentsNormalizerTest.php @@ -210,25 +210,51 @@ public function dataReorderValid(): iterable * @param array $argumentSettings * @param array $expectedArgumentTypes */ - public function testReorderValid(array $parameterSettings, array $argumentSettings, array $expectedArgumentTypes) : void + public function testReorderValid( + array $parameterSettings, + array $argumentSettings, + array $expectedArgumentTypes, + ): void { $parameters = []; foreach ($parameterSettings as [$name, $optional, $variadic, $defaultValue]) { - $parameters[] = new DummyParameter($name, new MixedType(), $optional, null, $variadic, $defaultValue); + $parameters[] = new DummyParameter( + $name, + new MixedType(), + $optional, + null, + $variadic, + $defaultValue, + ); } + $arguments = []; foreach ($argumentSettings as [$type, $name]) { $arguments[] = new Arg(new TypeExpr($type), false, false, [], $name === null ? null : new Identifier($name)); } - $normalized = ArgumentsNormalizer::reorderFuncArguments(new FunctionVariant(TemplateTypeMap::createEmpty(), TemplateTypeMap::createEmpty(), $parameters, false, new MixedType()), new FuncCall(new Name('foo'), $arguments)); + + $normalized = ArgumentsNormalizer::reorderFuncArguments( + new FunctionVariant( + TemplateTypeMap::createEmpty(), + TemplateTypeMap::createEmpty(), + $parameters, + false, + new MixedType(), + ), + new FuncCall(new Name('foo'), $arguments), + ); $this->assertNotNull($normalized); + $actualArguments = $normalized->getArgs(); $this->assertCount(count($expectedArgumentTypes), $actualArguments); foreach ($actualArguments as $i => $actualArgument) { $this->assertNull($actualArgument->name); $value = $actualArgument->value; $this->assertInstanceOf(TypeExpr::class, $value); - $this->assertSame($expectedArgumentTypes[$i]->describe(VerbosityLevel::precise()), $value->getExprType()->describe(VerbosityLevel::precise())); + $this->assertSame( + $expectedArgumentTypes[$i]->describe(VerbosityLevel::precise()), + $value->getExprType()->describe(VerbosityLevel::precise()), + ); } } @@ -286,17 +312,38 @@ public function dataReorderInvalid(): iterable * @param array $parameterSettings * @param array $argumentSettings */ - public function testReorderInvalid(array $parameterSettings, array $argumentSettings) : void + public function testReorderInvalid( + array $parameterSettings, + array $argumentSettings, + ): void { $parameters = []; foreach ($parameterSettings as [$name, $optional, $variadic, $defaultValue]) { - $parameters[] = new DummyParameter($name, new MixedType(), $optional, null, $variadic, $defaultValue); + $parameters[] = new DummyParameter( + $name, + new MixedType(), + $optional, + null, + $variadic, + $defaultValue, + ); } + $arguments = []; foreach ($argumentSettings as [$type, $name]) { $arguments[] = new Arg(new TypeExpr($type), false, false, [], $name === null ? null : new Identifier($name)); } - $normalized = ArgumentsNormalizer::reorderFuncArguments(new FunctionVariant(TemplateTypeMap::createEmpty(), TemplateTypeMap::createEmpty(), $parameters, false, new MixedType()), new FuncCall(new Name('foo'), $arguments)); + + $normalized = ArgumentsNormalizer::reorderFuncArguments( + new FunctionVariant( + TemplateTypeMap::createEmpty(), + TemplateTypeMap::createEmpty(), + $parameters, + false, + new MixedType(), + ), + new FuncCall(new Name('foo'), $arguments), + ); $this->assertNull($normalized); } diff --git a/tests/PHPStan/Analyser/AssertStubTest.php b/tests/PHPStan/Analyser/AssertStubTest.php index f88bb3ee4fd..2ea24ac4ce4 100644 --- a/tests/PHPStan/Analyser/AssertStubTest.php +++ b/tests/PHPStan/Analyser/AssertStubTest.php @@ -16,7 +16,11 @@ public function dataFileAsserts(): iterable * @dataProvider dataFileAsserts * @param mixed ...$args */ - public function testFileAsserts(string $assertType, string $file, ...$args) : void + public function testFileAsserts( + string $assertType, + string $file, + ...$args, + ): void { $this->assertFileAsserts($assertType, $file, ...$args); } diff --git a/tests/PHPStan/Analyser/ClassConstantStubFileTest.php b/tests/PHPStan/Analyser/ClassConstantStubFileTest.php index 1c68b3f85a4..00d83693e61 100644 --- a/tests/PHPStan/Analyser/ClassConstantStubFileTest.php +++ b/tests/PHPStan/Analyser/ClassConstantStubFileTest.php @@ -16,7 +16,11 @@ public function dataFileAsserts(): iterable * @dataProvider dataFileAsserts * @param mixed ...$args */ - public function testFileAsserts(string $assertType, string $file, ...$args) : void + public function testFileAsserts( + string $assertType, + string $file, + ...$args, + ): void { $this->assertFileAsserts($assertType, $file, ...$args); } diff --git a/tests/PHPStan/Analyser/ConditionalReturnTypeFromMethodStubTest.php b/tests/PHPStan/Analyser/ConditionalReturnTypeFromMethodStubTest.php index 5e69dc0d934..84be755a38c 100644 --- a/tests/PHPStan/Analyser/ConditionalReturnTypeFromMethodStubTest.php +++ b/tests/PHPStan/Analyser/ConditionalReturnTypeFromMethodStubTest.php @@ -16,7 +16,11 @@ public function dataFileAsserts(): iterable * @dataProvider dataFileAsserts * @param mixed ...$args */ - public function testFileAsserts(string $assertType, string $file, ...$args) : void + public function testFileAsserts( + string $assertType, + string $file, + ...$args, + ): void { $this->assertFileAsserts($assertType, $file, ...$args); } diff --git a/tests/PHPStan/Analyser/DoNotRememberPossiblyImpureFunctionValuesTest.php b/tests/PHPStan/Analyser/DoNotRememberPossiblyImpureFunctionValuesTest.php index 56abbaf78b6..61c93088f9c 100644 --- a/tests/PHPStan/Analyser/DoNotRememberPossiblyImpureFunctionValuesTest.php +++ b/tests/PHPStan/Analyser/DoNotRememberPossiblyImpureFunctionValuesTest.php @@ -16,7 +16,11 @@ public function dataAsserts(): iterable * @dataProvider dataAsserts * @param mixed ...$args */ - public function testAsserts(string $assertType, string $file, ...$args) : void + public function testAsserts( + string $assertType, + string $file, + ...$args, + ): void { $this->assertFileAsserts($assertType, $file, ...$args); } diff --git a/tests/PHPStan/Analyser/DynamicMethodThrowTypeExtensionTest.php b/tests/PHPStan/Analyser/DynamicMethodThrowTypeExtensionTest.php index 34814a628a6..0d5f8a8dc80 100644 --- a/tests/PHPStan/Analyser/DynamicMethodThrowTypeExtensionTest.php +++ b/tests/PHPStan/Analyser/DynamicMethodThrowTypeExtensionTest.php @@ -22,7 +22,11 @@ public function dataFileAsserts(): iterable * @dataProvider dataFileAsserts * @param mixed ...$args */ - public function testFileAsserts(string $assertType, string $file, ...$args) : void + public function testFileAsserts( + string $assertType, + string $file, + ...$args, + ): void { $this->assertFileAsserts($assertType, $file, ...$args); } diff --git a/tests/PHPStan/Analyser/DynamicReturnTypeExtensionTypeInferenceTest.php b/tests/PHPStan/Analyser/DynamicReturnTypeExtensionTypeInferenceTest.php index c46db28a357..59ebef356ec 100644 --- a/tests/PHPStan/Analyser/DynamicReturnTypeExtensionTypeInferenceTest.php +++ b/tests/PHPStan/Analyser/DynamicReturnTypeExtensionTypeInferenceTest.php @@ -26,7 +26,11 @@ public function dataAsserts(): iterable * @dataProvider dataAsserts * @param mixed ...$args */ - public function testAsserts(string $assertType, string $file, ...$args) : void + public function testAsserts( + string $assertType, + string $file, + ...$args, + ): void { $this->assertFileAsserts($assertType, $file, ...$args); } diff --git a/tests/PHPStan/Analyser/ExpressionTypeResolverExtensionTest.php b/tests/PHPStan/Analyser/ExpressionTypeResolverExtensionTest.php index 9c9c26068dc..b8dda807d40 100644 --- a/tests/PHPStan/Analyser/ExpressionTypeResolverExtensionTest.php +++ b/tests/PHPStan/Analyser/ExpressionTypeResolverExtensionTest.php @@ -16,7 +16,11 @@ public function dataFileAsserts(): iterable * @dataProvider dataFileAsserts * @param mixed ...$args */ - public function testFileAsserts(string $assertType, string $file, ...$args) : void + public function testFileAsserts( + string $assertType, + string $file, + ...$args, + ): void { $this->assertFileAsserts($assertType, $file, ...$args); } diff --git a/tests/PHPStan/Analyser/LegacyNodeScopeResolverTest.php b/tests/PHPStan/Analyser/LegacyNodeScopeResolverTest.php index ef889953749..430e94505c7 100644 --- a/tests/PHPStan/Analyser/LegacyNodeScopeResolverTest.php +++ b/tests/PHPStan/Analyser/LegacyNodeScopeResolverTest.php @@ -32,7 +32,7 @@ class LegacyNodeScopeResolverTest extends TypeInferenceTestCase { /** @var Scope[][] */ - private static $assertTypesCache = []; + private static array $assertTypesCache = []; public function testClassMethodScope(): void { @@ -91,9 +91,16 @@ public function dataUnionInCatch(): array /** * @dataProvider dataUnionInCatch */ - public function testUnionInCatch(string $description, string $expression) : void + public function testUnionInCatch( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/catch-union.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/catch-union.php', + $description, + $expression, + ); } public function dataUnionAndIntersection(): array @@ -209,9 +216,16 @@ public function dataUnionAndIntersection(): array /** * @dataProvider dataUnionAndIntersection */ - public function testUnionAndIntersection(string $description, string $expression) : void + public function testUnionAndIntersection( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/union-intersection.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/union-intersection.php', + $description, + $expression, + ); } public function dataAssignInIf(): array @@ -727,9 +741,21 @@ public function dataAssignInIf(): array /** * @dataProvider dataAssignInIf */ - public function testAssignInIf(Scope $scope, string $variableName, TrinaryLogic $expectedCertainty, ?string $typeDescription = null, ?string $iterableValueTypeDescription = null) : void - { - $this->assertVariables($scope, $variableName, $expectedCertainty, $typeDescription, $iterableValueTypeDescription); + public function testAssignInIf( + Scope $scope, + string $variableName, + TrinaryLogic $expectedCertainty, + ?string $typeDescription = null, + ?string $iterableValueTypeDescription = null, + ): void + { + $this->assertVariables( + $scope, + $variableName, + $expectedCertainty, + $typeDescription, + $iterableValueTypeDescription, + ); } public function dataConstantTypes(): array @@ -853,27 +879,65 @@ public function dataConstantTypes(): array /** * @dataProvider dataConstantTypes */ - public function testConstantTypes(Scope $scope, string $variableName, string $typeDescription) : void - { - $this->assertVariables($scope, $variableName, TrinaryLogic::createYes(), $typeDescription, null); - } - - private function assertVariables(Scope $scope, string $variableName, TrinaryLogic $expectedCertainty, ?string $typeDescription = null, ?string $iterableValueTypeDescription = null) : void + public function testConstantTypes( + Scope $scope, + string $variableName, + string $typeDescription, + ): void + { + $this->assertVariables( + $scope, + $variableName, + TrinaryLogic::createYes(), + $typeDescription, + null, + ); + } + + private function assertVariables( + Scope $scope, + string $variableName, + TrinaryLogic $expectedCertainty, + ?string $typeDescription = null, + ?string $iterableValueTypeDescription = null, + ): void { $certainty = $scope->hasVariableType($variableName); - $this->assertTrue($expectedCertainty->equals($certainty), sprintf('Certainty of variable $%s is %s, expected %s', $variableName, $certainty->describe(), $expectedCertainty->describe())); + $this->assertTrue( + $expectedCertainty->equals($certainty), + sprintf( + 'Certainty of variable $%s is %s, expected %s', + $variableName, + $certainty->describe(), + $expectedCertainty->describe(), + ), + ); if (!$expectedCertainty->no()) { if ($typeDescription === null) { $this->fail(sprintf('Missing expected type for defined variable $%s.', $variableName)); } - $this->assertSame($typeDescription, $scope->getVariableType($variableName)->describe(VerbosityLevel::precise()), sprintf('Type of variable $%s does not match the expected one.', $variableName)); + $this->assertSame( + $typeDescription, + $scope->getVariableType($variableName)->describe(VerbosityLevel::precise()), + sprintf('Type of variable $%s does not match the expected one.', $variableName), + ); if ($iterableValueTypeDescription !== null) { - $this->assertSame($iterableValueTypeDescription, $scope->getVariableType($variableName)->getIterableValueType()->describe(VerbosityLevel::precise()), sprintf('Iterable value type of variable $%s does not match the expected one.', $variableName)); + $this->assertSame( + $iterableValueTypeDescription, + $scope->getVariableType($variableName)->getIterableValueType()->describe(VerbosityLevel::precise()), + sprintf('Iterable value type of variable $%s does not match the expected one.', $variableName), + ); } } elseif ($typeDescription !== null) { - $this->fail(sprintf('No type should be asserted for an undefined variable $%s, %s given.', $variableName, $typeDescription)); + $this->fail( + sprintf( + 'No type should be asserted for an undefined variable $%s, %s given.', + $variableName, + $typeDescription, + ), + ); } } @@ -1150,9 +1214,16 @@ public function dataArrayDestructuring(): array /** * @dataProvider dataArrayDestructuring */ - public function testArrayDestructuring(string $description, string $expression) : void + public function testArrayDestructuring( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/array-destructuring.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/array-destructuring.php', + $description, + $expression, + ); } public function dataParameterTypes(): array @@ -1224,9 +1295,16 @@ public function dataParameterTypes(): array /** * @dataProvider dataParameterTypes */ - public function testTypehints(string $typeClass, string $expression) : void + public function testTypehints( + string $typeClass, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/typehints.php', $typeClass, $expression); + $this->assertTypes( + __DIR__ . '/data/typehints.php', + $typeClass, + $expression, + ); } public function dataAnonymousFunctionParameterTypes(): array @@ -1278,9 +1356,16 @@ public function dataAnonymousFunctionParameterTypes(): array /** * @dataProvider dataAnonymousFunctionParameterTypes */ - public function testAnonymousFunctionTypehints(string $description, string $expression) : void + public function testAnonymousFunctionTypehints( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/typehints-anonymous-function.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/typehints-anonymous-function.php', + $description, + $expression, + ); } public function dataVarAnnotations(): array @@ -1352,9 +1437,19 @@ public function dataVarAnnotations(): array /** * @dataProvider dataVarAnnotations */ - public function testVarAnnotations(string $description, string $expression) : void + public function testVarAnnotations( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/var-annotations.php', $description, $expression, 'die', [], false); + $this->assertTypes( + __DIR__ . '/data/var-annotations.php', + $description, + $expression, + 'die', + [], + false, + ); } public function dataCasts(): array @@ -1498,9 +1593,16 @@ public function dataCasts(): array /** * @dataProvider dataCasts */ - public function testCasts(string $desciptiion, string $expression) : void + public function testCasts( + string $desciptiion, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/casts.php', $desciptiion, $expression); + $this->assertTypes( + __DIR__ . '/data/casts.php', + $desciptiion, + $expression, + ); } public function dataDeductedTypes(): array @@ -1620,10 +1722,17 @@ public function dataDeductedTypes(): array /** * @dataProvider dataDeductedTypes */ - public function testDeductedTypes(string $description, string $expression) : void + public function testDeductedTypes( + string $description, + string $expression, + ): void { require_once __DIR__ . '/data/function-definitions.php'; - $this->assertTypes(__DIR__ . '/data/deducted-types.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/deducted-types.php', + $description, + $expression, + ); } public function dataProperties(): array @@ -1759,9 +1868,16 @@ public function dataProperties(): array /** * @dataProvider dataProperties */ - public function testProperties(string $description, string $expression) : void + public function testProperties( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/properties.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/properties.php', + $description, + $expression, + ); } public function dataBinaryOperations(): array @@ -3049,9 +3165,16 @@ public function dataBinaryOperations(): array /** * @dataProvider dataBinaryOperations */ - public function testBinaryOperations(string $description, string $expression) : void + public function testBinaryOperations( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/binary.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/binary.php', + $description, + $expression, + ); } public function dataVarStatementAnnotation(): array @@ -3067,9 +3190,16 @@ public function dataVarStatementAnnotation(): array /** * @dataProvider dataVarStatementAnnotation */ - public function testVarStatementAnnotation(string $description, string $expression) : void + public function testVarStatementAnnotation( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/var-stmt-annotation.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/var-stmt-annotation.php', + $description, + $expression, + ); } public function dataCloneOperators(): array @@ -3085,9 +3215,16 @@ public function dataCloneOperators(): array /** * @dataProvider dataCloneOperators */ - public function testCloneOperators(string $description, string $expression) : void + public function testCloneOperators( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/clone.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/clone.php', + $description, + $expression, + ); } public function dataLiteralArrays(): array @@ -3131,9 +3268,16 @@ public function dataLiteralArrays(): array /** * @dataProvider dataLiteralArrays */ - public function testLiteralArrays(string $description, string $expression) : void + public function testLiteralArrays( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/literal-arrays.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/literal-arrays.php', + $description, + $expression, + ); } public function dataLiteralArraysKeys(): array @@ -3201,9 +3345,17 @@ public function dataLiteralArraysKeys(): array /** * @dataProvider dataLiteralArraysKeys */ - public function testLiteralArraysKeys(string $description, string $evaluatedPointExpressionType) : void + public function testLiteralArraysKeys( + string $description, + string $evaluatedPointExpressionType, + ): void { - $this->assertTypes(__DIR__ . '/data/literal-arrays-keys.php', $description, '$key', $evaluatedPointExpressionType); + $this->assertTypes( + __DIR__ . '/data/literal-arrays-keys.php', + $description, + '$key', + $evaluatedPointExpressionType, + ); } public function dataStringArrayAccess(): array @@ -3235,9 +3387,16 @@ public function dataStringArrayAccess(): array /** * @dataProvider dataStringArrayAccess */ - public function testStringArrayAccess(string $description, string $expression) : void + public function testStringArrayAccess( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/string-array-access.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/string-array-access.php', + $description, + $expression, + ); } public function dataTypeFromFunctionPhpDocs(): array @@ -3404,10 +3563,17 @@ public function dataTypeFromFunctionFunctionPhpDocs(): array * @dataProvider dataTypeFromFunctionPhpDocs * @dataProvider dataTypeFromFunctionFunctionPhpDocs */ - public function testTypeFromFunctionPhpDocs(string $description, string $expression) : void + public function testTypeFromFunctionPhpDocs( + string $description, + string $expression, + ): void { require_once __DIR__ . '/data/functionPhpDocs.php'; - $this->assertTypes(__DIR__ . '/data/functionPhpDocs.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/functionPhpDocs.php', + $description, + $expression, + ); } public function dataTypeFromFunctionPrefixedPhpDocs(): array @@ -3424,20 +3590,34 @@ public function dataTypeFromFunctionPrefixedPhpDocs(): array * @dataProvider dataTypeFromFunctionPhpDocs * @dataProvider dataTypeFromFunctionPrefixedPhpDocs */ - public function testTypeFromFunctionPhpDocsPsalmPrefix(string $description, string $expression) : void + public function testTypeFromFunctionPhpDocsPsalmPrefix( + string $description, + string $expression, + ): void { require_once __DIR__ . '/data/functionPhpDocs-psalmPrefix.php'; - $this->assertTypes(__DIR__ . '/data/functionPhpDocs-psalmPrefix.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/functionPhpDocs-psalmPrefix.php', + $description, + $expression, + ); } /** * @dataProvider dataTypeFromFunctionPhpDocs * @dataProvider dataTypeFromFunctionPrefixedPhpDocs */ - public function testTypeFromFunctionPhpDocsPhpstanPrefix(string $description, string $expression) : void + public function testTypeFromFunctionPhpDocsPhpstanPrefix( + string $description, + string $expression, + ): void { require_once __DIR__ . '/data/functionPhpDocs-phpstanPrefix.php'; - $this->assertTypes(__DIR__ . '/data/functionPhpDocs-phpstanPrefix.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/functionPhpDocs-phpstanPrefix.php', + $description, + $expression, + ); } public function dataTypeFromMethodPhpDocs(): array @@ -3586,25 +3766,41 @@ public function dataTypeFromMethodPhpDocs(): array * @dataProvider dataTypeFromFunctionPhpDocs * @dataProvider dataTypeFromMethodPhpDocs */ - public function testTypeFromMethodPhpDocs(string $description, string $expression) : void + public function testTypeFromMethodPhpDocs( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/methodPhpDocs.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/methodPhpDocs.php', + $description, + $expression, + ); } /** * @dataProvider dataTypeFromFunctionPhpDocs * @dataProvider dataTypeFromMethodPhpDocs */ - public function testTypeFromMethodPhpDocsPsalmPrefix(string $description, string $expression, bool $replaceClass = true) : void + public function testTypeFromMethodPhpDocsPsalmPrefix( + string $description, + string $expression, + bool $replaceClass = true, + ): void { $description = str_replace('static(MethodPhpDocsNamespace\Foo)', 'static(MethodPhpDocsNamespace\FooPsalmPrefix)', $description); + if ($replaceClass && $expression !== '$this->doFoo()') { $description = str_replace('$this(MethodPhpDocsNamespace\Foo)', '$this(MethodPhpDocsNamespace\FooPsalmPrefix)', $description); if ($description === 'MethodPhpDocsNamespace\Foo') { $description = 'MethodPhpDocsNamespace\FooPsalmPrefix'; } } - $this->assertTypes(__DIR__ . '/data/methodPhpDocs-psalmPrefix.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/methodPhpDocs-psalmPrefix.php', + $description, + $expression, + ); } /** @@ -3612,39 +3808,61 @@ public function testTypeFromMethodPhpDocsPsalmPrefix(string $description, string * @dataProvider dataTypeFromMethodPhpDocs * @param bool $replaceClass = true */ - public function testTypeFromMethodPhpDocsPhpstanPrefix(string $description, string $expression, bool $replaceClass = true) : void + public function testTypeFromMethodPhpDocsPhpstanPrefix( + string $description, + string $expression, + bool $replaceClass = true, + ): void { $description = str_replace('static(MethodPhpDocsNamespace\Foo)', 'static(MethodPhpDocsNamespace\FooPhpstanPrefix)', $description); + if ($replaceClass && $expression !== '$this->doFoo()') { $description = str_replace('$this(MethodPhpDocsNamespace\Foo)', '$this(MethodPhpDocsNamespace\FooPhpstanPrefix)', $description); if ($description === 'MethodPhpDocsNamespace\Foo') { $description = 'MethodPhpDocsNamespace\FooPhpstanPrefix'; } } - $this->assertTypes(__DIR__ . '/data/methodPhpDocs-phpstanPrefix.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/methodPhpDocs-phpstanPrefix.php', + $description, + $expression, + ); } /** * @dataProvider dataTypeFromFunctionPhpDocs * @dataProvider dataTypeFromMethodPhpDocs */ - public function testTypeFromTraitPhpDocs(string $description, string $expression, bool $replaceClass = true) : void + public function testTypeFromTraitPhpDocs( + string $description, + string $expression, + bool $replaceClass = true, + ): void { $description = str_replace('static(MethodPhpDocsNamespace\Foo)', 'static(MethodPhpDocsNamespace\FooWithTrait)', $description); + if ($replaceClass && $expression !== '$this->doFoo()') { $description = str_replace('$this(MethodPhpDocsNamespace\Foo)', '$this(MethodPhpDocsNamespace\FooWithTrait)', $description); if ($description === 'MethodPhpDocsNamespace\Foo') { $description = 'MethodPhpDocsNamespace\FooWithTrait'; } } - $this->assertTypes(__DIR__ . '/data/methodPhpDocs-trait.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/methodPhpDocs-trait.php', + $description, + $expression, + ); } /** * @dataProvider dataTypeFromFunctionPhpDocs * @dataProvider dataTypeFromMethodPhpDocs */ - public function testTypeFromMethodPhpDocsInheritDocWithoutCurlyBraces(string $description, string $expression, bool $replaceClass = true) : void + public function testTypeFromMethodPhpDocsInheritDocWithoutCurlyBraces( + string $description, + string $expression, + bool $replaceClass = true, + ): void { if ($replaceClass) { $description = str_replace('$this(MethodPhpDocsNamespace\Foo)', '$this(MethodPhpDocsNamespace\FooInheritDocChildWithoutCurly)', $description); @@ -3654,23 +3872,36 @@ public function testTypeFromMethodPhpDocsInheritDocWithoutCurlyBraces(string $de $description = 'MethodPhpDocsNamespace\FooInheritDocChildWithoutCurly'; } } - $this->assertTypes(__DIR__ . '/data/method-phpDocs-inheritdoc-without-curly-braces.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/method-phpDocs-inheritdoc-without-curly-braces.php', + $description, + $expression, + ); } /** * @dataProvider dataTypeFromFunctionPhpDocs * @dataProvider dataTypeFromMethodPhpDocs */ - public function testTypeFromRecursiveTraitPhpDocs(string $description, string $expression, bool $replaceClass = true) : void + public function testTypeFromRecursiveTraitPhpDocs( + string $description, + string $expression, + bool $replaceClass = true, + ): void { $description = str_replace('static(MethodPhpDocsNamespace\Foo)', 'static(MethodPhpDocsNamespace\FooWithRecursiveTrait)', $description); + if ($replaceClass && $expression !== '$this->doFoo()') { $description = str_replace('$this(MethodPhpDocsNamespace\Foo)', '$this(MethodPhpDocsNamespace\FooWithRecursiveTrait)', $description); if ($description === 'MethodPhpDocsNamespace\Foo') { $description = 'MethodPhpDocsNamespace\FooWithRecursiveTrait'; } } - $this->assertTypes(__DIR__ . '/data/methodPhpDocs-recursiveTrait.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/methodPhpDocs-recursiveTrait.php', + $description, + $expression, + ); } public function dataTypeFromTraitPhpDocsInSameFile(): array @@ -3686,16 +3917,27 @@ public function dataTypeFromTraitPhpDocsInSameFile(): array /** * @dataProvider dataTypeFromTraitPhpDocsInSameFile */ - public function testTypeFromTraitPhpDocsInSameFile(string $description, string $expression) : void + public function testTypeFromTraitPhpDocsInSameFile( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/methodPhpDocs-traitInSameFileAsClass.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/methodPhpDocs-traitInSameFileAsClass.php', + $description, + $expression, + ); } /** * @dataProvider dataTypeFromFunctionPhpDocs * @dataProvider dataTypeFromMethodPhpDocs */ - public function testTypeFromMethodPhpDocsInheritDoc(string $description, string $expression, bool $replaceClass = true) : void + public function testTypeFromMethodPhpDocsInheritDoc( + string $description, + string $expression, + bool $replaceClass = true, + ): void { if ($replaceClass) { $description = str_replace('$this(MethodPhpDocsNamespace\Foo)', '$this(MethodPhpDocsNamespace\FooInheritDocChild)', $description); @@ -3705,14 +3947,22 @@ public function testTypeFromMethodPhpDocsInheritDoc(string $description, string $description = 'MethodPhpDocsNamespace\FooInheritDocChild'; } } - $this->assertTypes(__DIR__ . '/data/method-phpDocs-inheritdoc.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/method-phpDocs-inheritdoc.php', + $description, + $expression, + ); } /** * @dataProvider dataTypeFromFunctionPhpDocs * @dataProvider dataTypeFromMethodPhpDocs */ - public function testTypeFromMethodPhpDocsImplicitInheritance(string $description, string $expression, bool $replaceClass = true) : void + public function testTypeFromMethodPhpDocsImplicitInheritance( + string $description, + string $expression, + bool $replaceClass = true, + ): void { if ($replaceClass) { $description = str_replace('$this(MethodPhpDocsNamespace\Foo)', '$this(MethodPhpDocsNamespace\FooPhpDocsImplicitInheritanceChild)', $description); @@ -3722,12 +3972,20 @@ public function testTypeFromMethodPhpDocsImplicitInheritance(string $description $description = 'MethodPhpDocsNamespace\FooPhpDocsImplicitInheritanceChild'; } } - $this->assertTypes(__DIR__ . '/data/methodPhpDocs-implicitInheritance.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/methodPhpDocs-implicitInheritance.php', + $description, + $expression, + ); } public function testNotSwitchInstanceof(): void { - $this->assertTypes(__DIR__ . '/data/switch-instanceof-not.php', '*NEVER*', '$foo'); + $this->assertTypes( + __DIR__ . '/data/switch-instanceof-not.php', + '*NEVER*', + '$foo', + ); } public function dataSwitchInstanceOf(): array @@ -3751,17 +4009,31 @@ public function dataSwitchInstanceOf(): array /** * @dataProvider dataSwitchInstanceOf */ - public function testSwitchInstanceof(string $description, string $expression) : void + public function testSwitchInstanceof( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/switch-instanceof.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/switch-instanceof.php', + $description, + $expression, + ); } /** * @dataProvider dataSwitchInstanceOf */ - public function testSwitchInstanceofTruthy(string $description, string $expression) : void + public function testSwitchInstanceofTruthy( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/switch-instanceof-truthy.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/switch-instanceof-truthy.php', + $description, + $expression, + ); } public function dataSwitchGetClass(): array @@ -3783,9 +4055,18 @@ public function dataSwitchGetClass(): array /** * @dataProvider dataSwitchGetClass */ - public function testSwitchGetClass(string $description, string $expression, string $evaluatedPointExpression) : void + public function testSwitchGetClass( + string $description, + string $expression, + string $evaluatedPointExpression, + ): void { - $this->assertTypes(__DIR__ . '/data/switch-get-class.php', $description, $expression, $evaluatedPointExpression); + $this->assertTypes( + __DIR__ . '/data/switch-get-class.php', + $description, + $expression, + $evaluatedPointExpression, + ); } public function dataSwitchInstanceOfFallthrough(): array @@ -3801,9 +4082,16 @@ public function dataSwitchInstanceOfFallthrough(): array /** * @dataProvider dataSwitchInstanceOfFallthrough */ - public function testSwitchInstanceOfFallthrough(string $description, string $expression) : void + public function testSwitchInstanceOfFallthrough( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/switch-instanceof-fallthrough.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/switch-instanceof-fallthrough.php', + $description, + $expression, + ); } public function dataSwitchTypeElimination(): array @@ -3819,9 +4107,16 @@ public function dataSwitchTypeElimination(): array /** * @dataProvider dataSwitchTypeElimination */ - public function testSwitchTypeElimination(string $description, string $expression) : void + public function testSwitchTypeElimination( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/switch-type-elimination.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/switch-type-elimination.php', + $description, + $expression, + ); } public function dataOverwritingVariable(): array @@ -3848,9 +4143,18 @@ public function dataOverwritingVariable(): array /** * @dataProvider dataOverwritingVariable */ - public function testOverwritingVariable(string $description, string $expression, string $evaluatedPointExpressionType) : void + public function testOverwritingVariable( + string $description, + string $expression, + string $evaluatedPointExpressionType, + ): void { - $this->assertTypes(__DIR__ . '/data/overwritingVariable.php', $description, $expression, $evaluatedPointExpressionType); + $this->assertTypes( + __DIR__ . '/data/overwritingVariable.php', + $description, + $expression, + $evaluatedPointExpressionType, + ); } public function dataNegatedInstanceof(): array @@ -3906,9 +4210,16 @@ public function dataNegatedInstanceof(): array /** * @dataProvider dataNegatedInstanceof */ - public function testNegatedInstanceof(string $description, string $expression) : void + public function testNegatedInstanceof( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/negated-instanceof.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/negated-instanceof.php', + $description, + $expression, + ); } public function dataAnonymousFunction(): array @@ -3936,9 +4247,16 @@ public function dataAnonymousFunction(): array /** * @dataProvider dataAnonymousFunction */ - public function testAnonymousFunction(string $description, string $expression) : void + public function testAnonymousFunction( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/anonymous-function.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/anonymous-function.php', + $description, + $expression, + ); } public function dataForeachArrayType(): array @@ -4065,9 +4383,17 @@ public function dataForeachArrayType(): array /** * @dataProvider dataForeachArrayType */ - public function testForeachArrayType(string $file, string $description, string $expression) : void + public function testForeachArrayType( + string $file, + string $description, + string $expression, + ): void { - $this->assertTypes($file, $description, $expression); + $this->assertTypes( + $file, + $description, + $expression, + ); } public function dataOverridingSpecifiedType(): array @@ -4084,9 +4410,17 @@ public function dataOverridingSpecifiedType(): array /** * @dataProvider dataOverridingSpecifiedType */ - public function testOverridingSpecifiedType(string $file, string $description, string $expression) : void + public function testOverridingSpecifiedType( + string $file, + string $description, + string $expression, + ): void { - $this->assertTypes($file, $description, $expression); + $this->assertTypes( + $file, + $description, + $expression, + ); } public function dataForeachObjectType(): array @@ -4134,9 +4468,19 @@ public function dataForeachObjectType(): array /** * @dataProvider dataForeachObjectType */ - public function testForeachObjectType(string $file, string $description, string $expression, string $evaluatedPointExpression) : void + public function testForeachObjectType( + string $file, + string $description, + string $expression, + string $evaluatedPointExpression, + ): void { - $this->assertTypes($file, $description, $expression, $evaluatedPointExpression); + $this->assertTypes( + $file, + $description, + $expression, + $evaluatedPointExpression, + ); } public function dataArrayFunctions(): array @@ -4853,9 +5197,16 @@ public function dataArrayFunctions(): array /** * @dataProvider dataArrayFunctions */ - public function testArrayFunctions(string $description, string $expression) : void + public function testArrayFunctions( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/array-functions.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/array-functions.php', + $description, + $expression, + ); } public function dataFunctions(): array @@ -5224,9 +5575,16 @@ public function dataFunctions(): array /** * @dataProvider dataFunctions */ - public function testFunctions(string $description, string $expression) : void + public function testFunctions( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/functions.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/functions.php', + $description, + $expression, + ); } public function dataDioFunctions(): array @@ -5242,12 +5600,19 @@ public function dataDioFunctions(): array /** * @dataProvider dataDioFunctions */ - public function testDioFunctions(string $description, string $expression) : void + public function testDioFunctions( + string $description, + string $expression, + ): void { if (!function_exists('dio_stat')) { $this->markTestSkipped('This test requires DIO extension.'); } - $this->assertTypes(__DIR__ . '/data/dio-functions.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/dio-functions.php', + $description, + $expression, + ); } public function dataSsh2Functions(): array @@ -5263,9 +5628,16 @@ public function dataSsh2Functions(): array /** * @dataProvider dataSsh2Functions */ - public function testSsh2Functions(string $description, string $expression) : void + public function testSsh2Functions( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/ssh2-functions.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/ssh2-functions.php', + $description, + $expression, + ); } public function dataRangeFunction(): array @@ -5325,9 +5697,16 @@ public function dataRangeFunction(): array /** * @dataProvider dataRangeFunction */ - public function testRangeFunction(string $description, string $expression) : void + public function testRangeFunction( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/range-function.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/range-function.php', + $description, + $expression, + ); } public function dataSpecifiedTypesUsingIsFunctions(): array @@ -5475,9 +5854,16 @@ public function dataSpecifiedTypesUsingIsFunctions(): array /** * @dataProvider dataSpecifiedTypesUsingIsFunctions */ - public function testSpecifiedTypesUsingIsFunctions(string $description, string $expression) : void + public function testSpecifiedTypesUsingIsFunctions( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/specifiedTypesUsingIsFunctions.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/specifiedTypesUsingIsFunctions.php', + $description, + $expression, + ); } public function dataIterable(): array @@ -5633,9 +6019,16 @@ public function dataIterable(): array /** * @dataProvider dataIterable */ - public function testIterable(string $description, string $expression) : void + public function testIterable( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/iterable.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/iterable.php', + $description, + $expression, + ); } public function dataArrayAccess(): array @@ -5663,9 +6056,16 @@ public function dataArrayAccess(): array /** * @dataProvider dataArrayAccess */ - public function testArrayAccess(string $description, string $expression) : void + public function testArrayAccess( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/array-accessable.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/array-accessable.php', + $description, + $expression, + ); } public function dataVoid(): array @@ -5689,9 +6089,16 @@ public function dataVoid(): array /** * @dataProvider dataVoid */ - public function testVoid(string $description, string $expression) : void + public function testVoid( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/void.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/void.php', + $description, + $expression, + ); } public function dataNullableReturnTypes(): array @@ -5719,9 +6126,16 @@ public function dataNullableReturnTypes(): array /** * @dataProvider dataNullableReturnTypes */ - public function testNullableReturnTypes(string $description, string $expression) : void + public function testNullableReturnTypes( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/nullable-returnTypes.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/nullable-returnTypes.php', + $description, + $expression, + ); } public function dataTernary(): array @@ -5757,9 +6171,16 @@ public function dataTernary(): array /** * @dataProvider dataTernary */ - public function testTernary(string $description, string $expression) : void + public function testTernary( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/ternary.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/ternary.php', + $description, + $expression, + ); } public function dataHeredoc(): array @@ -5779,9 +6200,16 @@ public function dataHeredoc(): array /** * @dataProvider dataHeredoc */ - public function testHeredoc(string $description, string $expression) : void + public function testHeredoc( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/heredoc.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/heredoc.php', + $description, + $expression, + ); } public function dataTypeElimination(): array @@ -5943,9 +6371,18 @@ public function dataTypeElimination(): array /** * @dataProvider dataTypeElimination */ - public function testTypeElimination(string $description, string $expression, string $evaluatedPointExpression) : void + public function testTypeElimination( + string $description, + string $expression, + string $evaluatedPointExpression, + ): void { - $this->assertTypes(__DIR__ . '/data/type-elimination.php', $description, $expression, $evaluatedPointExpression); + $this->assertTypes( + __DIR__ . '/data/type-elimination.php', + $description, + $expression, + $evaluatedPointExpression, + ); } public function dataMisleadingTypes(): array @@ -5969,9 +6406,16 @@ public function dataMisleadingTypes(): array /** * @dataProvider dataMisleadingTypes */ - public function testMisleadingTypes(string $description, string $expression) : void + public function testMisleadingTypes( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/misleading-types.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/misleading-types.php', + $description, + $expression, + ); } public function dataMisleadingTypesWithoutNamespace(): array @@ -5991,9 +6435,16 @@ public function dataMisleadingTypesWithoutNamespace(): array /** * @dataProvider dataMisleadingTypesWithoutNamespace */ - public function testMisleadingTypesWithoutNamespace(string $description, string $expression) : void + public function testMisleadingTypesWithoutNamespace( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/misleading-types-without-namespace.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/misleading-types-without-namespace.php', + $description, + $expression, + ); } public function dataUnresolvableTypes(): array @@ -6017,9 +6468,16 @@ public function dataUnresolvableTypes(): array /** * @dataProvider dataUnresolvableTypes */ - public function testUnresolvableTypes(string $description, string $expression) : void + public function testUnresolvableTypes( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/unresolvable-types.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/unresolvable-types.php', + $description, + $expression, + ); } public function dataCombineTypes(): array @@ -6039,9 +6497,16 @@ public function dataCombineTypes(): array /** * @dataProvider dataCombineTypes */ - public function testCombineTypes(string $description, string $expression) : void + public function testCombineTypes( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/combine-types.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/combine-types.php', + $description, + $expression, + ); } public function dataConstants(): array @@ -6071,9 +6536,16 @@ public function dataConstants(): array /** * @dataProvider dataConstants */ - public function testConstants(string $description, string $expression) : void + public function testConstants( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/constants.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/constants.php', + $description, + $expression, + ); } public function dataFinally(): array @@ -6093,17 +6565,31 @@ public function dataFinally(): array /** * @dataProvider dataFinally */ - public function testFinally(string $description, string $expression) : void + public function testFinally( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/finally.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/finally.php', + $description, + $expression, + ); } /** * @dataProvider dataFinally */ - public function testFinallyWithEarlyTermination(string $description, string $expression) : void + public function testFinallyWithEarlyTermination( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/finally-with-early-termination.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/finally-with-early-termination.php', + $description, + $expression, + ); } public function dataInheritDocFromInterface(): array @@ -6119,17 +6605,31 @@ public function dataInheritDocFromInterface(): array /** * @dataProvider dataInheritDocFromInterface */ - public function testInheritDocFromInterface(string $description, string $expression) : void + public function testInheritDocFromInterface( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/inheritdoc-from-interface.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/inheritdoc-from-interface.php', + $description, + $expression, + ); } /** * @dataProvider dataInheritDocFromInterface */ - public function testInheritDocWithoutCurlyBracesFromInterface(string $description, string $expression) : void + public function testInheritDocWithoutCurlyBracesFromInterface( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/inheritdoc-without-curly-braces-from-interface.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/inheritdoc-without-curly-braces-from-interface.php', + $description, + $expression, + ); } public function dataInheritDocFromInterface2(): array @@ -6145,19 +6645,33 @@ public function dataInheritDocFromInterface2(): array /** * @dataProvider dataInheritDocFromInterface2 */ - public function testInheritDocFromInterface2(string $description, string $expression) : void + public function testInheritDocFromInterface2( + string $description, + string $expression, + ): void { require_once __DIR__ . '/data/inheritdoc-from-interface2-definition.php'; - $this->assertTypes(__DIR__ . '/data/inheritdoc-from-interface2.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/inheritdoc-from-interface2.php', + $description, + $expression, + ); } /** * @dataProvider dataInheritDocFromInterface2 */ - public function testInheritDocWithoutCurlyBracesFromInterface2(string $description, string $expression) : void + public function testInheritDocWithoutCurlyBracesFromInterface2( + string $description, + string $expression, + ): void { require_once __DIR__ . '/data/inheritdoc-without-curly-braces-from-interface2-definition.php'; - $this->assertTypes(__DIR__ . '/data/inheritdoc-without-curly-braces-from-interface2.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/inheritdoc-without-curly-braces-from-interface2.php', + $description, + $expression, + ); } public function dataInheritDocFromTrait(): array @@ -6173,17 +6687,31 @@ public function dataInheritDocFromTrait(): array /** * @dataProvider dataInheritDocFromTrait */ - public function testInheritDocFromTrait(string $description, string $expression) : void + public function testInheritDocFromTrait( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/inheritdoc-from-trait.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/inheritdoc-from-trait.php', + $description, + $expression, + ); } /** * @dataProvider dataInheritDocFromTrait */ - public function testInheritDocWithoutCurlyBracesFromTrait(string $description, string $expression) : void + public function testInheritDocWithoutCurlyBracesFromTrait( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/inheritdoc-without-curly-braces-from-trait.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/inheritdoc-without-curly-braces-from-trait.php', + $description, + $expression, + ); } public function dataInheritDocFromTrait2(): array @@ -6199,21 +6727,35 @@ public function dataInheritDocFromTrait2(): array /** * @dataProvider dataInheritDocFromTrait2 */ - public function testInheritDocFromTrait2(string $description, string $expression) : void + public function testInheritDocFromTrait2( + string $description, + string $expression, + ): void { require_once __DIR__ . '/data/inheritdoc-from-trait2-definition.php'; require_once __DIR__ . '/data/inheritdoc-from-trait2-definition2.php'; - $this->assertTypes(__DIR__ . '/data/inheritdoc-from-trait2.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/inheritdoc-from-trait2.php', + $description, + $expression, + ); } /** * @dataProvider dataInheritDocFromTrait2 */ - public function testInheritDocWithoutCurlyBracesFromTrait2(string $description, string $expression) : void + public function testInheritDocWithoutCurlyBracesFromTrait2( + string $description, + string $expression, + ): void { require_once __DIR__ . '/data/inheritdoc-without-curly-braces-from-trait2-definition.php'; require_once __DIR__ . '/data/inheritdoc-without-curly-braces-from-trait2-definition2.php'; - $this->assertTypes(__DIR__ . '/data/inheritdoc-without-curly-braces-from-trait2.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/inheritdoc-without-curly-braces-from-trait2.php', + $description, + $expression, + ); } public function dataResolveStatic(): array @@ -6245,9 +6787,16 @@ public function dataResolveStatic(): array /** * @dataProvider dataResolveStatic */ - public function testResolveStatic(string $description, string $expression) : void + public function testResolveStatic( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/resolve-static.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/resolve-static.php', + $description, + $expression, + ); } public function dataLoopVariables(): array @@ -6468,27 +7017,54 @@ public function dataForLoopVariables(): array * @dataProvider dataLoopVariables * @dataProvider dataForeachLoopVariables */ - public function testForeachLoopVariables(string $description, string $expression, string $evaluatedPointExpression) : void + public function testForeachLoopVariables( + string $description, + string $expression, + string $evaluatedPointExpression, + ): void { - $this->assertTypes(__DIR__ . '/data/foreach-loop-variables.php', $description, $expression, $evaluatedPointExpression); + $this->assertTypes( + __DIR__ . '/data/foreach-loop-variables.php', + $description, + $expression, + $evaluatedPointExpression, + ); } /** * @dataProvider dataLoopVariables * @dataProvider dataWhileLoopVariables */ - public function testWhileLoopVariables(string $description, string $expression, string $evaluatedPointExpression) : void + public function testWhileLoopVariables( + string $description, + string $expression, + string $evaluatedPointExpression, + ): void { - $this->assertTypes(__DIR__ . '/data/while-loop-variables.php', $description, $expression, $evaluatedPointExpression); + $this->assertTypes( + __DIR__ . '/data/while-loop-variables.php', + $description, + $expression, + $evaluatedPointExpression, + ); } /** * @dataProvider dataLoopVariables * @dataProvider dataForLoopVariables */ - public function testForLoopVariables(string $description, string $expression, string $evaluatedPointExpression) : void + public function testForLoopVariables( + string $description, + string $expression, + string $evaluatedPointExpression, + ): void { - $this->assertTypes(__DIR__ . '/data/for-loop-variables.php', $description, $expression, $evaluatedPointExpression); + $this->assertTypes( + __DIR__ . '/data/for-loop-variables.php', + $description, + $expression, + $evaluatedPointExpression, + ); } public function dataDoWhileLoopVariables(): array @@ -6586,9 +7162,18 @@ public function dataDoWhileLoopVariables(): array /** * @dataProvider dataDoWhileLoopVariables */ - public function testDoWhileLoopVariables(string $description, string $expression, string $evaluatedPointExpression) : void + public function testDoWhileLoopVariables( + string $description, + string $expression, + string $evaluatedPointExpression, + ): void { - $this->assertTypes(__DIR__ . '/data/do-while-loop-variables.php', $description, $expression, $evaluatedPointExpression); + $this->assertTypes( + __DIR__ . '/data/do-while-loop-variables.php', + $description, + $expression, + $evaluatedPointExpression, + ); } public function dataMultipleClassesInOneFile(): array @@ -6610,9 +7195,18 @@ public function dataMultipleClassesInOneFile(): array /** * @dataProvider dataMultipleClassesInOneFile */ - public function testMultipleClassesInOneFile(string $description, string $expression, string $evaluatedPointExpression) : void + public function testMultipleClassesInOneFile( + string $description, + string $expression, + string $evaluatedPointExpression, + ): void { - $this->assertTypes(__DIR__ . '/data/multiple-classes-per-file.php', $description, $expression, $evaluatedPointExpression); + $this->assertTypes( + __DIR__ . '/data/multiple-classes-per-file.php', + $description, + $expression, + $evaluatedPointExpression, + ); } public function dataCallingMultipleClassesInOneFile(): array @@ -6632,9 +7226,16 @@ public function dataCallingMultipleClassesInOneFile(): array /** * @dataProvider dataCallingMultipleClassesInOneFile */ - public function testCallingMultipleClassesInOneFile(string $description, string $expression) : void + public function testCallingMultipleClassesInOneFile( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/calling-multiple-classes-per-file.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/calling-multiple-classes-per-file.php', + $description, + $expression, + ); } public function dataExplode(): array @@ -6666,9 +7267,16 @@ public function dataExplode(): array /** * @dataProvider dataExplode */ - public function testExplode(string $description, string $expression) : void + public function testExplode( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/explode.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/explode.php', + $description, + $expression, + ); } public function dataArrayPointerFunctions(): array @@ -6752,9 +7360,16 @@ public function dataArrayPointerFunctions(): array /** * @dataProvider dataArrayPointerFunctions */ - public function testArrayPointerFunctions(string $description, string $expression) : void + public function testArrayPointerFunctions( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/array-pointer-functions.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/array-pointer-functions.php', + $description, + $expression, + ); } public function dataReplaceFunctions(): array @@ -6822,9 +7437,16 @@ public function dataReplaceFunctions(): array /** * @dataProvider dataReplaceFunctions */ - public function testReplaceFunctions(string $description, string $expression) : void + public function testReplaceFunctions( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/replaceFunctions.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/replaceFunctions.php', + $description, + $expression, + ); } public function dataFilterVar(): Generator @@ -6976,9 +7598,16 @@ public function dataFilterVarUnchanged(): array * @dataProvider dataFilterVar * @dataProvider dataFilterVarUnchanged */ - public function testFilterVar(string $description, string $expression) : void + public function testFilterVar( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/filterVar.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/filterVar.php', + $description, + $expression, + ); } public function dataClosureWithUsePassedByReference(): array @@ -7080,9 +7709,18 @@ public function dataClosureWithUsePassedByReference(): array /** * @dataProvider dataClosureWithUsePassedByReference */ - public function testClosureWithUsePassedByReference(string $description, string $expression, string $evaluatedPointExpression) : void + public function testClosureWithUsePassedByReference( + string $description, + string $expression, + string $evaluatedPointExpression, + ): void { - $this->assertTypes(__DIR__ . '/data/closure-passed-by-reference.php', $description, $expression, $evaluatedPointExpression); + $this->assertTypes( + __DIR__ . '/data/closure-passed-by-reference.php', + $description, + $expression, + $evaluatedPointExpression, + ); } public function dataClosureWithUsePassedByReferenceInMethodCall(): array @@ -7098,9 +7736,16 @@ public function dataClosureWithUsePassedByReferenceInMethodCall(): array /** * @dataProvider dataClosureWithUsePassedByReferenceInMethodCall */ - public function testClosureWithUsePassedByReferenceInMethodCall(string $description, string $expression) : void + public function testClosureWithUsePassedByReferenceInMethodCall( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/closure-passed-by-reference-in-call.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/closure-passed-by-reference-in-call.php', + $description, + $expression, + ); } public function dataClosureWithUsePassedByReferenceReturn(): array @@ -7142,17 +7787,33 @@ public function dataStaticClosure(): array /** * @dataProvider dataStaticClosure */ - public function testStaticClosure(string $description, string $expression) : void + public function testStaticClosure( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/static-closure.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/static-closure.php', + $description, + $expression, + ); } /** * @dataProvider dataClosureWithUsePassedByReferenceReturn */ - public function testClosureWithUsePassedByReferenceReturn(string $description, string $expression, string $evaluatedPointExpression) : void + public function testClosureWithUsePassedByReferenceReturn( + string $description, + string $expression, + string $evaluatedPointExpression, + ): void { - $this->assertTypes(__DIR__ . '/data/closure-passed-by-reference-return.php', $description, $expression, $evaluatedPointExpression); + $this->assertTypes( + __DIR__ . '/data/closure-passed-by-reference-return.php', + $description, + $expression, + $evaluatedPointExpression, + ); } public function dataClosureWithInferredTypehint(): array @@ -7172,9 +7833,19 @@ public function dataClosureWithInferredTypehint(): array /** * @dataProvider dataClosureWithInferredTypehint */ - public function testClosureWithInferredTypehint(string $description, string $expression) : void + public function testClosureWithInferredTypehint( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/closure-inferred-typehint.php', $description, $expression, 'die', [], false); + $this->assertTypes( + __DIR__ . '/data/closure-inferred-typehint.php', + $description, + $expression, + 'die', + [], + false, + ); } public function dataTraitsPhpDocs(): array @@ -7270,9 +7941,16 @@ public function dataTraitsPhpDocs(): array /** * @dataProvider dataTraitsPhpDocs */ - public function testTraitsPhpDocs(string $description, string $expression) : void + public function testTraitsPhpDocs( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/traits/traits.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/traits/traits.php', + $description, + $expression, + ); } public function dataPassedByReference(): array @@ -7296,9 +7974,16 @@ public function dataPassedByReference(): array /** * @dataProvider dataPassedByReference */ - public function testPassedByReference(string $description, string $expression) : void + public function testPassedByReference( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/passed-by-reference.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/passed-by-reference.php', + $description, + $expression, + ); } public function dataCallables(): array @@ -7334,9 +8019,16 @@ public function dataCallables(): array /** * @dataProvider dataCallables */ - public function testCallables(string $description, string $expression) : void + public function testCallables( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/callables.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/callables.php', + $description, + $expression, + ); } public function dataArrayKeysInBranches(): array @@ -7384,9 +8076,16 @@ public function dataArrayKeysInBranches(): array /** * @dataProvider dataArrayKeysInBranches */ - public function testArrayKeysInBranches(string $description, string $expression) : void + public function testArrayKeysInBranches( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/array-keys-branches.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/array-keys-branches.php', + $description, + $expression, + ); } public function dataSpecifiedFunctionCall(): array @@ -7423,9 +8122,18 @@ public function dataSpecifiedFunctionCall(): array /** * @dataProvider dataSpecifiedFunctionCall */ - public function testSpecifiedFunctionCall(string $description, string $expression, string $evaluatedPointExpression) : void + public function testSpecifiedFunctionCall( + string $description, + string $expression, + string $evaluatedPointExpression, + ): void { - $this->assertTypes(__DIR__ . '/data/specified-function-call.php', $description, $expression, $evaluatedPointExpression); + $this->assertTypes( + __DIR__ . '/data/specified-function-call.php', + $description, + $expression, + $evaluatedPointExpression, + ); } public function dataElementsOnMixed(): array @@ -7457,9 +8165,16 @@ public function dataElementsOnMixed(): array /** * @dataProvider dataElementsOnMixed */ - public function testElementsOnMixed(string $description, string $expression) : void + public function testElementsOnMixed( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/mixed-elements.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/mixed-elements.php', + $description, + $expression, + ); } public function dataCaseInsensitivePhpDocTypes(): array @@ -7479,9 +8194,16 @@ public function dataCaseInsensitivePhpDocTypes(): array /** * @dataProvider dataCaseInsensitivePhpDocTypes */ - public function testCaseInsensitivePhpDocTypes(string $description, string $expression) : void + public function testCaseInsensitivePhpDocTypes( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/case-insensitive-phpdocs.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/case-insensitive-phpdocs.php', + $description, + $expression, + ); } public function dataConstantTypeAfterDuplicateCondition(): array @@ -7553,9 +8275,18 @@ public function dataConstantTypeAfterDuplicateCondition(): array /** * @dataProvider dataConstantTypeAfterDuplicateCondition */ - public function testConstantTypeAfterDuplicateCondition(string $description, string $expression, string $evaluatedPointExpression) : void + public function testConstantTypeAfterDuplicateCondition( + string $description, + string $expression, + string $evaluatedPointExpression, + ): void { - $this->assertTypes(__DIR__ . '/data/constant-types-duplicate-condition.php', $description, $expression, $evaluatedPointExpression); + $this->assertTypes( + __DIR__ . '/data/constant-types-duplicate-condition.php', + $description, + $expression, + $evaluatedPointExpression, + ); } public function dataAnonymousClass(): array @@ -7597,9 +8328,18 @@ public function dataAnonymousClass(): array /** * @dataProvider dataAnonymousClass */ - public function testAnonymousClassName(string $description, string $expression, string $evaluatedPointExpression) : void + public function testAnonymousClassName( + string $description, + string $expression, + string $evaluatedPointExpression, + ): void { - $this->assertTypes(__DIR__ . '/data/anonymous-class-name.php', $description, $expression, $evaluatedPointExpression); + $this->assertTypes( + __DIR__ . '/data/anonymous-class-name.php', + $description, + $expression, + $evaluatedPointExpression, + ); } public function dataAnonymousClassInTrait(): array @@ -7615,9 +8355,16 @@ public function dataAnonymousClassInTrait(): array /** * @dataProvider dataAnonymousClassInTrait */ - public function testAnonymousClassNameInTrait(string $description, string $expression) : void + public function testAnonymousClassNameInTrait( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/anonymous-class-name-in-trait.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/anonymous-class-name-in-trait.php', + $description, + $expression, + ); } public function dataDynamicConstants(): array @@ -7649,12 +8396,21 @@ public function dataDynamicConstants(): array /** * @dataProvider dataDynamicConstants */ - public function testDynamicConstants(string $description, string $expression) : void + public function testDynamicConstants( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/dynamic-constant.php', $description, $expression, 'die', [ + $this->assertTypes( + __DIR__ . '/data/dynamic-constant.php', + $description, + $expression, + 'die', + [ 'DynamicConstants\\DynamicConstantClass::DYNAMIC_CONSTANT_IN_CLASS', 'GLOBAL_DYNAMIC_CONSTANT', - ]); + ], + ); } public function dataDynamicConstantsWithNativeTypes(): array @@ -7682,15 +8438,25 @@ public function dataDynamicConstantsWithNativeTypes(): array /** * @dataProvider dataDynamicConstantsWithNativeTypes */ - public function testDynamicConstantsWithNativeTypes(string $description, string $expression) : void + public function testDynamicConstantsWithNativeTypes( + string $description, + string $expression, + ): void { if (PHP_VERSION_ID < 80300) { $this->markTestSkipped('Test requires PHP 8.3.'); } - $this->assertTypes(__DIR__ . '/data/dynamic-constant-native-types.php', $description, $expression, 'die', [ + + $this->assertTypes( + __DIR__ . '/data/dynamic-constant-native-types.php', + $description, + $expression, + 'die', + [ 'DynamicConstantNativeTypes\Foo::FOO', 'DynamicConstantNativeTypes\Foo::BAR', - ]); + ], + ); } public function dataIsset(): array @@ -7762,9 +8528,16 @@ public function dataIsset(): array /** * @dataProvider dataIsset */ - public function testIsset(string $description, string $expression) : void + public function testIsset( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/isset.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/isset.php', + $description, + $expression, + ); } public function dataPropertyArrayAssignment(): array @@ -7801,9 +8574,18 @@ public function dataPropertyArrayAssignment(): array /** * @dataProvider dataPropertyArrayAssignment */ - public function testPropertyArrayAssignment(string $description, string $expression, string $evaluatedPointExpression) : void + public function testPropertyArrayAssignment( + string $description, + string $expression, + string $evaluatedPointExpression, + ): void { - $this->assertTypes(__DIR__ . '/data/property-array.php', $description, $expression, $evaluatedPointExpression); + $this->assertTypes( + __DIR__ . '/data/property-array.php', + $description, + $expression, + $evaluatedPointExpression, + ); } public function dataGetParentClass(): array @@ -7883,9 +8665,18 @@ public function dataGetParentClass(): array /** * @dataProvider dataGetParentClass */ - public function testGetParentClass(string $description, string $expression, string $evaluatedPointExpression = 'die') : void + public function testGetParentClass( + string $description, + string $expression, + string $evaluatedPointExpression = 'die', + ): void { - $this->assertTypes(__DIR__ . '/data/get-parent-class.php', $description, $expression, $evaluatedPointExpression); + $this->assertTypes( + __DIR__ . '/data/get-parent-class.php', + $description, + $expression, + $evaluatedPointExpression, + ); } public function dataIsCountable(): array @@ -7907,9 +8698,18 @@ public function dataIsCountable(): array /** * @dataProvider dataIsCountable */ - public function testIsCountable(string $description, string $expression, string $evaluatedPointExpression) : void + public function testIsCountable( + string $description, + string $expression, + string $evaluatedPointExpression, + ): void { - $this->assertTypes(__DIR__ . '/data/is_countable.php', $description, $expression, $evaluatedPointExpression); + $this->assertTypes( + __DIR__ . '/data/is_countable.php', + $description, + $expression, + $evaluatedPointExpression, + ); } public function dataPhp73Functions(): array @@ -8037,12 +8837,19 @@ public function dataPhp73Functions(): array /** * @dataProvider dataPhp73Functions */ - public function testPhp73Functions(string $description, string $expression) : void + public function testPhp73Functions( + string $description, + string $expression, + ): void { if (PHP_VERSION_ID < 70300) { $this->markTestSkipped('Test requires PHP 7.3'); } - $this->assertTypes(__DIR__ . '/data/php73_functions.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/php73_functions.php', + $description, + $expression, + ); } public function dataPhp74Functions(): array @@ -8162,12 +8969,19 @@ public function dataPhp74Functions(): array /** * @dataProvider dataPhp74Functions */ - public function testPhp74Functions(string $description, string $expression) : void + public function testPhp74Functions( + string $description, + string $expression, + ): void { if (PHP_VERSION_ID < 70400) { $this->markTestSkipped('Test requires PHP 7.4'); } - $this->assertTypes(__DIR__ . '/data/php74_functions.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/php74_functions.php', + $description, + $expression, + ); } public function dataUnionMethods(): array @@ -8187,9 +9001,16 @@ public function dataUnionMethods(): array /** * @dataProvider dataUnionMethods */ - public function testUnionMethods(string $description, string $expression) : void + public function testUnionMethods( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/union-methods.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/union-methods.php', + $description, + $expression, + ); } public function dataUnionProperties(): array @@ -8209,9 +9030,16 @@ public function dataUnionProperties(): array /** * @dataProvider dataUnionProperties */ - public function testUnionProperties(string $description, string $expression) : void + public function testUnionProperties( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/union-properties.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/union-properties.php', + $description, + $expression, + ); } public function dataAssignmentInCondition(): array @@ -8227,9 +9055,16 @@ public function dataAssignmentInCondition(): array /** * @dataProvider dataAssignmentInCondition */ - public function testAssignmentInCondition(string $description, string $expression) : void + public function testAssignmentInCondition( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/assignment-in-condition.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/assignment-in-condition.php', + $description, + $expression, + ); } public function dataGeneralizeScope(): array @@ -8245,9 +9080,16 @@ public function dataGeneralizeScope(): array /** * @dataProvider dataGeneralizeScope */ - public function testGeneralizeScope(string $description, string $expression) : void + public function testGeneralizeScope( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/generalize-scope.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/generalize-scope.php', + $description, + $expression, + ); } public function dataGeneralizeScopeRecursiveType(): array @@ -8263,9 +9105,16 @@ public function dataGeneralizeScopeRecursiveType(): array /** * @dataProvider dataGeneralizeScopeRecursiveType */ - public function testGeneralizeScopeRecursiveType(string $description, string $expression) : void + public function testGeneralizeScopeRecursiveType( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/generalize-scope-recursive.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/generalize-scope-recursive.php', + $description, + $expression, + ); } public function dataArrayShapesInPhpDoc(): array @@ -8289,9 +9138,16 @@ public function dataArrayShapesInPhpDoc(): array /** * @dataProvider dataArrayShapesInPhpDoc */ - public function testArrayShapesInPhpDoc(string $description, string $expression) : void + public function testArrayShapesInPhpDoc( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/array-shapes.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/array-shapes.php', + $description, + $expression, + ); } public function dataInferPrivatePropertyTypeFromConstructor(): array @@ -8335,9 +9191,16 @@ public function dataInferPrivatePropertyTypeFromConstructor(): array /** * @dataProvider dataInferPrivatePropertyTypeFromConstructor */ - public function testInferPrivatePropertyTypeFromConstructor(string $description, string $expression) : void + public function testInferPrivatePropertyTypeFromConstructor( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/infer-private-property-type-from-constructor.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/infer-private-property-type-from-constructor.php', + $description, + $expression, + ); } public function dataPropertyNativeTypes(): array @@ -8361,9 +9224,16 @@ public function dataPropertyNativeTypes(): array /** * @dataProvider dataPropertyNativeTypes */ - public function testPropertyNativeTypes(string $description, string $expression) : void + public function testPropertyNativeTypes( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/property-native-types.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/property-native-types.php', + $description, + $expression, + ); } public function dataArrowFunctions(): array @@ -8387,9 +9257,16 @@ public function dataArrowFunctions(): array /** * @dataProvider dataArrowFunctions */ - public function testArrowFunctions(string $description, string $expression) : void + public function testArrowFunctions( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/arrow-functions.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/arrow-functions.php', + $description, + $expression, + ); } public function dataArrowFunctionsInside(): array @@ -8413,9 +9290,16 @@ public function dataArrowFunctionsInside(): array /** * @dataProvider dataArrowFunctionsInside */ - public function testArrowFunctionsInside(string $description, string $expression) : void + public function testArrowFunctionsInside( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/arrow-functions-inside.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/arrow-functions-inside.php', + $description, + $expression, + ); } public function dataCoalesceAssign(): array @@ -8463,9 +9347,16 @@ public function dataCoalesceAssign(): array /** * @dataProvider dataCoalesceAssign */ - public function testCoalesceAssign(string $description, string $expression) : void + public function testCoalesceAssign( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/coalesce-assign.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/coalesce-assign.php', + $description, + $expression, + ); } public function dataArraySpread(): array @@ -8505,9 +9396,16 @@ public function dataArraySpread(): array /** * @dataProvider dataArraySpread */ - public function testArraySpread(string $description, string $expression) : void + public function testArraySpread( + string $description, + string $expression, + ): void { - $this->assertTypes(__DIR__ . '/data/array-spread.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/array-spread.php', + $description, + $expression, + ); } public function dataPhp74FunctionsIn73(): array @@ -8523,12 +9421,19 @@ public function dataPhp74FunctionsIn73(): array /** * @dataProvider dataPhp74FunctionsIn73 */ - public function testPhp74FunctionsIn73(string $description, string $expression) : void + public function testPhp74FunctionsIn73( + string $description, + string $expression, + ): void { if (PHP_VERSION_ID >= 70400) { $this->markTestSkipped('Test does not run on PHP >= 7.4.'); } - $this->assertTypes(__DIR__ . '/data/die-73.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/die-73.php', + $description, + $expression, + ); } public function dataPhp74FunctionsIn74(): array @@ -8544,12 +9449,19 @@ public function dataPhp74FunctionsIn74(): array /** * @dataProvider dataPhp74FunctionsIn74 */ - public function testPhp74FunctionsIn74(string $description, string $expression) : void + public function testPhp74FunctionsIn74( + string $description, + string $expression, + ): void { if (PHP_VERSION_ID < 70400) { $this->markTestSkipped('Test requires PHP 7.4.'); } - $this->assertTypes(__DIR__ . '/data/die-74.php', $description, $expression); + $this->assertTypes( + __DIR__ . '/data/die-74.php', + $description, + $expression, + ); } public function dataTryCatchScope(): array @@ -8576,27 +9488,52 @@ public function dataTryCatchScope(): array /** * @dataProvider dataTryCatchScope */ - public function testTryCatchScope(string $description, string $expression, string $evaluatedPointExpression) : void - { - $this->assertTypes(__DIR__ . '/data/try-catch-scope.php', $description, $expression, $evaluatedPointExpression, [], false); + public function testTryCatchScope( + string $description, + string $expression, + string $evaluatedPointExpression, + ): void + { + $this->assertTypes( + __DIR__ . '/data/try-catch-scope.php', + $description, + $expression, + $evaluatedPointExpression, + [], + false, + ); } /** * @param string[] $dynamicConstantNames */ - private function assertTypes(string $file, string $description, string $expression, string $evaluatedPointExpression = 'die', array $dynamicConstantNames = [], bool $useCache = true) : void + private function assertTypes( + string $file, + string $description, + string $expression, + string $evaluatedPointExpression = 'die', + array $dynamicConstantNames = [], + bool $useCache = true, + ): void { $assertType = function (Scope $scope) use ($expression, $description, $evaluatedPointExpression): void { /** @var Node\Stmt\Expression $expressionNode */ $expressionNode = $this->getParser()->parseString(sprintf('getType($expressionNode->expr); - $this->assertTypeDescribe($description, $type, sprintf('%s at %s', $expression, $evaluatedPointExpression)); + $this->assertTypeDescribe( + $description, + $type, + sprintf('%s at %s', $expression, $evaluatedPointExpression), + ); }; if ($useCache && isset(self::$assertTypesCache[$file][$evaluatedPointExpression])) { $assertType(self::$assertTypesCache[$file][$evaluatedPointExpression]); return; } - self::processFile($file, static function (Node $node, Scope $scope) use ($file, $evaluatedPointExpression, $assertType): void { + + self::processFile( + $file, + static function (Node $node, Scope $scope) use ($file, $evaluatedPointExpression, $assertType): void { if ($node instanceof VirtualNode) { return; } @@ -8609,7 +9546,9 @@ private function assertTypes(string $file, string $description, string $expressi self::$assertTypesCache[$file][$evaluatedPointExpression] = $scope; $assertType($scope); - }, $dynamicConstantNames); + }, + $dynamicConstantNames, + ); } public static function getAdditionalConfigFiles(): array @@ -8680,10 +9619,18 @@ protected static function getEarlyTerminatingFunctionCalls(): array return ['baz']; } - private function assertTypeDescribe(string $expectedDescription, Type $actualType, string $label = '') : void + private function assertTypeDescribe( + string $expectedDescription, + Type $actualType, + string $label = '', + ): void { $actualDescription = $actualType->describe(VerbosityLevel::precise()); - $this->assertSame($expectedDescription, $actualDescription, $label); + $this->assertSame( + $expectedDescription, + $actualDescription, + $label, + ); } /** @return string[] */ diff --git a/tests/PHPStan/Analyser/LooseConstComparisonPhp7Test.php b/tests/PHPStan/Analyser/LooseConstComparisonPhp7Test.php index d5efdce8319..83bb27b70b5 100644 --- a/tests/PHPStan/Analyser/LooseConstComparisonPhp7Test.php +++ b/tests/PHPStan/Analyser/LooseConstComparisonPhp7Test.php @@ -21,7 +21,11 @@ public function dataFileAsserts(): iterable * @dataProvider dataFileAsserts * @param mixed ...$args */ - public function testFileAsserts(string $assertType, string $file, ...$args) : void + public function testFileAsserts( + string $assertType, + string $file, + ...$args, + ): void { $this->assertFileAsserts($assertType, $file, ...$args); } diff --git a/tests/PHPStan/Analyser/LooseConstComparisonPhp8Test.php b/tests/PHPStan/Analyser/LooseConstComparisonPhp8Test.php index 88e7c200e7d..e765ca01d5f 100644 --- a/tests/PHPStan/Analyser/LooseConstComparisonPhp8Test.php +++ b/tests/PHPStan/Analyser/LooseConstComparisonPhp8Test.php @@ -21,7 +21,11 @@ public function dataFileAsserts(): iterable * @dataProvider dataFileAsserts * @param mixed ...$args */ - public function testFileAsserts(string $assertType, string $file, ...$args) : void + public function testFileAsserts( + string $assertType, + string $file, + ...$args, + ): void { $this->assertFileAsserts($assertType, $file, ...$args); } diff --git a/tests/PHPStan/Analyser/NodeScopeResolverTest.php b/tests/PHPStan/Analyser/NodeScopeResolverTest.php index 88a202c4ca3..11b860600c2 100644 --- a/tests/PHPStan/Analyser/NodeScopeResolverTest.php +++ b/tests/PHPStan/Analyser/NodeScopeResolverTest.php @@ -1434,7 +1434,11 @@ public function dataFileAsserts(): iterable * @dataProvider dataFileAsserts * @param mixed ...$args */ - public function testFileAsserts(string $assertType, string $file, ...$args) : void + public function testFileAsserts( + string $assertType, + string $file, + ...$args, + ): void { $this->assertFileAsserts($assertType, $file, ...$args); } diff --git a/tests/PHPStan/Analyser/ParamOutTypeTest.php b/tests/PHPStan/Analyser/ParamOutTypeTest.php index edd3626b9a6..b29b6fbd0c8 100644 --- a/tests/PHPStan/Analyser/ParamOutTypeTest.php +++ b/tests/PHPStan/Analyser/ParamOutTypeTest.php @@ -16,7 +16,11 @@ public function dataFileAsserts(): iterable * @dataProvider dataFileAsserts * @param mixed ...$args */ - public function testFileAsserts(string $assertType, string $file, ...$args) : void + public function testFileAsserts( + string $assertType, + string $file, + ...$args, + ): void { $this->assertFileAsserts($assertType, $file, ...$args); } diff --git a/tests/PHPStan/Analyser/PathConstantsTest.php b/tests/PHPStan/Analyser/PathConstantsTest.php index 7331e10c551..c22864f6988 100644 --- a/tests/PHPStan/Analyser/PathConstantsTest.php +++ b/tests/PHPStan/Analyser/PathConstantsTest.php @@ -16,7 +16,11 @@ public function dataFileAsserts(): iterable * @dataProvider dataFileAsserts * @param mixed ...$args */ - public function testFileAsserts(string $assertType, string $file, ...$args) : void + public function testFileAsserts( + string $assertType, + string $file, + ...$args, + ): void { $this->assertFileAsserts($assertType, $file, ...$args); } diff --git a/tests/PHPStan/Analyser/StatementResultTest.php b/tests/PHPStan/Analyser/StatementResultTest.php index 3f45ae850bb..fb3a9dd5b1a 100644 --- a/tests/PHPStan/Analyser/StatementResultTest.php +++ b/tests/PHPStan/Analyser/StatementResultTest.php @@ -379,12 +379,17 @@ public function dataIsAlwaysTerminating(): array /** * @dataProvider dataIsAlwaysTerminating */ - public function testIsAlwaysTerminating(string $code, bool $expectedIsAlwaysTerminating) : void + public function testIsAlwaysTerminating( + string $code, + bool $expectedIsAlwaysTerminating, + ): void { /** @var Parser $parser */ $parser = self::getContainer()->getService('currentPhpVersionRichParser'); + /** @var Stmt[] $stmts */ $stmts = $parser->parseString(sprintf('getByType(NodeScopeResolver::class); /** @var ScopeFactory $scopeFactory */ @@ -394,8 +399,13 @@ public function testIsAlwaysTerminating(string $code, bool $expectedIsAlwaysTerm ->assignVariable('x', new IntegerType(), new IntegerType()) ->assignVariable('cond', new MixedType(), new MixedType()) ->assignVariable('arr', new ArrayType(new MixedType(), new MixedType()), new ArrayType(new MixedType(), new MixedType())); - $result = $nodeScopeResolver->processStmtNodes(new Stmt\Namespace_(null, $stmts), $stmts, $scope, static function (): void { - }); + $result = $nodeScopeResolver->processStmtNodes( + new Stmt\Namespace_(null, $stmts), + $stmts, + $scope, + static function (): void { + }, + ); $this->assertSame($expectedIsAlwaysTerminating, $result->isAlwaysTerminating()); } diff --git a/tests/PHPStan/Analyser/ThrowsTagFromNativeFunctionStubTest.php b/tests/PHPStan/Analyser/ThrowsTagFromNativeFunctionStubTest.php index b2684c61a65..a6f515560be 100644 --- a/tests/PHPStan/Analyser/ThrowsTagFromNativeFunctionStubTest.php +++ b/tests/PHPStan/Analyser/ThrowsTagFromNativeFunctionStubTest.php @@ -16,7 +16,11 @@ public function dataFileAsserts(): iterable * @dataProvider dataFileAsserts * @param mixed ...$args */ - public function testFileAsserts(string $assertType, string $file, ...$args) : void + public function testFileAsserts( + string $assertType, + string $file, + ...$args, + ): void { $this->assertFileAsserts($assertType, $file, ...$args); } diff --git a/tests/PHPStan/Analyser/TraitStubFilesTest.php b/tests/PHPStan/Analyser/TraitStubFilesTest.php index 0f88f2cd42c..9858c6389d8 100644 --- a/tests/PHPStan/Analyser/TraitStubFilesTest.php +++ b/tests/PHPStan/Analyser/TraitStubFilesTest.php @@ -16,7 +16,11 @@ public function dataFileAsserts(): iterable * @dataProvider dataFileAsserts * @param mixed ...$args */ - public function testFileAsserts(string $assertType, string $file, ...$args) : void + public function testFileAsserts( + string $assertType, + string $file, + ...$args, + ): void { $this->assertFileAsserts($assertType, $file, ...$args); } diff --git a/tests/PHPStan/Analyser/TypeSpecifierTest.php b/tests/PHPStan/Analyser/TypeSpecifierTest.php index 9a0ffb311c8..245ba3d5549 100644 --- a/tests/PHPStan/Analyser/TypeSpecifierTest.php +++ b/tests/PHPStan/Analyser/TypeSpecifierTest.php @@ -49,17 +49,11 @@ class TypeSpecifierTest extends PHPStanTestCase private const SURE_NOT_TRUTHY = '~' . self::TRUTHY_TYPE_DESCRIPTION; /** @var Standard () */ - private $printer; + private Standard $printer; - /** - * @var TypeSpecifier - */ - private $typeSpecifier; + private TypeSpecifier $typeSpecifier; - /** - * @var Scope - */ - private $scope; + private Scope $scope; protected function setUp(): void { @@ -104,7 +98,10 @@ public function dataCondition(): iterable { if (PHP_VERSION_ID >= 80100) { yield [ - new Identical(new PropertyFetch(new Variable('foo'), 'bar'), new Expr\ClassConstFetch(new Name('Bug9499\\FooEnum'), 'A')), + new Identical( + new PropertyFetch(new Variable('foo'), 'bar'), + new Expr\ClassConstFetch(new Name('Bug9499\\FooEnum'), 'A'), + ), [ '$foo->bar' => 'Bug9499\FooEnum::A', ], @@ -113,7 +110,14 @@ public function dataCondition(): iterable ], ]; yield [ - new Identical(new AlwaysRememberedExpr(new PropertyFetch(new Variable('foo'), 'bar'), new ObjectType('Bug9499\\FooEnum'), new ObjectType('Bug9499\\FooEnum')), new Expr\ClassConstFetch(new Name('Bug9499\\FooEnum'), 'A')), + new Identical( + new AlwaysRememberedExpr( + new PropertyFetch(new Variable('foo'), 'bar'), + new ObjectType('Bug9499\\FooEnum'), + new ObjectType('Bug9499\\FooEnum'), + ), + new Expr\ClassConstFetch(new Name('Bug9499\\FooEnum'), 'A'), + ), [ '__phpstanRembered($foo->bar)' => 'Bug9499\FooEnum::A', '$foo->bar' => 'Bug9499\FooEnum::A', @@ -141,22 +145,34 @@ public function dataCondition(): iterable ['$foo' => '~bool|float|int|string'], ], [ - new Expr\BinaryOp\BooleanAnd($this->createFunctionCall('is_int'), $this->createFunctionCall('random')), + new Expr\BinaryOp\BooleanAnd( + $this->createFunctionCall('is_int'), + $this->createFunctionCall('random'), + ), ['$foo' => 'int'], [], ], [ - new Expr\BinaryOp\BooleanOr($this->createFunctionCall('is_int'), $this->createFunctionCall('random')), + new Expr\BinaryOp\BooleanOr( + $this->createFunctionCall('is_int'), + $this->createFunctionCall('random'), + ), [], ['$foo' => '~int'], ], [ - new Expr\BinaryOp\LogicalAnd($this->createFunctionCall('is_int'), $this->createFunctionCall('random')), + new Expr\BinaryOp\LogicalAnd( + $this->createFunctionCall('is_int'), + $this->createFunctionCall('random'), + ), ['$foo' => 'int'], [], ], [ - new Expr\BinaryOp\LogicalOr($this->createFunctionCall('is_int'), $this->createFunctionCall('random')), + new Expr\BinaryOp\LogicalOr( + $this->createFunctionCall('is_int'), + $this->createFunctionCall('random'), + ), [], ['$foo' => '~int'], ], @@ -167,12 +183,18 @@ public function dataCondition(): iterable ], [ - new Expr\BinaryOp\BooleanAnd(new Expr\BooleanNot($this->createFunctionCall('is_int')), $this->createFunctionCall('random')), + new Expr\BinaryOp\BooleanAnd( + new Expr\BooleanNot($this->createFunctionCall('is_int')), + $this->createFunctionCall('random'), + ), ['$foo' => '~int'], [], ], [ - new Expr\BinaryOp\BooleanOr(new Expr\BooleanNot($this->createFunctionCall('is_int')), $this->createFunctionCall('random')), + new Expr\BinaryOp\BooleanOr( + new Expr\BooleanNot($this->createFunctionCall('is_int')), + $this->createFunctionCall('random'), + ), [], ['$foo' => 'int'], ], @@ -192,26 +214,40 @@ public function dataCondition(): iterable ['$foo' => 'Foo'], ], [ - new Expr\Instanceof_(new Variable('foo'), new Variable('className')), + new Expr\Instanceof_( + new Variable('foo'), + new Variable('className'), + ), ['$foo' => 'object'], [], ], [ - new Equal(new FuncCall(new Name('get_class'), [ + new Equal( + new FuncCall(new Name('get_class'), [ new Arg(new Variable('foo')), - ]), new String_('Foo')), + ]), + new String_('Foo'), + ), ['$foo' => 'Foo', 'get_class($foo)' => '\'Foo\''], ['get_class($foo)' => '~\'Foo\''], ], [ - new Equal(new String_('Foo'), new FuncCall(new Name('get_class'), [ + new Equal( + new String_('Foo'), + new FuncCall(new Name('get_class'), [ new Arg(new Variable('foo')), - ])), + ]), + ), ['$foo' => 'Foo', 'get_class($foo)' => '\'Foo\''], ['get_class($foo)' => '~\'Foo\''], ], [ - new BooleanNot(new Expr\Instanceof_(new Variable('foo'), new Variable('className'))), + new BooleanNot( + new Expr\Instanceof_( + new Variable('foo'), + new Variable('className'), + ), + ), [], ['$foo' => 'object'], ], @@ -221,12 +257,18 @@ public function dataCondition(): iterable ['$foo' => self::SURE_NOT_TRUTHY], ], [ - new Expr\BinaryOp\BooleanAnd(new Variable('foo'), $this->createFunctionCall('random')), + new Expr\BinaryOp\BooleanAnd( + new Variable('foo'), + $this->createFunctionCall('random'), + ), ['$foo' => self::SURE_NOT_FALSEY], [], ], [ - new Expr\BinaryOp\BooleanOr(new Variable('foo'), $this->createFunctionCall('random')), + new Expr\BinaryOp\BooleanOr( + new Variable('foo'), + $this->createFunctionCall('random'), + ), [], ['$foo' => self::SURE_NOT_TRUTHY], ], @@ -242,12 +284,18 @@ public function dataCondition(): iterable ['$this->foo' => self::SURE_NOT_TRUTHY], ], [ - new Expr\BinaryOp\BooleanAnd(new PropertyFetch(new Variable('this'), 'foo'), $this->createFunctionCall('random')), + new Expr\BinaryOp\BooleanAnd( + new PropertyFetch(new Variable('this'), 'foo'), + $this->createFunctionCall('random'), + ), ['$this->foo' => self::SURE_NOT_FALSEY], [], ], [ - new Expr\BinaryOp\BooleanOr(new PropertyFetch(new Variable('this'), 'foo'), $this->createFunctionCall('random')), + new Expr\BinaryOp\BooleanOr( + new PropertyFetch(new Variable('this'), 'foo'), + $this->createFunctionCall('random'), + ), [], ['$this->foo' => self::SURE_NOT_TRUTHY], ], @@ -258,93 +306,165 @@ public function dataCondition(): iterable ], [ - new Expr\BinaryOp\BooleanOr($this->createFunctionCall('is_int'), $this->createFunctionCall('is_string')), + new Expr\BinaryOp\BooleanOr( + $this->createFunctionCall('is_int'), + $this->createFunctionCall('is_string'), + ), ['$foo' => 'int|string'], ['$foo' => '~int|string'], ], [ - new Expr\BinaryOp\BooleanOr($this->createFunctionCall('is_int'), new Expr\BinaryOp\BooleanOr($this->createFunctionCall('is_string'), $this->createFunctionCall('is_bool'))), + new Expr\BinaryOp\BooleanOr( + $this->createFunctionCall('is_int'), + new Expr\BinaryOp\BooleanOr( + $this->createFunctionCall('is_string'), + $this->createFunctionCall('is_bool'), + ), + ), ['$foo' => 'bool|int|string'], ['$foo' => '~bool|int|string'], ], [ - new Expr\BinaryOp\BooleanOr($this->createFunctionCall('is_int', 'foo'), $this->createFunctionCall('is_string', 'bar')), + new Expr\BinaryOp\BooleanOr( + $this->createFunctionCall('is_int', 'foo'), + $this->createFunctionCall('is_string', 'bar'), + ), [], ['$foo' => '~int', '$bar' => '~string'], ], [ - new Expr\BinaryOp\BooleanAnd(new Expr\BinaryOp\BooleanOr($this->createFunctionCall('is_int', 'foo'), $this->createFunctionCall('is_string', 'foo')), $this->createFunctionCall('random')), + new Expr\BinaryOp\BooleanAnd( + new Expr\BinaryOp\BooleanOr( + $this->createFunctionCall('is_int', 'foo'), + $this->createFunctionCall('is_string', 'foo'), + ), + $this->createFunctionCall('random'), + ), ['$foo' => 'int|string'], [], ], [ - new Expr\BinaryOp\BooleanOr(new Expr\BinaryOp\BooleanAnd($this->createFunctionCall('is_int', 'foo'), $this->createFunctionCall('is_string', 'foo')), $this->createFunctionCall('random')), + new Expr\BinaryOp\BooleanOr( + new Expr\BinaryOp\BooleanAnd( + $this->createFunctionCall('is_int', 'foo'), + $this->createFunctionCall('is_string', 'foo'), + ), + $this->createFunctionCall('random'), + ), [], ['$foo' => 'mixed'], ], [ - new Expr\BinaryOp\BooleanOr(new Expr\BinaryOp\BooleanAnd($this->createFunctionCall('is_int', 'foo'), $this->createFunctionCall('is_string', 'bar')), $this->createFunctionCall('random')), + new Expr\BinaryOp\BooleanOr( + new Expr\BinaryOp\BooleanAnd( + $this->createFunctionCall('is_int', 'foo'), + $this->createFunctionCall('is_string', 'bar'), + ), + $this->createFunctionCall('random'), + ), [], [], ], [ - new Expr\BinaryOp\BooleanOr(new Expr\BinaryOp\BooleanAnd(new Expr\BooleanNot($this->createFunctionCall('is_int', 'foo')), new Expr\BooleanNot($this->createFunctionCall('is_string', 'foo'))), $this->createFunctionCall('random')), + new Expr\BinaryOp\BooleanOr( + new Expr\BinaryOp\BooleanAnd( + new Expr\BooleanNot($this->createFunctionCall('is_int', 'foo')), + new Expr\BooleanNot($this->createFunctionCall('is_string', 'foo')), + ), + $this->createFunctionCall('random'), + ), [], ['$foo' => 'int|string'], ], [ - new Expr\BinaryOp\BooleanAnd(new Expr\BinaryOp\BooleanOr(new Expr\BooleanNot($this->createFunctionCall('is_int', 'foo')), new Expr\BooleanNot($this->createFunctionCall('is_string', 'foo'))), $this->createFunctionCall('random')), + new Expr\BinaryOp\BooleanAnd( + new Expr\BinaryOp\BooleanOr( + new Expr\BooleanNot($this->createFunctionCall('is_int', 'foo')), + new Expr\BooleanNot($this->createFunctionCall('is_string', 'foo')), + ), + $this->createFunctionCall('random'), + ), ['$foo' => 'mixed'], [], ], [ - new Identical(new Variable('foo'), new Expr\ConstFetch(new Name('true'))), + new Identical( + new Variable('foo'), + new Expr\ConstFetch(new Name('true')), + ), ['$foo' => 'true & ~' . self::FALSEY_TYPE_DESCRIPTION], ['$foo' => '~true'], ], [ - new Identical(new Variable('foo'), new Expr\ConstFetch(new Name('false'))), + new Identical( + new Variable('foo'), + new Expr\ConstFetch(new Name('false')), + ), ['$foo' => 'false & ~' . self::TRUTHY_TYPE_DESCRIPTION], ['$foo' => '~false'], ], [ - new Identical($this->createFunctionCall('is_int'), new Expr\ConstFetch(new Name('true'))), + new Identical( + $this->createFunctionCall('is_int'), + new Expr\ConstFetch(new Name('true')), + ), ['is_int($foo)' => 'true', '$foo' => 'int'], ['is_int($foo)' => '~true', '$foo' => '~int'], ], [ - new Identical($this->createFunctionCall('is_string'), new Expr\ConstFetch(new Name('true'))), + new Identical( + $this->createFunctionCall('is_string'), + new Expr\ConstFetch(new Name('true')), + ), ['is_string($foo)' => 'true', '$foo' => 'string'], ['is_string($foo)' => '~true', '$foo' => '~string'], ], [ - new Identical($this->createFunctionCall('is_int'), new Expr\ConstFetch(new Name('false'))), + new Identical( + $this->createFunctionCall('is_int'), + new Expr\ConstFetch(new Name('false')), + ), ['is_int($foo)' => 'false', '$foo' => '~int'], ['$foo' => 'int', 'is_int($foo)' => '~false'], ], [ - new Equal($this->createFunctionCall('is_int'), new Expr\ConstFetch(new Name('true'))), + new Equal( + $this->createFunctionCall('is_int'), + new Expr\ConstFetch(new Name('true')), + ), ['$foo' => 'int'], ['$foo' => '~int'], ], [ - new Equal($this->createFunctionCall('is_int'), new Expr\ConstFetch(new Name('false'))), + new Equal( + $this->createFunctionCall('is_int'), + new Expr\ConstFetch(new Name('false')), + ), ['$foo' => '~int'], ['$foo' => 'int'], ], [ - new Equal(new Variable('foo'), new Expr\ConstFetch(new Name('false'))), + new Equal( + new Variable('foo'), + new Expr\ConstFetch(new Name('false')), + ), ['$foo' => self::SURE_NOT_TRUTHY], ['$foo' => self::SURE_NOT_FALSEY], ], [ - new Equal(new Variable('foo'), new Expr\ConstFetch(new Name('null'))), + new Equal( + new Variable('foo'), + new Expr\ConstFetch(new Name('null')), + ), ['$foo' => self::SURE_NOT_TRUTHY], ['$foo' => self::SURE_NOT_FALSEY], ], [ - new Expr\BinaryOp\Identical(new Variable('foo'), new Variable('bar')), + new Expr\BinaryOp\Identical( + new Variable('foo'), + new Variable('bar'), + ), ['$foo' => 'Bar', '$bar' => 'mixed'], // could be '$bar' => 'Bar' [], ], @@ -367,7 +487,10 @@ public function dataCondition(): iterable [ new FuncCall(new Name('is_a'), [ new Arg(new Variable('foo')), - new Arg(new Expr\ClassConstFetch(new Name('static'), 'class')), + new Arg(new Expr\ClassConstFetch( + new Name('static'), + 'class', + )), ]), ['$foo' => 'static(DateTime)'], [], @@ -425,17 +548,26 @@ public function dataCondition(): iterable [], ], [ - new Expr\Assign(new Variable('foo'), new Variable('stringOrNull')), + new Expr\Assign( + new Variable('foo'), + new Variable('stringOrNull'), + ), ['$foo' => self::SURE_NOT_FALSEY], ['$foo' => self::SURE_NOT_TRUTHY], ], [ - new Expr\Assign(new Variable('foo'), new Variable('stringOrFalse')), + new Expr\Assign( + new Variable('foo'), + new Variable('stringOrFalse'), + ), ['$foo' => self::SURE_NOT_FALSEY], ['$foo' => self::SURE_NOT_TRUTHY], ], [ - new Expr\Assign(new Variable('foo'), new Variable('bar')), + new Expr\Assign( + new Variable('foo'), + new Variable('bar'), + ), ['$foo' => self::SURE_NOT_FALSEY], ['$foo' => self::SURE_NOT_TRUTHY], ], @@ -484,7 +616,10 @@ public function dataCondition(): iterable ], ], [ - new Expr\BinaryOp\Identical(new Variable('foo'), new LNumber(123)), + new Expr\BinaryOp\Identical( + new Variable('foo'), + new LNumber(123), + ), [ '$foo' => '123', ], @@ -571,21 +706,35 @@ public function dataCondition(): iterable ], ], [ - new Equal(new Expr\Instanceof_(new Variable('foo'), new Variable('className')), new LNumber(1)), + new Equal( + new Expr\Instanceof_( + new Variable('foo'), + new Variable('className'), + ), + new LNumber(1), + ), ['$foo' => 'object'], [], ], [ - new Equal(new Expr\Instanceof_(new Variable('foo'), new Variable('className')), new LNumber(0)), + new Equal( + new Expr\Instanceof_( + new Variable('foo'), + new Variable('className'), + ), + new LNumber(0), + ), [], [ '$foo' => 'object', ], ], [ - new Expr\Isset_([ + new Expr\Isset_( + [ new PropertyFetch(new Variable('foo'), new Identifier('bar')), - ]), + ], + ), [ '$foo' => 'object&hasProperty(bar) & ~null', '$foo->bar' => '~null', @@ -593,16 +742,21 @@ public function dataCondition(): iterable [], ], [ - new Expr\Isset_([ + new Expr\Isset_( + [ new Expr\StaticPropertyFetch(new Name('Foo'), new VarLikeIdentifier('bar')), - ]), + ], + ), [ 'Foo::$bar' => '~null', ], [], ], [ - new Identical(new Variable('barOrNull'), new Expr\ConstFetch(new Name('null'))), + new Identical( + new Variable('barOrNull'), + new Expr\ConstFetch(new Name('null')), + ), [ '$barOrNull' => 'null', ], @@ -611,7 +765,13 @@ public function dataCondition(): iterable ], ], [ - new Identical(new Expr\Assign(new Variable('notNullBar'), new Variable('barOrNull')), new Expr\ConstFetch(new Name('null'))), + new Identical( + new Expr\Assign( + new Variable('notNullBar'), + new Variable('barOrNull'), + ), + new Expr\ConstFetch(new Name('null')), + ), [ '$notNullBar' => 'null', '$barOrNull' => 'null', @@ -622,7 +782,10 @@ public function dataCondition(): iterable ], ], [ - new NotIdentical(new Variable('barOrNull'), new Expr\ConstFetch(new Name('null'))), + new NotIdentical( + new Variable('barOrNull'), + new Expr\ConstFetch(new Name('null')), + ), [ '$barOrNull' => '~null', ], @@ -631,7 +794,10 @@ public function dataCondition(): iterable ], ], [ - new Expr\BinaryOp\Smaller(new Variable('n'), new LNumber(3)), + new Expr\BinaryOp\Smaller( + new Variable('n'), + new LNumber(3), + ), [ '$n' => 'mixed~int<3, max>|true', ], @@ -640,7 +806,10 @@ public function dataCondition(): iterable ], ], [ - new Expr\BinaryOp\Smaller(new Variable('n'), new LNumber(PHP_INT_MIN)), + new Expr\BinaryOp\Smaller( + new Variable('n'), + new LNumber(PHP_INT_MIN), + ), [ '$n' => 'mixed~int<' . PHP_INT_MIN . ', max>|true', ], @@ -649,7 +818,10 @@ public function dataCondition(): iterable ], ], [ - new Expr\BinaryOp\Greater(new Variable('n'), new LNumber(PHP_INT_MAX)), + new Expr\BinaryOp\Greater( + new Variable('n'), + new LNumber(PHP_INT_MAX), + ), [ '$n' => 'mixed~bool|int|null', ], @@ -658,7 +830,10 @@ public function dataCondition(): iterable ], ], [ - new Expr\BinaryOp\SmallerOrEqual(new Variable('n'), new LNumber(PHP_INT_MIN)), + new Expr\BinaryOp\SmallerOrEqual( + new Variable('n'), + new LNumber(PHP_INT_MIN), + ), [ '$n' => 'mixed~int<' . (PHP_INT_MIN + 1) . ', max>', ], @@ -667,7 +842,10 @@ public function dataCondition(): iterable ], ], [ - new Expr\BinaryOp\GreaterOrEqual(new Variable('n'), new LNumber(PHP_INT_MAX)), + new Expr\BinaryOp\GreaterOrEqual( + new Variable('n'), + new LNumber(PHP_INT_MAX), + ), [ '$n' => 'mixed~int|false|null', ], @@ -676,7 +854,16 @@ public function dataCondition(): iterable ], ], [ - new Expr\BinaryOp\BooleanAnd(new Expr\BinaryOp\GreaterOrEqual(new Variable('n'), new LNumber(3)), new Expr\BinaryOp\SmallerOrEqual(new Variable('n'), new LNumber(5))), + new Expr\BinaryOp\BooleanAnd( + new Expr\BinaryOp\GreaterOrEqual( + new Variable('n'), + new LNumber(3), + ), + new Expr\BinaryOp\SmallerOrEqual( + new Variable('n'), + new LNumber(5), + ), + ), [ '$n' => 'mixed~int|int<6, max>|false|null', ], @@ -685,7 +872,16 @@ public function dataCondition(): iterable ], ], [ - new Expr\BinaryOp\BooleanAnd(new Expr\Assign(new Variable('foo'), new LNumber(1)), new Expr\BinaryOp\SmallerOrEqual(new Variable('n'), new LNumber(5))), + new Expr\BinaryOp\BooleanAnd( + new Expr\Assign( + new Variable('foo'), + new LNumber(1), + ), + new Expr\BinaryOp\SmallerOrEqual( + new Variable('n'), + new LNumber(5), + ), + ), [ '$n' => 'mixed~int<6, max>', '$foo' => self::SURE_NOT_FALSEY, @@ -693,7 +889,13 @@ public function dataCondition(): iterable [], ], [ - new NotIdentical(new Expr\Assign(new Variable('notNullBar'), new Variable('barOrNull')), new Expr\ConstFetch(new Name('null'))), + new NotIdentical( + new Expr\Assign( + new Variable('notNullBar'), + new Variable('barOrNull'), + ), + new Expr\ConstFetch(new Name('null')), + ), [ '$notNullBar' => '~null', '$barOrNull' => '~null', @@ -704,7 +906,10 @@ public function dataCondition(): iterable ], ], [ - new Identical(new Variable('barOrFalse'), new Expr\ConstFetch(new Name('false'))), + new Identical( + new Variable('barOrFalse'), + new Expr\ConstFetch(new Name('false')), + ), [ '$barOrFalse' => 'false & ' . self::SURE_NOT_TRUTHY, ], @@ -713,7 +918,13 @@ public function dataCondition(): iterable ], ], [ - new Identical(new Expr\Assign(new Variable('notFalseBar'), new Variable('barOrFalse')), new Expr\ConstFetch(new Name('false'))), + new Identical( + new Expr\Assign( + new Variable('notFalseBar'), + new Variable('barOrFalse'), + ), + new Expr\ConstFetch(new Name('false')), + ), [ '$notFalseBar' => 'false & ' . self::SURE_NOT_TRUTHY, '$barOrFalse' => 'false', @@ -724,7 +935,19 @@ public function dataCondition(): iterable ], ], [ - new Identical(new Expr\ConstFetch(new Name('null')), new Expr\AssignOp\Coalesce(new Variable('a'), new Expr\Ternary(new Variable('b'), new Variable('b'), new Expr\ConstFetch(new Name('null'))))), + new Identical( + new Expr\ConstFetch(new Name('null')), + new Expr\AssignOp\Coalesce( + new Variable('a'), + new Expr\Ternary( + new Variable('b'), + new Variable('b'), + new Expr\ConstFetch( + new Name('null'), + ), + ), + ), + ), [ '$a' => 'null', ], @@ -733,7 +956,10 @@ public function dataCondition(): iterable ], ], [ - new NotIdentical(new Variable('barOrFalse'), new Expr\ConstFetch(new Name('false'))), + new NotIdentical( + new Variable('barOrFalse'), + new Expr\ConstFetch(new Name('false')), + ), [ '$barOrFalse' => '~false', ], @@ -742,7 +968,13 @@ public function dataCondition(): iterable ], ], [ - new NotIdentical(new Expr\Assign(new Variable('notFalseBar'), new Variable('barOrFalse')), new Expr\ConstFetch(new Name('false'))), + new NotIdentical( + new Expr\Assign( + new Variable('notFalseBar'), + new Variable('barOrFalse'), + ), + new Expr\ConstFetch(new Name('false')), + ), [ '$notFalseBar' => '~false', '$barOrFalse' => '~false', @@ -753,7 +985,13 @@ public function dataCondition(): iterable ], ], [ - new Expr\Instanceof_(new Expr\Assign(new Variable('notFalseBar'), new Variable('barOrFalse')), new Name('Bar')), + new Expr\Instanceof_( + new Expr\Assign( + new Variable('notFalseBar'), + new Variable('barOrFalse'), + ), + new Name('Bar'), + ), [ '$notFalseBar' => 'Bar', '$barOrFalse' => 'Bar', @@ -764,13 +1002,16 @@ public function dataCondition(): iterable ], ], [ - new Expr\BinaryOp\BooleanOr(new FuncCall(new Name('array_key_exists'), [ + new Expr\BinaryOp\BooleanOr( + new FuncCall(new Name('array_key_exists'), [ new Arg(new String_('foo')), new Arg(new Variable('array')), - ]), new FuncCall(new Name('array_key_exists'), [ + ]), + new FuncCall(new Name('array_key_exists'), [ new Arg(new String_('bar')), new Arg(new Variable('array')), - ])), + ]), + ), [ '$array' => 'array', ], @@ -779,13 +1020,16 @@ public function dataCondition(): iterable ], ], [ - new BooleanNot(new Expr\BinaryOp\BooleanOr(new FuncCall(new Name('array_key_exists'), [ + new BooleanNot(new Expr\BinaryOp\BooleanOr( + new FuncCall(new Name('array_key_exists'), [ new Arg(new String_('foo')), new Arg(new Variable('array')), - ]), new FuncCall(new Name('array_key_exists'), [ + ]), + new FuncCall(new Name('array_key_exists'), [ new Arg(new String_('bar')), new Arg(new Variable('array')), - ]))), + ]), + )), [ '$array' => '~hasOffset(\'bar\')|hasOffset(\'foo\')', ], @@ -806,13 +1050,16 @@ public function dataCondition(): iterable ], ], [ - new Expr\BinaryOp\BooleanOr(new FuncCall(new Name('key_exists'), [ + new Expr\BinaryOp\BooleanOr( + new FuncCall(new Name('key_exists'), [ new Arg(new String_('foo')), new Arg(new Variable('array')), - ]), new FuncCall(new Name('key_exists'), [ + ]), + new FuncCall(new Name('key_exists'), [ new Arg(new String_('bar')), new Arg(new Variable('array')), - ])), + ]), + ), [ '$array' => 'array', ], @@ -821,13 +1068,16 @@ public function dataCondition(): iterable ], ], [ - new BooleanNot(new Expr\BinaryOp\BooleanOr(new FuncCall(new Name('key_exists'), [ + new BooleanNot(new Expr\BinaryOp\BooleanOr( + new FuncCall(new Name('key_exists'), [ new Arg(new String_('foo')), new Arg(new Variable('array')), - ]), new FuncCall(new Name('key_exists'), [ + ]), + new FuncCall(new Name('key_exists'), [ new Arg(new String_('bar')), new Arg(new Variable('array')), - ]))), + ]), + )), [ '$array' => '~hasOffset(\'bar\')|hasOffset(\'foo\')', ], @@ -912,22 +1162,55 @@ public function dataCondition(): iterable [], ], [ - new Expr\BinaryOp\BooleanOr(new Expr\BinaryOp\BooleanAnd($this->createFunctionCall('is_string', 'a'), new NotIdentical(new String_(''), new Variable('a'))), new Identical(new Expr\ConstFetch(new Name('null')), new Variable('a'))), + new Expr\BinaryOp\BooleanOr( + new Expr\BinaryOp\BooleanAnd( + $this->createFunctionCall('is_string', 'a'), + new NotIdentical(new String_(''), new Variable('a')), + ), + new Identical(new Expr\ConstFetch(new Name('null')), new Variable('a')), + ), ['$a' => 'non-empty-string|null'], ['$a' => 'mixed~non-empty-string & ~null'], ], [ - new Expr\BinaryOp\BooleanOr(new Expr\BinaryOp\BooleanAnd($this->createFunctionCall('is_string', 'a'), new Expr\BinaryOp\Greater($this->createFunctionCall('strlen', 'a'), new LNumber(0))), new Identical(new Expr\ConstFetch(new Name('null')), new Variable('a'))), + new Expr\BinaryOp\BooleanOr( + new Expr\BinaryOp\BooleanAnd( + $this->createFunctionCall('is_string', 'a'), + new Expr\BinaryOp\Greater( + $this->createFunctionCall('strlen', 'a'), + new LNumber(0), + ), + ), + new Identical(new Expr\ConstFetch(new Name('null')), new Variable('a')), + ), ['$a' => 'non-empty-string|null'], ['$a' => 'mixed~non-empty-string & ~null'], ], [ - new Expr\BinaryOp\BooleanOr(new Expr\BinaryOp\BooleanAnd($this->createFunctionCall('is_array', 'a'), new Expr\BinaryOp\Greater($this->createFunctionCall('count', 'a'), new LNumber(0))), new Identical(new Expr\ConstFetch(new Name('null')), new Variable('a'))), + new Expr\BinaryOp\BooleanOr( + new Expr\BinaryOp\BooleanAnd( + $this->createFunctionCall('is_array', 'a'), + new Expr\BinaryOp\Greater( + $this->createFunctionCall('count', 'a'), + new LNumber(0), + ), + ), + new Identical(new Expr\ConstFetch(new Name('null')), new Variable('a')), + ), ['$a' => 'non-empty-array|null'], ['$a' => 'mixed~non-empty-array & ~null'], ], [ - new Expr\BinaryOp\BooleanAnd($this->createFunctionCall('is_array', 'foo'), new Identical(new FuncCall(new Name('array_filter'), [new Arg(new Variable('foo')), new Arg(new String_('is_string')), new Arg(new ConstFetch(new Name('ARRAY_FILTER_USE_KEY')))]), new Variable('foo'))), + new Expr\BinaryOp\BooleanAnd( + $this->createFunctionCall('is_array', 'foo'), + new Identical( + new FuncCall( + new Name('array_filter'), + [new Arg(new Variable('foo')), new Arg(new String_('is_string')), new Arg(new ConstFetch(new Name('ARRAY_FILTER_USE_KEY')))], + ), + new Variable('foo'), + ), + ), [ '$foo' => 'array', 'array_filter($foo, \'is_string\', ARRAY_FILTER_USE_KEY)' => 'array', // could be 'array' @@ -935,7 +1218,16 @@ public function dataCondition(): iterable [], ], [ - new Expr\BinaryOp\BooleanAnd($this->createFunctionCall('is_array', 'foo'), new Expr\BinaryOp\GreaterOrEqual(new FuncCall(new Name('count'), [new Arg(new Variable('foo'))]), new LNumber(2))), + new Expr\BinaryOp\BooleanAnd( + $this->createFunctionCall('is_array', 'foo'), + new Expr\BinaryOp\GreaterOrEqual( + new FuncCall( + new Name('count'), + [new Arg(new Variable('foo'))], + ), + new LNumber(2), + ), + ), [ '$foo' => 'non-empty-array', 'count($foo)' => 'mixed~int|false|null', @@ -943,7 +1235,16 @@ public function dataCondition(): iterable [], ], [ - new Expr\BinaryOp\BooleanAnd($this->createFunctionCall('is_array', 'foo'), new Identical(new FuncCall(new Name('count'), [new Arg(new Variable('foo'))]), new LNumber(2))), + new Expr\BinaryOp\BooleanAnd( + $this->createFunctionCall('is_array', 'foo'), + new Identical( + new FuncCall( + new Name('count'), + [new Arg(new Variable('foo'))], + ), + new LNumber(2), + ), + ), [ '$foo' => 'non-empty-array', 'count($foo)' => '2', @@ -951,7 +1252,16 @@ public function dataCondition(): iterable [], ], [ - new Expr\BinaryOp\BooleanAnd($this->createFunctionCall('is_string', 'foo'), new NotIdentical(new FuncCall(new Name('strlen'), [new Arg(new Variable('foo'))]), new LNumber(0))), + new Expr\BinaryOp\BooleanAnd( + $this->createFunctionCall('is_string', 'foo'), + new NotIdentical( + new FuncCall( + new Name('strlen'), + [new Arg(new Variable('foo'))], + ), + new LNumber(0), + ), + ), [ '$foo' => 'non-empty-string', 'strlen($foo)' => '~0', @@ -961,7 +1271,13 @@ public function dataCondition(): iterable ], ], [ - new Expr\BinaryOp\BooleanAnd($this->createFunctionCall('is_numeric', 'int'), new Expr\BinaryOp\Equal(new Variable('int'), new Expr\Cast\Int_(new Variable('int')))), + new Expr\BinaryOp\BooleanAnd( + $this->createFunctionCall('is_numeric', 'int'), + new Expr\BinaryOp\Equal( + new Variable('int'), + new Expr\Cast\Int_(new Variable('int')), + ), + ), [ '$int' => 'int', '(int) $int' => 'int', @@ -969,7 +1285,13 @@ public function dataCondition(): iterable [], ], [ - new Expr\BinaryOp\BooleanAnd($this->createFunctionCall('is_numeric', 'float'), new Expr\BinaryOp\Equal(new Variable('float'), new Expr\Cast\Int_(new Variable('float')))), + new Expr\BinaryOp\BooleanAnd( + $this->createFunctionCall('is_numeric', 'float'), + new Expr\BinaryOp\Equal( + new Variable('float'), + new Expr\Cast\Int_(new Variable('float')), + ), + ), [ '$float' => 'float', '(int) $float' => 'int', diff --git a/tests/PHPStan/Analyser/TypeSpecifyingExtensionTypeInferenceFalseTest.php b/tests/PHPStan/Analyser/TypeSpecifyingExtensionTypeInferenceFalseTest.php index adc8f35e386..33789229939 100644 --- a/tests/PHPStan/Analyser/TypeSpecifyingExtensionTypeInferenceFalseTest.php +++ b/tests/PHPStan/Analyser/TypeSpecifyingExtensionTypeInferenceFalseTest.php @@ -18,7 +18,11 @@ public function dataTypeSpecifyingExtensionsFalse(): iterable * @dataProvider dataTypeSpecifyingExtensionsFalse * @param mixed ...$args */ - public function testTypeSpecifyingExtensionsFalse(string $assertType, string $file, ...$args) : void + public function testTypeSpecifyingExtensionsFalse( + string $assertType, + string $file, + ...$args, + ): void { $this->assertFileAsserts($assertType, $file, ...$args); } diff --git a/tests/PHPStan/Analyser/TypeSpecifyingExtensionTypeInferenceNullTest.php b/tests/PHPStan/Analyser/TypeSpecifyingExtensionTypeInferenceNullTest.php index 04489b22552..bc8276fb590 100644 --- a/tests/PHPStan/Analyser/TypeSpecifyingExtensionTypeInferenceNullTest.php +++ b/tests/PHPStan/Analyser/TypeSpecifyingExtensionTypeInferenceNullTest.php @@ -18,7 +18,11 @@ public function dataTypeSpecifyingExtensionsNull(): iterable * @dataProvider dataTypeSpecifyingExtensionsNull * @param mixed ...$args */ - public function testTypeSpecifyingExtensionsNull(string $assertType, string $file, ...$args) : void + public function testTypeSpecifyingExtensionsNull( + string $assertType, + string $file, + ...$args, + ): void { $this->assertFileAsserts($assertType, $file, ...$args); } diff --git a/tests/PHPStan/Analyser/TypeSpecifyingExtensionTypeInferenceTrueTest.php b/tests/PHPStan/Analyser/TypeSpecifyingExtensionTypeInferenceTrueTest.php index 9d3ea5dfe1c..7478a93f2af 100644 --- a/tests/PHPStan/Analyser/TypeSpecifyingExtensionTypeInferenceTrueTest.php +++ b/tests/PHPStan/Analyser/TypeSpecifyingExtensionTypeInferenceTrueTest.php @@ -18,7 +18,11 @@ public function dataTypeSpecifyingExtensionsTrue(): iterable * @dataProvider dataTypeSpecifyingExtensionsTrue * @param mixed ...$args */ - public function testTypeSpecifyingExtensionsTrue(string $assertType, string $file, ...$args) : void + public function testTypeSpecifyingExtensionsTrue( + string $assertType, + string $file, + ...$args, + ): void { $this->assertFileAsserts($assertType, $file, ...$args); } diff --git a/tests/PHPStan/Collectors/RegistryTest.php b/tests/PHPStan/Collectors/RegistryTest.php index 130d460cf07..ac7e0c2e9d3 100644 --- a/tests/PHPStan/Collectors/RegistryTest.php +++ b/tests/PHPStan/Collectors/RegistryTest.php @@ -26,12 +26,8 @@ public function testGetCollectors(): void public function testGetCollectorsWithTwoDifferentInstances(): void { - $fooCollector = new UniversalCollector(Node\Expr\FuncCall::class, static function (Node\Expr\FuncCall $node, Scope $scope) : array { - return ['Foo error']; - }); - $barCollector = new UniversalCollector(Node\Expr\FuncCall::class, static function (Node\Expr\FuncCall $node, Scope $scope) : array { - return ['Bar error']; - }); + $fooCollector = new UniversalCollector(Node\Expr\FuncCall::class, static fn (Node\Expr\FuncCall $node, Scope $scope): array => ['Foo error']); + $barCollector = new UniversalCollector(Node\Expr\FuncCall::class, static fn (Node\Expr\FuncCall $node, Scope $scope): array => ['Bar error']); $registry = new Registry([ $fooCollector, diff --git a/tests/PHPStan/Command/AnalyseApplicationIntegrationTest.php b/tests/PHPStan/Command/AnalyseApplicationIntegrationTest.php index 8dfe735eebe..a7cb8997d84 100644 --- a/tests/PHPStan/Command/AnalyseApplicationIntegrationTest.php +++ b/tests/PHPStan/Command/AnalyseApplicationIntegrationTest.php @@ -37,7 +37,10 @@ public function testExecuteOnANonExistentPath(): void { $path = __DIR__ . '/foo'; $output = $this->runPath($path, 1); - $this->assertStringContainsString(sprintf('File %s does not exist.', $path), $output); + $this->assertStringContainsString(sprintf( + 'File %s does not exist.', + $path, + ), $output); } public function testExecuteOnAFileWithErrors(): void @@ -57,13 +60,36 @@ private function runPath(string $path, int $expectedStatusCode): string } $output = new StreamOutput($resource); - $symfonyOutput = new SymfonyOutput($output, new \PHPStan\Command\Symfony\SymfonyStyle(new SymfonyStyle($this->createMock(InputInterface::class), $output))); + $symfonyOutput = new SymfonyOutput( + $output, + new \PHPStan\Command\Symfony\SymfonyStyle(new SymfonyStyle($this->createMock(InputInterface::class), $output)), + ); $memoryLimitFile = self::getContainer()->getParameter('memoryLimitFile'); $relativePathHelper = new FuzzyRelativePathHelper(new NullRelativePathHelper(), __DIR__, [], DIRECTORY_SEPARATOR); - $errorFormatter = new TableErrorFormatter($relativePathHelper, new SimpleRelativePathHelper(__DIR__), new CiDetectedErrorFormatter(new GithubErrorFormatter($relativePathHelper), new TeamcityErrorFormatter($relativePathHelper)), false, null, null); - $analysisResult = $analyserApplication->analyse([$path], true, $symfonyOutput, $symfonyOutput, false, true, null, null, $this->createMock(InputInterface::class)); + $errorFormatter = new TableErrorFormatter( + $relativePathHelper, + new SimpleRelativePathHelper(__DIR__), + new CiDetectedErrorFormatter( + new GithubErrorFormatter($relativePathHelper), + new TeamcityErrorFormatter($relativePathHelper), + ), + false, + null, + null, + ); + $analysisResult = $analyserApplication->analyse( + [$path], + true, + $symfonyOutput, + $symfonyOutput, + false, + true, + null, + null, + $this->createMock(InputInterface::class), + ); if (file_exists($memoryLimitFile)) { unlink($memoryLimitFile); } diff --git a/tests/PHPStan/Command/AnalysisResultTest.php b/tests/PHPStan/Command/AnalysisResultTest.php index aac5a74e6de..ea7cb93fc42 100644 --- a/tests/PHPStan/Command/AnalysisResultTest.php +++ b/tests/PHPStan/Command/AnalysisResultTest.php @@ -10,7 +10,8 @@ final class AnalysisResultTest extends PHPStanTestCase public function testErrorsAreSortedByFileNameAndLine(): void { - self::assertEquals([ + self::assertEquals( + [ new Error('aa1', 'aaa'), new Error('aa2', 'aaa', 10), new Error('aa3', 'aaa', 15), @@ -21,7 +22,9 @@ public function testErrorsAreSortedByFileNameAndLine(): void new Error('bb1', 'bbb', 4), new Error('ccc', 'ccc'), new Error('ddd', 'ddd'), - ], (new AnalysisResult([ + ], + (new AnalysisResult( + [ new Error('bb1', 'bbb', 4), new Error('bb2', 'bbb', 2), new Error('aa1', 'aaa'), @@ -32,7 +35,18 @@ public function testErrorsAreSortedByFileNameAndLine(): void new Error('aa5', 'aaa', 16), new Error('aa6', 'aaa', 16), new Error('aa4', 'aaa', 16), - ], [], [], [], [], false, null, true, 0, false))->getFileSpecificErrors()); + ], + [], + [], + [], + [], + false, + null, + true, + 0, + false, + ))->getFileSpecificErrors(), + ); } } diff --git a/tests/PHPStan/Command/CommandHelperTest.php b/tests/PHPStan/Command/CommandHelperTest.php index 0803cb3cec3..8c29068a989 100644 --- a/tests/PHPStan/Command/CommandHelperTest.php +++ b/tests/PHPStan/Command/CommandHelperTest.php @@ -97,19 +97,38 @@ public function dataBegin(): array * @dataProvider dataBegin * @param mixed[] $expectedParameters */ - public function testBegin(string $input, string $expectedOutput, ?string $projectConfigFile, ?string $level, array $expectedParameters, bool $expectException) : void + public function testBegin( + string $input, + string $expectedOutput, + ?string $projectConfigFile, + ?string $level, + array $expectedParameters, + bool $expectException, + ): void { $resource = fopen('php://memory', 'w', false); if ($resource === false) { throw new ShouldNotHappenException(); } $output = new StreamOutput($resource); + try { - $result = CommandHelper::begin(new StringInput($input), $output, [__DIR__], null, null, [], $projectConfigFile, null, $level, false); + $result = CommandHelper::begin( + new StringInput($input), + $output, + [__DIR__], + null, + null, + [], + $projectConfigFile, + null, + $level, + false, + ); if ($expectException) { $this->fail(); } - } catch (InceptionNotSuccessfulException $e) { + } catch (InceptionNotSuccessfulException) { if (!$expectException) { rewind($output->getStream()); $contents = stream_get_contents($output->getStream()); @@ -119,12 +138,15 @@ public function testBegin(string $input, string $expectedOutput, ?string $projec $this->fail($contents); } } + rewind($output->getStream()); + $contents = stream_get_contents($output->getStream()); if ($contents === false) { throw new ShouldNotHappenException(); } $this->assertStringContainsString($expectedOutput, $contents); + if (isset($result)) { $parameters = $result->getContainer()->getParameters(); foreach ($expectedParameters as $name => $expectedValue) { @@ -269,9 +291,23 @@ public function dataParameters(): array * @param array $expectedParameters * @throws InceptionNotSuccessfulException */ - public function testResolveParameters(string $configFile, array $expectedParameters) : void + public function testResolveParameters( + string $configFile, + array $expectedParameters, + ): void { - $result = CommandHelper::begin(new StringInput(''), new NullOutput(), [__DIR__], null, null, [], $configFile, null, '0', false); + $result = CommandHelper::begin( + new StringInput(''), + new NullOutput(), + [__DIR__], + null, + null, + [], + $configFile, + null, + '0', + false, + ); $parameters = $result->getContainer()->getParameters(); foreach ($expectedParameters as $name => $expectedValue) { $this->assertArrayHasKey($name, $parameters); diff --git a/tests/PHPStan/Command/ErrorFormatter/BaselineNeonErrorFormatterIntegrationTest.php b/tests/PHPStan/Command/ErrorFormatter/BaselineNeonErrorFormatterIntegrationTest.php index 7f88f7ed890..07c6d9ffe27 100644 --- a/tests/PHPStan/Command/ErrorFormatter/BaselineNeonErrorFormatterIntegrationTest.php +++ b/tests/PHPStan/Command/ErrorFormatter/BaselineNeonErrorFormatterIntegrationTest.php @@ -57,7 +57,12 @@ public function testRunUnixFileWithWindowsBaseline(): void $this->assertCount(0, $errors['files']); } - private function runPhpStan(string $analysedPath, ?string $configFile, string $errorFormatter = 'json', ?string $baselineFile = null) : string + private function runPhpStan( + string $analysedPath, + ?string $configFile, + string $errorFormatter = 'json', + ?string $baselineFile = null, + ): string { $originalDir = getcwd(); if ($originalDir === false) { @@ -68,8 +73,10 @@ private function runPhpStan(string $analysedPath, ?string $configFile, string $e if ($clearResultCacheExitCode !== 0) { throw new ShouldNotHappenException('Could not clear result cache.'); } + exec(sprintf('%s %s analyse --no-progress --error-format=%s --level=7 %s %s%s', escapeshellarg(PHP_BINARY), 'bin/phpstan', $errorFormatter, $configFile !== null ? '--configuration ' . escapeshellarg($configFile) : '', escapeshellarg($analysedPath), $baselineFile !== null ? ' --generate-baseline ' . escapeshellarg($baselineFile) : ''), $outputLines); chdir($originalDir); + return implode("\n", $outputLines); } diff --git a/tests/PHPStan/Command/ErrorFormatter/BaselineNeonErrorFormatterTest.php b/tests/PHPStan/Command/ErrorFormatter/BaselineNeonErrorFormatterTest.php index f7a141f7311..4066079d7f6 100644 --- a/tests/PHPStan/Command/ErrorFormatter/BaselineNeonErrorFormatterTest.php +++ b/tests/PHPStan/Command/ErrorFormatter/BaselineNeonErrorFormatterTest.php @@ -116,10 +116,22 @@ public function dataFormatterOutputProvider(): iterable * * @param mixed[] $expected */ - public function testFormatErrors(string $message, int $exitCode, int $numFileErrors, int $numGenericErrors, array $expected) : void + public function testFormatErrors( + string $message, + int $exitCode, + int $numFileErrors, + int $numGenericErrors, + array $expected, + ): void { $formatter = new BaselineNeonErrorFormatter(new SimpleRelativePathHelper(self::DIRECTORY_PATH)); - $this->assertSame($exitCode, $formatter->formatErrors($this->getAnalysisResult($numFileErrors, $numGenericErrors), $this->getOutput(), ''), sprintf('%s: response code do not match', $message)); + + $this->assertSame($exitCode, $formatter->formatErrors( + $this->getAnalysisResult($numFileErrors, $numGenericErrors), + $this->getOutput(), + '', + ), sprintf('%s: response code do not match', $message)); + $this->assertSame(trim(Neon::encode(['parameters' => ['ignoreErrors' => $expected]], Neon::BLOCK)), trim($this->getOutputContent()), sprintf('%s: output do not match', $message)); } @@ -127,10 +139,27 @@ public function testFormatErrorMessagesRegexEscape(): void { $formatter = new BaselineNeonErrorFormatter(new SimpleRelativePathHelper(self::DIRECTORY_PATH)); - $result = new AnalysisResult([new Error('Escape Regex with file # ~ \' ()', 'Testfile')], ['Escape Regex without file # ~ <> \' ()'], [], [], [], false, null, true, 0, false); - $formatter->formatErrors($result, $this->getOutput(), ''); + $result = new AnalysisResult( + [new Error('Escape Regex with file # ~ \' ()', 'Testfile')], + ['Escape Regex without file # ~ <> \' ()'], + [], + [], + [], + false, + null, + true, + 0, + false, + ); + $formatter->formatErrors( + $result, + $this->getOutput(), + '', + ); - self::assertSame(trim(Neon::encode([ + self::assertSame( + trim( + Neon::encode([ 'parameters' => [ 'ignoreErrors' => [ [ @@ -140,16 +169,36 @@ public function testFormatErrorMessagesRegexEscape(): void ], ], ], - ], Neon::BLOCK)), trim($this->getOutputContent())); + ], Neon::BLOCK), + ), + trim($this->getOutputContent()), + ); } public function testEscapeDiNeon(): void { $formatter = new BaselineNeonErrorFormatter(new SimpleRelativePathHelper(self::DIRECTORY_PATH)); - $result = new AnalysisResult([new Error('Test %value%', 'Testfile')], [], [], [], [], false, null, true, 0, false); + $result = new AnalysisResult( + [new Error('Test %value%', 'Testfile')], + [], + [], + [], + [], + false, + null, + true, + 0, + false, + ); - $formatter->formatErrors($result, $this->getOutput(), ''); - self::assertSame(trim(Neon::encode([ + $formatter->formatErrors( + $result, + $this->getOutput(), + '', + ); + self::assertSame( + trim( + Neon::encode([ 'parameters' => [ 'ignoreErrors' => [ [ @@ -159,7 +208,10 @@ public function testEscapeDiNeon(): void ], ], ], - ], Neon::BLOCK)), trim($this->getOutputContent())); + ], Neon::BLOCK), + ), + trim($this->getOutputContent()), + ); } /** @@ -192,10 +244,26 @@ public function outputOrderingProvider(): Generator public function testOutputOrdering(array $errors): void { $formatter = new BaselineNeonErrorFormatter(new SimpleRelativePathHelper(self::DIRECTORY_PATH)); - $result = new AnalysisResult($errors, [], [], [], [], false, null, true, 0, false); + $result = new AnalysisResult( + $errors, + [], + [], + [], + [], + false, + null, + true, + 0, + false, + ); - $formatter->formatErrors($result, $this->getOutput(), ''); - self::assertSame(trim(Neon::encode([ + $formatter->formatErrors( + $result, + $this->getOutput(), + '', + ); + self::assertSame( + trim(Neon::encode([ 'parameters' => [ 'ignoreErrors' => [ [ @@ -235,7 +303,9 @@ public function testOutputOrdering(array $errors): void ], ], ], - ], Neon::BLOCK)), $f = trim($this->getOutputContent())); + ], Neon::BLOCK)), + $f = trim($this->getOutputContent()), + ); } /** @@ -326,23 +396,48 @@ public function endOfFileNewlinesProvider(): Generator * * @param list $errors */ - public function testEndOfFileNewlines(array $errors, string $existingBaselineContent, int $expectedNewlinesCount) : void + public function testEndOfFileNewlines( + array $errors, + string $existingBaselineContent, + int $expectedNewlinesCount, + ): void { $formatter = new BaselineNeonErrorFormatter(new SimpleRelativePathHelper(self::DIRECTORY_PATH)); - $result = new AnalysisResult($errors, [], [], [], [], false, null, true, 0, false); + $result = new AnalysisResult( + $errors, + [], + [], + [], + [], + false, + null, + true, + 0, + false, + ); + $resource = fopen('php://memory', 'w', false); if ($resource === false) { throw new ShouldNotHappenException(); } $outputStream = new StreamOutput($resource, StreamOutput::VERBOSITY_NORMAL, false); + $errorConsoleStyle = new ErrorsConsoleStyle(new StringInput(''), $outputStream); $output = new SymfonyOutput($outputStream, new SymfonyStyle($errorConsoleStyle)); - $formatter->formatErrors($result, $output, $existingBaselineContent); + + $formatter->formatErrors( + $result, + $output, + $existingBaselineContent, + ); + rewind($outputStream->getStream()); + $content = stream_get_contents($outputStream->getStream()); if ($content === false) { throw new ShouldNotHappenException(); } + if ($expectedNewlinesCount > 0) { Assert::assertSame(str_repeat("\n", $expectedNewlinesCount), substr($content, -$expectedNewlinesCount)); } diff --git a/tests/PHPStan/Command/ErrorFormatter/BaselinePhpErrorFormatterTest.php b/tests/PHPStan/Command/ErrorFormatter/BaselinePhpErrorFormatterTest.php index 18047c723b0..661768da455 100644 --- a/tests/PHPStan/Command/ErrorFormatter/BaselinePhpErrorFormatterTest.php +++ b/tests/PHPStan/Command/ErrorFormatter/BaselinePhpErrorFormatterTest.php @@ -14,9 +14,21 @@ public function dataFormatErrors(): iterable { yield [ [ - new Error('Foo', __DIR__ . '/Foo.php', 5), - new Error('Foo', __DIR__ . '/Foo.php', 5), - new Error('Bar', __DIR__ . '/../Foo.php', 5), + new Error( + 'Foo', + __DIR__ . '/Foo.php', + 5, + ), + new Error( + 'Foo', + __DIR__ . '/Foo.php', + 5, + ), + new Error( + 'Bar', + __DIR__ . '/../Foo.php', + 5, + ), ], "withIdentifier('argument.type'), - (new Error('Foo with identifier', __DIR__ . '/Foo.php', 6))->withIdentifier('argument.type'), + new Error( + 'Foo', + __DIR__ . '/Foo.php', + 5, + ), + new Error( + 'Foo', + __DIR__ . '/Foo.php', + 5, + ), + (new Error( + 'Foo with identifier', + __DIR__ . '/Foo.php', + 5, + ))->withIdentifier('argument.type'), + (new Error( + 'Foo with identifier', + __DIR__ . '/Foo.php', + 6, + ))->withIdentifier('argument.type'), ], "withIdentifier('argument.type'), - (new Error('Foo with same message, different identifier', __DIR__ . '/Foo.php', 6))->withIdentifier('argument.byRef'), - (new Error('Foo with another message', __DIR__ . '/Foo.php', 5))->withIdentifier('argument.type'), + new Error( + 'Foo', + __DIR__ . '/Foo.php', + 5, + ), + new Error( + 'Foo', + __DIR__ . '/Foo.php', + 5, + ), + (new Error( + 'Foo with same message, different identifier', + __DIR__ . '/Foo.php', + 5, + ))->withIdentifier('argument.type'), + (new Error( + 'Foo with same message, different identifier', + __DIR__ . '/Foo.php', + 6, + ))->withIdentifier('argument.byRef'), + (new Error( + 'Foo with another message', + __DIR__ . '/Foo.php', + 5, + ))->withIdentifier('argument.type'), ], "formatErrors(new AnalysisResult($errors, [], [], [], [], false, null, true, 0, true), $this->getOutput()); + $formatter->formatErrors( + new AnalysisResult( + $errors, + [], + [], + [], + [], + false, + null, + true, + 0, + true, + ), + $this->getOutput(), + ); $this->assertSame($expectedOutput, $this->getOutputContent()); } diff --git a/tests/PHPStan/Command/ErrorFormatter/CheckstyleErrorFormatterTest.php b/tests/PHPStan/Command/ErrorFormatter/CheckstyleErrorFormatterTest.php index ccb4ae7214c..172a74ede55 100644 --- a/tests/PHPStan/Command/ErrorFormatter/CheckstyleErrorFormatterTest.php +++ b/tests/PHPStan/Command/ErrorFormatter/CheckstyleErrorFormatterTest.php @@ -114,10 +114,21 @@ public function dataFormatterOutputProvider(): iterable * @dataProvider dataFormatterOutputProvider * */ - public function testFormatErrors(string $message, int $exitCode, int $numFileErrors, int $numGenericErrors, string $expected) : void + public function testFormatErrors( + string $message, + int $exitCode, + int $numFileErrors, + int $numGenericErrors, + string $expected, + ): void { $formatter = new CheckstyleErrorFormatter(new SimpleRelativePathHelper(self::DIRECTORY_PATH)); - $this->assertSame($exitCode, $formatter->formatErrors($this->getAnalysisResult($numFileErrors, $numGenericErrors), $this->getOutput()), sprintf('%s: response code do not match', $message)); + + $this->assertSame($exitCode, $formatter->formatErrors( + $this->getAnalysisResult($numFileErrors, $numGenericErrors), + $this->getOutput(), + ), sprintf('%s: response code do not match', $message)); + $outputContent = $this->getOutputContent(); $this->assertXmlStringEqualsXmlString($expected, $outputContent, sprintf('%s: XML do not match', $message)); $this->assertStringStartsWith('formatErrors(new AnalysisResult([$error], [], [], [], [], false, null, true, 0, false), $this->getOutput()); + $error = new Error( + 'Foo', + __DIR__ . '/FooTrait.php (in context of class Foo)', + 5, + true, + __DIR__ . '/Foo.php', + __DIR__ . '/FooTrait.php', + ); + $formatter->formatErrors(new AnalysisResult( + [$error], + [], + [], + [], + [], + false, + null, + true, + 0, + false, + ), $this->getOutput()); $this->assertXmlStringEqualsXmlString(' @@ -138,8 +167,26 @@ public function testTraitPath(): void public function testIdentifier(): void { $formatter = new CheckstyleErrorFormatter(new SimpleRelativePathHelper(__DIR__)); - $error = (new Error('Foo', __DIR__ . '/FooTrait.php', 5, true, __DIR__ . '/Foo.php', null))->withIdentifier('argument.type'); - $formatter->formatErrors(new AnalysisResult([$error], [], [], [], [], false, null, true, 0, true), $this->getOutput()); + $error = (new Error( + 'Foo', + __DIR__ . '/FooTrait.php', + 5, + true, + __DIR__ . '/Foo.php', + null, + ))->withIdentifier('argument.type'); + $formatter->formatErrors(new AnalysisResult( + [$error], + [], + [], + [], + [], + false, + null, + true, + 0, + true, + ), $this->getOutput()); $this->assertXmlStringEqualsXmlString(' diff --git a/tests/PHPStan/Command/ErrorFormatter/GithubErrorFormatterTest.php b/tests/PHPStan/Command/ErrorFormatter/GithubErrorFormatterTest.php index daa0bba3ae0..b6a921e06c6 100644 --- a/tests/PHPStan/Command/ErrorFormatter/GithubErrorFormatterTest.php +++ b/tests/PHPStan/Command/ErrorFormatter/GithubErrorFormatterTest.php @@ -79,11 +79,24 @@ public function dataFormatterOutputProvider(): iterable * @dataProvider dataFormatterOutputProvider * */ - public function testFormatErrors(string $message, int $exitCode, int $numFileErrors, int $numGenericErrors, string $expected) : void + public function testFormatErrors( + string $message, + int $exitCode, + int $numFileErrors, + int $numGenericErrors, + string $expected, + ): void { $relativePathHelper = new FuzzyRelativePathHelper(new NullRelativePathHelper(), self::DIRECTORY_PATH, [], '/'); - $formatter = new GithubErrorFormatter($relativePathHelper); - $this->assertSame($exitCode, $formatter->formatErrors($this->getAnalysisResult($numFileErrors, $numGenericErrors), $this->getOutput()), sprintf('%s: response code do not match', $message)); + $formatter = new GithubErrorFormatter( + $relativePathHelper, + ); + + $this->assertSame($exitCode, $formatter->formatErrors( + $this->getAnalysisResult($numFileErrors, $numGenericErrors), + $this->getOutput(), + ), sprintf('%s: response code do not match', $message)); + $this->assertEquals($expected, $this->getOutputContent(), sprintf('%s: output do not match', $message)); } diff --git a/tests/PHPStan/Command/ErrorFormatter/GitlabFormatterTest.php b/tests/PHPStan/Command/ErrorFormatter/GitlabFormatterTest.php index 6c09e70f1ce..e4d63c28d71 100644 --- a/tests/PHPStan/Command/ErrorFormatter/GitlabFormatterTest.php +++ b/tests/PHPStan/Command/ErrorFormatter/GitlabFormatterTest.php @@ -288,10 +288,21 @@ public function dataFormatterOutputProvider(): iterable * * */ - public function testFormatErrors(string $message, int $exitCode, int $numFileErrors, int $numGenericErrors, string $expected) : void + public function testFormatErrors( + string $message, + int $exitCode, + int $numFileErrors, + int $numGenericErrors, + string $expected, + ): void { $formatter = new GitlabErrorFormatter(new SimpleRelativePathHelper('/data/folder')); - $this->assertSame($exitCode, $formatter->formatErrors($this->getAnalysisResult($numFileErrors, $numGenericErrors), $this->getOutput()), sprintf('%s: response code do not match', $message)); + + $this->assertSame($exitCode, $formatter->formatErrors( + $this->getAnalysisResult($numFileErrors, $numGenericErrors), + $this->getOutput(), + ), sprintf('%s: response code do not match', $message)); + $this->assertJsonStringEqualsJsonString($expected, $this->getOutputContent(), sprintf('%s: output do not match', $message)); } diff --git a/tests/PHPStan/Command/ErrorFormatter/JsonErrorFormatterTest.php b/tests/PHPStan/Command/ErrorFormatter/JsonErrorFormatterTest.php index 6e3c5fdbc51..3e6008cdf4c 100644 --- a/tests/PHPStan/Command/ErrorFormatter/JsonErrorFormatterTest.php +++ b/tests/PHPStan/Command/ErrorFormatter/JsonErrorFormatterTest.php @@ -197,10 +197,21 @@ public function dataFormatterOutputProvider(): iterable * @dataProvider dataFormatterOutputProvider * */ - public function testPrettyFormatErrors(string $message, int $exitCode, int $numFileErrors, int $numGenericErrors, string $expected) : void + public function testPrettyFormatErrors( + string $message, + int $exitCode, + int $numFileErrors, + int $numGenericErrors, + string $expected, + ): void { $formatter = new JsonErrorFormatter(true); - $this->assertSame($exitCode, $formatter->formatErrors($this->getAnalysisResult($numFileErrors, $numGenericErrors), $this->getOutput()), $message); + + $this->assertSame($exitCode, $formatter->formatErrors( + $this->getAnalysisResult($numFileErrors, $numGenericErrors), + $this->getOutput(), + ), $message); + $this->assertJsonStringEqualsJsonString($expected, $this->getOutputContent()); } @@ -209,10 +220,21 @@ public function testPrettyFormatErrors(string $message, int $exitCode, int $numF * * */ - public function testFormatErrors(string $message, int $exitCode, int $numFileErrors, int $numGenericErrors, string $expected) : void + public function testFormatErrors( + string $message, + int $exitCode, + int $numFileErrors, + int $numGenericErrors, + string $expected, + ): void { $formatter = new JsonErrorFormatter(false); - $this->assertSame($exitCode, $formatter->formatErrors($this->getAnalysisResult($numFileErrors, $numGenericErrors), $this->getOutput()), sprintf('%s: response code do not match', $message)); + + $this->assertSame($exitCode, $formatter->formatErrors( + $this->getAnalysisResult($numFileErrors, $numGenericErrors), + $this->getOutput(), + ), sprintf('%s: response code do not match', $message)); + $this->assertJsonStringEqualsJsonString($expected, $this->getOutputContent(), sprintf('%s: JSON do not match', $message)); } diff --git a/tests/PHPStan/Command/ErrorFormatter/JunitErrorFormatterTest.php b/tests/PHPStan/Command/ErrorFormatter/JunitErrorFormatterTest.php index 679cec95a5c..7a913521ef5 100644 --- a/tests/PHPStan/Command/ErrorFormatter/JunitErrorFormatterTest.php +++ b/tests/PHPStan/Command/ErrorFormatter/JunitErrorFormatterTest.php @@ -10,10 +10,7 @@ class JunitErrorFormatterTest extends ErrorFormatterTestCase { - /** - * @var JunitErrorFormatter - */ - private $formatter; + private JunitErrorFormatter $formatter; public function setUp(): void { @@ -136,13 +133,35 @@ public function dataFormatterOutputProvider(): Generator * * @dataProvider dataFormatterOutputProvider */ - public function testFormatErrors(int $exitCode, int $numFileErrors, int $numGeneralErrors, string $expected) : void + public function testFormatErrors( + int $exitCode, + int $numFileErrors, + int $numGeneralErrors, + string $expected, + ): void { - $this->assertSame($exitCode, $this->formatter->formatErrors($this->getAnalysisResult($numFileErrors, $numGeneralErrors), $this->getOutput()), 'Response code do not match'); + $this->assertSame( + $exitCode, + $this->formatter->formatErrors( + $this->getAnalysisResult($numFileErrors, $numGeneralErrors), + $this->getOutput(), + ), + 'Response code do not match', + ); + $xml = new DOMDocument(); $xml->loadXML($this->getOutputContent()); - $this->assertTrue($xml->schemaValidate(__DIR__ . '/junit-schema.xsd'), 'Schema do not validate'); - $this->assertXmlStringEqualsXmlString($expected, $this->getOutputContent(), 'XML do not match'); + + $this->assertTrue( + $xml->schemaValidate(__DIR__ . '/junit-schema.xsd'), + 'Schema do not validate', + ); + + $this->assertXmlStringEqualsXmlString( + $expected, + $this->getOutputContent(), + 'XML do not match', + ); } } diff --git a/tests/PHPStan/Command/ErrorFormatter/RawErrorFormatterTest.php b/tests/PHPStan/Command/ErrorFormatter/RawErrorFormatterTest.php index 6b6e182f40c..5b61402bbd9 100644 --- a/tests/PHPStan/Command/ErrorFormatter/RawErrorFormatterTest.php +++ b/tests/PHPStan/Command/ErrorFormatter/RawErrorFormatterTest.php @@ -72,10 +72,21 @@ public function dataFormatterOutputProvider(): iterable * @dataProvider dataFormatterOutputProvider * */ - public function testFormatErrors(string $message, int $exitCode, int $numFileErrors, int $numGenericErrors, string $expected) : void + public function testFormatErrors( + string $message, + int $exitCode, + int $numFileErrors, + int $numGenericErrors, + string $expected, + ): void { $formatter = new RawErrorFormatter(); - $this->assertSame($exitCode, $formatter->formatErrors($this->getAnalysisResult($numFileErrors, $numGenericErrors), $this->getOutput()), sprintf('%s: response code do not match', $message)); + + $this->assertSame($exitCode, $formatter->formatErrors( + $this->getAnalysisResult($numFileErrors, $numGenericErrors), + $this->getOutput(), + ), sprintf('%s: response code do not match', $message)); + $this->assertEquals($expected, $this->getOutputContent(), sprintf('%s: output do not match', $message)); } diff --git a/tests/PHPStan/Command/ErrorFormatter/TableErrorFormatterTest.php b/tests/PHPStan/Command/ErrorFormatter/TableErrorFormatterTest.php index 0c1b999f1a9..5232f164ff0 100644 --- a/tests/PHPStan/Command/ErrorFormatter/TableErrorFormatterTest.php +++ b/tests/PHPStan/Command/ErrorFormatter/TableErrorFormatterTest.php @@ -181,16 +181,29 @@ public function dataFormatterOutputProvider(): iterable * @dataProvider dataFormatterOutputProvider * @param array $extraEnvVars */ - public function testFormatErrors(string $message, int $exitCode, int $numFileErrors, int $numGenericErrors, array $extraEnvVars, string $expected) : void + public function testFormatErrors( + string $message, + int $exitCode, + int $numFileErrors, + int $numGenericErrors, + array $extraEnvVars, + string $expected, + ): void { if (PHP_VERSION_ID >= 80100) { self::markTestSkipped('Skipped on PHP 8.1 because of different result'); } $formatter = $this->createErrorFormatter(null); + foreach ($extraEnvVars as $envVar) { putenv($envVar); } - $this->assertSame($exitCode, $formatter->formatErrors($this->getAnalysisResult($numFileErrors, $numGenericErrors), $this->getOutput()), sprintf('%s: response code do not match', $message)); + + $this->assertSame($exitCode, $formatter->formatErrors( + $this->getAnalysisResult($numFileErrors, $numGenericErrors), + $this->getOutput(), + ), sprintf('%s: response code do not match', $message)); + $this->assertEquals($expected, $this->getOutputContent(), sprintf('%s: output do not match', $message)); } @@ -229,9 +242,27 @@ public function testBug6727(): void { putenv('COLUMNS=30'); $formatter = $this->createErrorFormatter(null); - $formatter->formatErrors(new AnalysisResult([ - new Error('Method MissingTypehintPromotedProperties\Foo::__construct() has parameter $foo with no value type specified in iterable type array.', '/var/www/html/app/src/Foo.php (in context of class App\Foo\Bar)', 5), - ], [], [], [], [], false, null, true, 0, false), $this->getOutput()); + $formatter->formatErrors( + new AnalysisResult( + [ + new Error( + 'Method MissingTypehintPromotedProperties\Foo::__construct() has parameter $foo with no value type specified in iterable type array.', + '/var/www/html/app/src/Foo.php (in context of class App\Foo\Bar)', + 5, + ), + ], + [], + [], + [], + [], + false, + null, + true, + 0, + false, + ), + $this->getOutput(), + ); self::expectNotToPerformAssertions(); } @@ -239,7 +270,17 @@ private function createErrorFormatter(?string $editorUrl, ?string $editorUrlTitl { $relativePathHelper = new FuzzyRelativePathHelper(new NullRelativePathHelper(), self::DIRECTORY_PATH, [], '/'); - return new TableErrorFormatter($relativePathHelper, new SimpleRelativePathHelper(self::DIRECTORY_PATH), new CiDetectedErrorFormatter(new GithubErrorFormatter($relativePathHelper), new TeamcityErrorFormatter($relativePathHelper)), false, $editorUrl, $editorUrlTitle); + return new TableErrorFormatter( + $relativePathHelper, + new SimpleRelativePathHelper(self::DIRECTORY_PATH), + new CiDetectedErrorFormatter( + new GithubErrorFormatter($relativePathHelper), + new TeamcityErrorFormatter($relativePathHelper), + ), + false, + $editorUrl, + $editorUrlTitle, + ); } } diff --git a/tests/PHPStan/Command/ErrorFormatter/TeamcityErrorFormatterTest.php b/tests/PHPStan/Command/ErrorFormatter/TeamcityErrorFormatterTest.php index df6e928476f..c0932ac1d12 100644 --- a/tests/PHPStan/Command/ErrorFormatter/TeamcityErrorFormatterTest.php +++ b/tests/PHPStan/Command/ErrorFormatter/TeamcityErrorFormatterTest.php @@ -84,11 +84,24 @@ public function dataFormatterOutputProvider(): iterable * @dataProvider dataFormatterOutputProvider * */ - public function testFormatErrors(string $message, int $exitCode, int $numFileErrors, int $numGenericErrors, string $expected) : void + public function testFormatErrors( + string $message, + int $exitCode, + int $numFileErrors, + int $numGenericErrors, + string $expected, + ): void { $relativePathHelper = new FuzzyRelativePathHelper(new NullRelativePathHelper(), self::DIRECTORY_PATH, [], '/'); - $formatter = new TeamcityErrorFormatter($relativePathHelper); - $this->assertSame($exitCode, $formatter->formatErrors($this->getAnalysisResult($numFileErrors, $numGenericErrors), $this->getOutput()), sprintf('%s: response code do not match', $message)); + $formatter = new TeamcityErrorFormatter( + $relativePathHelper, + ); + + $this->assertSame($exitCode, $formatter->formatErrors( + $this->getAnalysisResult($numFileErrors, $numGenericErrors), + $this->getOutput(), + ), sprintf('%s: response code do not match', $message)); + $this->assertEquals($expected, $this->getOutputContent(), sprintf('%s: output do not match', $message)); } diff --git a/tests/PHPStan/Command/IgnoredRegexValidatorTest.php b/tests/PHPStan/Command/IgnoredRegexValidatorTest.php index 45fbe1f8294..9dff05c44fb 100644 --- a/tests/PHPStan/Command/IgnoredRegexValidatorTest.php +++ b/tests/PHPStan/Command/IgnoredRegexValidatorTest.php @@ -119,11 +119,17 @@ public function dataValidate(): array * @dataProvider dataValidate * @param string[] $expectedTypes */ - public function testValidate(string $regex, array $expectedTypes, bool $expectedHasAnchors, bool $expectAllErrorsIgnored) : void + public function testValidate( + string $regex, + array $expectedTypes, + bool $expectedHasAnchors, + bool $expectAllErrorsIgnored, + ): void { $grammar = new Read('hoa://Library/Regex/Grammar.pp'); $parser = Llk::load($grammar); $validator = new IgnoredRegexValidator($parser, self::getContainer()->getByType(TypeStringResolver::class)); + $result = $validator->validate($regex); $this->assertSame($expectedTypes, $result->getIgnoredTypes()); $this->assertSame($expectedHasAnchors, $result->hasAnchorsInTheMiddle()); diff --git a/tests/PHPStan/Composer/AutoloadFilesTest.php b/tests/PHPStan/Composer/AutoloadFilesTest.php index cf4381869e1..b16b469e75e 100644 --- a/tests/PHPStan/Composer/AutoloadFilesTest.php +++ b/tests/PHPStan/Composer/AutoloadFilesTest.php @@ -83,9 +83,7 @@ public function testExpectedFiles(): void ]); } - $expectedFiles = array_map(static function (string $path) use($fileHelper) : string { - return $fileHelper->normalizePath($path); - }, $expectedFiles); + $expectedFiles = array_map(static fn (string $path): string => $fileHelper->normalizePath($path), $expectedFiles); sort($expectedFiles); $this->assertSame($expectedFiles, $autoloadFiles); diff --git a/tests/PHPStan/DependencyInjection/ConditionalTagsExtensionTest.php b/tests/PHPStan/DependencyInjection/ConditionalTagsExtensionTest.php index 73cae812e36..5c2b2e28d5b 100644 --- a/tests/PHPStan/DependencyInjection/ConditionalTagsExtensionTest.php +++ b/tests/PHPStan/DependencyInjection/ConditionalTagsExtensionTest.php @@ -13,9 +13,7 @@ class ConditionalTagsExtensionTest extends PHPStanTestCase public function testConditionalTags(): void { $enabledServices = self::getContainer()->getServicesByTag(LazyRegistry::RULE_TAG); - $enabledServices = array_map(static function ($service) { - return get_class($service); - }, $enabledServices); + $enabledServices = array_map(static fn ($service) => get_class($service), $enabledServices); $this->assertNotContains(TestedConditionalServiceDisabled::class, $enabledServices); $this->assertContains(TestedConditionalServiceEnabled::class, $enabledServices); $this->assertNotContains(TestedConditionalServiceDisabledDisabled::class, $enabledServices); diff --git a/tests/PHPStan/File/FileExcluderTest.php b/tests/PHPStan/File/FileExcluderTest.php index 18051866fcb..eebe8236e6b 100644 --- a/tests/PHPStan/File/FileExcluderTest.php +++ b/tests/PHPStan/File/FileExcluderTest.php @@ -11,10 +11,16 @@ class FileExcluderTest extends PHPStanTestCase * @dataProvider dataExcludeOnWindows * @param string[] $analyseExcludes */ - public function testFilesAreExcludedFromAnalysingOnWindows(string $filePath, array $analyseExcludes, bool $isExcluded) : void + public function testFilesAreExcludedFromAnalysingOnWindows( + string $filePath, + array $analyseExcludes, + bool $isExcluded, + ): void { $this->skipIfNotOnWindows(); + $fileExcluder = new FileExcluder($this->getFileHelper(), $analyseExcludes); + $this->assertSame($isExcluded, $fileExcluder->isExcludedFromAnalysing($filePath)); } @@ -113,10 +119,16 @@ public function dataExcludeOnWindows(): array * @dataProvider dataExcludeOnUnix * @param string[] $analyseExcludes */ - public function testFilesAreExcludedFromAnalysingOnUnix(string $filePath, array $analyseExcludes, bool $isExcluded) : void + public function testFilesAreExcludedFromAnalysingOnUnix( + string $filePath, + array $analyseExcludes, + bool $isExcluded, + ): void { $this->skipIfNotOnUnix(); + $fileExcluder = new FileExcluder($this->getFileHelper(), $analyseExcludes); + $this->assertSame($isExcluded, $fileExcluder->isExcludedFromAnalysing($filePath)); } diff --git a/tests/PHPStan/File/ParentDirectoryRelativePathHelperTest.php b/tests/PHPStan/File/ParentDirectoryRelativePathHelperTest.php index 7b4fcedef76..d4065efb28a 100644 --- a/tests/PHPStan/File/ParentDirectoryRelativePathHelperTest.php +++ b/tests/PHPStan/File/ParentDirectoryRelativePathHelperTest.php @@ -106,10 +106,17 @@ public function dataGetRelativePath(): array /** * @dataProvider dataGetRelativePath */ - public function testGetRelativePath(string $parentDirectory, string $filename, string $expectedRelativePath) : void + public function testGetRelativePath( + string $parentDirectory, + string $filename, + string $expectedRelativePath, + ): void { $helper = new ParentDirectoryRelativePathHelper($parentDirectory); - $this->assertSame($expectedRelativePath, $helper->getRelativePath($filename)); + $this->assertSame( + $expectedRelativePath, + $helper->getRelativePath($filename), + ); } } diff --git a/tests/PHPStan/File/RelativePathHelperTest.php b/tests/PHPStan/File/RelativePathHelperTest.php index 1c333531500..5d5b3eca41b 100644 --- a/tests/PHPStan/File/RelativePathHelperTest.php +++ b/tests/PHPStan/File/RelativePathHelperTest.php @@ -183,17 +183,30 @@ public function dataGetRelativePath(): array * @dataProvider dataGetRelativePath * @param string[] $analysedPaths */ - public function testGetRelativePathOnUnix(string $currentWorkingDirectory, array $analysedPaths, string $filenameToRelativize, string $expectedResult) : void + public function testGetRelativePathOnUnix( + string $currentWorkingDirectory, + array $analysedPaths, + string $filenameToRelativize, + string $expectedResult, + ): void { $helper = new FuzzyRelativePathHelper(new NullRelativePathHelper(), $currentWorkingDirectory, $analysedPaths, '/'); - $this->assertSame($expectedResult, $helper->getRelativePath($filenameToRelativize)); + $this->assertSame( + $expectedResult, + $helper->getRelativePath($filenameToRelativize), + ); } /** * @dataProvider dataGetRelativePath * @param string[] $analysedPaths */ - public function testGetRelativePathOnWindows(string $currentWorkingDirectory, array $analysedPaths, string $filenameToRelativize, string $expectedResult) : void + public function testGetRelativePathOnWindows( + string $currentWorkingDirectory, + array $analysedPaths, + string $filenameToRelativize, + string $expectedResult, + ): void { $sanitize = static function (string $path): string { if (substr($path, 0, 1) === '/') { @@ -203,7 +216,10 @@ public function testGetRelativePathOnWindows(string $currentWorkingDirectory, ar return str_replace('/', '\\', $path); }; $helper = new FuzzyRelativePathHelper(new NullRelativePathHelper(), $sanitize($currentWorkingDirectory), array_map($sanitize, $analysedPaths), '\\'); - $this->assertSame($sanitize($expectedResult), $helper->getRelativePath($sanitize($filenameToRelativize))); + $this->assertSame( + $sanitize($expectedResult), + $helper->getRelativePath($sanitize($filenameToRelativize)), + ); } public function dataGetRelativePathWindowsSpecific(): array @@ -234,10 +250,18 @@ public function dataGetRelativePathWindowsSpecific(): array * @dataProvider dataGetRelativePathWindowsSpecific * @param string[] $analysedPaths */ - public function testGetRelativePathWindowsSpecific(string $currentWorkingDirectory, array $analysedPaths, string $filenameToRelativize, string $expectedResult) : void + public function testGetRelativePathWindowsSpecific( + string $currentWorkingDirectory, + array $analysedPaths, + string $filenameToRelativize, + string $expectedResult, + ): void { $helper = new FuzzyRelativePathHelper(new NullRelativePathHelper(), $currentWorkingDirectory, $analysedPaths, '\\'); - $this->assertSame($expectedResult, $helper->getRelativePath($filenameToRelativize)); + $this->assertSame( + $expectedResult, + $helper->getRelativePath($filenameToRelativize), + ); } } diff --git a/tests/PHPStan/Generics/TemplateTypeFactoryTest.php b/tests/PHPStan/Generics/TemplateTypeFactoryTest.php index 7a88af64d26..16fe1d24df2 100644 --- a/tests/PHPStan/Generics/TemplateTypeFactoryTest.php +++ b/tests/PHPStan/Generics/TemplateTypeFactoryTest.php @@ -48,7 +48,12 @@ public function dataCreate(): array new MixedType(), ], [ - TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('a'), 'U', null, TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('a'), + 'U', + null, + TemplateTypeVariance::createInvariant(), + ), new MixedType(), ], [ @@ -70,9 +75,17 @@ public function dataCreate(): array public function testCreate(?Type $bound, Type $expectedBound): void { $scope = TemplateTypeScope::createWithFunction('a'); - $templateType = TemplateTypeFactory::create($scope, 'T', $bound, TemplateTypeVariance::createInvariant()); + $templateType = TemplateTypeFactory::create( + $scope, + 'T', + $bound, + TemplateTypeVariance::createInvariant(), + ); - $this->assertTrue($expectedBound->equals($templateType->getBound()), sprintf('%s -> equals(%s)', $expectedBound->describe(VerbosityLevel::precise()), $templateType->getBound()->describe(VerbosityLevel::precise()))); + $this->assertTrue( + $expectedBound->equals($templateType->getBound()), + sprintf('%s -> equals(%s)', $expectedBound->describe(VerbosityLevel::precise()), $templateType->getBound()->describe(VerbosityLevel::precise())), + ); } } diff --git a/tests/PHPStan/Node/FileNodeTest.php b/tests/PHPStan/Node/FileNodeTest.php index a9415b791d1..60a132a7f8e 100644 --- a/tests/PHPStan/Node/FileNodeTest.php +++ b/tests/PHPStan/Node/FileNodeTest.php @@ -42,7 +42,9 @@ public function processNode(Node $node, Scope $scope): array } return [ - RuleErrorBuilder::message(sprintf('First node in file %s is: %s', $pathHelper->getRelativePath($scope->getFile()), get_class($nodes[0])))->identifier('tests.fileNode')->build(), + RuleErrorBuilder::message( + sprintf('First node in file %s is: %s', $pathHelper->getRelativePath($scope->getFile()), get_class($nodes[0])), + )->identifier('tests.fileNode')->build(), ]; } diff --git a/tests/PHPStan/Node/ParentStmtTypesRule.php b/tests/PHPStan/Node/ParentStmtTypesRule.php index 86b5eadee0d..d0116157733 100644 --- a/tests/PHPStan/Node/ParentStmtTypesRule.php +++ b/tests/PHPStan/Node/ParentStmtTypesRule.php @@ -24,7 +24,10 @@ public function getNodeType(): string public function processNode(Node $node, Scope $scope): array { return [ - RuleErrorBuilder::message(sprintf('Parents: %s', implode(', ', array_reverse($node->getAttribute('parentStmtTypes')))))->identifier('tests.parentStmtTypes')->build(), + RuleErrorBuilder::message(sprintf( + 'Parents: %s', + implode(', ', array_reverse($node->getAttribute('parentStmtTypes'))), + ))->identifier('tests.parentStmtTypes')->build(), ]; } diff --git a/tests/PHPStan/Node/TryCatchTypeRule.php b/tests/PHPStan/Node/TryCatchTypeRule.php index 3973fa4df67..e71958eedfa 100644 --- a/tests/PHPStan/Node/TryCatchTypeRule.php +++ b/tests/PHPStan/Node/TryCatchTypeRule.php @@ -28,12 +28,13 @@ public function processNode(Node $node, Scope $scope): array $tryCatchTypes = $node->getAttribute('tryCatchTypes'); $type = null; if ($tryCatchTypes !== null) { - $type = TypeCombinator::union(...array_map(static function (string $name) { - return new ObjectType($name); - }, $tryCatchTypes)); + $type = TypeCombinator::union(...array_map(static fn (string $name) => new ObjectType($name), $tryCatchTypes)); } return [ - RuleErrorBuilder::message(sprintf('Try catch type: %s', $type !== null ? $type->describe(VerbosityLevel::precise()) : 'nothing'))->identifier('tests.tryCatchType')->build(), + RuleErrorBuilder::message(sprintf( + 'Try catch type: %s', + $type !== null ? $type->describe(VerbosityLevel::precise()) : 'nothing', + ))->identifier('tests.tryCatchType')->build(), ]; } diff --git a/tests/PHPStan/Parallel/ParallelAnalyserIntegrationTest.php b/tests/PHPStan/Parallel/ParallelAnalyserIntegrationTest.php index 7b9207a253d..3ae92e09dcb 100644 --- a/tests/PHPStan/Parallel/ParallelAnalyserIntegrationTest.php +++ b/tests/PHPStan/Parallel/ParallelAnalyserIntegrationTest.php @@ -37,12 +37,17 @@ public function testRun(string $command): void throw new ShouldNotHappenException('Could not clear result cache.'); } - exec(sprintf('%s %s %s -l 8 -c %s --error-format json --no-progress %s', escapeshellarg(PHP_BINARY), escapeshellarg(__DIR__ . '/../../../bin/phpstan'), $command, escapeshellarg(__DIR__ . '/parallel-analyser.neon'), implode(' ', array_map(static function (string $path) : string { - return escapeshellarg($path); - }, [ + exec(sprintf( + '%s %s %s -l 8 -c %s --error-format json --no-progress %s', + escapeshellarg(PHP_BINARY), + escapeshellarg(__DIR__ . '/../../../bin/phpstan'), + $command, + escapeshellarg(__DIR__ . '/parallel-analyser.neon'), + implode(' ', array_map(static fn (string $path): string => escapeshellarg($path), [ __DIR__ . '/data/trait-definition.php', __DIR__ . '/data/traits.php', - ]))), $outputLines, $exitCode); + ])), + ), $outputLines, $exitCode); $output = implode("\n", $outputLines); $fileHelper = new FileHelper(__DIR__); diff --git a/tests/PHPStan/Parallel/SchedulerTest.php b/tests/PHPStan/Parallel/SchedulerTest.php index 070c675bf9e..fb1fd626cff 100644 --- a/tests/PHPStan/Parallel/SchedulerTest.php +++ b/tests/PHPStan/Parallel/SchedulerTest.php @@ -78,15 +78,22 @@ public function dataSchedule(): array * @param 0|positive-int $numberOfFiles * @param array $expectedJobSizes */ - public function testSchedule(int $cpuCores, int $maximumNumberOfProcesses, int $minimumNumberOfJobsPerProcess, int $jobSize, int $numberOfFiles, int $expectedNumberOfProcesses, array $expectedJobSizes) : void + public function testSchedule( + int $cpuCores, + int $maximumNumberOfProcesses, + int $minimumNumberOfJobsPerProcess, + int $jobSize, + int $numberOfFiles, + int $expectedNumberOfProcesses, + array $expectedJobSizes, + ): void { $files = array_fill(0, $numberOfFiles, 'file.php'); $scheduler = new Scheduler($jobSize, $maximumNumberOfProcesses, $minimumNumberOfJobsPerProcess); $schedule = $scheduler->scheduleWork($cpuCores, $files); + $this->assertSame($expectedNumberOfProcesses, $schedule->getNumberOfProcesses()); - $jobSizes = array_map(static function (array $job) : int { - return count($job); - }, $schedule->getJobs()); + $jobSizes = array_map(static fn (array $job): int => count($job), $schedule->getJobs()); $this->assertSame($expectedJobSizes, $jobSizes); } diff --git a/tests/PHPStan/Parser/CachedParserTest.php b/tests/PHPStan/Parser/CachedParserTest.php index 53dedd0326e..76bb9e215df 100644 --- a/tests/PHPStan/Parser/CachedParserTest.php +++ b/tests/PHPStan/Parser/CachedParserTest.php @@ -60,10 +60,7 @@ public function dataParseFileClearCache(): \Generator ]; } - /** - * @return Parser&MockObject - */ - private function getParserMock() + private function getParserMock(): Parser&MockObject { $mock = $this->createMock(Parser::class); @@ -73,10 +70,7 @@ private function getParserMock() return $mock; } - /** - * @return \PhpParser\Node&MockObject - */ - private function getPhpParserNodeMock() + private function getPhpParserNodeMock(): \PhpParser\Node&MockObject { return $this->createMock(\PhpParser\Node::class); } @@ -84,7 +78,12 @@ private function getPhpParserNodeMock() public function testParseTheSameFileWithDifferentMethod(): void { $fileHelper = self::getContainer()->getByType(FileHelper::class); - $pathRoutingParser = new PathRoutingParser($fileHelper, self::getContainer()->getService('currentPhpVersionRichParser'), self::getContainer()->getService('currentPhpVersionSimpleDirectParser'), self::getContainer()->getService('php8Parser')); + $pathRoutingParser = new PathRoutingParser( + $fileHelper, + self::getContainer()->getService('currentPhpVersionRichParser'), + self::getContainer()->getService('currentPhpVersionSimpleDirectParser'), + self::getContainer()->getService('php8Parser'), + ); $parser = new CachedParser($pathRoutingParser, 500); $path = $fileHelper->normalizePath(__DIR__ . '/data/test.php'); $pathRoutingParser->setAnalysedFiles([$path]); diff --git a/tests/PHPStan/Parser/CleaningParserTest.php b/tests/PHPStan/Parser/CleaningParserTest.php index 1483768c4c8..692ea7b6995 100644 --- a/tests/PHPStan/Parser/CleaningParserTest.php +++ b/tests/PHPStan/Parser/CleaningParserTest.php @@ -58,9 +58,19 @@ public function dataParse(): iterable /** * @dataProvider dataParse */ - public function testParse(string $beforeFile, string $afterFile, int $phpVersionId) : void + public function testParse( + string $beforeFile, + string $afterFile, + int $phpVersionId, + ): void { - $parser = new CleaningParser(new SimpleParser(new Php7(new Emulative()), new NameResolver()), new PhpVersion($phpVersionId)); + $parser = new CleaningParser( + new SimpleParser( + new Php7(new Emulative()), + new NameResolver(), + ), + new PhpVersion($phpVersionId), + ); $printer = new Printer(); $ast = $parser->parseFile($beforeFile); $this->assertSame(FileReader::read($afterFile), "prettyPrint($ast) . "\n"); diff --git a/tests/PHPStan/Php/PhpVersionFactoryTest.php b/tests/PHPStan/Php/PhpVersionFactoryTest.php index 76f03d8dd5a..f84fe900ce7 100644 --- a/tests/PHPStan/Php/PhpVersionFactoryTest.php +++ b/tests/PHPStan/Php/PhpVersionFactoryTest.php @@ -89,14 +89,21 @@ public function dataCreate(): array /** * @dataProvider dataCreate */ - public function testCreate(?int $versionId, ?string $composerPhpVersion, int $expectedVersion, ?string $expectedVersionString) : void + public function testCreate( + ?int $versionId, + ?string $composerPhpVersion, + int $expectedVersion, + ?string $expectedVersionString, + ): void { $factory = new PhpVersionFactory($versionId, $composerPhpVersion); $phpVersion = $factory->create(); $this->assertSame($expectedVersion, $phpVersion->getVersionId()); + if ($expectedVersionString === null) { return; } + $this->assertSame($expectedVersionString, $phpVersion->getVersionString()); } diff --git a/tests/PHPStan/PhpDoc/DefaultStubFilesProviderTest.php b/tests/PHPStan/PhpDoc/DefaultStubFilesProviderTest.php index d8c041f75e0..e7ea48c5993 100644 --- a/tests/PHPStan/PhpDoc/DefaultStubFilesProviderTest.php +++ b/tests/PHPStan/PhpDoc/DefaultStubFilesProviderTest.php @@ -8,10 +8,7 @@ class DefaultStubFilesProviderTest extends PHPStanTestCase { - /** - * @var string - */ - private $currentWorkingDirectory; + private string $currentWorkingDirectory; protected function setUp(): void { diff --git a/tests/PHPStan/Reflection/AllowedSubTypesClassReflectionExtensionTest.php b/tests/PHPStan/Reflection/AllowedSubTypesClassReflectionExtensionTest.php index d1b1d2b6673..58890ef52e1 100644 --- a/tests/PHPStan/Reflection/AllowedSubTypesClassReflectionExtensionTest.php +++ b/tests/PHPStan/Reflection/AllowedSubTypesClassReflectionExtensionTest.php @@ -16,7 +16,11 @@ public function dataFileAsserts(): iterable * @dataProvider dataFileAsserts * @param mixed ...$args */ - public function testFileAsserts(string $assertType, string $file, ...$args) : void + public function testFileAsserts( + string $assertType, + string $file, + ...$args, + ): void { $this->assertFileAsserts($assertType, $file, ...$args); } diff --git a/tests/PHPStan/Reflection/Annotations/AnnotationsMethodsClassReflectionExtensionTest.php b/tests/PHPStan/Reflection/Annotations/AnnotationsMethodsClassReflectionExtensionTest.php index 8a3e2bc78f6..dfdb480fb84 100644 --- a/tests/PHPStan/Reflection/Annotations/AnnotationsMethodsClassReflectionExtensionTest.php +++ b/tests/PHPStan/Reflection/Annotations/AnnotationsMethodsClassReflectionExtensionTest.php @@ -440,7 +440,9 @@ public function dataMethods(): array 'parameters' => [], ], ]; - $barMethods = array_merge($fooMethods, [ + $barMethods = array_merge( + $fooMethods, + [ 'overridenMethod' => [ 'class' => Bar::class, 'returnType' => Bar::class, @@ -462,8 +464,11 @@ public function dataMethods(): array 'isVariadic' => false, 'parameters' => [], ], - ]); - $bazMethods = array_merge($barMethods, [ + ], + ); + $bazMethods = array_merge( + $barMethods, + [ 'doSomething' => [ 'class' => Baz::class, 'returnType' => 'void', @@ -647,8 +652,11 @@ public function dataMethods(): array 'isVariadic' => false, 'parameters' => [], ], - ]); - $bazBazMethods = array_merge($bazMethods, [ + ], + ); + $bazBazMethods = array_merge( + $bazMethods, + [ 'getTest' => [ 'class' => BazBaz::class, 'returnType' => 'OtherNamespace\Test', @@ -939,7 +947,8 @@ public function dataMethods(): array ], ], ], - ]); + ], + ); return [ [Foo::class, $fooMethods], @@ -966,17 +975,51 @@ public function testMethods(string $className, array $methods): void $method = $class->getMethod($methodName, $scope); $selectedParametersAcceptor = ParametersAcceptorSelector::selectSingle($method->getVariants()); - $this->assertSame($expectedMethodData['class'], $method->getDeclaringClass()->getName(), sprintf('Declaring class of method %s() does not match.', $methodName)); - $this->assertSame($expectedMethodData['returnType'], $selectedParametersAcceptor->getReturnType()->describe(VerbosityLevel::precise()), sprintf('Return type of method %s::%s() does not match', $className, $methodName)); - $this->assertSame($expectedMethodData['isStatic'], $method->isStatic(), sprintf('Scope of method %s::%s() does not match', $className, $methodName)); - $this->assertSame($expectedMethodData['isVariadic'], $selectedParametersAcceptor->isVariadic(), sprintf('Method %s::%s() does not match expected variadicity', $className, $methodName)); - $this->assertCount(count($expectedMethodData['parameters']), $selectedParametersAcceptor->getParameters(), sprintf('Method %s::%s() does not match expected count of parameters', $className, $methodName)); + $this->assertSame( + $expectedMethodData['class'], + $method->getDeclaringClass()->getName(), + sprintf('Declaring class of method %s() does not match.', $methodName), + ); + $this->assertSame( + $expectedMethodData['returnType'], + $selectedParametersAcceptor->getReturnType()->describe(VerbosityLevel::precise()), + sprintf('Return type of method %s::%s() does not match', $className, $methodName), + ); + $this->assertSame( + $expectedMethodData['isStatic'], + $method->isStatic(), + sprintf('Scope of method %s::%s() does not match', $className, $methodName), + ); + $this->assertSame( + $expectedMethodData['isVariadic'], + $selectedParametersAcceptor->isVariadic(), + sprintf('Method %s::%s() does not match expected variadicity', $className, $methodName), + ); + $this->assertCount( + count($expectedMethodData['parameters']), + $selectedParametersAcceptor->getParameters(), + sprintf('Method %s::%s() does not match expected count of parameters', $className, $methodName), + ); foreach ($selectedParametersAcceptor->getParameters() as $i => $parameter) { - $this->assertSame($expectedMethodData['parameters'][$i]['name'], $parameter->getName()); - $this->assertSame($expectedMethodData['parameters'][$i]['type'], $parameter->getType()->describe(VerbosityLevel::precise())); - $this->assertTrue($expectedMethodData['parameters'][$i]['passedByReference']->equals($parameter->passedByReference())); - $this->assertSame($expectedMethodData['parameters'][$i]['isOptional'], $parameter->isOptional()); - $this->assertSame($expectedMethodData['parameters'][$i]['isVariadic'], $parameter->isVariadic()); + $this->assertSame( + $expectedMethodData['parameters'][$i]['name'], + $parameter->getName(), + ); + $this->assertSame( + $expectedMethodData['parameters'][$i]['type'], + $parameter->getType()->describe(VerbosityLevel::precise()), + ); + $this->assertTrue( + $expectedMethodData['parameters'][$i]['passedByReference']->equals($parameter->passedByReference()), + ); + $this->assertSame( + $expectedMethodData['parameters'][$i]['isOptional'], + $parameter->isOptional(), + ); + $this->assertSame( + $expectedMethodData['parameters'][$i]['isVariadic'], + $parameter->isVariadic(), + ); } } } diff --git a/tests/PHPStan/Reflection/Annotations/AnnotationsPropertiesClassReflectionExtensionTest.php b/tests/PHPStan/Reflection/Annotations/AnnotationsPropertiesClassReflectionExtensionTest.php index 6b81761143d..d58eeb7217a 100644 --- a/tests/PHPStan/Reflection/Annotations/AnnotationsPropertiesClassReflectionExtensionTest.php +++ b/tests/PHPStan/Reflection/Annotations/AnnotationsPropertiesClassReflectionExtensionTest.php @@ -284,14 +284,37 @@ public function testProperties(string $className, array $properties): void $scope->method('getClassReflection')->willReturn($class); $scope->method('canAccessProperty')->willReturn(true); foreach ($properties as $propertyName => $expectedPropertyData) { - $this->assertTrue($class->hasProperty($propertyName), sprintf('Class %s does not define property %s.', $className, $propertyName)); + $this->assertTrue( + $class->hasProperty($propertyName), + sprintf('Class %s does not define property %s.', $className, $propertyName), + ); $property = $class->getProperty($propertyName, $scope); - $this->assertSame($expectedPropertyData['class'], $property->getDeclaringClass()->getName(), sprintf('Declaring class of property $%s does not match.', $propertyName)); - $this->assertSame($expectedPropertyData['readableType'], $property->getReadableType()->describe(VerbosityLevel::precise()), sprintf('Readable type of property %s::$%s does not match.', $property->getDeclaringClass()->getName(), $propertyName)); - $this->assertSame($expectedPropertyData['writableType'], $property->getWritableType()->describe(VerbosityLevel::precise()), sprintf('Writable type of property %s::$%s does not match.', $property->getDeclaringClass()->getName(), $propertyName)); - $this->assertSame($expectedPropertyData['readable'], $property->isReadable(), sprintf('Property %s::$%s readability is not as expected.', $property->getDeclaringClass()->getName(), $propertyName)); - $this->assertSame($expectedPropertyData['writable'], $property->isWritable(), sprintf('Property %s::$%s writability is not as expected.', $property->getDeclaringClass()->getName(), $propertyName)); + $this->assertSame( + $expectedPropertyData['class'], + $property->getDeclaringClass()->getName(), + sprintf('Declaring class of property $%s does not match.', $propertyName), + ); + $this->assertSame( + $expectedPropertyData['readableType'], + $property->getReadableType()->describe(VerbosityLevel::precise()), + sprintf('Readable type of property %s::$%s does not match.', $property->getDeclaringClass()->getName(), $propertyName), + ); + $this->assertSame( + $expectedPropertyData['writableType'], + $property->getWritableType()->describe(VerbosityLevel::precise()), + sprintf('Writable type of property %s::$%s does not match.', $property->getDeclaringClass()->getName(), $propertyName), + ); + $this->assertSame( + $expectedPropertyData['readable'], + $property->isReadable(), + sprintf('Property %s::$%s readability is not as expected.', $property->getDeclaringClass()->getName(), $propertyName), + ); + $this->assertSame( + $expectedPropertyData['writable'], + $property->isWritable(), + sprintf('Property %s::$%s writability is not as expected.', $property->getDeclaringClass()->getName(), $propertyName), + ); } } diff --git a/tests/PHPStan/Reflection/BetterReflection/SourceLocator/AutoloadSourceLocatorTest.php b/tests/PHPStan/Reflection/BetterReflection/SourceLocator/AutoloadSourceLocatorTest.php index 39b93e62276..f56a41be51a 100644 --- a/tests/PHPStan/Reflection/BetterReflection/SourceLocator/AutoloadSourceLocatorTest.php +++ b/tests/PHPStan/Reflection/BetterReflection/SourceLocator/AutoloadSourceLocatorTest.php @@ -36,14 +36,20 @@ public function testAutoloadEverythingInFile(): void $this->assertSame('a.php', basename($someConstant->getFileName())); $initializerExprTypeResolver = self::getContainer()->getByType(InitializerExprTypeResolver::class); - $someConstantValue = $initializerExprTypeResolver->getType($someConstant->getValueExpression(), InitializerExprContext::fromGlobalConstant($someConstant)); + $someConstantValue = $initializerExprTypeResolver->getType( + $someConstant->getValueExpression(), + InitializerExprContext::fromGlobalConstant($someConstant), + ); $this->assertInstanceOf(ConstantIntegerType::class, $someConstantValue); $this->assertSame(1, $someConstantValue->getValue()); $anotherConstant = $reflector->reflectConstant('TestSingleFileSourceLocator\\ANOTHER_CONSTANT'); $this->assertNotNull($anotherConstant->getFileName()); $this->assertSame('a.php', basename($anotherConstant->getFileName())); - $anotherConstantValue = $initializerExprTypeResolver->getType($anotherConstant->getValueExpression(), InitializerExprContext::fromGlobalConstant($anotherConstant)); + $anotherConstantValue = $initializerExprTypeResolver->getType( + $anotherConstant->getValueExpression(), + InitializerExprContext::fromGlobalConstant($anotherConstant), + ); $this->assertInstanceOf(ConstantIntegerType::class, $anotherConstantValue); $this->assertSame(2, $anotherConstantValue->getValue()); diff --git a/tests/PHPStan/Reflection/BetterReflection/SourceLocator/OptimizedDirectorySourceLocatorTest.php b/tests/PHPStan/Reflection/BetterReflection/SourceLocator/OptimizedDirectorySourceLocatorTest.php index b9dfd9cdf29..c9726f3247d 100644 --- a/tests/PHPStan/Reflection/BetterReflection/SourceLocator/OptimizedDirectorySourceLocatorTest.php +++ b/tests/PHPStan/Reflection/BetterReflection/SourceLocator/OptimizedDirectorySourceLocatorTest.php @@ -229,7 +229,10 @@ public function testLocateIdentifiersByType(): void $locator = $factory->createByDirectory(__DIR__ . '/data/directory'); $reflector = new DefaultReflector($locator); - $classIdentifiers = $locator->locateIdentifiersByType($reflector, new IdentifierType(IdentifierType::IDENTIFIER_CLASS)); + $classIdentifiers = $locator->locateIdentifiersByType( + $reflector, + new IdentifierType(IdentifierType::IDENTIFIER_CLASS), + ); $expectedClasses = [ 'TestDirectorySourceLocator\AFoo', @@ -245,16 +248,15 @@ public function testLocateIdentifiersByType(): void $expectedClasses[] = 'OptimizedDirectory\UppercaseEnum'; } - $actualClasses = array_map(static function (Reflection $reflection) { - return $reflection->getName(); - }, $classIdentifiers); + $actualClasses = array_map(static fn (Reflection $reflection) => $reflection->getName(), $classIdentifiers); $this->assertEqualsCanonicalizing($expectedClasses, $actualClasses); - $functionIdentifiers = $locator->locateIdentifiersByType($reflector, new IdentifierType(IdentifierType::IDENTIFIER_FUNCTION)); + $functionIdentifiers = $locator->locateIdentifiersByType( + $reflector, + new IdentifierType(IdentifierType::IDENTIFIER_FUNCTION), + ); - $actualFunctions = array_map(static function (Reflection $reflection) { - return $reflection->getName(); - }, $functionIdentifiers); + $actualFunctions = array_map(static fn (Reflection $reflection) => $reflection->getName(), $functionIdentifiers); $this->assertEqualsCanonicalizing([ 'TestDirectorySourceLocator\doLorem', @@ -265,11 +267,12 @@ public function testLocateIdentifiersByType(): void 'OptimizedDirectory\upperCaseFunction', ], $actualFunctions); - $constantIdentifiers = $locator->locateIdentifiersByType($reflector, new IdentifierType(IdentifierType::IDENTIFIER_CONSTANT)); + $constantIdentifiers = $locator->locateIdentifiersByType( + $reflector, + new IdentifierType(IdentifierType::IDENTIFIER_CONSTANT), + ); - $actualConstants = array_map(static function (Reflection $reflection) { - return $reflection->getName(); - }, $constantIdentifiers); + $actualConstants = array_map(static fn (Reflection $reflection) => $reflection->getName(), $constantIdentifiers); $this->assertEqualsCanonicalizing([ 'NOTHING', diff --git a/tests/PHPStan/Reflection/BetterReflection/SourceLocator/OptimizedSingleFileSourceLocatorTest.php b/tests/PHPStan/Reflection/BetterReflection/SourceLocator/OptimizedSingleFileSourceLocatorTest.php index 15a25e36650..80b588643f3 100644 --- a/tests/PHPStan/Reflection/BetterReflection/SourceLocator/OptimizedSingleFileSourceLocatorTest.php +++ b/tests/PHPStan/Reflection/BetterReflection/SourceLocator/OptimizedSingleFileSourceLocatorTest.php @@ -215,7 +215,10 @@ public function testConst(string $constantName, string $valueTypeDescription): v $this->assertSame($constantName, $constant->getName()); $initializerExprTypeResolver = self::getContainer()->getByType(InitializerExprTypeResolver::class); - $valueType = $initializerExprTypeResolver->getType($constant->getValueExpression(), InitializerExprContext::fromGlobalConstant($constant)); + $valueType = $initializerExprTypeResolver->getType( + $constant->getValueExpression(), + InitializerExprContext::fromGlobalConstant($constant), + ); $this->assertSame($valueTypeDescription, $valueType->describe(VerbosityLevel::precise())); } @@ -242,16 +245,23 @@ public function testConstUnknown(string $constantName): void * @dataProvider dataForIdenifiersByType * @param class-string[] $expectedIdentifiers */ - public function testLocateIdentifiersByType(IdentifierType $identifierType, array $expectedIdentifiers, string $file) : void + public function testLocateIdentifiersByType( + IdentifierType $identifierType, + array $expectedIdentifiers, + string $file, + ): void { /** @var OptimizedSingleFileSourceLocatorFactory $factory */ $factory = self::getContainer()->getByType(OptimizedSingleFileSourceLocatorFactory::class); $locator = $factory->create($file); $reflector = new DefaultReflector($locator); - $reflections = $locator->locateIdentifiersByType($reflector, $identifierType); - $actualIdentifiers = array_map(static function (Reflection $reflection) { - return $reflection->getName(); - }, $reflections); + + $reflections = $locator->locateIdentifiersByType( + $reflector, + $identifierType, + ); + + $actualIdentifiers = array_map(static fn (Reflection $reflection) => $reflection->getName(), $reflections); $this->assertEqualsCanonicalizing($expectedIdentifiers, $actualIdentifiers); } diff --git a/tests/PHPStan/Reflection/ClassReflectionTest.php b/tests/PHPStan/Reflection/ClassReflectionTest.php index 20ad01662ef..fa00afc63fa 100644 --- a/tests/PHPStan/Reflection/ClassReflectionTest.php +++ b/tests/PHPStan/Reflection/ClassReflectionTest.php @@ -97,11 +97,17 @@ public function dataClassHierarchyDistances(): array * @param class-string $class * @param int[] $expectedDistances */ - public function testClassHierarchyDistances(string $class, array $expectedDistances) : void + public function testClassHierarchyDistances( + string $class, + array $expectedDistances, + ): void { $reflectionProvider = $this->createReflectionProvider(); $classReflection = $reflectionProvider->getClass($class); - $this->assertSame($expectedDistances, $classReflection->getClassHierarchyDistances()); + $this->assertSame( + $expectedDistances, + $classReflection->getClassHierarchyDistances(), + ); } public function testVariadicTraitMethod(): void @@ -129,9 +135,7 @@ public function testGenericInheritance(): void 'GenericInheritance\\I', 'GenericInheritance\\I0', 'GenericInheritance\\I1', - ], array_map(static function (ClassReflection $r) : string { - return $r->getDisplayName(); - }, array_values($reflection->getInterfaces()))); + ], array_map(static fn (ClassReflection $r): string => $r->getDisplayName(), array_values($reflection->getInterfaces()))); } public function testIsGenericWithStubPhpDoc(): void @@ -196,9 +200,13 @@ public function testGetTraits(string $className, array $expected, bool $recursiv { $reflectionProvider = $this->createReflectionProvider(); - $this->assertSame(array_map(static function (ClassReflection $classReflection) : string { - return $classReflection->getNativeReflection()->getName(); - }, $reflectionProvider->getClass($className)->getTraits($recursive)), $expected); + $this->assertSame( + array_map( + static fn (ClassReflection $classReflection): string => $classReflection->getNativeReflection()->getName(), + $reflectionProvider->getClass($className)->getTraits($recursive), + ), + $expected, + ); } public function dataNestedRecursiveTraits(): array diff --git a/tests/PHPStan/Reflection/GenericParametersAcceptorResolverTest.php b/tests/PHPStan/Reflection/GenericParametersAcceptorResolverTest.php index da973f5589e..4bcd1d68097 100644 --- a/tests/PHPStan/Reflection/GenericParametersAcceptorResolverTest.php +++ b/tests/PHPStan/Reflection/GenericParametersAcceptorResolverTest.php @@ -29,91 +29,240 @@ class GenericParametersAcceptorResolverTest extends PHPStanTestCase */ public function dataResolve(): array { - $templateType = static function (string $name, ?Type $type = null) : Type { - return TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('a'), $name, $type, TemplateTypeVariance::createInvariant()); - }; + $templateType = static fn (string $name, ?Type $type = null): Type => TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('a'), + $name, + $type, + TemplateTypeVariance::createInvariant(), + ); return [ 'one param, one arg' => [ [ new ObjectType('DateTime'), ], - new FunctionVariant(new TemplateTypeMap([ + new FunctionVariant( + new TemplateTypeMap([ 'T' => $templateType('T'), - ]), null, [ - new DummyParameter('a', $templateType('T'), false, PassedByReference::createNo(), false, null), - ], false, new NullType()), - new FunctionVariant(new TemplateTypeMap([ + ]), + null, + [ + new DummyParameter( + 'a', + $templateType('T'), + false, + PassedByReference::createNo(), + false, + null, + ), + ], + false, + new NullType(), + ), + new FunctionVariant( + new TemplateTypeMap([ 'T' => $templateType('T'), - ]), null, [ - new DummyParameter('a', new ObjectType('DateTime'), false, PassedByReference::createNo(), false, null), - ], false, new NullType()), + ]), + null, + [ + new DummyParameter( + 'a', + new ObjectType('DateTime'), + false, + PassedByReference::createNo(), + false, + null, + ), + ], + false, + new NullType(), + ), ], 'two params, two args, return type' => [ [ new ObjectType('DateTime'), new IntegerType(), ], - new FunctionVariant(new TemplateTypeMap([ + new FunctionVariant( + new TemplateTypeMap([ 'T' => $templateType('T'), 'U' => $templateType('U'), - ]), null, [ - new DummyParameter('a', $templateType('T'), false, PassedByReference::createNo(), false, null), - new DummyParameter('b', $templateType('U'), false, PassedByReference::createNo(), false, null), - ], false, $templateType('U')), - new FunctionVariant(new TemplateTypeMap([ + ]), + null, + [ + new DummyParameter( + 'a', + $templateType('T'), + false, + PassedByReference::createNo(), + false, + null, + ), + new DummyParameter( + 'b', + $templateType('U'), + false, + PassedByReference::createNo(), + false, + null, + ), + ], + false, + $templateType('U'), + ), + new FunctionVariant( + new TemplateTypeMap([ 'T' => $templateType('T'), 'U' => $templateType('U'), - ]), null, [ - new DummyParameter('a', new ObjectType('DateTime'), false, PassedByReference::createNo(), false, null), - new DummyParameter('b', new IntegerType(), false, PassedByReference::createNo(), false, null), - ], false, new IntegerType()), + ]), + null, + [ + new DummyParameter( + 'a', + new ObjectType('DateTime'), + false, + PassedByReference::createNo(), + false, + null, + ), + new DummyParameter( + 'b', + new IntegerType(), + false, + PassedByReference::createNo(), + false, + null, + ), + ], + false, + new IntegerType(), + ), ], 'mixed types' => [ [ new ObjectType('DateTime'), new IntegerType(), ], - new FunctionVariant(new TemplateTypeMap([ + new FunctionVariant( + new TemplateTypeMap([ 'T' => $templateType('T'), - ]), null, [ - new DummyParameter('a', $templateType('T'), false, PassedByReference::createNo(), false, null), - new DummyParameter('b', $templateType('T'), false, PassedByReference::createNo(), false, null), - ], false, $templateType('T')), - new FunctionVariant(new TemplateTypeMap([ + ]), + null, + [ + new DummyParameter( + 'a', + $templateType('T'), + false, + PassedByReference::createNo(), + false, + null, + ), + new DummyParameter( + 'b', + $templateType('T'), + false, + PassedByReference::createNo(), + false, + null, + ), + ], + false, + $templateType('T'), + ), + new FunctionVariant( + new TemplateTypeMap([ 'T' => $templateType('T'), - ]), null, [ - new DummyParameter('a', new UnionType([ + ]), + null, + [ + new DummyParameter( + 'a', + new UnionType([ new ObjectType('DateTime'), new IntegerType(), - ]), false, PassedByReference::createNo(), false, null), - new DummyParameter('b', new UnionType([ + ]), + false, + PassedByReference::createNo(), + false, + null, + ), + new DummyParameter( + 'b', + new UnionType([ new ObjectType('DateTime'), new IntegerType(), - ]), false, PassedByReference::createNo(), false, null), - ], false, new UnionType([ + ]), + false, + PassedByReference::createNo(), + false, + null, + ), + ], + false, + new UnionType([ new ObjectType('DateTime'), new IntegerType(), - ])), + ]), + ), ], 'parameter default value' => [ [ new ObjectType('DateTime'), ], - new FunctionVariant(new TemplateTypeMap([ + new FunctionVariant( + new TemplateTypeMap([ 'T' => $templateType('T'), 'U' => $templateType('U'), - ]), null, [ - new DummyParameter('a', $templateType('T'), false, PassedByReference::createNo(), false, null), - new DummyParameter('b', $templateType('U'), true, PassedByReference::createNo(), false, new IntegerType()), - ], false, new NullType()), - new FunctionVariant(new TemplateTypeMap([ + ]), + null, + [ + new DummyParameter( + 'a', + $templateType('T'), + false, + PassedByReference::createNo(), + false, + null, + ), + new DummyParameter( + 'b', + $templateType('U'), + true, + PassedByReference::createNo(), + false, + new IntegerType(), + ), + ], + false, + new NullType(), + ), + new FunctionVariant( + new TemplateTypeMap([ 'T' => $templateType('T'), 'U' => $templateType('U'), - ]), null, [ - new DummyParameter('a', new ObjectType('DateTime'), false, PassedByReference::createNo(), false, null), - new DummyParameter('b', new IntegerType(), false, PassedByReference::createNo(), false, null), - ], false, new NullType()), + ]), + null, + [ + new DummyParameter( + 'a', + new ObjectType('DateTime'), + false, + PassedByReference::createNo(), + false, + null, + ), + new DummyParameter( + 'b', + new IntegerType(), + false, + PassedByReference::createNo(), + false, + null, + ), + ], + false, + new NullType(), + ), ], 'variadic parameter' => [ [ @@ -122,60 +271,152 @@ public function dataResolve(): array new ConstantIntegerType(2), new ConstantIntegerType(3), ], - new FunctionVariant(new TemplateTypeMap([ + new FunctionVariant( + new TemplateTypeMap([ 'T' => $templateType('T'), 'U' => $templateType('U'), - ]), null, [ - new DummyParameter('a', $templateType('T'), false, PassedByReference::createNo(), false, null), - new DummyParameter('b', $templateType('U'), false, PassedByReference::createNo(), true, null), - ], true, $templateType('U')), - new FunctionVariant(new TemplateTypeMap([ + ]), + null, + [ + new DummyParameter( + 'a', + $templateType('T'), + false, + PassedByReference::createNo(), + false, + null, + ), + new DummyParameter( + 'b', + $templateType('U'), + false, + PassedByReference::createNo(), + true, + null, + ), + ], + true, + $templateType('U'), + ), + new FunctionVariant( + new TemplateTypeMap([ 'T' => $templateType('T'), 'U' => $templateType('U'), - ]), null, [ - new DummyParameter('a', new ObjectType('DateTime'), false, PassedByReference::createNo(), false, null), - new DummyParameter('b', new UnionType([ + ]), + null, + [ + new DummyParameter( + 'a', + new ObjectType('DateTime'), + false, + PassedByReference::createNo(), + false, + null, + ), + new DummyParameter( + 'b', + new UnionType([ new ConstantIntegerType(1), new ConstantIntegerType(2), new ConstantIntegerType(3), - ]), false, PassedByReference::createNo(), true, null), - ], false, new UnionType([ + ]), + false, + PassedByReference::createNo(), + true, + null, + ), + ], + false, + new UnionType([ new ConstantIntegerType(1), new ConstantIntegerType(2), new ConstantIntegerType(3), - ])), + ]), + ), ], 'missing args' => [ [ new ObjectType('DateTime'), ], - new FunctionVariant(new TemplateTypeMap([ + new FunctionVariant( + new TemplateTypeMap([ 'T' => $templateType('T'), 'U' => $templateType('U'), - ]), null, [ - new DummyParameter('a', $templateType('T'), false, PassedByReference::createNo(), false, null), - new DummyParameter('b', $templateType('U'), false, PassedByReference::createNo(), false, null), - ], false, new NullType()), - new FunctionVariant(new TemplateTypeMap([ + ]), + null, + [ + new DummyParameter( + 'a', + $templateType('T'), + false, + PassedByReference::createNo(), + false, + null, + ), + new DummyParameter( + 'b', + $templateType('U'), + false, + PassedByReference::createNo(), + false, + null, + ), + ], + false, + new NullType(), + ), + new FunctionVariant( + new TemplateTypeMap([ 'T' => $templateType('T'), 'U' => $templateType('U'), - ]), null, [ - new DummyParameter('a', new ObjectType('DateTime'), false, PassedByReference::createNo(), false, null), - new DummyParameter('b', new MixedType(), false, PassedByReference::createNo(), false, null), - ], false, new NullType()), + ]), + null, + [ + new DummyParameter( + 'a', + new ObjectType('DateTime'), + false, + PassedByReference::createNo(), + false, + null, + ), + new DummyParameter( + 'b', + new MixedType(), + false, + PassedByReference::createNo(), + false, + null, + ), + ], + false, + new NullType(), + ), ], 'constant string arg resolved to constant string' => [ [ new ConstantStringType('foooooo'), ], - new FunctionVariant(new TemplateTypeMap([ + new FunctionVariant( + new TemplateTypeMap([ 'T' => $templateType('T'), - ]), null, [ + ]), + null, + [ new DummyParameter('str', $templateType('T'), false, null, false, null), - ], false, $templateType('T')), - new FunctionVariant(TemplateTypeMap::createEmpty(), null, [ + ], + false, + $templateType('T'), + ), + new FunctionVariant( + TemplateTypeMap::createEmpty(), + null, + [ new DummyParameter('str', new ConstantStringType('foooooo'), false, null, false, null), - ], false, new ConstantStringType('foooooo')), + ], + false, + new ConstantStringType('foooooo'), + ), ], ]; } @@ -187,10 +428,21 @@ public function dataResolve(): array public function testResolve(array $argTypes, ParametersAcceptor $parametersAcceptor, ParametersAcceptor $expectedResult): void { self::getContainer(); // to initialize bleeding edge - $result = GenericParametersAcceptorResolver::resolve($argTypes, $parametersAcceptor); + $result = GenericParametersAcceptorResolver::resolve( + $argTypes, + $parametersAcceptor, + ); - $this->assertInstanceOf(get_class($expectedResult->getReturnType()), $result->getReturnType(), 'Unexpected return type'); - $this->assertSame($expectedResult->getReturnType()->describe(VerbosityLevel::precise()), $result->getReturnType()->describe(VerbosityLevel::precise()), 'Unexpected return type'); + $this->assertInstanceOf( + get_class($expectedResult->getReturnType()), + $result->getReturnType(), + 'Unexpected return type', + ); + $this->assertSame( + $expectedResult->getReturnType()->describe(VerbosityLevel::precise()), + $result->getReturnType()->describe(VerbosityLevel::precise()), + 'Unexpected return type', + ); $resultParameters = $result->getParameters(); $expectedParameters = $expectedResult->getParameters(); @@ -198,8 +450,16 @@ public function testResolve(array $argTypes, ParametersAcceptor $parametersAccep $this->assertCount(count($expectedParameters), $resultParameters); foreach ($expectedParameters as $i => $param) { - $this->assertInstanceOf(get_class($param->getType()), $resultParameters[$i]->getType(), sprintf('Unexpected parameter %d', $i + 1)); - $this->assertSame($param->getType()->describe(VerbosityLevel::precise()), $resultParameters[$i]->getType()->describe(VerbosityLevel::precise()), sprintf('Unexpected parameter %d', $i + 1)); + $this->assertInstanceOf( + get_class($param->getType()), + $resultParameters[$i]->getType(), + sprintf('Unexpected parameter %d', $i + 1), + ); + $this->assertSame( + $param->getType()->describe(VerbosityLevel::precise()), + $resultParameters[$i]->getType()->describe(VerbosityLevel::precise()), + sprintf('Unexpected parameter %d', $i + 1), + ); } } diff --git a/tests/PHPStan/Reflection/InitializerExprTypeResolverTest.php b/tests/PHPStan/Reflection/InitializerExprTypeResolverTest.php index 6242f52aa32..9288f62e8df 100644 --- a/tests/PHPStan/Reflection/InitializerExprTypeResolverTest.php +++ b/tests/PHPStan/Reflection/InitializerExprTypeResolverTest.php @@ -94,9 +94,7 @@ static function (Expr $expr): Type { yield [ new LNumber(1), new LNumber(1), - static function (Expr $expr) : Type { - return new ConstantIntegerType(1); - }, + static fn (Expr $expr): Type => new ConstantIntegerType(1), ConstantIntegerType::class, ]; } @@ -111,7 +109,11 @@ public function testExplicitNever(Expr $left, Expr $right, callable $callback, s { $initializerExprTypeResolver = self::getContainer()->getByType(InitializerExprTypeResolver::class); - $result = $initializerExprTypeResolver->getPlusType($left, $right, $callback); + $result = $initializerExprTypeResolver->getPlusType( + $left, + $right, + $callback, + ); $this->assertInstanceOf($resultClass, $result); if (!($result instanceof NeverType)) { diff --git a/tests/PHPStan/Reflection/ParametersAcceptorSelectorTest.php b/tests/PHPStan/Reflection/ParametersAcceptorSelectorTest.php index 24a14959686..2b2b96c00f7 100644 --- a/tests/PHPStan/Reflection/ParametersAcceptorSelectorTest.php +++ b/tests/PHPStan/Reflection/ParametersAcceptorSelectorTest.php @@ -118,10 +118,30 @@ public function dataSelectFromTypes(): Generator ], $ibaseWaitEventVariants, false, - new FunctionVariant(TemplateTypeMap::createEmpty(), null, [ - new NativeParameterReflection('link_identifier|event', false, new MixedType(), PassedByReference::createNo(), false, null), - new NativeParameterReflection('event|args', true, new MixedType(), PassedByReference::createNo(), true, null), - ], true, new StringType()), + new FunctionVariant( + TemplateTypeMap::createEmpty(), + null, + [ + new NativeParameterReflection( + 'link_identifier|event', + false, + new MixedType(), + PassedByReference::createNo(), + false, + null, + ), + new NativeParameterReflection( + 'event|args', + true, + new MixedType(), + PassedByReference::createNo(), + true, + null, + ), + ], + true, + new StringType(), + ), ]; $absVariants = $reflectionProvider->getFunction(new Name('abs'), null)->getVariants(); @@ -158,10 +178,30 @@ public function dataSelectFromTypes(): Generator [], $strtokVariants, false, - new FunctionVariant(TemplateTypeMap::createEmpty(), null, [ - new NativeParameterReflection('str|token', false, new StringType(), PassedByReference::createNo(), false, null), - new NativeParameterReflection('token', true, new StringType(), PassedByReference::createNo(), false, new NullType()), - ], false, new UnionType([new IntersectionType([new StringType(), new AccessoryNonEmptyStringType()]), new ConstantBooleanType(false)])), + new FunctionVariant( + TemplateTypeMap::createEmpty(), + null, + [ + new NativeParameterReflection( + 'str|token', + false, + new StringType(), + PassedByReference::createNo(), + false, + null, + ), + new NativeParameterReflection( + 'token', + true, + new StringType(), + PassedByReference::createNo(), + false, + new NullType(), + ), + ], + false, + new UnionType([new IntersectionType([new StringType(), new AccessoryNonEmptyStringType()]), new ConstantBooleanType(false)]), + ), ]; yield [ [ @@ -173,14 +213,54 @@ public function dataSelectFromTypes(): Generator ]; $variadicVariants = [ - new FunctionVariant(TemplateTypeMap::createEmpty(), null, [ - new NativeParameterReflection('int', false, new IntegerType(), PassedByReference::createNo(), false, null), - new NativeParameterReflection('intVariadic', true, new IntegerType(), PassedByReference::createNo(), true, null), - ], true, new IntegerType()), - new FunctionVariant(TemplateTypeMap::createEmpty(), null, [ - new NativeParameterReflection('int', false, new IntegerType(), PassedByReference::createNo(), false, null), - new NativeParameterReflection('floatVariadic', true, new FloatType(), PassedByReference::createNo(), true, null), - ], true, new IntegerType()), + new FunctionVariant( + TemplateTypeMap::createEmpty(), + null, + [ + new NativeParameterReflection( + 'int', + false, + new IntegerType(), + PassedByReference::createNo(), + false, + null, + ), + new NativeParameterReflection( + 'intVariadic', + true, + new IntegerType(), + PassedByReference::createNo(), + true, + null, + ), + ], + true, + new IntegerType(), + ), + new FunctionVariant( + TemplateTypeMap::createEmpty(), + null, + [ + new NativeParameterReflection( + 'int', + false, + new IntegerType(), + PassedByReference::createNo(), + false, + null, + ), + new NativeParameterReflection( + 'floatVariadic', + true, + new FloatType(), + PassedByReference::createNo(), + true, + null, + ), + ], + true, + new IntegerType(), + ), ]; yield [ @@ -202,12 +282,38 @@ public function dataSelectFromTypes(): Generator ]; $defaultValuesVariants1 = [ - new FunctionVariant(TemplateTypeMap::createEmpty(), null, [ - new DummyParameter('a', new MixedType(), false, PassedByReference::createNo(), false, new ConstantIntegerType(1)), - ], false, new NullType()), - new FunctionVariant(TemplateTypeMap::createEmpty(), null, [ - new DummyParameter('a', new MixedType(), false, PassedByReference::createNo(), false, new ConstantIntegerType(2)), - ], false, new NullType()), + new FunctionVariant( + TemplateTypeMap::createEmpty(), + null, + [ + new DummyParameter( + 'a', + new MixedType(), + false, + PassedByReference::createNo(), + false, + new ConstantIntegerType(1), + ), + ], + false, + new NullType(), + ), + new FunctionVariant( + TemplateTypeMap::createEmpty(), + null, + [ + new DummyParameter( + 'a', + new MixedType(), + false, + PassedByReference::createNo(), + false, + new ConstantIntegerType(2), + ), + ], + false, + new NullType(), + ), ]; yield [ @@ -216,21 +322,60 @@ public function dataSelectFromTypes(): Generator ], $defaultValuesVariants1, true, - new FunctionVariant(TemplateTypeMap::createEmpty(), null, [ - new DummyParameter('a', new MixedType(), false, PassedByReference::createNo(), false, new UnionType([ + new FunctionVariant( + TemplateTypeMap::createEmpty(), + null, + [ + new DummyParameter( + 'a', + new MixedType(), + false, + PassedByReference::createNo(), + false, + new UnionType([ new ConstantIntegerType(1), new ConstantIntegerType(2), - ])), - ], false, new NullType()), + ]), + ), + ], + false, + new NullType(), + ), ]; $defaultValuesVariants2 = [ - new FunctionVariant(TemplateTypeMap::createEmpty(), null, [ - new DummyParameter('a', new MixedType(), false, PassedByReference::createNo(), false, new ConstantIntegerType(1)), - ], false, new NullType()), - new FunctionVariant(TemplateTypeMap::createEmpty(), null, [ - new DummyParameter('a', new MixedType(), false, PassedByReference::createNo(), false, null), - ], false, new NullType()), + new FunctionVariant( + TemplateTypeMap::createEmpty(), + null, + [ + new DummyParameter( + 'a', + new MixedType(), + false, + PassedByReference::createNo(), + false, + new ConstantIntegerType(1), + ), + ], + false, + new NullType(), + ), + new FunctionVariant( + TemplateTypeMap::createEmpty(), + null, + [ + new DummyParameter( + 'a', + new MixedType(), + false, + PassedByReference::createNo(), + false, + null, + ), + ], + false, + new NullType(), + ), ]; yield [ @@ -239,15 +384,46 @@ public function dataSelectFromTypes(): Generator ], $defaultValuesVariants2, true, - new FunctionVariant(TemplateTypeMap::createEmpty(), null, [ - new DummyParameter('a', new MixedType(), false, PassedByReference::createNo(), false, null), - ], false, new NullType()), + new FunctionVariant( + TemplateTypeMap::createEmpty(), + null, + [ + new DummyParameter( + 'a', + new MixedType(), + false, + PassedByReference::createNo(), + false, + null, + ), + ], + false, + new NullType(), + ), ]; $genericVariants = [ - new FunctionVariant(TemplateTypeMap::createEmpty(), null, [ - new DummyParameter('a', TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('a'), 'T', null, TemplateTypeVariance::createInvariant()), false, PassedByReference::createNo(), false, null), - ], false, new NullType()), + new FunctionVariant( + TemplateTypeMap::createEmpty(), + null, + [ + new DummyParameter( + 'a', + TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('a'), + 'T', + null, + TemplateTypeVariance::createInvariant(), + ), + false, + PassedByReference::createNo(), + false, + null, + ), + ], + false, + new NullType(), + ), ]; yield [ @@ -256,9 +432,22 @@ public function dataSelectFromTypes(): Generator ], $genericVariants, true, - new FunctionVariant(TemplateTypeMap::createEmpty(), null, [ - new DummyParameter('a', new IntegerType(), false, PassedByReference::createNo(), false, null), - ], false, new NullType()), + new FunctionVariant( + TemplateTypeMap::createEmpty(), + null, + [ + new DummyParameter( + 'a', + new IntegerType(), + false, + PassedByReference::createNo(), + false, + null, + ), + ], + false, + new NullType(), + ), ]; } @@ -267,24 +456,50 @@ public function dataSelectFromTypes(): Generator * @param Type[] $types * @param ParametersAcceptor[] $variants */ - public function testSelectFromTypes(array $types, array $variants, bool $unpack, ParametersAcceptor $expected) : void + public function testSelectFromTypes( + array $types, + array $variants, + bool $unpack, + ParametersAcceptor $expected, + ): void { $selectedAcceptor = ParametersAcceptorSelector::selectFromTypes($types, $variants, $unpack); $this->assertCount(count($expected->getParameters()), $selectedAcceptor->getParameters()); foreach ($selectedAcceptor->getParameters() as $i => $parameter) { $expectedParameter = $expected->getParameters()[$i]; - $this->assertSame($expectedParameter->getName(), $parameter->getName()); - $this->assertSame($expectedParameter->isOptional(), $parameter->isOptional()); - $this->assertSame($expectedParameter->getType()->describe(VerbosityLevel::precise()), $parameter->getType()->describe(VerbosityLevel::precise())); - $this->assertTrue($expectedParameter->passedByReference()->equals($parameter->passedByReference())); - $this->assertSame($expectedParameter->isVariadic(), $parameter->isVariadic()); + $this->assertSame( + $expectedParameter->getName(), + $parameter->getName(), + ); + $this->assertSame( + $expectedParameter->isOptional(), + $parameter->isOptional(), + ); + $this->assertSame( + $expectedParameter->getType()->describe(VerbosityLevel::precise()), + $parameter->getType()->describe(VerbosityLevel::precise()), + ); + $this->assertTrue( + $expectedParameter->passedByReference()->equals($parameter->passedByReference()), + ); + $this->assertSame( + $expectedParameter->isVariadic(), + $parameter->isVariadic(), + ); if ($expectedParameter->getDefaultValue() === null) { $this->assertNull($parameter->getDefaultValue()); } else { - $this->assertSame($expectedParameter->getDefaultValue()->describe(VerbosityLevel::precise()), $parameter->getDefaultValue() !== null ? $parameter->getDefaultValue()->describe(VerbosityLevel::precise()) : null); + $this->assertSame( + $expectedParameter->getDefaultValue()->describe(VerbosityLevel::precise()), + $parameter->getDefaultValue() !== null ? $parameter->getDefaultValue()->describe(VerbosityLevel::precise()) : null, + ); } } - $this->assertSame($expected->getReturnType()->describe(VerbosityLevel::precise()), $selectedAcceptor->getReturnType()->describe(VerbosityLevel::precise())); + + $this->assertSame( + $expected->getReturnType()->describe(VerbosityLevel::precise()), + $selectedAcceptor->getReturnType()->describe(VerbosityLevel::precise()), + ); $this->assertSame($expected->isVariadic(), $selectedAcceptor->isVariadic()); } diff --git a/tests/PHPStan/Reflection/Php/UniversalObjectCratesClassReflectionExtensionTest.php b/tests/PHPStan/Reflection/Php/UniversalObjectCratesClassReflectionExtensionTest.php index 925acf70952..dabd3948e05 100644 --- a/tests/PHPStan/Reflection/Php/UniversalObjectCratesClassReflectionExtensionTest.php +++ b/tests/PHPStan/Reflection/Php/UniversalObjectCratesClassReflectionExtensionTest.php @@ -14,7 +14,11 @@ class UniversalObjectCratesClassReflectionExtensionTest extends PHPStanTestCase public function testNonexistentClass(): void { $reflectionProvider = $this->createReflectionProvider(); - $extension = new UniversalObjectCratesClassReflectionExtension($reflectionProvider, ['NonexistentClass', 'stdClass'], new AnnotationsPropertiesClassReflectionExtension()); + $extension = new UniversalObjectCratesClassReflectionExtension( + $reflectionProvider, + ['NonexistentClass', 'stdClass'], + new AnnotationsPropertiesClassReflectionExtension(), + ); $this->assertTrue($extension->hasProperty($reflectionProvider->getClass(stdClass::class), 'foo')); } @@ -23,14 +27,24 @@ public function testDifferentGetSetType(): void require_once __DIR__ . '/data/universal-object-crates.php'; $reflectionProvider = $this->createReflectionProvider(); - $extension = new UniversalObjectCratesClassReflectionExtension($reflectionProvider, ['UniversalObjectCreates\DifferentGetSetTypes'], new AnnotationsPropertiesClassReflectionExtension()); + $extension = new UniversalObjectCratesClassReflectionExtension( + $reflectionProvider, + ['UniversalObjectCreates\DifferentGetSetTypes'], + new AnnotationsPropertiesClassReflectionExtension(), + ); - $this->assertEquals(new ObjectType('UniversalObjectCreates\DifferentGetSetTypesValue'), $extension + $this->assertEquals( + new ObjectType('UniversalObjectCreates\DifferentGetSetTypesValue'), + $extension ->getProperty($reflectionProvider->getClass('UniversalObjectCreates\DifferentGetSetTypes'), 'foo') - ->getReadableType()); - $this->assertEquals(new StringType(), $extension + ->getReadableType(), + ); + $this->assertEquals( + new StringType(), + $extension ->getProperty($reflectionProvider->getClass('UniversalObjectCreates\DifferentGetSetTypes'), 'foo') - ->getWritableType()); + ->getWritableType(), + ); } public function testAnnotationOverrides(): void @@ -39,14 +53,24 @@ public function testAnnotationOverrides(): void $className = 'UniversalObjectCratesAnnotations\Model'; $reflectionProvider = $this->createReflectionProvider(); - $extension = new UniversalObjectCratesClassReflectionExtension($reflectionProvider, [$className], new AnnotationsPropertiesClassReflectionExtension()); + $extension = new UniversalObjectCratesClassReflectionExtension( + $reflectionProvider, + [$className], + new AnnotationsPropertiesClassReflectionExtension(), + ); - $this->assertEquals(new StringType(), $extension + $this->assertEquals( + new StringType(), + $extension ->getProperty($reflectionProvider->getClass($className), 'foo') - ->getReadableType()); - $this->assertEquals(new StringType(), $extension + ->getReadableType(), + ); + $this->assertEquals( + new StringType(), + $extension ->getProperty($reflectionProvider->getClass($className), 'foo') - ->getWritableType()); + ->getWritableType(), + ); } } diff --git a/tests/PHPStan/Reflection/ReflectionProviderGoldenTest.php b/tests/PHPStan/Reflection/ReflectionProviderGoldenTest.php index ec725d30781..e6fe0eed753 100644 --- a/tests/PHPStan/Reflection/ReflectionProviderGoldenTest.php +++ b/tests/PHPStan/Reflection/ReflectionProviderGoldenTest.php @@ -485,10 +485,12 @@ public static function dumpInputSymbols(): void /** @return list */ public static function scrapeInputSymbols(): array { - $result = array_keys(self::scrapeInputSymbolsFromFunctionMap() + $result = array_keys( + self::scrapeInputSymbolsFromFunctionMap() + self::scrapeInputSymbolsFromPhp8Stubs() + self::scrapeInputSymbolsFromPhpStormStubs() - + self::scrapeInputSymbolsFromReflection()); + + self::scrapeInputSymbolsFromReflection(), + ); sort($result); return $result; @@ -609,12 +611,9 @@ private static function scrapeSymbolsFromStubs(array $stubFiles): array $visitor = new class () extends NodeVisitorAbstract { /** @var array */ - public $symbols = []; + public array $symbols = []; - /** - * @var Node\Stmt\ClassLike - */ - private $classLike; + private Node\Stmt\ClassLike $classLike; public function enterNode(Node $node) { diff --git a/tests/PHPStan/Reflection/ReflectionProviderTest.php b/tests/PHPStan/Reflection/ReflectionProviderTest.php index 67a98787b67..06f7545d49e 100644 --- a/tests/PHPStan/Reflection/ReflectionProviderTest.php +++ b/tests/PHPStan/Reflection/ReflectionProviderTest.php @@ -62,7 +62,10 @@ public function testFunctionThrowType(string $functionName, ?Type $expectedThrow return; } $this->assertNotNull($throwType); - $this->assertSame($expectedThrowType->describe(VerbosityLevel::precise()), $throwType->describe(VerbosityLevel::precise())); + $this->assertSame( + $expectedThrowType->describe(VerbosityLevel::precise()), + $throwType->describe(VerbosityLevel::precise()), + ); } public function dataFunctionDeprecated(): iterable @@ -131,7 +134,10 @@ public function testMethodThrowType(string $className, string $methodName, ?Type return; } $this->assertNotNull($throwType); - $this->assertSame($expectedThrowType->describe(VerbosityLevel::precise()), $throwType->describe(VerbosityLevel::precise())); + $this->assertSame( + $expectedThrowType->describe(VerbosityLevel::precise()), + $throwType->describe(VerbosityLevel::precise()), + ); } public function testNativeClassConstantTypeInEvaledClass(): void diff --git a/tests/PHPStan/Reflection/SignatureMap/FunctionMetadataTest.php b/tests/PHPStan/Reflection/SignatureMap/FunctionMetadataTest.php index 8b9c233429a..24ef8431eee 100644 --- a/tests/PHPStan/Reflection/SignatureMap/FunctionMetadataTest.php +++ b/tests/PHPStan/Reflection/SignatureMap/FunctionMetadataTest.php @@ -15,9 +15,11 @@ public function testSchema(): void $this->assertIsArray($data); $processor = new Processor(); - $processor->process(Expect::arrayOf(Expect::structure([ + $processor->process(Expect::arrayOf( + Expect::structure([ 'hasSideEffects' => Expect::bool()->required(), - ])->required())->required(), $data); + ])->required(), + )->required(), $data); } } diff --git a/tests/PHPStan/Reflection/SignatureMap/Php8SignatureMapProviderTest.php b/tests/PHPStan/Reflection/SignatureMap/Php8SignatureMapProviderTest.php index a0f0dc9cd1f..ad5aa4077f2 100644 --- a/tests/PHPStan/Reflection/SignatureMap/Php8SignatureMapProviderTest.php +++ b/tests/PHPStan/Reflection/SignatureMap/Php8SignatureMapProviderTest.php @@ -130,7 +130,13 @@ public function dataFunctions(): array * @dataProvider dataFunctions * @param mixed[] $parameters */ - public function testFunctions(string $functionName, array $parameters, Type $returnType, Type $nativeReturnType, bool $variadic) : void + public function testFunctions( + string $functionName, + array $parameters, + Type $returnType, + Type $nativeReturnType, + bool $variadic, + ): void { $provider = $this->createProvider(); $reflector = self::getContainer()->getByType(Reflector::class); @@ -143,7 +149,18 @@ private function createProvider(): Php8SignatureMapProvider { $phpVersion = new PhpVersion(80000); - return new Php8SignatureMapProvider(new FunctionSignatureMapProvider(self::getContainer()->getByType(SignatureMapParser::class), self::getContainer()->getByType(InitializerExprTypeResolver::class), $phpVersion, true), self::getContainer()->getByType(FileNodesFetcher::class), self::getContainer()->getByType(FileTypeMapper::class), $phpVersion, self::getContainer()->getByType(InitializerExprTypeResolver::class)); + return new Php8SignatureMapProvider( + new FunctionSignatureMapProvider( + self::getContainer()->getByType(SignatureMapParser::class), + self::getContainer()->getByType(InitializerExprTypeResolver::class), + $phpVersion, + true, + ), + self::getContainer()->getByType(FileNodesFetcher::class), + self::getContainer()->getByType(FileTypeMapper::class), + $phpVersion, + self::getContainer()->getByType(InitializerExprTypeResolver::class), + ); } public function dataMethods(): array @@ -241,7 +258,14 @@ public function dataMethods(): array * @dataProvider dataMethods * @param mixed[] $parameters */ - public function testMethods(string $className, string $methodName, array $parameters, Type $returnType, Type $nativeReturnType, bool $variadic) : void + public function testMethods( + string $className, + string $methodName, + array $parameters, + Type $returnType, + Type $nativeReturnType, + bool $variadic, + ): void { $provider = $this->createProvider(); $signatures = $provider->getMethodSignatures($className, $methodName, null)['positional']; @@ -252,7 +276,13 @@ public function testMethods(string $className, string $methodName, array $parame /** * @param mixed[] $expectedParameters */ - private function assertSignature(array $expectedParameters, Type $expectedReturnType, Type $expectedNativeReturnType, bool $expectedVariadic, FunctionSignature $actualSignature) : void + private function assertSignature( + array $expectedParameters, + Type $expectedReturnType, + Type $expectedNativeReturnType, + bool $expectedVariadic, + FunctionSignature $actualSignature, + ): void { $this->assertCount(count($expectedParameters), $actualSignature->getParameters()); foreach ($expectedParameters as $i => $expectedParameter) { @@ -264,6 +294,7 @@ private function assertSignature(array $expectedParameters, Type $expectedReturn $this->assertTrue($expectedParameter['passedByReference']->equals($actualParameter->passedByReference())); $this->assertSame($expectedParameter['variadic'], $actualParameter->isVariadic()); } + $this->assertSame($expectedReturnType->describe(VerbosityLevel::precise()), $actualSignature->getReturnType()->describe(VerbosityLevel::precise())); $this->assertSame($expectedNativeReturnType->describe(VerbosityLevel::precise()), $actualSignature->getNativeReturnType()->describe(VerbosityLevel::precise())); $this->assertSame($expectedVariadic, $actualSignature->isVariadic()); @@ -272,9 +303,7 @@ private function assertSignature(array $expectedParameters, Type $expectedReturn public function dataParseAll(): array { $map = new Php8StubsMap(PHP_VERSION_ID); - return array_map(static function (string $file) : array { - return [__DIR__ . '/../../../../vendor/phpstan/php-8-stubs/' . $file]; - }, array_merge($map->classes, $map->functions)); + return array_map(static fn (string $file): array => [__DIR__ . '/../../../../vendor/phpstan/php-8-stubs/' . $file], array_merge($map->classes, $map->functions)); } /** diff --git a/tests/PHPStan/Reflection/SignatureMap/SignatureMapParserTest.php b/tests/PHPStan/Reflection/SignatureMap/SignatureMapParserTest.php index 5e7d5a9a49c..00ed1a41591 100644 --- a/tests/PHPStan/Reflection/SignatureMap/SignatureMapParserTest.php +++ b/tests/PHPStan/Reflection/SignatureMap/SignatureMapParserTest.php @@ -46,107 +46,379 @@ public function dataGetFunctions(): array [ ['int', 'fp' => 'resource', 'fields' => 'array', 'delimiter=' => 'string', 'enclosure=' => 'string', 'escape_char=' => 'string'], null, - new FunctionSignature([ - new ParameterSignature('fp', false, new ResourceType(), new MixedType(), PassedByReference::createNo(), false, null, null), - new ParameterSignature('fields', false, new ArrayType(new MixedType(), new MixedType()), new MixedType(), PassedByReference::createNo(), false, null, null), - new ParameterSignature('delimiter', true, new StringType(), new MixedType(), PassedByReference::createNo(), false, null, null), - new ParameterSignature('enclosure', true, new StringType(), new MixedType(), PassedByReference::createNo(), false, null, null), - new ParameterSignature('escape_char', true, new StringType(), new MixedType(), PassedByReference::createNo(), false, null, null), - ], new IntegerType(), new MixedType(), false), + new FunctionSignature( + [ + new ParameterSignature( + 'fp', + false, + new ResourceType(), + new MixedType(), + PassedByReference::createNo(), + false, + null, + null, + ), + new ParameterSignature( + 'fields', + false, + new ArrayType(new MixedType(), new MixedType()), + new MixedType(), + PassedByReference::createNo(), + false, + null, + null, + ), + new ParameterSignature( + 'delimiter', + true, + new StringType(), + new MixedType(), + PassedByReference::createNo(), + false, + null, + null, + ), + new ParameterSignature( + 'enclosure', + true, + new StringType(), + new MixedType(), + PassedByReference::createNo(), + false, + null, + null, + ), + new ParameterSignature( + 'escape_char', + true, + new StringType(), + new MixedType(), + PassedByReference::createNo(), + false, + null, + null, + ), + ], + new IntegerType(), + new MixedType(), + false, + ), ], [ ['bool', 'fp' => 'resource'], null, - new FunctionSignature([ - new ParameterSignature('fp', false, new ResourceType(), new MixedType(), PassedByReference::createNo(), false, null, null), - ], new BooleanType(), new MixedType(), false), + new FunctionSignature( + [ + new ParameterSignature( + 'fp', + false, + new ResourceType(), + new MixedType(), + PassedByReference::createNo(), + false, + null, + null, + ), + ], + new BooleanType(), + new MixedType(), + false, + ), ], [ ['bool', '&rw_array_arg' => 'array'], null, - new FunctionSignature([ - new ParameterSignature('array_arg', false, new ArrayType(new MixedType(), new MixedType()), new MixedType(), PassedByReference::createReadsArgument(), false, null, null), - ], new BooleanType(), new MixedType(), false), + new FunctionSignature( + [ + new ParameterSignature( + 'array_arg', + false, + new ArrayType(new MixedType(), new MixedType()), + new MixedType(), + PassedByReference::createReadsArgument(), + false, + null, + null, + ), + ], + new BooleanType(), + new MixedType(), + false, + ), ], [ ['bool', 'csr' => 'string|resource', '&w_out' => 'string', 'notext=' => 'bool'], null, - new FunctionSignature([ - new ParameterSignature('csr', false, new UnionType([ + new FunctionSignature( + [ + new ParameterSignature( + 'csr', + false, + new UnionType([ new StringType(), new ResourceType(), - ]), new MixedType(), PassedByReference::createNo(), false, null, null), - new ParameterSignature('out', false, new StringType(), new MixedType(), PassedByReference::createCreatesNewVariable(), false, null, null), - new ParameterSignature('notext', true, new BooleanType(), new MixedType(), PassedByReference::createNo(), false, null, null), - ], new BooleanType(), new MixedType(), false), + ]), + new MixedType(), + PassedByReference::createNo(), + false, + null, + null, + ), + new ParameterSignature( + 'out', + false, + new StringType(), + new MixedType(), + PassedByReference::createCreatesNewVariable(), + false, + null, + null, + ), + new ParameterSignature( + 'notext', + true, + new BooleanType(), + new MixedType(), + PassedByReference::createNo(), + false, + null, + null, + ), + ], + new BooleanType(), + new MixedType(), + false, + ), ], [ ['(?Throwable)|(?Foo)'], null, - new FunctionSignature([], new UnionType([ + new FunctionSignature( + [], + new UnionType([ new ObjectType(Throwable::class), new ObjectType('Foo'), new NullType(), - ]), new MixedType(), false), + ]), + new MixedType(), + false, + ), ], [ [''], null, - new FunctionSignature([], new MixedType(), new MixedType(), false), + new FunctionSignature( + [], + new MixedType(), + new MixedType(), + false, + ), ], [ ['array', 'arr1' => 'array', 'arr2' => 'array', '...=' => 'array'], null, - new FunctionSignature([ - new ParameterSignature('arr1', false, new ArrayType(new MixedType(), new MixedType()), new MixedType(), PassedByReference::createNo(), false, null, null), - new ParameterSignature('arr2', false, new ArrayType(new MixedType(), new MixedType()), new MixedType(), PassedByReference::createNo(), false, null, null), - new ParameterSignature('...', true, new ArrayType(new MixedType(), new MixedType()), new MixedType(), PassedByReference::createNo(), true, null, null), - ], new ArrayType(new MixedType(), new MixedType()), new MixedType(), true), + new FunctionSignature( + [ + new ParameterSignature( + 'arr1', + false, + new ArrayType(new MixedType(), new MixedType()), + new MixedType(), + PassedByReference::createNo(), + false, + null, + null, + ), + new ParameterSignature( + 'arr2', + false, + new ArrayType(new MixedType(), new MixedType()), + new MixedType(), + PassedByReference::createNo(), + false, + null, + null, + ), + new ParameterSignature( + '...', + true, + new ArrayType(new MixedType(), new MixedType()), + new MixedType(), + PassedByReference::createNo(), + true, + null, + null, + ), + ], + new ArrayType(new MixedType(), new MixedType()), + new MixedType(), + true, + ), ], [ ['resource', 'callback' => 'callable', 'event' => 'string', '...' => ''], null, - new FunctionSignature([ - new ParameterSignature('callback', false, new CallableType(), new MixedType(), PassedByReference::createNo(), false, null, null), - new ParameterSignature('event', false, new StringType(), new MixedType(), PassedByReference::createNo(), false, null, null), - new ParameterSignature('...', true, new MixedType(), new MixedType(), PassedByReference::createNo(), true, null, null), - ], new ResourceType(), new MixedType(), true), + new FunctionSignature( + [ + new ParameterSignature( + 'callback', + false, + new CallableType(), + new MixedType(), + PassedByReference::createNo(), + false, + null, + null, + ), + new ParameterSignature( + 'event', + false, + new StringType(), + new MixedType(), + PassedByReference::createNo(), + false, + null, + null, + ), + new ParameterSignature( + '...', + true, + new MixedType(), + new MixedType(), + PassedByReference::createNo(), + true, + null, + null, + ), + ], + new ResourceType(), + new MixedType(), + true, + ), ], [ ['string', 'format' => 'string', '...args=' => ''], null, - new FunctionSignature([ - new ParameterSignature('format', false, new StringType(), new MixedType(), PassedByReference::createNo(), false, null, null), - new ParameterSignature('args', true, new MixedType(), new MixedType(), PassedByReference::createNo(), true, null, null), - ], new StringType(), new MixedType(), true), + new FunctionSignature( + [ + new ParameterSignature( + 'format', + false, + new StringType(), + new MixedType(), + PassedByReference::createNo(), + false, + null, + null, + ), + new ParameterSignature( + 'args', + true, + new MixedType(), + new MixedType(), + PassedByReference::createNo(), + true, + null, + null, + ), + ], + new StringType(), + new MixedType(), + true, + ), ], [ ['string', 'format' => 'string', '...args' => ''], null, - new FunctionSignature([ - new ParameterSignature('format', false, new StringType(), new MixedType(), PassedByReference::createNo(), false, null, null), - new ParameterSignature('args', true, new MixedType(), new MixedType(), PassedByReference::createNo(), true, null, null), - ], new StringType(), new MixedType(), true), + new FunctionSignature( + [ + new ParameterSignature( + 'format', + false, + new StringType(), + new MixedType(), + PassedByReference::createNo(), + false, + null, + null, + ), + new ParameterSignature( + 'args', + true, + new MixedType(), + new MixedType(), + PassedByReference::createNo(), + true, + null, + null, + ), + ], + new StringType(), + new MixedType(), + true, + ), ], [ ['array'], null, - new FunctionSignature([], new ArrayType(new IntegerType(), new ObjectType(ReflectionParameter::class)), new MixedType(), false), + new FunctionSignature( + [], + new ArrayType(new IntegerType(), new ObjectType(ReflectionParameter::class)), + new MixedType(), + false, + ), ], [ ['static', 'interval' => 'DateInterval'], DateTime::class, - new FunctionSignature([ - new ParameterSignature('interval', false, new ObjectType(DateInterval::class), new MixedType(), PassedByReference::createNo(), false, null, null), - ], new StaticType($reflectionProvider->getClass(DateTime::class)), new MixedType(), false), + new FunctionSignature( + [ + new ParameterSignature( + 'interval', + false, + new ObjectType(DateInterval::class), + new MixedType(), + PassedByReference::createNo(), + false, + null, + null, + ), + ], + new StaticType($reflectionProvider->getClass(DateTime::class)), + new MixedType(), + false, + ), ], [ ['bool', '&rw_string' => 'string', '&...rw_strings=' => 'string'], null, - new FunctionSignature([ - new ParameterSignature('string', false, new StringType(), new MixedType(), PassedByReference::createReadsArgument(), false, null, null), - new ParameterSignature('strings', true, new StringType(), new MixedType(), PassedByReference::createReadsArgument(), true, null, null), - ], new BooleanType(), new MixedType(), true), + new FunctionSignature( + [ + new ParameterSignature( + 'string', + false, + new StringType(), + new MixedType(), + PassedByReference::createReadsArgument(), + false, + null, + null, + ), + new ParameterSignature( + 'strings', + true, + new StringType(), + new MixedType(), + PassedByReference::createReadsArgument(), + true, + null, + null, + ), + ], + new BooleanType(), + new MixedType(), + true, + ), ], ]; } @@ -155,22 +427,59 @@ public function dataGetFunctions(): array * @dataProvider dataGetFunctions * @param mixed[] $map */ - public function testGetFunctions(array $map, ?string $className, FunctionSignature $expectedSignature) : void + public function testGetFunctions( + array $map, + ?string $className, + FunctionSignature $expectedSignature, + ): void { /** @var SignatureMapParser $parser */ $parser = self::getContainer()->getByType(SignatureMapParser::class); $functionSignature = $parser->getFunctionSignature($map, $className); - $this->assertCount(count($expectedSignature->getParameters()), $functionSignature->getParameters(), 'Number of parameters does not match.'); + $this->assertCount( + count($expectedSignature->getParameters()), + $functionSignature->getParameters(), + 'Number of parameters does not match.', + ); + foreach ($functionSignature->getParameters() as $i => $parameterSignature) { $expectedParameterSignature = $expectedSignature->getParameters()[$i]; - $this->assertSame($expectedParameterSignature->getName(), $parameterSignature->getName(), sprintf('Name of parameter #%d does not match.', $i)); - $this->assertSame($expectedParameterSignature->isOptional(), $parameterSignature->isOptional(), sprintf('Optionality of parameter $%s does not match.', $parameterSignature->getName())); - $this->assertSame($expectedParameterSignature->getType()->describe(VerbosityLevel::precise()), $parameterSignature->getType()->describe(VerbosityLevel::precise()), sprintf('Type of parameter $%s does not match.', $parameterSignature->getName())); - $this->assertTrue($expectedParameterSignature->passedByReference()->equals($parameterSignature->passedByReference()), sprintf('Passed-by-reference of parameter $%s does not match.', $parameterSignature->getName())); - $this->assertSame($expectedParameterSignature->isVariadic(), $parameterSignature->isVariadic(), sprintf('Variadicity of parameter $%s does not match.', $parameterSignature->getName())); + $this->assertSame( + $expectedParameterSignature->getName(), + $parameterSignature->getName(), + sprintf('Name of parameter #%d does not match.', $i), + ); + $this->assertSame( + $expectedParameterSignature->isOptional(), + $parameterSignature->isOptional(), + sprintf('Optionality of parameter $%s does not match.', $parameterSignature->getName()), + ); + $this->assertSame( + $expectedParameterSignature->getType()->describe(VerbosityLevel::precise()), + $parameterSignature->getType()->describe(VerbosityLevel::precise()), + sprintf('Type of parameter $%s does not match.', $parameterSignature->getName()), + ); + $this->assertTrue( + $expectedParameterSignature->passedByReference()->equals($parameterSignature->passedByReference()), + sprintf('Passed-by-reference of parameter $%s does not match.', $parameterSignature->getName()), + ); + $this->assertSame( + $expectedParameterSignature->isVariadic(), + $parameterSignature->isVariadic(), + sprintf('Variadicity of parameter $%s does not match.', $parameterSignature->getName()), + ); } - $this->assertSame($expectedSignature->getReturnType()->describe(VerbosityLevel::precise()), $functionSignature->getReturnType()->describe(VerbosityLevel::precise()), 'Return type does not match.'); - $this->assertSame($expectedSignature->isVariadic(), $functionSignature->isVariadic(), 'Variadicity does not match.'); + + $this->assertSame( + $expectedSignature->getReturnType()->describe(VerbosityLevel::precise()), + $functionSignature->getReturnType()->describe(VerbosityLevel::precise()), + 'Return type does not match.', + ); + $this->assertSame( + $expectedSignature->isVariadic(), + $functionSignature->isVariadic(), + 'Variadicity does not match.', + ); } public function dataParseAll(): array diff --git a/tests/PHPStan/Reflection/Type/IntersectionTypeMethodReflectionTest.php b/tests/PHPStan/Reflection/Type/IntersectionTypeMethodReflectionTest.php index 85c1b62bd88..2d7d3ca3577 100644 --- a/tests/PHPStan/Reflection/Type/IntersectionTypeMethodReflectionTest.php +++ b/tests/PHPStan/Reflection/Type/IntersectionTypeMethodReflectionTest.php @@ -11,21 +11,27 @@ class IntersectionTypeMethodReflectionTest extends PHPStanTestCase public function testCollectsDeprecatedMessages(): void { - $reflection = new IntersectionTypeMethodReflection('foo', [ + $reflection = new IntersectionTypeMethodReflection( + 'foo', + [ $this->createDeprecatedMethod(TrinaryLogic::createYes(), 'Deprecated'), $this->createDeprecatedMethod(TrinaryLogic::createMaybe(), 'Maybe deprecated'), $this->createDeprecatedMethod(TrinaryLogic::createNo(), 'Not deprecated'), - ]); + ], + ); $this->assertSame('Deprecated', $reflection->getDeprecatedDescription()); } public function testMultipleDeprecationsAreJoined(): void { - $reflection = new IntersectionTypeMethodReflection('foo', [ + $reflection = new IntersectionTypeMethodReflection( + 'foo', + [ $this->createDeprecatedMethod(TrinaryLogic::createYes(), 'Deprecated #1'), $this->createDeprecatedMethod(TrinaryLogic::createYes(), 'Deprecated #2'), - ]); + ], + ); $this->assertSame('Deprecated #1 Deprecated #2', $reflection->getDeprecatedDescription()); } diff --git a/tests/PHPStan/Reflection/Type/UnionTypeMethodReflectionTest.php b/tests/PHPStan/Reflection/Type/UnionTypeMethodReflectionTest.php index 26da6b1fd1d..b41d8d9636f 100644 --- a/tests/PHPStan/Reflection/Type/UnionTypeMethodReflectionTest.php +++ b/tests/PHPStan/Reflection/Type/UnionTypeMethodReflectionTest.php @@ -11,21 +11,27 @@ class UnionTypeMethodReflectionTest extends PHPStanTestCase public function testCollectsDeprecatedMessages(): void { - $reflection = new UnionTypeMethodReflection('foo', [ + $reflection = new UnionTypeMethodReflection( + 'foo', + [ $this->createDeprecatedMethod(TrinaryLogic::createYes(), 'Deprecated'), $this->createDeprecatedMethod(TrinaryLogic::createMaybe(), 'Maybe deprecated'), $this->createDeprecatedMethod(TrinaryLogic::createNo(), 'Not deprecated'), - ]); + ], + ); $this->assertSame('Deprecated', $reflection->getDeprecatedDescription()); } public function testMultipleDeprecationsAreJoined(): void { - $reflection = new UnionTypeMethodReflection('foo', [ + $reflection = new UnionTypeMethodReflection( + 'foo', + [ $this->createDeprecatedMethod(TrinaryLogic::createYes(), 'Deprecated #1'), $this->createDeprecatedMethod(TrinaryLogic::createYes(), 'Deprecated #2'), - ]); + ], + ); $this->assertSame('Deprecated #1 Deprecated #2', $reflection->getDeprecatedDescription()); } diff --git a/tests/PHPStan/Rules/Api/ApiClassConstFetchRuleTest.php b/tests/PHPStan/Rules/Api/ApiClassConstFetchRuleTest.php index b1b3e2ab87b..f5a0b797ab1 100644 --- a/tests/PHPStan/Rules/Api/ApiClassConstFetchRuleTest.php +++ b/tests/PHPStan/Rules/Api/ApiClassConstFetchRuleTest.php @@ -24,7 +24,10 @@ public function testRuleInPhpStan(): void public function testRuleOutOfPhpStan(): void { - $tip = sprintf("If you think it should be covered by backward compatibility promise, open a discussion:\n %s\n\n See also:\n https://phpstan.org/developing-extensions/backward-compatibility-promise", 'https://github.com/phpstan/phpstan/discussions'); + $tip = sprintf( + "If you think it should be covered by backward compatibility promise, open a discussion:\n %s\n\n See also:\n https://phpstan.org/developing-extensions/backward-compatibility-promise", + 'https://github.com/phpstan/phpstan/discussions', + ); $this->analyse([__DIR__ . '/data/class-const-fetch-out-of-phpstan.php'], [ [ diff --git a/tests/PHPStan/Rules/Api/ApiClassExtendsRuleTest.php b/tests/PHPStan/Rules/Api/ApiClassExtendsRuleTest.php index b319e950b6b..26651b4e970 100644 --- a/tests/PHPStan/Rules/Api/ApiClassExtendsRuleTest.php +++ b/tests/PHPStan/Rules/Api/ApiClassExtendsRuleTest.php @@ -24,7 +24,10 @@ public function testRuleInPhpStan(): void public function testRuleOutOfPhpStan(): void { - $tip = sprintf("If you think it should be covered by backward compatibility promise, open a discussion:\n %s\n\n See also:\n https://phpstan.org/developing-extensions/backward-compatibility-promise", 'https://github.com/phpstan/phpstan/discussions'); + $tip = sprintf( + "If you think it should be covered by backward compatibility promise, open a discussion:\n %s\n\n See also:\n https://phpstan.org/developing-extensions/backward-compatibility-promise", + 'https://github.com/phpstan/phpstan/discussions', + ); $this->analyse([__DIR__ . '/data/class-extends-out-of-phpstan.php'], [ [ diff --git a/tests/PHPStan/Rules/Api/ApiClassImplementsRuleTest.php b/tests/PHPStan/Rules/Api/ApiClassImplementsRuleTest.php index f9077e12934..9b95f57e258 100644 --- a/tests/PHPStan/Rules/Api/ApiClassImplementsRuleTest.php +++ b/tests/PHPStan/Rules/Api/ApiClassImplementsRuleTest.php @@ -24,7 +24,10 @@ public function testRuleInPhpStan(): void public function testRuleOutOfPhpStan(): void { - $tip = sprintf("If you think it should be covered by backward compatibility promise, open a discussion:\n %s\n\n See also:\n https://phpstan.org/developing-extensions/backward-compatibility-promise", 'https://github.com/phpstan/phpstan/discussions'); + $tip = sprintf( + "If you think it should be covered by backward compatibility promise, open a discussion:\n %s\n\n See also:\n https://phpstan.org/developing-extensions/backward-compatibility-promise", + 'https://github.com/phpstan/phpstan/discussions', + ); $this->analyse([__DIR__ . '/data/class-implements-out-of-phpstan.php'], [ [ diff --git a/tests/PHPStan/Rules/Api/ApiInstanceofRuleTest.php b/tests/PHPStan/Rules/Api/ApiInstanceofRuleTest.php index 9d84bf98e0c..a22b102c63d 100644 --- a/tests/PHPStan/Rules/Api/ApiInstanceofRuleTest.php +++ b/tests/PHPStan/Rules/Api/ApiInstanceofRuleTest.php @@ -24,8 +24,14 @@ public function testRuleInPhpStan(): void public function testRuleOutOfPhpStan(): void { - $tip = sprintf("If you think it should be covered by backward compatibility promise, open a discussion:\n %s\n\n See also:\n https://phpstan.org/developing-extensions/backward-compatibility-promise", 'https://github.com/phpstan/phpstan/discussions'); - $instanceofTip = sprintf("In case of questions how to solve this correctly, open a discussion:\n %s\n\n See also:\n https://phpstan.org/developing-extensions/backward-compatibility-promise", 'https://github.com/phpstan/phpstan/discussions'); + $tip = sprintf( + "If you think it should be covered by backward compatibility promise, open a discussion:\n %s\n\n See also:\n https://phpstan.org/developing-extensions/backward-compatibility-promise", + 'https://github.com/phpstan/phpstan/discussions', + ); + $instanceofTip = sprintf( + "In case of questions how to solve this correctly, open a discussion:\n %s\n\n See also:\n https://phpstan.org/developing-extensions/backward-compatibility-promise", + 'https://github.com/phpstan/phpstan/discussions', + ); $this->analyse([__DIR__ . '/data/instanceof-out-of-phpstan.php'], [ [ diff --git a/tests/PHPStan/Rules/Api/ApiInstantiationRuleTest.php b/tests/PHPStan/Rules/Api/ApiInstantiationRuleTest.php index 30c46459242..0d96c5a6648 100644 --- a/tests/PHPStan/Rules/Api/ApiInstantiationRuleTest.php +++ b/tests/PHPStan/Rules/Api/ApiInstantiationRuleTest.php @@ -14,7 +14,10 @@ class ApiInstantiationRuleTest extends RuleTestCase protected function getRule(): Rule { - return new ApiInstantiationRule(new ApiRuleHelper(), $this->createReflectionProvider()); + return new ApiInstantiationRule( + new ApiRuleHelper(), + $this->createReflectionProvider(), + ); } public function testRuleInPhpStan(): void @@ -24,7 +27,10 @@ public function testRuleInPhpStan(): void public function testRuleOutOfPhpStan(): void { - $tip = sprintf("If you think it should be covered by backward compatibility promise, open a discussion:\n %s\n\n See also:\n https://phpstan.org/developing-extensions/backward-compatibility-promise", 'https://github.com/phpstan/phpstan/discussions'); + $tip = sprintf( + "If you think it should be covered by backward compatibility promise, open a discussion:\n %s\n\n See also:\n https://phpstan.org/developing-extensions/backward-compatibility-promise", + 'https://github.com/phpstan/phpstan/discussions', + ); $this->analyse([__DIR__ . '/data/new-out-of-phpstan.php'], [ [ 'Creating new PHPStan\Type\FileTypeMapper is not covered by backward compatibility promise. The class might change in a minor PHPStan version.', diff --git a/tests/PHPStan/Rules/Api/ApiInterfaceExtendsRuleTest.php b/tests/PHPStan/Rules/Api/ApiInterfaceExtendsRuleTest.php index ab96198c450..770c59da3ae 100644 --- a/tests/PHPStan/Rules/Api/ApiInterfaceExtendsRuleTest.php +++ b/tests/PHPStan/Rules/Api/ApiInterfaceExtendsRuleTest.php @@ -24,7 +24,10 @@ public function testRuleInPhpStan(): void public function testRuleOutOfPhpStan(): void { - $tip = sprintf("If you think it should be covered by backward compatibility promise, open a discussion:\n %s\n\n See also:\n https://phpstan.org/developing-extensions/backward-compatibility-promise", 'https://github.com/phpstan/phpstan/discussions'); + $tip = sprintf( + "If you think it should be covered by backward compatibility promise, open a discussion:\n %s\n\n See also:\n https://phpstan.org/developing-extensions/backward-compatibility-promise", + 'https://github.com/phpstan/phpstan/discussions', + ); $this->analyse([__DIR__ . '/data/interface-extends-out-of-phpstan.php'], [ [ diff --git a/tests/PHPStan/Rules/Api/ApiMethodCallRuleTest.php b/tests/PHPStan/Rules/Api/ApiMethodCallRuleTest.php index 2016689e0dd..d91f1166106 100644 --- a/tests/PHPStan/Rules/Api/ApiMethodCallRuleTest.php +++ b/tests/PHPStan/Rules/Api/ApiMethodCallRuleTest.php @@ -24,7 +24,10 @@ public function testRuleInPhpStan(): void public function testRuleOutOfPhpStan(): void { - $tip = sprintf("If you think it should be covered by backward compatibility promise, open a discussion:\n %s\n\n See also:\n https://phpstan.org/developing-extensions/backward-compatibility-promise", 'https://github.com/phpstan/phpstan/discussions'); + $tip = sprintf( + "If you think it should be covered by backward compatibility promise, open a discussion:\n %s\n\n See also:\n https://phpstan.org/developing-extensions/backward-compatibility-promise", + 'https://github.com/phpstan/phpstan/discussions', + ); $this->analyse([__DIR__ . '/data/method-call-out-of-phpstan.php'], [ [ diff --git a/tests/PHPStan/Rules/Api/ApiRuleHelperTest.php b/tests/PHPStan/Rules/Api/ApiRuleHelperTest.php index d3dd97325b5..93d8428b77f 100644 --- a/tests/PHPStan/Rules/Api/ApiRuleHelperTest.php +++ b/tests/PHPStan/Rules/Api/ApiRuleHelperTest.php @@ -136,7 +136,13 @@ public function dataIsPhpStanCode(): array /** * @dataProvider dataIsPhpStanCode */ - public function testIsPhpStanCode(?string $scopeNamespace, string $scopeFile, string $nameToCheck, ?string $declaringFileNameToCheck, bool $expected) : void + public function testIsPhpStanCode( + ?string $scopeNamespace, + string $scopeFile, + string $nameToCheck, + ?string $declaringFileNameToCheck, + bool $expected, + ): void { $rule = new ApiRuleHelper(); $scope = $this->createMock(Scope::class); diff --git a/tests/PHPStan/Rules/Api/ApiStaticCallRuleTest.php b/tests/PHPStan/Rules/Api/ApiStaticCallRuleTest.php index 905443f2392..8331674e4b6 100644 --- a/tests/PHPStan/Rules/Api/ApiStaticCallRuleTest.php +++ b/tests/PHPStan/Rules/Api/ApiStaticCallRuleTest.php @@ -24,7 +24,10 @@ public function testRuleInPhpStan(): void public function testRuleOutOfPhpStan(): void { - $tip = sprintf("If you think it should be covered by backward compatibility promise, open a discussion:\n %s\n\n See also:\n https://phpstan.org/developing-extensions/backward-compatibility-promise", 'https://github.com/phpstan/phpstan/discussions'); + $tip = sprintf( + "If you think it should be covered by backward compatibility promise, open a discussion:\n %s\n\n See also:\n https://phpstan.org/developing-extensions/backward-compatibility-promise", + 'https://github.com/phpstan/phpstan/discussions', + ); $this->analyse([__DIR__ . '/data/static-call-out-of-phpstan.php'], [ [ diff --git a/tests/PHPStan/Rules/Api/ApiTraitUseRuleTest.php b/tests/PHPStan/Rules/Api/ApiTraitUseRuleTest.php index c9e8dee08ee..da2dbbeefe6 100644 --- a/tests/PHPStan/Rules/Api/ApiTraitUseRuleTest.php +++ b/tests/PHPStan/Rules/Api/ApiTraitUseRuleTest.php @@ -24,7 +24,10 @@ public function testRuleInPhpStan(): void public function testRuleOutOfPhpStan(): void { - $tip = sprintf("If you think it should be covered by backward compatibility promise, open a discussion:\n %s\n\n See also:\n https://phpstan.org/developing-extensions/backward-compatibility-promise", 'https://github.com/phpstan/phpstan/discussions'); + $tip = sprintf( + "If you think it should be covered by backward compatibility promise, open a discussion:\n %s\n\n See also:\n https://phpstan.org/developing-extensions/backward-compatibility-promise", + 'https://github.com/phpstan/phpstan/discussions', + ); $this->analyse([__DIR__ . '/data/trait-use-out-of-phpstan.php'], [ [ diff --git a/tests/PHPStan/Rules/Arrays/AppendedArrayItemTypeRuleTest.php b/tests/PHPStan/Rules/Arrays/AppendedArrayItemTypeRuleTest.php index 92b2fcea9f6..ea09ce0cb4c 100644 --- a/tests/PHPStan/Rules/Arrays/AppendedArrayItemTypeRuleTest.php +++ b/tests/PHPStan/Rules/Arrays/AppendedArrayItemTypeRuleTest.php @@ -15,12 +15,17 @@ class AppendedArrayItemTypeRuleTest extends RuleTestCase protected function getRule(): Rule { - return new AppendedArrayItemTypeRule(new PropertyReflectionFinder(), new RuleLevelHelper($this->createReflectionProvider(), true, false, true, false, false, true, false)); + return new AppendedArrayItemTypeRule( + new PropertyReflectionFinder(), + new RuleLevelHelper($this->createReflectionProvider(), true, false, true, false, false, true, false), + ); } public function testAppendedArrayItemType(): void { - $this->analyse([__DIR__ . '/data/appended-array-item.php'], [ + $this->analyse( + [__DIR__ . '/data/appended-array-item.php'], + [ [ 'Array (array) does not accept string.', 18, @@ -53,7 +58,8 @@ public function testAppendedArrayItemType(): void 'Array (array) does not accept AppendedArrayItem\Baz.', 79, ], - ]); + ], + ); } } diff --git a/tests/PHPStan/Rules/Arrays/AppendedArrayKeyTypeRuleTest.php b/tests/PHPStan/Rules/Arrays/AppendedArrayKeyTypeRuleTest.php index 15c4409b7ed..d74a1ddd8e7 100644 --- a/tests/PHPStan/Rules/Arrays/AppendedArrayKeyTypeRuleTest.php +++ b/tests/PHPStan/Rules/Arrays/AppendedArrayKeyTypeRuleTest.php @@ -14,7 +14,10 @@ class AppendedArrayKeyTypeRuleTest extends RuleTestCase protected function getRule(): Rule { - return new AppendedArrayKeyTypeRule(new PropertyReflectionFinder(), true); + return new AppendedArrayKeyTypeRule( + new PropertyReflectionFinder(), + true, + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Arrays/ArrayDestructuringRuleTest.php b/tests/PHPStan/Rules/Arrays/ArrayDestructuringRuleTest.php index a5b87a7a3ff..ac959693ec9 100644 --- a/tests/PHPStan/Rules/Arrays/ArrayDestructuringRuleTest.php +++ b/tests/PHPStan/Rules/Arrays/ArrayDestructuringRuleTest.php @@ -13,16 +13,16 @@ class ArrayDestructuringRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $bleedingEdge = false; + private bool $bleedingEdge = false; protected function getRule(): Rule { $ruleLevelHelper = new RuleLevelHelper($this->createReflectionProvider(), true, false, true, false, false, true, false); - return new ArrayDestructuringRule($ruleLevelHelper, new NonexistentOffsetInArrayDimFetchCheck($ruleLevelHelper, true, $this->bleedingEdge)); + return new ArrayDestructuringRule( + $ruleLevelHelper, + new NonexistentOffsetInArrayDimFetchCheck($ruleLevelHelper, true, $this->bleedingEdge), + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Arrays/ArrayUnpackingRuleTest.php b/tests/PHPStan/Rules/Arrays/ArrayUnpackingRuleTest.php index e268d88c1d9..b733df51cde 100644 --- a/tests/PHPStan/Rules/Arrays/ArrayUnpackingRuleTest.php +++ b/tests/PHPStan/Rules/Arrays/ArrayUnpackingRuleTest.php @@ -14,19 +14,16 @@ class ArrayUnpackingRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $checkUnions; + private bool $checkUnions; - /** - * @var bool - */ - private $checkBenevolentUnions = false; + private bool $checkBenevolentUnions = false; protected function getRule(): Rule { - return new ArrayUnpackingRule(self::getContainer()->getByType(PhpVersion::class), new RuleLevelHelper($this->createReflectionProvider(), true, false, $this->checkUnions, false, false, true, $this->checkBenevolentUnions)); + return new ArrayUnpackingRule( + self::getContainer()->getByType(PhpVersion::class), + new RuleLevelHelper($this->createReflectionProvider(), true, false, $this->checkUnions, false, false, true, $this->checkBenevolentUnions), + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Arrays/DuplicateKeysInLiteralArraysRuleTest.php b/tests/PHPStan/Rules/Arrays/DuplicateKeysInLiteralArraysRuleTest.php index 174289020d8..e0a4ce3798a 100644 --- a/tests/PHPStan/Rules/Arrays/DuplicateKeysInLiteralArraysRuleTest.php +++ b/tests/PHPStan/Rules/Arrays/DuplicateKeysInLiteralArraysRuleTest.php @@ -16,7 +16,9 @@ class DuplicateKeysInLiteralArraysRuleTest extends RuleTestCase protected function getRule(): Rule { - return new DuplicateKeysInLiteralArraysRule(new ExprPrinter(new Printer())); + return new DuplicateKeysInLiteralArraysRule( + new ExprPrinter(new Printer()), + ); } public function testDuplicateKeys(): void diff --git a/tests/PHPStan/Rules/Arrays/IterableInForeachRuleTest.php b/tests/PHPStan/Rules/Arrays/IterableInForeachRuleTest.php index 940b241dbf9..dbb64b29cab 100644 --- a/tests/PHPStan/Rules/Arrays/IterableInForeachRuleTest.php +++ b/tests/PHPStan/Rules/Arrays/IterableInForeachRuleTest.php @@ -15,15 +15,9 @@ class IterableInForeachRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $checkExplicitMixed = false; + private bool $checkExplicitMixed = false; - /** - * @var bool - */ - private $checkImplicitMixed = false; + private bool $checkImplicitMixed = false; protected function getRule(): Rule { @@ -109,9 +103,7 @@ public function dataMixed(): array ], ]; $combinedErrors = array_merge($explicitOnlyErrors, $implicitOnlyErrors); - usort($combinedErrors, static function (array $a, array $b) : int { - return $a[1] <=> $b[1]; - }); + usort($combinedErrors, static fn (array $a, array $b): int => $a[1] <=> $b[1]); return [ [ diff --git a/tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php b/tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php index c21fc29d986..a0d76f1cbce 100644 --- a/tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php +++ b/tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php @@ -13,26 +13,21 @@ class NonexistentOffsetInArrayDimFetchRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $checkExplicitMixed = false; + private bool $checkExplicitMixed = false; - /** - * @var bool - */ - private $checkImplicitMixed = false; + private bool $checkImplicitMixed = false; - /** - * @var bool - */ - private $bleedingEdge = false; + private bool $bleedingEdge = false; protected function getRule(): Rule { $ruleLevelHelper = new RuleLevelHelper($this->createReflectionProvider(), true, false, true, $this->checkExplicitMixed, $this->checkImplicitMixed, true, false); - return new NonexistentOffsetInArrayDimFetchRule($ruleLevelHelper, new NonexistentOffsetInArrayDimFetchCheck($ruleLevelHelper, true, $this->bleedingEdge), true); + return new NonexistentOffsetInArrayDimFetchRule( + $ruleLevelHelper, + new NonexistentOffsetInArrayDimFetchCheck($ruleLevelHelper, true, $this->bleedingEdge), + true, + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Arrays/OffsetAccessAssignOpRuleTest.php b/tests/PHPStan/Rules/Arrays/OffsetAccessAssignOpRuleTest.php index e70ee5dff23..2daf7b7ed4b 100644 --- a/tests/PHPStan/Rules/Arrays/OffsetAccessAssignOpRuleTest.php +++ b/tests/PHPStan/Rules/Arrays/OffsetAccessAssignOpRuleTest.php @@ -13,10 +13,7 @@ class OffsetAccessAssignOpRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $checkUnions; + private bool $checkUnions; protected function getRule(): Rule { diff --git a/tests/PHPStan/Rules/Arrays/OffsetAccessAssignmentRuleTest.php b/tests/PHPStan/Rules/Arrays/OffsetAccessAssignmentRuleTest.php index acc5785d7ce..ea8b897b570 100644 --- a/tests/PHPStan/Rules/Arrays/OffsetAccessAssignmentRuleTest.php +++ b/tests/PHPStan/Rules/Arrays/OffsetAccessAssignmentRuleTest.php @@ -13,10 +13,7 @@ class OffsetAccessAssignmentRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $checkUnionTypes; + private bool $checkUnionTypes; protected function getRule(): Rule { @@ -27,7 +24,9 @@ protected function getRule(): Rule public function testOffsetAccessAssignmentToScalar(): void { $this->checkUnionTypes = true; - $this->analyse([__DIR__ . '/data/offset-access-assignment-to-scalar.php'], [ + $this->analyse( + [__DIR__ . '/data/offset-access-assignment-to-scalar.php'], + [ [ 'Cannot assign offset \'foo\' to string.', 14, @@ -72,13 +71,16 @@ public function testOffsetAccessAssignmentToScalar(): void 'Cannot assign new offset to OffsetAccessAssignment\ObjectWithOffsetAccess.', 81, ], - ]); + ], + ); } public function testOffsetAccessAssignmentToScalarWithoutMaybes(): void { $this->checkUnionTypes = false; - $this->analyse([__DIR__ . '/data/offset-access-assignment-to-scalar.php'], [ + $this->analyse( + [__DIR__ . '/data/offset-access-assignment-to-scalar.php'], + [ [ 'Cannot assign offset \'foo\' to string.', 14, @@ -111,7 +113,8 @@ public function testOffsetAccessAssignmentToScalarWithoutMaybes(): void 'Cannot assign new offset to OffsetAccessAssignment\ObjectWithOffsetAccess.', 81, ], - ]); + ], + ); } public function testInheritDocTemplateTypeResolution(): void diff --git a/tests/PHPStan/Rules/Arrays/OffsetAccessWithoutDimForReadingRuleTest.php b/tests/PHPStan/Rules/Arrays/OffsetAccessWithoutDimForReadingRuleTest.php index fa4b8878804..db6846cfa01 100644 --- a/tests/PHPStan/Rules/Arrays/OffsetAccessWithoutDimForReadingRuleTest.php +++ b/tests/PHPStan/Rules/Arrays/OffsetAccessWithoutDimForReadingRuleTest.php @@ -18,7 +18,9 @@ protected function getRule(): Rule public function testOffsetAccessWithoutDimForReading(): void { - $this->analyse([__DIR__ . '/data/offset-access-without-dim-for-reading.php'], [ + $this->analyse( + [__DIR__ . '/data/offset-access-without-dim-for-reading.php'], + [ [ 'Cannot use [] for reading.', 7, @@ -83,7 +85,8 @@ public function testOffsetAccessWithoutDimForReading(): void 'Cannot use [] for reading.', 30, ], - ]); + ], + ); } } diff --git a/tests/PHPStan/Rules/Arrays/UnpackIterableInArrayRuleTest.php b/tests/PHPStan/Rules/Arrays/UnpackIterableInArrayRuleTest.php index 9212b862fcb..32d49006861 100644 --- a/tests/PHPStan/Rules/Arrays/UnpackIterableInArrayRuleTest.php +++ b/tests/PHPStan/Rules/Arrays/UnpackIterableInArrayRuleTest.php @@ -15,15 +15,9 @@ class UnpackIterableInArrayRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $checkExplicitMixed = false; + private bool $checkExplicitMixed = false; - /** - * @var bool - */ - private $checkImplicitMixed = false; + private bool $checkImplicitMixed = false; protected function getRule(): Rule { @@ -81,9 +75,7 @@ public function dataMixed(): array ], ]; $combinedErrors = array_merge($explicitOnlyErrors, $implicitOnlyErrors); - usort($combinedErrors, static function (array $a, array $b) : int { - return $a[1] <=> $b[1]; - }); + usort($combinedErrors, static fn (array $a, array $b): int => $a[1] <=> $b[1]); return [ [ diff --git a/tests/PHPStan/Rules/Cast/EchoRuleTest.php b/tests/PHPStan/Rules/Cast/EchoRuleTest.php index 8ba43fa6e5c..c536b8f130f 100644 --- a/tests/PHPStan/Rules/Cast/EchoRuleTest.php +++ b/tests/PHPStan/Rules/Cast/EchoRuleTest.php @@ -15,7 +15,9 @@ class EchoRuleTest extends RuleTestCase protected function getRule(): Rule { - return new EchoRule(new RuleLevelHelper($this->createReflectionProvider(), true, false, true, false, false, true, false)); + return new EchoRule( + new RuleLevelHelper($this->createReflectionProvider(), true, false, true, false, false, true, false), + ); } public function testEchoRule(): void diff --git a/tests/PHPStan/Rules/Cast/InvalidCastRuleTest.php b/tests/PHPStan/Rules/Cast/InvalidCastRuleTest.php index f7a5cf92670..5734b479287 100644 --- a/tests/PHPStan/Rules/Cast/InvalidCastRuleTest.php +++ b/tests/PHPStan/Rules/Cast/InvalidCastRuleTest.php @@ -15,15 +15,9 @@ class InvalidCastRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $checkExplicitMixed = false; + private bool $checkExplicitMixed = false; - /** - * @var bool - */ - private $checkImplicitMixed = false; + private bool $checkImplicitMixed = false; protected function getRule(): Rule { @@ -137,9 +131,7 @@ public function dataMixed(): array ], ]; $combinedErrors = array_merge($explicitOnlyErrors, $implicitOnlyErrors); - usort($combinedErrors, static function (array $a, array $b) : int { - return $a[1] <=> $b[1]; - }); + usort($combinedErrors, static fn (array $a, array $b): int => $a[1] <=> $b[1]); return [ [ diff --git a/tests/PHPStan/Rules/Cast/InvalidPartOfEncapsedStringRuleTest.php b/tests/PHPStan/Rules/Cast/InvalidPartOfEncapsedStringRuleTest.php index 352a4f5f494..3ba7d5ce61c 100644 --- a/tests/PHPStan/Rules/Cast/InvalidPartOfEncapsedStringRuleTest.php +++ b/tests/PHPStan/Rules/Cast/InvalidPartOfEncapsedStringRuleTest.php @@ -17,7 +17,10 @@ class InvalidPartOfEncapsedStringRuleTest extends RuleTestCase protected function getRule(): Rule { - return new InvalidPartOfEncapsedStringRule(new ExprPrinter(new Printer()), new RuleLevelHelper($this->createReflectionProvider(), true, false, true, false, false, true, false)); + return new InvalidPartOfEncapsedStringRule( + new ExprPrinter(new Printer()), + new RuleLevelHelper($this->createReflectionProvider(), true, false, true, false, false, true, false), + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Cast/PrintRuleTest.php b/tests/PHPStan/Rules/Cast/PrintRuleTest.php index ac063eab42d..c7a52e8123b 100644 --- a/tests/PHPStan/Rules/Cast/PrintRuleTest.php +++ b/tests/PHPStan/Rules/Cast/PrintRuleTest.php @@ -15,7 +15,9 @@ class PrintRuleTest extends RuleTestCase protected function getRule(): Rule { - return new PrintRule(new RuleLevelHelper($this->createReflectionProvider(), true, false, true, false, false, true, false)); + return new PrintRule( + new RuleLevelHelper($this->createReflectionProvider(), true, false, true, false, false, true, false), + ); } public function testPrintRule(): void diff --git a/tests/PHPStan/Rules/Cast/UnsetCastRuleTest.php b/tests/PHPStan/Rules/Cast/UnsetCastRuleTest.php index 0a86b4dc4ff..ebab5c0aa66 100644 --- a/tests/PHPStan/Rules/Cast/UnsetCastRuleTest.php +++ b/tests/PHPStan/Rules/Cast/UnsetCastRuleTest.php @@ -12,10 +12,7 @@ class UnsetCastRuleTest extends RuleTestCase { - /** - * @var int - */ - private $phpVersion; + private int $phpVersion; protected function getRule(): Rule { diff --git a/tests/PHPStan/Rules/Classes/ClassAttributesRuleTest.php b/tests/PHPStan/Rules/Classes/ClassAttributesRuleTest.php index ad8fd0863a7..42201f8276d 100644 --- a/tests/PHPStan/Rules/Classes/ClassAttributesRuleTest.php +++ b/tests/PHPStan/Rules/Classes/ClassAttributesRuleTest.php @@ -23,7 +23,25 @@ class ClassAttributesRuleTest extends RuleTestCase protected function getRule(): Rule { $reflectionProvider = $this->createReflectionProvider(); - return new ClassAttributesRule(new AttributesCheck($reflectionProvider, new FunctionCallParametersCheck(new RuleLevelHelper($reflectionProvider, true, false, true, false, false, true, false), new NullsafeCheck(), new PhpVersion(80000), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true, true), new ClassCaseSensitivityCheck($reflectionProvider, false), true)); + return new ClassAttributesRule( + new AttributesCheck( + $reflectionProvider, + new FunctionCallParametersCheck( + new RuleLevelHelper($reflectionProvider, true, false, true, false, false, true, false), + new NullsafeCheck(), + new PhpVersion(80000), + new UnresolvableTypeHelper(), + new PropertyReflectionFinder(), + true, + true, + true, + true, + true, + ), + new ClassCaseSensitivityCheck($reflectionProvider, false), + true, + ), + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Classes/ClassConstantAttributesRuleTest.php b/tests/PHPStan/Rules/Classes/ClassConstantAttributesRuleTest.php index f59e0130295..cd0391d560c 100644 --- a/tests/PHPStan/Rules/Classes/ClassConstantAttributesRuleTest.php +++ b/tests/PHPStan/Rules/Classes/ClassConstantAttributesRuleTest.php @@ -22,7 +22,25 @@ class ClassConstantAttributesRuleTest extends RuleTestCase protected function getRule(): Rule { $reflectionProvider = $this->createReflectionProvider(); - return new ClassConstantAttributesRule(new AttributesCheck($reflectionProvider, new FunctionCallParametersCheck(new RuleLevelHelper($reflectionProvider, true, false, true, false, false, true, false), new NullsafeCheck(), new PhpVersion(80000), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true, true), new ClassCaseSensitivityCheck($reflectionProvider, false), true)); + return new ClassConstantAttributesRule( + new AttributesCheck( + $reflectionProvider, + new FunctionCallParametersCheck( + new RuleLevelHelper($reflectionProvider, true, false, true, false, false, true, false), + new NullsafeCheck(), + new PhpVersion(80000), + new UnresolvableTypeHelper(), + new PropertyReflectionFinder(), + true, + true, + true, + true, + true, + ), + new ClassCaseSensitivityCheck($reflectionProvider, false), + true, + ), + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Classes/ClassConstantRuleTest.php b/tests/PHPStan/Rules/Classes/ClassConstantRuleTest.php index e5aaa096b8d..37bc5cf2292 100644 --- a/tests/PHPStan/Rules/Classes/ClassConstantRuleTest.php +++ b/tests/PHPStan/Rules/Classes/ClassConstantRuleTest.php @@ -15,10 +15,7 @@ class ClassConstantRuleTest extends RuleTestCase { - /** - * @var int - */ - private $phpVersion; + private int $phpVersion; protected function getRule(): Rule { @@ -29,10 +26,12 @@ protected function getRule(): Rule public function testClassConstant(): void { $this->phpVersion = PHP_VERSION_ID; - $this->analyse([ + $this->analyse( + [ __DIR__ . '/data/class-constant.php', __DIR__ . '/data/class-constant-defined.php', - ], [ + ], + [ [ 'Class ClassConstantNamespace\Bar not found.', 6, @@ -83,7 +82,8 @@ public function testClassConstant(): void 'Access to undefined constant ClassConstantNamespace\Foo|string::DOLOR.', 33, ], - ]); + ], + ); } public function testClassConstantVisibility(): void diff --git a/tests/PHPStan/Rules/Classes/DuplicateClassDeclarationRuleTest.php b/tests/PHPStan/Rules/Classes/DuplicateClassDeclarationRuleTest.php index be4385f71ec..e16ccce93ce 100644 --- a/tests/PHPStan/Rules/Classes/DuplicateClassDeclarationRuleTest.php +++ b/tests/PHPStan/Rules/Classes/DuplicateClassDeclarationRuleTest.php @@ -22,7 +22,13 @@ protected function getRule(): Rule { $fileHelper = new FileHelper(__DIR__ . '/data'); - return new DuplicateClassDeclarationRule(new DefaultReflector(new OptimizedSingleFileSourceLocator(self::getContainer()->getByType(FileNodesFetcher::class), self::FILENAME)), new SimpleRelativePathHelper($fileHelper->normalizePath($fileHelper->getWorkingDirectory(), '/'))); + return new DuplicateClassDeclarationRule( + new DefaultReflector(new OptimizedSingleFileSourceLocator( + self::getContainer()->getByType(FileNodesFetcher::class), + self::FILENAME, + )), + new SimpleRelativePathHelper($fileHelper->normalizePath($fileHelper->getWorkingDirectory(), '/')), + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Classes/DuplicateDeclarationRuleTest.php b/tests/PHPStan/Rules/Classes/DuplicateDeclarationRuleTest.php index 59921a54fca..e75c5907565 100644 --- a/tests/PHPStan/Rules/Classes/DuplicateDeclarationRuleTest.php +++ b/tests/PHPStan/Rules/Classes/DuplicateDeclarationRuleTest.php @@ -18,9 +18,11 @@ protected function getRule(): Rule public function testDuplicateDeclarations(): void { - $this->analyse([ + $this->analyse( + [ __DIR__ . '/data/duplicate-declarations.php', - ], [ + ], + [ [ 'Cannot redeclare constant DuplicateDeclarations\Foo::CONST1.', 8, @@ -45,7 +47,8 @@ public function testDuplicateDeclarations(): void 'Cannot redeclare method DuplicateDeclarations\Foo::Func1().', 35, ], - ]); + ], + ); } public function testDuplicatePromotedProperty(): void diff --git a/tests/PHPStan/Rules/Classes/ExistingClassInClassExtendsRuleTest.php b/tests/PHPStan/Rules/Classes/ExistingClassInClassExtendsRuleTest.php index ed3762b73d5..e3ba1adb148 100644 --- a/tests/PHPStan/Rules/Classes/ExistingClassInClassExtendsRuleTest.php +++ b/tests/PHPStan/Rules/Classes/ExistingClassInClassExtendsRuleTest.php @@ -16,7 +16,10 @@ class ExistingClassInClassExtendsRuleTest extends RuleTestCase protected function getRule(): Rule { $broker = $this->createReflectionProvider(); - return new ExistingClassInClassExtendsRule(new ClassCaseSensitivityCheck($broker, true), $broker); + return new ExistingClassInClassExtendsRule( + new ClassCaseSensitivityCheck($broker, true), + $broker, + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Classes/ExistingClassInInstanceOfRuleTest.php b/tests/PHPStan/Rules/Classes/ExistingClassInInstanceOfRuleTest.php index 571851110de..0a0ced56201 100644 --- a/tests/PHPStan/Rules/Classes/ExistingClassInInstanceOfRuleTest.php +++ b/tests/PHPStan/Rules/Classes/ExistingClassInInstanceOfRuleTest.php @@ -15,15 +15,21 @@ class ExistingClassInInstanceOfRuleTest extends RuleTestCase protected function getRule(): Rule { $broker = $this->createReflectionProvider(); - return new ExistingClassInInstanceOfRule($broker, new ClassCaseSensitivityCheck($broker, true), true); + return new ExistingClassInInstanceOfRule( + $broker, + new ClassCaseSensitivityCheck($broker, true), + true, + ); } public function testClassDoesNotExist(): void { - $this->analyse([ + $this->analyse( + [ __DIR__ . '/data/instanceof.php', __DIR__ . '/data/instanceof-defined.php', - ], [ + ], + [ [ 'Class InstanceOfNamespaceRule\Bar not found.', 7, @@ -45,7 +51,8 @@ public function testClassDoesNotExist(): void 'Using self outside of class scope.', 17, ], - ]); + ], + ); } public function testClassExists(): void diff --git a/tests/PHPStan/Rules/Classes/ExistingClassInTraitUseRuleTest.php b/tests/PHPStan/Rules/Classes/ExistingClassInTraitUseRuleTest.php index 045c46c0c28..0e78d7b9fca 100644 --- a/tests/PHPStan/Rules/Classes/ExistingClassInTraitUseRuleTest.php +++ b/tests/PHPStan/Rules/Classes/ExistingClassInTraitUseRuleTest.php @@ -16,7 +16,10 @@ class ExistingClassInTraitUseRuleTest extends RuleTestCase protected function getRule(): Rule { $broker = $this->createReflectionProvider(); - return new ExistingClassInTraitUseRule(new ClassCaseSensitivityCheck($broker, true), $broker); + return new ExistingClassInTraitUseRule( + new ClassCaseSensitivityCheck($broker, true), + $broker, + ); } public function testClassWithWrongCase(): void diff --git a/tests/PHPStan/Rules/Classes/ExistingClassesInClassImplementsRuleTest.php b/tests/PHPStan/Rules/Classes/ExistingClassesInClassImplementsRuleTest.php index 448be71f0c3..0c09626ef88 100644 --- a/tests/PHPStan/Rules/Classes/ExistingClassesInClassImplementsRuleTest.php +++ b/tests/PHPStan/Rules/Classes/ExistingClassesInClassImplementsRuleTest.php @@ -16,7 +16,10 @@ class ExistingClassesInClassImplementsRuleTest extends RuleTestCase protected function getRule(): Rule { $broker = $this->createReflectionProvider(); - return new ExistingClassesInClassImplementsRule(new ClassCaseSensitivityCheck($broker, true), $broker); + return new ExistingClassesInClassImplementsRule( + new ClassCaseSensitivityCheck($broker, true), + $broker, + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Classes/ExistingClassesInEnumImplementsRuleTest.php b/tests/PHPStan/Rules/Classes/ExistingClassesInEnumImplementsRuleTest.php index d72741c7516..c6cdcc20ad1 100644 --- a/tests/PHPStan/Rules/Classes/ExistingClassesInEnumImplementsRuleTest.php +++ b/tests/PHPStan/Rules/Classes/ExistingClassesInEnumImplementsRuleTest.php @@ -17,7 +17,10 @@ protected function getRule(): Rule { $reflectionProvider = $this->createReflectionProvider(); - return new ExistingClassesInEnumImplementsRule(new ClassCaseSensitivityCheck($reflectionProvider, true), $reflectionProvider); + return new ExistingClassesInEnumImplementsRule( + new ClassCaseSensitivityCheck($reflectionProvider, true), + $reflectionProvider, + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Classes/ExistingClassesInInterfaceExtendsRuleTest.php b/tests/PHPStan/Rules/Classes/ExistingClassesInInterfaceExtendsRuleTest.php index 9be73090ccb..4a3a30cf208 100644 --- a/tests/PHPStan/Rules/Classes/ExistingClassesInInterfaceExtendsRuleTest.php +++ b/tests/PHPStan/Rules/Classes/ExistingClassesInInterfaceExtendsRuleTest.php @@ -16,7 +16,10 @@ class ExistingClassesInInterfaceExtendsRuleTest extends RuleTestCase protected function getRule(): Rule { $broker = $this->createReflectionProvider(); - return new ExistingClassesInInterfaceExtendsRule(new ClassCaseSensitivityCheck($broker, true), $broker); + return new ExistingClassesInInterfaceExtendsRule( + new ClassCaseSensitivityCheck($broker, true), + $broker, + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Classes/ImpossibleInstanceOfRuleTest.php b/tests/PHPStan/Rules/Classes/ImpossibleInstanceOfRuleTest.php index 0e4abdf2db9..271ab2dd83e 100644 --- a/tests/PHPStan/Rules/Classes/ImpossibleInstanceOfRuleTest.php +++ b/tests/PHPStan/Rules/Classes/ImpossibleInstanceOfRuleTest.php @@ -12,20 +12,11 @@ class ImpossibleInstanceOfRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $checkAlwaysTrueInstanceOf; + private bool $checkAlwaysTrueInstanceOf; - /** - * @var bool - */ - private $treatPhpDocTypesAsCertain; + private bool $treatPhpDocTypesAsCertain; - /** - * @var bool - */ - private $reportAlwaysTrueInLastCondition = false; + private bool $reportAlwaysTrueInLastCondition = false; protected function getRule(): Rule { @@ -42,7 +33,9 @@ public function testInstanceof(): void $this->checkAlwaysTrueInstanceOf = true; $this->treatPhpDocTypesAsCertain = true; $tipText = 'Because the type is coming from a PHPDoc, you can turn off this check by setting treatPhpDocTypesAsCertain: false in your %configurationFile%.'; - $this->analyse([__DIR__ . '/data/impossible-instanceof.php'], [ + $this->analyse( + [__DIR__ . '/data/impossible-instanceof.php'], + [ [ 'Instanceof between ImpossibleInstanceOf\Lorem and ImpossibleInstanceOf\Lorem will always evaluate to true.', 59, @@ -194,7 +187,8 @@ public function testInstanceof(): void 433, $tipText, ], - ]); + ], + ); } public function testInstanceofWithoutAlwaysTrue(): void @@ -203,7 +197,9 @@ public function testInstanceofWithoutAlwaysTrue(): void $this->treatPhpDocTypesAsCertain = true; $tipText = 'Because the type is coming from a PHPDoc, you can turn off this check by setting treatPhpDocTypesAsCertain: false in your %configurationFile%.'; - $this->analyse([__DIR__ . '/data/impossible-instanceof.php'], [ + $this->analyse( + [__DIR__ . '/data/impossible-instanceof.php'], + [ [ 'Instanceof between ImpossibleInstanceOf\Dolor and ImpossibleInstanceOf\Lorem will always evaluate to false.', 71, @@ -289,7 +285,8 @@ public function testInstanceofWithoutAlwaysTrue(): void 432, $tipText, ], - ]); + ], + ); } public function testDoNotReportTypesFromPhpDocs(): void diff --git a/tests/PHPStan/Rules/Classes/InstantiationRuleTest.php b/tests/PHPStan/Rules/Classes/InstantiationRuleTest.php index a3107c0e3d3..5f9b6c7cb30 100644 --- a/tests/PHPStan/Rules/Classes/InstantiationRuleTest.php +++ b/tests/PHPStan/Rules/Classes/InstantiationRuleTest.php @@ -22,12 +22,18 @@ class InstantiationRuleTest extends RuleTestCase protected function getRule(): Rule { $broker = $this->createReflectionProvider(); - return new InstantiationRule($broker, new FunctionCallParametersCheck(new RuleLevelHelper($broker, true, false, true, false, false, true, false), new NullsafeCheck(), new PhpVersion(80000), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true, true), new ClassCaseSensitivityCheck($broker, true)); + return new InstantiationRule( + $broker, + new FunctionCallParametersCheck(new RuleLevelHelper($broker, true, false, true, false, false, true, false), new NullsafeCheck(), new PhpVersion(80000), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true, true), + new ClassCaseSensitivityCheck($broker, true), + ); } public function testInstantiation(): void { - $this->analyse([__DIR__ . '/data/instantiation.php'], [ + $this->analyse( + [__DIR__ . '/data/instantiation.php'], + [ [ 'Class TestInstantiation\InstantiatingClass constructor invoked with 0 parameters, 1 required.', 15, @@ -185,17 +191,21 @@ public function testInstantiation(): void 'Class TestInstantiation\ClassExtendingAbstractConstructor constructor invoked with 0 parameters, 1 required.', 273, ], - ]); + ], + ); } public function testSoap(): void { - $this->analyse([__DIR__ . '/data/instantiation-soap.php'], [ + $this->analyse( + [__DIR__ . '/data/instantiation-soap.php'], + [ [ 'Parameter #2 $string of class SoapFault constructor expects string, int given.', 6, ], - ]); + ], + ); } public function testClassExists(): void diff --git a/tests/PHPStan/Rules/Classes/InvalidPromotedPropertiesRuleTest.php b/tests/PHPStan/Rules/Classes/InvalidPromotedPropertiesRuleTest.php index 058521a96c0..de80ea8f955 100644 --- a/tests/PHPStan/Rules/Classes/InvalidPromotedPropertiesRuleTest.php +++ b/tests/PHPStan/Rules/Classes/InvalidPromotedPropertiesRuleTest.php @@ -13,10 +13,7 @@ class InvalidPromotedPropertiesRuleTest extends RuleTestCase { - /** - * @var int - */ - private $phpVersion; + private int $phpVersion; protected function getRule(): Rule { diff --git a/tests/PHPStan/Rules/Classes/LocalTypeAliasesRuleTest.php b/tests/PHPStan/Rules/Classes/LocalTypeAliasesRuleTest.php index d914b270e7f..e55f4293172 100644 --- a/tests/PHPStan/Rules/Classes/LocalTypeAliasesRuleTest.php +++ b/tests/PHPStan/Rules/Classes/LocalTypeAliasesRuleTest.php @@ -15,7 +15,13 @@ class LocalTypeAliasesRuleTest extends RuleTestCase protected function getRule(): Rule { - return new LocalTypeAliasesRule(new LocalTypeAliasesCheck(['GlobalTypeAlias' => 'int|string'], $this->createReflectionProvider(), self::getContainer()->getByType(TypeNodeResolver::class))); + return new LocalTypeAliasesRule( + new LocalTypeAliasesCheck( + ['GlobalTypeAlias' => 'int|string'], + $this->createReflectionProvider(), + self::getContainer()->getByType(TypeNodeResolver::class), + ), + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Classes/LocalTypeTraitAliasesRuleTest.php b/tests/PHPStan/Rules/Classes/LocalTypeTraitAliasesRuleTest.php index 9072bc9e05a..49d73e9c5c8 100644 --- a/tests/PHPStan/Rules/Classes/LocalTypeTraitAliasesRuleTest.php +++ b/tests/PHPStan/Rules/Classes/LocalTypeTraitAliasesRuleTest.php @@ -14,7 +14,14 @@ class LocalTypeTraitAliasesRuleTest extends RuleTestCase protected function getRule(): Rule { - return new LocalTypeTraitAliasesRule(new LocalTypeAliasesCheck(['GlobalTypeAlias' => 'int|string'], $this->createReflectionProvider(), self::getContainer()->getByType(TypeNodeResolver::class)), $this->createReflectionProvider()); + return new LocalTypeTraitAliasesRule( + new LocalTypeAliasesCheck( + ['GlobalTypeAlias' => 'int|string'], + $this->createReflectionProvider(), + self::getContainer()->getByType(TypeNodeResolver::class), + ), + $this->createReflectionProvider(), + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Classes/MixinRuleTest.php b/tests/PHPStan/Rules/Classes/MixinRuleTest.php index 9f161e2e80f..0a2c9a4922d 100644 --- a/tests/PHPStan/Rules/Classes/MixinRuleTest.php +++ b/tests/PHPStan/Rules/Classes/MixinRuleTest.php @@ -20,7 +20,14 @@ protected function getRule(): Rule { $reflectionProvider = $this->createReflectionProvider(); - return new MixinRule($reflectionProvider, new ClassCaseSensitivityCheck($reflectionProvider, true), new GenericObjectTypeCheck(), new MissingTypehintCheck(true, true, true, true, []), new UnresolvableTypeHelper(), true); + return new MixinRule( + $reflectionProvider, + new ClassCaseSensitivityCheck($reflectionProvider, true), + new GenericObjectTypeCheck(), + new MissingTypehintCheck(true, true, true, true, []), + new UnresolvableTypeHelper(), + true, + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Classes/UnusedConstructorParametersRuleTest.php b/tests/PHPStan/Rules/Classes/UnusedConstructorParametersRuleTest.php index 6451f00e4be..7aa4f4e62fb 100644 --- a/tests/PHPStan/Rules/Classes/UnusedConstructorParametersRuleTest.php +++ b/tests/PHPStan/Rules/Classes/UnusedConstructorParametersRuleTest.php @@ -14,7 +14,9 @@ class UnusedConstructorParametersRuleTest extends RuleTestCase protected function getRule(): Rule { - return new UnusedConstructorParametersRule(new UnusedFunctionParametersCheck($this->createReflectionProvider())); + return new UnusedConstructorParametersRule(new UnusedFunctionParametersCheck( + $this->createReflectionProvider(), + )); } public function testUnusedConstructorParameters(): void diff --git a/tests/PHPStan/Rules/Comparison/BooleanAndConstantConditionRuleTest.php b/tests/PHPStan/Rules/Comparison/BooleanAndConstantConditionRuleTest.php index b799e9e6f95..6ebe5bc5441 100644 --- a/tests/PHPStan/Rules/Comparison/BooleanAndConstantConditionRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/BooleanAndConstantConditionRuleTest.php @@ -11,24 +11,30 @@ class BooleanAndConstantConditionRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $treatPhpDocTypesAsCertain; + private bool $treatPhpDocTypesAsCertain; - /** - * @var bool - */ - private $bleedingEdge = false; + private bool $bleedingEdge = false; - /** - * @var bool - */ - private $reportAlwaysTrueInLastCondition = false; + private bool $reportAlwaysTrueInLastCondition = false; protected function getRule(): Rule { - return new BooleanAndConstantConditionRule(new ConstantConditionRuleHelper(new ImpossibleCheckTypeHelper($this->createReflectionProvider(), $this->getTypeSpecifier(), [], $this->treatPhpDocTypesAsCertain, true), $this->treatPhpDocTypesAsCertain, true), $this->treatPhpDocTypesAsCertain, $this->bleedingEdge, $this->reportAlwaysTrueInLastCondition); + return new BooleanAndConstantConditionRule( + new ConstantConditionRuleHelper( + new ImpossibleCheckTypeHelper( + $this->createReflectionProvider(), + $this->getTypeSpecifier(), + [], + $this->treatPhpDocTypesAsCertain, + true, + ), + $this->treatPhpDocTypesAsCertain, + true, + ), + $this->treatPhpDocTypesAsCertain, + $this->bleedingEdge, + $this->reportAlwaysTrueInLastCondition, + ); } protected function shouldTreatPhpDocTypesAsCertain(): bool diff --git a/tests/PHPStan/Rules/Comparison/BooleanNotConstantConditionRuleTest.php b/tests/PHPStan/Rules/Comparison/BooleanNotConstantConditionRuleTest.php index 043b636d1d4..43ecf911a65 100644 --- a/tests/PHPStan/Rules/Comparison/BooleanNotConstantConditionRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/BooleanNotConstantConditionRuleTest.php @@ -12,19 +12,27 @@ class BooleanNotConstantConditionRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $treatPhpDocTypesAsCertain; + private bool $treatPhpDocTypesAsCertain; - /** - * @var bool - */ - private $reportAlwaysTrueInLastCondition = false; + private bool $reportAlwaysTrueInLastCondition = false; protected function getRule(): Rule { - return new BooleanNotConstantConditionRule(new ConstantConditionRuleHelper(new ImpossibleCheckTypeHelper($this->createReflectionProvider(), $this->getTypeSpecifier(), [], $this->treatPhpDocTypesAsCertain, true), $this->treatPhpDocTypesAsCertain, true), $this->treatPhpDocTypesAsCertain, $this->reportAlwaysTrueInLastCondition); + return new BooleanNotConstantConditionRule( + new ConstantConditionRuleHelper( + new ImpossibleCheckTypeHelper( + $this->createReflectionProvider(), + $this->getTypeSpecifier(), + [], + $this->treatPhpDocTypesAsCertain, + true, + ), + $this->treatPhpDocTypesAsCertain, + true, + ), + $this->treatPhpDocTypesAsCertain, + $this->reportAlwaysTrueInLastCondition, + ); } protected function shouldTreatPhpDocTypesAsCertain(): bool diff --git a/tests/PHPStan/Rules/Comparison/BooleanOrConstantConditionRuleTest.php b/tests/PHPStan/Rules/Comparison/BooleanOrConstantConditionRuleTest.php index 17ee5bb713b..b8b0777ca27 100644 --- a/tests/PHPStan/Rules/Comparison/BooleanOrConstantConditionRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/BooleanOrConstantConditionRuleTest.php @@ -12,24 +12,30 @@ class BooleanOrConstantConditionRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $treatPhpDocTypesAsCertain; + private bool $treatPhpDocTypesAsCertain; - /** - * @var bool - */ - private $bleedingEdge = false; + private bool $bleedingEdge = false; - /** - * @var bool - */ - private $reportAlwaysTrueInLastCondition = false; + private bool $reportAlwaysTrueInLastCondition = false; protected function getRule(): Rule { - return new BooleanOrConstantConditionRule(new ConstantConditionRuleHelper(new ImpossibleCheckTypeHelper($this->createReflectionProvider(), $this->getTypeSpecifier(), [], $this->treatPhpDocTypesAsCertain, true), $this->treatPhpDocTypesAsCertain, true), $this->treatPhpDocTypesAsCertain, $this->bleedingEdge, $this->reportAlwaysTrueInLastCondition); + return new BooleanOrConstantConditionRule( + new ConstantConditionRuleHelper( + new ImpossibleCheckTypeHelper( + $this->createReflectionProvider(), + $this->getTypeSpecifier(), + [], + $this->treatPhpDocTypesAsCertain, + true, + ), + $this->treatPhpDocTypesAsCertain, + true, + ), + $this->treatPhpDocTypesAsCertain, + $this->bleedingEdge, + $this->reportAlwaysTrueInLastCondition, + ); } protected function shouldTreatPhpDocTypesAsCertain(): bool diff --git a/tests/PHPStan/Rules/Comparison/ConstantLooseComparisonRuleTest.php b/tests/PHPStan/Rules/Comparison/ConstantLooseComparisonRuleTest.php index a4f0c766048..f8a0b7d87d7 100644 --- a/tests/PHPStan/Rules/Comparison/ConstantLooseComparisonRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/ConstantLooseComparisonRuleTest.php @@ -12,20 +12,11 @@ class ConstantLooseComparisonRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $checkAlwaysTrueStrictComparison; + private bool $checkAlwaysTrueStrictComparison; - /** - * @var bool - */ - private $treatPhpDocTypesAsCertain = true; + private bool $treatPhpDocTypesAsCertain = true; - /** - * @var bool - */ - private $reportAlwaysTrueInLastCondition = false; + private bool $reportAlwaysTrueInLastCondition = false; protected function getRule(): Rule { diff --git a/tests/PHPStan/Rules/Comparison/DoWhileLoopConstantConditionRuleTest.php b/tests/PHPStan/Rules/Comparison/DoWhileLoopConstantConditionRuleTest.php index 2c08c0f2f6e..703c2e5a870 100644 --- a/tests/PHPStan/Rules/Comparison/DoWhileLoopConstantConditionRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/DoWhileLoopConstantConditionRuleTest.php @@ -11,14 +11,24 @@ class DoWhileLoopConstantConditionRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $treatPhpDocTypesAsCertain = true; + private bool $treatPhpDocTypesAsCertain = true; protected function getRule(): Rule { - return new DoWhileLoopConstantConditionRule(new ConstantConditionRuleHelper(new ImpossibleCheckTypeHelper($this->createReflectionProvider(), $this->getTypeSpecifier(), [], $this->treatPhpDocTypesAsCertain, true), $this->treatPhpDocTypesAsCertain, true), $this->treatPhpDocTypesAsCertain); + return new DoWhileLoopConstantConditionRule( + new ConstantConditionRuleHelper( + new ImpossibleCheckTypeHelper( + $this->createReflectionProvider(), + $this->getTypeSpecifier(), + [], + $this->treatPhpDocTypesAsCertain, + true, + ), + $this->treatPhpDocTypesAsCertain, + true, + ), + $this->treatPhpDocTypesAsCertain, + ); } protected function shouldTreatPhpDocTypesAsCertain(): bool diff --git a/tests/PHPStan/Rules/Comparison/ElseIfConstantConditionRuleTest.php b/tests/PHPStan/Rules/Comparison/ElseIfConstantConditionRuleTest.php index 5408481b263..7d3b008d908 100644 --- a/tests/PHPStan/Rules/Comparison/ElseIfConstantConditionRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/ElseIfConstantConditionRuleTest.php @@ -11,19 +11,27 @@ class ElseIfConstantConditionRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $treatPhpDocTypesAsCertain; + private bool $treatPhpDocTypesAsCertain; - /** - * @var bool - */ - private $reportAlwaysTrueInLastCondition = false; + private bool $reportAlwaysTrueInLastCondition = false; protected function getRule(): Rule { - return new ElseIfConstantConditionRule(new ConstantConditionRuleHelper(new ImpossibleCheckTypeHelper($this->createReflectionProvider(), $this->getTypeSpecifier(), [], $this->treatPhpDocTypesAsCertain, true), $this->treatPhpDocTypesAsCertain, true), $this->treatPhpDocTypesAsCertain, $this->reportAlwaysTrueInLastCondition); + return new ElseIfConstantConditionRule( + new ConstantConditionRuleHelper( + new ImpossibleCheckTypeHelper( + $this->createReflectionProvider(), + $this->getTypeSpecifier(), + [], + $this->treatPhpDocTypesAsCertain, + true, + ), + $this->treatPhpDocTypesAsCertain, + true, + ), + $this->treatPhpDocTypesAsCertain, + $this->reportAlwaysTrueInLastCondition, + ); } protected function shouldTreatPhpDocTypesAsCertain(): bool diff --git a/tests/PHPStan/Rules/Comparison/IfConstantConditionRuleTest.php b/tests/PHPStan/Rules/Comparison/IfConstantConditionRuleTest.php index 97933f7645b..979af0dc121 100644 --- a/tests/PHPStan/Rules/Comparison/IfConstantConditionRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/IfConstantConditionRuleTest.php @@ -12,14 +12,24 @@ class IfConstantConditionRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $treatPhpDocTypesAsCertain; + private bool $treatPhpDocTypesAsCertain; protected function getRule(): Rule { - return new IfConstantConditionRule(new ConstantConditionRuleHelper(new ImpossibleCheckTypeHelper($this->createReflectionProvider(), $this->getTypeSpecifier(), [], $this->treatPhpDocTypesAsCertain, true), $this->treatPhpDocTypesAsCertain, true), $this->treatPhpDocTypesAsCertain); + return new IfConstantConditionRule( + new ConstantConditionRuleHelper( + new ImpossibleCheckTypeHelper( + $this->createReflectionProvider(), + $this->getTypeSpecifier(), + [], + $this->treatPhpDocTypesAsCertain, + true, + ), + $this->treatPhpDocTypesAsCertain, + true, + ), + $this->treatPhpDocTypesAsCertain, + ); } protected function shouldTreatPhpDocTypesAsCertain(): bool diff --git a/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php b/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php index fbeeec7a651..361aa84bbb2 100644 --- a/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php @@ -17,24 +17,26 @@ class ImpossibleCheckTypeFunctionCallRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $checkAlwaysTrueCheckTypeFunctionCall; + private bool $checkAlwaysTrueCheckTypeFunctionCall; - /** - * @var bool - */ - private $treatPhpDocTypesAsCertain; + private bool $treatPhpDocTypesAsCertain; - /** - * @var bool - */ - private $reportAlwaysTrueInLastCondition = false; + private bool $reportAlwaysTrueInLastCondition = false; protected function getRule(): Rule { - return new ImpossibleCheckTypeFunctionCallRule(new ImpossibleCheckTypeHelper($this->createReflectionProvider(), $this->getTypeSpecifier(), [stdClass::class], $this->treatPhpDocTypesAsCertain, true), $this->checkAlwaysTrueCheckTypeFunctionCall, $this->treatPhpDocTypesAsCertain, $this->reportAlwaysTrueInLastCondition); + return new ImpossibleCheckTypeFunctionCallRule( + new ImpossibleCheckTypeHelper( + $this->createReflectionProvider(), + $this->getTypeSpecifier(), + [stdClass::class], + $this->treatPhpDocTypesAsCertain, + true, + ), + $this->checkAlwaysTrueCheckTypeFunctionCall, + $this->treatPhpDocTypesAsCertain, + $this->reportAlwaysTrueInLastCondition, + ); } protected function shouldTreatPhpDocTypesAsCertain(): bool @@ -46,7 +48,9 @@ public function testImpossibleCheckTypeFunctionCall(): void { $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = true; - $this->analyse([__DIR__ . '/data/check-type-function-call.php'], [ + $this->analyse( + [__DIR__ . '/data/check-type-function-call.php'], + [ [ 'Call to function is_int() with int will always evaluate to true.', 25, @@ -257,7 +261,8 @@ public function testImpossibleCheckTypeFunctionCall(): void 927, 'Because the type is coming from a PHPDoc, you can turn off this check by setting treatPhpDocTypesAsCertain: false in your %configurationFile%.', ], - ]); + ], + ); } public function testBug7898(): void @@ -271,7 +276,9 @@ public function testImpossibleCheckTypeFunctionCallWithoutAlwaysTrue(): void { $this->checkAlwaysTrueCheckTypeFunctionCall = false; $this->treatPhpDocTypesAsCertain = true; - $this->analyse([__DIR__ . '/data/check-type-function-call.php'], [ + $this->analyse( + [__DIR__ . '/data/check-type-function-call.php'], + [ [ 'Call to function is_int() with string will always evaluate to false.', 31, @@ -364,7 +371,8 @@ public function testImpossibleCheckTypeFunctionCallWithoutAlwaysTrue(): void 927, 'Because the type is coming from a PHPDoc, you can turn off this check by setting treatPhpDocTypesAsCertain: false in your %configurationFile%.', ], - ]); + ], + ); } public function testDoNotReportTypesFromPhpDocs(): void @@ -1002,13 +1010,16 @@ public function testLooseComparisonAgainstEnums(): void $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = true; - $issues = array_map(static function (array $i): array { + $issues = array_map( + static function (array $i): array { if (($i[2] ?? null) === 'BUG') { unset($i[2]); } return $i; - }, self::getLooseComparisonAgainsEnumsIssues()); + }, + self::getLooseComparisonAgainsEnumsIssues(), + ); $this->analyse([__DIR__ . '/data/loose-comparison-against-enums.php'], $issues); } @@ -1021,9 +1032,7 @@ public function testLooseComparisonAgainstEnumsNoPhpdoc(): void $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = false; $issues = self::getLooseComparisonAgainsEnumsIssues(); - $issues = array_values(array_filter($issues, static function (array $i) { - return count($i) === 2; - })); + $issues = array_values(array_filter($issues, static fn (array $i) => count($i) === 2)); $this->analyse([__DIR__ . '/data/loose-comparison-against-enums.php'], $issues); } diff --git a/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeGenericOverwriteRuleTest.php b/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeGenericOverwriteRuleTest.php index d26d7e3e0a9..9be90b80542 100644 --- a/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeGenericOverwriteRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeGenericOverwriteRuleTest.php @@ -13,7 +13,18 @@ class ImpossibleCheckTypeGenericOverwriteRuleTest extends RuleTestCase public function getRule(): Rule { - return new ImpossibleCheckTypeMethodCallRule(new ImpossibleCheckTypeHelper($this->createReflectionProvider(), $this->getTypeSpecifier(), [], true, true), true, true, false); + return new ImpossibleCheckTypeMethodCallRule( + new ImpossibleCheckTypeHelper( + $this->createReflectionProvider(), + $this->getTypeSpecifier(), + [], + true, + true, + ), + true, + true, + false, + ); } public function testNoReportedErrorOnOverwrite(): void diff --git a/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeMethodCallRuleEqualsTest.php b/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeMethodCallRuleEqualsTest.php index cd0116146b7..3aa4bf08108 100644 --- a/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeMethodCallRuleEqualsTest.php +++ b/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeMethodCallRuleEqualsTest.php @@ -13,7 +13,18 @@ class ImpossibleCheckTypeMethodCallRuleEqualsTest extends RuleTestCase public function getRule(): Rule { - return new ImpossibleCheckTypeMethodCallRule(new ImpossibleCheckTypeHelper($this->createReflectionProvider(), $this->getTypeSpecifier(), [], true, true), true, true, false); + return new ImpossibleCheckTypeMethodCallRule( + new ImpossibleCheckTypeHelper( + $this->createReflectionProvider(), + $this->getTypeSpecifier(), + [], + true, + true, + ), + true, + true, + false, + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeMethodCallRuleTest.php b/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeMethodCallRuleTest.php index 291b517e8eb..7a697e6ffa1 100644 --- a/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeMethodCallRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeMethodCallRuleTest.php @@ -11,19 +11,24 @@ class ImpossibleCheckTypeMethodCallRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $treatPhpDocTypesAsCertain; + private bool $treatPhpDocTypesAsCertain; - /** - * @var bool - */ - private $reportAlwaysTrueInLastCondition = false; + private bool $reportAlwaysTrueInLastCondition = false; public function getRule(): Rule { - return new ImpossibleCheckTypeMethodCallRule(new ImpossibleCheckTypeHelper($this->createReflectionProvider(), $this->getTypeSpecifier(), [], $this->treatPhpDocTypesAsCertain, true), true, $this->treatPhpDocTypesAsCertain, $this->reportAlwaysTrueInLastCondition); + return new ImpossibleCheckTypeMethodCallRule( + new ImpossibleCheckTypeHelper( + $this->createReflectionProvider(), + $this->getTypeSpecifier(), + [], + $this->treatPhpDocTypesAsCertain, + true, + ), + true, + $this->treatPhpDocTypesAsCertain, + $this->reportAlwaysTrueInLastCondition, + ); } protected function shouldTreatPhpDocTypesAsCertain(): bool diff --git a/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeStaticMethodCallRuleTest.php b/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeStaticMethodCallRuleTest.php index ed8b627c527..a93147ab835 100644 --- a/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeStaticMethodCallRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeStaticMethodCallRuleTest.php @@ -11,19 +11,24 @@ class ImpossibleCheckTypeStaticMethodCallRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $treatPhpDocTypesAsCertain; + private bool $treatPhpDocTypesAsCertain; - /** - * @var bool - */ - private $reportAlwaysTrueInLastCondition = false; + private bool $reportAlwaysTrueInLastCondition = false; public function getRule(): Rule { - return new ImpossibleCheckTypeStaticMethodCallRule(new ImpossibleCheckTypeHelper($this->createReflectionProvider(), $this->getTypeSpecifier(), [], $this->treatPhpDocTypesAsCertain, true), true, $this->treatPhpDocTypesAsCertain, $this->reportAlwaysTrueInLastCondition); + return new ImpossibleCheckTypeStaticMethodCallRule( + new ImpossibleCheckTypeHelper( + $this->createReflectionProvider(), + $this->getTypeSpecifier(), + [], + $this->treatPhpDocTypesAsCertain, + true, + ), + true, + $this->treatPhpDocTypesAsCertain, + $this->reportAlwaysTrueInLastCondition, + ); } protected function shouldTreatPhpDocTypesAsCertain(): bool diff --git a/tests/PHPStan/Rules/Comparison/LogicalXorConstantConditionRuleTest.php b/tests/PHPStan/Rules/Comparison/LogicalXorConstantConditionRuleTest.php index a8024902c98..24080f2e008 100644 --- a/tests/PHPStan/Rules/Comparison/LogicalXorConstantConditionRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/LogicalXorConstantConditionRuleTest.php @@ -11,19 +11,27 @@ class LogicalXorConstantConditionRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $treatPhpDocTypesAsCertain; + private bool $treatPhpDocTypesAsCertain; - /** - * @var bool - */ - private $reportAlwaysTrueInLastCondition = false; + private bool $reportAlwaysTrueInLastCondition = false; protected function getRule(): TRule { - return new LogicalXorConstantConditionRule(new ConstantConditionRuleHelper(new ImpossibleCheckTypeHelper($this->createReflectionProvider(), $this->getTypeSpecifier(), [], $this->treatPhpDocTypesAsCertain, true), $this->treatPhpDocTypesAsCertain, true), $this->treatPhpDocTypesAsCertain, $this->reportAlwaysTrueInLastCondition); + return new LogicalXorConstantConditionRule( + new ConstantConditionRuleHelper( + new ImpossibleCheckTypeHelper( + $this->createReflectionProvider(), + $this->getTypeSpecifier(), + [], + $this->treatPhpDocTypesAsCertain, + true, + ), + $this->treatPhpDocTypesAsCertain, + true, + ), + $this->treatPhpDocTypesAsCertain, + $this->reportAlwaysTrueInLastCondition, + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Comparison/MatchExpressionDoNotRememberPossiblyImpureValuesRuleTest.php b/tests/PHPStan/Rules/Comparison/MatchExpressionDoNotRememberPossiblyImpureValuesRuleTest.php index ef34888928f..b52785c6f59 100644 --- a/tests/PHPStan/Rules/Comparison/MatchExpressionDoNotRememberPossiblyImpureValuesRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/MatchExpressionDoNotRememberPossiblyImpureValuesRuleTest.php @@ -38,9 +38,12 @@ public function testBug9007(): void public static function getAdditionalConfigFiles(): array { - return array_merge(parent::getAdditionalConfigFiles(), [ + return array_merge( + parent::getAdditionalConfigFiles(), + [ __DIR__ . '/doNotRememberPossiblyImpureValues.neon', - ]); + ], + ); } } diff --git a/tests/PHPStan/Rules/Comparison/MatchExpressionRuleTest.php b/tests/PHPStan/Rules/Comparison/MatchExpressionRuleTest.php index 619f5bbdb07..b267bfc3e1f 100644 --- a/tests/PHPStan/Rules/Comparison/MatchExpressionRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/MatchExpressionRuleTest.php @@ -12,24 +12,31 @@ class MatchExpressionRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $treatPhpDocTypesAsCertain = true; + private bool $treatPhpDocTypesAsCertain = true; - /** - * @var bool - */ - private $reportAlwaysTrueInLastCondition = false; + private bool $reportAlwaysTrueInLastCondition = false; - /** - * @var bool - */ - private $disableUnreachable = false; + private bool $disableUnreachable = false; protected function getRule(): Rule { - return new MatchExpressionRule(new ConstantConditionRuleHelper(new ImpossibleCheckTypeHelper($this->createReflectionProvider(), $this->getTypeSpecifier(), [], $this->treatPhpDocTypesAsCertain, true), $this->treatPhpDocTypesAsCertain, true), true, $this->disableUnreachable, $this->reportAlwaysTrueInLastCondition, $this->treatPhpDocTypesAsCertain); + return new MatchExpressionRule( + new ConstantConditionRuleHelper( + new ImpossibleCheckTypeHelper( + $this->createReflectionProvider(), + $this->getTypeSpecifier(), + [], + $this->treatPhpDocTypesAsCertain, + true, + ), + $this->treatPhpDocTypesAsCertain, + true, + ), + true, + $this->disableUnreachable, + $this->reportAlwaysTrueInLastCondition, + $this->treatPhpDocTypesAsCertain, + ); } protected function shouldTreatPhpDocTypesAsCertain(): bool diff --git a/tests/PHPStan/Rules/Comparison/NumberComparisonOperatorsConstantConditionRuleTest.php b/tests/PHPStan/Rules/Comparison/NumberComparisonOperatorsConstantConditionRuleTest.php index ce9d6f7a6a2..78cef84972d 100644 --- a/tests/PHPStan/Rules/Comparison/NumberComparisonOperatorsConstantConditionRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/NumberComparisonOperatorsConstantConditionRuleTest.php @@ -12,10 +12,7 @@ class NumberComparisonOperatorsConstantConditionRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $treatPhpDocTypesAsCertain = true; + private bool $treatPhpDocTypesAsCertain = true; protected function getRule(): Rule { diff --git a/tests/PHPStan/Rules/Comparison/StrictComparisonOfDifferentTypesRuleTest.php b/tests/PHPStan/Rules/Comparison/StrictComparisonOfDifferentTypesRuleTest.php index 06605c981c6..f23be18f9da 100644 --- a/tests/PHPStan/Rules/Comparison/StrictComparisonOfDifferentTypesRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/StrictComparisonOfDifferentTypesRuleTest.php @@ -13,20 +13,11 @@ class StrictComparisonOfDifferentTypesRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $checkAlwaysTrueStrictComparison; + private bool $checkAlwaysTrueStrictComparison; - /** - * @var bool - */ - private $reportAlwaysTrueInLastCondition = false; + private bool $reportAlwaysTrueInLastCondition = false; - /** - * @var bool - */ - private $treatPhpDocTypesAsCertain = true; + private bool $treatPhpDocTypesAsCertain = true; protected function getRule(): Rule { @@ -42,7 +33,9 @@ public function testStrictComparison(): void { $this->checkAlwaysTrueStrictComparison = true; $tipText = 'Because the type is coming from a PHPDoc, you can turn off this check by setting treatPhpDocTypesAsCertain: false in your %configurationFile%.'; - $this->analyse([__DIR__ . '/data/strict-comparison.php'], [ + $this->analyse( + [__DIR__ . '/data/strict-comparison.php'], + [ [ 'Strict comparison using === between 1 and 1 will always evaluate to true.', 10, @@ -272,14 +265,17 @@ public function testStrictComparison(): void 996, 'Remove remaining cases below this one and this error will disappear too.', ], - ]); + ], + ); } public function testStrictComparisonWithoutAlwaysTrue(): void { $this->checkAlwaysTrueStrictComparison = false; $tipText = 'Because the type is coming from a PHPDoc, you can turn off this check by setting treatPhpDocTypesAsCertain: false in your %configurationFile%.'; - $this->analyse([__DIR__ . '/data/strict-comparison.php'], [ + $this->analyse( + [__DIR__ . '/data/strict-comparison.php'], + [ [ 'Strict comparison using === between 1 and \'1\' will always evaluate to false.', 11, @@ -422,7 +418,8 @@ public function testStrictComparisonWithoutAlwaysTrue(): void 'Strict comparison using !== between INF and INF will always evaluate to false.', 982, ], - ]); + ], + ); } public function testStrictComparisonPhp71(): void diff --git a/tests/PHPStan/Rules/Comparison/TernaryOperatorConstantConditionRuleTest.php b/tests/PHPStan/Rules/Comparison/TernaryOperatorConstantConditionRuleTest.php index 4da5b8fd695..71fce9241dc 100644 --- a/tests/PHPStan/Rules/Comparison/TernaryOperatorConstantConditionRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/TernaryOperatorConstantConditionRuleTest.php @@ -11,14 +11,24 @@ class TernaryOperatorConstantConditionRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $treatPhpDocTypesAsCertain; + private bool $treatPhpDocTypesAsCertain; protected function getRule(): Rule { - return new TernaryOperatorConstantConditionRule(new ConstantConditionRuleHelper(new ImpossibleCheckTypeHelper($this->createReflectionProvider(), $this->getTypeSpecifier(), [], $this->treatPhpDocTypesAsCertain, true), $this->treatPhpDocTypesAsCertain, true), $this->treatPhpDocTypesAsCertain); + return new TernaryOperatorConstantConditionRule( + new ConstantConditionRuleHelper( + new ImpossibleCheckTypeHelper( + $this->createReflectionProvider(), + $this->getTypeSpecifier(), + [], + $this->treatPhpDocTypesAsCertain, + true, + ), + $this->treatPhpDocTypesAsCertain, + true, + ), + $this->treatPhpDocTypesAsCertain, + ); } protected function shouldTreatPhpDocTypesAsCertain(): bool diff --git a/tests/PHPStan/Rules/Comparison/UnreachableIfBranchesRuleTest.php b/tests/PHPStan/Rules/Comparison/UnreachableIfBranchesRuleTest.php index 3548fc54c9c..7843308281b 100644 --- a/tests/PHPStan/Rules/Comparison/UnreachableIfBranchesRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/UnreachableIfBranchesRuleTest.php @@ -11,14 +11,25 @@ class UnreachableIfBranchesRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $treatPhpDocTypesAsCertain; + private bool $treatPhpDocTypesAsCertain; protected function getRule(): Rule { - return new UnreachableIfBranchesRule(new ConstantConditionRuleHelper(new ImpossibleCheckTypeHelper($this->createReflectionProvider(), $this->getTypeSpecifier(), [], $this->treatPhpDocTypesAsCertain, true), $this->treatPhpDocTypesAsCertain, true), $this->treatPhpDocTypesAsCertain, false); + return new UnreachableIfBranchesRule( + new ConstantConditionRuleHelper( + new ImpossibleCheckTypeHelper( + $this->createReflectionProvider(), + $this->getTypeSpecifier(), + [], + $this->treatPhpDocTypesAsCertain, + true, + ), + $this->treatPhpDocTypesAsCertain, + true, + ), + $this->treatPhpDocTypesAsCertain, + false, + ); } protected function shouldTreatPhpDocTypesAsCertain(): bool diff --git a/tests/PHPStan/Rules/Comparison/UnreachableTernaryElseBranchRuleTest.php b/tests/PHPStan/Rules/Comparison/UnreachableTernaryElseBranchRuleTest.php index 56983418b62..317f5f98aae 100644 --- a/tests/PHPStan/Rules/Comparison/UnreachableTernaryElseBranchRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/UnreachableTernaryElseBranchRuleTest.php @@ -11,14 +11,25 @@ class UnreachableTernaryElseBranchRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $treatPhpDocTypesAsCertain; + private bool $treatPhpDocTypesAsCertain; protected function getRule(): Rule { - return new UnreachableTernaryElseBranchRule(new ConstantConditionRuleHelper(new ImpossibleCheckTypeHelper($this->createReflectionProvider(), $this->getTypeSpecifier(), [], $this->treatPhpDocTypesAsCertain, true), $this->treatPhpDocTypesAsCertain, true), $this->treatPhpDocTypesAsCertain, false); + return new UnreachableTernaryElseBranchRule( + new ConstantConditionRuleHelper( + new ImpossibleCheckTypeHelper( + $this->createReflectionProvider(), + $this->getTypeSpecifier(), + [], + $this->treatPhpDocTypesAsCertain, + true, + ), + $this->treatPhpDocTypesAsCertain, + true, + ), + $this->treatPhpDocTypesAsCertain, + false, + ); } protected function shouldTreatPhpDocTypesAsCertain(): bool diff --git a/tests/PHPStan/Rules/Comparison/WhileLoopAlwaysFalseConditionRuleTest.php b/tests/PHPStan/Rules/Comparison/WhileLoopAlwaysFalseConditionRuleTest.php index 7ee730ee46b..42675f9d8ac 100644 --- a/tests/PHPStan/Rules/Comparison/WhileLoopAlwaysFalseConditionRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/WhileLoopAlwaysFalseConditionRuleTest.php @@ -11,14 +11,24 @@ class WhileLoopAlwaysFalseConditionRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $treatPhpDocTypesAsCertain = true; + private bool $treatPhpDocTypesAsCertain = true; protected function getRule(): Rule { - return new WhileLoopAlwaysFalseConditionRule(new ConstantConditionRuleHelper(new ImpossibleCheckTypeHelper($this->createReflectionProvider(), $this->getTypeSpecifier(), [], $this->treatPhpDocTypesAsCertain, true), $this->treatPhpDocTypesAsCertain, true), $this->treatPhpDocTypesAsCertain); + return new WhileLoopAlwaysFalseConditionRule( + new ConstantConditionRuleHelper( + new ImpossibleCheckTypeHelper( + $this->createReflectionProvider(), + $this->getTypeSpecifier(), + [], + $this->treatPhpDocTypesAsCertain, + true, + ), + $this->treatPhpDocTypesAsCertain, + true, + ), + $this->treatPhpDocTypesAsCertain, + ); } protected function shouldTreatPhpDocTypesAsCertain(): bool diff --git a/tests/PHPStan/Rules/Comparison/WhileLoopAlwaysTrueConditionRuleTest.php b/tests/PHPStan/Rules/Comparison/WhileLoopAlwaysTrueConditionRuleTest.php index 1da0ea2e110..e6f158f91af 100644 --- a/tests/PHPStan/Rules/Comparison/WhileLoopAlwaysTrueConditionRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/WhileLoopAlwaysTrueConditionRuleTest.php @@ -11,14 +11,24 @@ class WhileLoopAlwaysTrueConditionRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $treatPhpDocTypesAsCertain = true; + private bool $treatPhpDocTypesAsCertain = true; protected function getRule(): Rule { - return new WhileLoopAlwaysTrueConditionRule(new ConstantConditionRuleHelper(new ImpossibleCheckTypeHelper($this->createReflectionProvider(), $this->getTypeSpecifier(), [], $this->treatPhpDocTypesAsCertain, true), $this->treatPhpDocTypesAsCertain, true), $this->treatPhpDocTypesAsCertain); + return new WhileLoopAlwaysTrueConditionRule( + new ConstantConditionRuleHelper( + new ImpossibleCheckTypeHelper( + $this->createReflectionProvider(), + $this->getTypeSpecifier(), + [], + $this->treatPhpDocTypesAsCertain, + true, + ), + $this->treatPhpDocTypesAsCertain, + true, + ), + $this->treatPhpDocTypesAsCertain, + ); } protected function shouldTreatPhpDocTypesAsCertain(): bool diff --git a/tests/PHPStan/Rules/Constants/DirectAlwaysUsedClassConstantsExtensionProvider.php b/tests/PHPStan/Rules/Constants/DirectAlwaysUsedClassConstantsExtensionProvider.php index 392259b27d9..861c72d7ab5 100644 --- a/tests/PHPStan/Rules/Constants/DirectAlwaysUsedClassConstantsExtensionProvider.php +++ b/tests/PHPStan/Rules/Constants/DirectAlwaysUsedClassConstantsExtensionProvider.php @@ -5,16 +5,11 @@ class DirectAlwaysUsedClassConstantsExtensionProvider implements AlwaysUsedClassConstantsExtensionProvider { - /** - * @var AlwaysUsedClassConstantsExtension[] - */ - private $extensions; /** * @param AlwaysUsedClassConstantsExtension[] $extensions */ - public function __construct(array $extensions) + public function __construct(private array $extensions) { - $this->extensions = $extensions; } /** diff --git a/tests/PHPStan/Rules/Constants/DynamicClassConstantFetchRuleTest.php b/tests/PHPStan/Rules/Constants/DynamicClassConstantFetchRuleTest.php index 78a5ab750dd..28069352264 100644 --- a/tests/PHPStan/Rules/Constants/DynamicClassConstantFetchRuleTest.php +++ b/tests/PHPStan/Rules/Constants/DynamicClassConstantFetchRuleTest.php @@ -16,7 +16,10 @@ class DynamicClassConstantFetchRuleTest extends RuleTestCase protected function getRule(): TRule { - return new DynamicClassConstantFetchRule(self::getContainer()->getByType(PhpVersion::class), new RuleLevelHelper($this->createReflectionProvider(), true, false, true, false, false, true, false)); + return new DynamicClassConstantFetchRule( + self::getContainer()->getByType(PhpVersion::class), + new RuleLevelHelper($this->createReflectionProvider(), true, false, true, false, false, true, false), + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Constants/FinalConstantRuleTest.php b/tests/PHPStan/Rules/Constants/FinalConstantRuleTest.php index 45d912a3d76..1fac7d6798f 100644 --- a/tests/PHPStan/Rules/Constants/FinalConstantRuleTest.php +++ b/tests/PHPStan/Rules/Constants/FinalConstantRuleTest.php @@ -12,10 +12,7 @@ class FinalConstantRuleTest extends RuleTestCase { - /** - * @var int - */ - private $phpVersionId; + private int $phpVersionId; protected function getRule(): Rule { diff --git a/tests/PHPStan/Rules/DateTimeInstantiationRuleTest.php b/tests/PHPStan/Rules/DateTimeInstantiationRuleTest.php index 4d12884caef..40711affecf 100644 --- a/tests/PHPStan/Rules/DateTimeInstantiationRuleTest.php +++ b/tests/PHPStan/Rules/DateTimeInstantiationRuleTest.php @@ -17,7 +17,9 @@ protected function getRule(): Rule public function test(): void { - $this->analyse([__DIR__ . '/data/datetime-instantiation.php'], [ + $this->analyse( + [__DIR__ . '/data/datetime-instantiation.php'], + [ [ 'Instantiating DateTime with 2020.11.17 produces an error: Double time specification', 3, @@ -50,7 +52,8 @@ public function test(): void 'Instantiating DateTimeImmutable with 2020.11.17 produces an error: Double time specification', 23, ], - ]); + ], + ); } } diff --git a/tests/PHPStan/Rules/DeadCode/UnreachableStatementRuleTest.php b/tests/PHPStan/Rules/DeadCode/UnreachableStatementRuleTest.php index bf90a499ad8..0efdb81138d 100644 --- a/tests/PHPStan/Rules/DeadCode/UnreachableStatementRuleTest.php +++ b/tests/PHPStan/Rules/DeadCode/UnreachableStatementRuleTest.php @@ -11,10 +11,7 @@ class UnreachableStatementRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $treatPhpDocTypesAsCertain; + private bool $treatPhpDocTypesAsCertain; protected function getRule(): Rule { diff --git a/tests/PHPStan/Rules/DeadCode/UnusedPrivateConstantRuleTest.php b/tests/PHPStan/Rules/DeadCode/UnusedPrivateConstantRuleTest.php index 737aedd6cb3..24bde42de8d 100644 --- a/tests/PHPStan/Rules/DeadCode/UnusedPrivateConstantRuleTest.php +++ b/tests/PHPStan/Rules/DeadCode/UnusedPrivateConstantRuleTest.php @@ -18,7 +18,8 @@ class UnusedPrivateConstantRuleTest extends RuleTestCase protected function getRule(): Rule { - return new UnusedPrivateConstantRule(new DirectAlwaysUsedClassConstantsExtensionProvider([ + return new UnusedPrivateConstantRule( + new DirectAlwaysUsedClassConstantsExtensionProvider([ new class() implements AlwaysUsedClassConstantsExtension { public function isAlwaysUsed(ConstantReflection $constant): bool @@ -28,7 +29,8 @@ public function isAlwaysUsed(ConstantReflection $constant): bool } }, - ])); + ]), + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/DeadCode/UnusedPrivatePropertyRuleTest.php b/tests/PHPStan/Rules/DeadCode/UnusedPrivatePropertyRuleTest.php index c312299e497..649afd822b3 100644 --- a/tests/PHPStan/Rules/DeadCode/UnusedPrivatePropertyRuleTest.php +++ b/tests/PHPStan/Rules/DeadCode/UnusedPrivatePropertyRuleTest.php @@ -17,14 +17,15 @@ class UnusedPrivatePropertyRuleTest extends RuleTestCase { /** @var string[] */ - private $alwaysWrittenTags; + private array $alwaysWrittenTags; /** @var string[] */ - private $alwaysReadTags; + private array $alwaysReadTags; protected function getRule(): Rule { - return new UnusedPrivatePropertyRule(new DirectReadWritePropertiesExtensionProvider([ + return new UnusedPrivatePropertyRule( + new DirectReadWritePropertiesExtensionProvider([ new class() implements ReadWritePropertiesExtension { public function isAlwaysRead(PropertyReflection $property, string $propertyName): bool @@ -51,7 +52,11 @@ public function isInitialized(PropertyReflection $property, string $propertyName } }, - ]), $this->alwaysWrittenTags, $this->alwaysReadTags, true); + ]), + $this->alwaysWrittenTags, + $this->alwaysReadTags, + true, + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/DirectRegistryTest.php b/tests/PHPStan/Rules/DirectRegistryTest.php index 8f5ee0ba89b..c1ac9fc1096 100644 --- a/tests/PHPStan/Rules/DirectRegistryTest.php +++ b/tests/PHPStan/Rules/DirectRegistryTest.php @@ -26,16 +26,12 @@ public function testGetRules(): void public function testGetRulesWithTwoDifferentInstances(): void { - $fooRule = new UniversalRule(Node\Expr\FuncCall::class, static function (Node\Expr\FuncCall $node, Scope $scope) : array { - return [ - RuleErrorBuilder::message('Foo error')->identifier('tests.fooRule')->build(), - ]; - }); - $barRule = new UniversalRule(Node\Expr\FuncCall::class, static function (Node\Expr\FuncCall $node, Scope $scope) : array { - return [ - RuleErrorBuilder::message('Bar error')->identifier('tests.barRule')->build(), - ]; - }); + $fooRule = new UniversalRule(Node\Expr\FuncCall::class, static fn (Node\Expr\FuncCall $node, Scope $scope): array => [ + RuleErrorBuilder::message('Foo error')->identifier('tests.fooRule')->build(), + ]); + $barRule = new UniversalRule(Node\Expr\FuncCall::class, static fn (Node\Expr\FuncCall $node, Scope $scope): array => [ + RuleErrorBuilder::message('Bar error')->identifier('tests.barRule')->build(), + ]); $registry = new DirectRegistry([ $fooRule, diff --git a/tests/PHPStan/Rules/EnumCases/EnumCaseAttributesRuleTest.php b/tests/PHPStan/Rules/EnumCases/EnumCaseAttributesRuleTest.php index 59834dc70a9..9edc0ef9411 100644 --- a/tests/PHPStan/Rules/EnumCases/EnumCaseAttributesRuleTest.php +++ b/tests/PHPStan/Rules/EnumCases/EnumCaseAttributesRuleTest.php @@ -22,7 +22,25 @@ class EnumCaseAttributesRuleTest extends RuleTestCase protected function getRule(): Rule { $reflectionProvider = $this->createReflectionProvider(); - return new EnumCaseAttributesRule(new AttributesCheck($reflectionProvider, new FunctionCallParametersCheck(new RuleLevelHelper($reflectionProvider, true, false, true, false, false, true, false), new NullsafeCheck(), new PhpVersion(80100), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true, true), new ClassCaseSensitivityCheck($reflectionProvider, false), true)); + return new EnumCaseAttributesRule( + new AttributesCheck( + $reflectionProvider, + new FunctionCallParametersCheck( + new RuleLevelHelper($reflectionProvider, true, false, true, false, false, true, false), + new NullsafeCheck(), + new PhpVersion(80100), + new UnresolvableTypeHelper(), + new PropertyReflectionFinder(), + true, + true, + true, + true, + true, + ), + new ClassCaseSensitivityCheck($reflectionProvider, false), + true, + ), + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Exceptions/AbilityToDisableImplicitThrowsTest.php b/tests/PHPStan/Rules/Exceptions/AbilityToDisableImplicitThrowsTest.php index 816c721680c..08f48850674 100644 --- a/tests/PHPStan/Rules/Exceptions/AbilityToDisableImplicitThrowsTest.php +++ b/tests/PHPStan/Rules/Exceptions/AbilityToDisableImplicitThrowsTest.php @@ -14,7 +14,13 @@ class AbilityToDisableImplicitThrowsTest extends RuleTestCase protected function getRule(): Rule { - return new CatchWithUnthrownExceptionRule(new DefaultExceptionTypeResolver($this->createReflectionProvider(), [], [], [], []), true); + return new CatchWithUnthrownExceptionRule(new DefaultExceptionTypeResolver( + $this->createReflectionProvider(), + [], + [], + [], + [], + ), true); } public function testRule(): void @@ -29,7 +35,10 @@ public function testRule(): void public static function getAdditionalConfigFiles(): array { - return array_merge(parent::getAdditionalConfigFiles(), [__DIR__ . '/data/ability-to-disable-implicit-throws.neon']); + return array_merge( + parent::getAdditionalConfigFiles(), + [__DIR__ . '/data/ability-to-disable-implicit-throws.neon'], + ); } } diff --git a/tests/PHPStan/Rules/Exceptions/Bug5364Test.php b/tests/PHPStan/Rules/Exceptions/Bug5364Test.php index 5eb17048a0c..e6c4a38a424 100644 --- a/tests/PHPStan/Rules/Exceptions/Bug5364Test.php +++ b/tests/PHPStan/Rules/Exceptions/Bug5364Test.php @@ -13,7 +13,15 @@ class Bug5364Test extends RuleTestCase protected function getRule(): Rule { - return new MissingCheckedExceptionInMethodThrowsRule(new MissingCheckedExceptionInThrowsCheck(new DefaultExceptionTypeResolver($this->createReflectionProvider(), [], [], [], []))); + return new MissingCheckedExceptionInMethodThrowsRule( + new MissingCheckedExceptionInThrowsCheck(new DefaultExceptionTypeResolver( + $this->createReflectionProvider(), + [], + [], + [], + [], + )), + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Exceptions/CatchWithUnthrownExceptionRuleTest.php b/tests/PHPStan/Rules/Exceptions/CatchWithUnthrownExceptionRuleTest.php index ae5bc386903..4ef9cc3fd1e 100644 --- a/tests/PHPStan/Rules/Exceptions/CatchWithUnthrownExceptionRuleTest.php +++ b/tests/PHPStan/Rules/Exceptions/CatchWithUnthrownExceptionRuleTest.php @@ -14,17 +14,20 @@ class CatchWithUnthrownExceptionRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $reportUncheckedExceptionDeadCatch = true; + private bool $reportUncheckedExceptionDeadCatch = true; /** @var string[] */ - private $uncheckedExceptionClasses = []; + private array $uncheckedExceptionClasses = []; protected function getRule(): Rule { - return new CatchWithUnthrownExceptionRule(new DefaultExceptionTypeResolver($this->createReflectionProvider(), [], $this->uncheckedExceptionClasses, [], []), $this->reportUncheckedExceptionDeadCatch); + return new CatchWithUnthrownExceptionRule(new DefaultExceptionTypeResolver( + $this->createReflectionProvider(), + [], + $this->uncheckedExceptionClasses, + [], + [], + ), $this->reportUncheckedExceptionDeadCatch); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Exceptions/CatchWithUnthrownExceptionRuleWithDisabledMultiCatchTest.php b/tests/PHPStan/Rules/Exceptions/CatchWithUnthrownExceptionRuleWithDisabledMultiCatchTest.php index a87fa553ccb..debb459f031 100644 --- a/tests/PHPStan/Rules/Exceptions/CatchWithUnthrownExceptionRuleWithDisabledMultiCatchTest.php +++ b/tests/PHPStan/Rules/Exceptions/CatchWithUnthrownExceptionRuleWithDisabledMultiCatchTest.php @@ -14,12 +14,21 @@ class CatchWithUnthrownExceptionRuleWithDisabledMultiCatchTest extends RuleTestC protected function getRule(): Rule { - return new CatchWithUnthrownExceptionRule(new DefaultExceptionTypeResolver($this->createReflectionProvider(), [], [], [], []), true); + return new CatchWithUnthrownExceptionRule(new DefaultExceptionTypeResolver( + $this->createReflectionProvider(), + [], + [], + [], + [], + ), true); } public static function getAdditionalConfigFiles(): array { - return array_merge(parent::getAdditionalConfigFiles(), [__DIR__ . '/disable-detect-multi-catch.neon']); + return array_merge( + parent::getAdditionalConfigFiles(), + [__DIR__ . '/disable-detect-multi-catch.neon'], + ); } public function testMultiCatchBackwardCompatible(): void diff --git a/tests/PHPStan/Rules/Exceptions/CaughtExceptionExistenceRuleTest.php b/tests/PHPStan/Rules/Exceptions/CaughtExceptionExistenceRuleTest.php index 23e2c9e28e1..6af5ae9a2ce 100644 --- a/tests/PHPStan/Rules/Exceptions/CaughtExceptionExistenceRuleTest.php +++ b/tests/PHPStan/Rules/Exceptions/CaughtExceptionExistenceRuleTest.php @@ -15,7 +15,11 @@ class CaughtExceptionExistenceRuleTest extends RuleTestCase protected function getRule(): Rule { $broker = $this->createReflectionProvider(); - return new CaughtExceptionExistenceRule($broker, new ClassCaseSensitivityCheck($broker, true), true); + return new CaughtExceptionExistenceRule( + $broker, + new ClassCaseSensitivityCheck($broker, true), + true, + ); } public function testCheckCaughtException(): void diff --git a/tests/PHPStan/Rules/Exceptions/DefaultExceptionTypeResolverTest.php b/tests/PHPStan/Rules/Exceptions/DefaultExceptionTypeResolverTest.php index f285e72bf2f..07080289244 100644 --- a/tests/PHPStan/Rules/Exceptions/DefaultExceptionTypeResolverTest.php +++ b/tests/PHPStan/Rules/Exceptions/DefaultExceptionTypeResolverTest.php @@ -133,7 +133,14 @@ public function dataIsCheckedException(): array * @param string[] $checkedExceptionRegexes * @param string[] $checkedExceptionClasses */ - public function testIsCheckedException(array $uncheckedExceptionRegexes, array $uncheckedExceptionClasses, array $checkedExceptionRegexes, array $checkedExceptionClasses, string $className, bool $expectedResult) : void + public function testIsCheckedException( + array $uncheckedExceptionRegexes, + array $uncheckedExceptionClasses, + array $checkedExceptionRegexes, + array $checkedExceptionClasses, + string $className, + bool $expectedResult, + ): void { $resolver = new DefaultExceptionTypeResolver($this->createReflectionProvider(), $uncheckedExceptionRegexes, $uncheckedExceptionClasses, $checkedExceptionRegexes, $checkedExceptionClasses); $this->assertSame($expectedResult, $resolver->isCheckedException($className, self::getContainer()->getByType(ScopeFactory::class)->create(ScopeContext::create(__DIR__)))); diff --git a/tests/PHPStan/Rules/Exceptions/MissingCheckedExceptionInFunctionThrowsRuleTest.php b/tests/PHPStan/Rules/Exceptions/MissingCheckedExceptionInFunctionThrowsRuleTest.php index 9f921d94886..716e7b86870 100644 --- a/tests/PHPStan/Rules/Exceptions/MissingCheckedExceptionInFunctionThrowsRuleTest.php +++ b/tests/PHPStan/Rules/Exceptions/MissingCheckedExceptionInFunctionThrowsRuleTest.php @@ -14,7 +14,15 @@ class MissingCheckedExceptionInFunctionThrowsRuleTest extends RuleTestCase protected function getRule(): Rule { - return new MissingCheckedExceptionInFunctionThrowsRule(new MissingCheckedExceptionInThrowsCheck(new DefaultExceptionTypeResolver($this->createReflectionProvider(), [], [ShouldNotHappenException::class], [], []))); + return new MissingCheckedExceptionInFunctionThrowsRule( + new MissingCheckedExceptionInThrowsCheck(new DefaultExceptionTypeResolver( + $this->createReflectionProvider(), + [], + [ShouldNotHappenException::class], + [], + [], + )), + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Exceptions/MissingCheckedExceptionInMethodThrowsRuleTest.php b/tests/PHPStan/Rules/Exceptions/MissingCheckedExceptionInMethodThrowsRuleTest.php index e37f126f05a..d085543b84f 100644 --- a/tests/PHPStan/Rules/Exceptions/MissingCheckedExceptionInMethodThrowsRuleTest.php +++ b/tests/PHPStan/Rules/Exceptions/MissingCheckedExceptionInMethodThrowsRuleTest.php @@ -14,7 +14,15 @@ class MissingCheckedExceptionInMethodThrowsRuleTest extends RuleTestCase protected function getRule(): Rule { - return new MissingCheckedExceptionInMethodThrowsRule(new MissingCheckedExceptionInThrowsCheck(new DefaultExceptionTypeResolver($this->createReflectionProvider(), [], [ShouldNotHappenException::class], [], []))); + return new MissingCheckedExceptionInMethodThrowsRule( + new MissingCheckedExceptionInThrowsCheck(new DefaultExceptionTypeResolver( + $this->createReflectionProvider(), + [], + [ShouldNotHappenException::class], + [], + [], + )), + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Exceptions/NoncapturingCatchRuleTest.php b/tests/PHPStan/Rules/Exceptions/NoncapturingCatchRuleTest.php index 254647d8bec..9c8181f4a39 100644 --- a/tests/PHPStan/Rules/Exceptions/NoncapturingCatchRuleTest.php +++ b/tests/PHPStan/Rules/Exceptions/NoncapturingCatchRuleTest.php @@ -12,10 +12,7 @@ class NoncapturingCatchRuleTest extends RuleTestCase { - /** - * @var PhpVersion - */ - private $phpVersion; + private PhpVersion $phpVersion; protected function getRule(): Rule { diff --git a/tests/PHPStan/Rules/Exceptions/ThrowExprTypeRuleTest.php b/tests/PHPStan/Rules/Exceptions/ThrowExprTypeRuleTest.php index f84d154e276..8ef6277fe18 100644 --- a/tests/PHPStan/Rules/Exceptions/ThrowExprTypeRuleTest.php +++ b/tests/PHPStan/Rules/Exceptions/ThrowExprTypeRuleTest.php @@ -20,7 +20,9 @@ protected function getRule(): Rule public function testRule(): void { - $this->analyse([__DIR__ . '/data/throw-values.php'], [ + $this->analyse( + [__DIR__ . '/data/throw-values.php'], + [ /*[ 'Invalid type int to throw.', 29, @@ -46,7 +48,8 @@ public function testRule(): void 'Invalid type int to throw.', 65, ], - ]); + ], + ); } public function testClassExists(): void diff --git a/tests/PHPStan/Rules/Exceptions/ThrowExpressionRuleTest.php b/tests/PHPStan/Rules/Exceptions/ThrowExpressionRuleTest.php index 593fe170b07..1f32de8fe46 100644 --- a/tests/PHPStan/Rules/Exceptions/ThrowExpressionRuleTest.php +++ b/tests/PHPStan/Rules/Exceptions/ThrowExpressionRuleTest.php @@ -12,10 +12,7 @@ class ThrowExpressionRuleTest extends RuleTestCase { - /** - * @var PhpVersion - */ - private $phpVersion; + private PhpVersion $phpVersion; protected function getRule(): Rule { diff --git a/tests/PHPStan/Rules/Exceptions/ThrowsVoidFunctionWithExplicitThrowPointRuleTest.php b/tests/PHPStan/Rules/Exceptions/ThrowsVoidFunctionWithExplicitThrowPointRuleTest.php index 530ab8ea122..ff6c4416a6e 100644 --- a/tests/PHPStan/Rules/Exceptions/ThrowsVoidFunctionWithExplicitThrowPointRuleTest.php +++ b/tests/PHPStan/Rules/Exceptions/ThrowsVoidFunctionWithExplicitThrowPointRuleTest.php @@ -12,17 +12,20 @@ class ThrowsVoidFunctionWithExplicitThrowPointRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $missingCheckedExceptionInThrows; + private bool $missingCheckedExceptionInThrows; /** @var string[] */ - private $checkedExceptionClasses; + private array $checkedExceptionClasses; protected function getRule(): Rule { - return new ThrowsVoidFunctionWithExplicitThrowPointRule(new DefaultExceptionTypeResolver($this->createReflectionProvider(), [], [], [], $this->checkedExceptionClasses), $this->missingCheckedExceptionInThrows); + return new ThrowsVoidFunctionWithExplicitThrowPointRule(new DefaultExceptionTypeResolver( + $this->createReflectionProvider(), + [], + [], + [], + $this->checkedExceptionClasses, + ), $this->missingCheckedExceptionInThrows); } public function dataRule(): array diff --git a/tests/PHPStan/Rules/Exceptions/ThrowsVoidMethodWithExplicitThrowPointRuleTest.php b/tests/PHPStan/Rules/Exceptions/ThrowsVoidMethodWithExplicitThrowPointRuleTest.php index 13c20797241..5a2dcb0429a 100644 --- a/tests/PHPStan/Rules/Exceptions/ThrowsVoidMethodWithExplicitThrowPointRuleTest.php +++ b/tests/PHPStan/Rules/Exceptions/ThrowsVoidMethodWithExplicitThrowPointRuleTest.php @@ -14,17 +14,20 @@ class ThrowsVoidMethodWithExplicitThrowPointRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $missingCheckedExceptionInThrows; + private bool $missingCheckedExceptionInThrows; /** @var string[] */ - private $checkedExceptionClasses; + private array $checkedExceptionClasses; protected function getRule(): Rule { - return new ThrowsVoidMethodWithExplicitThrowPointRule(new DefaultExceptionTypeResolver($this->createReflectionProvider(), [], [], [], $this->checkedExceptionClasses), $this->missingCheckedExceptionInThrows); + return new ThrowsVoidMethodWithExplicitThrowPointRule(new DefaultExceptionTypeResolver( + $this->createReflectionProvider(), + [], + [], + [], + $this->checkedExceptionClasses, + ), $this->missingCheckedExceptionInThrows); } public function dataRule(): array diff --git a/tests/PHPStan/Rules/Functions/ArrayFilterRuleTest.php b/tests/PHPStan/Rules/Functions/ArrayFilterRuleTest.php index 2df41b98c92..1c62d47af25 100644 --- a/tests/PHPStan/Rules/Functions/ArrayFilterRuleTest.php +++ b/tests/PHPStan/Rules/Functions/ArrayFilterRuleTest.php @@ -11,10 +11,7 @@ class ArrayFilterRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $treatPhpDocTypesAsCertain = true; + private bool $treatPhpDocTypesAsCertain = true; protected function getRule(): Rule { diff --git a/tests/PHPStan/Rules/Functions/ArrowFunctionAttributesRuleTest.php b/tests/PHPStan/Rules/Functions/ArrowFunctionAttributesRuleTest.php index 66a1a888c72..dfad3ae5b28 100644 --- a/tests/PHPStan/Rules/Functions/ArrowFunctionAttributesRuleTest.php +++ b/tests/PHPStan/Rules/Functions/ArrowFunctionAttributesRuleTest.php @@ -22,7 +22,25 @@ class ArrowFunctionAttributesRuleTest extends RuleTestCase protected function getRule(): Rule { $reflectionProvider = $this->createReflectionProvider(); - return new ArrowFunctionAttributesRule(new AttributesCheck($reflectionProvider, new FunctionCallParametersCheck(new RuleLevelHelper($reflectionProvider, true, false, true, false, false, true, false), new NullsafeCheck(), new PhpVersion(80000), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true, true), new ClassCaseSensitivityCheck($reflectionProvider, false), true)); + return new ArrowFunctionAttributesRule( + new AttributesCheck( + $reflectionProvider, + new FunctionCallParametersCheck( + new RuleLevelHelper($reflectionProvider, true, false, true, false, false, true, false), + new NullsafeCheck(), + new PhpVersion(80000), + new UnresolvableTypeHelper(), + new PropertyReflectionFinder(), + true, + true, + true, + true, + true, + ), + new ClassCaseSensitivityCheck($reflectionProvider, false), + true, + ), + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Functions/ArrowFunctionReturnTypeRuleTest.php b/tests/PHPStan/Rules/Functions/ArrowFunctionReturnTypeRuleTest.php index 55efbc55c69..3155b387c25 100644 --- a/tests/PHPStan/Rules/Functions/ArrowFunctionReturnTypeRuleTest.php +++ b/tests/PHPStan/Rules/Functions/ArrowFunctionReturnTypeRuleTest.php @@ -16,7 +16,16 @@ class ArrowFunctionReturnTypeRuleTest extends RuleTestCase protected function getRule(): Rule { - return new ArrowFunctionReturnTypeRule(new FunctionReturnTypeCheck(new RuleLevelHelper($this->createReflectionProvider(), true, false, true, false, false, true, false))); + return new ArrowFunctionReturnTypeRule(new FunctionReturnTypeCheck(new RuleLevelHelper( + $this->createReflectionProvider(), + true, + false, + true, + false, + false, + true, + false, + ))); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Functions/CallCallablesRuleTest.php b/tests/PHPStan/Rules/Functions/CallCallablesRuleTest.php index 7b4065c160f..f0698017810 100644 --- a/tests/PHPStan/Rules/Functions/CallCallablesRuleTest.php +++ b/tests/PHPStan/Rules/Functions/CallCallablesRuleTest.php @@ -18,15 +18,27 @@ class CallCallablesRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $checkExplicitMixed = false; + private bool $checkExplicitMixed = false; protected function getRule(): Rule { $ruleLevelHelper = new RuleLevelHelper($this->createReflectionProvider(), true, false, true, $this->checkExplicitMixed, false, true, false); - return new CallCallablesRule(new FunctionCallParametersCheck($ruleLevelHelper, new NullsafeCheck(), new PhpVersion(80000), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true, true), $ruleLevelHelper, true); + return new CallCallablesRule( + new FunctionCallParametersCheck( + $ruleLevelHelper, + new NullsafeCheck(), + new PhpVersion(80000), + new UnresolvableTypeHelper(), + new PropertyReflectionFinder(), + true, + true, + true, + true, + true, + ), + $ruleLevelHelper, + true, + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php b/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php index bc77d690c3a..e00f619105b 100644 --- a/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php +++ b/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php @@ -19,15 +19,15 @@ class CallToFunctionParametersRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $checkExplicitMixed = false; + private bool $checkExplicitMixed = false; protected function getRule(): Rule { $broker = $this->createReflectionProvider(); - return new CallToFunctionParametersRule($broker, new FunctionCallParametersCheck(new RuleLevelHelper($broker, true, false, true, $this->checkExplicitMixed, false, true, false), new NullsafeCheck(), new PhpVersion(80000), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true, true)); + return new CallToFunctionParametersRule( + $broker, + new FunctionCallParametersCheck(new RuleLevelHelper($broker, true, false, true, $this->checkExplicitMixed, false, true, false), new NullsafeCheck(), new PhpVersion(80000), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true, true), + ); } public function testCallToFunctionWithoutParameters(): void diff --git a/tests/PHPStan/Rules/Functions/ClosureAttributesRuleTest.php b/tests/PHPStan/Rules/Functions/ClosureAttributesRuleTest.php index 5bdad4a9aa7..8f5fcb4e6b5 100644 --- a/tests/PHPStan/Rules/Functions/ClosureAttributesRuleTest.php +++ b/tests/PHPStan/Rules/Functions/ClosureAttributesRuleTest.php @@ -22,7 +22,25 @@ class ClosureAttributesRuleTest extends RuleTestCase protected function getRule(): Rule { $reflectionProvider = $this->createReflectionProvider(); - return new ClosureAttributesRule(new AttributesCheck($reflectionProvider, new FunctionCallParametersCheck(new RuleLevelHelper($reflectionProvider, true, false, true, false, false, true, false), new NullsafeCheck(), new PhpVersion(80000), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true, true), new ClassCaseSensitivityCheck($reflectionProvider, false), true)); + return new ClosureAttributesRule( + new AttributesCheck( + $reflectionProvider, + new FunctionCallParametersCheck( + new RuleLevelHelper($reflectionProvider, true, false, true, false, false, true, false), + new NullsafeCheck(), + new PhpVersion(80000), + new UnresolvableTypeHelper(), + new PropertyReflectionFinder(), + true, + true, + true, + true, + true, + ), + new ClassCaseSensitivityCheck($reflectionProvider, false), + true, + ), + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Functions/DuplicateFunctionDeclarationRuleTest.php b/tests/PHPStan/Rules/Functions/DuplicateFunctionDeclarationRuleTest.php index 91c1713c24e..5a78c1d1aa3 100644 --- a/tests/PHPStan/Rules/Functions/DuplicateFunctionDeclarationRuleTest.php +++ b/tests/PHPStan/Rules/Functions/DuplicateFunctionDeclarationRuleTest.php @@ -22,7 +22,13 @@ protected function getRule(): Rule { $fileHelper = new FileHelper(__DIR__ . '/data'); - return new DuplicateFunctionDeclarationRule(new DefaultReflector(new OptimizedSingleFileSourceLocator(self::getContainer()->getByType(FileNodesFetcher::class), self::FILENAME)), new SimpleRelativePathHelper($fileHelper->normalizePath($fileHelper->getWorkingDirectory(), '/'))); + return new DuplicateFunctionDeclarationRule( + new DefaultReflector(new OptimizedSingleFileSourceLocator( + self::getContainer()->getByType(FileNodesFetcher::class), + self::FILENAME, + )), + new SimpleRelativePathHelper($fileHelper->normalizePath($fileHelper->getWorkingDirectory(), '/')), + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Functions/ExistingClassesInArrowFunctionTypehintsRuleTest.php b/tests/PHPStan/Rules/Functions/ExistingClassesInArrowFunctionTypehintsRuleTest.php index 9d4da5b19f8..e2cdf27f1be 100644 --- a/tests/PHPStan/Rules/Functions/ExistingClassesInArrowFunctionTypehintsRuleTest.php +++ b/tests/PHPStan/Rules/Functions/ExistingClassesInArrowFunctionTypehintsRuleTest.php @@ -16,10 +16,7 @@ class ExistingClassesInArrowFunctionTypehintsRuleTest extends RuleTestCase { - /** - * @var int - */ - private $phpVersionId = PHP_VERSION_ID; + private int $phpVersionId = PHP_VERSION_ID; protected function getRule(): Rule { diff --git a/tests/PHPStan/Rules/Functions/ExistingClassesInClosureTypehintsRuleTest.php b/tests/PHPStan/Rules/Functions/ExistingClassesInClosureTypehintsRuleTest.php index bd0dbda16c7..f3e02354ddd 100644 --- a/tests/PHPStan/Rules/Functions/ExistingClassesInClosureTypehintsRuleTest.php +++ b/tests/PHPStan/Rules/Functions/ExistingClassesInClosureTypehintsRuleTest.php @@ -16,10 +16,7 @@ class ExistingClassesInClosureTypehintsRuleTest extends RuleTestCase { - /** - * @var int - */ - private $phpVersionId = PHP_VERSION_ID; + private int $phpVersionId = PHP_VERSION_ID; protected function getRule(): Rule { diff --git a/tests/PHPStan/Rules/Functions/ExistingClassesInTypehintsRuleTest.php b/tests/PHPStan/Rules/Functions/ExistingClassesInTypehintsRuleTest.php index 23419fc0cef..31de1353adb 100644 --- a/tests/PHPStan/Rules/Functions/ExistingClassesInTypehintsRuleTest.php +++ b/tests/PHPStan/Rules/Functions/ExistingClassesInTypehintsRuleTest.php @@ -16,10 +16,7 @@ class ExistingClassesInTypehintsRuleTest extends RuleTestCase { - /** - * @var int - */ - private $phpVersionId = PHP_VERSION_ID; + private int $phpVersionId = PHP_VERSION_ID; protected function getRule(): Rule { diff --git a/tests/PHPStan/Rules/Functions/FunctionAttributesRuleTest.php b/tests/PHPStan/Rules/Functions/FunctionAttributesRuleTest.php index 34e73f1a537..0491852e08e 100644 --- a/tests/PHPStan/Rules/Functions/FunctionAttributesRuleTest.php +++ b/tests/PHPStan/Rules/Functions/FunctionAttributesRuleTest.php @@ -22,7 +22,25 @@ class FunctionAttributesRuleTest extends RuleTestCase protected function getRule(): Rule { $reflectionProvider = $this->createReflectionProvider(); - return new FunctionAttributesRule(new AttributesCheck($reflectionProvider, new FunctionCallParametersCheck(new RuleLevelHelper($reflectionProvider, true, false, true, false, false, true, false), new NullsafeCheck(), new PhpVersion(80000), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true, true), new ClassCaseSensitivityCheck($reflectionProvider, false), true)); + return new FunctionAttributesRule( + new AttributesCheck( + $reflectionProvider, + new FunctionCallParametersCheck( + new RuleLevelHelper($reflectionProvider, true, false, true, false, false, true, false), + new NullsafeCheck(), + new PhpVersion(80000), + new UnresolvableTypeHelper(), + new PropertyReflectionFinder(), + true, + true, + true, + true, + true, + ), + new ClassCaseSensitivityCheck($reflectionProvider, false), + true, + ), + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Functions/FunctionCallableRuleTest.php b/tests/PHPStan/Rules/Functions/FunctionCallableRuleTest.php index eb3d77ff448..2a92e5f5a2e 100644 --- a/tests/PHPStan/Rules/Functions/FunctionCallableRuleTest.php +++ b/tests/PHPStan/Rules/Functions/FunctionCallableRuleTest.php @@ -18,7 +18,13 @@ protected function getRule(): Rule { $reflectionProvider = $this->createReflectionProvider(); - return new FunctionCallableRule($reflectionProvider, new RuleLevelHelper($reflectionProvider, true, false, true, false, false, true, false), new PhpVersion(PHP_VERSION_ID), true, true); + return new FunctionCallableRule( + $reflectionProvider, + new RuleLevelHelper($reflectionProvider, true, false, true, false, false, true, false), + new PhpVersion(PHP_VERSION_ID), + true, + true, + ); } public function testNotSupportedOnOlderVersions(): void diff --git a/tests/PHPStan/Rules/Functions/ParamAttributesRuleTest.php b/tests/PHPStan/Rules/Functions/ParamAttributesRuleTest.php index 0ba37863f59..73fa588489c 100644 --- a/tests/PHPStan/Rules/Functions/ParamAttributesRuleTest.php +++ b/tests/PHPStan/Rules/Functions/ParamAttributesRuleTest.php @@ -22,7 +22,25 @@ class ParamAttributesRuleTest extends RuleTestCase protected function getRule(): Rule { $reflectionProvider = $this->createReflectionProvider(); - return new ParamAttributesRule(new AttributesCheck($reflectionProvider, new FunctionCallParametersCheck(new RuleLevelHelper($reflectionProvider, true, false, true, false, false, true, false), new NullsafeCheck(), new PhpVersion(80000), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true, true), new ClassCaseSensitivityCheck($reflectionProvider, false), true)); + return new ParamAttributesRule( + new AttributesCheck( + $reflectionProvider, + new FunctionCallParametersCheck( + new RuleLevelHelper($reflectionProvider, true, false, true, false, false, true, false), + new NullsafeCheck(), + new PhpVersion(80000), + new UnresolvableTypeHelper(), + new PropertyReflectionFinder(), + true, + true, + true, + true, + true, + ), + new ClassCaseSensitivityCheck($reflectionProvider, false), + true, + ), + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Functions/ReturnTypeRuleTest.php b/tests/PHPStan/Rules/Functions/ReturnTypeRuleTest.php index 4b562695fcb..bb99cc426a3 100644 --- a/tests/PHPStan/Rules/Functions/ReturnTypeRuleTest.php +++ b/tests/PHPStan/Rules/Functions/ReturnTypeRuleTest.php @@ -14,15 +14,9 @@ class ReturnTypeRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $checkNullables; + private bool $checkNullables; - /** - * @var bool - */ - private $checkExplicitMixed; + private bool $checkExplicitMixed; protected function getRule(): Rule { diff --git a/tests/PHPStan/Rules/Generics/ClassAncestorsRuleTest.php b/tests/PHPStan/Rules/Generics/ClassAncestorsRuleTest.php index 33a1dc9c1c6..ae78243b8c3 100644 --- a/tests/PHPStan/Rules/Generics/ClassAncestorsRuleTest.php +++ b/tests/PHPStan/Rules/Generics/ClassAncestorsRuleTest.php @@ -13,7 +13,16 @@ class ClassAncestorsRuleTest extends RuleTestCase protected function getRule(): Rule { - return new ClassAncestorsRule(new GenericAncestorsCheck($this->createReflectionProvider(), new GenericObjectTypeCheck(), new VarianceCheck(true, true), true, []), new CrossCheckInterfacesHelper()); + return new ClassAncestorsRule( + new GenericAncestorsCheck( + $this->createReflectionProvider(), + new GenericObjectTypeCheck(), + new VarianceCheck(true, true), + true, + [], + ), + new CrossCheckInterfacesHelper(), + ); } public function testRuleExtends(): void diff --git a/tests/PHPStan/Rules/Generics/ClassTemplateTypeRuleTest.php b/tests/PHPStan/Rules/Generics/ClassTemplateTypeRuleTest.php index ee8fefabbc4..683f974e571 100644 --- a/tests/PHPStan/Rules/Generics/ClassTemplateTypeRuleTest.php +++ b/tests/PHPStan/Rules/Generics/ClassTemplateTypeRuleTest.php @@ -18,7 +18,15 @@ protected function getRule(): Rule $broker = $this->createReflectionProvider(); $typeAliasResolver = $this->createTypeAliasResolver(['TypeAlias' => 'int'], $broker); - return new ClassTemplateTypeRule(new TemplateTypeCheck($broker, new ClassCaseSensitivityCheck($broker, true), new GenericObjectTypeCheck(), $typeAliasResolver, true)); + return new ClassTemplateTypeRule( + new TemplateTypeCheck( + $broker, + new ClassCaseSensitivityCheck($broker, true), + new GenericObjectTypeCheck(), + $typeAliasResolver, + true, + ), + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Generics/EnumAncestorsRuleTest.php b/tests/PHPStan/Rules/Generics/EnumAncestorsRuleTest.php index f5c541272d6..6b19578ec29 100644 --- a/tests/PHPStan/Rules/Generics/EnumAncestorsRuleTest.php +++ b/tests/PHPStan/Rules/Generics/EnumAncestorsRuleTest.php @@ -14,7 +14,16 @@ class EnumAncestorsRuleTest extends RuleTestCase protected function getRule(): Rule { - return new EnumAncestorsRule(new GenericAncestorsCheck($this->createReflectionProvider(), new GenericObjectTypeCheck(), new VarianceCheck(true, true), true, []), new CrossCheckInterfacesHelper()); + return new EnumAncestorsRule( + new GenericAncestorsCheck( + $this->createReflectionProvider(), + new GenericObjectTypeCheck(), + new VarianceCheck(true, true), + true, + [], + ), + new CrossCheckInterfacesHelper(), + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Generics/FunctionSignatureVarianceRuleTest.php b/tests/PHPStan/Rules/Generics/FunctionSignatureVarianceRuleTest.php index 16df760c9ca..f80773321a8 100644 --- a/tests/PHPStan/Rules/Generics/FunctionSignatureVarianceRuleTest.php +++ b/tests/PHPStan/Rules/Generics/FunctionSignatureVarianceRuleTest.php @@ -13,7 +13,9 @@ class FunctionSignatureVarianceRuleTest extends RuleTestCase protected function getRule(): Rule { - return new FunctionSignatureVarianceRule(self::getContainer()->getByType(VarianceCheck::class)); + return new FunctionSignatureVarianceRule( + self::getContainer()->getByType(VarianceCheck::class), + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Generics/FunctionTemplateTypeRuleTest.php b/tests/PHPStan/Rules/Generics/FunctionTemplateTypeRuleTest.php index 153b4b6b9dd..1fe44413935 100644 --- a/tests/PHPStan/Rules/Generics/FunctionTemplateTypeRuleTest.php +++ b/tests/PHPStan/Rules/Generics/FunctionTemplateTypeRuleTest.php @@ -18,7 +18,10 @@ protected function getRule(): Rule $broker = $this->createReflectionProvider(); $typeAliasResolver = $this->createTypeAliasResolver(['TypeAlias' => 'int'], $broker); - return new FunctionTemplateTypeRule(self::getContainer()->getByType(FileTypeMapper::class), new TemplateTypeCheck($broker, new ClassCaseSensitivityCheck($broker, true), new GenericObjectTypeCheck(), $typeAliasResolver, true)); + return new FunctionTemplateTypeRule( + self::getContainer()->getByType(FileTypeMapper::class), + new TemplateTypeCheck($broker, new ClassCaseSensitivityCheck($broker, true), new GenericObjectTypeCheck(), $typeAliasResolver, true), + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Generics/InterfaceAncestorsRuleTest.php b/tests/PHPStan/Rules/Generics/InterfaceAncestorsRuleTest.php index fff762cf497..f0e148bf568 100644 --- a/tests/PHPStan/Rules/Generics/InterfaceAncestorsRuleTest.php +++ b/tests/PHPStan/Rules/Generics/InterfaceAncestorsRuleTest.php @@ -13,7 +13,16 @@ class InterfaceAncestorsRuleTest extends RuleTestCase protected function getRule(): Rule { - return new InterfaceAncestorsRule(new GenericAncestorsCheck($this->createReflectionProvider(), new GenericObjectTypeCheck(), new VarianceCheck(true, true), true, []), new CrossCheckInterfacesHelper()); + return new InterfaceAncestorsRule( + new GenericAncestorsCheck( + $this->createReflectionProvider(), + new GenericObjectTypeCheck(), + new VarianceCheck(true, true), + true, + [], + ), + new CrossCheckInterfacesHelper(), + ); } public function testRuleImplements(): void diff --git a/tests/PHPStan/Rules/Generics/InterfaceTemplateTypeRuleTest.php b/tests/PHPStan/Rules/Generics/InterfaceTemplateTypeRuleTest.php index 3d6406a7370..ac5755f7638 100644 --- a/tests/PHPStan/Rules/Generics/InterfaceTemplateTypeRuleTest.php +++ b/tests/PHPStan/Rules/Generics/InterfaceTemplateTypeRuleTest.php @@ -17,7 +17,9 @@ protected function getRule(): Rule $broker = $this->createReflectionProvider(); $typeAliasResolver = $this->createTypeAliasResolver(['TypeAlias' => 'int'], $broker); - return new InterfaceTemplateTypeRule(new TemplateTypeCheck($broker, new ClassCaseSensitivityCheck($broker, true), new GenericObjectTypeCheck(), $typeAliasResolver, true)); + return new InterfaceTemplateTypeRule( + new TemplateTypeCheck($broker, new ClassCaseSensitivityCheck($broker, true), new GenericObjectTypeCheck(), $typeAliasResolver, true), + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Generics/MethodSignatureVarianceRuleTest.php b/tests/PHPStan/Rules/Generics/MethodSignatureVarianceRuleTest.php index 49df1be9acb..8f743f4dc71 100644 --- a/tests/PHPStan/Rules/Generics/MethodSignatureVarianceRuleTest.php +++ b/tests/PHPStan/Rules/Generics/MethodSignatureVarianceRuleTest.php @@ -13,7 +13,9 @@ class MethodSignatureVarianceRuleTest extends RuleTestCase protected function getRule(): Rule { - return new MethodSignatureVarianceRule(self::getContainer()->getByType(VarianceCheck::class)); + return new MethodSignatureVarianceRule( + self::getContainer()->getByType(VarianceCheck::class), + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Generics/MethodTemplateTypeRuleTest.php b/tests/PHPStan/Rules/Generics/MethodTemplateTypeRuleTest.php index 052c2a853db..9e5a8968653 100644 --- a/tests/PHPStan/Rules/Generics/MethodTemplateTypeRuleTest.php +++ b/tests/PHPStan/Rules/Generics/MethodTemplateTypeRuleTest.php @@ -18,7 +18,10 @@ protected function getRule(): Rule $broker = $this->createReflectionProvider(); $typeAliasResolver = $this->createTypeAliasResolver(['TypeAlias' => 'int'], $broker); - return new MethodTemplateTypeRule(self::getContainer()->getByType(FileTypeMapper::class), new TemplateTypeCheck($broker, new ClassCaseSensitivityCheck($broker, true), new GenericObjectTypeCheck(), $typeAliasResolver, true)); + return new MethodTemplateTypeRule( + self::getContainer()->getByType(FileTypeMapper::class), + new TemplateTypeCheck($broker, new ClassCaseSensitivityCheck($broker, true), new GenericObjectTypeCheck(), $typeAliasResolver, true), + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Generics/PropertyVarianceRuleTest.php b/tests/PHPStan/Rules/Generics/PropertyVarianceRuleTest.php index 23bb0c55505..97870f3572d 100644 --- a/tests/PHPStan/Rules/Generics/PropertyVarianceRuleTest.php +++ b/tests/PHPStan/Rules/Generics/PropertyVarianceRuleTest.php @@ -14,7 +14,10 @@ class PropertyVarianceRuleTest extends RuleTestCase protected function getRule(): Rule { - return new PropertyVarianceRule(self::getContainer()->getByType(VarianceCheck::class), true); + return new PropertyVarianceRule( + self::getContainer()->getByType(VarianceCheck::class), + true, + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Generics/TraitTemplateTypeRuleTest.php b/tests/PHPStan/Rules/Generics/TraitTemplateTypeRuleTest.php index ea107c1c3f9..1e51ca4be5b 100644 --- a/tests/PHPStan/Rules/Generics/TraitTemplateTypeRuleTest.php +++ b/tests/PHPStan/Rules/Generics/TraitTemplateTypeRuleTest.php @@ -18,7 +18,10 @@ protected function getRule(): Rule $broker = $this->createReflectionProvider(); $typeAliasResolver = $this->createTypeAliasResolver(['TypeAlias' => 'int'], $broker); - return new TraitTemplateTypeRule(self::getContainer()->getByType(FileTypeMapper::class), new TemplateTypeCheck($broker, new ClassCaseSensitivityCheck($broker, true), new GenericObjectTypeCheck(), $typeAliasResolver, true)); + return new TraitTemplateTypeRule( + self::getContainer()->getByType(FileTypeMapper::class), + new TemplateTypeCheck($broker, new ClassCaseSensitivityCheck($broker, true), new GenericObjectTypeCheck(), $typeAliasResolver, true), + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Generics/UsedTraitsRuleTest.php b/tests/PHPStan/Rules/Generics/UsedTraitsRuleTest.php index 49d8f9d0867..3ec30d55c6d 100644 --- a/tests/PHPStan/Rules/Generics/UsedTraitsRuleTest.php +++ b/tests/PHPStan/Rules/Generics/UsedTraitsRuleTest.php @@ -14,7 +14,16 @@ class UsedTraitsRuleTest extends RuleTestCase protected function getRule(): Rule { - return new UsedTraitsRule(self::getContainer()->getByType(FileTypeMapper::class), new GenericAncestorsCheck($this->createReflectionProvider(), new GenericObjectTypeCheck(), new VarianceCheck(true, true), true, [])); + return new UsedTraitsRule( + self::getContainer()->getByType(FileTypeMapper::class), + new GenericAncestorsCheck( + $this->createReflectionProvider(), + new GenericObjectTypeCheck(), + new VarianceCheck(true, true), + true, + [], + ), + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Methods/CallMethodsRuleNoBleedingEdgeTest.php b/tests/PHPStan/Rules/Methods/CallMethodsRuleNoBleedingEdgeTest.php index bb2e803ac6a..71678d99ff5 100644 --- a/tests/PHPStan/Rules/Methods/CallMethodsRuleNoBleedingEdgeTest.php +++ b/tests/PHPStan/Rules/Methods/CallMethodsRuleNoBleedingEdgeTest.php @@ -18,16 +18,16 @@ class CallMethodsRuleNoBleedingEdgeTest extends RuleTestCase { - /** - * @var bool - */ - private $checkExplicitMixed; + private bool $checkExplicitMixed; protected function getRule(): Rule { $reflectionProvider = $this->createReflectionProvider(); $ruleLevelHelper = new RuleLevelHelper($reflectionProvider, true, false, true, $this->checkExplicitMixed, false, true, false); - return new CallMethodsRule(new MethodCallCheck($reflectionProvider, $ruleLevelHelper, true, true), new FunctionCallParametersCheck($ruleLevelHelper, new NullsafeCheck(), new PhpVersion(PHP_VERSION_ID), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true, false)); + return new CallMethodsRule( + new MethodCallCheck($reflectionProvider, $ruleLevelHelper, true, true), + new FunctionCallParametersCheck($ruleLevelHelper, new NullsafeCheck(), new PhpVersion(PHP_VERSION_ID), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true, false), + ); } public function testGenericsInferCollection(): void diff --git a/tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php b/tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php index 077fe61cd17..e1b601daf19 100644 --- a/tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php +++ b/tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php @@ -18,41 +18,26 @@ class CallMethodsRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $checkThisOnly; + private bool $checkThisOnly; - /** - * @var bool - */ - private $checkNullables; + private bool $checkNullables; - /** - * @var bool - */ - private $checkUnionTypes; + private bool $checkUnionTypes; - /** - * @var bool - */ - private $checkExplicitMixed = false; + private bool $checkExplicitMixed = false; - /** - * @var bool - */ - private $checkImplicitMixed = false; + private bool $checkImplicitMixed = false; - /** - * @var int - */ - private $phpVersion = PHP_VERSION_ID; + private int $phpVersion = PHP_VERSION_ID; protected function getRule(): Rule { $reflectionProvider = $this->createReflectionProvider(); $ruleLevelHelper = new RuleLevelHelper($reflectionProvider, $this->checkNullables, $this->checkThisOnly, $this->checkUnionTypes, $this->checkExplicitMixed, $this->checkImplicitMixed, true, false); - return new CallMethodsRule(new MethodCallCheck($reflectionProvider, $ruleLevelHelper, true, true), new FunctionCallParametersCheck($ruleLevelHelper, new NullsafeCheck(), new PhpVersion($this->phpVersion), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true, true)); + return new CallMethodsRule( + new MethodCallCheck($reflectionProvider, $ruleLevelHelper, true, true), + new FunctionCallParametersCheck($ruleLevelHelper, new NullsafeCheck(), new PhpVersion($this->phpVersion), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true, true), + ); } public function testIsCallablePhp7(): void diff --git a/tests/PHPStan/Rules/Methods/CallStaticMethodsRuleTest.php b/tests/PHPStan/Rules/Methods/CallStaticMethodsRuleTest.php index d29e1ef1130..4f0c0681cf7 100644 --- a/tests/PHPStan/Rules/Methods/CallStaticMethodsRuleTest.php +++ b/tests/PHPStan/Rules/Methods/CallStaticMethodsRuleTest.php @@ -21,26 +21,20 @@ class CallStaticMethodsRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $checkThisOnly; + private bool $checkThisOnly; - /** - * @var bool - */ - private $checkExplicitMixed = false; + private bool $checkExplicitMixed = false; - /** - * @var bool - */ - private $checkImplicitMixed = false; + private bool $checkImplicitMixed = false; protected function getRule(): Rule { $reflectionProvider = $this->createReflectionProvider(); $ruleLevelHelper = new RuleLevelHelper($reflectionProvider, true, $this->checkThisOnly, true, $this->checkExplicitMixed, $this->checkImplicitMixed, true, false); - return new CallStaticMethodsRule(new StaticMethodCallCheck($reflectionProvider, $ruleLevelHelper, new ClassCaseSensitivityCheck($reflectionProvider, true), true, true), new FunctionCallParametersCheck($ruleLevelHelper, new NullsafeCheck(), new PhpVersion(80000), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true, true)); + return new CallStaticMethodsRule( + new StaticMethodCallCheck($reflectionProvider, $ruleLevelHelper, new ClassCaseSensitivityCheck($reflectionProvider, true), true, true), + new FunctionCallParametersCheck($ruleLevelHelper, new NullsafeCheck(), new PhpVersion(80000), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true, true), + ); } public function testCallStaticMethods(): void @@ -695,9 +689,7 @@ public function dataMixed(): array ], ]; $combinedErrors = array_merge($explicitOnlyErrors, $implicitOnlyErrors); - usort($combinedErrors, static function (array $a, array $b) : int { - return $a[1] <=> $b[1]; - }); + usort($combinedErrors, static fn (array $a, array $b): int => $a[1] <=> $b[1]); return [ [ diff --git a/tests/PHPStan/Rules/Methods/CallToStaticMethodStatementWithoutSideEffectsRuleTest.php b/tests/PHPStan/Rules/Methods/CallToStaticMethodStatementWithoutSideEffectsRuleTest.php index 295ed4fe4b2..324e3c33c73 100644 --- a/tests/PHPStan/Rules/Methods/CallToStaticMethodStatementWithoutSideEffectsRuleTest.php +++ b/tests/PHPStan/Rules/Methods/CallToStaticMethodStatementWithoutSideEffectsRuleTest.php @@ -15,7 +15,10 @@ class CallToStaticMethodStatementWithoutSideEffectsRuleTest extends RuleTestCase protected function getRule(): Rule { $broker = $this->createReflectionProvider(); - return new CallToStaticMethodStatementWithoutSideEffectsRule(new RuleLevelHelper($broker, true, false, true, false, false, true, false), $broker); + return new CallToStaticMethodStatementWithoutSideEffectsRule( + new RuleLevelHelper($broker, true, false, true, false, false, true, false), + $broker, + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Methods/ConsistentConstructorRuleTest.php b/tests/PHPStan/Rules/Methods/ConsistentConstructorRuleTest.php index 3c8ca01b7c1..4ea2484ef5e 100644 --- a/tests/PHPStan/Rules/Methods/ConsistentConstructorRuleTest.php +++ b/tests/PHPStan/Rules/Methods/ConsistentConstructorRuleTest.php @@ -40,7 +40,10 @@ public function testRule(): void public function testRuleNoErrors(): void { - $this->analyse([__DIR__ . '/data/consistent-constructor-no-errors.php'], PHP_VERSION_ID < 70400 ? [['Parameter #1 $b (ConsistentConstructorNoErrors\A) of method ConsistentConstructorNoErrors\Baz::__construct() is not compatible with parameter #1 $b (ConsistentConstructorNoErrors\B) of method ConsistentConstructorNoErrors\Foo::__construct().', 49]] : []); + $this->analyse( + [__DIR__ . '/data/consistent-constructor-no-errors.php'], + PHP_VERSION_ID < 70400 ? [['Parameter #1 $b (ConsistentConstructorNoErrors\A) of method ConsistentConstructorNoErrors\Baz::__construct() is not compatible with parameter #1 $b (ConsistentConstructorNoErrors\B) of method ConsistentConstructorNoErrors\Foo::__construct().', 49]] : [], + ); } } diff --git a/tests/PHPStan/Rules/Methods/ExistingClassesInTypehintsRuleTest.php b/tests/PHPStan/Rules/Methods/ExistingClassesInTypehintsRuleTest.php index 0854e650697..fd8e406297e 100644 --- a/tests/PHPStan/Rules/Methods/ExistingClassesInTypehintsRuleTest.php +++ b/tests/PHPStan/Rules/Methods/ExistingClassesInTypehintsRuleTest.php @@ -16,10 +16,7 @@ class ExistingClassesInTypehintsRuleTest extends RuleTestCase { - /** - * @var int - */ - private $phpVersionId = PHP_VERSION_ID; + private int $phpVersionId = PHP_VERSION_ID; protected function getRule(): Rule { diff --git a/tests/PHPStan/Rules/Methods/FinalPrivateMethodRuleTest.php b/tests/PHPStan/Rules/Methods/FinalPrivateMethodRuleTest.php index c8996763852..64a4b89c0f9 100644 --- a/tests/PHPStan/Rules/Methods/FinalPrivateMethodRuleTest.php +++ b/tests/PHPStan/Rules/Methods/FinalPrivateMethodRuleTest.php @@ -10,14 +10,13 @@ class FinalPrivateMethodRuleTest extends RuleTestCase { - /** - * @var int - */ - private $phpVersionId; + private int $phpVersionId; protected function getRule(): Rule { - return new FinalPrivateMethodRule(new PhpVersion($this->phpVersionId)); + return new FinalPrivateMethodRule( + new PhpVersion($this->phpVersionId), + ); } public function dataRule(): array diff --git a/tests/PHPStan/Rules/Methods/MethodAttributesRuleTest.php b/tests/PHPStan/Rules/Methods/MethodAttributesRuleTest.php index 3f2450aa82c..325115301c1 100644 --- a/tests/PHPStan/Rules/Methods/MethodAttributesRuleTest.php +++ b/tests/PHPStan/Rules/Methods/MethodAttributesRuleTest.php @@ -19,15 +19,30 @@ class MethodAttributesRuleTest extends RuleTestCase { - /** - * @var int - */ - private $phpVersion; + private int $phpVersion; protected function getRule(): Rule { $reflectionProvider = $this->createReflectionProvider(); - return new MethodAttributesRule(new AttributesCheck($reflectionProvider, new FunctionCallParametersCheck(new RuleLevelHelper($reflectionProvider, true, false, true, false, false, true, false), new NullsafeCheck(), new PhpVersion($this->phpVersion), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true, true), new ClassCaseSensitivityCheck($reflectionProvider, false), true)); + return new MethodAttributesRule( + new AttributesCheck( + $reflectionProvider, + new FunctionCallParametersCheck( + new RuleLevelHelper($reflectionProvider, true, false, true, false, false, true, false), + new NullsafeCheck(), + new PhpVersion($this->phpVersion), + new UnresolvableTypeHelper(), + new PropertyReflectionFinder(), + true, + true, + true, + true, + true, + ), + new ClassCaseSensitivityCheck($reflectionProvider, false), + true, + ), + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Methods/MethodCallableRuleTest.php b/tests/PHPStan/Rules/Methods/MethodCallableRuleTest.php index 2a52caa35e9..b5bc1f8efb2 100644 --- a/tests/PHPStan/Rules/Methods/MethodCallableRuleTest.php +++ b/tests/PHPStan/Rules/Methods/MethodCallableRuleTest.php @@ -14,17 +14,17 @@ class MethodCallableRuleTest extends RuleTestCase { - /** - * @var int - */ - private $phpVersion = PHP_VERSION_ID; + private int $phpVersion = PHP_VERSION_ID; protected function getRule(): Rule { $reflectionProvider = $this->createReflectionProvider(); $ruleLevelHelper = new RuleLevelHelper($reflectionProvider, true, false, true, false, false, true, false); - return new MethodCallableRule(new MethodCallCheck($reflectionProvider, $ruleLevelHelper, true, true), new PhpVersion($this->phpVersion)); + return new MethodCallableRule( + new MethodCallCheck($reflectionProvider, $ruleLevelHelper, true, true), + new PhpVersion($this->phpVersion), + ); } public function testNotSupportedOnOlderVersions(): void diff --git a/tests/PHPStan/Rules/Methods/MethodSignatureRuleTest.php b/tests/PHPStan/Rules/Methods/MethodSignatureRuleTest.php index 3c1fb61270b..93c6a67b9d2 100644 --- a/tests/PHPStan/Rules/Methods/MethodSignatureRuleTest.php +++ b/tests/PHPStan/Rules/Methods/MethodSignatureRuleTest.php @@ -14,15 +14,9 @@ class MethodSignatureRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $reportMaybes; + private bool $reportMaybes; - /** - * @var bool - */ - private $reportStatic; + private bool $reportStatic; protected function getRule(): Rule { @@ -30,16 +24,27 @@ protected function getRule(): Rule $phpClassReflectionExtension = self::getContainer()->getByType(PhpClassReflectionExtension::class); - return new OverridingMethodRule($phpVersion, new MethodSignatureRule($phpClassReflectionExtension, $this->reportMaybes, $this->reportStatic, true), true, new MethodParameterComparisonHelper($phpVersion, true), $phpClassReflectionExtension, true, true, false); + return new OverridingMethodRule( + $phpVersion, + new MethodSignatureRule($phpClassReflectionExtension, $this->reportMaybes, $this->reportStatic, true), + true, + new MethodParameterComparisonHelper($phpVersion, true), + $phpClassReflectionExtension, + true, + true, + false, + ); } public function testReturnTypeRule(): void { $this->reportMaybes = true; $this->reportStatic = true; - $this->analyse([ + $this->analyse( + [ __DIR__ . '/data/method-signature.php', - ], [ + ], + [ [ 'Parameter #1 $animal (MethodSignature\Dog) of method MethodSignature\SubClass::parameterTypeTest4() should be contravariant with parameter $animal (MethodSignature\Animal) of method MethodSignature\BaseClass::parameterTypeTest4()', 298, @@ -76,16 +81,19 @@ public function testReturnTypeRule(): void 'Parameter #1 $node (PhpParser\Node\Expr\StaticCall) of method MethodSignature\Rule::processNode() should be contravariant with parameter $node (PhpParser\Node) of method MethodSignature\GenericRule::processNode()', 454, ], - ]); + ], + ); } public function testReturnTypeRuleTrait(): void { $this->reportMaybes = true; $this->reportStatic = true; - $this->analyse([ + $this->analyse( + [ __DIR__ . '/data/method-signature-trait.php', - ], [ + ], + [ [ 'Parameter #1 $animal (MethodSignature\Dog) of method MethodSignature\SubClassUsingTrait::parameterTypeTest4() should be contravariant with parameter $animal (MethodSignature\Animal) of method MethodSignature\BaseClass::parameterTypeTest4()', 43, @@ -118,16 +126,19 @@ public function testReturnTypeRuleTrait(): void 'Return type (MethodSignature\Cat) of method MethodSignature\SubClassUsingTrait::returnTypeTest5() should be compatible with return type (MethodSignature\Dog) of method MethodSignature\BaseInterface::returnTypeTest5()', 103, ], - ]); + ], + ); } public function testReturnTypeRuleTraitWithoutMaybes(): void { $this->reportMaybes = false; $this->reportStatic = true; - $this->analyse([ + $this->analyse( + [ __DIR__ . '/data/method-signature-trait.php', - ], [ + ], + [ [ 'Parameter #1 $animal (MethodSignature\Dog) of method MethodSignature\SubClassUsingTrait::parameterTypeTest5() should be compatible with parameter $animal (MethodSignature\Cat) of method MethodSignature\BaseClass::parameterTypeTest5()', 50, @@ -144,16 +155,19 @@ public function testReturnTypeRuleTraitWithoutMaybes(): void 'Return type (MethodSignature\Cat) of method MethodSignature\SubClassUsingTrait::returnTypeTest5() should be compatible with return type (MethodSignature\Dog) of method MethodSignature\BaseInterface::returnTypeTest5()', 103, ], - ]); + ], + ); } public function testReturnTypeRuleWithoutMaybes(): void { $this->reportMaybes = false; $this->reportStatic = true; - $this->analyse([ + $this->analyse( + [ __DIR__ . '/data/method-signature.php', - ], [ + ], + [ [ 'Parameter #1 $animal (MethodSignature\Dog) of method MethodSignature\SubClass::parameterTypeTest5() should be compatible with parameter $animal (MethodSignature\Cat) of method MethodSignature\BaseClass::parameterTypeTest5()', 305, @@ -170,7 +184,8 @@ public function testReturnTypeRuleWithoutMaybes(): void 'Return type (MethodSignature\Cat) of method MethodSignature\SubClass::returnTypeTest5() should be compatible with return type (MethodSignature\Dog) of method MethodSignature\BaseInterface::returnTypeTest5()', 358, ], - ]); + ], + ); } public function testRuleWithoutStaticMethods(): void diff --git a/tests/PHPStan/Rules/Methods/OverridingMethodRuleTest.php b/tests/PHPStan/Rules/Methods/OverridingMethodRuleTest.php index 2c6fabf363c..7f83d1cdea4 100644 --- a/tests/PHPStan/Rules/Methods/OverridingMethodRuleTest.php +++ b/tests/PHPStan/Rules/Methods/OverridingMethodRuleTest.php @@ -16,15 +16,9 @@ class OverridingMethodRuleTest extends RuleTestCase { - /** - * @var int - */ - private $phpVersionId; + private int $phpVersionId; - /** - * @var bool - */ - private $checkMissingOverrideMethodAttribute = false; + private bool $checkMissingOverrideMethodAttribute = false; protected function getRule(): Rule { @@ -32,7 +26,16 @@ protected function getRule(): Rule $phpClassReflectionExtension = self::getContainer()->getByType(PhpClassReflectionExtension::class); - return new OverridingMethodRule($phpVersion, new MethodSignatureRule($phpClassReflectionExtension, true, true, true), false, new MethodParameterComparisonHelper($phpVersion, true), $phpClassReflectionExtension, true, true, $this->checkMissingOverrideMethodAttribute); + return new OverridingMethodRule( + $phpVersion, + new MethodSignatureRule($phpClassReflectionExtension, true, true, true), + false, + new MethodParameterComparisonHelper($phpVersion, true), + $phpClassReflectionExtension, + true, + true, + $this->checkMissingOverrideMethodAttribute, + ); } public function dataOverridingFinalMethod(): array @@ -136,9 +139,7 @@ public function testOverridingFinalMethod(int $phpVersion, string $contravariant ]; if (PHP_VERSION_ID >= 80000) { - $errors = array_values(array_filter($errors, static function (array $error) : bool { - return $error[1] !== 125; - })); + $errors = array_values(array_filter($errors, static fn (array $error): bool => $error[1] !== 125)); } $this->phpVersionId = $phpVersion; @@ -231,7 +232,11 @@ public function dataParameterContravariance(): array * @dataProvider dataParameterContravariance * @param list $expectedErrors */ - public function testParameterContravariance(string $file, int $phpVersion, array $expectedErrors) : void + public function testParameterContravariance( + string $file, + int $phpVersion, + array $expectedErrors, + ): void { $this->phpVersionId = $phpVersion; $this->analyse([$file], $expectedErrors); @@ -285,7 +290,10 @@ public function dataReturnTypeCovariance(): array * @dataProvider dataReturnTypeCovariance * @param list $expectedErrors */ - public function testReturnTypeCovariance(int $phpVersion, array $expectedErrors) : void + public function testReturnTypeCovariance( + int $phpVersion, + array $expectedErrors, + ): void { $this->phpVersionId = $phpVersion; $this->analyse([__DIR__ . '/data/return-type-covariance.php'], $expectedErrors); diff --git a/tests/PHPStan/Rules/Methods/ReturnTypeRuleTest.php b/tests/PHPStan/Rules/Methods/ReturnTypeRuleTest.php index 7c099825dab..0939b3fca93 100644 --- a/tests/PHPStan/Rules/Methods/ReturnTypeRuleTest.php +++ b/tests/PHPStan/Rules/Methods/ReturnTypeRuleTest.php @@ -14,20 +14,11 @@ class ReturnTypeRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $checkExplicitMixed = false; + private bool $checkExplicitMixed = false; - /** - * @var bool - */ - private $checkUnionTypes = true; + private bool $checkUnionTypes = true; - /** - * @var bool - */ - private $checkBenevolentUnionTypes = false; + private bool $checkBenevolentUnionTypes = false; protected function getRule(): Rule { diff --git a/tests/PHPStan/Rules/Methods/StaticMethodCallableRuleTest.php b/tests/PHPStan/Rules/Methods/StaticMethodCallableRuleTest.php index 6a597a5aa26..0f5b3087ed4 100644 --- a/tests/PHPStan/Rules/Methods/StaticMethodCallableRuleTest.php +++ b/tests/PHPStan/Rules/Methods/StaticMethodCallableRuleTest.php @@ -15,17 +15,17 @@ class StaticMethodCallableRuleTest extends RuleTestCase { - /** - * @var int - */ - private $phpVersion = PHP_VERSION_ID; + private int $phpVersion = PHP_VERSION_ID; protected function getRule(): Rule { $reflectionProvider = $this->createReflectionProvider(); $ruleLevelHelper = new RuleLevelHelper($reflectionProvider, true, false, true, false, false, true, false); - return new StaticMethodCallableRule(new StaticMethodCallCheck($reflectionProvider, $ruleLevelHelper, new ClassCaseSensitivityCheck($reflectionProvider, true), true, true), new PhpVersion($this->phpVersion)); + return new StaticMethodCallableRule( + new StaticMethodCallCheck($reflectionProvider, $ruleLevelHelper, new ClassCaseSensitivityCheck($reflectionProvider, true), true, true), + new PhpVersion($this->phpVersion), + ); } public function testNotSupportedOnOlderVersions(): void diff --git a/tests/PHPStan/Rules/Missing/MissingReturnRuleTest.php b/tests/PHPStan/Rules/Missing/MissingReturnRuleTest.php index 33a6f67f590..377a296017e 100644 --- a/tests/PHPStan/Rules/Missing/MissingReturnRuleTest.php +++ b/tests/PHPStan/Rules/Missing/MissingReturnRuleTest.php @@ -12,15 +12,9 @@ class MissingReturnRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $checkExplicitMixedMissingReturn; + private bool $checkExplicitMixedMissingReturn; - /** - * @var bool - */ - private $checkPhpDocMissingReturn = true; + private bool $checkPhpDocMissingReturn = true; protected function getRule(): Rule { diff --git a/tests/PHPStan/Rules/Operators/InvalidBinaryOperationRuleTest.php b/tests/PHPStan/Rules/Operators/InvalidBinaryOperationRuleTest.php index 9cc8204b172..7729265a856 100644 --- a/tests/PHPStan/Rules/Operators/InvalidBinaryOperationRuleTest.php +++ b/tests/PHPStan/Rules/Operators/InvalidBinaryOperationRuleTest.php @@ -17,7 +17,10 @@ class InvalidBinaryOperationRuleTest extends RuleTestCase protected function getRule(): Rule { - return new InvalidBinaryOperationRule(new ExprPrinter(new Printer()), new RuleLevelHelper($this->createReflectionProvider(), true, false, true, false, false, true, false)); + return new InvalidBinaryOperationRule( + new ExprPrinter(new Printer()), + new RuleLevelHelper($this->createReflectionProvider(), true, false, true, false, false, true, false), + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Operators/InvalidComparisonOperationRuleTest.php b/tests/PHPStan/Rules/Operators/InvalidComparisonOperationRuleTest.php index ea3f0dd5861..3221658bc46 100644 --- a/tests/PHPStan/Rules/Operators/InvalidComparisonOperationRuleTest.php +++ b/tests/PHPStan/Rules/Operators/InvalidComparisonOperationRuleTest.php @@ -15,7 +15,9 @@ class InvalidComparisonOperationRuleTest extends RuleTestCase protected function getRule(): Rule { - return new InvalidComparisonOperationRule(new RuleLevelHelper($this->createReflectionProvider(), true, false, true, false, false, true, false)); + return new InvalidComparisonOperationRule( + new RuleLevelHelper($this->createReflectionProvider(), true, false, true, false, false, true, false), + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/PhpDoc/IncompatiblePhpDocTypeRuleTest.php b/tests/PHPStan/Rules/PhpDoc/IncompatiblePhpDocTypeRuleTest.php index 3049298e30a..439c68f90fd 100644 --- a/tests/PHPStan/Rules/PhpDoc/IncompatiblePhpDocTypeRuleTest.php +++ b/tests/PHPStan/Rules/PhpDoc/IncompatiblePhpDocTypeRuleTest.php @@ -16,7 +16,11 @@ class IncompatiblePhpDocTypeRuleTest extends RuleTestCase protected function getRule(): Rule { - return new IncompatiblePhpDocTypeRule(self::getContainer()->getByType(FileTypeMapper::class), new GenericObjectTypeCheck(), new UnresolvableTypeHelper()); + return new IncompatiblePhpDocTypeRule( + self::getContainer()->getByType(FileTypeMapper::class), + new GenericObjectTypeCheck(), + new UnresolvableTypeHelper(), + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/PhpDoc/IncompatiblePropertyPhpDocTypeRuleTest.php b/tests/PHPStan/Rules/PhpDoc/IncompatiblePropertyPhpDocTypeRuleTest.php index 2e939ed6de3..5f68803d9d0 100644 --- a/tests/PHPStan/Rules/PhpDoc/IncompatiblePropertyPhpDocTypeRuleTest.php +++ b/tests/PHPStan/Rules/PhpDoc/IncompatiblePropertyPhpDocTypeRuleTest.php @@ -14,7 +14,10 @@ class IncompatiblePropertyPhpDocTypeRuleTest extends RuleTestCase protected function getRule(): Rule { - return new IncompatiblePropertyPhpDocTypeRule(new GenericObjectTypeCheck(), new UnresolvableTypeHelper()); + return new IncompatiblePropertyPhpDocTypeRule( + new GenericObjectTypeCheck(), + new UnresolvableTypeHelper(), + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/PhpDoc/InvalidPHPStanDocTagRuleTest.php b/tests/PHPStan/Rules/PhpDoc/InvalidPHPStanDocTagRuleTest.php index 81144245195..7995c696f47 100644 --- a/tests/PHPStan/Rules/PhpDoc/InvalidPHPStanDocTagRuleTest.php +++ b/tests/PHPStan/Rules/PhpDoc/InvalidPHPStanDocTagRuleTest.php @@ -14,14 +14,15 @@ class InvalidPHPStanDocTagRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $checkAllInvalidPhpDocs; + private bool $checkAllInvalidPhpDocs; protected function getRule(): Rule { - return new InvalidPHPStanDocTagRule(self::getContainer()->getByType(Lexer::class), self::getContainer()->getByType(PhpDocParser::class), $this->checkAllInvalidPhpDocs); + return new InvalidPHPStanDocTagRule( + self::getContainer()->getByType(Lexer::class), + self::getContainer()->getByType(PhpDocParser::class), + $this->checkAllInvalidPhpDocs, + ); } public function dataRule(): iterable diff --git a/tests/PHPStan/Rules/PhpDoc/InvalidPhpDocTagValueRuleNoBleedingEdgeTest.php b/tests/PHPStan/Rules/PhpDoc/InvalidPhpDocTagValueRuleNoBleedingEdgeTest.php index 45d9b0ff5b6..f8158edb1e9 100644 --- a/tests/PHPStan/Rules/PhpDoc/InvalidPhpDocTagValueRuleNoBleedingEdgeTest.php +++ b/tests/PHPStan/Rules/PhpDoc/InvalidPhpDocTagValueRuleNoBleedingEdgeTest.php @@ -14,14 +14,16 @@ class InvalidPhpDocTagValueRuleNoBleedingEdgeTest extends RuleTestCase { - /** - * @var bool - */ - private $checkAllInvalidPhpDocs; + private bool $checkAllInvalidPhpDocs; protected function getRule(): Rule { - return new InvalidPhpDocTagValueRule(self::getContainer()->getByType(Lexer::class), self::getContainer()->getByType(PhpDocParser::class), $this->checkAllInvalidPhpDocs, false); + return new InvalidPhpDocTagValueRule( + self::getContainer()->getByType(Lexer::class), + self::getContainer()->getByType(PhpDocParser::class), + $this->checkAllInvalidPhpDocs, + false, + ); } public function dataRule(): iterable diff --git a/tests/PHPStan/Rules/PhpDoc/InvalidPhpDocTagValueRuleTest.php b/tests/PHPStan/Rules/PhpDoc/InvalidPhpDocTagValueRuleTest.php index d9c1d5d43f4..c726559432c 100644 --- a/tests/PHPStan/Rules/PhpDoc/InvalidPhpDocTagValueRuleTest.php +++ b/tests/PHPStan/Rules/PhpDoc/InvalidPhpDocTagValueRuleTest.php @@ -14,14 +14,16 @@ class InvalidPhpDocTagValueRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $checkAllInvalidPhpDocs; + private bool $checkAllInvalidPhpDocs; protected function getRule(): Rule { - return new InvalidPhpDocTagValueRule(self::getContainer()->getByType(Lexer::class), self::getContainer()->getByType(PhpDocParser::class), $this->checkAllInvalidPhpDocs, true); + return new InvalidPhpDocTagValueRule( + self::getContainer()->getByType(Lexer::class), + self::getContainer()->getByType(PhpDocParser::class), + $this->checkAllInvalidPhpDocs, + true, + ); } public function dataRule(): iterable diff --git a/tests/PHPStan/Rules/PhpDoc/InvalidPhpDocVarTagTypeRuleTest.php b/tests/PHPStan/Rules/PhpDoc/InvalidPhpDocVarTagTypeRuleTest.php index a2372ccbfc4..7adb36a7d5a 100644 --- a/tests/PHPStan/Rules/PhpDoc/InvalidPhpDocVarTagTypeRuleTest.php +++ b/tests/PHPStan/Rules/PhpDoc/InvalidPhpDocVarTagTypeRuleTest.php @@ -19,7 +19,16 @@ class InvalidPhpDocVarTagTypeRuleTest extends RuleTestCase protected function getRule(): Rule { $broker = $this->createReflectionProvider(); - return new InvalidPhpDocVarTagTypeRule(self::getContainer()->getByType(FileTypeMapper::class), $broker, new ClassCaseSensitivityCheck($broker, true), new GenericObjectTypeCheck(), new MissingTypehintCheck(true, true, true, true, []), new UnresolvableTypeHelper(), true, true); + return new InvalidPhpDocVarTagTypeRule( + self::getContainer()->getByType(FileTypeMapper::class), + $broker, + new ClassCaseSensitivityCheck($broker, true), + new GenericObjectTypeCheck(), + new MissingTypehintCheck(true, true, true, true, []), + new UnresolvableTypeHelper(), + true, + true, + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/PhpDoc/InvalidThrowsPhpDocValueRuleTest.php b/tests/PHPStan/Rules/PhpDoc/InvalidThrowsPhpDocValueRuleTest.php index c30f156f595..2328aeb0d74 100644 --- a/tests/PHPStan/Rules/PhpDoc/InvalidThrowsPhpDocValueRuleTest.php +++ b/tests/PHPStan/Rules/PhpDoc/InvalidThrowsPhpDocValueRuleTest.php @@ -123,7 +123,11 @@ public function dataMergeInheritedPhpDocs(): array /** * @dataProvider dataMergeInheritedPhpDocs */ - public function testMergeInheritedPhpDocs(string $className, string $method, string $expectedType) : void + public function testMergeInheritedPhpDocs( + string $className, + string $method, + string $expectedType, + ): void { $reflectionProvider = $this->createReflectionProvider(); $reflection = $reflectionProvider->getClass($className); diff --git a/tests/PHPStan/Rules/PhpDoc/RequireExtendsDefinitionClassRuleTest.php b/tests/PHPStan/Rules/PhpDoc/RequireExtendsDefinitionClassRuleTest.php index da1e8caf596..c07d216650b 100644 --- a/tests/PHPStan/Rules/PhpDoc/RequireExtendsDefinitionClassRuleTest.php +++ b/tests/PHPStan/Rules/PhpDoc/RequireExtendsDefinitionClassRuleTest.php @@ -17,7 +17,12 @@ protected function getRule(): Rule { $reflectionProvider = $this->createReflectionProvider(); - return new RequireExtendsDefinitionClassRule(new RequireExtendsCheck(new ClassCaseSensitivityCheck($reflectionProvider, true), true)); + return new RequireExtendsDefinitionClassRule( + new RequireExtendsCheck( + new ClassCaseSensitivityCheck($reflectionProvider, true), + true, + ), + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/PhpDoc/RequireExtendsDefinitionTraitRuleTest.php b/tests/PHPStan/Rules/PhpDoc/RequireExtendsDefinitionTraitRuleTest.php index 30bfd35cba3..39676e8db8f 100644 --- a/tests/PHPStan/Rules/PhpDoc/RequireExtendsDefinitionTraitRuleTest.php +++ b/tests/PHPStan/Rules/PhpDoc/RequireExtendsDefinitionTraitRuleTest.php @@ -16,7 +16,13 @@ protected function getRule(): Rule { $reflectionProvider = $this->createReflectionProvider(); - return new RequireExtendsDefinitionTraitRule($reflectionProvider, new RequireExtendsCheck(new ClassCaseSensitivityCheck($reflectionProvider, true), true)); + return new RequireExtendsDefinitionTraitRule( + $reflectionProvider, + new RequireExtendsCheck( + new ClassCaseSensitivityCheck($reflectionProvider, true), + true, + ), + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/PhpDoc/RequireImplementsDefinitionTraitRuleTest.php b/tests/PHPStan/Rules/PhpDoc/RequireImplementsDefinitionTraitRuleTest.php index 49d1ddde1c9..495de2a5985 100644 --- a/tests/PHPStan/Rules/PhpDoc/RequireImplementsDefinitionTraitRuleTest.php +++ b/tests/PHPStan/Rules/PhpDoc/RequireImplementsDefinitionTraitRuleTest.php @@ -17,7 +17,11 @@ protected function getRule(): Rule { $reflectionProvider = $this->createReflectionProvider(); - return new RequireImplementsDefinitionTraitRule($reflectionProvider, new ClassCaseSensitivityCheck($reflectionProvider, true), true); + return new RequireImplementsDefinitionTraitRule( + $reflectionProvider, + new ClassCaseSensitivityCheck($reflectionProvider, true), + true, + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/PhpDoc/WrongVariableNameInVarTagRuleTest.php b/tests/PHPStan/Rules/PhpDoc/WrongVariableNameInVarTagRuleTest.php index 4ac07dec918..959a87c8475 100644 --- a/tests/PHPStan/Rules/PhpDoc/WrongVariableNameInVarTagRuleTest.php +++ b/tests/PHPStan/Rules/PhpDoc/WrongVariableNameInVarTagRuleTest.php @@ -13,19 +13,17 @@ class WrongVariableNameInVarTagRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $checkTypeAgainstNativeType = false; + private bool $checkTypeAgainstNativeType = false; - /** - * @var bool - */ - private $checkTypeAgainstPhpDocType = false; + private bool $checkTypeAgainstPhpDocType = false; protected function getRule(): Rule { - return new WrongVariableNameInVarTagRule(self::getContainer()->getByType(FileTypeMapper::class), new VarTagTypeRuleHelper($this->checkTypeAgainstPhpDocType), $this->checkTypeAgainstNativeType); + return new WrongVariableNameInVarTagRule( + self::getContainer()->getByType(FileTypeMapper::class), + new VarTagTypeRuleHelper($this->checkTypeAgainstPhpDocType), + $this->checkTypeAgainstNativeType, + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Properties/AccessPropertiesInAssignRuleTest.php b/tests/PHPStan/Rules/Properties/AccessPropertiesInAssignRuleTest.php index 481469f165d..9b700049950 100644 --- a/tests/PHPStan/Rules/Properties/AccessPropertiesInAssignRuleTest.php +++ b/tests/PHPStan/Rules/Properties/AccessPropertiesInAssignRuleTest.php @@ -16,7 +16,9 @@ class AccessPropertiesInAssignRuleTest extends RuleTestCase protected function getRule(): Rule { $reflectionProvider = $this->createReflectionProvider(); - return new AccessPropertiesInAssignRule(new AccessPropertiesRule($reflectionProvider, new RuleLevelHelper($reflectionProvider, true, false, true, false, false, true, false), true, true)); + return new AccessPropertiesInAssignRule( + new AccessPropertiesRule($reflectionProvider, new RuleLevelHelper($reflectionProvider, true, false, true, false, false, true, false), true, true), + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Properties/AccessPropertiesRuleTest.php b/tests/PHPStan/Rules/Properties/AccessPropertiesRuleTest.php index 33bc10da2f0..46734098804 100644 --- a/tests/PHPStan/Rules/Properties/AccessPropertiesRuleTest.php +++ b/tests/PHPStan/Rules/Properties/AccessPropertiesRuleTest.php @@ -14,20 +14,11 @@ class AccessPropertiesRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $checkThisOnly; + private bool $checkThisOnly; - /** - * @var bool - */ - private $checkUnionTypes; + private bool $checkUnionTypes; - /** - * @var bool - */ - private $checkDynamicProperties; + private bool $checkDynamicProperties; protected function getRule(): Rule { @@ -42,7 +33,9 @@ public function testAccessProperties(): void $this->checkDynamicProperties = false; $tipText = 'Learn more: https://phpstan.org/blog/solving-phpstan-access-to-undefined-property'; - $this->analyse([__DIR__ . '/data/access-properties.php'], [ + $this->analyse( + [__DIR__ . '/data/access-properties.php'], + [ [ 'Access to an undefined property TestAccessProperties\BarAccessProperties::$loremipsum.', 24, @@ -176,7 +169,8 @@ public function testAccessProperties(): void 'Cannot access property $selfOrNull on TestAccessProperties\RevertNonNullabilityForIsset|null.', 407, ], - ]); + ], + ); } public function testAccessPropertiesWithoutUnionTypes(): void @@ -186,7 +180,9 @@ public function testAccessPropertiesWithoutUnionTypes(): void $this->checkDynamicProperties = false; $tipText = 'Learn more: https://phpstan.org/blog/solving-phpstan-access-to-undefined-property'; - $this->analyse([__DIR__ . '/data/access-properties.php'], [ + $this->analyse( + [__DIR__ . '/data/access-properties.php'], + [ [ 'Access to an undefined property TestAccessProperties\BarAccessProperties::$loremipsum.', 24, @@ -299,7 +295,8 @@ public function testAccessPropertiesWithoutUnionTypes(): void 302, $tipText, ], - ]); + ], + ); } public function testRuleAssignOp(): void @@ -328,7 +325,9 @@ public function testAccessPropertiesOnThisOnly(): void $this->checkDynamicProperties = false; $tipText = 'Learn more: https://phpstan.org/blog/solving-phpstan-access-to-undefined-property'; - $this->analyse([__DIR__ . '/data/access-properties.php'], [ + $this->analyse( + [__DIR__ . '/data/access-properties.php'], + [ [ 'Access to an undefined property TestAccessProperties\BarAccessProperties::$loremipsum.', 24, @@ -338,7 +337,8 @@ public function testAccessPropertiesOnThisOnly(): void 'Access to private property $foo of parent class TestAccessProperties\FooAccessProperties.', 25, ], - ]); + ], + ); } public function testAccessPropertiesAfterIsNullInBooleanOr(): void diff --git a/tests/PHPStan/Rules/Properties/AccessStaticPropertiesInAssignRuleTest.php b/tests/PHPStan/Rules/Properties/AccessStaticPropertiesInAssignRuleTest.php index aed325bed68..174d06ad241 100644 --- a/tests/PHPStan/Rules/Properties/AccessStaticPropertiesInAssignRuleTest.php +++ b/tests/PHPStan/Rules/Properties/AccessStaticPropertiesInAssignRuleTest.php @@ -17,7 +17,9 @@ class AccessStaticPropertiesInAssignRuleTest extends RuleTestCase protected function getRule(): Rule { $reflectionProvider = $this->createReflectionProvider(); - return new AccessStaticPropertiesInAssignRule(new AccessStaticPropertiesRule($reflectionProvider, new RuleLevelHelper($reflectionProvider, true, false, true, false, false, true, false), new ClassCaseSensitivityCheck($reflectionProvider, true))); + return new AccessStaticPropertiesInAssignRule( + new AccessStaticPropertiesRule($reflectionProvider, new RuleLevelHelper($reflectionProvider, true, false, true, false, false, true, false), new ClassCaseSensitivityCheck($reflectionProvider, true)), + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Properties/AccessStaticPropertiesRuleTest.php b/tests/PHPStan/Rules/Properties/AccessStaticPropertiesRuleTest.php index 70265d3d938..3b71c235fba 100644 --- a/tests/PHPStan/Rules/Properties/AccessStaticPropertiesRuleTest.php +++ b/tests/PHPStan/Rules/Properties/AccessStaticPropertiesRuleTest.php @@ -17,7 +17,11 @@ class AccessStaticPropertiesRuleTest extends RuleTestCase protected function getRule(): Rule { $reflectionProvider = $this->createReflectionProvider(); - return new AccessStaticPropertiesRule($reflectionProvider, new RuleLevelHelper($reflectionProvider, true, false, true, false, false, true, false), new ClassCaseSensitivityCheck($reflectionProvider, true)); + return new AccessStaticPropertiesRule( + $reflectionProvider, + new RuleLevelHelper($reflectionProvider, true, false, true, false, false, true, false), + new ClassCaseSensitivityCheck($reflectionProvider, true), + ); } public function testAccessStaticProperties(): void diff --git a/tests/PHPStan/Rules/Properties/Bug7074Test.php b/tests/PHPStan/Rules/Properties/Bug7074Test.php index 532c292cf74..37486754903 100644 --- a/tests/PHPStan/Rules/Properties/Bug7074Test.php +++ b/tests/PHPStan/Rules/Properties/Bug7074Test.php @@ -30,7 +30,10 @@ public function testRule(): void public static function getAdditionalConfigFiles(): array { - return array_merge(parent::getAdditionalConfigFiles(), [__DIR__ . '/bug-7074.neon']); + return array_merge( + parent::getAdditionalConfigFiles(), + [__DIR__ . '/bug-7074.neon'], + ); } } diff --git a/tests/PHPStan/Rules/Properties/ExistingClassesInPropertiesRuleTest.php b/tests/PHPStan/Rules/Properties/ExistingClassesInPropertiesRuleTest.php index b11f2fb76d5..ee02ea4ac65 100644 --- a/tests/PHPStan/Rules/Properties/ExistingClassesInPropertiesRuleTest.php +++ b/tests/PHPStan/Rules/Properties/ExistingClassesInPropertiesRuleTest.php @@ -15,22 +15,28 @@ class ExistingClassesInPropertiesRuleTest extends RuleTestCase { - /** - * @var int - */ - private $phpVersion = PHP_VERSION_ID; + private int $phpVersion = PHP_VERSION_ID; protected function getRule(): Rule { $broker = $this->createReflectionProvider(); - return new ExistingClassesInPropertiesRule($broker, new ClassCaseSensitivityCheck($broker, true), new UnresolvableTypeHelper(), new PhpVersion($this->phpVersion), true, false); + return new ExistingClassesInPropertiesRule( + $broker, + new ClassCaseSensitivityCheck($broker, true), + new UnresolvableTypeHelper(), + new PhpVersion($this->phpVersion), + true, + false, + ); } public function testNonexistentClass(): void { - $this->analyse([ + $this->analyse( + [ __DIR__ . '/data/properties-types.php', - ], [ + ], + [ [ 'Property PropertiesTypes\Foo::$bar has unknown class PropertiesTypes\Bar as its type.', 12, @@ -83,7 +89,8 @@ public function testNonexistentClass(): void 33, 'Learn more at https://phpstan.org/user-guide/discovering-symbols', ], - ]); + ], + ); } public function testNativeTypes(): void diff --git a/tests/PHPStan/Rules/Properties/MissingReadOnlyByPhpDocPropertyAssignRuleTest.php b/tests/PHPStan/Rules/Properties/MissingReadOnlyByPhpDocPropertyAssignRuleTest.php index ba5d6e82f82..c7a90b03ab2 100644 --- a/tests/PHPStan/Rules/Properties/MissingReadOnlyByPhpDocPropertyAssignRuleTest.php +++ b/tests/PHPStan/Rules/Properties/MissingReadOnlyByPhpDocPropertyAssignRuleTest.php @@ -17,9 +17,14 @@ class MissingReadOnlyByPhpDocPropertyAssignRuleTest extends RuleTestCase protected function getRule(): Rule { - return new MissingReadOnlyByPhpDocPropertyAssignRule(new ConstructorsHelper(self::getContainer(), [ + return new MissingReadOnlyByPhpDocPropertyAssignRule( + new ConstructorsHelper( + self::getContainer(), + [ 'MissingReadOnlyPropertyAssignPhpDoc\\TestCase::setUp', - ])); + ], + ), + ); } protected function getReadWritePropertiesExtensions(): array diff --git a/tests/PHPStan/Rules/Properties/MissingReadOnlyPropertyAssignRuleTest.php b/tests/PHPStan/Rules/Properties/MissingReadOnlyPropertyAssignRuleTest.php index 89ebc7dded7..c07a25f502b 100644 --- a/tests/PHPStan/Rules/Properties/MissingReadOnlyPropertyAssignRuleTest.php +++ b/tests/PHPStan/Rules/Properties/MissingReadOnlyPropertyAssignRuleTest.php @@ -18,9 +18,14 @@ class MissingReadOnlyPropertyAssignRuleTest extends RuleTestCase protected function getRule(): Rule { - return new MissingReadOnlyPropertyAssignRule(new ConstructorsHelper(self::getContainer(), [ + return new MissingReadOnlyPropertyAssignRule( + new ConstructorsHelper( + self::getContainer(), + [ 'MissingReadOnlyPropertyAssign\\TestCase::setUp', - ])); + ], + ), + ); } protected function getReadWritePropertiesExtensions(): array diff --git a/tests/PHPStan/Rules/Properties/OverridingPropertyRuleTest.php b/tests/PHPStan/Rules/Properties/OverridingPropertyRuleTest.php index 59b09219964..dafac4e5f07 100644 --- a/tests/PHPStan/Rules/Properties/OverridingPropertyRuleTest.php +++ b/tests/PHPStan/Rules/Properties/OverridingPropertyRuleTest.php @@ -12,10 +12,7 @@ class OverridingPropertyRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $reportMaybes; + private bool $reportMaybes; protected function getRule(): Rule { @@ -93,15 +90,25 @@ public function testRule(): void [ 'PHPDoc type 4 of property OverridingProperty\Typed2WithPhpDoc::$foo is not the same as PHPDoc type 1|2|3 of overridden property OverridingProperty\TypedWithPhpDoc::$foo.', 158, - sprintf("You can fix 3rd party PHPDoc types with stub files:\n %s", 'https://phpstan.org/user-guide/stub-files'), + sprintf( + "You can fix 3rd party PHPDoc types with stub files:\n %s", + 'https://phpstan.org/user-guide/stub-files', + ), ], ]); } public function dataRulePHPDocTypes(): array { - $tip = sprintf("You can fix 3rd party PHPDoc types with stub files:\n %s", 'https://phpstan.org/user-guide/stub-files'); - $tipWithOption = sprintf("You can fix 3rd party PHPDoc types with stub files:\n %s\n This error can be turned off by setting\n %s", 'https://phpstan.org/user-guide/stub-files', 'reportMaybesInPropertyPhpDocTypes: false in your %configurationFile%.'); + $tip = sprintf( + "You can fix 3rd party PHPDoc types with stub files:\n %s", + 'https://phpstan.org/user-guide/stub-files', + ); + $tipWithOption = sprintf( + "You can fix 3rd party PHPDoc types with stub files:\n %s\n This error can be turned off by setting\n %s", + 'https://phpstan.org/user-guide/stub-files', + 'reportMaybesInPropertyPhpDocTypes: false in your %configurationFile%.', + ); return [ [ diff --git a/tests/PHPStan/Rules/Properties/PropertyAttributesRuleTest.php b/tests/PHPStan/Rules/Properties/PropertyAttributesRuleTest.php index e3a1efd3f38..f8e50f870ec 100644 --- a/tests/PHPStan/Rules/Properties/PropertyAttributesRuleTest.php +++ b/tests/PHPStan/Rules/Properties/PropertyAttributesRuleTest.php @@ -21,7 +21,25 @@ class PropertyAttributesRuleTest extends RuleTestCase protected function getRule(): Rule { $reflectionProvider = $this->createReflectionProvider(); - return new PropertyAttributesRule(new AttributesCheck($reflectionProvider, new FunctionCallParametersCheck(new RuleLevelHelper($reflectionProvider, true, false, true, false, false, true, false), new NullsafeCheck(), new PhpVersion(80000), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true, true), new ClassCaseSensitivityCheck($reflectionProvider, false), true)); + return new PropertyAttributesRule( + new AttributesCheck( + $reflectionProvider, + new FunctionCallParametersCheck( + new RuleLevelHelper($reflectionProvider, true, false, true, false, false, true, false), + new NullsafeCheck(), + new PhpVersion(80000), + new UnresolvableTypeHelper(), + new PropertyReflectionFinder(), + true, + true, + true, + true, + true, + ), + new ClassCaseSensitivityCheck($reflectionProvider, false), + true, + ), + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Properties/ReadOnlyByPhpDocPropertyAssignRuleTest.php b/tests/PHPStan/Rules/Properties/ReadOnlyByPhpDocPropertyAssignRuleTest.php index fad43b0f4e4..197473fbf51 100644 --- a/tests/PHPStan/Rules/Properties/ReadOnlyByPhpDocPropertyAssignRuleTest.php +++ b/tests/PHPStan/Rules/Properties/ReadOnlyByPhpDocPropertyAssignRuleTest.php @@ -15,9 +15,15 @@ class ReadOnlyByPhpDocPropertyAssignRuleTest extends RuleTestCase protected function getRule(): Rule { - return new ReadOnlyByPhpDocPropertyAssignRule(new PropertyReflectionFinder(), new ConstructorsHelper(self::getContainer(), [ + return new ReadOnlyByPhpDocPropertyAssignRule( + new PropertyReflectionFinder(), + new ConstructorsHelper( + self::getContainer(), + [ 'ReadonlyPropertyAssignPhpDoc\\TestCase::setUp', - ])); + ], + ), + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Properties/ReadOnlyPropertyAssignRuleTest.php b/tests/PHPStan/Rules/Properties/ReadOnlyPropertyAssignRuleTest.php index 9158913aea1..fec1fb11921 100644 --- a/tests/PHPStan/Rules/Properties/ReadOnlyPropertyAssignRuleTest.php +++ b/tests/PHPStan/Rules/Properties/ReadOnlyPropertyAssignRuleTest.php @@ -15,9 +15,15 @@ class ReadOnlyPropertyAssignRuleTest extends RuleTestCase protected function getRule(): Rule { - return new ReadOnlyPropertyAssignRule(new PropertyReflectionFinder(), new ConstructorsHelper(self::getContainer(), [ + return new ReadOnlyPropertyAssignRule( + new PropertyReflectionFinder(), + new ConstructorsHelper( + self::getContainer(), + [ 'ReadonlyPropertyAssign\\TestCase::setUp', - ])); + ], + ), + ); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Properties/ReadOnlyPropertyRuleTest.php b/tests/PHPStan/Rules/Properties/ReadOnlyPropertyRuleTest.php index 0c5fde9ef41..30f96067440 100644 --- a/tests/PHPStan/Rules/Properties/ReadOnlyPropertyRuleTest.php +++ b/tests/PHPStan/Rules/Properties/ReadOnlyPropertyRuleTest.php @@ -12,10 +12,7 @@ class ReadOnlyPropertyRuleTest extends RuleTestCase { - /** - * @var int - */ - private $phpVersionId; + private int $phpVersionId; protected function getRule(): Rule { diff --git a/tests/PHPStan/Rules/Properties/ReadingWriteOnlyPropertiesRuleTest.php b/tests/PHPStan/Rules/Properties/ReadingWriteOnlyPropertiesRuleTest.php index 391f5811204..d5834f40030 100644 --- a/tests/PHPStan/Rules/Properties/ReadingWriteOnlyPropertiesRuleTest.php +++ b/tests/PHPStan/Rules/Properties/ReadingWriteOnlyPropertiesRuleTest.php @@ -12,10 +12,7 @@ class ReadingWriteOnlyPropertiesRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $checkThisOnly; + private bool $checkThisOnly; protected function getRule(): Rule { diff --git a/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleNoBleedingEdgeTest.php b/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleNoBleedingEdgeTest.php index 25687efd50b..9b0aaf913d7 100644 --- a/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleNoBleedingEdgeTest.php +++ b/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleNoBleedingEdgeTest.php @@ -12,10 +12,7 @@ class TypesAssignedToPropertiesRuleNoBleedingEdgeTest extends RuleTestCase { - /** - * @var bool - */ - private $checkExplicitMixed = false; + private bool $checkExplicitMixed = false; protected function getRule(): Rule { diff --git a/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleTest.php b/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleTest.php index 4eb78347b13..2429f670ed8 100644 --- a/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleTest.php +++ b/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleTest.php @@ -13,10 +13,7 @@ class TypesAssignedToPropertiesRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $checkExplicitMixed = false; + private bool $checkExplicitMixed = false; protected function getRule(): Rule { @@ -263,7 +260,9 @@ public function testBug5447(): void public function testAppendedArrayItemType(): void { - $this->analyse([__DIR__ . '/../Arrays/data/appended-array-item.php'], [ + $this->analyse( + [__DIR__ . '/../Arrays/data/appended-array-item.php'], + [ [ 'Property AppendedArrayItem\Foo::$integers (array) does not accept array.', 18, @@ -296,7 +295,8 @@ public function testAppendedArrayItemType(): void 'Property AppendedArrayItem\Baz::$staticProperty (array) does not accept array.', 79, ], - ]); + ], + ); } public function testBug5804(): void diff --git a/tests/PHPStan/Rules/Properties/UninitializedPropertyRuleTest.php b/tests/PHPStan/Rules/Properties/UninitializedPropertyRuleTest.php index c92226bf286..39fdf5acc10 100644 --- a/tests/PHPStan/Rules/Properties/UninitializedPropertyRuleTest.php +++ b/tests/PHPStan/Rules/Properties/UninitializedPropertyRuleTest.php @@ -16,13 +16,18 @@ class UninitializedPropertyRuleTest extends RuleTestCase protected function getRule(): Rule { - return new UninitializedPropertyRule(new ConstructorsHelper(self::getContainer(), [ + return new UninitializedPropertyRule( + new ConstructorsHelper( + self::getContainer(), + [ 'UninitializedProperty\\TestCase::setUp', 'Bug9619\\AdminPresenter::startup', 'Bug9619\\AdminPresenter2::startup', 'Bug9619\\AdminPresenter3::startup', 'Bug9619\\AdminPresenter3::startup2', - ])); + ], + ), + ); } protected function getReadWritePropertiesExtensions(): array diff --git a/tests/PHPStan/Rules/Properties/WritingToReadOnlyPropertiesRuleTest.php b/tests/PHPStan/Rules/Properties/WritingToReadOnlyPropertiesRuleTest.php index 6f634e41a74..d3196aba89a 100644 --- a/tests/PHPStan/Rules/Properties/WritingToReadOnlyPropertiesRuleTest.php +++ b/tests/PHPStan/Rules/Properties/WritingToReadOnlyPropertiesRuleTest.php @@ -12,10 +12,7 @@ class WritingToReadOnlyPropertiesRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $checkThisOnly; + private bool $checkThisOnly; protected function getRule(): Rule { diff --git a/tests/PHPStan/Rules/Regexp/RegularExpressionPatternRuleTest.php b/tests/PHPStan/Rules/Regexp/RegularExpressionPatternRuleTest.php index 82c5d97de10..4a37f5114b8 100644 --- a/tests/PHPStan/Rules/Regexp/RegularExpressionPatternRuleTest.php +++ b/tests/PHPStan/Rules/Regexp/RegularExpressionPatternRuleTest.php @@ -24,7 +24,9 @@ public function testValidRegexPatternBefore73(): void $this->markTestSkipped('This test requires PHP < 7.3.0'); } - $this->analyse([__DIR__ . '/data/valid-regex-pattern.php'], [ + $this->analyse( + [__DIR__ . '/data/valid-regex-pattern.php'], + [ [ 'Regex pattern is invalid: Delimiter must not be alphanumeric or backslash in pattern: nok', 6, @@ -113,7 +115,8 @@ public function testValidRegexPatternBefore73(): void 'Regex pattern is invalid: Compilation failed: missing ) at offset 1 in pattern: ~(~', 43, ], - ]); + ], + ); } public function testValidRegexPatternAfter73(): void @@ -127,7 +130,9 @@ public function testValidRegexPatternAfter73(): void $messagePart = 'alphanumeric, backslash, or NUL'; } - $this->analyse([__DIR__ . '/data/valid-regex-pattern.php'], [ + $this->analyse( + [__DIR__ . '/data/valid-regex-pattern.php'], + [ [ sprintf('Regex pattern is invalid: Delimiter must not be %s in pattern: nok', $messagePart), 6, @@ -216,7 +221,8 @@ public function testValidRegexPatternAfter73(): void 'Regex pattern is invalid: Compilation failed: missing closing parenthesis at offset 1 in pattern: ~(~', 43, ], - ]); + ], + ); } } diff --git a/tests/PHPStan/Rules/TooWideTypehints/TooWideMethodReturnTypehintRuleTest.php b/tests/PHPStan/Rules/TooWideTypehints/TooWideMethodReturnTypehintRuleTest.php index 59a54dceee6..0a6e1382793 100644 --- a/tests/PHPStan/Rules/TooWideTypehints/TooWideMethodReturnTypehintRuleTest.php +++ b/tests/PHPStan/Rules/TooWideTypehints/TooWideMethodReturnTypehintRuleTest.php @@ -12,15 +12,9 @@ class TooWideMethodReturnTypehintRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $checkProtectedAndPublicMethods = true; + private bool $checkProtectedAndPublicMethods = true; - /** - * @var bool - */ - private $alwaysCheckFinal = false; + private bool $alwaysCheckFinal = false; protected function getRule(): Rule { diff --git a/tests/PHPStan/Rules/Traits/ConstantsInTraitsRuleTest.php b/tests/PHPStan/Rules/Traits/ConstantsInTraitsRuleTest.php index abb595cbcc4..3b6f5915277 100644 --- a/tests/PHPStan/Rules/Traits/ConstantsInTraitsRuleTest.php +++ b/tests/PHPStan/Rules/Traits/ConstantsInTraitsRuleTest.php @@ -13,10 +13,7 @@ class ConstantsInTraitsRuleTest extends RuleTestCase { - /** - * @var int - */ - private $phpVersionId; + private int $phpVersionId; protected function getRule(): Rule { diff --git a/tests/PHPStan/Rules/Variables/CompactVariablesRuleTest.php b/tests/PHPStan/Rules/Variables/CompactVariablesRuleTest.php index 24630efdf98..ccd8f350fc8 100644 --- a/tests/PHPStan/Rules/Variables/CompactVariablesRuleTest.php +++ b/tests/PHPStan/Rules/Variables/CompactVariablesRuleTest.php @@ -11,10 +11,7 @@ class CompactVariablesRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $checkMaybeUndefinedVariables; + private bool $checkMaybeUndefinedVariables; protected function getRule(): Rule { diff --git a/tests/PHPStan/Rules/Variables/DefinedVariableRuleTest.php b/tests/PHPStan/Rules/Variables/DefinedVariableRuleTest.php index 2cd7640d476..6c557437405 100644 --- a/tests/PHPStan/Rules/Variables/DefinedVariableRuleTest.php +++ b/tests/PHPStan/Rules/Variables/DefinedVariableRuleTest.php @@ -12,29 +12,20 @@ class DefinedVariableRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $cliArgumentsVariablesRegistered; + private bool $cliArgumentsVariablesRegistered; - /** - * @var bool - */ - private $checkMaybeUndefinedVariables; + private bool $checkMaybeUndefinedVariables; - /** - * @var bool - */ - private $polluteScopeWithLoopInitialAssignments; + private bool $polluteScopeWithLoopInitialAssignments; - /** - * @var bool - */ - private $polluteScopeWithAlwaysIterableForeach; + private bool $polluteScopeWithAlwaysIterableForeach; protected function getRule(): Rule { - return new DefinedVariableRule($this->cliArgumentsVariablesRegistered, $this->checkMaybeUndefinedVariables); + return new DefinedVariableRule( + $this->cliArgumentsVariablesRegistered, + $this->checkMaybeUndefinedVariables, + ); } protected function shouldPolluteScopeWithLoopInitialAssignments(): bool @@ -361,7 +352,11 @@ public function dataLoopInitialAssignments(): array * @dataProvider dataLoopInitialAssignments * @param list $expectedErrors */ - public function testLoopInitialAssignments(bool $polluteScopeWithLoopInitialAssignments, bool $checkMaybeUndefinedVariables, array $expectedErrors) : void + public function testLoopInitialAssignments( + bool $polluteScopeWithLoopInitialAssignments, + bool $checkMaybeUndefinedVariables, + array $expectedErrors, + ): void { $this->cliArgumentsVariablesRegistered = false; $this->polluteScopeWithLoopInitialAssignments = $polluteScopeWithLoopInitialAssignments; diff --git a/tests/PHPStan/Rules/Variables/EmptyRuleTest.php b/tests/PHPStan/Rules/Variables/EmptyRuleTest.php index f41d789f0ad..6fa229669f7 100644 --- a/tests/PHPStan/Rules/Variables/EmptyRuleTest.php +++ b/tests/PHPStan/Rules/Variables/EmptyRuleTest.php @@ -15,19 +15,19 @@ class EmptyRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $treatPhpDocTypesAsCertain; + private bool $treatPhpDocTypesAsCertain; - /** - * @var bool - */ - private $strictUnnecessaryNullsafePropertyFetch; + private bool $strictUnnecessaryNullsafePropertyFetch; protected function getRule(): Rule { - return new EmptyRule(new IssetCheck(new PropertyDescriptor(), new PropertyReflectionFinder(), true, $this->treatPhpDocTypesAsCertain, $this->strictUnnecessaryNullsafePropertyFetch)); + return new EmptyRule(new IssetCheck( + new PropertyDescriptor(), + new PropertyReflectionFinder(), + true, + $this->treatPhpDocTypesAsCertain, + $this->strictUnnecessaryNullsafePropertyFetch, + )); } protected function shouldTreatPhpDocTypesAsCertain(): bool diff --git a/tests/PHPStan/Rules/Variables/IssetRuleTest.php b/tests/PHPStan/Rules/Variables/IssetRuleTest.php index 1056db867f9..960dad4d31d 100644 --- a/tests/PHPStan/Rules/Variables/IssetRuleTest.php +++ b/tests/PHPStan/Rules/Variables/IssetRuleTest.php @@ -15,19 +15,19 @@ class IssetRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $treatPhpDocTypesAsCertain; + private bool $treatPhpDocTypesAsCertain; - /** - * @var bool - */ - private $strictUnnecessaryNullsafePropertyFetch; + private bool $strictUnnecessaryNullsafePropertyFetch; protected function getRule(): Rule { - return new IssetRule(new IssetCheck(new PropertyDescriptor(), new PropertyReflectionFinder(), true, $this->treatPhpDocTypesAsCertain, $this->strictUnnecessaryNullsafePropertyFetch)); + return new IssetRule(new IssetCheck( + new PropertyDescriptor(), + new PropertyReflectionFinder(), + true, + $this->treatPhpDocTypesAsCertain, + $this->strictUnnecessaryNullsafePropertyFetch, + )); } protected function shouldTreatPhpDocTypesAsCertain(): bool diff --git a/tests/PHPStan/Rules/Variables/NullCoalesceRuleTest.php b/tests/PHPStan/Rules/Variables/NullCoalesceRuleTest.php index 9d8e5925cae..613770aeadf 100644 --- a/tests/PHPStan/Rules/Variables/NullCoalesceRuleTest.php +++ b/tests/PHPStan/Rules/Variables/NullCoalesceRuleTest.php @@ -15,19 +15,19 @@ class NullCoalesceRuleTest extends RuleTestCase { - /** - * @var bool - */ - private $treatPhpDocTypesAsCertain; + private bool $treatPhpDocTypesAsCertain; - /** - * @var bool - */ - private $strictUnnecessaryNullsafePropertyFetch; + private bool $strictUnnecessaryNullsafePropertyFetch; protected function getRule(): Rule { - return new NullCoalesceRule(new IssetCheck(new PropertyDescriptor(), new PropertyReflectionFinder(), true, $this->treatPhpDocTypesAsCertain, $this->strictUnnecessaryNullsafePropertyFetch)); + return new NullCoalesceRule(new IssetCheck( + new PropertyDescriptor(), + new PropertyReflectionFinder(), + true, + $this->treatPhpDocTypesAsCertain, + $this->strictUnnecessaryNullsafePropertyFetch, + )); } protected function shouldTreatPhpDocTypesAsCertain(): bool diff --git a/tests/PHPStan/Rules/Variables/ThrowTypeRuleTest.php b/tests/PHPStan/Rules/Variables/ThrowTypeRuleTest.php index 1b0b5592eae..020f7137087 100644 --- a/tests/PHPStan/Rules/Variables/ThrowTypeRuleTest.php +++ b/tests/PHPStan/Rules/Variables/ThrowTypeRuleTest.php @@ -20,7 +20,9 @@ protected function getRule(): Rule public function testRule(): void { - $this->analyse([__DIR__ . '/data/throw-values.php'], [ + $this->analyse( + [__DIR__ . '/data/throw-values.php'], + [ [ 'Invalid type int to throw.', 29, @@ -42,7 +44,8 @@ public function testRule(): void 44, 'Learn more at https://phpstan.org/user-guide/discovering-symbols', ], - ]); + ], + ); } public function testClassExists(): void diff --git a/tests/PHPStan/Tests/AssertionClassMethodTypeSpecifyingExtension.php b/tests/PHPStan/Tests/AssertionClassMethodTypeSpecifyingExtension.php index bf51e25e34e..4f8adec6528 100644 --- a/tests/PHPStan/Tests/AssertionClassMethodTypeSpecifyingExtension.php +++ b/tests/PHPStan/Tests/AssertionClassMethodTypeSpecifyingExtension.php @@ -13,13 +13,8 @@ class AssertionClassMethodTypeSpecifyingExtension implements MethodTypeSpecifyingExtension { - /** - * @var ?bool - */ - private $nullContext; - public function __construct(?bool $nullContext = null) + public function __construct(private ?bool $nullContext = null) { - $this->nullContext = $nullContext; } public function getClass(): string @@ -27,18 +22,29 @@ public function getClass(): string return AssertionClass::class; } - public function isMethodSupported(MethodReflection $methodReflection, MethodCall $node, TypeSpecifierContext $context) : bool + public function isMethodSupported( + MethodReflection $methodReflection, + MethodCall $node, + TypeSpecifierContext $context, + ): bool { if ($this->nullContext === null) { return $methodReflection->getName() === 'assertString'; } + if ($this->nullContext) { return $methodReflection->getName() === 'assertString' && $context->null(); } + return $methodReflection->getName() === 'assertString' && !$context->null(); } - public function specifyTypes(MethodReflection $methodReflection, MethodCall $node, Scope $scope, TypeSpecifierContext $context) : SpecifiedTypes + public function specifyTypes( + MethodReflection $methodReflection, + MethodCall $node, + Scope $scope, + TypeSpecifierContext $context, + ): SpecifiedTypes { return new SpecifiedTypes(['$foo' => [$node->getArgs()[0]->value, new StringType()]]); } diff --git a/tests/PHPStan/Tests/AssertionClassStaticMethodTypeSpecifyingExtension.php b/tests/PHPStan/Tests/AssertionClassStaticMethodTypeSpecifyingExtension.php index 96d52d2ec2a..8a1a20f8c50 100644 --- a/tests/PHPStan/Tests/AssertionClassStaticMethodTypeSpecifyingExtension.php +++ b/tests/PHPStan/Tests/AssertionClassStaticMethodTypeSpecifyingExtension.php @@ -13,13 +13,8 @@ class AssertionClassStaticMethodTypeSpecifyingExtension implements StaticMethodTypeSpecifyingExtension { - /** - * @var ?bool - */ - private $nullContext; - public function __construct(?bool $nullContext = null) + public function __construct(private ?bool $nullContext = null) { - $this->nullContext = $nullContext; } public function getClass(): string @@ -27,18 +22,29 @@ public function getClass(): string return AssertionClass::class; } - public function isStaticMethodSupported(MethodReflection $staticMethodReflection, StaticCall $node, TypeSpecifierContext $context) : bool + public function isStaticMethodSupported( + MethodReflection $staticMethodReflection, + StaticCall $node, + TypeSpecifierContext $context, + ): bool { if ($this->nullContext === null) { return $staticMethodReflection->getName() === 'assertInt'; } + if ($this->nullContext) { return $staticMethodReflection->getName() === 'assertInt' && $context->null(); } + return $staticMethodReflection->getName() === 'assertInt' && !$context->null(); } - public function specifyTypes(MethodReflection $staticMethodReflection, StaticCall $node, Scope $scope, TypeSpecifierContext $context) : SpecifiedTypes + public function specifyTypes( + MethodReflection $staticMethodReflection, + StaticCall $node, + Scope $scope, + TypeSpecifierContext $context, + ): SpecifiedTypes { return new SpecifiedTypes(['$bar' => [$node->getArgs()[0]->value, new IntegerType()]]); } diff --git a/tests/PHPStan/TrinaryLogicTest.php b/tests/PHPStan/TrinaryLogicTest.php index a7e02936848..c487e2d5c32 100644 --- a/tests/PHPStan/TrinaryLogicTest.php +++ b/tests/PHPStan/TrinaryLogicTest.php @@ -31,7 +31,11 @@ public function dataAnd(): array /** * @dataProvider dataAnd */ - public function testAnd(TrinaryLogic $expectedResult, TrinaryLogic $value, TrinaryLogic ...$operands) : void + public function testAnd( + TrinaryLogic $expectedResult, + TrinaryLogic $value, + TrinaryLogic ...$operands, + ): void { $this->assertTrue($expectedResult->equals($value->and(...$operands))); } @@ -39,11 +43,13 @@ public function testAnd(TrinaryLogic $expectedResult, TrinaryLogic $value, Trina /** * @dataProvider dataAnd */ - public function testLazyAnd(TrinaryLogic $expectedResult, TrinaryLogic $value, TrinaryLogic ...$operands) : void + public function testLazyAnd( + TrinaryLogic $expectedResult, + TrinaryLogic $value, + TrinaryLogic ...$operands, + ): void { - $this->assertTrue($expectedResult->equals($value->lazyAnd($operands, static function (TrinaryLogic $result) { - return $result; - }))); + $this->assertTrue($expectedResult->equals($value->lazyAnd($operands, static fn (TrinaryLogic $result) => $result))); } public function dataOr(): array @@ -70,7 +76,11 @@ public function dataOr(): array /** * @dataProvider dataOr */ - public function testOr(TrinaryLogic $expectedResult, TrinaryLogic $value, TrinaryLogic ...$operands) : void + public function testOr( + TrinaryLogic $expectedResult, + TrinaryLogic $value, + TrinaryLogic ...$operands, + ): void { $this->assertTrue($expectedResult->equals($value->or(...$operands))); } @@ -78,11 +88,13 @@ public function testOr(TrinaryLogic $expectedResult, TrinaryLogic $value, Trinar /** * @dataProvider dataOr */ - public function testLazyOr(TrinaryLogic $expectedResult, TrinaryLogic $value, TrinaryLogic ...$operands) : void + public function testLazyOr( + TrinaryLogic $expectedResult, + TrinaryLogic $value, + TrinaryLogic ...$operands, + ): void { - $this->assertTrue($expectedResult->equals($value->lazyOr($operands, static function (TrinaryLogic $result) { - return $result; - }))); + $this->assertTrue($expectedResult->equals($value->lazyOr($operands, static fn (TrinaryLogic $result) => $result))); } public function dataNegate(): array @@ -146,7 +158,10 @@ public function dataCompareTo(): array */ public function testCompareTo(TrinaryLogic $first, TrinaryLogic $second, ?TrinaryLogic $expected): void { - $this->assertSame($expected, $first->compareTo($second)); + $this->assertSame( + $expected, + $first->compareTo($second), + ); } /** @@ -154,7 +169,10 @@ public function testCompareTo(TrinaryLogic $first, TrinaryLogic $second, ?Trinar */ public function testCompareToInversed(TrinaryLogic $first, TrinaryLogic $second, ?TrinaryLogic $expected): void { - $this->assertSame($expected, $second->compareTo($first)); + $this->assertSame( + $expected, + $second->compareTo($first), + ); } } diff --git a/tests/PHPStan/Type/Accessory/HasMethodTypeTest.php b/tests/PHPStan/Type/Accessory/HasMethodTypeTest.php index a0758934bbc..a70ff82ceb0 100644 --- a/tests/PHPStan/Type/Accessory/HasMethodTypeTest.php +++ b/tests/PHPStan/Type/Accessory/HasMethodTypeTest.php @@ -147,7 +147,11 @@ public function dataIsSuperTypeOf(): array public function testIsSuperTypeOf(HasMethodType $type, Type $otherType, TrinaryLogic $expectedResult): void { $actualResult = $type->isSuperTypeOf($otherType); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isSuperTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isSuperTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise())), + ); } public function dataIsSubTypeOf(): array @@ -193,7 +197,11 @@ public function dataIsSubTypeOf(): array public function testIsSubTypeOf(HasMethodType $type, Type $otherType, TrinaryLogic $expectedResult): void { $actualResult = $type->isSubTypeOf($otherType); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isSubTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isSubTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise())), + ); } /** @@ -202,7 +210,11 @@ public function testIsSubTypeOf(HasMethodType $type, Type $otherType, TrinaryLog public function testIsSubTypeOfInversed(HasMethodType $type, Type $otherType, TrinaryLogic $expectedResult): void { $actualResult = $otherType->isSuperTypeOf($type); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isSuperTypeOf(%s)', $otherType->describe(VerbosityLevel::precise()), $type->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isSuperTypeOf(%s)', $otherType->describe(VerbosityLevel::precise()), $type->describe(VerbosityLevel::precise())), + ); } } diff --git a/tests/PHPStan/Type/Accessory/HasPropertyTypeTest.php b/tests/PHPStan/Type/Accessory/HasPropertyTypeTest.php index 18b8e7ac1ef..52b44a61686 100644 --- a/tests/PHPStan/Type/Accessory/HasPropertyTypeTest.php +++ b/tests/PHPStan/Type/Accessory/HasPropertyTypeTest.php @@ -113,7 +113,11 @@ public function dataIsSuperTypeOf(): array public function testIsSuperTypeOf(HasPropertyType $type, Type $otherType, TrinaryLogic $expectedResult): void { $actualResult = $type->isSuperTypeOf($otherType); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isSuperTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isSuperTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise())), + ); } public function dataIsSubTypeOf(): array @@ -154,7 +158,11 @@ public function dataIsSubTypeOf(): array public function testIsSubTypeOf(HasPropertyType $type, Type $otherType, TrinaryLogic $expectedResult): void { $actualResult = $type->isSubTypeOf($otherType); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isSubTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isSubTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise())), + ); } /** @@ -163,7 +171,11 @@ public function testIsSubTypeOf(HasPropertyType $type, Type $otherType, TrinaryL public function testIsSubTypeOfInversed(HasPropertyType $type, Type $otherType, TrinaryLogic $expectedResult): void { $actualResult = $otherType->isSuperTypeOf($type); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isSuperTypeOf(%s)', $otherType->describe(VerbosityLevel::precise()), $type->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isSuperTypeOf(%s)', $otherType->describe(VerbosityLevel::precise()), $type->describe(VerbosityLevel::precise())), + ); } } diff --git a/tests/PHPStan/Type/ArrayTypeTest.php b/tests/PHPStan/Type/ArrayTypeTest.php index 3f4f10643dc..ed3af635077 100644 --- a/tests/PHPStan/Type/ArrayTypeTest.php +++ b/tests/PHPStan/Type/ArrayTypeTest.php @@ -80,7 +80,11 @@ public function dataIsSuperTypeOf(): array public function testIsSuperTypeOf(ArrayType $type, Type $otherType, TrinaryLogic $expectedResult): void { $actualResult = $type->isSuperTypeOf($otherType); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isSuperTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isSuperTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise())), + ); } public function dataAccepts(): array @@ -90,13 +94,20 @@ public function dataAccepts(): array return [ [ new ArrayType(new MixedType(), new StringType()), - TypeCombinator::union(new ConstantArrayType([], []), new ConstantArrayType([new ConstantIntegerType(0)], [new MixedType()]), new ConstantArrayType([ + TypeCombinator::union( + new ConstantArrayType([], []), + new ConstantArrayType( + [new ConstantIntegerType(0)], + [new MixedType()], + ), + new ConstantArrayType([ new ConstantIntegerType(0), new ConstantIntegerType(1), ], [ new StringType(), new MixedType(), - ])), + ]), + ), TrinaryLogic::createYes(), ], [ @@ -128,10 +139,18 @@ public function dataAccepts(): array /** * @dataProvider dataAccepts */ - public function testAccepts(ArrayType $acceptingType, Type $acceptedType, TrinaryLogic $expectedResult) : void + public function testAccepts( + ArrayType $acceptingType, + Type $acceptedType, + TrinaryLogic $expectedResult, + ): void { $actualResult = $acceptingType->accepts($acceptedType, true); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> accepts(%s)', $acceptingType->describe(VerbosityLevel::precise()), $acceptedType->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> accepts(%s)', $acceptingType->describe(VerbosityLevel::precise()), $acceptedType->describe(VerbosityLevel::precise())), + ); } public function dataDescribe(): array @@ -150,48 +169,81 @@ public function dataDescribe(): array /** * @dataProvider dataDescribe */ - public function testDescribe(ArrayType $type, string $expectedDescription) : void + public function testDescribe( + ArrayType $type, + string $expectedDescription, + ): void { $this->assertSame($expectedDescription, $type->describe(VerbosityLevel::precise())); } public function dataInferTemplateTypes(): array { - $templateType = static function (string $name) : Type { - return TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('a'), $name, new MixedType(), TemplateTypeVariance::createInvariant()); - }; + $templateType = static fn (string $name): Type => TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('a'), + $name, + new MixedType(), + TemplateTypeVariance::createInvariant(), + ); return [ 'valid templated item' => [ - new ArrayType(new MixedType(), new ObjectType('DateTime')), - new ArrayType(new MixedType(), $templateType('T')), + new ArrayType( + new MixedType(), + new ObjectType('DateTime'), + ), + new ArrayType( + new MixedType(), + $templateType('T'), + ), ['T' => 'DateTime'], ], 'receive mixed' => [ new MixedType(), - new ArrayType(new MixedType(), $templateType('T')), + new ArrayType( + new MixedType(), + $templateType('T'), + ), [], ], 'receive non-accepted' => [ new StringType(), - new ArrayType(new MixedType(), $templateType('T')), + new ArrayType( + new MixedType(), + $templateType('T'), + ), [], ], 'receive union items' => [ - new ArrayType(new MixedType(), new UnionType([ + new ArrayType( + new MixedType(), + new UnionType([ new StringType(), new IntegerType(), - ])), - new ArrayType(new MixedType(), $templateType('T')), + ]), + ), + new ArrayType( + new MixedType(), + $templateType('T'), + ), ['T' => 'int|string'], ], 'receive union' => [ new UnionType([ new StringType(), - new ArrayType(new MixedType(), new StringType()), - new ArrayType(new MixedType(), new IntegerType()), + new ArrayType( + new MixedType(), + new StringType(), + ), + new ArrayType( + new MixedType(), + new IntegerType(), + ), ]), - new ArrayType(new MixedType(), $templateType('T')), + new ArrayType( + new MixedType(), + $templateType('T'), + ), ['T' => 'int|string'], ], ]; @@ -205,9 +257,10 @@ public function testResolveTemplateTypes(Type $received, Type $template, array $ { $result = $template->inferTemplateTypes($received); - $this->assertSame($expectedTypes, array_map(static function (Type $type) : string { - return $type->describe(VerbosityLevel::precise()); - }, $result->getTypes())); + $this->assertSame( + $expectedTypes, + array_map(static fn (Type $type): string => $type->describe(VerbosityLevel::precise()), $result->getTypes()), + ); } } diff --git a/tests/PHPStan/Type/BenevolentUnionTypeTest.php b/tests/PHPStan/Type/BenevolentUnionTypeTest.php index 86683c4fccb..18a37f8be0e 100644 --- a/tests/PHPStan/Type/BenevolentUnionTypeTest.php +++ b/tests/PHPStan/Type/BenevolentUnionTypeTest.php @@ -41,7 +41,11 @@ public function dataCanAccessProperties(): Iterator public function testCanAccessProperties(BenevolentUnionType $type, TrinaryLogic $expectedResult): void { $actualResult = $type->canAccessProperties(); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> canAccessProperties()', $type->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> canAccessProperties()', $type->describe(VerbosityLevel::precise())), + ); } public function dataHasProperty(): Iterator @@ -75,7 +79,11 @@ public function dataHasProperty(): Iterator public function testHasProperty(BenevolentUnionType $type, string $propertyName, TrinaryLogic $expectedResult): void { $actualResult = $type->hasProperty($propertyName); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> hasProperty()', $type->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> hasProperty()', $type->describe(VerbosityLevel::precise())), + ); } public function dataCanCallMethods(): Iterator @@ -100,7 +108,11 @@ public function dataCanCallMethods(): Iterator public function testCanCanCallMethods(BenevolentUnionType $type, TrinaryLogic $expectedResult): void { $actualResult = $type->canCallMethods(); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> canCallMethods()', $type->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> canCallMethods()', $type->describe(VerbosityLevel::precise())), + ); } public function dataHasMethod(): Iterator @@ -131,7 +143,11 @@ public function dataHasMethod(): Iterator public function testHasMethod(BenevolentUnionType $type, string $methodName, TrinaryLogic $expectedResult): void { $actualResult = $type->hasMethod($methodName); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> hasMethod()', $type->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> hasMethod()', $type->describe(VerbosityLevel::precise())), + ); } public function dataCanAccessConstants(): Iterator @@ -156,7 +172,11 @@ public function dataCanAccessConstants(): Iterator public function testCanAccessConstants(BenevolentUnionType $type, TrinaryLogic $expectedResult): void { $actualResult = $type->canAccessConstants(); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> canAccessConstants()', $type->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> canAccessConstants()', $type->describe(VerbosityLevel::precise())), + ); } public function dataIsIterable(): Iterator @@ -187,7 +207,11 @@ public function dataIsIterable(): Iterator public function testIsIterable(BenevolentUnionType $type, TrinaryLogic $expectedResult): void { $actualResult = $type->isIterable(); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isIterable()', $type->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isIterable()', $type->describe(VerbosityLevel::precise())), + ); } public function dataIsIterableAtLeastOnce(): Iterator @@ -218,7 +242,11 @@ public function dataIsIterableAtLeastOnce(): Iterator public function testIsIterableAtLeastOnce(BenevolentUnionType $type, TrinaryLogic $expectedResult): void { $actualResult = $type->isIterableAtLeastOnce(); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isIterableAtLeastOnce()', $type->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isIterableAtLeastOnce()', $type->describe(VerbosityLevel::precise())), + ); } public function dataIsArray(): Iterator @@ -243,7 +271,11 @@ public function dataIsArray(): Iterator public function testIsArray(BenevolentUnionType $type, TrinaryLogic $expectedResult): void { $actualResult = $type->isArray(); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isArray()', $type->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isArray()', $type->describe(VerbosityLevel::precise())), + ); } public function dataIsString(): Iterator @@ -271,7 +303,11 @@ public function dataIsString(): Iterator public function testIsString(BenevolentUnionType $type, TrinaryLogic $expectedResult): void { $actualResult = $type->isString(); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isString()', $type->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isString()', $type->describe(VerbosityLevel::precise())), + ); } public function dataIsNumericString(): Iterator @@ -298,7 +334,11 @@ public function dataIsNumericString(): Iterator public function testIsNumericString(BenevolentUnionType $type, TrinaryLogic $expectedResult): void { $actualResult = $type->isNumericString(); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isNumericString()', $type->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isNumericString()', $type->describe(VerbosityLevel::precise())), + ); } public function dataIsNonFalsyString(): Iterator @@ -325,7 +365,11 @@ public function dataIsNonFalsyString(): Iterator public function testIsNonFalsyString(BenevolentUnionType $type, TrinaryLogic $expectedResult): void { $actualResult = $type->isNonFalsyString(); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isNonFalsyString()', $type->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isNonFalsyString()', $type->describe(VerbosityLevel::precise())), + ); } public function dataIsLiteralString(): Iterator @@ -352,7 +396,11 @@ public function dataIsLiteralString(): Iterator public function testIsLiteralString(BenevolentUnionType $type, TrinaryLogic $expectedResult): void { $actualResult = $type->isLiteralString(); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isLiteralString()', $type->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isLiteralString()', $type->describe(VerbosityLevel::precise())), + ); } public function dataIsOffsetAccesible(): Iterator @@ -383,7 +431,11 @@ public function dataIsOffsetAccesible(): Iterator public function testIsOffsetAccessible(BenevolentUnionType $type, TrinaryLogic $expectedResult): void { $actualResult = $type->isOffsetAccessible(); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isOffsetAccessible()', $type->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isOffsetAccessible()', $type->describe(VerbosityLevel::precise())), + ); } public function dataHasOffsetValueType(): Iterator @@ -417,7 +469,11 @@ public function dataHasOffsetValueType(): Iterator public function testHasOffsetValue(BenevolentUnionType $type, Type $offsetType, TrinaryLogic $expectedResult): void { $actualResult = $type->hasOffsetValueType($offsetType); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> hasOffsetValueType()', $type->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> hasOffsetValueType()', $type->describe(VerbosityLevel::precise())), + ); } public function dataIsCallable(): Iterator @@ -442,7 +498,11 @@ public function dataIsCallable(): Iterator public function testIsCallable(BenevolentUnionType $type, TrinaryLogic $expectedResult): void { $actualResult = $type->isCallable(); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isCallable()', $type->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isCallable()', $type->describe(VerbosityLevel::precise())), + ); } public function dataIsCloneable(): Iterator @@ -467,7 +527,11 @@ public function dataIsCloneable(): Iterator public function testIsCloneable(BenevolentUnionType $type, TrinaryLogic $expectedResult): void { $actualResult = $type->isCloneable(); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isCloneable()', $type->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isCloneable()', $type->describe(VerbosityLevel::precise())), + ); } } diff --git a/tests/PHPStan/Type/BitwiseFlagHelperTest.php b/tests/PHPStan/Type/BitwiseFlagHelperTest.php index 13c10ee1662..49381b899b5 100644 --- a/tests/PHPStan/Type/BitwiseFlagHelperTest.php +++ b/tests/PHPStan/Type/BitwiseFlagHelperTest.php @@ -27,12 +27,18 @@ public function dataUnknownConstants(): array TrinaryLogic::createYes(), ], [ - new BitwiseOr(new ConstFetch(new Name('SOME_CONST1')), new ConstFetch(new Name('SOME_CONST2'))), + new BitwiseOr( + new ConstFetch(new Name('SOME_CONST1')), + new ConstFetch(new Name('SOME_CONST2')), + ), 'SOME_CONST2', TrinaryLogic::createYes(), ], [ - new BitwiseOr(new ConstFetch(new Name('SOME_CONST1')), new ConstFetch(new Name('SOME_CONST2'))), + new BitwiseOr( + new ConstFetch(new Name('SOME_CONST1')), + new ConstFetch(new Name('SOME_CONST2')), + ), 'SOME_CONST3', TrinaryLogic::createNo(), ], @@ -57,12 +63,18 @@ public function dataJsonExprContainsConst(): array TrinaryLogic::createNo(), ], [ - new BitwiseOr(new ConstFetch(new FullyQualified('JSON_NUMERIC_CHECK')), new ConstFetch(new FullyQualified('JSON_THROW_ON_ERROR'))), + new BitwiseOr( + new ConstFetch(new FullyQualified('JSON_NUMERIC_CHECK')), + new ConstFetch(new FullyQualified('JSON_THROW_ON_ERROR')), + ), 'JSON_THROW_ON_ERROR', TrinaryLogic::createYes(), ], [ - new BitwiseOr(new ConstFetch(new FullyQualified('JSON_NUMERIC_CHECK')), new ConstFetch(new FullyQualified('JSON_FORCE_OBJECT'))), + new BitwiseOr( + new ConstFetch(new FullyQualified('JSON_NUMERIC_CHECK')), + new ConstFetch(new FullyQualified('JSON_FORCE_OBJECT')), + ), 'JSON_THROW_ON_ERROR', TrinaryLogic::createNo(), ], diff --git a/tests/PHPStan/Type/BooleanTypeTest.php b/tests/PHPStan/Type/BooleanTypeTest.php index 61735476593..375210eea27 100644 --- a/tests/PHPStan/Type/BooleanTypeTest.php +++ b/tests/PHPStan/Type/BooleanTypeTest.php @@ -53,7 +53,11 @@ public function dataAccepts(): array public function testAccepts(BooleanType $type, Type $otherType, TrinaryLogic $expectedResult): void { $actualResult = $type->accepts($otherType, true); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> accepts(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> accepts(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise())), + ); } public function dataIsSuperTypeOf(): iterable @@ -95,7 +99,11 @@ public function dataIsSuperTypeOf(): iterable public function testIsSuperTypeOf(BooleanType $type, Type $otherType, TrinaryLogic $expectedResult): void { $actualResult = $type->isSuperTypeOf($otherType); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isSuperTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isSuperTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise())), + ); } public function dataEquals(): array @@ -145,7 +153,11 @@ public function dataEquals(): array public function testEquals(BooleanType $type, Type $otherType, bool $expectedResult): void { $actualResult = $type->equals($otherType); - $this->assertSame($expectedResult, $actualResult, sprintf('%s->equals(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult, + $actualResult, + sprintf('%s->equals(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise())), + ); } } diff --git a/tests/PHPStan/Type/CallableTypeTest.php b/tests/PHPStan/Type/CallableTypeTest.php index 89371b7574d..1f6e0dc3791 100644 --- a/tests/PHPStan/Type/CallableTypeTest.php +++ b/tests/PHPStan/Type/CallableTypeTest.php @@ -59,7 +59,11 @@ public function dataIsSuperTypeOf(): array public function testIsSuperTypeOf(CallableType $type, Type $otherType, TrinaryLogic $expectedResult): void { $actualResult = $type->isSuperTypeOf($otherType); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isSuperTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isSuperTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise())), + ); } public function dataIsSubTypeOf(): array @@ -134,7 +138,11 @@ public function dataIsSubTypeOf(): array public function testIsSubTypeOf(CallableType $type, Type $otherType, TrinaryLogic $expectedResult): void { $actualResult = $type->isSubTypeOf($otherType); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isSubTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isSubTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise())), + ); } /** @@ -143,69 +151,108 @@ public function testIsSubTypeOf(CallableType $type, Type $otherType, TrinaryLogi public function testIsSubTypeOfInversed(CallableType $type, Type $otherType, TrinaryLogic $expectedResult): void { $actualResult = $otherType->isSuperTypeOf($type); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isSuperTypeOf(%s)', $otherType->describe(VerbosityLevel::precise()), $type->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isSuperTypeOf(%s)', $otherType->describe(VerbosityLevel::precise()), $type->describe(VerbosityLevel::precise())), + ); } public function dataInferTemplateTypes(): array { - $param = static function (Type $type) : NativeParameterReflection { - return new NativeParameterReflection('', false, $type, PassedByReference::createNo(), false, null); - }; + $param = static fn (Type $type): NativeParameterReflection => new NativeParameterReflection( + '', + false, + $type, + PassedByReference::createNo(), + false, + null, + ); - $templateType = static function (string $name) : Type { - return TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('a'), $name, new MixedType(), TemplateTypeVariance::createInvariant()); - }; + $templateType = static fn (string $name): Type => TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('a'), + $name, + new MixedType(), + TemplateTypeVariance::createInvariant(), + ); return [ 'template param' => [ - new CallableType([ + new CallableType( + [ $param(new StringType()), - ], new IntegerType()), - new CallableType([ + ], + new IntegerType(), + ), + new CallableType( + [ $param($templateType('T')), - ], new IntegerType()), + ], + new IntegerType(), + ), ['T' => 'string'], ], 'template return' => [ - new CallableType([ + new CallableType( + [ $param(new StringType()), - ], new IntegerType()), - new CallableType([ + ], + new IntegerType(), + ), + new CallableType( + [ $param(new StringType()), - ], $templateType('T')), + ], + $templateType('T'), + ), ['T' => 'int'], ], 'multiple templates' => [ - new CallableType([ + new CallableType( + [ $param(new StringType()), $param(new ObjectType('DateTime')), - ], new IntegerType()), - new CallableType([ + ], + new IntegerType(), + ), + new CallableType( + [ $param(new StringType()), $param($templateType('A')), - ], $templateType('B')), + ], + $templateType('B'), + ), ['B' => 'int', 'A' => 'DateTime'], ], 'receive union' => [ new UnionType([ new NullType(), - new CallableType([ + new CallableType( + [ $param(new StringType()), $param(new ObjectType('DateTime')), - ], new IntegerType()), + ], + new IntegerType(), + ), ]), - new CallableType([ + new CallableType( + [ $param(new StringType()), $param($templateType('A')), - ], $templateType('B')), + ], + $templateType('B'), + ), ['B' => 'int', 'A' => 'DateTime'], ], 'receive non-accepted' => [ new NullType(), - new CallableType([ + new CallableType( + [ $param(new StringType()), $param($templateType('A')), - ], $templateType('B')), + ], + $templateType('B'), + ), [], ], ]; @@ -219,9 +266,10 @@ public function testResolveTemplateTypes(Type $received, Type $template, array $ { $result = $template->inferTemplateTypes($received); - $this->assertSame($expectedTypes, array_map(static function (Type $type) : string { - return $type->describe(VerbosityLevel::precise()); - }, $result->getTypes())); + $this->assertSame( + $expectedTypes, + array_map(static fn (Type $type): string => $type->describe(VerbosityLevel::precise()), $result->getTypes()), + ); } public function dataAccepts(): array @@ -296,9 +344,17 @@ public function dataAccepts(): array /** * @dataProvider dataAccepts */ - public function testAccepts(CallableType $type, Type $acceptedType, TrinaryLogic $expectedResult) : void + public function testAccepts( + CallableType $type, + Type $acceptedType, + TrinaryLogic $expectedResult, + ): void { - $this->assertSame($expectedResult->describe(), $type->accepts($acceptedType, true)->describe(), sprintf('%s -> accepts(%s)', $type->describe(VerbosityLevel::precise()), $acceptedType->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $type->accepts($acceptedType, true)->describe(), + sprintf('%s -> accepts(%s)', $type->describe(VerbosityLevel::precise()), $acceptedType->describe(VerbosityLevel::precise())), + ); } } diff --git a/tests/PHPStan/Type/ClassStringTypeTest.php b/tests/PHPStan/Type/ClassStringTypeTest.php index 8fccb964748..2d827f72718 100644 --- a/tests/PHPStan/Type/ClassStringTypeTest.php +++ b/tests/PHPStan/Type/ClassStringTypeTest.php @@ -45,7 +45,11 @@ public function dataIsSuperTypeOf(): array public function testIsSuperTypeOf(ClassStringType $type, Type $otherType, TrinaryLogic $expectedResult): void { $actualResult = $type->isSuperTypeOf($otherType); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isSuperTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isSuperTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise())), + ); } public function dataAccepts(): iterable @@ -105,7 +109,11 @@ public function dataAccepts(): iterable public function testAccepts(ClassStringType $type, Type $otherType, TrinaryLogic $expectedResult): void { $actualResult = $type->accepts($otherType, true); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> accepts(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> accepts(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise())), + ); } public function dataEquals(): array @@ -130,7 +138,11 @@ public function dataEquals(): array public function testEquals(ClassStringType $type, Type $otherType, bool $expectedResult): void { $actualResult = $type->equals($otherType); - $this->assertSame($expectedResult, $actualResult, sprintf('%s->equals(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult, + $actualResult, + sprintf('%s->equals(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise())), + ); } } diff --git a/tests/PHPStan/Type/ClosureTypeFactoryTest.php b/tests/PHPStan/Type/ClosureTypeFactoryTest.php index 656c130ab10..7e3a4537b3b 100644 --- a/tests/PHPStan/Type/ClosureTypeFactoryTest.php +++ b/tests/PHPStan/Type/ClosureTypeFactoryTest.php @@ -15,9 +15,7 @@ public function dataFromClosureObjectReturnType(): array }, 'void'], [static function () { // @phpcs:ignore }, 'mixed'], - [static function () : int { - return 5; - }, 'int'], + [static fn (): int => 5, 'int'], ]; } diff --git a/tests/PHPStan/Type/ClosureTypeTest.php b/tests/PHPStan/Type/ClosureTypeTest.php index 41e57bb0b9b..f8d029048e3 100644 --- a/tests/PHPStan/Type/ClosureTypeTest.php +++ b/tests/PHPStan/Type/ClosureTypeTest.php @@ -89,10 +89,18 @@ public function dataIsSuperTypeOf(): array /** * @dataProvider dataIsSuperTypeOf */ - public function testIsSuperTypeOf(Type $type, Type $otherType, TrinaryLogic $expectedResult) : void + public function testIsSuperTypeOf( + Type $type, + Type $otherType, + TrinaryLogic $expectedResult, + ): void { $actualResult = $type->isSuperTypeOf($otherType); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isSuperTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isSuperTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise())), + ); } } diff --git a/tests/PHPStan/Type/Constant/ConstantArrayTypeBuilderTest.php b/tests/PHPStan/Type/Constant/ConstantArrayTypeBuilderTest.php index 8e2f54eb783..0b8bff2efbf 100644 --- a/tests/PHPStan/Type/Constant/ConstantArrayTypeBuilderTest.php +++ b/tests/PHPStan/Type/Constant/ConstantArrayTypeBuilderTest.php @@ -59,7 +59,11 @@ public function testOptionalKeysNextAutoIndex(): void public function testNextAutoIndex(): void { - $builder = ConstantArrayTypeBuilder::createFromConstantArray(new ConstantArrayType([new ConstantIntegerType(0)], [new ConstantStringType('foo')], [1])); + $builder = ConstantArrayTypeBuilder::createFromConstantArray(new ConstantArrayType( + [new ConstantIntegerType(0)], + [new ConstantStringType('foo')], + [1], + )); $builder->setOffsetValueType(new ConstantIntegerType(0), new ConstantStringType('bar')); $array = $builder->getArray(); $this->assertInstanceOf(ConstantArrayType::class, $array); @@ -69,7 +73,11 @@ public function testNextAutoIndex(): void public function testNextAutoIndexAnother(): void { - $builder = ConstantArrayTypeBuilder::createFromConstantArray(new ConstantArrayType([new ConstantIntegerType(0)], [new ConstantStringType('foo')], [1])); + $builder = ConstantArrayTypeBuilder::createFromConstantArray(new ConstantArrayType( + [new ConstantIntegerType(0)], + [new ConstantStringType('foo')], + [1], + )); $builder->setOffsetValueType(new ConstantIntegerType(1), new ConstantStringType('bar')); $array = $builder->getArray(); $this->assertInstanceOf(ConstantArrayType::class, $array); diff --git a/tests/PHPStan/Type/Constant/ConstantArrayTypeTest.php b/tests/PHPStan/Type/Constant/ConstantArrayTypeTest.php index eeb254006ae..049139818e2 100644 --- a/tests/PHPStan/Type/Constant/ConstantArrayTypeTest.php +++ b/tests/PHPStan/Type/Constant/ConstantArrayTypeTest.php @@ -119,17 +119,20 @@ public function dataAccepts(): iterable ]; yield [ - TypeCombinator::union(new ConstantArrayType([ + TypeCombinator::union( + new ConstantArrayType([ new ConstantStringType('name'), ], [ new StringType(), - ]), new ConstantArrayType([ + ]), + new ConstantArrayType([ new ConstantStringType('name'), new ConstantStringType('color'), ], [ new StringType(), new StringType(), - ])), + ]), + ), new ConstantArrayType([ new ConstantStringType('name'), new ConstantStringType('color'), @@ -157,13 +160,16 @@ public function dataAccepts(): iterable ]; yield [ - TypeCombinator::union(new ConstantArrayType([], []), new ConstantArrayType([ + TypeCombinator::union( + new ConstantArrayType([], []), + new ConstantArrayType([ new ConstantStringType('name'), new ConstantStringType('color'), ], [ new StringType(), new StringType(), - ])), + ]), + ), new ConstantArrayType([ new ConstantStringType('surname'), ], [ @@ -347,7 +353,11 @@ public function dataAccepts(): iterable public function testAccepts(Type $type, Type $otherType, TrinaryLogic $expectedResult): void { $actualResult = $type->accepts($otherType, true); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> accepts(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> accepts(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise())), + ); } public function dataIsSuperTypeOf(): iterable @@ -591,81 +601,112 @@ public function dataIsSuperTypeOf(): iterable public function testIsSuperTypeOf(ConstantArrayType $type, Type $otherType, TrinaryLogic $expectedResult): void { $actualResult = $type->isSuperTypeOf($otherType); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isSuperTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isSuperTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise())), + ); } public function dataInferTemplateTypes(): array { - $templateType = static function (string $name) : Type { - return TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('a'), $name, new MixedType(), TemplateTypeVariance::createInvariant()); - }; + $templateType = static fn (string $name): Type => TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('a'), + $name, + new MixedType(), + TemplateTypeVariance::createInvariant(), + ); return [ 'receive constant array' => [ - new ConstantArrayType([ + new ConstantArrayType( + [ new ConstantStringType('a'), new ConstantStringType('b'), - ], [ + ], + [ new StringType(), new IntegerType(), - ]), - new ConstantArrayType([ + ], + ), + new ConstantArrayType( + [ new ConstantStringType('a'), new ConstantStringType('b'), - ], [ + ], + [ $templateType('T'), $templateType('U'), - ]), + ], + ), ['T' => 'string', 'U' => 'int'], ], 'receive constant array int' => [ - new ConstantArrayType([ + new ConstantArrayType( + [ new ConstantIntegerType(0), new ConstantIntegerType(1), - ], [ + ], + [ new StringType(), new IntegerType(), - ]), - new ConstantArrayType([ + ], + ), + new ConstantArrayType( + [ new ConstantIntegerType(0), new ConstantIntegerType(1), - ], [ + ], + [ $templateType('T'), $templateType('U'), - ]), + ], + ), ['T' => 'string', 'U' => 'int'], ], 'receive incompatible constant array' => [ - new ConstantArrayType([ + new ConstantArrayType( + [ new ConstantStringType('c'), - ], [ + ], + [ new StringType(), - ]), - new ConstantArrayType([ + ], + ), + new ConstantArrayType( + [ new ConstantStringType('a'), new ConstantStringType('b'), - ], [ + ], + [ $templateType('T'), $templateType('U'), - ]), + ], + ), [], ], 'receive mixed' => [ new MixedType(), - new ConstantArrayType([ + new ConstantArrayType( + [ new ConstantStringType('a'), - ], [ + ], + [ $templateType('T'), - ]), + ], + ), [], ], 'receive array' => [ new ArrayType(new MixedType(), new StringType()), - new ConstantArrayType([ + new ConstantArrayType( + [ new ConstantStringType('a'), - ], [ + ], + [ $templateType('T'), - ]), + ], + ), ['T' => 'string'], ], ]; @@ -679,9 +720,10 @@ public function testResolveTemplateTypes(Type $received, Type $template, array $ { $result = $template->inferTemplateTypes($received); - $this->assertSame($expectedTypes, array_map(static function (Type $type) : string { - return $type->describe(VerbosityLevel::precise()); - }, $result->getTypes())); + $this->assertSame( + $expectedTypes, + array_map(static fn (Type $type): string => $type->describe(VerbosityLevel::precise()), $result->getTypes()), + ); } /** @@ -690,7 +732,11 @@ public function testResolveTemplateTypes(Type $received, Type $template, array $ public function testIsCallable(ConstantArrayType $type, TrinaryLogic $expectedResult): void { $actualResult = $type->isCallable(); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isCallable()', $type->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isCallable()', $type->describe(VerbosityLevel::precise())), + ); } public function dataIsCallable(): iterable @@ -896,7 +942,12 @@ public function dataValuesArray(): iterable public function testValuesArray(ConstantArrayType $type, ConstantArrayType $expectedType): void { $actualType = $type->getValuesArray(); - $message = sprintf('Values array of %s is %s, but should be %s', $type->describe(VerbosityLevel::precise()), $actualType->describe(VerbosityLevel::precise()), $expectedType->describe(VerbosityLevel::precise())); + $message = sprintf( + 'Values array of %s is %s, but should be %s', + $type->describe(VerbosityLevel::precise()), + $actualType->describe(VerbosityLevel::precise()), + $expectedType->describe(VerbosityLevel::precise()), + ); $this->assertTrue($expectedType->equals($actualType), $message); $this->assertSame($expectedType->isList(), $actualType->isList()); $this->assertSame($expectedType->getNextAutoIndexes(), $actualType->getNextAutoIndexes()); diff --git a/tests/PHPStan/Type/Constant/ConstantFloatTypeTest.php b/tests/PHPStan/Type/Constant/ConstantFloatTypeTest.php index 21010555484..2122e3c8297 100644 --- a/tests/PHPStan/Type/Constant/ConstantFloatTypeTest.php +++ b/tests/PHPStan/Type/Constant/ConstantFloatTypeTest.php @@ -41,7 +41,10 @@ public function dataDescribe(): array /** * @dataProvider dataDescribe */ - public function testDescribe(ConstantFloatType $type, string $expectedDescription) : void + public function testDescribe( + ConstantFloatType $type, + string $expectedDescription, + ): void { $this->assertSame($expectedDescription, $type->describe(VerbosityLevel::precise())); } diff --git a/tests/PHPStan/Type/Constant/ConstantIntegerTypeTest.php b/tests/PHPStan/Type/Constant/ConstantIntegerTypeTest.php index d78252befe3..1b39e5ff557 100644 --- a/tests/PHPStan/Type/Constant/ConstantIntegerTypeTest.php +++ b/tests/PHPStan/Type/Constant/ConstantIntegerTypeTest.php @@ -39,7 +39,11 @@ public function dataAccepts(): iterable public function testAccepts(ConstantIntegerType $type, Type $otherType, TrinaryLogic $expectedResult): void { $actualResult = $type->accepts($otherType, true); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> accepts(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> accepts(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise())), + ); } public function dataIsSuperTypeOf(): iterable @@ -69,7 +73,11 @@ public function dataIsSuperTypeOf(): iterable public function testIsSuperTypeOf(ConstantIntegerType $type, Type $otherType, TrinaryLogic $expectedResult): void { $actualResult = $type->isSuperTypeOf($otherType); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isSuperTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isSuperTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise())), + ); } } diff --git a/tests/PHPStan/Type/Constant/ConstantStringTypeTest.php b/tests/PHPStan/Type/Constant/ConstantStringTypeTest.php index a7472c0cdf2..4acb72d2809 100644 --- a/tests/PHPStan/Type/Constant/ConstantStringTypeTest.php +++ b/tests/PHPStan/Type/Constant/ConstantStringTypeTest.php @@ -70,27 +70,52 @@ public function dataIsSuperTypeOf(): array ], 8 => [ new ConstantStringType(Exception::class), - new GenericClassStringType(TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('foo'), 'T', null, TemplateTypeVariance::createInvariant())), + new GenericClassStringType(TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('foo'), + 'T', + null, + TemplateTypeVariance::createInvariant(), + )), TrinaryLogic::createMaybe(), ], 9 => [ new ConstantStringType(Exception::class), - new GenericClassStringType(TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('foo'), 'T', new ObjectType(Exception::class), TemplateTypeVariance::createInvariant())), + new GenericClassStringType(TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('foo'), + 'T', + new ObjectType(Exception::class), + TemplateTypeVariance::createInvariant(), + )), TrinaryLogic::createMaybe(), ], 10 => [ new ConstantStringType(InvalidArgumentException::class), - new GenericClassStringType(TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('foo'), 'T', new ObjectType(Exception::class), TemplateTypeVariance::createInvariant())), + new GenericClassStringType(TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('foo'), + 'T', + new ObjectType(Exception::class), + TemplateTypeVariance::createInvariant(), + )), TrinaryLogic::createMaybe(), ], 11 => [ new ConstantStringType(Throwable::class), - new GenericClassStringType(TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('foo'), 'T', new ObjectType(Exception::class), TemplateTypeVariance::createInvariant())), + new GenericClassStringType(TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('foo'), + 'T', + new ObjectType(Exception::class), + TemplateTypeVariance::createInvariant(), + )), TrinaryLogic::createNo(), ], 12 => [ new ConstantStringType(stdClass::class), - new GenericClassStringType(TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('foo'), 'T', new ObjectType(Exception::class), TemplateTypeVariance::createInvariant())), + new GenericClassStringType(TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('foo'), + 'T', + new ObjectType(Exception::class), + TemplateTypeVariance::createInvariant(), + )), TrinaryLogic::createNo(), ], 13 => [ @@ -117,7 +142,11 @@ public function dataIsSuperTypeOf(): array public function testIsSuperTypeOf(ConstantStringType $type, Type $otherType, TrinaryLogic $expectedResult): void { $actualResult = $type->isSuperTypeOf($otherType); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isSuperTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isSuperTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise())), + ); } public function testGeneralize(): void diff --git a/tests/PHPStan/Type/Constant/OversizedArrayBuilderTest.php b/tests/PHPStan/Type/Constant/OversizedArrayBuilderTest.php index 37e350181c3..e083852496f 100644 --- a/tests/PHPStan/Type/Constant/OversizedArrayBuilderTest.php +++ b/tests/PHPStan/Type/Constant/OversizedArrayBuilderTest.php @@ -68,9 +68,7 @@ public function testBuild(string $sourceCode, string $expectedTypeDescription): $builder = new OversizedArrayBuilder(); $initializerExprTypeResolver = self::getContainer()->getByType(InitializerExprTypeResolver::class); - $arrayType = $builder->build($array, static function (Expr $expr) use($initializerExprTypeResolver) : Type { - return $initializerExprTypeResolver->getType($expr, InitializerExprContext::createEmpty()); - }); + $arrayType = $builder->build($array, static fn (Expr $expr): Type => $initializerExprTypeResolver->getType($expr, InitializerExprContext::createEmpty())); $this->assertSame($expectedTypeDescription, $arrayType->describe(VerbosityLevel::precise())); } diff --git a/tests/PHPStan/Type/Enum/EnumCaseObjectTypeTest.php b/tests/PHPStan/Type/Enum/EnumCaseObjectTypeTest.php index dacc1572143..e700d67a3d7 100644 --- a/tests/PHPStan/Type/Enum/EnumCaseObjectTypeTest.php +++ b/tests/PHPStan/Type/Enum/EnumCaseObjectTypeTest.php @@ -111,7 +111,11 @@ public function testIsSuperTypeOf(Type $type, Type $otherType, TrinaryLogic $exp $this->markTestSkipped('Test requires PHP 8.1.'); } $actualResult = $type->isSuperTypeOf($otherType); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isSuperTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isSuperTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise())), + ); } public function dataAccepts(): iterable @@ -203,12 +207,21 @@ public function dataAccepts(): iterable /** * @dataProvider dataAccepts */ - public function testAccepts(Type $type, Type $acceptedType, TrinaryLogic $expectedResult) : void + public function testAccepts( + Type $type, + Type $acceptedType, + TrinaryLogic $expectedResult, + ): void { if (PHP_VERSION_ID < 80100) { $this->markTestSkipped('Test requires PHP 8.1.'); } - $this->assertSame($expectedResult->describe(), $type->accepts($acceptedType, true)->describe(), sprintf('%s -> accepts(%s)', $type->describe(VerbosityLevel::precise()), $acceptedType->describe(VerbosityLevel::precise()))); + + $this->assertSame( + $expectedResult->describe(), + $type->accepts($acceptedType, true)->describe(), + sprintf('%s -> accepts(%s)', $type->describe(VerbosityLevel::precise()), $acceptedType->describe(VerbosityLevel::precise())), + ); } } diff --git a/tests/PHPStan/Type/FileTypeMapperTest.php b/tests/PHPStan/Type/FileTypeMapperTest.php index c66d29e8c52..a5be40c268e 100644 --- a/tests/PHPStan/Type/FileTypeMapperTest.php +++ b/tests/PHPStan/Type/FileTypeMapperTest.php @@ -102,10 +102,19 @@ public function testFileWithDependentPhpDocs(): void throw new ShouldNotHappenException(); } - $resolved = $fileTypeMapper->getResolvedPhpDoc($realpath, Foo::class, null, 'addPages', '/** @param Foo[]|Foo|\Iterator $pages */'); + $resolved = $fileTypeMapper->getResolvedPhpDoc( + $realpath, + Foo::class, + null, + 'addPages', + '/** @param Foo[]|Foo|\Iterator $pages */', + ); $this->assertCount(1, $resolved->getParamTags()); - $this->assertSame('(DependentPhpDocs\Foo&iterable)|(iterable&Iterator)', $resolved->getParamTags()['pages']->getType()->describe(VerbosityLevel::precise())); + $this->assertSame( + '(DependentPhpDocs\Foo&iterable)|(iterable&Iterator)', + $resolved->getParamTags()['pages']->getType()->describe(VerbosityLevel::precise()), + ); } public function testFileThrowsPhpDocs(): void @@ -123,14 +132,20 @@ public function testFileThrowsPhpDocs(): void */'); $this->assertNotNull($resolved->getThrowsTag()); - $this->assertSame(RuntimeException::class, $resolved->getThrowsTag()->getType()->describe(VerbosityLevel::precise())); + $this->assertSame( + RuntimeException::class, + $resolved->getThrowsTag()->getType()->describe(VerbosityLevel::precise()), + ); $resolved = $fileTypeMapper->getResolvedPhpDoc($realpath, \ThrowsPhpDocs\Foo::class, null, 'throwRuntimeAndLogicException', '/** * @throws RuntimeException|LogicException */'); $this->assertNotNull($resolved->getThrowsTag()); - $this->assertSame('LogicException|RuntimeException', $resolved->getThrowsTag()->getType()->describe(VerbosityLevel::precise())); + $this->assertSame( + 'LogicException|RuntimeException', + $resolved->getThrowsTag()->getType()->describe(VerbosityLevel::precise()), + ); $resolved = $fileTypeMapper->getResolvedPhpDoc($realpath, \ThrowsPhpDocs\Foo::class, null, 'throwRuntimeAndLogicException2', '/** * @throws RuntimeException @@ -138,7 +153,10 @@ public function testFileThrowsPhpDocs(): void */'); $this->assertNotNull($resolved->getThrowsTag()); - $this->assertSame('LogicException|RuntimeException', $resolved->getThrowsTag()->getType()->describe(VerbosityLevel::precise())); + $this->assertSame( + 'LogicException|RuntimeException', + $resolved->getThrowsTag()->getType()->describe(VerbosityLevel::precise()), + ); } public function testFileWithCyclicPhpDocs(): void @@ -153,7 +171,13 @@ public function testFileWithCyclicPhpDocs(): void throw new ShouldNotHappenException(); } - $resolved = $fileTypeMapper->getResolvedPhpDoc($realpath, \CyclicPhpDocs\Foo::class, null, 'getIterator', '/** @return iterable | Foo */'); + $resolved = $fileTypeMapper->getResolvedPhpDoc( + $realpath, + \CyclicPhpDocs\Foo::class, + null, + 'getIterator', + '/** @return iterable | Foo */', + ); /** @var ReturnTag $returnTag */ $returnTag = $resolved->getReturnTag(); diff --git a/tests/PHPStan/Type/FloatTypeTest.php b/tests/PHPStan/Type/FloatTypeTest.php index 40e47c664df..ef878bf6dd1 100644 --- a/tests/PHPStan/Type/FloatTypeTest.php +++ b/tests/PHPStan/Type/FloatTypeTest.php @@ -67,7 +67,11 @@ public function testAccepts(Type $otherType, TrinaryLogic $expectedResult): void { $type = new FloatType(); $actualResult = $type->accepts($otherType, true); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> accepts(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> accepts(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise())), + ); } public function dataEquals(): array @@ -122,7 +126,11 @@ public function dataEquals(): array public function testEquals(FloatType $type, Type $otherType, bool $expectedResult): void { $actualResult = $type->equals($otherType); - $this->assertSame($expectedResult, $actualResult, sprintf('%s->equals(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult, + $actualResult, + sprintf('%s->equals(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise())), + ); } } diff --git a/tests/PHPStan/Type/Generic/GenericClassStringTypeTest.php b/tests/PHPStan/Type/Generic/GenericClassStringTypeTest.php index f0c6862e5e8..3efd727f4c7 100644 --- a/tests/PHPStan/Type/Generic/GenericClassStringTypeTest.php +++ b/tests/PHPStan/Type/Generic/GenericClassStringTypeTest.php @@ -83,27 +83,52 @@ public function dataIsSuperTypeOf(): array TrinaryLogic::createNo(), ], 10 => [ - new GenericClassStringType(TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('foo'), 'T', null, TemplateTypeVariance::createInvariant())), + new GenericClassStringType(TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('foo'), + 'T', + null, + TemplateTypeVariance::createInvariant(), + )), new ConstantStringType(Exception::class), TrinaryLogic::createYes(), ], 11 => [ - new GenericClassStringType(TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('foo'), 'T', new ObjectType(Exception::class), TemplateTypeVariance::createInvariant())), + new GenericClassStringType(TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('foo'), + 'T', + new ObjectType(Exception::class), + TemplateTypeVariance::createInvariant(), + )), new ConstantStringType(Exception::class), TrinaryLogic::createYes(), ], 12 => [ - new GenericClassStringType(TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('foo'), 'T', new ObjectType(Exception::class), TemplateTypeVariance::createInvariant())), + new GenericClassStringType(TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('foo'), + 'T', + new ObjectType(Exception::class), + TemplateTypeVariance::createInvariant(), + )), new ConstantStringType(stdClass::class), TrinaryLogic::createNo(), ], 13 => [ - new GenericClassStringType(TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('foo'), 'T', new ObjectType(Exception::class), TemplateTypeVariance::createInvariant())), + new GenericClassStringType(TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('foo'), + 'T', + new ObjectType(Exception::class), + TemplateTypeVariance::createInvariant(), + )), new ConstantStringType(InvalidArgumentException::class), TrinaryLogic::createYes(), ], 14 => [ - new GenericClassStringType(TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('foo'), 'T', new ObjectType(Exception::class), TemplateTypeVariance::createInvariant())), + new GenericClassStringType(TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('foo'), + 'T', + new ObjectType(Exception::class), + TemplateTypeVariance::createInvariant(), + )), new ConstantStringType(Throwable::class), TrinaryLogic::createMaybe(), ], @@ -139,7 +164,11 @@ public function dataIsSuperTypeOf(): array public function testIsSuperTypeOf(GenericClassStringType $type, Type $otherType, TrinaryLogic $expectedResult): void { $actualResult = $type->isSuperTypeOf($otherType); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isSuperTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isSuperTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise())), + ); } public function dataAccepts(): array @@ -176,12 +205,22 @@ public function dataAccepts(): array TrinaryLogic::createYes(), ], 6 => [ - new GenericClassStringType(TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('foo'), 'T', null, TemplateTypeVariance::createInvariant())), + new GenericClassStringType(TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('foo'), + 'T', + null, + TemplateTypeVariance::createInvariant(), + )), new ConstantStringType('NonexistentClass'), TrinaryLogic::createNo(), ], 7 => [ - new GenericClassStringType(TemplateTypeFactory::create(TemplateTypeScope::createWithClass('Foo'), 'T', null, TemplateTypeVariance::createInvariant())), + new GenericClassStringType(TemplateTypeFactory::create( + TemplateTypeScope::createWithClass('Foo'), + 'T', + null, + TemplateTypeVariance::createInvariant(), + )), new UnionType([ new ConstantStringType(DateTime::class), new ConstantStringType(Exception::class), @@ -189,22 +228,47 @@ public function dataAccepts(): array TrinaryLogic::createYes(), ], 8 => [ - new GenericClassStringType(TemplateTypeFactory::create(TemplateTypeScope::createWithClass('Foo'), 'T', new ObjectWithoutClassType(), TemplateTypeVariance::createInvariant())), + new GenericClassStringType(TemplateTypeFactory::create( + TemplateTypeScope::createWithClass('Foo'), + 'T', + new ObjectWithoutClassType(), + TemplateTypeVariance::createInvariant(), + )), new ClassStringType(), TrinaryLogic::createYes(), ], 9 => [ - new GenericClassStringType(TemplateTypeFactory::create(TemplateTypeScope::createWithClass('Foo'), 'T', new ObjectWithoutClassType(), TemplateTypeVariance::createInvariant())), - new GenericClassStringType(TemplateTypeFactory::create(TemplateTypeScope::createWithClass('Boo'), 'U', new ObjectWithoutClassType(), TemplateTypeVariance::createInvariant())), + new GenericClassStringType(TemplateTypeFactory::create( + TemplateTypeScope::createWithClass('Foo'), + 'T', + new ObjectWithoutClassType(), + TemplateTypeVariance::createInvariant(), + )), + new GenericClassStringType(TemplateTypeFactory::create( + TemplateTypeScope::createWithClass('Boo'), + 'U', + new ObjectWithoutClassType(), + TemplateTypeVariance::createInvariant(), + )), TrinaryLogic::createMaybe(), ], 10 => [ - new GenericClassStringType(TemplateTypeFactory::create(TemplateTypeScope::createWithClass('Foo'), 'T', new ObjectWithoutClassType(), TemplateTypeVariance::createInvariant())), + new GenericClassStringType(TemplateTypeFactory::create( + TemplateTypeScope::createWithClass('Foo'), + 'T', + new ObjectWithoutClassType(), + TemplateTypeVariance::createInvariant(), + )), new UnionType([new IntegerType(), new StringType()]), TrinaryLogic::createMaybe(), ], 11 => [ - new GenericClassStringType(TemplateTypeFactory::create(TemplateTypeScope::createWithClass('Foo'), 'T', new ObjectWithoutClassType(), TemplateTypeVariance::createInvariant())), + new GenericClassStringType(TemplateTypeFactory::create( + TemplateTypeScope::createWithClass('Foo'), + 'T', + new ObjectWithoutClassType(), + TemplateTypeVariance::createInvariant(), + )), new BenevolentUnionType([new IntegerType(), new StringType()]), TrinaryLogic::createMaybe(), ], @@ -214,10 +278,18 @@ public function dataAccepts(): array /** * @dataProvider dataAccepts */ - public function testAccepts(GenericClassStringType $acceptingType, Type $acceptedType, TrinaryLogic $expectedResult) : void + public function testAccepts( + GenericClassStringType $acceptingType, + Type $acceptedType, + TrinaryLogic $expectedResult, + ): void { $actualResult = $acceptingType->accepts($acceptedType, true); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> accepts(%s)', $acceptingType->describe(VerbosityLevel::precise()), $acceptedType->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> accepts(%s)', $acceptingType->describe(VerbosityLevel::precise()), $acceptedType->describe(VerbosityLevel::precise())), + ); } public function dataEquals(): array @@ -258,10 +330,18 @@ public function testEquals(GenericClassStringType $type, Type $otherType, bool $ $otherTypeDescription = $otherType->describe($verbosityLevel); $actual = $type->equals($otherType); - $this->assertSame($expected, $actual, sprintf('%s -> equals(%s)', $typeDescription, $otherTypeDescription)); + $this->assertSame( + $expected, + $actual, + sprintf('%s -> equals(%s)', $typeDescription, $otherTypeDescription), + ); $actual = $otherType->equals($type); - $this->assertSame($expected, $actual, sprintf('%s -> equals(%s)', $otherTypeDescription, $typeDescription)); + $this->assertSame( + $expected, + $actual, + sprintf('%s -> equals(%s)', $otherTypeDescription, $typeDescription), + ); } } diff --git a/tests/PHPStan/Type/Generic/GenericObjectTypeTest.php b/tests/PHPStan/Type/Generic/GenericObjectTypeTest.php index 50447b1e1de..929ec087dc2 100644 --- a/tests/PHPStan/Type/Generic/GenericObjectTypeTest.php +++ b/tests/PHPStan/Type/Generic/GenericObjectTypeTest.php @@ -267,7 +267,11 @@ public function dataTypeProjections(): array public function testIsSuperTypeOf(Type $type, Type $otherType, TrinaryLogic $expectedResult): void { $actualResult = $type->isSuperTypeOf($otherType); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isSuperTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isSuperTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise())), + ); } public function dataAccepts(): array @@ -330,18 +334,29 @@ public function dataAccepts(): array * @dataProvider dataAccepts * @dataProvider dataTypeProjections */ - public function testAccepts(Type $acceptingType, Type $acceptedType, TrinaryLogic $expectedResult) : void + public function testAccepts( + Type $acceptingType, + Type $acceptedType, + TrinaryLogic $expectedResult, + ): void { $actualResult = $acceptingType->accepts($acceptedType, true); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> accepts(%s)', $acceptingType->describe(VerbosityLevel::precise()), $acceptedType->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> accepts(%s)', $acceptingType->describe(VerbosityLevel::precise()), $acceptedType->describe(VerbosityLevel::precise())), + ); } /** @return array}> */ public function dataInferTemplateTypes(): array { - $templateType = static function (string $name, ?Type $bound = null) : Type { - return TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('a'), $name, $bound ?? new MixedType(), TemplateTypeVariance::createInvariant()); - }; + $templateType = static fn (string $name, ?Type $bound = null): Type => TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('a'), + $name, + $bound ?? new MixedType(), + TemplateTypeVariance::createInvariant(), + ); return [ 'simple' => [ @@ -440,17 +455,21 @@ public function testResolveTemplateTypes(Type $received, Type $template, array $ { $result = $template->inferTemplateTypes($received); - $this->assertSame($expectedTypes, array_map(static function (Type $type) : string { - return $type->describe(VerbosityLevel::precise()); - }, $result->getTypes())); + $this->assertSame( + $expectedTypes, + array_map(static fn (Type $type): string => $type->describe(VerbosityLevel::precise()), $result->getTypes()), + ); } /** @return array}> */ public function dataGetReferencedTypeArguments(): array { - $templateType = static function (string $name, ?Type $bound = null) : TemplateType { - return TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('a'), $name, $bound ?? new MixedType(), TemplateTypeVariance::createInvariant()); - }; + $templateType = static fn (string $name, ?Type $bound = null): TemplateType => TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('a'), + $name, + $bound ?? new MixedType(), + TemplateTypeVariance::createInvariant(), + ); return [ 'param: Invariant' => [ @@ -460,7 +479,10 @@ public function dataGetReferencedTypeArguments(): array ]), false, [ - new TemplateTypeReference($templateType('T'), TemplateTypeVariance::createInvariant()), + new TemplateTypeReference( + $templateType('T'), + TemplateTypeVariance::createInvariant(), + ), ], ], 'param: Invariant' => [ @@ -472,7 +494,10 @@ public function dataGetReferencedTypeArguments(): array ]), false, [ - new TemplateTypeReference($templateType('T'), TemplateTypeVariance::createContravariant()), + new TemplateTypeReference( + $templateType('T'), + TemplateTypeVariance::createContravariant(), + ), ], ], 'param: Invariant' => [ @@ -484,7 +509,10 @@ public function dataGetReferencedTypeArguments(): array ]), false, [ - new TemplateTypeReference($templateType('T'), TemplateTypeVariance::createCovariant()), + new TemplateTypeReference( + $templateType('T'), + TemplateTypeVariance::createCovariant(), + ), ], ], 'param: Out' => [ @@ -494,7 +522,10 @@ public function dataGetReferencedTypeArguments(): array ]), false, [ - new TemplateTypeReference($templateType('T'), TemplateTypeVariance::createContravariant()), + new TemplateTypeReference( + $templateType('T'), + TemplateTypeVariance::createContravariant(), + ), ], ], 'param: Out>' => [ @@ -506,7 +537,10 @@ public function dataGetReferencedTypeArguments(): array ]), false, [ - new TemplateTypeReference($templateType('T'), TemplateTypeVariance::createContravariant()), + new TemplateTypeReference( + $templateType('T'), + TemplateTypeVariance::createContravariant(), + ), ], ], 'param: Out>>' => [ @@ -520,7 +554,10 @@ public function dataGetReferencedTypeArguments(): array ]), false, [ - new TemplateTypeReference($templateType('T'), TemplateTypeVariance::createContravariant()), + new TemplateTypeReference( + $templateType('T'), + TemplateTypeVariance::createContravariant(), + ), ], ], 'param: In' => [ @@ -530,7 +567,10 @@ public function dataGetReferencedTypeArguments(): array ]), false, [ - new TemplateTypeReference($templateType('T'), TemplateTypeVariance::createCovariant()), + new TemplateTypeReference( + $templateType('T'), + TemplateTypeVariance::createCovariant(), + ), ], ], 'param: In>' => [ @@ -542,7 +582,10 @@ public function dataGetReferencedTypeArguments(): array ]), false, [ - new TemplateTypeReference($templateType('T'), TemplateTypeVariance::createContravariant()), + new TemplateTypeReference( + $templateType('T'), + TemplateTypeVariance::createContravariant(), + ), ], ], 'param: In>>' => [ @@ -556,7 +599,10 @@ public function dataGetReferencedTypeArguments(): array ]), false, [ - new TemplateTypeReference($templateType('T'), TemplateTypeVariance::createCovariant()), + new TemplateTypeReference( + $templateType('T'), + TemplateTypeVariance::createCovariant(), + ), ], ], 'param: In>' => [ @@ -568,7 +614,10 @@ public function dataGetReferencedTypeArguments(): array ]), false, [ - new TemplateTypeReference($templateType('T'), TemplateTypeVariance::createCovariant()), + new TemplateTypeReference( + $templateType('T'), + TemplateTypeVariance::createCovariant(), + ), ], ], 'param: Out>' => [ @@ -580,7 +629,10 @@ public function dataGetReferencedTypeArguments(): array ]), false, [ - new TemplateTypeReference($templateType('T'), TemplateTypeVariance::createCovariant()), + new TemplateTypeReference( + $templateType('T'), + TemplateTypeVariance::createCovariant(), + ), ], ], 'param: Out>' => [ @@ -592,7 +644,10 @@ public function dataGetReferencedTypeArguments(): array ]), false, [ - new TemplateTypeReference($templateType('T'), TemplateTypeVariance::createInvariant()), + new TemplateTypeReference( + $templateType('T'), + TemplateTypeVariance::createInvariant(), + ), ], ], 'param: In>' => [ @@ -604,7 +659,10 @@ public function dataGetReferencedTypeArguments(): array ]), false, [ - new TemplateTypeReference($templateType('T'), TemplateTypeVariance::createInvariant()), + new TemplateTypeReference( + $templateType('T'), + TemplateTypeVariance::createInvariant(), + ), ], ], 'param: Invariant>' => [ @@ -616,7 +674,10 @@ public function dataGetReferencedTypeArguments(): array ]), false, [ - new TemplateTypeReference($templateType('T'), TemplateTypeVariance::createCovariant()), + new TemplateTypeReference( + $templateType('T'), + TemplateTypeVariance::createCovariant(), + ), ], ], 'param: Invariant>' => [ @@ -628,7 +689,10 @@ public function dataGetReferencedTypeArguments(): array ]), false, [ - new TemplateTypeReference($templateType('T'), TemplateTypeVariance::createContravariant()), + new TemplateTypeReference( + $templateType('T'), + TemplateTypeVariance::createContravariant(), + ), ], ], 'param: In>>' => [ @@ -642,7 +706,10 @@ public function dataGetReferencedTypeArguments(): array ]), false, [ - new TemplateTypeReference($templateType('T'), TemplateTypeVariance::createCovariant()), + new TemplateTypeReference( + $templateType('T'), + TemplateTypeVariance::createCovariant(), + ), ], ], 'param: Out>>' => [ @@ -656,7 +723,10 @@ public function dataGetReferencedTypeArguments(): array ]), false, [ - new TemplateTypeReference($templateType('T'), TemplateTypeVariance::createContravariant()), + new TemplateTypeReference( + $templateType('T'), + TemplateTypeVariance::createContravariant(), + ), ], ], 'return: Invariant' => [ @@ -666,7 +736,10 @@ public function dataGetReferencedTypeArguments(): array ]), false, [ - new TemplateTypeReference($templateType('T'), TemplateTypeVariance::createInvariant()), + new TemplateTypeReference( + $templateType('T'), + TemplateTypeVariance::createInvariant(), + ), ], ], 'return: Invariant' => [ @@ -678,7 +751,10 @@ public function dataGetReferencedTypeArguments(): array ]), false, [ - new TemplateTypeReference($templateType('T'), TemplateTypeVariance::createCovariant()), + new TemplateTypeReference( + $templateType('T'), + TemplateTypeVariance::createCovariant(), + ), ], ], 'return: Invariant' => [ @@ -690,7 +766,10 @@ public function dataGetReferencedTypeArguments(): array ]), false, [ - new TemplateTypeReference($templateType('T'), TemplateTypeVariance::createContravariant()), + new TemplateTypeReference( + $templateType('T'), + TemplateTypeVariance::createContravariant(), + ), ], ], 'return: Out' => [ @@ -700,7 +779,10 @@ public function dataGetReferencedTypeArguments(): array ]), false, [ - new TemplateTypeReference($templateType('T'), TemplateTypeVariance::createCovariant()), + new TemplateTypeReference( + $templateType('T'), + TemplateTypeVariance::createCovariant(), + ), ], ], 'return: Out>' => [ @@ -712,7 +794,10 @@ public function dataGetReferencedTypeArguments(): array ]), false, [ - new TemplateTypeReference($templateType('T'), TemplateTypeVariance::createCovariant()), + new TemplateTypeReference( + $templateType('T'), + TemplateTypeVariance::createCovariant(), + ), ], ], 'return: Out>>' => [ @@ -726,7 +811,10 @@ public function dataGetReferencedTypeArguments(): array ]), false, [ - new TemplateTypeReference($templateType('T'), TemplateTypeVariance::createCovariant()), + new TemplateTypeReference( + $templateType('T'), + TemplateTypeVariance::createCovariant(), + ), ], ], 'return: In' => [ @@ -736,7 +824,10 @@ public function dataGetReferencedTypeArguments(): array ]), false, [ - new TemplateTypeReference($templateType('T'), TemplateTypeVariance::createContravariant()), + new TemplateTypeReference( + $templateType('T'), + TemplateTypeVariance::createContravariant(), + ), ], ], 'return: In>' => [ @@ -748,7 +839,10 @@ public function dataGetReferencedTypeArguments(): array ]), false, [ - new TemplateTypeReference($templateType('T'), TemplateTypeVariance::createCovariant()), + new TemplateTypeReference( + $templateType('T'), + TemplateTypeVariance::createCovariant(), + ), ], ], 'return: In>>' => [ @@ -762,7 +856,10 @@ public function dataGetReferencedTypeArguments(): array ]), false, [ - new TemplateTypeReference($templateType('T'), TemplateTypeVariance::createContravariant()), + new TemplateTypeReference( + $templateType('T'), + TemplateTypeVariance::createContravariant(), + ), ], ], 'return: In>' => [ @@ -774,7 +871,10 @@ public function dataGetReferencedTypeArguments(): array ]), false, [ - new TemplateTypeReference($templateType('T'), TemplateTypeVariance::createContravariant()), + new TemplateTypeReference( + $templateType('T'), + TemplateTypeVariance::createContravariant(), + ), ], ], 'return: Out>' => [ @@ -786,7 +886,10 @@ public function dataGetReferencedTypeArguments(): array ]), false, [ - new TemplateTypeReference($templateType('T'), TemplateTypeVariance::createContravariant()), + new TemplateTypeReference( + $templateType('T'), + TemplateTypeVariance::createContravariant(), + ), ], ], 'return: Out>' => [ @@ -798,7 +901,10 @@ public function dataGetReferencedTypeArguments(): array ]), false, [ - new TemplateTypeReference($templateType('T'), TemplateTypeVariance::createInvariant()), + new TemplateTypeReference( + $templateType('T'), + TemplateTypeVariance::createInvariant(), + ), ], ], 'return: In>' => [ @@ -810,7 +916,10 @@ public function dataGetReferencedTypeArguments(): array ]), false, [ - new TemplateTypeReference($templateType('T'), TemplateTypeVariance::createInvariant()), + new TemplateTypeReference( + $templateType('T'), + TemplateTypeVariance::createInvariant(), + ), ], ], 'return: Invariant>' => [ @@ -822,7 +931,10 @@ public function dataGetReferencedTypeArguments(): array ]), false, [ - new TemplateTypeReference($templateType('T'), TemplateTypeVariance::createCovariant()), + new TemplateTypeReference( + $templateType('T'), + TemplateTypeVariance::createCovariant(), + ), ], ], 'return: Invariant>' => [ @@ -834,7 +946,10 @@ public function dataGetReferencedTypeArguments(): array ]), false, [ - new TemplateTypeReference($templateType('T'), TemplateTypeVariance::createContravariant()), + new TemplateTypeReference( + $templateType('T'), + TemplateTypeVariance::createContravariant(), + ), ], ], 'return: In>>' => [ @@ -848,7 +963,10 @@ public function dataGetReferencedTypeArguments(): array ]), false, [ - new TemplateTypeReference($templateType('T'), TemplateTypeVariance::createCovariant()), + new TemplateTypeReference( + $templateType('T'), + TemplateTypeVariance::createCovariant(), + ), ], ], 'return: Out>>' => [ @@ -862,7 +980,10 @@ public function dataGetReferencedTypeArguments(): array ]), false, [ - new TemplateTypeReference($templateType('T'), TemplateTypeVariance::createContravariant()), + new TemplateTypeReference( + $templateType('T'), + TemplateTypeVariance::createContravariant(), + ), ], ], 'param: Out> (with invariance composition)' => [ @@ -874,7 +995,10 @@ public function dataGetReferencedTypeArguments(): array ]), true, [ - new TemplateTypeReference($templateType('T'), TemplateTypeVariance::createInvariant()), + new TemplateTypeReference( + $templateType('T'), + TemplateTypeVariance::createInvariant(), + ), ], ], 'param: In> (with invariance composition)' => [ @@ -886,7 +1010,10 @@ public function dataGetReferencedTypeArguments(): array ]), true, [ - new TemplateTypeReference($templateType('T'), TemplateTypeVariance::createInvariant()), + new TemplateTypeReference( + $templateType('T'), + TemplateTypeVariance::createInvariant(), + ), ], ], 'param: Invariant> (with invariance composition)' => [ @@ -898,7 +1025,10 @@ public function dataGetReferencedTypeArguments(): array ]), true, [ - new TemplateTypeReference($templateType('T'), TemplateTypeVariance::createInvariant()), + new TemplateTypeReference( + $templateType('T'), + TemplateTypeVariance::createInvariant(), + ), ], ], 'param: Invariant> (with invariance composition)' => [ @@ -910,7 +1040,10 @@ public function dataGetReferencedTypeArguments(): array ]), true, [ - new TemplateTypeReference($templateType('T'), TemplateTypeVariance::createInvariant()), + new TemplateTypeReference( + $templateType('T'), + TemplateTypeVariance::createInvariant(), + ), ], ], 'param: In>> (with invariance composition)' => [ @@ -924,7 +1057,10 @@ public function dataGetReferencedTypeArguments(): array ]), true, [ - new TemplateTypeReference($templateType('T'), TemplateTypeVariance::createInvariant()), + new TemplateTypeReference( + $templateType('T'), + TemplateTypeVariance::createInvariant(), + ), ], ], 'param: Out>> (with invariance composition)' => [ @@ -938,7 +1074,10 @@ public function dataGetReferencedTypeArguments(): array ]), true, [ - new TemplateTypeReference($templateType('T'), TemplateTypeVariance::createInvariant()), + new TemplateTypeReference( + $templateType('T'), + TemplateTypeVariance::createInvariant(), + ), ], ], 'param: Invariant (with invariance composition)' => [ @@ -950,7 +1089,10 @@ public function dataGetReferencedTypeArguments(): array ]), true, [ - new TemplateTypeReference($templateType('T'), TemplateTypeVariance::createContravariant()), + new TemplateTypeReference( + $templateType('T'), + TemplateTypeVariance::createContravariant(), + ), ], ], 'param: Invariant (with invariance composition)' => [ @@ -962,7 +1104,10 @@ public function dataGetReferencedTypeArguments(): array ]), true, [ - new TemplateTypeReference($templateType('T'), TemplateTypeVariance::createCovariant()), + new TemplateTypeReference( + $templateType('T'), + TemplateTypeVariance::createCovariant(), + ), ], ], 'return: Out> (with invariance composition)' => [ @@ -974,7 +1119,10 @@ public function dataGetReferencedTypeArguments(): array ]), true, [ - new TemplateTypeReference($templateType('T'), TemplateTypeVariance::createInvariant()), + new TemplateTypeReference( + $templateType('T'), + TemplateTypeVariance::createInvariant(), + ), ], ], 'return: In> (with invariance composition)' => [ @@ -986,7 +1134,10 @@ public function dataGetReferencedTypeArguments(): array ]), true, [ - new TemplateTypeReference($templateType('T'), TemplateTypeVariance::createInvariant()), + new TemplateTypeReference( + $templateType('T'), + TemplateTypeVariance::createInvariant(), + ), ], ], 'return: Invariant> (with invariance composition)' => [ @@ -998,7 +1149,10 @@ public function dataGetReferencedTypeArguments(): array ]), true, [ - new TemplateTypeReference($templateType('T'), TemplateTypeVariance::createInvariant()), + new TemplateTypeReference( + $templateType('T'), + TemplateTypeVariance::createInvariant(), + ), ], ], 'return: Invariant> (with invariance composition)' => [ @@ -1010,7 +1164,10 @@ public function dataGetReferencedTypeArguments(): array ]), true, [ - new TemplateTypeReference($templateType('T'), TemplateTypeVariance::createInvariant()), + new TemplateTypeReference( + $templateType('T'), + TemplateTypeVariance::createInvariant(), + ), ], ], 'return: In>> (with invariance composition)' => [ @@ -1024,7 +1181,10 @@ public function dataGetReferencedTypeArguments(): array ]), true, [ - new TemplateTypeReference($templateType('T'), TemplateTypeVariance::createInvariant()), + new TemplateTypeReference( + $templateType('T'), + TemplateTypeVariance::createInvariant(), + ), ], ], 'return: Out>> (with invariance composition)' => [ @@ -1038,7 +1198,10 @@ public function dataGetReferencedTypeArguments(): array ]), true, [ - new TemplateTypeReference($templateType('T'), TemplateTypeVariance::createInvariant()), + new TemplateTypeReference( + $templateType('T'), + TemplateTypeVariance::createInvariant(), + ), ], ], 'return: Invariant (with invariance composition)' => [ @@ -1050,7 +1213,10 @@ public function dataGetReferencedTypeArguments(): array ]), true, [ - new TemplateTypeReference($templateType('T'), TemplateTypeVariance::createCovariant()), + new TemplateTypeReference( + $templateType('T'), + TemplateTypeVariance::createCovariant(), + ), ], ], 'return: Invariant (with invariance composition)' => [ @@ -1062,7 +1228,10 @@ public function dataGetReferencedTypeArguments(): array ]), true, [ - new TemplateTypeReference($templateType('T'), TemplateTypeVariance::createContravariant()), + new TemplateTypeReference( + $templateType('T'), + TemplateTypeVariance::createContravariant(), + ), ], ], ]; @@ -1082,19 +1251,15 @@ public function testGetReferencedTypeArguments(TemplateTypeVariance $positionVar $result[] = $r; } - $comparableResult = array_map(static function (TemplateTypeReference $ref) : array { - return [ - 'type' => $ref->getType()->describe(VerbosityLevel::typeOnly()), - 'positionVariance' => $ref->getPositionVariance()->describe(), - ]; - }, $result); + $comparableResult = array_map(static fn (TemplateTypeReference $ref): array => [ + 'type' => $ref->getType()->describe(VerbosityLevel::typeOnly()), + 'positionVariance' => $ref->getPositionVariance()->describe(), + ], $result); - $comparableExpect = array_map(static function (TemplateTypeReference $ref) : array { - return [ - 'type' => $ref->getType()->describe(VerbosityLevel::typeOnly()), - 'positionVariance' => $ref->getPositionVariance()->describe(), - ]; - }, $expectedReferences); + $comparableExpect = array_map(static fn (TemplateTypeReference $ref): array => [ + 'type' => $ref->getType()->describe(VerbosityLevel::typeOnly()), + 'positionVariance' => $ref->getPositionVariance()->describe(), + ], $expectedReferences); $this->assertSame($comparableExpect, $comparableResult); } diff --git a/tests/PHPStan/Type/Generic/TemplateTypeHelperTest.php b/tests/PHPStan/Type/Generic/TemplateTypeHelperTest.php index 7c48c25f305..2bcde9560a7 100644 --- a/tests/PHPStan/Type/Generic/TemplateTypeHelperTest.php +++ b/tests/PHPStan/Type/Generic/TemplateTypeHelperTest.php @@ -13,22 +13,43 @@ class TemplateTypeHelperTest extends PHPStanTestCase public function testIssue2512(): void { - $templateType = TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('a'), 'T', null, TemplateTypeVariance::createInvariant()); - - $type = TemplateTypeHelper::resolveTemplateTypes($templateType, new TemplateTypeMap([ + $templateType = TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('a'), + 'T', + null, + TemplateTypeVariance::createInvariant(), + ); + + $type = TemplateTypeHelper::resolveTemplateTypes( + $templateType, + new TemplateTypeMap([ 'T' => $templateType, - ]), TemplateTypeVarianceMap::createEmpty(), TemplateTypeVariance::createInvariant()); - - $this->assertEquals('T (function a(), parameter)', $type->describe(VerbosityLevel::precise())); - - $type = TemplateTypeHelper::resolveTemplateTypes($templateType, new TemplateTypeMap([ + ]), + TemplateTypeVarianceMap::createEmpty(), + TemplateTypeVariance::createInvariant(), + ); + + $this->assertEquals( + 'T (function a(), parameter)', + $type->describe(VerbosityLevel::precise()), + ); + + $type = TemplateTypeHelper::resolveTemplateTypes( + $templateType, + new TemplateTypeMap([ 'T' => new IntersectionType([ new ObjectType(DateTime::class), $templateType, ]), - ]), TemplateTypeVarianceMap::createEmpty(), TemplateTypeVariance::createInvariant()); - - $this->assertEquals('DateTime&T (function a(), parameter)', $type->describe(VerbosityLevel::precise())); + ]), + TemplateTypeVarianceMap::createEmpty(), + TemplateTypeVariance::createInvariant(), + ); + + $this->assertEquals( + 'DateTime&T (function a(), parameter)', + $type->describe(VerbosityLevel::precise()), + ); } } diff --git a/tests/PHPStan/Type/Generic/TemplateTypeVarianceTest.php b/tests/PHPStan/Type/Generic/TemplateTypeVarianceTest.php index 3f467372673..71a57dda6d8 100644 --- a/tests/PHPStan/Type/Generic/TemplateTypeVarianceTest.php +++ b/tests/PHPStan/Type/Generic/TemplateTypeVarianceTest.php @@ -79,10 +79,24 @@ public function dataIsValidVariance(): iterable /** * @dataProvider dataIsValidVariance */ - public function testIsValidVariance(TemplateTypeVariance $variance, Type $a, Type $b, TrinaryLogic $expected, TrinaryLogic $expectedInversed) : void + public function testIsValidVariance( + TemplateTypeVariance $variance, + Type $a, + Type $b, + TrinaryLogic $expected, + TrinaryLogic $expectedInversed, + ): void { - $this->assertSame($expected->describe(), $variance->isValidVariance($a, $b)->describe(), sprintf('%s->isValidVariance(%s, %s)', $variance->describe(), $a->describe(VerbosityLevel::precise()), $b->describe(VerbosityLevel::precise()))); - $this->assertSame($expectedInversed->describe(), $variance->isValidVariance($b, $a)->describe(), sprintf('%s->isValidVariance(%s, %s)', $variance->describe(), $b->describe(VerbosityLevel::precise()), $a->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expected->describe(), + $variance->isValidVariance($a, $b)->describe(), + sprintf('%s->isValidVariance(%s, %s)', $variance->describe(), $a->describe(VerbosityLevel::precise()), $b->describe(VerbosityLevel::precise())), + ); + $this->assertSame( + $expectedInversed->describe(), + $variance->isValidVariance($b, $a)->describe(), + sprintf('%s->isValidVariance(%s, %s)', $variance->describe(), $b->describe(VerbosityLevel::precise()), $a->describe(VerbosityLevel::precise())), + ); } } diff --git a/tests/PHPStan/Type/IntegerTypeTest.php b/tests/PHPStan/Type/IntegerTypeTest.php index f580ac2b9c5..a1c83f78853 100644 --- a/tests/PHPStan/Type/IntegerTypeTest.php +++ b/tests/PHPStan/Type/IntegerTypeTest.php @@ -54,7 +54,11 @@ public function dataAccepts(): array public function testAccepts(IntegerType $type, Type $otherType, TrinaryLogic $expectedResult): void { $actualResult = $type->accepts($otherType, true); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> accepts(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> accepts(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise())), + ); } public function dataIsSuperTypeOf(): iterable @@ -96,7 +100,11 @@ public function dataIsSuperTypeOf(): iterable public function testIsSuperTypeOf(IntegerType $type, Type $otherType, TrinaryLogic $expectedResult): void { $actualResult = $type->isSuperTypeOf($otherType); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isSuperTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isSuperTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise())), + ); } public function dataEquals(): array @@ -151,7 +159,11 @@ public function dataEquals(): array public function testEquals(IntegerType $type, Type $otherType, bool $expectedResult): void { $actualResult = $type->equals($otherType); - $this->assertSame($expectedResult, $actualResult, sprintf('%s->equals(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult, + $actualResult, + sprintf('%s->equals(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise())), + ); } } diff --git a/tests/PHPStan/Type/IntersectionTypeTest.php b/tests/PHPStan/Type/IntersectionTypeTest.php index 03f5fa72659..aae9faa0bd9 100644 --- a/tests/PHPStan/Type/IntersectionTypeTest.php +++ b/tests/PHPStan/Type/IntersectionTypeTest.php @@ -72,7 +72,11 @@ public function dataAccepts(): Iterator public function testAccepts(IntersectionType $type, Type $otherType, TrinaryLogic $expectedResult): void { $actualResult = $type->accepts($otherType, true); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> accepts(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> accepts(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise())), + ); } public function dataIsCallable(): array @@ -80,7 +84,10 @@ public function dataIsCallable(): array return [ [ new IntersectionType([ - new ConstantArrayType([new ConstantIntegerType(0), new ConstantIntegerType(1)], [new ConstantStringType('Closure'), new ConstantStringType('bind')]), + new ConstantArrayType( + [new ConstantIntegerType(0), new ConstantIntegerType(1)], + [new ConstantStringType('Closure'), new ConstantStringType('bind')], + ), new IterableType(new MixedType(), new ObjectType('Item')), ]), TrinaryLogic::createYes(), @@ -108,7 +115,11 @@ public function dataIsCallable(): array public function testIsCallable(IntersectionType $type, TrinaryLogic $expectedResult): void { $actualResult = $type->isCallable(); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isCallable()', $type->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isCallable()', $type->describe(VerbosityLevel::precise())), + ); } public function dataIsSuperTypeOf(): Iterator @@ -273,7 +284,11 @@ public function dataIsSuperTypeOf(): Iterator public function testIsSuperTypeOf(IntersectionType $type, Type $otherType, TrinaryLogic $expectedResult): void { $actualResult = $type->isSuperTypeOf($otherType); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isSuperTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isSuperTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise())), + ); } public function dataIsSubTypeOf(): Iterator @@ -369,7 +384,11 @@ public function dataIsSubTypeOf(): Iterator public function testIsSubTypeOf(IntersectionType $type, Type $otherType, TrinaryLogic $expectedResult): void { $actualResult = $type->isSubTypeOf($otherType); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isSubTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isSubTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise())), + ); } /** @@ -378,7 +397,11 @@ public function testIsSubTypeOf(IntersectionType $type, Type $otherType, Trinary public function testIsSubTypeOfInversed(IntersectionType $type, Type $otherType, TrinaryLogic $expectedResult): void { $actualResult = $otherType->isSuperTypeOf($type); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isSuperTypeOf(%s)', $otherType->describe(VerbosityLevel::precise()), $type->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isSuperTypeOf(%s)', $otherType->describe(VerbosityLevel::precise()), $type->describe(VerbosityLevel::precise())), + ); } public function testToBooleanCrash(): void @@ -411,7 +434,10 @@ public function dataGetEnumCases(): iterable * @dataProvider dataGetEnumCases * @param list $expectedEnumCases */ - public function testGetEnumCases(IntersectionType $type, array $expectedEnumCases) : void + public function testGetEnumCases( + IntersectionType $type, + array $expectedEnumCases, + ): void { $enumCases = $type->getEnumCases(); $this->assertCount(count($expectedEnumCases), $enumCases); diff --git a/tests/PHPStan/Type/IterableTypeTest.php b/tests/PHPStan/Type/IterableTypeTest.php index ece142cd6c3..02a10d0dde3 100644 --- a/tests/PHPStan/Type/IterableTypeTest.php +++ b/tests/PHPStan/Type/IterableTypeTest.php @@ -64,7 +64,11 @@ public function dataIsSuperTypeOf(): array public function testIsSuperTypeOf(IterableType $type, Type $otherType, TrinaryLogic $expectedResult): void { $actualResult = $type->isSuperTypeOf($otherType); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isSuperTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isSuperTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise())), + ); } public function dataIsSubTypeOf(): array @@ -159,7 +163,11 @@ public function dataIsSubTypeOf(): array public function testIsSubTypeOf(IterableType $type, Type $otherType, TrinaryLogic $expectedResult): void { $actualResult = $type->isSubTypeOf($otherType); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isSubTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isSubTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise())), + ); } /** @@ -168,34 +176,59 @@ public function testIsSubTypeOf(IterableType $type, Type $otherType, TrinaryLogi public function testIsSubTypeOfInversed(IterableType $type, Type $otherType, TrinaryLogic $expectedResult): void { $actualResult = $otherType->isSuperTypeOf($type); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isSuperTypeOf(%s)', $otherType->describe(VerbosityLevel::precise()), $type->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isSuperTypeOf(%s)', $otherType->describe(VerbosityLevel::precise()), $type->describe(VerbosityLevel::precise())), + ); } public function dataInferTemplateTypes(): array { - $templateType = static function (string $name) : Type { - return TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('a'), $name, new MixedType(), TemplateTypeVariance::createInvariant()); - }; + $templateType = static fn (string $name): Type => TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('a'), + $name, + new MixedType(), + TemplateTypeVariance::createInvariant(), + ); return [ 'receive iterable' => [ - new IterableType(new MixedType(), new ObjectType('DateTime')), - new IterableType(new MixedType(), $templateType('T')), + new IterableType( + new MixedType(), + new ObjectType('DateTime'), + ), + new IterableType( + new MixedType(), + $templateType('T'), + ), ['T' => 'DateTime'], ], 'receive iterable template key' => [ - new IterableType(new StringType(), new ObjectType('DateTime')), - new IterableType($templateType('U'), $templateType('T')), + new IterableType( + new StringType(), + new ObjectType('DateTime'), + ), + new IterableType( + $templateType('U'), + $templateType('T'), + ), ['U' => 'string', 'T' => 'DateTime'], ], 'receive mixed' => [ new MixedType(), - new IterableType(new MixedType(), $templateType('T')), + new IterableType( + new MixedType(), + $templateType('T'), + ), [], ], 'receive non-accepted' => [ new StringType(), - new IterableType(new MixedType(), $templateType('T')), + new IterableType( + new MixedType(), + $templateType('T'), + ), [], ], ]; @@ -209,14 +242,20 @@ public function testResolveTemplateTypes(Type $received, Type $template, array $ { $result = $template->inferTemplateTypes($received); - $this->assertSame($expectedTypes, array_map(static function (Type $type) : string { - return $type->describe(VerbosityLevel::precise()); - }, $result->getTypes())); + $this->assertSame( + $expectedTypes, + array_map(static fn (Type $type): string => $type->describe(VerbosityLevel::precise()), $result->getTypes()), + ); } public function dataDescribe(): array { - $templateType = TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('a'), 'T', null, TemplateTypeVariance::createInvariant()); + $templateType = TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('a'), + 'T', + null, + TemplateTypeVariance::createInvariant(), + ); return [ [ @@ -259,15 +298,26 @@ public function testDescribe(Type $type, string $expect): void public function dataAccepts(): array { /** @var TemplateMixedType $t */ - $t = TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('foo'), 'T', null, TemplateTypeVariance::createInvariant()); + $t = TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('foo'), + 'T', + null, + TemplateTypeVariance::createInvariant(), + ); return [ [ - new IterableType(new MixedType(), $t), + new IterableType( + new MixedType(), + $t, + ), new ConstantArrayType([], []), TrinaryLogic::createYes(), ], [ - new IterableType(new MixedType(), $t->toArgument()), + new IterableType( + new MixedType(), + $t->toArgument(), + ), new ConstantArrayType([], []), TrinaryLogic::createYes(), ], @@ -280,7 +330,11 @@ public function dataAccepts(): array public function testAccepts(IterableType $iterableType, Type $otherType, TrinaryLogic $expectedResult): void { $actualResult = $iterableType->accepts($otherType, true); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> accepts(%s)', $iterableType->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> accepts(%s)', $iterableType->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise())), + ); } } diff --git a/tests/PHPStan/Type/MixedTypeTest.php b/tests/PHPStan/Type/MixedTypeTest.php index 164cf310c02..6ee710a8c13 100644 --- a/tests/PHPStan/Type/MixedTypeTest.php +++ b/tests/PHPStan/Type/MixedTypeTest.php @@ -165,7 +165,11 @@ public function dataIsSuperTypeOf(): array public function testIsSuperTypeOf(MixedType $type, Type $otherType, TrinaryLogic $expectedResult): void { $actualResult = $type->isSuperTypeOf($otherType); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isSuperTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isSuperTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise())), + ); } public function dataSubstractedIsArray(): array @@ -188,7 +192,10 @@ public function dataSubstractedIsArray(): array ], [ new MixedType(), - new ConstantArrayType([new ConstantIntegerType(1)], [new ConstantStringType('hello')]), + new ConstantArrayType( + [new ConstantIntegerType(1)], + [new ConstantStringType('hello')], + ), TrinaryLogic::createMaybe(), ], [ @@ -227,7 +234,11 @@ public function testSubstractedIsArray(MixedType $mixedType, Type $typeToSubtrac $subtracted = $mixedType->subtract($typeToSubtract); $actualResult = $subtracted->isArray(); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isArray()', $subtracted->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isArray()', $subtracted->describe(VerbosityLevel::precise())), + ); } public function dataSubstractedIsConstantArray(): array @@ -250,7 +261,10 @@ public function dataSubstractedIsConstantArray(): array ], [ new MixedType(), - new ConstantArrayType([new ConstantIntegerType(1)], [new ConstantStringType('hello')]), + new ConstantArrayType( + [new ConstantIntegerType(1)], + [new ConstantStringType('hello')], + ), TrinaryLogic::createMaybe(), ], [ @@ -294,7 +308,11 @@ public function testSubstractedIsConstantArray(MixedType $mixedType, Type $typeT $subtracted = $mixedType->subtract($typeToSubtract); $actualResult = $subtracted->isConstantArray(); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isConstantArray()', $subtracted->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isConstantArray()', $subtracted->describe(VerbosityLevel::precise())), + ); } public function dataSubstractedIsString(): array @@ -307,12 +325,18 @@ public function dataSubstractedIsString(): array ], [ new MixedType(), - TypeCombinator::intersect(new StringType(), new AccessoryNonEmptyStringType()), + TypeCombinator::intersect( + new StringType(), + new AccessoryNonEmptyStringType(), + ), TrinaryLogic::createMaybe(), ], [ new MixedType(), - TypeCombinator::intersect(new StringType(), new AccessoryNumericStringType()), + TypeCombinator::intersect( + new StringType(), + new AccessoryNumericStringType(), + ), TrinaryLogic::createMaybe(), ], [ @@ -336,7 +360,11 @@ public function testSubstractedIsString(MixedType $mixedType, Type $typeToSubtra $subtracted = $mixedType->subtract($typeToSubtract); $actualResult = $subtracted->isString(); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isString()', $subtracted->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isString()', $subtracted->describe(VerbosityLevel::precise())), + ); } public function dataSubstractedIsNumericString(): array @@ -349,12 +377,18 @@ public function dataSubstractedIsNumericString(): array ], [ new MixedType(), - TypeCombinator::intersect(new StringType(), new AccessoryNonEmptyStringType()), + TypeCombinator::intersect( + new StringType(), + new AccessoryNonEmptyStringType(), + ), TrinaryLogic::createMaybe(), ], [ new MixedType(), - TypeCombinator::intersect(new StringType(), new AccessoryNumericStringType()), + TypeCombinator::intersect( + new StringType(), + new AccessoryNumericStringType(), + ), TrinaryLogic::createNo(), ], [ @@ -378,7 +412,11 @@ public function testSubstractedIsNumericString(MixedType $mixedType, Type $typeT $subtracted = $mixedType->subtract($typeToSubtract); $actualResult = $subtracted->isNumericString(); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isNumericString()', $subtracted->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isNumericString()', $subtracted->describe(VerbosityLevel::precise())), + ); } public function dataSubstractedIsNonEmptyString(): array @@ -391,17 +429,26 @@ public function dataSubstractedIsNonEmptyString(): array ], [ new MixedType(), - TypeCombinator::intersect(new StringType(), new AccessoryNonEmptyStringType()), + TypeCombinator::intersect( + new StringType(), + new AccessoryNonEmptyStringType(), + ), TrinaryLogic::createNo(), ], [ new MixedType(), - TypeCombinator::intersect(new StringType(), new AccessoryNonFalsyStringType()), + TypeCombinator::intersect( + new StringType(), + new AccessoryNonFalsyStringType(), + ), TrinaryLogic::createMaybe(), ], [ new MixedType(), - TypeCombinator::intersect(new StringType(), new AccessoryNumericStringType()), + TypeCombinator::intersect( + new StringType(), + new AccessoryNumericStringType(), + ), TrinaryLogic::createMaybe(), ], [ @@ -425,7 +472,11 @@ public function testSubstractedIsNonEmptyString(MixedType $mixedType, Type $type $subtracted = $mixedType->subtract($typeToSubtract); $actualResult = $subtracted->isNonEmptyString(); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isNonEmptyString()', $subtracted->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isNonEmptyString()', $subtracted->describe(VerbosityLevel::precise())), + ); } public function dataSubstractedIsNonFalsyString(): array @@ -438,17 +489,26 @@ public function dataSubstractedIsNonFalsyString(): array ], [ new MixedType(), - TypeCombinator::intersect(new StringType(), new AccessoryNonEmptyStringType()), + TypeCombinator::intersect( + new StringType(), + new AccessoryNonEmptyStringType(), + ), TrinaryLogic::createNo(), ], [ new MixedType(), - TypeCombinator::intersect(new StringType(), new AccessoryNonFalsyStringType()), + TypeCombinator::intersect( + new StringType(), + new AccessoryNonFalsyStringType(), + ), TrinaryLogic::createNo(), ], [ new MixedType(), - TypeCombinator::intersect(new StringType(), new AccessoryNumericStringType()), + TypeCombinator::intersect( + new StringType(), + new AccessoryNumericStringType(), + ), TrinaryLogic::createMaybe(), ], [ @@ -472,7 +532,11 @@ public function testSubstractedIsNonFalsyString(MixedType $mixedType, Type $type $subtracted = $mixedType->subtract($typeToSubtract); $actualResult = $subtracted->isNonFalsyString(); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isNonFalsyString()', $subtracted->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isNonFalsyString()', $subtracted->describe(VerbosityLevel::precise())), + ); } public function dataSubstractedIsLiteralString(): array @@ -485,22 +549,34 @@ public function dataSubstractedIsLiteralString(): array ], [ new MixedType(), - TypeCombinator::intersect(new StringType(), new AccessoryLiteralStringType()), + TypeCombinator::intersect( + new StringType(), + new AccessoryLiteralStringType(), + ), TrinaryLogic::createNo(), ], [ new MixedType(), - TypeCombinator::intersect(new StringType(), new AccessoryNonEmptyStringType()), + TypeCombinator::intersect( + new StringType(), + new AccessoryNonEmptyStringType(), + ), TrinaryLogic::createMaybe(), ], [ new MixedType(), - TypeCombinator::intersect(new StringType(), new AccessoryNonFalsyStringType()), + TypeCombinator::intersect( + new StringType(), + new AccessoryNonFalsyStringType(), + ), TrinaryLogic::createMaybe(), ], [ new MixedType(), - TypeCombinator::intersect(new StringType(), new AccessoryNumericStringType()), + TypeCombinator::intersect( + new StringType(), + new AccessoryNumericStringType(), + ), TrinaryLogic::createMaybe(), ], [ @@ -524,7 +600,11 @@ public function testSubstractedIsClassString(MixedType $mixedType, Type $typeToS $subtracted = $mixedType->subtract($typeToSubtract); $actualResult = $subtracted->isClassStringType(); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isClassStringType()', $subtracted->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isClassStringType()', $subtracted->describe(VerbosityLevel::precise())), + ); } public function dataSubstractedIsClassString(): array @@ -562,7 +642,11 @@ public function testSubtractedIsVoid(MixedType $mixedType, Type $typeToSubtract, $subtracted = $mixedType->subtract($typeToSubtract); $actualResult = $subtracted->isVoid(); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isVoid()', $subtracted->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isVoid()', $subtracted->describe(VerbosityLevel::precise())), + ); } public function dataSubtractedIsVoid(): array @@ -587,7 +671,11 @@ public function testSubtractedIsScalar(MixedType $mixedType, Type $typeToSubtrac $subtracted = $mixedType->subtract($typeToSubtract); $actualResult = $subtracted->isScalar(); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isScalar()', $subtracted->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isScalar()', $subtracted->describe(VerbosityLevel::precise())), + ); } public function dataSubtractedIsScalar(): array @@ -614,7 +702,11 @@ public function testSubstractedIsLiteralString(MixedType $mixedType, Type $typeT $subtracted = $mixedType->subtract($typeToSubtract); $actualResult = $subtracted->isLiteralString(); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isLiteralString()', $subtracted->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isLiteralString()', $subtracted->describe(VerbosityLevel::precise())), + ); } public function dataSubstractedIsIterable(): array @@ -627,7 +719,10 @@ public function dataSubstractedIsIterable(): array ], [ new MixedType(), - TypeCombinator::intersect(new StringType(), new AccessoryLiteralStringType()), + TypeCombinator::intersect( + new StringType(), + new AccessoryLiteralStringType(), + ), TrinaryLogic::createMaybe(), ], [ @@ -661,7 +756,11 @@ public function testSubstractedIsBoolean(MixedType $mixedType, Type $typeToSubtr $subtracted = $mixedType->subtract($typeToSubtract); $actualResult = $subtracted->isBoolean(); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isBoolean()', $subtracted->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isBoolean()', $subtracted->describe(VerbosityLevel::precise())), + ); } public function dataSubstractedIsBoolean(): array @@ -698,7 +797,11 @@ public function testSubstractedIsFalse(MixedType $mixedType, Type $typeToSubtrac $subtracted = $mixedType->subtract($typeToSubtract); $actualResult = $subtracted->isFalse(); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isFalse()', $subtracted->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isFalse()', $subtracted->describe(VerbosityLevel::precise())), + ); } public function dataSubstractedIsFalse(): array @@ -735,7 +838,11 @@ public function testSubstractedIsNull(MixedType $mixedType, Type $typeToSubtract $subtracted = $mixedType->subtract($typeToSubtract); $actualResult = $subtracted->isNull(); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isNull()', $subtracted->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isNull()', $subtracted->describe(VerbosityLevel::precise())), + ); } public function dataSubstractedIsNull(): array @@ -777,7 +884,11 @@ public function testSubstractedIsTrue(MixedType $mixedType, Type $typeToSubtract $subtracted = $mixedType->subtract($typeToSubtract); $actualResult = $subtracted->isTrue(); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isTrue()', $subtracted->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isTrue()', $subtracted->describe(VerbosityLevel::precise())), + ); } public function dataSubstractedIsTrue(): array @@ -814,7 +925,11 @@ public function testSubstractedIsFloat(MixedType $mixedType, Type $typeToSubtrac $subtracted = $mixedType->subtract($typeToSubtract); $actualResult = $subtracted->isFloat(); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isFloat()', $subtracted->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isFloat()', $subtracted->describe(VerbosityLevel::precise())), + ); } public function dataSubstractedIsFloat(): array @@ -846,7 +961,11 @@ public function testSubstractedIsInteger(MixedType $mixedType, Type $typeToSubtr $subtracted = $mixedType->subtract($typeToSubtract); $actualResult = $subtracted->isInteger(); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isInteger()', $subtracted->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isInteger()', $subtracted->describe(VerbosityLevel::precise())), + ); } public function dataSubstractedIsInteger(): array @@ -878,7 +997,11 @@ public function testSubstractedIsIterable(MixedType $mixedType, Type $typeToSubt $subtracted = $mixedType->subtract($typeToSubtract); $actualResult = $subtracted->isIterable(); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isIterable()', $subtracted->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isIterable()', $subtracted->describe(VerbosityLevel::precise())), + ); } public function dataSubstractedIsOffsetAccessible(): array @@ -929,7 +1052,11 @@ public function testSubstractedIsOffsetAccessible(MixedType $mixedType, Type $ty $subtracted = $mixedType->subtract($typeToSubtract); $actualResult = $subtracted->isOffsetAccessible(); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isOffsetAccessible()', $subtracted->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isOffsetAccessible()', $subtracted->describe(VerbosityLevel::precise())), + ); } public function dataSubtractedHasOffsetValueType(): array @@ -983,7 +1110,11 @@ public function testSubtractedHasOffsetValueType(MixedType $mixedType, Type $typ $subtracted = $mixedType->subtract($typeToSubtract); $actualResult = $subtracted->hasOffsetValueType($offsetType); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> hasOffsetValueType()', $subtracted->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> hasOffsetValueType()', $subtracted->describe(VerbosityLevel::precise())), + ); } } diff --git a/tests/PHPStan/Type/ObjectTypeTest.php b/tests/PHPStan/Type/ObjectTypeTest.php index 54403f707a2..6d8cfb28ee4 100644 --- a/tests/PHPStan/Type/ObjectTypeTest.php +++ b/tests/PHPStan/Type/ObjectTypeTest.php @@ -63,7 +63,11 @@ public function dataIsIterable(): array public function testIsIterable(ObjectType $type, TrinaryLogic $expectedResult): void { $actualResult = $type->isIterable(); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isIterable()', $type->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isIterable()', $type->describe(VerbosityLevel::precise())), + ); } public function dataIsCallable(): array @@ -81,7 +85,11 @@ public function dataIsCallable(): array public function testIsCallable(ObjectType $type, TrinaryLogic $expectedResult): void { $actualResult = $type->isCallable(); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isCallable()', $type->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isCallable()', $type->describe(VerbosityLevel::precise())), + ); } public function dataIsSuperTypeOf(): array @@ -339,17 +347,32 @@ public function dataIsSuperTypeOf(): array ], 46 => [ new ObjectType(DateTimeInterface::class), - TemplateTypeFactory::create(TemplateTypeScope::createWithClass(DateTimeInterface::class), 'T', new ObjectType(DateTimeInterface::class), TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithClass(DateTimeInterface::class), + 'T', + new ObjectType(DateTimeInterface::class), + TemplateTypeVariance::createInvariant(), + ), TrinaryLogic::createYes(), ], 47 => [ new ObjectType(DateTimeInterface::class), - TemplateTypeFactory::create(TemplateTypeScope::createWithClass(DateTime::class), 'T', new ObjectType(DateTime::class), TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithClass(DateTime::class), + 'T', + new ObjectType(DateTime::class), + TemplateTypeVariance::createInvariant(), + ), TrinaryLogic::createYes(), ], 48 => [ new ObjectType(DateTime::class), - TemplateTypeFactory::create(TemplateTypeScope::createWithClass(DateTimeInterface::class), 'T', new ObjectType(DateTimeInterface::class), TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithClass(DateTimeInterface::class), + 'T', + new ObjectType(DateTimeInterface::class), + TemplateTypeVariance::createInvariant(), + ), TrinaryLogic::createMaybe(), ], 49 => [ @@ -439,7 +462,11 @@ public function dataIsSuperTypeOf(): array public function testIsSuperTypeOf(ObjectType $type, Type $otherType, TrinaryLogic $expectedResult): void { $actualResult = $type->isSuperTypeOf($otherType); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isSuperTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isSuperTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise())), + ); } public function dataAccepts(): array @@ -462,12 +489,22 @@ public function dataAccepts(): array ], [ new ObjectType(DateTimeInterface::class), - TemplateTypeFactory::create(TemplateTypeScope::createWithClass(DateTimeInterface::class), 'T', new ObjectType(DateTimeInterface::class), TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithClass(DateTimeInterface::class), + 'T', + new ObjectType(DateTimeInterface::class), + TemplateTypeVariance::createInvariant(), + ), TrinaryLogic::createYes(), ], [ new ObjectType(DateTime::class), - TemplateTypeFactory::create(TemplateTypeScope::createWithClass(DateTimeInterface::class), 'T', new ObjectType(DateTimeInterface::class), TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithClass(DateTimeInterface::class), + 'T', + new ObjectType(DateTimeInterface::class), + TemplateTypeVariance::createInvariant(), + ), TrinaryLogic::createNo(), ], [ @@ -486,9 +523,17 @@ public function dataAccepts(): array /** * @dataProvider dataAccepts */ - public function testAccepts(ObjectType $type, Type $acceptedType, TrinaryLogic $expectedResult) : void + public function testAccepts( + ObjectType $type, + Type $acceptedType, + TrinaryLogic $expectedResult, + ): void { - $this->assertSame($expectedResult->describe(), $type->accepts($acceptedType, true)->describe(), sprintf('%s -> accepts(%s)', $type->describe(VerbosityLevel::precise()), $acceptedType->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $type->accepts($acceptedType, true)->describe(), + sprintf('%s -> accepts(%s)', $type->describe(VerbosityLevel::precise()), $acceptedType->describe(VerbosityLevel::precise())), + ); } public function testGetClassReflectionOfGenericClass(): void @@ -558,9 +603,17 @@ public function dataHasOffsetValueType(): array /** * @dataProvider dataHasOffsetValueType */ - public function testHasOffsetValueType(ObjectType $type, Type $offsetType, TrinaryLogic $expectedResult) : void + public function testHasOffsetValueType( + ObjectType $type, + Type $offsetType, + TrinaryLogic $expectedResult, + ): void { - $this->assertSame($expectedResult->describe(), $type->hasOffsetValueType($offsetType)->describe(), sprintf('%s -> accepts(%s)', $type->describe(VerbosityLevel::precise()), $offsetType->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $type->hasOffsetValueType($offsetType)->describe(), + sprintf('%s -> accepts(%s)', $type->describe(VerbosityLevel::precise()), $offsetType->describe(VerbosityLevel::precise())), + ); } public function dataGetEnumCases(): iterable @@ -599,11 +652,15 @@ public function dataGetEnumCases(): iterable * @dataProvider dataGetEnumCases * @param list $expectedEnumCases */ - public function testGetEnumCases(ObjectType $type, array $expectedEnumCases) : void + public function testGetEnumCases( + ObjectType $type, + array $expectedEnumCases, + ): void { if (PHP_VERSION_ID < 80100) { $this->markTestSkipped('Test requires PHP 8.1.'); } + $enumCases = $type->getEnumCases(); $this->assertCount(count($expectedEnumCases), $enumCases); foreach ($enumCases as $i => $enumCase) { diff --git a/tests/PHPStan/Type/ObjectWithoutClassTypeTest.php b/tests/PHPStan/Type/ObjectWithoutClassTypeTest.php index d1a9924a2bb..c5fde900ce1 100644 --- a/tests/PHPStan/Type/ObjectWithoutClassTypeTest.php +++ b/tests/PHPStan/Type/ObjectWithoutClassTypeTest.php @@ -67,7 +67,11 @@ public function dataIsSuperTypeOf(): array public function testIsSuperTypeOf(ObjectWithoutClassType $type, Type $otherType, TrinaryLogic $expectedResult): void { $actualResult = $type->isSuperTypeOf($otherType); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isSuperTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isSuperTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise())), + ); } } diff --git a/tests/PHPStan/Type/SimultaneousTypeTraverserTest.php b/tests/PHPStan/Type/SimultaneousTypeTraverserTest.php index 7154b401be8..e9cb8ada700 100644 --- a/tests/PHPStan/Type/SimultaneousTypeTraverserTest.php +++ b/tests/PHPStan/Type/SimultaneousTypeTraverserTest.php @@ -19,17 +19,29 @@ public function dataChangeStringIntoNonEmptyString(): iterable ]; yield [ new ArrayType(new MixedType(), new StringType()), - new ConstantArrayType([new ConstantIntegerType(0)], [new IntersectionType([new StringType(), new AccessoryNonEmptyStringType()])], 1), + new ConstantArrayType( + [new ConstantIntegerType(0)], + [new IntersectionType([new StringType(), new AccessoryNonEmptyStringType()])], + 1, + ), 'array', ]; yield [ new ArrayType(new MixedType(), new IntegerType()), - new ConstantArrayType([new ConstantIntegerType(0)], [new IntersectionType([new StringType(), new AccessoryNonEmptyStringType()])], 1), + new ConstantArrayType( + [new ConstantIntegerType(0)], + [new IntersectionType([new StringType(), new AccessoryNonEmptyStringType()])], + 1, + ), 'array', ]; yield [ new ArrayType(new MixedType(), new StringType()), - new ConstantArrayType([new ConstantIntegerType(0)], [new IntegerType()], 1), + new ConstantArrayType( + [new ConstantIntegerType(0)], + [new IntegerType()], + 1, + ), 'array', ]; diff --git a/tests/PHPStan/Type/StaticTypeTest.php b/tests/PHPStan/Type/StaticTypeTest.php index 239c55b5c2a..a462bda476d 100644 --- a/tests/PHPStan/Type/StaticTypeTest.php +++ b/tests/PHPStan/Type/StaticTypeTest.php @@ -39,7 +39,11 @@ public function dataIsIterable(): array public function testIsIterable(StaticType $type, TrinaryLogic $expectedResult): void { $actualResult = $type->isIterable(); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isIterable()', $type->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isIterable()', $type->describe(VerbosityLevel::precise())), + ); } public function dataIsCallable(): array @@ -58,7 +62,11 @@ public function dataIsCallable(): array public function testIsCallable(StaticType $type, TrinaryLogic $expectedResult): void { $actualResult = $type->isCallable(); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isCallable()', $type->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isCallable()', $type->describe(VerbosityLevel::precise())), + ); } public function dataIsSuperTypeOf(): array @@ -247,9 +255,8 @@ public function dataIsSuperTypeOf(): array ], [ new ThisType( - $reflectionProvider->getClass(\ThisSubtractable\Foo::class), - // phpcs:ignore - new UnionType([new ObjectType(\ThisSubtractable\Bar::class), new ObjectType(\ThisSubtractable\Baz::class)]) + $reflectionProvider->getClass(\ThisSubtractable\Foo::class), // phpcs:ignore + new UnionType([new ObjectType(\ThisSubtractable\Bar::class), new ObjectType(\ThisSubtractable\Baz::class)]), // phpcs:ignore ), new UnionType([ new IntersectionType([ @@ -272,7 +279,11 @@ public function dataIsSuperTypeOf(): array public function testIsSuperTypeOf(Type $type, Type $otherType, TrinaryLogic $expectedResult): void { $actualResult = $type->isSuperTypeOf($otherType); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isSuperTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isSuperTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise())), + ); } public function dataEquals(): array diff --git a/tests/PHPStan/Type/StringTypeTest.php b/tests/PHPStan/Type/StringTypeTest.php index 58536a1e7e8..8f22550446c 100644 --- a/tests/PHPStan/Type/StringTypeTest.php +++ b/tests/PHPStan/Type/StringTypeTest.php @@ -28,31 +28,61 @@ public function dataIsSuperTypeOf(): array ], [ new StringType(), - TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('foo'), 'T', new StringType(), TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('foo'), + 'T', + new StringType(), + TemplateTypeVariance::createInvariant(), + ), TrinaryLogic::createYes(), ], [ - TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('foo'), 'T', new StringType(), TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('foo'), + 'T', + new StringType(), + TemplateTypeVariance::createInvariant(), + ), new StringType(), TrinaryLogic::createMaybe(), ], [ new ClassStringType(), - TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('foo'), 'T', new StringType(), TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('foo'), + 'T', + new StringType(), + TemplateTypeVariance::createInvariant(), + ), TrinaryLogic::createMaybe(), ], [ - TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('foo'), 'T', new StringType(), TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('foo'), + 'T', + new StringType(), + TemplateTypeVariance::createInvariant(), + ), new ClassStringType(), TrinaryLogic::createMaybe(), ], [ new GenericClassStringType(new ObjectType(stdClass::class)), - TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('foo'), 'T', new StringType(), TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('foo'), + 'T', + new StringType(), + TemplateTypeVariance::createInvariant(), + ), TrinaryLogic::createMaybe(), ], [ - TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('foo'), 'T', new StringType(), TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('foo'), + 'T', + new StringType(), + TemplateTypeVariance::createInvariant(), + ), new GenericClassStringType(new ObjectType(stdClass::class)), TrinaryLogic::createMaybe(), ], @@ -70,7 +100,11 @@ public function dataIsSuperTypeOf(): array public function testIsSuperTypeOf(StringType $type, Type $otherType, TrinaryLogic $expectedResult): void { $actualResult = $type->isSuperTypeOf($otherType); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isSuperTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isSuperTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise())), + ); } public function dataAccepts(): iterable @@ -92,25 +126,50 @@ public function dataAccepts(): iterable yield [ new StringType(), - TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('foo'), 'T', new StringType(), TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('foo'), + 'T', + new StringType(), + TemplateTypeVariance::createInvariant(), + ), TrinaryLogic::createYes(), ]; yield [ - TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('foo'), 'T', new StringType(), TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('foo'), + 'T', + new StringType(), + TemplateTypeVariance::createInvariant(), + ), new StringType(), TrinaryLogic::createYes(), ]; yield [ - TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('foo'), 'T', new StringType(), TemplateTypeVariance::createInvariant())->toArgument(), + TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('foo'), + 'T', + new StringType(), + TemplateTypeVariance::createInvariant(), + )->toArgument(), new StringType(), TrinaryLogic::createMaybe(), ]; yield [ - TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('foo'), 'T', new StringType(), TemplateTypeVariance::createInvariant())->toArgument(), - TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('foo'), 'T', new StringType(), TemplateTypeVariance::createInvariant())->toArgument(), + TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('foo'), + 'T', + new StringType(), + TemplateTypeVariance::createInvariant(), + )->toArgument(), + TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('foo'), + 'T', + new StringType(), + TemplateTypeVariance::createInvariant(), + )->toArgument(), TrinaryLogic::createYes(), ]; } @@ -121,7 +180,11 @@ public function dataAccepts(): iterable public function testAccepts(StringType $type, Type $otherType, TrinaryLogic $expectedResult): void { $actualResult = $type->accepts($otherType, true); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> accepts(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> accepts(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise())), + ); } public function dataEquals(): array @@ -166,7 +229,11 @@ public function dataEquals(): array public function testEquals(StringType $type, Type $otherType, bool $expectedResult): void { $actualResult = $type->equals($otherType); - $this->assertSame($expectedResult, $actualResult, sprintf('%s->equals(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult, + $actualResult, + sprintf('%s->equals(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise())), + ); } } diff --git a/tests/PHPStan/Type/TemplateTypeTest.php b/tests/PHPStan/Type/TemplateTypeTest.php index aae246498f6..36281bdba18 100644 --- a/tests/PHPStan/Type/TemplateTypeTest.php +++ b/tests/PHPStan/Type/TemplateTypeTest.php @@ -25,9 +25,12 @@ class TemplateTypeTest extends PHPStanTestCase public function dataAccepts(): array { - $templateType = static function (string $name, ?Type $bound, ?string $functionName = null) : Type { - return TemplateTypeFactory::create(TemplateTypeScope::createWithFunction($functionName ?? '_'), $name, $bound, TemplateTypeVariance::createInvariant()); - }; + $templateType = static fn (string $name, ?Type $bound, ?string $functionName = null): Type => TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction($functionName ?? '_'), + $name, + $bound, + TemplateTypeVariance::createInvariant(), + ); return [ 0 => [ @@ -96,21 +99,40 @@ public function dataAccepts(): array /** * @dataProvider dataAccepts */ - public function testAccepts(Type $type, Type $otherType, TrinaryLogic $expectedAccept, TrinaryLogic $expectedAcceptArg) : void + public function testAccepts( + Type $type, + Type $otherType, + TrinaryLogic $expectedAccept, + TrinaryLogic $expectedAcceptArg, + ): void { assert($type instanceof TemplateType); + $actualResult = $type->accepts($otherType, true); - $this->assertSame($expectedAccept->describe(), $actualResult->describe(), sprintf('%s -> accepts(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedAccept->describe(), + $actualResult->describe(), + sprintf('%s -> accepts(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise())), + ); + $type = $type->toArgument(); + $actualResult = $type->accepts($otherType, true); - $this->assertSame($expectedAcceptArg->describe(), $actualResult->describe(), sprintf('%s -> accepts(%s) (Argument strategy)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedAcceptArg->describe(), + $actualResult->describe(), + sprintf('%s -> accepts(%s) (Argument strategy)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise())), + ); } public function dataIsSuperTypeOf(): array { - $templateType = static function (string $name, ?Type $bound, ?string $functionName = null) : Type { - return TemplateTypeFactory::create(TemplateTypeScope::createWithFunction($functionName ?? '_'), $name, $bound, TemplateTypeVariance::createInvariant()); - }; + $templateType = static fn (string $name, ?Type $bound, ?string $functionName = null): Type => TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction($functionName ?? '_'), + $name, + $bound, + TemplateTypeVariance::createInvariant(), + ); return [ 0 => [ @@ -266,21 +288,39 @@ public function dataIsSuperTypeOf(): array /** * @dataProvider dataIsSuperTypeOf */ - public function testIsSuperTypeOf(Type $type, Type $otherType, TrinaryLogic $expectedIsSuperType, TrinaryLogic $expectedIsSuperTypeInverse) : void + public function testIsSuperTypeOf( + Type $type, + Type $otherType, + TrinaryLogic $expectedIsSuperType, + TrinaryLogic $expectedIsSuperTypeInverse, + ): void { assert($type instanceof TemplateType); + $actualResult = $type->isSuperTypeOf($otherType); - $this->assertSame($expectedIsSuperType->describe(), $actualResult->describe(), sprintf('%s -> isSuperTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedIsSuperType->describe(), + $actualResult->describe(), + sprintf('%s -> isSuperTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise())), + ); + $actualResult = $otherType->isSuperTypeOf($type); - $this->assertSame($expectedIsSuperTypeInverse->describe(), $actualResult->describe(), sprintf('%s -> isSuperTypeOf(%s)', $otherType->describe(VerbosityLevel::precise()), $type->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedIsSuperTypeInverse->describe(), + $actualResult->describe(), + sprintf('%s -> isSuperTypeOf(%s)', $otherType->describe(VerbosityLevel::precise()), $type->describe(VerbosityLevel::precise())), + ); } /** @return array}> */ public function dataInferTemplateTypes(): array { - $templateType = static function (string $name, ?Type $bound = null, ?string $functionName = null) : Type { - return TemplateTypeFactory::create(TemplateTypeScope::createWithFunction($functionName ?? '_'), $name, $bound, TemplateTypeVariance::createInvariant()); - }; + $templateType = static fn (string $name, ?Type $bound = null, ?string $functionName = null): Type => TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction($functionName ?? '_'), + $name, + $bound, + TemplateTypeVariance::createInvariant(), + ); return [ 'simple' => [ @@ -329,9 +369,10 @@ public function testResolveTemplateTypes(Type $received, Type $template, array $ { $result = $template->inferTemplateTypes($received); - $this->assertSame($expectedTypes, array_map(static function (Type $type) : string { - return $type->describe(VerbosityLevel::precise()); - }, $result->getTypes())); + $this->assertSame( + $expectedTypes, + array_map(static fn (Type $type): string => $type->describe(VerbosityLevel::precise()), $result->getTypes()), + ); } } diff --git a/tests/PHPStan/Type/TypeCombinatorTest.php b/tests/PHPStan/Type/TypeCombinatorTest.php index 6e29c995ee0..76b00749098 100644 --- a/tests/PHPStan/Type/TypeCombinatorTest.php +++ b/tests/PHPStan/Type/TypeCombinatorTest.php @@ -124,7 +124,11 @@ public function dataAddNull(): array * @dataProvider dataAddNull * @param class-string $expectedTypeClass */ - public function testAddNull(Type $type, string $expectedTypeClass, string $expectedTypeDescription) : void + public function testAddNull( + Type $type, + string $expectedTypeClass, + string $expectedTypeDescription, + ): void { $result = TypeCombinator::addNull($type); $this->assertSame($expectedTypeDescription, $result->describe(VerbosityLevel::precise())); @@ -135,7 +139,11 @@ public function testAddNull(Type $type, string $expectedTypeClass, string $expec * @dataProvider dataAddNull * @param class-string $expectedTypeClass */ - public function testUnionWithNull(Type $type, string $expectedTypeClass, string $expectedTypeDescription) : void + public function testUnionWithNull( + Type $type, + string $expectedTypeClass, + string $expectedTypeDescription, + ): void { $result = TypeCombinator::union($type, new NullType()); $this->assertSame($expectedTypeDescription, $result->describe(VerbosityLevel::precise())); @@ -234,7 +242,11 @@ public function dataRemoveNull(): array * @dataProvider dataRemoveNull * @param class-string $expectedTypeClass */ - public function testRemoveNull(Type $type, string $expectedTypeClass, string $expectedTypeDescription) : void + public function testRemoveNull( + Type $type, + string $expectedTypeClass, + string $expectedTypeDescription, + ): void { $result = TypeCombinator::removeNull($type); $this->assertSame($expectedTypeDescription, $result->describe(VerbosityLevel::precise())); @@ -751,7 +763,10 @@ public function dataUnion(): iterable ], [ [ - new ArrayType(new IntegerType(), new ObjectType(stdClass::class)), + new ArrayType( + new IntegerType(), + new ObjectType(stdClass::class), + ), new ConstantArrayType([ new ConstantStringType('foo'), new ConstantStringType('bar'), @@ -886,23 +901,29 @@ public function dataUnion(): iterable [ [ new IntersectionType([ - new ConstantArrayType([ + new ConstantArrayType( + [ new ConstantIntegerType(0), new ConstantIntegerType(1), - ], [ + ], + [ new ObjectWithoutClassType(), new ConstantStringType('foo'), - ]), + ], + ), new CallableType(), ]), new IntersectionType([ - new ConstantArrayType([ + new ConstantArrayType( + [ new ConstantIntegerType(0), new ConstantIntegerType(1), - ], [ + ], + [ new ObjectWithoutClassType(), new ConstantStringType('foo'), - ]), + ], + ), new CallableType(), ]), ], @@ -1131,7 +1152,12 @@ public function dataUnion(): iterable ], [ [ - TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('a'), 'T', null, TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('a'), + 'T', + null, + TemplateTypeVariance::createInvariant(), + ), new ObjectType('DateTime'), ], UnionType::class, @@ -1139,7 +1165,12 @@ public function dataUnion(): iterable ], [ [ - TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('a'), 'T', new ObjectType('DateTime'), TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('a'), + 'T', + new ObjectType('DateTime'), + TemplateTypeVariance::createInvariant(), + ), new ObjectType('DateTime'), ], ObjectType::class, @@ -1147,16 +1178,36 @@ public function dataUnion(): iterable ], [ [ - TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('a'), 'T', new ObjectType('DateTime'), TemplateTypeVariance::createInvariant()), - TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('a'), 'T', new ObjectType('DateTime'), TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('a'), + 'T', + new ObjectType('DateTime'), + TemplateTypeVariance::createInvariant(), + ), + TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('a'), + 'T', + new ObjectType('DateTime'), + TemplateTypeVariance::createInvariant(), + ), ], TemplateType::class, 'T of DateTime (function a(), parameter)', ], [ [ - TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('a'), 'T', new ObjectType('DateTime'), TemplateTypeVariance::createInvariant()), - TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('a'), 'U', new ObjectType('DateTime'), TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('a'), + 'T', + new ObjectType('DateTime'), + TemplateTypeVariance::createInvariant(), + ), + TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('a'), + 'U', + new ObjectType('DateTime'), + TemplateTypeVariance::createInvariant(), + ), ], UnionType::class, 'T of DateTime (function a(), parameter)|U of DateTime (function a(), parameter)', @@ -1174,9 +1225,19 @@ public function dataUnion(): iterable ], 'bug6210-2' => [ [ - TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('a'), 'T', null, TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('a'), + 'T', + null, + TemplateTypeVariance::createInvariant(), + ), new IntersectionType([ - TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('a'), 'T', null, TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('a'), + 'T', + null, + TemplateTypeVariance::createInvariant(), + ), new HasMethodType('getId'), ]), ], @@ -1185,9 +1246,19 @@ public function dataUnion(): iterable ], 'bug6210-3' => [ [ - TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('a'), 'T', new ObjectWithoutClassType(), TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('a'), + 'T', + new ObjectWithoutClassType(), + TemplateTypeVariance::createInvariant(), + ), new IntersectionType([ - TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('a'), 'T', new ObjectWithoutClassType(), TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('a'), + 'T', + new ObjectWithoutClassType(), + TemplateTypeVariance::createInvariant(), + ), new HasMethodType('getId'), ]), ], @@ -1207,9 +1278,19 @@ public function dataUnion(): iterable ], 'bug6210-5' => [ [ - TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('a'), 'T', null, TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('a'), + 'T', + null, + TemplateTypeVariance::createInvariant(), + ), new IntersectionType([ - TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('a'), 'T', null, TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('a'), + 'T', + null, + TemplateTypeVariance::createInvariant(), + ), new HasPropertyType('getId'), ]), ], @@ -1218,9 +1299,19 @@ public function dataUnion(): iterable ], 'bug6210-6' => [ [ - TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('a'), 'T', new ObjectWithoutClassType(), TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('a'), + 'T', + new ObjectWithoutClassType(), + TemplateTypeVariance::createInvariant(), + ), new IntersectionType([ - TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('a'), 'T', new ObjectWithoutClassType(), TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('a'), + 'T', + new ObjectWithoutClassType(), + TemplateTypeVariance::createInvariant(), + ), new HasPropertyType('getId'), ]), ], @@ -1574,7 +1665,12 @@ public function dataUnion(): iterable ], [ [ - TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('a'), 'T', new ObjectWithoutClassType(), TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('a'), + 'T', + new ObjectWithoutClassType(), + TemplateTypeVariance::createInvariant(), + ), new ObjectWithoutClassType(), ], ObjectWithoutClassType::class, @@ -1582,7 +1678,12 @@ public function dataUnion(): iterable ], [ [ - TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('a'), 'T', new ObjectWithoutClassType(), TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('a'), + 'T', + new ObjectWithoutClassType(), + TemplateTypeVariance::createInvariant(), + ), new ObjectType(stdClass::class), ], UnionType::class, @@ -1590,7 +1691,12 @@ public function dataUnion(): iterable ], [ [ - TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('a'), 'T', new ObjectWithoutClassType(), TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('a'), + 'T', + new ObjectWithoutClassType(), + TemplateTypeVariance::createInvariant(), + ), new MixedType(), ], MixedType::class, @@ -1598,24 +1704,54 @@ public function dataUnion(): iterable ], [ [ - TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('a'), 'T', null, TemplateTypeVariance::createInvariant()), - TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('a'), 'K', null, TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('a'), + 'T', + null, + TemplateTypeVariance::createInvariant(), + ), + TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('a'), + 'K', + null, + TemplateTypeVariance::createInvariant(), + ), ], UnionType::class, 'K (function a(), parameter)|T (function a(), parameter)', ], [ [ - TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('a'), 'T', new ObjectWithoutClassType(), TemplateTypeVariance::createInvariant()), - TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('a'), 'K', new ObjectWithoutClassType(), TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('a'), + 'T', + new ObjectWithoutClassType(), + TemplateTypeVariance::createInvariant(), + ), + TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('a'), + 'K', + new ObjectWithoutClassType(), + TemplateTypeVariance::createInvariant(), + ), ], UnionType::class, 'K of object (function a(), parameter)|T of object (function a(), parameter)', ], [ [ - TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('a'), 'T', new ObjectType(Exception::class), TemplateTypeVariance::createInvariant()), - TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('a'), 'K', new ObjectType(stdClass::class), TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('a'), + 'T', + new ObjectType(Exception::class), + TemplateTypeVariance::createInvariant(), + ), + TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('a'), + 'K', + new ObjectType(stdClass::class), + TemplateTypeVariance::createInvariant(), + ), ], UnionType::class, 'K of stdClass (function a(), parameter)|T of Exception (function a(), parameter)', @@ -1824,12 +1960,17 @@ public function dataUnion(): iterable ], [ [ - TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('doFoo'), 'T', new UnionType([ + TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('doFoo'), + 'T', + new UnionType([ new StringType(), new IntegerType(), new FloatType(), new BooleanType(), - ]), TemplateTypeVariance::createInvariant()), + ]), + TemplateTypeVariance::createInvariant(), + ), new NullType(), ], UnionType::class, @@ -1842,7 +1983,12 @@ public function dataUnion(): iterable IntegerRangeType::fromInterval(null, -1), IntegerRangeType::fromInterval(1, null), ]), - TemplateTypeFactory::create(TemplateTypeScope::createWithClass('Foo'), 'TCode', new UnionType([new ArrayType(new IntegerType(), new IntegerType()), new IntegerType()]), TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithClass('Foo'), + 'TCode', + new UnionType([new ArrayType(new IntegerType(), new IntegerType()), new IntegerType()]), + TemplateTypeVariance::createInvariant(), + ), ], UnionType::class, 'array|int|int<1, max>|(TCode of array|int (class Foo, parameter))', @@ -1853,7 +1999,12 @@ public function dataUnion(): iterable new ArrayType(new MixedType(), new MixedType()), new CallableType(), ]), - TemplateTypeFactory::create(TemplateTypeScope::createWithClass('Foo'), 'TCode', new UnionType([new ArrayType(new IntegerType(), new IntegerType()), new IntegerType()]), TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithClass('Foo'), + 'TCode', + new UnionType([new ArrayType(new IntegerType(), new IntegerType()), new IntegerType()]), + TemplateTypeVariance::createInvariant(), + ), ], UnionType::class, 'array|(callable(): mixed)|(TCode of array|int (class Foo, parameter))', @@ -2013,9 +2164,8 @@ public function dataUnion(): iterable yield [ [ new ThisType( - $reflectionProvider->getClass(\ThisSubtractable\Foo::class), - // phpcs:ignore - new UnionType([new ObjectType(\ThisSubtractable\Bar::class), new ObjectType(\ThisSubtractable\Baz::class)]) + $reflectionProvider->getClass(\ThisSubtractable\Foo::class), // phpcs:ignore + new UnionType([new ObjectType(\ThisSubtractable\Bar::class), new ObjectType(\ThisSubtractable\Baz::class)]), // phpcs:ignore ), new UnionType([ new IntersectionType([ @@ -2103,11 +2253,17 @@ public function dataUnion(): iterable [ new IntersectionType([ new ArrayType(new MixedType(), new MixedType()), - new HasOffsetValueType(new ConstantStringType('a'), StaticTypeFactory::falsey()), + new HasOffsetValueType( + new ConstantStringType('a'), + StaticTypeFactory::falsey(), + ), ]), new IntersectionType([ new ArrayType(new MixedType(), new MixedType()), - new HasOffsetValueType(new ConstantStringType('a'), StaticTypeFactory::truthy()), + new HasOffsetValueType( + new ConstantStringType('a'), + StaticTypeFactory::truthy(), + ), ]), ], IntersectionType::class, @@ -2118,17 +2274,23 @@ public function dataUnion(): iterable [ new IntersectionType([ new ArrayType(new IntegerType(), new ArrayType(new MixedType(), new MixedType())), - new HasOffsetValueType(new ConstantIntegerType(0), new IntersectionType([ + new HasOffsetValueType( + new ConstantIntegerType(0), + new IntersectionType([ new ArrayType(new MixedType(), new MixedType()), new HasOffsetValueType(new ConstantStringType('code'), new ConstantIntegerType(1)), - ])), + ]), + ), ]), new IntersectionType([ new ArrayType(new IntegerType(), new ArrayType(new MixedType(), new MixedType())), - new HasOffsetValueType(new ConstantIntegerType(0), new IntersectionType([ + new HasOffsetValueType( + new ConstantIntegerType(0), + new IntersectionType([ new ArrayType(new MixedType(), new MixedType()), new HasOffsetValueType(new ConstantStringType('code'), new MixedType(true, new ConstantIntegerType(1))), - ])), + ]), + ), ]), ], IntersectionType::class, @@ -2137,8 +2299,18 @@ public function dataUnion(): iterable yield [ [ - new ConstantArrayType([new ConstantStringType('default'), new ConstantStringType('range')], [new ObjectType(Foo::class), new ObjectType(Foo::class)], [0], [0, 1]), - new ConstantArrayType([new ConstantStringType('range')], [new ObjectType(Foo::class)], [0], [0]), + new ConstantArrayType( + [new ConstantStringType('default'), new ConstantStringType('range')], + [new ObjectType(Foo::class), new ObjectType(Foo::class)], + [0], + [0, 1], + ), + new ConstantArrayType( + [new ConstantStringType('range')], + [new ObjectType(Foo::class)], + [0], + [0], + ), ], ConstantArrayType::class, 'array{default?: RecursionCallable\Foo, range?: RecursionCallable\Foo}', @@ -2147,10 +2319,20 @@ public function dataUnion(): iterable yield [ [ new IntersectionType([ - new ConstantArrayType([new ConstantStringType('default'), new ConstantStringType('range')], [new ObjectType(Foo::class), new ObjectType(Foo::class)], [0], [0, 1]), + new ConstantArrayType( + [new ConstantStringType('default'), new ConstantStringType('range')], + [new ObjectType(Foo::class), new ObjectType(Foo::class)], + [0], + [0, 1], + ), new NonEmptyArrayType(), ]), - new ConstantArrayType([new ConstantStringType('range')], [new ObjectType(Foo::class)], [0], [0]), + new ConstantArrayType( + [new ConstantStringType('range')], + [new ObjectType(Foo::class)], + [0], + [0], + ), ], ConstantArrayType::class, 'array{default?: RecursionCallable\Foo, range?: RecursionCallable\Foo}', @@ -2347,7 +2529,11 @@ public function dataUnion(): iterable * @param Type[] $types * @param class-string $expectedTypeClass */ - public function testUnion(array $types, string $expectedTypeClass, string $expectedTypeDescription) : void + public function testUnion( + array $types, + string $expectedTypeClass, + string $expectedTypeDescription, + ): void { $actualType = TypeCombinator::union(...$types); $actualTypeDescription = $actualType->describe(VerbosityLevel::precise()); @@ -2358,10 +2544,18 @@ public function testUnion(array $types, string $expectedTypeClass, string $expec $actualTypeDescription .= '=implicit'; } } - $this->assertSame($expectedTypeDescription, $actualTypeDescription, sprintf('union(%s)', implode(', ', array_map(static function (Type $type) : string { - return $type->describe(VerbosityLevel::precise()); - }, $types)))); + + $this->assertSame( + $expectedTypeDescription, + $actualTypeDescription, + sprintf('union(%s)', implode(', ', array_map( + static fn (Type $type): string => $type->describe(VerbosityLevel::precise()), + $types, + ))), + ); + $this->assertInstanceOf($expectedTypeClass, $actualType); + $hasSubtraction = false; foreach ($types as $type) { if (!($type instanceof SubtractableType) || $type->getSubtractedType() === null) { @@ -2370,6 +2564,7 @@ public function testUnion(array $types, string $expectedTypeClass, string $expec $hasSubtraction = true; } + if ($hasSubtraction) { return; } @@ -2380,7 +2575,11 @@ public function testUnion(array $types, string $expectedTypeClass, string $expec * @param Type[] $types * @param class-string $expectedTypeClass */ - public function testUnionInversed(array $types, string $expectedTypeClass, string $expectedTypeDescription) : void + public function testUnionInversed( + array $types, + string $expectedTypeClass, + string $expectedTypeDescription, + ): void { $types = array_reverse($types); $actualType = TypeCombinator::union(...$types); @@ -2392,9 +2591,14 @@ public function testUnionInversed(array $types, string $expectedTypeClass, strin $actualTypeDescription .= '=implicit'; } } - $this->assertSame($expectedTypeDescription, $actualTypeDescription, sprintf('union(%s)', implode(', ', array_map(static function (Type $type) : string { - return $type->describe(VerbosityLevel::precise()); - }, $types)))); + $this->assertSame( + $expectedTypeDescription, + $actualTypeDescription, + sprintf('union(%s)', implode(', ', array_map( + static fn (Type $type): string => $type->describe(VerbosityLevel::precise()), + $types, + ))), + ); $this->assertInstanceOf($expectedTypeClass, $actualType); } @@ -2430,7 +2634,15 @@ public function dataIntersect(): iterable [ [ new ObjectType('Iterator'), - new IterableType(new MixedType(true), TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('_'), 'T', null, TemplateTypeVariance::createInvariant())), + new IterableType( + new MixedType(true), + TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('_'), + 'T', + null, + TemplateTypeVariance::createInvariant(), + ), + ), ], IntersectionType::class, 'iterable&Iterator', @@ -2848,7 +3060,10 @@ public function dataIntersect(): iterable ], [ [ - new ConstantArrayType([new ConstantStringType('a')], [new ConstantStringType('foo')]), + new ConstantArrayType( + [new ConstantStringType('a')], + [new ConstantStringType('foo')], + ), new HasOffsetType(new ConstantStringType('a')), ], ConstantArrayType::class, @@ -2856,7 +3071,10 @@ public function dataIntersect(): iterable ], [ [ - new ConstantArrayType([new ConstantStringType('a')], [new ConstantStringType('foo')]), + new ConstantArrayType( + [new ConstantStringType('a')], + [new ConstantStringType('foo')], + ), new HasOffsetType(new ConstantStringType('b')), ], NeverType::class, @@ -2872,7 +3090,16 @@ public function dataIntersect(): iterable ], [ [ - TypeCombinator::union(new ConstantArrayType([new ConstantStringType('a')], [new ConstantStringType('foo')]), new ConstantArrayType([new ConstantStringType('b')], [new ConstantStringType('foo')])), + TypeCombinator::union( + new ConstantArrayType( + [new ConstantStringType('a')], + [new ConstantStringType('foo')], + ), + new ConstantArrayType( + [new ConstantStringType('b')], + [new ConstantStringType('foo')], + ), + ), new HasOffsetType(new ConstantStringType('b')), ], ConstantArrayType::class, @@ -2880,7 +3107,13 @@ public function dataIntersect(): iterable ], [ [ - TypeCombinator::union(new ConstantArrayType([new ConstantStringType('a')], [new ConstantStringType('foo')]), new ClosureType([], new MixedType(), false)), + TypeCombinator::union( + new ConstantArrayType( + [new ConstantStringType('a')], + [new ConstantStringType('foo')], + ), + new ClosureType([], new MixedType(), false), + ), new HasOffsetType(new ConstantStringType('a')), ], ConstantArrayType::class, @@ -2950,11 +3183,14 @@ public function dataIntersect(): iterable ], [ [ - TypeCombinator::union(new ConstantArrayType([], []), new ConstantArrayType([ + TypeCombinator::union( + new ConstantArrayType([], []), + new ConstantArrayType([ new ConstantIntegerType(0), ], [ new StringType(), - ])), + ]), + ), new NonEmptyArrayType(), ], ConstantArrayType::class, @@ -3024,7 +3260,12 @@ public function dataIntersect(): iterable ], [ [ - TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('a'), 'T', null, TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('a'), + 'T', + null, + TemplateTypeVariance::createInvariant(), + ), new ObjectType('DateTime'), ], IntersectionType::class, @@ -3032,7 +3273,12 @@ public function dataIntersect(): iterable ], [ [ - TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('a'), 'T', new ObjectType('DateTime'), TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('a'), + 'T', + new ObjectType('DateTime'), + TemplateTypeVariance::createInvariant(), + ), new ObjectType('DateTime'), ], TemplateObjectType::class, @@ -3040,23 +3286,48 @@ public function dataIntersect(): iterable ], [ [ - TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('a'), 'T', new ObjectType('DateTime'), TemplateTypeVariance::createInvariant()), - TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('a'), 'T', new ObjectType('DateTime'), TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('a'), + 'T', + new ObjectType('DateTime'), + TemplateTypeVariance::createInvariant(), + ), + TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('a'), + 'T', + new ObjectType('DateTime'), + TemplateTypeVariance::createInvariant(), + ), ], TemplateType::class, 'T of DateTime (function a(), parameter)', ], [ [ - TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('a'), 'T', new ObjectType('DateTime'), TemplateTypeVariance::createInvariant()), - TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('a'), 'U', new ObjectType('DateTime'), TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('a'), + 'T', + new ObjectType('DateTime'), + TemplateTypeVariance::createInvariant(), + ), + TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('a'), + 'U', + new ObjectType('DateTime'), + TemplateTypeVariance::createInvariant(), + ), ], IntersectionType::class, 'T of DateTime (function a(), parameter)&U of DateTime (function a(), parameter)', ], [ [ - TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('a'), 'T', null, TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('a'), + 'T', + null, + TemplateTypeVariance::createInvariant(), + ), new MixedType(), ], TemplateType::class, @@ -3308,7 +3579,12 @@ public function dataIntersect(): iterable ], [ [ - TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('a'), 'T', new ObjectWithoutClassType(), TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('a'), + 'T', + new ObjectWithoutClassType(), + TemplateTypeVariance::createInvariant(), + ), new ObjectWithoutClassType(), ], TemplateObjectWithoutClassType::class, @@ -3316,7 +3592,12 @@ public function dataIntersect(): iterable ], [ [ - TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('a'), 'T', new ObjectWithoutClassType(), TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('a'), + 'T', + new ObjectWithoutClassType(), + TemplateTypeVariance::createInvariant(), + ), new ObjectType(stdClass::class), ], IntersectionType::class, @@ -3324,7 +3605,12 @@ public function dataIntersect(): iterable ], [ [ - TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('a'), 'T', new ObjectWithoutClassType(), TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('a'), + 'T', + new ObjectWithoutClassType(), + TemplateTypeVariance::createInvariant(), + ), new MixedType(), ], TemplateObjectWithoutClassType::class, @@ -3437,7 +3723,12 @@ public function dataIntersect(): iterable ], [ [ - TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('my_array_keys'), 'T', new BenevolentUnionType([new IntegerType(), new StringType()]), TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('my_array_keys'), + 'T', + new BenevolentUnionType([new IntegerType(), new StringType()]), + TemplateTypeVariance::createInvariant(), + ), new UnionType([new IntegerType(), new StringType()]), ], TemplateBenevolentUnionType::class, @@ -3445,7 +3736,12 @@ public function dataIntersect(): iterable ], [ [ - TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('my_array_keys'), 'T', new BenevolentUnionType([new IntegerType(), new StringType()]), TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('my_array_keys'), + 'T', + new BenevolentUnionType([new IntegerType(), new StringType()]), + TemplateTypeVariance::createInvariant(), + ), new BenevolentUnionType([new IntegerType(), new StringType()]), ], TemplateBenevolentUnionType::class, @@ -3453,7 +3749,12 @@ public function dataIntersect(): iterable ], [ [ - TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('my_array_keys'), 'T', new UnionType([new IntegerType(), new StringType()]), TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('my_array_keys'), + 'T', + new UnionType([new IntegerType(), new StringType()]), + TemplateTypeVariance::createInvariant(), + ), new UnionType([new IntegerType(), new StringType()]), ], UnionType::class, @@ -3868,7 +4169,11 @@ public function dataIntersect(): iterable * @param Type[] $types * @param class-string $expectedTypeClass */ - public function testIntersect(array $types, string $expectedTypeClass, string $expectedTypeDescription) : void + public function testIntersect( + array $types, + string $expectedTypeClass, + string $expectedTypeDescription, + ): void { $actualType = TypeCombinator::intersect(...$types); $actualTypeDescription = $actualType->describe(VerbosityLevel::precise()); @@ -3895,7 +4200,11 @@ public function testIntersect(array $types, string $expectedTypeClass, string $e * @param Type[] $types * @param class-string $expectedTypeClass */ - public function testIntersectInversed(array $types, string $expectedTypeClass, string $expectedTypeDescription) : void + public function testIntersectInversed( + array $types, + string $expectedTypeClass, + string $expectedTypeDescription, + ): void { $actualType = TypeCombinator::intersect(...array_reverse($types)); $actualTypeDescription = $actualType->describe(VerbosityLevel::precise()); @@ -4146,11 +4455,14 @@ public function dataRemove(): array 'non-empty-array', ], [ - TypeCombinator::union(new ConstantArrayType([], []), new ConstantArrayType([ + TypeCombinator::union( + new ConstantArrayType([], []), + new ConstantArrayType([ new ConstantIntegerType(0), ], [ new StringType(), - ])), + ]), + ), new ConstantArrayType([], []), ConstantArrayType::class, 'array{string}', @@ -4375,7 +4687,12 @@ public function dataRemove(): array 'stdClass', ], [ - TemplateTypeFactory::create(TemplateTypeScope::createWithClass('Foo'), 'T', new BooleanType(), TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithClass('Foo'), + 'T', + new BooleanType(), + TemplateTypeVariance::createInvariant(), + ), new ConstantBooleanType(false), TemplateMixedType::class, // should be TemplateConstantBooleanType 'T (class Foo, parameter)', // should be T of true @@ -4411,7 +4728,12 @@ public function dataRemove(): array * @dataProvider dataRemove * @param class-string $expectedTypeClass */ - public function testRemove(Type $fromType, Type $type, string $expectedTypeClass, string $expectedTypeDescription) : void + public function testRemove( + Type $fromType, + Type $type, + string $expectedTypeClass, + string $expectedTypeDescription, + ): void { $result = TypeCombinator::remove($fromType, $type); $actualTypeDescription = $result->describe(VerbosityLevel::precise()); @@ -4448,7 +4770,10 @@ public function testSpecificUnionConstantArray(): void /** * @dataProvider dataContainsNull */ - public function testContainsNull(Type $type, bool $expectedResult) : void + public function testContainsNull( + Type $type, + bool $expectedResult, + ): void { $this->assertSame($expectedResult, TypeCombinator::containsNull($type)); } diff --git a/tests/PHPStan/Type/TypeGetFiniteTypesTest.php b/tests/PHPStan/Type/TypeGetFiniteTypesTest.php index 8aa358c36a7..ce605f3d5ab 100644 --- a/tests/PHPStan/Type/TypeGetFiniteTypesTest.php +++ b/tests/PHPStan/Type/TypeGetFiniteTypesTest.php @@ -68,7 +68,12 @@ public function dataGetFiniteTypes(): iterable yield [ new IntersectionType([ new BooleanType(), - TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('foo'), 'T', new BooleanType(), TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithFunction('foo'), + 'T', + new BooleanType(), + TemplateTypeVariance::createInvariant(), + ), ]), [ new ConstantBooleanType(true), @@ -121,7 +126,10 @@ public function dataGetFiniteTypes(): iterable * @dataProvider dataGetFiniteTypes * @param list $expectedTypes */ - public function testGetFiniteTypes(Type $type, array $expectedTypes) : void + public function testGetFiniteTypes( + Type $type, + array $expectedTypes, + ): void { $this->assertEquals($expectedTypes, $type->getFiniteTypes()); } diff --git a/tests/PHPStan/Type/TypeToPhpDocNodeTest.php b/tests/PHPStan/Type/TypeToPhpDocNodeTest.php index 94fa64da1c8..592271bddac 100644 --- a/tests/PHPStan/Type/TypeToPhpDocNodeTest.php +++ b/tests/PHPStan/Type/TypeToPhpDocNodeTest.php @@ -191,12 +191,24 @@ public function dataToPhpDocNode(): iterable ]; yield [ - new ConditionalType(new ObjectWithoutClassType(), new ObjectType('stdClass'), new IntegerType(), new StringType(), false), + new ConditionalType( + new ObjectWithoutClassType(), + new ObjectType('stdClass'), + new IntegerType(), + new StringType(), + false, + ), '(object is stdClass ? int : string)', ]; yield [ - new ConditionalType(new ObjectWithoutClassType(), new ObjectType('stdClass'), new IntegerType(), new StringType(), true), + new ConditionalType( + new ObjectWithoutClassType(), + new ObjectType('stdClass'), + new IntegerType(), + new StringType(), + true, + ), '(object is not stdClass ? int : string)', ]; diff --git a/tests/PHPStan/Type/UnionTypeTest.php b/tests/PHPStan/Type/UnionTypeTest.php index e39c1a7a22f..3e09804c397 100644 --- a/tests/PHPStan/Type/UnionTypeTest.php +++ b/tests/PHPStan/Type/UnionTypeTest.php @@ -42,7 +42,13 @@ public function dataIsCallable(): array { return [ [ - TypeCombinator::union(new ConstantArrayType([new ConstantIntegerType(0), new ConstantIntegerType(1)], [new ConstantStringType('Closure'), new ConstantStringType('bind')]), new ConstantStringType('array_push')), + TypeCombinator::union( + new ConstantArrayType( + [new ConstantIntegerType(0), new ConstantIntegerType(1)], + [new ConstantStringType('Closure'), new ConstantStringType('bind')], + ), + new ConstantStringType('array_push'), + ), TrinaryLogic::createYes(), ], [ @@ -75,7 +81,11 @@ public function dataIsCallable(): array public function testIsCallable(UnionType $type, TrinaryLogic $expectedResult): void { $actualResult = $type->isCallable(); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isCallable()', $type->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isCallable()', $type->describe(VerbosityLevel::precise())), + ); } public function dataSelfCompare(): Iterator @@ -144,9 +154,20 @@ public function dataSelfCompare(): Iterator public function testSelfCompare(Type $type): void { $description = $type->describe(VerbosityLevel::precise()); - $this->assertTrue($type->equals($type), sprintf('%s -> equals(itself)', $description)); - $this->assertEquals('Yes', $type->isSuperTypeOf($type)->describe(), sprintf('%s -> isSuperTypeOf(itself)', $description)); - $this->assertInstanceOf(get_class($type), TypeCombinator::union($type, $type), sprintf('%s -> union with itself is same type', $description)); + $this->assertTrue( + $type->equals($type), + sprintf('%s -> equals(itself)', $description), + ); + $this->assertEquals( + 'Yes', + $type->isSuperTypeOf($type)->describe(), + sprintf('%s -> isSuperTypeOf(itself)', $description), + ); + $this->assertInstanceOf( + get_class($type), + TypeCombinator::union($type, $type), + sprintf('%s -> union with itself is same type', $description), + ); } public function dataIsSuperTypeOf(): Iterator @@ -331,58 +352,103 @@ public function dataIsSuperTypeOf(): Iterator new IntegerType(), new FloatType(), ]), - TemplateTypeFactory::create(TemplateTypeScope::createWithClass('Foo'), 'T', new UnionType([ + TemplateTypeFactory::create( + TemplateTypeScope::createWithClass('Foo'), + 'T', + new UnionType([ new IntegerType(), new FloatType(), - ]), TemplateTypeVariance::createInvariant()), + ]), + TemplateTypeVariance::createInvariant(), + ), TrinaryLogic::createYes(), ]; yield 'is super type of template-of-union equal to a union member' => [ new UnionType([ - TemplateTypeFactory::create(TemplateTypeScope::createWithClass('Foo'), 'T', new UnionType([ + TemplateTypeFactory::create( + TemplateTypeScope::createWithClass('Foo'), + 'T', + new UnionType([ new IntegerType(), new FloatType(), - ]), TemplateTypeVariance::createInvariant()), + ]), + TemplateTypeVariance::createInvariant(), + ), new NullType(), ]), - TemplateTypeFactory::create(TemplateTypeScope::createWithClass('Foo'), 'T', new UnionType([ + TemplateTypeFactory::create( + TemplateTypeScope::createWithClass('Foo'), + 'T', + new UnionType([ new IntegerType(), new FloatType(), - ]), TemplateTypeVariance::createInvariant()), + ]), + TemplateTypeVariance::createInvariant(), + ), TrinaryLogic::createYes(), ]; yield 'maybe super type of template-of-union equal to a union member' => [ new UnionType([ - TemplateTypeFactory::create(TemplateTypeScope::createWithClass('Foo'), 'T', new UnionType([ + TemplateTypeFactory::create( + TemplateTypeScope::createWithClass('Foo'), + 'T', + new UnionType([ new IntegerType(), new FloatType(), - ]), TemplateTypeVariance::createInvariant()), + ]), + TemplateTypeVariance::createInvariant(), + ), new NullType(), ]), - TemplateTypeFactory::create(TemplateTypeScope::createWithClass('Bar'), 'T', new UnionType([ + TemplateTypeFactory::create( + TemplateTypeScope::createWithClass('Bar'), + 'T', + new UnionType([ new IntegerType(), new FloatType(), - ]), TemplateTypeVariance::createInvariant()), + ]), + TemplateTypeVariance::createInvariant(), + ), TrinaryLogic::createMaybe(), ]; yield 'is super type of template-of-string equal to a union member' => [ new UnionType([ - TemplateTypeFactory::create(TemplateTypeScope::createWithClass('Foo'), 'T', new StringType(), TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithClass('Foo'), + 'T', + new StringType(), + TemplateTypeVariance::createInvariant(), + ), new NullType(), ]), - TemplateTypeFactory::create(TemplateTypeScope::createWithClass('Foo'), 'T', new StringType(), TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithClass('Foo'), + 'T', + new StringType(), + TemplateTypeVariance::createInvariant(), + ), TrinaryLogic::createYes(), ]; yield 'maybe super type of template-of-string sub type of a union member' => [ new UnionType([ - TemplateTypeFactory::create(TemplateTypeScope::createWithClass('Foo'), 'T', new StringType(), TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithClass('Foo'), + 'T', + new StringType(), + TemplateTypeVariance::createInvariant(), + ), new NullType(), ]), - TemplateTypeFactory::create(TemplateTypeScope::createWithClass('Bar'), 'T', new StringType(), TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithClass('Bar'), + 'T', + new StringType(), + TemplateTypeVariance::createInvariant(), + ), TrinaryLogic::createMaybe(), ]; } @@ -393,7 +459,11 @@ public function dataIsSuperTypeOf(): Iterator public function testIsSuperTypeOf(UnionType $type, Type $otherType, TrinaryLogic $expectedResult): void { $actualResult = $type->isSuperTypeOf($otherType); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isSuperTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isSuperTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise())), + ); } public function dataIsSubTypeOf(): Iterator @@ -557,7 +627,11 @@ public function dataIsSubTypeOf(): Iterator public function testIsSubTypeOf(UnionType $type, Type $otherType, TrinaryLogic $expectedResult): void { $actualResult = $type->isSubTypeOf($otherType); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isSubTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isSubTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise())), + ); } /** @@ -566,14 +640,23 @@ public function testIsSubTypeOf(UnionType $type, Type $otherType, TrinaryLogic $ public function testIsSubTypeOfInversed(UnionType $type, Type $otherType, TrinaryLogic $expectedResult): void { $actualResult = $otherType->isSuperTypeOf($type); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isSuperTypeOf(%s)', $otherType->describe(VerbosityLevel::precise()), $type->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isSuperTypeOf(%s)', $otherType->describe(VerbosityLevel::precise()), $type->describe(VerbosityLevel::precise())), + ); } public function dataIsScalar(): array { return [ [ - TypeCombinator::union(new BooleanType(), new IntegerType(), new FloatType(), new StringType()), + TypeCombinator::union( + new BooleanType(), + new IntegerType(), + new FloatType(), + new StringType(), + ), TrinaryLogic::createYes(), ], [ @@ -620,7 +703,11 @@ public function dataIsScalar(): array public function testIsScalar(UnionType $type, TrinaryLogic $expectedResult): void { $actualResult = $type->isScalar(); - $this->assertSame($expectedResult->describe(), $actualResult->describe(), sprintf('%s -> isScalar()', $type->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isScalar()', $type->describe(VerbosityLevel::precise())), + ); } public function dataDescribe(): array @@ -658,62 +745,76 @@ public function dataDescribe(): array 'float|int|stdClass|string|true|null', ], [ - TypeCombinator::union(new ConstantArrayType([ + TypeCombinator::union( + new ConstantArrayType([ new ConstantStringType('a'), new ConstantStringType('b'), ], [ new StringType(), new BooleanType(), - ]), new ConstantArrayType([ + ]), + new ConstantArrayType([ new ConstantStringType('a'), new ConstantStringType('b'), ], [ new IntegerType(), new FloatType(), - ]), new ConstantStringType('aaa')), + ]), + new ConstantStringType('aaa'), + ), '\'aaa\'|array{a: int, b: float}|array{a: string, b: bool}', 'array|string', ], [ - TypeCombinator::union(new ConstantArrayType([ + TypeCombinator::union( + new ConstantArrayType([ new ConstantStringType('a'), new ConstantStringType('b'), ], [ new StringType(), new BooleanType(), - ]), new ConstantArrayType([ + ]), + new ConstantArrayType([ new ConstantStringType('b'), new ConstantStringType('c'), ], [ new IntegerType(), new FloatType(), - ]), new ConstantStringType('aaa')), + ]), + new ConstantStringType('aaa'), + ), '\'aaa\'|array{a: string, b: bool}|array{b: int, c: float}', 'array|string', ], [ - TypeCombinator::union(new ConstantArrayType([ + TypeCombinator::union( + new ConstantArrayType([ new ConstantStringType('a'), new ConstantStringType('b'), ], [ new StringType(), new BooleanType(), - ]), new ConstantArrayType([ + ]), + new ConstantArrayType([ new ConstantStringType('c'), new ConstantStringType('d'), ], [ new IntegerType(), new FloatType(), - ]), new ConstantStringType('aaa')), + ]), + new ConstantStringType('aaa'), + ), '\'aaa\'|array{a: string, b: bool}|array{c: int, d: float}', 'array|string', ], [ - TypeCombinator::union(new ConstantArrayType([ + TypeCombinator::union( + new ConstantArrayType([ new ConstantIntegerType(0), ], [ new StringType(), - ]), new ConstantArrayType([ + ]), + new ConstantArrayType([ new ConstantIntegerType(0), new ConstantIntegerType(1), new ConstantIntegerType(2), @@ -721,49 +822,96 @@ public function dataDescribe(): array new IntegerType(), new BooleanType(), new FloatType(), - ])), + ]), + ), 'array{int, bool, float}|array{string}', 'array', ], [ - TypeCombinator::union(new ConstantArrayType([], []), new ConstantArrayType([ + TypeCombinator::union( + new ConstantArrayType([], []), + new ConstantArrayType([ new ConstantStringType('foooo'), ], [ new ConstantStringType('barrr'), - ])), + ]), + ), 'array{}|array{foooo: \'barrr\'}', 'array', ], [ - TypeCombinator::union(new IntegerType(), new IntersectionType([ + TypeCombinator::union( + new IntegerType(), + new IntersectionType([ new StringType(), new AccessoryNumericStringType(), - ])), + ]), + ), 'int|numeric-string', 'int|string', ], [ - TypeCombinator::union(IntegerRangeType::fromInterval(0, 4), IntegerRangeType::fromInterval(6, 10)), + TypeCombinator::union( + IntegerRangeType::fromInterval(0, 4), + IntegerRangeType::fromInterval(6, 10), + ), 'int<0, 4>|int<6, 10>', 'int<0, 4>|int<6, 10>', ], [ - TypeCombinator::union(TemplateTypeFactory::create(TemplateTypeScope::createWithClass('foo'), 'TFoo', new IntegerType(), TemplateTypeVariance::createInvariant()), new NullType()), + TypeCombinator::union( + TemplateTypeFactory::create( + TemplateTypeScope::createWithClass('foo'), + 'TFoo', + new IntegerType(), + TemplateTypeVariance::createInvariant(), + ), + new NullType(), + ), '(TFoo of int)|null', '(TFoo of int)|null', ], [ - TypeCombinator::union(TemplateTypeFactory::create(TemplateTypeScope::createWithClass('foo'), 'TFoo', new IntegerType(), TemplateTypeVariance::createInvariant()), new GenericClassStringType(new ObjectType('Abc'))), + TypeCombinator::union( + TemplateTypeFactory::create( + TemplateTypeScope::createWithClass('foo'), + 'TFoo', + new IntegerType(), + TemplateTypeVariance::createInvariant(), + ), + new GenericClassStringType(new ObjectType('Abc')), + ), 'class-string|TFoo of int', 'class-string|TFoo of int', ], [ - TypeCombinator::union(TemplateTypeFactory::create(TemplateTypeScope::createWithClass('foo'), 'TFoo', new MixedType(true), TemplateTypeVariance::createInvariant()), new NullType()), + TypeCombinator::union( + TemplateTypeFactory::create( + TemplateTypeScope::createWithClass('foo'), + 'TFoo', + new MixedType(true), + TemplateTypeVariance::createInvariant(), + ), + new NullType(), + ), 'TFoo|null', 'TFoo|null', ], [ - TypeCombinator::union(TemplateTypeFactory::create(TemplateTypeScope::createWithClass('foo'), 'TFoo', TemplateTypeFactory::create(TemplateTypeScope::createWithClass('foo'), 'TBar', new MixedType(true), TemplateTypeVariance::createInvariant()), TemplateTypeVariance::createInvariant()), new NullType()), + TypeCombinator::union( + TemplateTypeFactory::create( + TemplateTypeScope::createWithClass('foo'), + 'TFoo', + TemplateTypeFactory::create( + TemplateTypeScope::createWithClass('foo'), + 'TBar', + new MixedType(true), + TemplateTypeVariance::createInvariant(), + ), + TemplateTypeVariance::createInvariant(), + ), + new NullType(), + ), '(TFoo of TBar)|null', '(TFoo of TBar)|null', ], @@ -773,7 +921,11 @@ public function dataDescribe(): array /** * @dataProvider dataDescribe */ - public function testDescribe(Type $type, string $expectedValueDescription, string $expectedTypeOnlyDescription) : void + public function testDescribe( + Type $type, + string $expectedValueDescription, + string $expectedTypeOnlyDescription, + ): void { $this->assertSame($expectedValueDescription, $type->describe(VerbosityLevel::value())); $this->assertSame($expectedTypeOnlyDescription, $type->describe(VerbosityLevel::typeOnly())); @@ -860,10 +1012,13 @@ public function dataAccepts(): iterable new EnumCaseObjectType('PHPStan\Fixture\ManyCasesTestEnum', 'C'), new EnumCaseObjectType('PHPStan\Fixture\ManyCasesTestEnum', 'D'), ]), - new ObjectType('PHPStan\Fixture\ManyCasesTestEnum', new UnionType([ + new ObjectType( + 'PHPStan\Fixture\ManyCasesTestEnum', + new UnionType([ new EnumCaseObjectType('PHPStan\Fixture\ManyCasesTestEnum', 'E'), new EnumCaseObjectType('PHPStan\Fixture\ManyCasesTestEnum', 'F'), - ])), + ]), + ), TrinaryLogic::createYes(), ]; @@ -875,7 +1030,10 @@ public function dataAccepts(): iterable new EnumCaseObjectType('PHPStan\Fixture\ManyCasesTestEnum', 'D'), new EnumCaseObjectType('PHPStan\Fixture\ManyCasesTestEnum', 'E'), ]), - new ObjectType('PHPStan\Fixture\ManyCasesTestEnum', new EnumCaseObjectType('PHPStan\Fixture\ManyCasesTestEnum', 'F')), + new ObjectType( + 'PHPStan\Fixture\ManyCasesTestEnum', + new EnumCaseObjectType('PHPStan\Fixture\ManyCasesTestEnum', 'F'), + ), TrinaryLogic::createYes(), ]; @@ -902,7 +1060,10 @@ public function dataAccepts(): iterable new EnumCaseObjectType('PHPStan\Fixture\TestEnum', 'ONE'), new NullType(), ]), - new ObjectType('PHPStan\Fixture\TestEnum', new EnumCaseObjectType('PHPStan\Fixture\TestEnum', 'TWO')), + new ObjectType( + 'PHPStan\Fixture\TestEnum', + new EnumCaseObjectType('PHPStan\Fixture\TestEnum', 'TWO'), + ), TrinaryLogic::createYes(), ]; @@ -912,7 +1073,10 @@ public function dataAccepts(): iterable new NullType(), ]), new UnionType([ - new ObjectType('PHPStan\Fixture\TestEnum', new EnumCaseObjectType('PHPStan\Fixture\TestEnum', 'TWO')), + new ObjectType( + 'PHPStan\Fixture\TestEnum', + new EnumCaseObjectType('PHPStan\Fixture\TestEnum', 'TWO'), + ), new NullType(), ]), TrinaryLogic::createYes(), @@ -925,76 +1089,141 @@ public function dataAccepts(): iterable new IntegerType(), new FloatType(), ]), - TemplateTypeFactory::create(TemplateTypeScope::createWithClass('Foo'), 'T', new UnionType([ + TemplateTypeFactory::create( + TemplateTypeScope::createWithClass('Foo'), + 'T', + new UnionType([ new IntegerType(), new FloatType(), - ]), TemplateTypeVariance::createInvariant()), + ]), + TemplateTypeVariance::createInvariant(), + ), TrinaryLogic::createYes(), ], 'accepts template-of-union equal to a union member' => [ new UnionType([ - TemplateTypeFactory::create(TemplateTypeScope::createWithClass('Foo'), 'T', new UnionType([ + TemplateTypeFactory::create( + TemplateTypeScope::createWithClass('Foo'), + 'T', + new UnionType([ new IntegerType(), new FloatType(), - ]), TemplateTypeVariance::createInvariant()), + ]), + TemplateTypeVariance::createInvariant(), + ), new NullType(), ]), - TemplateTypeFactory::create(TemplateTypeScope::createWithClass('Foo'), 'T', new UnionType([ + TemplateTypeFactory::create( + TemplateTypeScope::createWithClass('Foo'), + 'T', + new UnionType([ new IntegerType(), new FloatType(), - ]), TemplateTypeVariance::createInvariant()), + ]), + TemplateTypeVariance::createInvariant(), + ), TrinaryLogic::createYes(), ], 'accepts template-of-union sub type of a union member' => [ new UnionType([ - TemplateTypeFactory::create(TemplateTypeScope::createWithClass('Foo'), 'T', new UnionType([ + TemplateTypeFactory::create( + TemplateTypeScope::createWithClass('Foo'), + 'T', + new UnionType([ new IntegerType(), new FloatType(), - ]), TemplateTypeVariance::createInvariant()), + ]), + TemplateTypeVariance::createInvariant(), + ), new NullType(), ]), - TemplateTypeFactory::create(TemplateTypeScope::createWithClass('Bar'), 'T', new UnionType([ + TemplateTypeFactory::create( + TemplateTypeScope::createWithClass('Bar'), + 'T', + new UnionType([ new IntegerType(), new FloatType(), - ]), TemplateTypeVariance::createInvariant()), + ]), + TemplateTypeVariance::createInvariant(), + ), TrinaryLogic::createYes(), ], 'maybe accepts template-of-union sub type of a union member (argument)' => [ new UnionType([ - TemplateTypeFactory::create(TemplateTypeScope::createWithClass('Foo'), 'T', new UnionType([ + TemplateTypeFactory::create( + TemplateTypeScope::createWithClass('Foo'), + 'T', + new UnionType([ new IntegerType(), new FloatType(), - ]), TemplateTypeVariance::createInvariant())->toArgument(), + ]), + TemplateTypeVariance::createInvariant(), + )->toArgument(), new NullType(), ]), - TemplateTypeFactory::create(TemplateTypeScope::createWithClass('Bar'), 'T', new UnionType([ + TemplateTypeFactory::create( + TemplateTypeScope::createWithClass('Bar'), + 'T', + new UnionType([ new IntegerType(), new FloatType(), - ]), TemplateTypeVariance::createInvariant()), + ]), + TemplateTypeVariance::createInvariant(), + ), TrinaryLogic::createMaybe(), ], 'accepts template-of-string equal to a union member' => [ new UnionType([ - TemplateTypeFactory::create(TemplateTypeScope::createWithClass('Foo'), 'T', new StringType(), TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithClass('Foo'), + 'T', + new StringType(), + TemplateTypeVariance::createInvariant(), + ), new NullType(), ]), - TemplateTypeFactory::create(TemplateTypeScope::createWithClass('Foo'), 'T', new StringType(), TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithClass('Foo'), + 'T', + new StringType(), + TemplateTypeVariance::createInvariant(), + ), TrinaryLogic::createYes(), ], 'accepts template-of-string sub type of a union member' => [ new UnionType([ - TemplateTypeFactory::create(TemplateTypeScope::createWithClass('Foo'), 'T', new StringType(), TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithClass('Foo'), + 'T', + new StringType(), + TemplateTypeVariance::createInvariant(), + ), new NullType(), ]), - TemplateTypeFactory::create(TemplateTypeScope::createWithClass('Bar'), 'T', new StringType(), TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithClass('Bar'), + 'T', + new StringType(), + TemplateTypeVariance::createInvariant(), + ), TrinaryLogic::createMaybe(), ], 'maybe accepts template-of-string sub type of a union member (argument)' => [ new UnionType([ - TemplateTypeFactory::create(TemplateTypeScope::createWithClass('Foo'), 'T', new StringType(), TemplateTypeVariance::createInvariant())->toArgument(), + TemplateTypeFactory::create( + TemplateTypeScope::createWithClass('Foo'), + 'T', + new StringType(), + TemplateTypeVariance::createInvariant(), + )->toArgument(), new NullType(), ]), - TemplateTypeFactory::create(TemplateTypeScope::createWithClass('Bar'), 'T', new StringType(), TemplateTypeVariance::createInvariant()), + TemplateTypeFactory::create( + TemplateTypeScope::createWithClass('Bar'), + 'T', + new StringType(), + TemplateTypeVariance::createInvariant(), + ), TrinaryLogic::createMaybe(), ], 'accepts template-of-union containing a union member' => [ @@ -1002,25 +1231,40 @@ public function dataAccepts(): iterable new IntegerType(), new NullType(), ]), - TemplateTypeFactory::create(TemplateTypeScope::createWithClass('Foo'), 'T', new UnionType([ + TemplateTypeFactory::create( + TemplateTypeScope::createWithClass('Foo'), + 'T', + new UnionType([ new IntegerType(), new FloatType(), - ]), TemplateTypeVariance::createInvariant()), + ]), + TemplateTypeVariance::createInvariant(), + ), TrinaryLogic::createMaybe(), ], 'accepts intersection with template-of-union equal to a union member' => [ new UnionType([ - TemplateTypeFactory::create(TemplateTypeScope::createWithClass('Foo'), 'T', new UnionType([ + TemplateTypeFactory::create( + TemplateTypeScope::createWithClass('Foo'), + 'T', + new UnionType([ new ObjectType('Iterator'), new ObjectType('IteratorAggregate'), - ]), TemplateTypeVariance::createInvariant()), + ]), + TemplateTypeVariance::createInvariant(), + ), new NullType(), ]), new IntersectionType([ - TemplateTypeFactory::create(TemplateTypeScope::createWithClass('Foo'), 'T', new UnionType([ + TemplateTypeFactory::create( + TemplateTypeScope::createWithClass('Foo'), + 'T', + new UnionType([ new ObjectType('Iterator'), new ObjectType('IteratorAggregate'), - ]), TemplateTypeVariance::createInvariant()), + ]), + TemplateTypeVariance::createInvariant(), + ), new ObjectType('Countable'), ]), TrinaryLogic::createYes(), @@ -1031,9 +1275,17 @@ public function dataAccepts(): iterable /** * @dataProvider dataAccepts */ - public function testAccepts(UnionType $type, Type $acceptedType, TrinaryLogic $expectedResult) : void + public function testAccepts( + UnionType $type, + Type $acceptedType, + TrinaryLogic $expectedResult, + ): void { - $this->assertSame($expectedResult->describe(), $type->accepts($acceptedType, true)->describe(), sprintf('%s -> accepts(%s)', $type->describe(VerbosityLevel::precise()), $acceptedType->describe(VerbosityLevel::precise()))); + $this->assertSame( + $expectedResult->describe(), + $type->accepts($acceptedType, true)->describe(), + sprintf('%s -> accepts(%s)', $type->describe(VerbosityLevel::precise()), $acceptedType->describe(VerbosityLevel::precise())), + ); } public function dataHasMethod(): array @@ -1065,7 +1317,11 @@ public function dataHasMethod(): array /** * @dataProvider dataHasMethod */ - public function testHasMethod(UnionType $type, string $methodName, TrinaryLogic $expectedResult) : void + public function testHasMethod( + UnionType $type, + string $methodName, + TrinaryLogic $expectedResult, + ): void { $this->assertSame($expectedResult->describe(), $type->hasMethod($methodName)->describe()); } @@ -1098,9 +1354,16 @@ public function testSorting(): void $type1 = new UnionType($types); $type2 = new UnionType(array_reverse($types)); - $this->assertSame($type1->describe(VerbosityLevel::precise()), $type2->describe(VerbosityLevel::precise()), 'UnionType sorting always produces the same order'); + $this->assertSame( + $type1->describe(VerbosityLevel::precise()), + $type2->describe(VerbosityLevel::precise()), + 'UnionType sorting always produces the same order', + ); - $this->assertTrue($type1->equals($type2), 'UnionType sorting always produces the same order'); + $this->assertTrue( + $type1->equals($type2), + 'UnionType sorting always produces the same order', + ); } /** @@ -1108,14 +1371,19 @@ public function testSorting(): void * @param Type[] $types * @param list $expectedDescriptions */ - public function testGetConstantArrays(array $types, array $expectedDescriptions) : void + public function testGetConstantArrays( + array $types, + array $expectedDescriptions, + ): void { $unionType = TypeCombinator::union(...$types); $constantArrays = $unionType->getConstantArrays(); + $actualDescriptions = []; foreach ($constantArrays as $constantArray) { $actualDescriptions[] = $constantArray->describe(VerbosityLevel::precise()); } + $this->assertSame($expectedDescriptions, $actualDescriptions); } @@ -1124,8 +1392,20 @@ public function dataGetConstantArrays(): iterable yield from [ [ [ - TypeCombinator::intersect(new ConstantArrayType([new ConstantIntegerType(1), new ConstantIntegerType(2)], [new IntegerType(), new StringType()], 2, [0, 1]), new NonEmptyArrayType()), - new ConstantArrayType([new ConstantIntegerType(0), new ConstantIntegerType(1)], [new ObjectType(Foo::class), new ObjectType(stdClass::class)], 2), + TypeCombinator::intersect( + new ConstantArrayType( + [new ConstantIntegerType(1), new ConstantIntegerType(2)], + [new IntegerType(), new StringType()], + 2, + [0, 1], + ), + new NonEmptyArrayType(), + ), + new ConstantArrayType( + [new ConstantIntegerType(0), new ConstantIntegerType(1)], + [new ObjectType(Foo::class), new ObjectType(stdClass::class)], + 2, + ), ], [ 'array{1?: int, 2?: string}', @@ -1134,7 +1414,14 @@ public function dataGetConstantArrays(): iterable ], [ [ - TypeCombinator::intersect(new ConstantArrayType([new ConstantIntegerType(1), new ConstantIntegerType(2)], [new IntegerType(), new StringType()], 2, [0, 1])), + TypeCombinator::intersect( + new ConstantArrayType( + [new ConstantIntegerType(1), new ConstantIntegerType(2)], + [new IntegerType(), new StringType()], + 2, + [0, 1], + ), + ), new IntegerType(), ], [], @@ -1146,13 +1433,18 @@ public function dataGetConstantArrays(): iterable * @dataProvider dataGetConstantStrings * @param list $expectedDescriptions */ - public function testGetConstantStrings(Type $unionType, array $expectedDescriptions) : void + public function testGetConstantStrings( + Type $unionType, + array $expectedDescriptions, + ): void { $constantStrings = $unionType->getConstantStrings(); + $actualDescriptions = []; foreach ($constantStrings as $constantString) { $actualDescriptions[] = $constantString->describe(VerbosityLevel::precise()); } + $this->assertSame($expectedDescriptions, $actualDescriptions); } @@ -1160,26 +1452,39 @@ public function dataGetConstantStrings(): iterable { yield from [ [ - TypeCombinator::union(new ConstantStringType('hello'), new ConstantStringType('world')), + TypeCombinator::union( + new ConstantStringType('hello'), + new ConstantStringType('world'), + ), [ "'hello'", "'world'", ], ], [ - TypeCombinator::union(new ConstantStringType(''), TypeCombinator::intersect(new StringType(), new AccessoryNumericStringType())), + TypeCombinator::union( + new ConstantStringType(''), + TypeCombinator::intersect( + new StringType(), + new AccessoryNumericStringType(), + ), + ), [], ], [ new UnionType([ - new IntersectionType([ + new IntersectionType( + [ new ConstantStringType('foo'), new AccessoryLiteralStringType(), - ]), - new IntersectionType([ + ], + ), + new IntersectionType( + [ new ConstantStringType('bar'), new AccessoryLiteralStringType(), - ]), + ], + ), ]), [ "'foo'", @@ -1202,7 +1507,10 @@ public function dataGetConstantStrings(): iterable * @dataProvider dataGetObjectClassNames * @param list $expectedObjectClassNames */ - public function testGetObjectClassNames(Type $unionType, array $expectedObjectClassNames) : void + public function testGetObjectClassNames( + Type $unionType, + array $expectedObjectClassNames, + ): void { $this->assertSame($expectedObjectClassNames, $unionType->getObjectClassNames()); } @@ -1211,18 +1519,27 @@ public function dataGetObjectClassNames(): iterable { yield from [ [ - TypeCombinator::union(new ObjectType(stdClass::class), new ObjectType(DateTimeImmutable::class)), + TypeCombinator::union( + new ObjectType(stdClass::class), + new ObjectType(DateTimeImmutable::class), + ), [ 'stdClass', 'DateTimeImmutable', ], ], [ - TypeCombinator::union(new ObjectType(stdClass::class), new NullType()), + TypeCombinator::union( + new ObjectType(stdClass::class), + new NullType(), + ), [], ], [ - TypeCombinator::union(new StringType(), new NullType()), + TypeCombinator::union( + new StringType(), + new NullType(), + ), [], ], ]; @@ -1232,13 +1549,18 @@ public function dataGetObjectClassNames(): iterable * @dataProvider dataGetArrays * @param list $expectedDescriptions */ - public function testGetArrays(Type $unionType, array $expectedDescriptions) : void + public function testGetArrays( + Type $unionType, + array $expectedDescriptions, + ): void { $arrays = $unionType->getArrays(); + $actualDescriptions = []; foreach ($arrays as $arrayType) { $actualDescriptions[] = $arrayType->describe(VerbosityLevel::precise()); } + $this->assertSame($expectedDescriptions, $actualDescriptions); } @@ -1246,18 +1568,49 @@ public function dataGetArrays(): iterable { yield from [ [ - TypeCombinator::union(new ConstantStringType('hello'), new ConstantStringType('world')), + TypeCombinator::union( + new ConstantStringType('hello'), + new ConstantStringType('world'), + ), [], ], [ - TypeCombinator::union(TypeCombinator::intersect(new ConstantArrayType([new ConstantIntegerType(1), new ConstantIntegerType(2)], [new IntegerType(), new StringType()], 2, [0, 1]), new NonEmptyArrayType()), new ConstantArrayType([new ConstantIntegerType(0), new ConstantIntegerType(1)], [new ObjectType(Foo::class), new ObjectType(stdClass::class)], 2)), + TypeCombinator::union( + TypeCombinator::intersect( + new ConstantArrayType( + [new ConstantIntegerType(1), new ConstantIntegerType(2)], + [new IntegerType(), new StringType()], + 2, + [0, 1], + ), + new NonEmptyArrayType(), + ), + new ConstantArrayType( + [new ConstantIntegerType(0), new ConstantIntegerType(1)], + [new ObjectType(Foo::class), new ObjectType(stdClass::class)], + 2, + ), + ), [ 'array{1?: int, 2?: string}', 'array{RecursionCallable\Foo, stdClass}', ], ], [ - TypeCombinator::union(new ArrayType(new IntegerType(), new StringType()), new ConstantArrayType([new ConstantIntegerType(1), new ConstantIntegerType(2)], [new IntegerType(), new StringType()], 2, [0, 1]), new ConstantArrayType([new ConstantIntegerType(0), new ConstantIntegerType(1)], [new ObjectType(Foo::class), new ObjectType(stdClass::class)], 2)), + TypeCombinator::union( + new ArrayType(new IntegerType(), new StringType()), + new ConstantArrayType( + [new ConstantIntegerType(1), new ConstantIntegerType(2)], + [new IntegerType(), new StringType()], + 2, + [0, 1], + ), + new ConstantArrayType( + [new ConstantIntegerType(0), new ConstantIntegerType(1)], + [new ObjectType(Foo::class), new ObjectType(stdClass::class)], + 2, + ), + ), [ 'array', ], diff --git a/tests/e2e/ResultCacheEndToEndTest.php b/tests/e2e/ResultCacheEndToEndTest.php index 47a868dfc49..3ba8efae970 100644 --- a/tests/e2e/ResultCacheEndToEndTest.php +++ b/tests/e2e/ResultCacheEndToEndTest.php @@ -141,7 +141,12 @@ public function testResultCachePath(): void */ private function runPhpstan(int $expectedExitCode, string $phpstanConfigPath = __DIR__ . '/phpstan.neon'): array { - exec(sprintf('%s %s analyse -c %s -l 5 --no-progress --error-format json lib 2>&1', escapeshellarg(PHP_BINARY), escapeshellarg(__DIR__ . '/../../bin/phpstan'), escapeshellarg($phpstanConfigPath)), $outputLines, $exitCode); + exec(sprintf( + '%s %s analyse -c %s -l 5 --no-progress --error-format json lib 2>&1', + escapeshellarg(PHP_BINARY), + escapeshellarg(__DIR__ . '/../../bin/phpstan'), + escapeshellarg($phpstanConfigPath), + ), $outputLines, $exitCode); $output = implode("\n", $outputLines); try { @@ -165,9 +170,7 @@ private function transformResultCache(array $resultCache): array { $new = []; foreach ($resultCache['dependencies'] as $file => $data) { - $files = array_map(function (string $file) : string { - return $this->relativizePath($file); - }, $data['dependentFiles']); + $files = array_map(fn (string $file): string => $this->relativizePath($file), $data['dependentFiles']); sort($files); $new[$this->relativizePath($file)] = $files; }