diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 065346b2..ad3633e9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -6,7 +6,7 @@ on: pull_request: push: branches: - - "1.5.x" + - "2.0.x" jobs: lint: @@ -17,8 +17,6 @@ jobs: fail-fast: false matrix: php-version: - - "7.2" - - "7.3" - "7.4" - "8.0" - "8.1" @@ -45,10 +43,6 @@ jobs: if: matrix.php-version == '8.4' run: "composer config platform.php 8.3.99" - - name: "Downgrade PHPUnit" - if: matrix.php-version == '7.2' || matrix.php-version == '7.3' - run: "composer require --dev phpunit/phpunit:^8.5.31 --no-update --update-with-dependencies" - - name: "Install dependencies" run: "composer install --no-interaction --no-progress" @@ -69,7 +63,7 @@ jobs: with: repository: "phpstan/build-cs" path: "build-cs" - ref: "1.x" + ref: "2.x" - name: "Install PHP" uses: "shivammathur/setup-php@v2" @@ -103,8 +97,6 @@ jobs: fail-fast: false matrix: php-version: - - "7.2" - - "7.3" - "7.4" - "8.0" - "8.1" @@ -139,18 +131,10 @@ jobs: if: matrix.php-version == '8.4' run: "composer config platform.php 8.3.99" - - name: "Downgrade PHPUnit" - if: matrix.php-version == '7.2' || matrix.php-version == '7.3' - run: "composer require --dev phpunit/phpunit:^8.5.31 --no-update --update-with-dependencies" - - name: "Install lowest dependencies" if: ${{ matrix.dependencies == 'lowest' }} run: "composer update --prefer-lowest --no-interaction --no-progress" - - name: "Update Doctrine DBAl to ^3" - if: matrix.php-version != '7.2' && matrix.dependencies == 'lowest' - run: "composer require --dev doctrine/dbal:^3.3.8 --no-interaction --no-progress" - - name: "Install highest dependencies" if: ${{ matrix.dependencies == 'highest' }} run: "composer update --no-interaction --no-progress" @@ -169,7 +153,6 @@ jobs: fail-fast: false matrix: php-version: - - "7.3" - "7.4" - "8.0" - "8.1" @@ -198,10 +181,6 @@ jobs: if: matrix.php-version == '8.4' run: "composer config platform.php 8.3.99" - - name: "Downgrade PHPUnit" - if: matrix.php-version == '7.2' || matrix.php-version == '7.3' - run: "composer require --dev phpunit/phpunit:^8.5.31 --no-update --update-with-dependencies" - - name: "Install dependencies" run: "composer update --no-interaction --no-progress" diff --git a/.github/workflows/platform-test.yml b/.github/workflows/platform-test.yml index fe88b6c9..38110353 100644 --- a/.github/workflows/platform-test.yml +++ b/.github/workflows/platform-test.yml @@ -6,7 +6,7 @@ on: pull_request: push: branches: - - "1.5.x" + - "2.0.x" jobs: tests: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b1a669a9..b8c96d48 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,7 +18,7 @@ jobs: - name: Generate changelog id: changelog - uses: metcalfc/changelog-generator@v4.3.1 + uses: metcalfc/changelog-generator@v4.6.2 with: myToken: ${{ secrets.PHPSTAN_BOT_TOKEN }} diff --git a/.github/workflows/test-projects.yml b/.github/workflows/test-projects.yml index 2b85f70e..cebc3431 100644 --- a/.github/workflows/test-projects.yml +++ b/.github/workflows/test-projects.yml @@ -26,4 +26,4 @@ jobs: token: ${{ secrets.REPO_ACCESS_TOKEN }} repository: "${{ matrix.repository }}" event-type: test_phpstan - client-payload: '{"ref": "1.11.x"}' + client-payload: '{"ref": "2.1.x"}' diff --git a/LICENSE b/LICENSE index 7c0f2b7b..e5f34e60 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,7 @@ MIT License Copyright (c) 2016 Ondřej Mirtes +Copyright (c) 2025 PHPStan s.r.o. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/Makefile b/Makefile index c62886f9..efc169db 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ lint: .PHONY: cs-install cs-install: git clone https://github.com/phpstan/build-cs.git || true - git -C build-cs fetch origin && git -C build-cs reset --hard origin/1.x + git -C build-cs fetch origin && git -C build-cs reset --hard origin/2.x composer install --working-dir build-cs .PHONY: cs diff --git a/README.md b/README.md index 83bc5364..c8a587b1 100644 --- a/README.md +++ b/README.md @@ -126,7 +126,7 @@ $query->getResult(); // array Queries are analyzed statically and do not require a running database server. This makes use of the Doctrine DQL parser and entities metadata. -Most DQL features are supported, including `GROUP BY`, `DISTINCT`, all flavors of `JOIN`, arithmetic expressions, functions, aggregations, `NEW`, etc. Sub queries and `INDEX BY` are not yet supported (infered type will be `mixed`). +Most DQL features are supported, including `GROUP BY`, `INDEX BY`, `DISTINCT`, all flavors of `JOIN`, arithmetic expressions, functions, aggregations, `NEW`, etc. Sub queries are not yet supported (infered type will be `mixed`). ### Query type inference of expressions diff --git a/compatibility/BackedEnum.stub b/compatibility/BackedEnum.stub new file mode 100644 index 00000000..2376a2fc --- /dev/null +++ b/compatibility/BackedEnum.stub @@ -0,0 +1,6 @@ +, string given\\.$#" count: 1 path: tests/Rules/Doctrine/ORM/EntityColumnRuleTest.php + + - + message: ''' + #^Fetching class constant class of deprecated class Doctrine\\ORM\\Mapping\\Driver\\AnnotationDriver\: + This class will be removed in 3\.0 without replacement\. + Copyright \(c\) Doctrine Project + From https\://github\.com/doctrine/orm/blob/40fbbf4429b0d66517244051237a2bd0616a7a13/src/Mapping/Driver/AnnotationDriver\.php$# + ''' + identifier: classConstant.deprecatedClass + count: 1 + path: src/Doctrine/Mapping/ClassMetadataFactory.php + + - + message: ''' + #^Instantiation of deprecated class Doctrine\\ORM\\Mapping\\Driver\\AnnotationDriver\: + This class will be removed in 3\.0 without replacement\. + Copyright \(c\) Doctrine Project + From https\://github\.com/doctrine/orm/blob/40fbbf4429b0d66517244051237a2bd0616a7a13/src/Mapping/Driver/AnnotationDriver\.php$# + ''' + identifier: new.deprecated + count: 1 + path: src/Doctrine/Mapping/ClassMetadataFactory.php + + - + message: ''' + #^Instantiation of deprecated class Doctrine\\ORM\\Mapping\\Driver\\AnnotationDriver\: + This class will be removed in 3\.0 without replacement\. + Copyright \(c\) Doctrine Project + From https\://github\.com/doctrine/orm/blob/40fbbf4429b0d66517244051237a2bd0616a7a13/src/Mapping/Driver/AnnotationDriver\.php$# + ''' + identifier: new.deprecated + count: 1 + path: tests/Classes/entity-manager.php + + - + message: ''' + #^Instantiation of deprecated class Doctrine\\ORM\\Mapping\\Driver\\AnnotationDriver\: + This class will be removed in 3\.0 without replacement\. + Copyright \(c\) Doctrine Project + From https\://github\.com/doctrine/orm/blob/40fbbf4429b0d66517244051237a2bd0616a7a13/src/Mapping/Driver/AnnotationDriver\.php$# + ''' + identifier: new.deprecated + count: 1 + path: tests/DoctrineIntegration/ORM/entity-manager.php + + - + message: ''' + #^Instantiation of deprecated class Doctrine\\ORM\\Mapping\\Driver\\AnnotationDriver\: + This class will be removed in 3\.0 without replacement\. + Copyright \(c\) Doctrine Project + From https\://github\.com/doctrine/orm/blob/40fbbf4429b0d66517244051237a2bd0616a7a13/src/Mapping/Driver/AnnotationDriver\.php$# + ''' + identifier: new.deprecated + count: 1 + path: tests/Platform/QueryResultTypeWalkerFetchTypeMatrixTest.php + + - + message: ''' + #^Instantiation of deprecated class Doctrine\\ORM\\Mapping\\Driver\\AnnotationDriver\: + This class will be removed in 3\.0 without replacement\. + Copyright \(c\) Doctrine Project + From https\://github\.com/doctrine/orm/blob/40fbbf4429b0d66517244051237a2bd0616a7a13/src/Mapping/Driver/AnnotationDriver\.php$# + ''' + identifier: new.deprecated + count: 1 + path: tests/Rules/DeadCode/entity-manager.php + + - + message: ''' + #^Instantiation of deprecated class Doctrine\\ORM\\Mapping\\Driver\\AnnotationDriver\: + This class will be removed in 3\.0 without replacement\. + Copyright \(c\) Doctrine Project + From https\://github\.com/doctrine/orm/blob/40fbbf4429b0d66517244051237a2bd0616a7a13/src/Mapping/Driver/AnnotationDriver\.php$# + ''' + identifier: new.deprecated + count: 1 + path: tests/Rules/Properties/entity-manager.php + + - + message: ''' + #^Instantiation of deprecated class Doctrine\\ORM\\Mapping\\Driver\\AnnotationDriver\: + This class will be removed in 3\.0 without replacement\. + Copyright \(c\) Doctrine Project + From https\://github\.com/doctrine/orm/blob/40fbbf4429b0d66517244051237a2bd0616a7a13/src/Mapping/Driver/AnnotationDriver\.php$# + ''' + identifier: new.deprecated + count: 1 + path: tests/Type/Doctrine/DBAL/mysqli.php + + - + message: ''' + #^Instantiation of deprecated class Doctrine\\ORM\\Mapping\\Driver\\AnnotationDriver\: + This class will be removed in 3\.0 without replacement\. + Copyright \(c\) Doctrine Project + From https\://github\.com/doctrine/orm/blob/40fbbf4429b0d66517244051237a2bd0616a7a13/src/Mapping/Driver/AnnotationDriver\.php$# + ''' + identifier: new.deprecated + count: 1 + path: tests/Type/Doctrine/DBAL/pdo.php diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index cc1e2048..64b1a032 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1,71 +1,241 @@ parameters: ignoreErrors: - - message: "#^Calling PHPStan\\\\Type\\\\ParserNodeTypeToPHPStanType\\:\\:resolve\\(\\) is not covered by backward compatibility promise\\. The method might change in a minor PHPStan version\\.$#" + message: '#^Call to internal method Doctrine\\DBAL\\Connection\:\:getParams\(\) from outside its root namespace Doctrine\.$#' + identifier: method.internal + count: 2 + path: src/Doctrine/Driver/DriverDetector.php + + - + message: ''' + #^Access to constant on deprecated class Doctrine\\ORM\\Mapping\\Driver\\AnnotationDriver\: + This class will be removed in 3\.0 without replacement\.$# + ''' + identifier: classConstant.deprecatedClass count: 1 - path: src/Rules/Doctrine/ORM/EntityColumnRule.php + path: src/Doctrine/Mapping/ClassMetadataFactory.php - - message: "#^Calling PHPStan\\\\Type\\\\TypehintHelper\\:\\:decideType\\(\\) is not covered by backward compatibility promise\\. The method might change in a minor PHPStan version\\.$#" + message: ''' + #^Instantiation of deprecated class Doctrine\\ORM\\Mapping\\Driver\\AnnotationDriver\: + This class will be removed in 3\.0 without replacement\.$# + ''' + identifier: new.deprecatedClass count: 1 - path: src/Rules/Doctrine/ORM/EntityColumnRule.php + path: src/Doctrine/Mapping/ClassMetadataFactory.php - - message: "#^Calling PHPStan\\\\Type\\\\ParserNodeTypeToPHPStanType\\:\\:resolve\\(\\) is not covered by backward compatibility promise\\. The method might change in a minor PHPStan version\\.$#" + message: '#^Calling PHPStan\\Type\\TypehintHelper\:\:decideType\(\) is not covered by backward compatibility promise\. The method might change in a minor PHPStan version\.$#' + identifier: phpstanApi.method count: 1 - path: src/Rules/Doctrine/ORM/EntityRelationRule.php + path: src/Rules/Doctrine/ORM/EntityColumnRule.php - - message: "#^Calling PHPStan\\\\Type\\\\TypehintHelper\\:\\:decideType\\(\\) is not covered by backward compatibility promise\\. The method might change in a minor PHPStan version\\.$#" + message: '#^Calling PHPStan\\Type\\TypehintHelper\:\:decideType\(\) is not covered by backward compatibility promise\. The method might change in a minor PHPStan version\.$#' + identifier: phpstanApi.method count: 1 path: src/Rules/Doctrine/ORM/EntityRelationRule.php - - message: "#^PHPDoc tag @var with type class\\-string is not subtype of native type 'Doctrine\\\\\\\\Bundle…'\\.$#" + message: '#^PHPDoc tag @var with type class\-string is not subtype of native type ''Doctrine\\\\Bundle…''\.$#' + identifier: varTag.nativeType count: 1 path: src/Stubs/Doctrine/StubFilesExtensionLoader.php - - message: "#^Accessing PHPStan\\\\Rules\\\\Classes\\\\InstantiationRule\\:\\:class is not covered by backward compatibility promise\\. The class might change in a minor PHPStan version\\.$#" + message: ''' + #^Catching deprecated class Doctrine\\Common\\CommonException\: + The doctrine/common package is deprecated, please use specific packages and their exceptions instead\.$# + ''' + identifier: catch.deprecatedClass + count: 1 + path: src/Type/Doctrine/CreateQueryDynamicReturnTypeExtension.php + + - + message: ''' + #^Catching deprecated class Doctrine\\ORM\\ORMException\: + Use Doctrine\\ORM\\Exception\\ORMException for catch and instanceof$# + ''' + identifier: catch.deprecatedClass + count: 1 + path: src/Type/Doctrine/CreateQueryDynamicReturnTypeExtension.php + + - + message: ''' + #^Access to constant on deprecated class Doctrine\\DBAL\\Types\\ArrayType\: + Use \{@link JsonType\} instead\.$# + ''' + identifier: classConstant.deprecatedClass + count: 1 + path: src/Type/Doctrine/Descriptors/ArrayType.php + + - + message: ''' + #^Access to constant on deprecated class Doctrine\\DBAL\\Types\\ObjectType\: + Use \{@link JsonType\} instead\.$# + ''' + identifier: classConstant.deprecatedClass + count: 1 + path: src/Type/Doctrine/Descriptors/ObjectType.php + + - + message: '#^Parameter \$condExpr of method PHPStan\\Type\\Doctrine\\Query\\QueryResultTypeWalker\:\:walkConditionalExpression\(\) has typehint with internal interface Doctrine\\ORM\\Query\\AST\\Phase2OptimizableConditional\.$#' + identifier: parameter.internalInterface + count: 1 + path: src/Type/Doctrine/Query/QueryResultTypeWalker.php + + - + message: '#^Parameter \$condExpr of method PHPStan\\Type\\Doctrine\\Query\\QueryResultTypeWalker\:\:walkJoinAssociationDeclaration\(\) has typehint with internal interface Doctrine\\ORM\\Query\\AST\\Phase2OptimizableConditional\.$#' + identifier: parameter.internalInterface + count: 1 + path: src/Type/Doctrine/Query/QueryResultTypeWalker.php + + - + message: ''' + #^Catching deprecated class Doctrine\\Common\\CommonException\: + The doctrine/common package is deprecated, please use specific packages and their exceptions instead\.$# + ''' + identifier: catch.deprecatedClass + count: 1 + path: src/Type/Doctrine/QueryBuilder/QueryBuilderGetQueryDynamicReturnTypeExtension.php + + - + message: ''' + #^Catching deprecated class Doctrine\\ORM\\ORMException\: + Use Doctrine\\ORM\\Exception\\ORMException for catch and instanceof$# + ''' + identifier: catch.deprecatedClass + count: 1 + path: src/Type/Doctrine/QueryBuilder/QueryBuilderGetQueryDynamicReturnTypeExtension.php + + - + message: '#^Accessing PHPStan\\Rules\\Classes\\InstantiationRule\:\:class is not covered by backward compatibility promise\. The class might change in a minor PHPStan version\.$#' + identifier: phpstanApi.classConstant count: 1 path: tests/Classes/DoctrineProxyForbiddenClassNamesExtensionTest.php - - message: "#^Accessing PHPStan\\\\Rules\\\\DeadCode\\\\UnusedPrivatePropertyRule\\:\\:class is not covered by backward compatibility promise\\. The class might change in a minor PHPStan version\\.$#" + message: ''' + #^Instantiation of deprecated class Doctrine\\ORM\\Mapping\\Driver\\AnnotationDriver\: + This class will be removed in 3\.0 without replacement\.$# + ''' + identifier: new.deprecatedClass + count: 1 + path: tests/Classes/entity-manager.php + + - + message: ''' + #^Instantiation of deprecated class Doctrine\\ORM\\Mapping\\Driver\\AnnotationDriver\: + This class will be removed in 3\.0 without replacement\.$# + ''' + identifier: new.deprecatedClass + count: 1 + path: tests/DoctrineIntegration/ORM/entity-manager.php + + - + message: '#^Call to internal method PHPUnit\\Framework\\TestCase\:\:dataName\(\) from outside its root namespace PHPUnit\.$#' + identifier: method.internal + count: 14 + path: tests/Platform/QueryResultTypeWalkerFetchTypeMatrixTest.php + + - + message: ''' + #^Instantiation of deprecated class Doctrine\\ORM\\Mapping\\Driver\\AnnotationDriver\: + This class will be removed in 3\.0 without replacement\.$# + ''' + identifier: new.deprecatedClass + count: 1 + path: tests/Platform/QueryResultTypeWalkerFetchTypeMatrixTest.php + + - + message: '#^Accessing PHPStan\\Rules\\DeadCode\\UnusedPrivatePropertyRule\:\:class is not covered by backward compatibility promise\. The class might change in a minor PHPStan version\.$#' + identifier: phpstanApi.classConstant count: 1 path: tests/Rules/DeadCode/UnusedPrivatePropertyRuleTest.php - - message: "#^Accessing PHPStan\\\\Rules\\\\Methods\\\\CallMethodsRule\\:\\:class is not covered by backward compatibility promise\\. The class might change in a minor PHPStan version\\.$#" + message: ''' + #^Instantiation of deprecated class Doctrine\\ORM\\Mapping\\Driver\\AnnotationDriver\: + This class will be removed in 3\.0 without replacement\.$# + ''' + identifier: new.deprecatedClass + count: 1 + path: tests/Rules/DeadCode/entity-manager.php + + - + message: ''' + #^Access to constant on deprecated class Doctrine\\DBAL\\Types\\ArrayType\: + Use \{@link JsonType\} instead\.$# + ''' + identifier: classConstant.deprecatedClass + count: 1 + path: tests/Rules/Doctrine/ORM/EntityColumnRuleTest.php + + - + message: '#^Accessing PHPStan\\Rules\\Methods\\CallMethodsRule\:\:class is not covered by backward compatibility promise\. The class might change in a minor PHPStan version\.$#' + identifier: phpstanApi.classConstant count: 1 path: tests/Rules/Doctrine/ORM/MagicRepositoryMethodCallRuleTest.php - - message: "#^Accessing PHPStan\\\\Rules\\\\Exceptions\\\\CatchWithUnthrownExceptionRule\\:\\:class is not covered by backward compatibility promise\\. The class might change in a minor PHPStan version\\.$#" + message: '#^Accessing PHPStan\\Rules\\Exceptions\\CatchWithUnthrownExceptionRule\:\:class is not covered by backward compatibility promise\. The class might change in a minor PHPStan version\.$#' + identifier: phpstanApi.classConstant count: 1 path: tests/Rules/Exceptions/CatchWithUnthrownExceptionRuleTest.php - - message: "#^Accessing PHPStan\\\\Rules\\\\Exceptions\\\\TooWideMethodThrowTypeRule\\:\\:class is not covered by backward compatibility promise\\. The class might change in a minor PHPStan version\\.$#" + message: '#^Accessing PHPStan\\Rules\\Exceptions\\TooWideMethodThrowTypeRule\:\:class is not covered by backward compatibility promise\. The class might change in a minor PHPStan version\.$#' + identifier: phpstanApi.classConstant count: 1 path: tests/Rules/Exceptions/TooWideMethodThrowTypeRuleTest.php - - message: "#^Accessing PHPStan\\\\Rules\\\\DeadCode\\\\UnusedPrivatePropertyRule\\:\\:class is not covered by backward compatibility promise\\. The class might change in a minor PHPStan version\\.$#" + message: '#^Accessing PHPStan\\Rules\\DeadCode\\UnusedPrivatePropertyRule\:\:class is not covered by backward compatibility promise\. The class might change in a minor PHPStan version\.$#' + identifier: phpstanApi.classConstant count: 1 path: tests/Rules/Properties/MissingGedmoByPhpDocPropertyAssignRuleTest.php - - message: "#^Accessing PHPStan\\\\Rules\\\\DeadCode\\\\UnusedPrivatePropertyRule\\:\\:class is not covered by backward compatibility promise\\. The class might change in a minor PHPStan version\\.$#" + message: '#^Accessing PHPStan\\Rules\\DeadCode\\UnusedPrivatePropertyRule\:\:class is not covered by backward compatibility promise\. The class might change in a minor PHPStan version\.$#' + identifier: phpstanApi.classConstant count: 1 path: tests/Rules/Properties/MissingGedmoPropertyAssignRuleTest.php - - message: "#^Accessing PHPStan\\\\Rules\\\\Properties\\\\MissingReadOnlyByPhpDocPropertyAssignRule\\:\\:class is not covered by backward compatibility promise\\. The class might change in a minor PHPStan version\\.$#" + message: '#^Accessing PHPStan\\Rules\\Properties\\MissingReadOnlyByPhpDocPropertyAssignRule\:\:class is not covered by backward compatibility promise\. The class might change in a minor PHPStan version\.$#' + identifier: phpstanApi.classConstant count: 1 path: tests/Rules/Properties/MissingReadOnlyByPhpDocPropertyAssignRuleTest.php - - message: "#^Accessing PHPStan\\\\Rules\\\\Properties\\\\MissingReadOnlyPropertyAssignRule\\:\\:class is not covered by backward compatibility promise\\. The class might change in a minor PHPStan version\\.$#" + message: '#^Accessing PHPStan\\Rules\\Properties\\MissingReadOnlyPropertyAssignRule\:\:class is not covered by backward compatibility promise\. The class might change in a minor PHPStan version\.$#' + identifier: phpstanApi.classConstant count: 1 path: tests/Rules/Properties/MissingReadOnlyPropertyAssignRuleTest.php + + - + message: ''' + #^Instantiation of deprecated class Doctrine\\ORM\\Mapping\\Driver\\AnnotationDriver\: + This class will be removed in 3\.0 without replacement\.$# + ''' + identifier: new.deprecatedClass + count: 1 + path: tests/Rules/Properties/entity-manager.php + + - + message: ''' + #^Instantiation of deprecated class Doctrine\\ORM\\Mapping\\Driver\\AnnotationDriver\: + This class will be removed in 3\.0 without replacement\.$# + ''' + identifier: new.deprecatedClass + count: 1 + path: tests/Type/Doctrine/DBAL/mysqli.php + + - + message: ''' + #^Instantiation of deprecated class Doctrine\\ORM\\Mapping\\Driver\\AnnotationDriver\: + This class will be removed in 3\.0 without replacement\.$# + ''' + identifier: new.deprecatedClass + count: 1 + path: tests/Type/Doctrine/DBAL/pdo.php diff --git a/phpstan.neon b/phpstan.neon index d099cb21..efbf455d 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -2,9 +2,11 @@ includes: - extension.neon - rules.neon - phpstan-baseline.neon + - phpstan-baseline-deprecations.neon - phpstan-baseline-dbal-3.neon - compatibility/orm-3-baseline.php - vendor/phpstan/phpstan-strict-rules/rules.neon + - vendor/phpstan/phpstan-deprecation-rules/rules.neon - vendor/phpstan/phpstan-phpunit/extension.neon - vendor/phpstan/phpstan-phpunit/rules.neon - phar://phpstan.phar/conf/bleedingEdge.neon @@ -64,3 +66,9 @@ parameters: - '#^Call to function method_exists\(\) with Doctrine\\DBAL\\Connection and ''createSchemaManager'' will always evaluate to true\.$#' - '#^Call to an undefined method Doctrine\\DBAL\\Connection\:\:getSchemaManager\(\)\.$#' path: tests/Platform/QueryResultTypeWalkerFetchTypeMatrixTest.php + +services: + - + class: PHPStan\BackedEnumStubExtension + tags: + - phpstan.stubFilesExtension diff --git a/rules.neon b/rules.neon index de338d2a..0853184d 100644 --- a/rules.neon +++ b/rules.neon @@ -12,8 +12,6 @@ parametersSchema: queryBuilderClass: schema(string(), nullable()) allCollectionsSelectable: bool() objectManagerLoader: schema(string(), nullable()) - searchOtherMethodsForQueryBuilderBeginning: bool() - queryBuilderFastAlgorithm: bool() reportDynamicQueryBuilders: bool() reportUnknownTypes: bool() allowNullablePropertyForRequiredField: bool() @@ -23,14 +21,10 @@ parametersSchema: rules: - PHPStan\Rules\Doctrine\ORM\DqlRule - PHPStan\Rules\Doctrine\ORM\RepositoryMethodCallRule + - PHPStan\Rules\Doctrine\ORM\EntityConstructorNotFinalRule + - PHPStan\Rules\Doctrine\ORM\EntityMappingExceptionRule - PHPStan\Rules\Doctrine\ORM\EntityNotFinalRule -conditionalTags: - PHPStan\Rules\Doctrine\ORM\EntityMappingExceptionRule: - phpstan.rules.rule: %featureToggles.bleedingEdge% - PHPStan\Rules\Doctrine\ORM\EntityConstructorNotFinalRule: - phpstan.rules.rule: %featureToggles.bleedingEdge% - services: - class: PHPStan\Rules\Doctrine\ORM\QueryBuilderDqlRule @@ -43,23 +37,15 @@ services: arguments: reportUnknownTypes: %doctrine.reportUnknownTypes% allowNullablePropertyForRequiredField: %doctrine.allowNullablePropertyForRequiredField% - bleedingEdge: %featureToggles.bleedingEdge% descriptorRegistry: @doctrineTypeDescriptorRegistry tags: - phpstan.rules.rule - - - class: PHPStan\Rules\Doctrine\ORM\EntityMappingExceptionRule - - - class: PHPStan\Rules\Doctrine\ORM\EntityNotFinalRule - class: PHPStan\Rules\Doctrine\ORM\EntityRelationRule arguments: allowNullablePropertyForRequiredField: %doctrine.allowNullablePropertyForRequiredField% - bleedingEdge: %featureToggles.bleedingEdge% tags: - phpstan.rules.rule - - - class: PHPStan\Rules\Doctrine\ORM\EntityConstructorNotFinalRule - class: PHPStan\Classes\DoctrineProxyForbiddenClassNamesExtension tags: diff --git a/src/Classes/DoctrineProxyForbiddenClassNamesExtension.php b/src/Classes/DoctrineProxyForbiddenClassNamesExtension.php index 1ff7f4f6..dbca26af 100644 --- a/src/Classes/DoctrineProxyForbiddenClassNamesExtension.php +++ b/src/Classes/DoctrineProxyForbiddenClassNamesExtension.php @@ -8,8 +8,7 @@ class DoctrineProxyForbiddenClassNamesExtension implements ForbiddenClassNameExtension { - /** @var ObjectMetadataResolver */ - private $objectMetadataResolver; + private ObjectMetadataResolver $objectMetadataResolver; public function __construct(ObjectMetadataResolver $objectMetadataResolver) { diff --git a/src/Doctrine/DoctrineDiagnoseExtension.php b/src/Doctrine/DoctrineDiagnoseExtension.php index 58fda398..0502c736 100644 --- a/src/Doctrine/DoctrineDiagnoseExtension.php +++ b/src/Doctrine/DoctrineDiagnoseExtension.php @@ -15,11 +15,9 @@ class DoctrineDiagnoseExtension implements DiagnoseExtension { - /** @var ObjectMetadataResolver */ - private $objectMetadataResolver; + private ObjectMetadataResolver $objectMetadataResolver; - /** @var DriverDetector */ - private $driverDetector; + private DriverDetector $driverDetector; public function __construct( ObjectMetadataResolver $objectMetadataResolver, @@ -34,7 +32,7 @@ public function print(Output $output): void { $output->writeLineFormatted(sprintf( 'Doctrine\'s objectManagerLoader: %s', - $this->objectMetadataResolver->hasObjectManagerLoader() ? 'In use' : 'No' + $this->objectMetadataResolver->hasObjectManagerLoader() ? 'In use' : 'No', )); $objectManager = $this->objectMetadataResolver->getObjectManager(); @@ -44,7 +42,7 @@ public function print(Output $output): void $output->writeLineFormatted(sprintf( 'Detected driver: %s', - $driver === null ? 'None' : $driver + $driver === null ? 'None' : $driver, )); } diff --git a/src/Doctrine/Mapping/ClassMetadataFactory.php b/src/Doctrine/Mapping/ClassMetadataFactory.php index b2f82388..764268f1 100644 --- a/src/Doctrine/Mapping/ClassMetadataFactory.php +++ b/src/Doctrine/Mapping/ClassMetadataFactory.php @@ -18,8 +18,7 @@ class ClassMetadataFactory extends \Doctrine\ORM\Mapping\ClassMetadataFactory { - /** @var string */ - private $tmpDir; + private string $tmpDir; public function __construct(string $tmpDir) { diff --git a/src/Doctrine/Mapping/MappingDriverChain.php b/src/Doctrine/Mapping/MappingDriverChain.php index ebcdc423..532b208b 100644 --- a/src/Doctrine/Mapping/MappingDriverChain.php +++ b/src/Doctrine/Mapping/MappingDriverChain.php @@ -11,7 +11,7 @@ class MappingDriverChain implements MappingDriver { /** @var MappingDriver[] */ - private $drivers; + private array $drivers; /** * @param MappingDriver[] $drivers diff --git a/src/PhpDoc/Doctrine/DoctrineLiteralStringTypeNodeResolverExtension.php b/src/PhpDoc/Doctrine/DoctrineLiteralStringTypeNodeResolverExtension.php index 3aa371d5..b034f57a 100644 --- a/src/PhpDoc/Doctrine/DoctrineLiteralStringTypeNodeResolverExtension.php +++ b/src/PhpDoc/Doctrine/DoctrineLiteralStringTypeNodeResolverExtension.php @@ -14,8 +14,7 @@ class DoctrineLiteralStringTypeNodeResolverExtension implements TypeNodeResolverExtension { - /** @var bool */ - private $enabled; + private bool $enabled; public function __construct(bool $enabled) { diff --git a/src/PhpDoc/Doctrine/QueryTypeNodeResolverExtension.php b/src/PhpDoc/Doctrine/QueryTypeNodeResolverExtension.php index 39cd65d9..c8193892 100644 --- a/src/PhpDoc/Doctrine/QueryTypeNodeResolverExtension.php +++ b/src/PhpDoc/Doctrine/QueryTypeNodeResolverExtension.php @@ -18,8 +18,7 @@ class QueryTypeNodeResolverExtension implements TypeNodeResolverExtension, TypeNodeResolverAwareExtension { - /** @var TypeNodeResolver */ - private $typeNodeResolver; + private TypeNodeResolver $typeNodeResolver; public function setTypeNodeResolver(TypeNodeResolver $typeNodeResolver): void { @@ -47,7 +46,7 @@ public function resolve(TypeNode $typeNode, NameScope $nameScope): ?Type [ new NullType(), $this->typeNodeResolver->resolve($typeNode->genericTypes[0], $nameScope), - ] + ], ); } diff --git a/src/Reflection/Doctrine/DoctrineSelectableClassReflectionExtension.php b/src/Reflection/Doctrine/DoctrineSelectableClassReflectionExtension.php index 16970a60..ca726d8c 100644 --- a/src/Reflection/Doctrine/DoctrineSelectableClassReflectionExtension.php +++ b/src/Reflection/Doctrine/DoctrineSelectableClassReflectionExtension.php @@ -10,8 +10,7 @@ class DoctrineSelectableClassReflectionExtension implements MethodsClassReflectionExtension { - /** @var ReflectionProvider */ - private $reflectionProvider; + private ReflectionProvider $reflectionProvider; public function __construct(ReflectionProvider $reflectionProvider) { diff --git a/src/Reflection/Doctrine/DummyParameter.php b/src/Reflection/Doctrine/DummyParameter.php index 725f29f6..00eefa2c 100644 --- a/src/Reflection/Doctrine/DummyParameter.php +++ b/src/Reflection/Doctrine/DummyParameter.php @@ -9,23 +9,17 @@ class DummyParameter implements ParameterReflection { - /** @var string */ - private $name; + private string $name; - /** @var Type */ - private $type; + private Type $type; - /** @var bool */ - private $optional; + private bool $optional; - /** @var PassedByReference */ - private $passedByReference; + private PassedByReference $passedByReference; - /** @var bool */ - private $variadic; + private bool $variadic; - /** @var Type|null */ - private $defaultValue; + private ?Type $defaultValue = null; public function __construct(string $name, Type $type, bool $optional, ?PassedByReference $passedByReference, bool $variadic, ?Type $defaultValue) { diff --git a/src/Reflection/Doctrine/EntityRepositoryClassReflectionExtension.php b/src/Reflection/Doctrine/EntityRepositoryClassReflectionExtension.php index 799349da..52a8dcff 100644 --- a/src/Reflection/Doctrine/EntityRepositoryClassReflectionExtension.php +++ b/src/Reflection/Doctrine/EntityRepositoryClassReflectionExtension.php @@ -22,8 +22,7 @@ class EntityRepositoryClassReflectionExtension implements MethodsClassReflectionExtension { - /** @var ObjectMetadataResolver */ - private $objectMetadataResolver; + private ObjectMetadataResolver $objectMetadataResolver; public function __construct(ObjectMetadataResolver $objectMetadataResolver) { diff --git a/src/Reflection/Doctrine/MagicRepositoryMethodReflection.php b/src/Reflection/Doctrine/MagicRepositoryMethodReflection.php index 125f1440..94dc6011 100644 --- a/src/Reflection/Doctrine/MagicRepositoryMethodReflection.php +++ b/src/Reflection/Doctrine/MagicRepositoryMethodReflection.php @@ -21,14 +21,11 @@ class MagicRepositoryMethodReflection implements MethodReflection { - /** @var ClassReflection */ - private $declaringClass; + private ClassReflection $declaringClass; - /** @var string */ - private $name; + private string $name; - /** @var Type */ - private $type; + private Type $type; public function __construct( ClassReflection $declaringClass, @@ -104,7 +101,7 @@ public function getVariants(): array null, $arguments, false, - $this->type + $this->type, ), ]; } diff --git a/src/Rules/Doctrine/ORM/DqlRule.php b/src/Rules/Doctrine/ORM/DqlRule.php index 7a121525..23f4da41 100644 --- a/src/Rules/Doctrine/ORM/DqlRule.php +++ b/src/Rules/Doctrine/ORM/DqlRule.php @@ -11,7 +11,6 @@ use PHPStan\Rules\RuleErrorBuilder; use PHPStan\Type\Doctrine\ObjectMetadataResolver; use PHPStan\Type\ObjectType; -use PHPStan\Type\TypeUtils; use function count; use function sprintf; @@ -21,8 +20,7 @@ class DqlRule implements Rule { - /** @var ObjectMetadataResolver */ - private $objectMetadataResolver; + private ObjectMetadataResolver $objectMetadataResolver; public function __construct(ObjectMetadataResolver $objectMetadataResolver) { @@ -55,7 +53,7 @@ public function processNode(Node $node, Scope $scope): array return []; } - $dqls = TypeUtils::getConstantStrings($scope->getType($node->getArgs()[0]->value)); + $dqls = $scope->getType($node->getArgs()[0]->value)->getConstantStrings(); if (count($dqls) === 0) { return []; } diff --git a/src/Rules/Doctrine/ORM/EntityColumnRule.php b/src/Rules/Doctrine/ORM/EntityColumnRule.php index 70c1fcea..b5f42bb6 100644 --- a/src/Rules/Doctrine/ORM/EntityColumnRule.php +++ b/src/Rules/Doctrine/ORM/EntityColumnRule.php @@ -16,7 +16,6 @@ use PHPStan\Type\MixedType; use PHPStan\Type\NeverType; use PHPStan\Type\ObjectType; -use PHPStan\Type\ParserNodeTypeToPHPStanType; use PHPStan\Type\Type; use PHPStan\Type\TypeCombinator; use PHPStan\Type\TypehintHelper; @@ -34,31 +33,22 @@ class EntityColumnRule implements Rule { - /** @var ObjectMetadataResolver */ - private $objectMetadataResolver; + private ObjectMetadataResolver $objectMetadataResolver; - /** @var DescriptorRegistry */ - private $descriptorRegistry; + private DescriptorRegistry $descriptorRegistry; - /** @var ReflectionProvider */ - private $reflectionProvider; + private ReflectionProvider $reflectionProvider; - /** @var bool */ - private $reportUnknownTypes; + private bool $reportUnknownTypes; - /** @var bool */ - private $allowNullablePropertyForRequiredField; - - /** @var bool */ - private $bleedingEdge; + private bool $allowNullablePropertyForRequiredField; public function __construct( ObjectMetadataResolver $objectMetadataResolver, DescriptorRegistry $descriptorRegistry, ReflectionProvider $reflectionProvider, bool $reportUnknownTypes, - bool $allowNullablePropertyForRequiredField, - bool $bleedingEdge + bool $allowNullablePropertyForRequiredField ) { $this->objectMetadataResolver = $objectMetadataResolver; @@ -66,7 +56,6 @@ public function __construct( $this->reflectionProvider = $reflectionProvider; $this->reportUnknownTypes = $reportUnknownTypes; $this->allowNullablePropertyForRequiredField = $allowNullablePropertyForRequiredField; - $this->bleedingEdge = $bleedingEdge; } public function getNodeType(): string @@ -76,9 +65,6 @@ public function getNodeType(): string public function processNode(Node $node, Scope $scope): array { - if (!$this->bleedingEdge && !$this->objectMetadataResolver->hasObjectManagerLoader()) { - return []; - } $class = $scope->getClassReflection(); if ($class === null) { return []; @@ -106,7 +92,7 @@ public function processNode(Node $node, Scope $scope): array 'Property %s::$%s: Doctrine type "%s" does not have any registered descriptor.', $className, $propertyName, - $fieldMapping['type'] + $fieldMapping['type'], ))->identifier('doctrine.descriptorNotFound')->build(), ] : []; } @@ -128,7 +114,7 @@ public function processNode(Node $node, Scope $scope): array $propertyName, $backedEnumType->describe(VerbosityLevel::typeOnly()), $enumReflection->getDisplayName(), - $writableToDatabaseType->describe(VerbosityLevel::typeOnly()) + $writableToDatabaseType->describe(VerbosityLevel::typeOnly()), ))->identifier('doctrine.enumType')->build(); } } @@ -151,8 +137,8 @@ public function processNode(Node $node, Scope $scope): array $backedEnumType->describe(VerbosityLevel::typeOnly()), $enumReflection->getDisplayName(), $writableToDatabaseType->getIterableValueType()->describe(VerbosityLevel::typeOnly()), - $writableToDatabaseType->describe(VerbosityLevel::typeOnly()) - ) + $writableToDatabaseType->describe(VerbosityLevel::typeOnly()), + ), )->identifier('doctrine.enumType')->build(); } } @@ -160,11 +146,11 @@ public function processNode(Node $node, Scope $scope): array $writableToPropertyType = TypeCombinator::intersect(new ArrayType( $writableToPropertyType->getIterableKeyType(), - $enumType + $enumType, ), ...TypeUtils::getAccessoryTypes($writableToPropertyType)); $writableToDatabaseType = TypeCombinator::intersect(new ArrayType( $writableToDatabaseType->getIterableKeyType(), - $enumType + $enumType, ), ...TypeUtils::getAccessoryTypes($writableToDatabaseType)); } @@ -189,7 +175,7 @@ public function processNode(Node $node, Scope $scope): array } $phpDocType = $node->getPhpDocType(); - $nativeType = $node->getNativeType() !== null ? ParserNodeTypeToPHPStanType::resolve($node->getNativeType(), $scope->getClassReflection()) : new MixedType(); + $nativeType = $node->getNativeType() ?? new MixedType(); $propertyType = TypehintHelper::decideType($nativeType, $phpDocType); if (get_class($propertyType) === MixedType::class || $propertyType instanceof ErrorType || $propertyType instanceof NeverType) { @@ -211,7 +197,7 @@ public function processNode(Node $node, Scope $scope): array $className, $propertyName, $writableToPropertyType->describe(VerbosityLevel::getRecommendedLevelByType($propertyTransformedType, $writableToPropertyType)), - $propertyType->describe(VerbosityLevel::getRecommendedLevelByType($propertyTransformedType, $writableToPropertyType)) + $propertyType->describe(VerbosityLevel::getRecommendedLevelByType($propertyTransformedType, $writableToPropertyType)), ))->identifier('doctrine.columnType')->build(); } @@ -219,7 +205,7 @@ public function processNode(Node $node, Scope $scope): array !$writableToDatabaseType->isSuperTypeOf( $this->allowNullablePropertyForRequiredField || (in_array($propertyName, $identifiers, true) && !$nullable) ? TypeCombinator::removeNull($propertyType) - : $propertyType + : $propertyType, )->yes() ) { $errors[] = RuleErrorBuilder::message(sprintf( @@ -227,7 +213,7 @@ public function processNode(Node $node, Scope $scope): array $className, $propertyName, $propertyTransformedType->describe(VerbosityLevel::getRecommendedLevelByType($writableToDatabaseType, $propertyType)), - $writableToDatabaseType->describe(VerbosityLevel::getRecommendedLevelByType($writableToDatabaseType, $propertyType)) + $writableToDatabaseType->describe(VerbosityLevel::getRecommendedLevelByType($writableToDatabaseType, $propertyType)), ))->identifier('doctrine.columnType')->build(); } return $errors; diff --git a/src/Rules/Doctrine/ORM/EntityConstructorNotFinalRule.php b/src/Rules/Doctrine/ORM/EntityConstructorNotFinalRule.php index 5fd01213..24876b38 100644 --- a/src/Rules/Doctrine/ORM/EntityConstructorNotFinalRule.php +++ b/src/Rules/Doctrine/ORM/EntityConstructorNotFinalRule.php @@ -17,8 +17,7 @@ class EntityConstructorNotFinalRule implements Rule { - /** @var ObjectMetadataResolver */ - private $objectMetadataResolver; + private ObjectMetadataResolver $objectMetadataResolver; public function __construct(ObjectMetadataResolver $objectMetadataResolver) { @@ -57,7 +56,7 @@ public function processNode(Node $node, Scope $scope): array return [ RuleErrorBuilder::message(sprintf( 'Constructor of class %s is final which can cause problems with proxies.', - $classReflection->getDisplayName() + $classReflection->getDisplayName(), ))->identifier('doctrine.finalConstructor')->build(), ]; } diff --git a/src/Rules/Doctrine/ORM/EntityMappingExceptionRule.php b/src/Rules/Doctrine/ORM/EntityMappingExceptionRule.php index d74019ba..d0ce97f7 100644 --- a/src/Rules/Doctrine/ORM/EntityMappingExceptionRule.php +++ b/src/Rules/Doctrine/ORM/EntityMappingExceptionRule.php @@ -18,8 +18,7 @@ class EntityMappingExceptionRule implements Rule { - /** @var ObjectMetadataResolver */ - private $objectMetadataResolver; + private ObjectMetadataResolver $objectMetadataResolver; public function __construct( ObjectMetadataResolver $objectMetadataResolver diff --git a/src/Rules/Doctrine/ORM/EntityNotFinalRule.php b/src/Rules/Doctrine/ORM/EntityNotFinalRule.php index b4dfe4c7..9dd39ff3 100644 --- a/src/Rules/Doctrine/ORM/EntityNotFinalRule.php +++ b/src/Rules/Doctrine/ORM/EntityNotFinalRule.php @@ -17,8 +17,7 @@ class EntityNotFinalRule implements Rule { - /** @var ObjectMetadataResolver */ - private $objectMetadataResolver; + private ObjectMetadataResolver $objectMetadataResolver; public function __construct(ObjectMetadataResolver $objectMetadataResolver) { @@ -52,7 +51,7 @@ public function processNode(Node $node, Scope $scope): array return [ RuleErrorBuilder::message(sprintf( 'Entity class %s is final which can cause problems with proxies.', - $classReflection->getDisplayName() + $classReflection->getDisplayName(), ))->identifier('doctrine.finalEntity')->build(), ]; } diff --git a/src/Rules/Doctrine/ORM/EntityRelationRule.php b/src/Rules/Doctrine/ORM/EntityRelationRule.php index 69e0c2a5..84ce9120 100644 --- a/src/Rules/Doctrine/ORM/EntityRelationRule.php +++ b/src/Rules/Doctrine/ORM/EntityRelationRule.php @@ -13,7 +13,6 @@ use PHPStan\Type\MixedType; use PHPStan\Type\NeverType; use PHPStan\Type\ObjectType; -use PHPStan\Type\ParserNodeTypeToPHPStanType; use PHPStan\Type\TypeCombinator; use PHPStan\Type\TypehintHelper; use PHPStan\Type\VerbosityLevel; @@ -28,24 +27,17 @@ class EntityRelationRule implements Rule { - /** @var ObjectMetadataResolver */ - private $objectMetadataResolver; + private ObjectMetadataResolver $objectMetadataResolver; - /** @var bool */ - private $allowNullablePropertyForRequiredField; - - /** @var bool */ - private $bleedingEdge; + private bool $allowNullablePropertyForRequiredField; public function __construct( ObjectMetadataResolver $objectMetadataResolver, - bool $allowNullablePropertyForRequiredField, - bool $bleedingEdge + bool $allowNullablePropertyForRequiredField ) { $this->objectMetadataResolver = $objectMetadataResolver; $this->allowNullablePropertyForRequiredField = $allowNullablePropertyForRequiredField; - $this->bleedingEdge = $bleedingEdge; } public function getNodeType(): string @@ -55,10 +47,6 @@ public function getNodeType(): string public function processNode(Node $node, Scope $scope): array { - if (!$this->bleedingEdge && !$this->objectMetadataResolver->hasObjectManagerLoader()) { - return []; - } - $class = $scope->getClassReflection(); if ($class === null) { return []; @@ -102,12 +90,12 @@ public function processNode(Node $node, Scope $scope): array $toMany = true; $columnType = TypeCombinator::intersect( new ObjectType('Doctrine\Common\Collections\Collection'), - new IterableType(new MixedType(), new ObjectType($associationMapping['targetEntity'])) + new IterableType(new MixedType(), new ObjectType($associationMapping['targetEntity'])), ); } $phpDocType = $node->getPhpDocType(); - $nativeType = $node->getNativeType() !== null ? ParserNodeTypeToPHPStanType::resolve($node->getNativeType(), $scope->getClassReflection()) : new MixedType(); + $nativeType = $node->getNativeType() ?? new MixedType(); $propertyType = TypehintHelper::decideType($nativeType, $phpDocType); $errors = []; @@ -125,7 +113,7 @@ public function processNode(Node $node, Scope $scope): array ) { $propertyTypeToCheckAgainst = TypeCombinator::intersect( $collectionObjectType, - new IterableType(new MixedType(true), $propertyType->getIterableValueType()) + new IterableType(new MixedType(true), $propertyType->getIterableValueType()), ); } if (!$propertyTypeToCheckAgainst->isSuperTypeOf($columnType)->yes()) { @@ -134,14 +122,14 @@ public function processNode(Node $node, Scope $scope): array $className, $propertyName, $columnType->describe(VerbosityLevel::typeOnly()), - $propertyType->describe(VerbosityLevel::typeOnly()) + $propertyType->describe(VerbosityLevel::typeOnly()), ))->identifier('doctrine.associationType')->build(); } if ( !$columnType->isSuperTypeOf( $this->allowNullablePropertyForRequiredField ? TypeCombinator::removeNull($propertyType) - : $propertyType + : $propertyType, )->yes() ) { $errors[] = RuleErrorBuilder::message(sprintf( @@ -149,7 +137,7 @@ public function processNode(Node $node, Scope $scope): array $className, $propertyName, $propertyType->describe(VerbosityLevel::typeOnly()), - $columnType->describe(VerbosityLevel::typeOnly()) + $columnType->describe(VerbosityLevel::typeOnly()), ))->identifier('doctrine.associationType')->build(); } } diff --git a/src/Rules/Doctrine/ORM/PropertiesExtension.php b/src/Rules/Doctrine/ORM/PropertiesExtension.php index 4fdbf57d..9eab7dd7 100644 --- a/src/Rules/Doctrine/ORM/PropertiesExtension.php +++ b/src/Rules/Doctrine/ORM/PropertiesExtension.php @@ -12,8 +12,7 @@ class PropertiesExtension implements ReadWritePropertiesExtension { - /** @var ObjectMetadataResolver */ - private $objectMetadataResolver; + private ObjectMetadataResolver $objectMetadataResolver; public function __construct(ObjectMetadataResolver $objectMetadataResolver) { diff --git a/src/Rules/Doctrine/ORM/QueryBuilderDqlRule.php b/src/Rules/Doctrine/ORM/QueryBuilderDqlRule.php index 8596810d..69f9791a 100644 --- a/src/Rules/Doctrine/ORM/QueryBuilderDqlRule.php +++ b/src/Rules/Doctrine/ORM/QueryBuilderDqlRule.php @@ -13,7 +13,6 @@ use PHPStan\Type\Doctrine\DoctrineTypeUtils; use PHPStan\Type\Doctrine\ObjectMetadataResolver; use PHPStan\Type\ObjectType; -use PHPStan\Type\TypeUtils; use Throwable; use function array_values; use function count; @@ -26,11 +25,9 @@ class QueryBuilderDqlRule implements Rule { - /** @var ObjectMetadataResolver */ - private $objectMetadataResolver; + private ObjectMetadataResolver $objectMetadataResolver; - /** @var bool */ - private $reportDynamicQueryBuilders; + private bool $reportDynamicQueryBuilders; public function __construct( ObjectMetadataResolver $objectMetadataResolver, @@ -83,7 +80,7 @@ public function processNode(Node $node, Scope $scope): array ]; } - $dqls = TypeUtils::getConstantStrings($dqlType); + $dqls = $dqlType->getConstantStrings(); if (count($dqls) === 0) { if ($this->reportDynamicQueryBuilders) { return [ diff --git a/src/Rules/Doctrine/ORM/RepositoryMethodCallRule.php b/src/Rules/Doctrine/ORM/RepositoryMethodCallRule.php index 9061d6c4..9f5231fe 100644 --- a/src/Rules/Doctrine/ORM/RepositoryMethodCallRule.php +++ b/src/Rules/Doctrine/ORM/RepositoryMethodCallRule.php @@ -19,8 +19,7 @@ class RepositoryMethodCallRule implements Rule { - /** @var ObjectMetadataResolver */ - private $objectMetadataResolver; + private ObjectMetadataResolver $objectMetadataResolver; public function __construct(ObjectMetadataResolver $objectMetadataResolver) { @@ -82,7 +81,7 @@ public function processNode(Node $node, Scope $scope): array $calledOnType->describe(VerbosityLevel::typeOnly()), $methodName, $entityClassNames[0], - $fieldName->getValue() + $fieldName->getValue(), ))->identifier(sprintf('doctrine.%sArgument', $methodName))->build(); } } diff --git a/src/Rules/Gedmo/PropertiesExtension.php b/src/Rules/Gedmo/PropertiesExtension.php index d43b4308..e82f3bc5 100644 --- a/src/Rules/Gedmo/PropertiesExtension.php +++ b/src/Rules/Gedmo/PropertiesExtension.php @@ -41,11 +41,9 @@ class PropertiesExtension implements ReadWritePropertiesExtension Gedmo\Language::class, ]; - /** @var AnnotationReader|null */ - private $annotationReader; + private ?AnnotationReader $annotationReader = null; - /** @var ObjectMetadataResolver */ - private $objectMetadataResolver; + private ObjectMetadataResolver $objectMetadataResolver; public function __construct(ObjectMetadataResolver $objectMetadataResolver) { diff --git a/src/Stubs/Doctrine/StubFilesExtensionLoader.php b/src/Stubs/Doctrine/StubFilesExtensionLoader.php index 390e35a5..fc4b48aa 100644 --- a/src/Stubs/Doctrine/StubFilesExtensionLoader.php +++ b/src/Stubs/Doctrine/StubFilesExtensionLoader.php @@ -14,8 +14,7 @@ class StubFilesExtensionLoader implements StubFilesExtension { - /** @var Reflector */ - private $reflector; + private Reflector $reflector; public function __construct( Reflector $reflector diff --git a/src/Type/Doctrine/ArgumentsProcessor.php b/src/Type/Doctrine/ArgumentsProcessor.php index 4ace7f16..2cd94fd7 100644 --- a/src/Type/Doctrine/ArgumentsProcessor.php +++ b/src/Type/Doctrine/ArgumentsProcessor.php @@ -13,8 +13,7 @@ class ArgumentsProcessor { - /** @var ObjectMetadataResolver */ - private $objectMetadataResolver; + private ObjectMetadataResolver $objectMetadataResolver; public function __construct(ObjectMetadataResolver $objectMetadataResolver) { @@ -59,7 +58,7 @@ public function processArgs( continue; } - if ($value->isClassStringType()->yes() && count($value->getClassStringObjectType()->getObjectClassNames()) === 1) { + if ($value->isClassString()->yes() && count($value->getClassStringObjectType()->getObjectClassNames()) === 1) { /** @var class-string $className */ $className = $value->getClassStringObjectType()->getObjectClassNames()[0]; if ($this->objectMetadataResolver->isTransient($className)) { diff --git a/src/Type/Doctrine/Collection/IsEmptyTypeSpecifyingExtension.php b/src/Type/Doctrine/Collection/IsEmptyTypeSpecifyingExtension.php index 0d440940..9a177304 100644 --- a/src/Type/Doctrine/Collection/IsEmptyTypeSpecifyingExtension.php +++ b/src/Type/Doctrine/Collection/IsEmptyTypeSpecifyingExtension.php @@ -19,11 +19,10 @@ final class IsEmptyTypeSpecifyingExtension implements MethodTypeSpecifyingExtens private const FIRST_METHOD_NAME = 'first'; private const LAST_METHOD_NAME = 'last'; - /** @var TypeSpecifier */ - private $typeSpecifier; + private TypeSpecifier $typeSpecifier; /** @var class-string */ - private $collectionClass; + private string $collectionClass; /** * @param class-string $collectionClass @@ -44,11 +43,8 @@ public function isMethodSupported( TypeSpecifierContext $context ): bool { - return ( - $methodReflection->getDeclaringClass()->getName() === $this->collectionClass - || $methodReflection->getDeclaringClass()->isSubclassOf($this->collectionClass) - ) - && $methodReflection->getName() === self::IS_EMPTY_METHOD_NAME; + return $methodReflection->getDeclaringClass()->is($this->collectionClass) + && $methodReflection->getName() === self::IS_EMPTY_METHOD_NAME; } public function specifyTypes( @@ -61,13 +57,15 @@ public function specifyTypes( $first = $this->typeSpecifier->create( new MethodCall($node->var, self::FIRST_METHOD_NAME), new ConstantBooleanType(false), - $context + $context, + $scope, ); $last = $this->typeSpecifier->create( new MethodCall($node->var, self::LAST_METHOD_NAME), new ConstantBooleanType(false), - $context + $context, + $scope, ); return $first->unionWith($last); diff --git a/src/Type/Doctrine/CreateQueryDynamicReturnTypeExtension.php b/src/Type/Doctrine/CreateQueryDynamicReturnTypeExtension.php index 1cf5d50a..b78f8467 100644 --- a/src/Type/Doctrine/CreateQueryDynamicReturnTypeExtension.php +++ b/src/Type/Doctrine/CreateQueryDynamicReturnTypeExtension.php @@ -33,17 +33,13 @@ final class CreateQueryDynamicReturnTypeExtension implements DynamicMethodReturnTypeExtension { - /** @var ObjectMetadataResolver */ - private $objectMetadataResolver; + private ObjectMetadataResolver $objectMetadataResolver; - /** @var DescriptorRegistry */ - private $descriptorRegistry; + private DescriptorRegistry $descriptorRegistry; - /** @var PhpVersion */ - private $phpVersion; + private PhpVersion $phpVersion; - /** @var DriverDetector */ - private $driverDetector; + private DriverDetector $driverDetector; public function __construct( ObjectMetadataResolver $objectMetadataResolver, @@ -80,7 +76,7 @@ public function getTypeFromMethodCall( if (!isset($args[$queryStringArgIndex])) { return new GenericObjectType( Query::class, - [new MixedType(), new MixedType()] + [new MixedType(), new MixedType()], ); } @@ -113,7 +109,7 @@ public function getTypeFromMethodCall( } return new GenericObjectType( Query::class, - [new MixedType(), new MixedType()] + [new MixedType(), new MixedType()], ); }); } diff --git a/src/Type/Doctrine/DBAL/QueryBuilder/QueryBuilderExecuteMethodExtension.php b/src/Type/Doctrine/DBAL/QueryBuilder/QueryBuilderExecuteMethodExtension.php index 31170cfc..0a644f3a 100644 --- a/src/Type/Doctrine/DBAL/QueryBuilder/QueryBuilderExecuteMethodExtension.php +++ b/src/Type/Doctrine/DBAL/QueryBuilder/QueryBuilderExecuteMethodExtension.php @@ -19,8 +19,7 @@ class QueryBuilderExecuteMethodExtension implements DynamicMethodReturnTypeExtension { - /** @var ReflectionProvider */ - private $reflectionProvider; + private ReflectionProvider $reflectionProvider; public function __construct(ReflectionProvider $reflectionProvider) { @@ -39,7 +38,11 @@ public function isMethodSupported(MethodReflection $methodReflection): bool public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): Type { - $defaultReturnType = ParametersAcceptorSelector::selectSingle($methodReflection->getVariants())->getReturnType(); + $defaultReturnType = ParametersAcceptorSelector::selectFromArgs( + $scope, + $methodCall->getArgs(), + $methodReflection->getVariants(), + )->getReturnType(); $queryBuilderType = new ObjectType(QueryBuilder::class); $var = $methodCall->var; diff --git a/src/Type/Doctrine/DBAL/RowCountMethodDynamicReturnTypeExtension.php b/src/Type/Doctrine/DBAL/RowCountMethodDynamicReturnTypeExtension.php index c754a41b..ac6f38b4 100644 --- a/src/Type/Doctrine/DBAL/RowCountMethodDynamicReturnTypeExtension.php +++ b/src/Type/Doctrine/DBAL/RowCountMethodDynamicReturnTypeExtension.php @@ -8,7 +8,6 @@ use PHPStan\Analyser\Scope; use PHPStan\Doctrine\Driver\DriverDetector; use PHPStan\Reflection\MethodReflection; -use PHPStan\Reflection\ParametersAcceptorSelector; use PHPStan\Reflection\ReflectionProvider; use PHPStan\Type\Doctrine\ObjectMetadataResolver; use PHPStan\Type\DynamicMethodReturnTypeExtension; @@ -17,18 +16,18 @@ class RowCountMethodDynamicReturnTypeExtension implements DynamicMethodReturnTypeExtension { - /** @var string */ - private $class; + /** @var class-string */ + private string $class; - /** @var ObjectMetadataResolver */ - private $objectMetadataResolver; + private ObjectMetadataResolver $objectMetadataResolver; - /** @var DriverDetector */ - private $driverDetector; + private DriverDetector $driverDetector; - /** @var ReflectionProvider */ - private $reflectionProvider; + private ReflectionProvider $reflectionProvider; + /** + * @param class-string $class + */ public function __construct( string $class, ObjectMetadataResolver $objectMetadataResolver, @@ -77,7 +76,7 @@ public function getTypeFromMethodCall(MethodReflection $methodReflection, Method } $rowCountMethod = $resultReflection->getNativeMethod('rowCount'); - $variant = ParametersAcceptorSelector::selectSingle($rowCountMethod->getVariants()); + $variant = $rowCountMethod->getOnlyVariant(); return $variant->getReturnType(); } diff --git a/src/Type/Doctrine/DefaultDescriptorRegistry.php b/src/Type/Doctrine/DefaultDescriptorRegistry.php index 83647e3b..74ea184d 100644 --- a/src/Type/Doctrine/DefaultDescriptorRegistry.php +++ b/src/Type/Doctrine/DefaultDescriptorRegistry.php @@ -9,7 +9,7 @@ class DefaultDescriptorRegistry implements DescriptorRegistry { /** @var array, DoctrineTypeDescriptor> */ - private $descriptors = []; + private array $descriptors = []; /** * @param DoctrineTypeDescriptor[] $descriptors diff --git a/src/Type/Doctrine/DescriptorRegistryFactory.php b/src/Type/Doctrine/DescriptorRegistryFactory.php index 3e7dd190..2dbf70aa 100644 --- a/src/Type/Doctrine/DescriptorRegistryFactory.php +++ b/src/Type/Doctrine/DescriptorRegistryFactory.php @@ -9,8 +9,7 @@ class DescriptorRegistryFactory public const TYPE_DESCRIPTOR_TAG = 'phpstan.doctrine.typeDescriptor'; - /** @var Container */ - private $container; + private Container $container; public function __construct(Container $container) { diff --git a/src/Type/Doctrine/Descriptors/BooleanType.php b/src/Type/Doctrine/Descriptors/BooleanType.php index b9e59574..54e7f662 100644 --- a/src/Type/Doctrine/Descriptors/BooleanType.php +++ b/src/Type/Doctrine/Descriptors/BooleanType.php @@ -12,8 +12,7 @@ class BooleanType implements DoctrineTypeDescriptor, DoctrineTypeDriverAwareDescriptor { - /** @var DriverDetector */ - private $driverDetector; + private DriverDetector $driverDetector; public function __construct(DriverDetector $driverDetector) { @@ -40,7 +39,7 @@ public function getDatabaseInternalType(): Type return TypeCombinator::union( new ConstantIntegerType(0), new ConstantIntegerType(1), - new \PHPStan\Type\BooleanType() + new \PHPStan\Type\BooleanType(), ); } @@ -60,7 +59,7 @@ public function getDatabaseInternalTypeForDriver(Connection $connection): Type ], true)) { return TypeCombinator::union( new ConstantIntegerType(0), - new ConstantIntegerType(1) + new ConstantIntegerType(1), ); } diff --git a/src/Type/Doctrine/Descriptors/DecimalType.php b/src/Type/Doctrine/Descriptors/DecimalType.php index 066c0d93..0f0e16e3 100644 --- a/src/Type/Doctrine/Descriptors/DecimalType.php +++ b/src/Type/Doctrine/Descriptors/DecimalType.php @@ -14,8 +14,7 @@ class DecimalType implements DoctrineTypeDescriptor, DoctrineTypeDriverAwareDescriptor { - /** @var DriverDetector */ - private $driverDetector; + private DriverDetector $driverDetector; public function __construct(DriverDetector $driverDetector) { diff --git a/src/Type/Doctrine/Descriptors/FloatType.php b/src/Type/Doctrine/Descriptors/FloatType.php index 92accffa..7f472ceb 100644 --- a/src/Type/Doctrine/Descriptors/FloatType.php +++ b/src/Type/Doctrine/Descriptors/FloatType.php @@ -12,8 +12,7 @@ class FloatType implements DoctrineTypeDescriptor, DoctrineTypeDriverAwareDescriptor { - /** @var DriverDetector */ - private $driverDetector; + private DriverDetector $driverDetector; public function __construct(DriverDetector $driverDetector) { @@ -39,7 +38,7 @@ public function getDatabaseInternalType(): Type { return TypeCombinator::union( new \PHPStan\Type\FloatType(), - (new \PHPStan\Type\FloatType())->toString() + (new \PHPStan\Type\FloatType())->toString(), ); } diff --git a/src/Type/Doctrine/Descriptors/Ramsey/UuidTypeDescriptor.php b/src/Type/Doctrine/Descriptors/Ramsey/UuidTypeDescriptor.php index 78501f2c..549b14c4 100644 --- a/src/Type/Doctrine/Descriptors/Ramsey/UuidTypeDescriptor.php +++ b/src/Type/Doctrine/Descriptors/Ramsey/UuidTypeDescriptor.php @@ -23,8 +23,7 @@ class UuidTypeDescriptor implements DoctrineTypeDescriptor FakeTestingUuidType::class, ]; - /** @var string */ - private $uuidTypeName; + private string $uuidTypeName; public function __construct( string $uuidTypeName @@ -33,7 +32,7 @@ public function __construct( if (!in_array($uuidTypeName, self::SUPPORTED_UUID_TYPES, true)) { throw new ShouldNotHappenException(sprintf( 'Unexpected UUID column type "%s" provided', - $uuidTypeName + $uuidTypeName, )); } @@ -55,7 +54,7 @@ public function getWritableToDatabaseType(): Type { return TypeCombinator::union( new StringType(), - new ObjectType(UuidInterface::class) + new ObjectType(UuidInterface::class), ); } diff --git a/src/Type/Doctrine/Descriptors/ReflectionDescriptor.php b/src/Type/Doctrine/Descriptors/ReflectionDescriptor.php index 7d7cb778..f4b5dba0 100644 --- a/src/Type/Doctrine/Descriptors/ReflectionDescriptor.php +++ b/src/Type/Doctrine/Descriptors/ReflectionDescriptor.php @@ -21,11 +21,9 @@ class ReflectionDescriptor implements DoctrineTypeDescriptor, DoctrineTypeDriver /** @var class-string */ private $type; - /** @var ReflectionProvider */ - private $reflectionProvider; + private ReflectionProvider $reflectionProvider; - /** @var Container */ - private $container; + private Container $container; /** * @param class-string $type diff --git a/src/Type/Doctrine/Descriptors/SimpleArrayType.php b/src/Type/Doctrine/Descriptors/SimpleArrayType.php index 8044caca..2154eb91 100644 --- a/src/Type/Doctrine/Descriptors/SimpleArrayType.php +++ b/src/Type/Doctrine/Descriptors/SimpleArrayType.php @@ -8,6 +8,7 @@ use PHPStan\Type\MixedType; use PHPStan\Type\StringType; use PHPStan\Type\Type; +use PHPStan\Type\TypeCombinator; class SimpleArrayType implements DoctrineTypeDescriptor { @@ -19,7 +20,7 @@ public function getType(): string public function getWritableToPropertyType(): Type { - return AccessoryArrayListType::intersectWith(new ArrayType(new IntegerType(), new StringType())); + return TypeCombinator::intersect(new ArrayType(new IntegerType(), new StringType()), new AccessoryArrayListType()); } public function getWritableToDatabaseType(): Type diff --git a/src/Type/Doctrine/EntityManagerInterfaceThrowTypeExtension.php b/src/Type/Doctrine/EntityManagerInterfaceThrowTypeExtension.php index 0070af9f..be3407c3 100644 --- a/src/Type/Doctrine/EntityManagerInterfaceThrowTypeExtension.php +++ b/src/Type/Doctrine/EntityManagerInterfaceThrowTypeExtension.php @@ -37,9 +37,7 @@ public function getThrowTypeFromMethodCall(MethodReflection $methodReflection, M if ((new ObjectType(EntityManagerInterface::class))->isSuperTypeOf($type)->yes()) { return TypeCombinator::union( - ...array_map(static function ($class): Type { - return new ObjectType($class); - }, self::SUPPORTED_METHOD[$methodReflection->getName()]) + ...array_map(static fn ($class): Type => new ObjectType($class), self::SUPPORTED_METHOD[$methodReflection->getName()]), ); } diff --git a/src/Type/Doctrine/GetRepositoryDynamicReturnTypeExtension.php b/src/Type/Doctrine/GetRepositoryDynamicReturnTypeExtension.php index fd90fdd5..07d40ffa 100644 --- a/src/Type/Doctrine/GetRepositoryDynamicReturnTypeExtension.php +++ b/src/Type/Doctrine/GetRepositoryDynamicReturnTypeExtension.php @@ -27,24 +27,22 @@ class GetRepositoryDynamicReturnTypeExtension implements DynamicMethodReturnTypeExtension { - /** @var ReflectionProvider */ - private $reflectionProvider; + private ReflectionProvider $reflectionProvider; - /** @var string|null */ - private $repositoryClass; + private ?string $repositoryClass = null; - /** @var string|null */ - private $ormRepositoryClass; + private ?string $ormRepositoryClass = null; - /** @var string|null */ - private $odmRepositoryClass; + private ?string $odmRepositoryClass = null; - /** @var string */ - private $managerClass; + /** @var class-string */ + private string $managerClass; - /** @var ObjectMetadataResolver */ - private $metadataResolver; + private ObjectMetadataResolver $metadataResolver; + /** + * @param class-string $managerClass + */ public function __construct( ReflectionProvider $reflectionProvider, ?string $repositoryClass, @@ -87,11 +85,11 @@ public function getTypeFromMethodCall( if (count($methodCall->getArgs()) === 0) { return new GenericObjectType( $defaultRepositoryClass, - [new ObjectWithoutClassType()] + [new ObjectWithoutClassType()], ); } $argType = $scope->getType($methodCall->getArgs()[0]->value); - if (!$argType->isClassStringType()->yes()) { + if (!$argType->isClassString()->yes()) { return $this->getDefaultReturnType($scope, $methodCall->getArgs(), $methodReflection, $defaultRepositoryClass); } @@ -101,7 +99,7 @@ public function getTypeFromMethodCall( if (count($objectNames) === 0) { return new GenericObjectType( $defaultRepositoryClass, - [$classType] + [$classType], ); } @@ -127,13 +125,13 @@ private function getDefaultReturnType(Scope $scope, array $args, MethodReflectio $defaultType = ParametersAcceptorSelector::selectFromArgs( $scope, $args, - $methodReflection->getVariants() + $methodReflection->getVariants(), )->getReturnType(); $entity = $defaultType->getTemplateType(ObjectRepository::class, 'TEntityClass'); if (!$entity instanceof ErrorType) { return new GenericObjectType( $defaultRepositoryClass, - [$entity] + [$entity], ); } diff --git a/src/Type/Doctrine/HydrationModeReturnTypeResolver.php b/src/Type/Doctrine/HydrationModeReturnTypeResolver.php index 2f1c8e36..e978ae2f 100644 --- a/src/Type/Doctrine/HydrationModeReturnTypeResolver.php +++ b/src/Type/Doctrine/HydrationModeReturnTypeResolver.php @@ -73,18 +73,18 @@ public function getMethodReturnTypeForHydrationMode( case 'toIterable': return new IterableType( $queryKeyType->isNull()->yes() ? new IntegerType() : $queryKeyType, - $queryResultType + $queryResultType, ); default: if ($queryKeyType->isNull()->yes()) { - return AccessoryArrayListType::intersectWith(new ArrayType( + return TypeCombinator::intersect(new ArrayType( new IntegerType(), - $queryResultType - )); + $queryResultType, + ), new AccessoryArrayListType()); } return new ArrayType( $queryKeyType, - $queryResultType + $queryResultType, ); } } diff --git a/src/Type/Doctrine/ObjectMetadataResolver.php b/src/Type/Doctrine/ObjectMetadataResolver.php index 68024891..054e9a57 100644 --- a/src/Type/Doctrine/ObjectMetadataResolver.php +++ b/src/Type/Doctrine/ObjectMetadataResolver.php @@ -17,17 +17,14 @@ final class ObjectMetadataResolver { - /** @var string|null */ - private $objectManagerLoader; + private ?string $objectManagerLoader = null; /** @var ObjectManager|false|null */ private $objectManager; - /** @var ClassMetadataFactory|null */ - private $metadataFactory; + private ?ClassMetadataFactory $metadataFactory = null; - /** @var string */ - private $tmpDir; + private string $tmpDir; public function __construct( ?string $objectManagerLoader, @@ -152,14 +149,14 @@ private function loadObjectManager(string $objectManagerLoader): ?ObjectManager if (!is_file($objectManagerLoader)) { throw new ShouldNotHappenException(sprintf( 'Object manager could not be loaded: file "%s" does not exist', - $objectManagerLoader + $objectManagerLoader, )); } if (!is_readable($objectManagerLoader)) { throw new ShouldNotHappenException(sprintf( 'Object manager could not be loaded: file "%s" is not readable', - $objectManagerLoader + $objectManagerLoader, )); } diff --git a/src/Type/Doctrine/Query/QueryResultDynamicReturnTypeExtension.php b/src/Type/Doctrine/Query/QueryResultDynamicReturnTypeExtension.php index 091e3716..22ed0b5a 100644 --- a/src/Type/Doctrine/Query/QueryResultDynamicReturnTypeExtension.php +++ b/src/Type/Doctrine/Query/QueryResultDynamicReturnTypeExtension.php @@ -27,11 +27,9 @@ final class QueryResultDynamicReturnTypeExtension implements DynamicMethodReturn 'getSingleResult' => 0, ]; - /** @var ObjectMetadataResolver */ - private $objectMetadataResolver; + private ObjectMetadataResolver $objectMetadataResolver; - /** @var HydrationModeReturnTypeResolver */ - private $hydrationModeReturnTypeResolver; + private HydrationModeReturnTypeResolver $hydrationModeReturnTypeResolver; public function __construct( ObjectMetadataResolver $objectMetadataResolver, @@ -70,8 +68,10 @@ public function getTypeFromMethodCall( if (isset($args[$argIndex])) { $hydrationMode = $scope->getType($args[$argIndex]->value); } else { - $parametersAcceptor = ParametersAcceptorSelector::selectSingle( - $methodReflection->getVariants() + $parametersAcceptor = ParametersAcceptorSelector::selectFromArgs( + $scope, + $methodCall->getArgs(), + $methodReflection->getVariants(), ); $parameter = $parametersAcceptor->getParameters()[$argIndex]; $hydrationMode = $parameter->getDefaultValue() ?? new NullType(); @@ -84,7 +84,7 @@ public function getTypeFromMethodCall( $hydrationMode, $queryType->getTemplateType(AbstractQuery::class, 'TKey'), $queryType->getTemplateType(AbstractQuery::class, 'TResult'), - $this->objectMetadataResolver->getObjectManager() + $this->objectMetadataResolver->getObjectManager(), ); } diff --git a/src/Type/Doctrine/Query/QueryResultTypeBuilder.php b/src/Type/Doctrine/Query/QueryResultTypeBuilder.php index 30941cb3..2f6fae11 100644 --- a/src/Type/Doctrine/Query/QueryResultTypeBuilder.php +++ b/src/Type/Doctrine/Query/QueryResultTypeBuilder.php @@ -21,15 +21,13 @@ final class QueryResultTypeBuilder { - /** @var bool */ - private $selectQuery = false; + private bool $selectQuery = false; /** * Whether the result is an array shape or a single entity or NEW object * - * @var bool */ - private $isShape = false; + private bool $isShape = false; /** * Map from selected entity aliases to entity types @@ -38,7 +36,7 @@ final class QueryResultTypeBuilder * * @var array */ - private $entities = []; + private array $entities = []; /** * Map from selected entity alias to result alias @@ -47,24 +45,23 @@ final class QueryResultTypeBuilder * * @var array */ - private $entityResultAliases = []; + private array $entityResultAliases = []; /** * Map from selected scalar result alias to scalar type * * @var array */ - private $scalars = []; + private array $scalars = []; /** * Map from selected NEW objcet result alias to NEW object type * * @var array */ - private $newObjects = []; + private array $newObjects = []; - /** @var Type */ - private $indexedBy; + private Type $indexedBy; public function __construct() { diff --git a/src/Type/Doctrine/Query/QueryResultTypeWalker.php b/src/Type/Doctrine/Query/QueryResultTypeWalker.php index d6a898dc..128ae674 100644 --- a/src/Type/Doctrine/Query/QueryResultTypeWalker.php +++ b/src/Type/Doctrine/Query/QueryResultTypeWalker.php @@ -86,53 +86,45 @@ class QueryResultTypeWalker extends SqlWalker /** * Counter for generating unique scalar result. * - * @var int */ - private $scalarResultCounter = 1; + private int $scalarResultCounter = 1; /** * Counter for generating indexes. * - * @var int */ - private $newObjectCounter = 0; + private int $newObjectCounter = 0; /** @var Query */ - private $query; + private Query $query; - /** @var EntityManagerInterface */ - private $em; + private EntityManagerInterface $em; - /** @var PhpVersion */ - private $phpVersion; + private PhpVersion $phpVersion; /** @var DriverDetector::*|null */ private $driverType; /** @var array */ - private $driverOptions; + private array $driverOptions; /** * Map of all components/classes that appear in the DQL query. * * @var array $queryComponents */ - private $queryComponents; + private array $queryComponents; /** @var array */ - private $nullableQueryComponents; + private array $nullableQueryComponents; - /** @var QueryResultTypeBuilder */ - private $typeBuilder; + private QueryResultTypeBuilder $typeBuilder; - /** @var DescriptorRegistry */ - private $descriptorRegistry; + private DescriptorRegistry $descriptorRegistry; - /** @var bool */ - private $hasAggregateFunction; + private bool $hasAggregateFunction; - /** @var bool */ - private $hasGroupByClause; + private bool $hasGroupByClause; /** @@ -184,7 +176,7 @@ public function __construct($query, $parserResult, array $queryComponents) 'Expected the query hint %s to contain a %s, but got a %s', self::HINT_TYPE_MAPPING, QueryResultTypeBuilder::class, - is_object($typeBuilder) ? get_class($typeBuilder) : gettype($typeBuilder) + is_object($typeBuilder) ? get_class($typeBuilder) : gettype($typeBuilder), )); } @@ -197,7 +189,7 @@ public function __construct($query, $parserResult, array $queryComponents) 'Expected the query hint %s to contain a %s, but got a %s', self::HINT_DESCRIPTOR_REGISTRY, DescriptorRegistry::class, - is_object($descriptorRegistry) ? get_class($descriptorRegistry) : gettype($descriptorRegistry) + is_object($descriptorRegistry) ? get_class($descriptorRegistry) : gettype($descriptorRegistry), )); } @@ -210,7 +202,7 @@ public function __construct($query, $parserResult, array $queryComponents) 'Expected the query hint %s to contain a %s, but got a %s', self::HINT_PHP_VERSION, PhpVersion::class, - is_object($phpVersion) ? get_class($phpVersion) : gettype($phpVersion) + is_object($phpVersion) ? get_class($phpVersion) : gettype($phpVersion), )); } @@ -223,7 +215,7 @@ public function __construct($query, $parserResult, array $queryComponents) 'Expected the query hint %s to contain a %s, but got a %s', self::HINT_DRIVER_DETECTOR, DriverDetector::class, - is_object($driverDetector) ? get_class($driverDetector) : gettype($driverDetector) + is_object($driverDetector) ? get_class($driverDetector) : gettype($driverDetector), )); } $connection = $this->em->getConnection(); @@ -619,7 +611,7 @@ public function walkFunction($function): string if ($this->driverType === DriverDetector::MYSQLI || $this->driverType === DriverDetector::PDO_MYSQL || $this->driverType === DriverDetector::SQLITE3 || $this->driverType === DriverDetector::PDO_SQLITE) { $type = new FloatType(); - $cannotBeNegative = $exprType->isSmallerThan(new ConstantIntegerType(0))->no(); + $cannotBeNegative = $exprType->isSmallerThan(new ConstantIntegerType(0), $this->phpVersion)->no(); $canBeNegative = !$cannotBeNegative; if ($canBeNegative) { $type = TypeCombinator::addNull($type); @@ -810,7 +802,7 @@ private function inferSumFunction(AST\Functions\SumFunction $function): Type if ($exprTypeNoNull->isInteger()->yes()) { return TypeCombinator::union( $this->createInteger($nullable), - $this->createNumericString($nullable, true, true) + $this->createNumericString($nullable, true, true), ); } @@ -830,7 +822,7 @@ private function createFloatOrInt(bool $nullable): Type { $union = TypeCombinator::union( new FloatType(), - new IntegerType() + new IntegerType(), ); return $nullable ? TypeCombinator::addNull($union) : $union; } @@ -930,14 +922,14 @@ private function generalizeConstantType(Type $type, bool $makeNullable): Type $result = $this->createNumericString( $containsNull, $typeNoNull->isLowercaseString()->yes(), - $typeNoNull->isUppercaseString()->yes() + $typeNoNull->isUppercaseString()->yes(), ); } elseif ($typeNoNull->isString()->yes()) { $result = $this->createString( $containsNull, $typeNoNull->isLowercaseString()->yes(), - $typeNoNull->isUppercaseString()->yes() + $typeNoNull->isUppercaseString()->yes(), ); } else { @@ -1031,7 +1023,7 @@ public function walkCoalesceExpression($coalesceExpression): string if ($this->driverType === DriverDetector::MYSQLI || $this->driverType === DriverDetector::PDO_MYSQL) { return $this->marshalType( - $this->inferCoalesceForMySql($rawTypes, $generalizedUnion) + $this->inferCoalesceForMySql($rawTypes, $generalizedUnion), ); } @@ -1113,13 +1105,13 @@ public function walkGeneralCaseExpression(AST\GeneralCaseExpression $generalCase } $types[] = $this->unmarshalType( - $thenScalarExpression->dispatch($this) + $thenScalarExpression->dispatch($this), ); } if ($elseScalarExpression instanceof AST\Node) { $types[] = $this->unmarshalType( - $elseScalarExpression->dispatch($this) + $elseScalarExpression->dispatch($this), ); } @@ -1150,13 +1142,13 @@ public function walkSimpleCaseExpression($simpleCaseExpression): string } $types[] = $this->unmarshalType( - $thenScalarExpression->dispatch($this) + $thenScalarExpression->dispatch($this), ); } if ($elseScalarExpression instanceof AST\Node) { $types[] = $this->unmarshalType( - $elseScalarExpression->dispatch($this) + $elseScalarExpression->dispatch($this), ); } @@ -1247,7 +1239,7 @@ public function walkSelectExpression($selectExpression): string $dbalTypeName = DbalType::getTypeRegistry()->lookupName($expr->getReturnType()); $type = TypeCombinator::intersect( // e.g. count is typed as int, but we infer int<0, max> $type, - $this->resolveDoctrineType($dbalTypeName, null, TypeCombinator::containsNull($type)) + $this->resolveDoctrineType($dbalTypeName, null, TypeCombinator::containsNull($type)), ); if ($this->hasAggregateWithoutGroupBy() && !$expr instanceof AST\Functions\CountFunction) { @@ -1711,7 +1703,7 @@ public function walkSimpleArithmeticExpression($simpleArithmeticExpr): string } $types[] = $this->castStringLiteralForNumericExpression( - $this->unmarshalType($this->walkArithmeticPrimary($term)) + $this->unmarshalType($this->walkArithmeticPrimary($term)), ); } @@ -1738,7 +1730,7 @@ public function walkArithmeticTerm($term): string } $types[] = $this->castStringLiteralForNumericExpression( - $this->unmarshalType($this->walkArithmeticPrimary($factor)) + $this->unmarshalType($this->walkArithmeticPrimary($factor)), ); } @@ -1816,7 +1808,7 @@ private function inferPlusMinusTimesType(array $termTypes): Type return $this->createNumericString( $nullable, $unionWithoutNull->toString()->isLowercaseString()->yes(), - $unionWithoutNull->toString()->isUppercaseString()->yes() + $unionWithoutNull->toString()->isUppercaseString()->yes(), ); } @@ -1900,7 +1892,7 @@ private function inferDivisionType(array $termTypes): Type return $this->createNumericString( $nullable, $unionWithoutNull->toString()->isLowercaseString()->yes(), - $unionWithoutNull->toString()->isUppercaseString()->yes() + $unionWithoutNull->toString()->isUppercaseString()->yes(), ); } @@ -1935,7 +1927,7 @@ public function walkArithmeticFactor($factor): string } elseif ($type instanceof IntegerRangeType && $factor->sign === false) { $type = IntegerRangeType::fromInterval( $type->getMax() === null ? null : $type->getMax() * -1, - $type->getMin() === null ? null : $type->getMin() * -1 + $type->getMin() === null ? null : $type->getMin() * -1, ); } elseif ($type instanceof ConstantFloatType && $factor->sign === false) { @@ -2040,7 +2032,7 @@ private function resolveDoctrineType(string $typeName, ?string $enumType = null, } else { $type = TypeCombinator::intersect(new ArrayType( $type->getIterableKeyType(), - new ObjectType($enumType) + new ObjectType($enumType), ), ...TypeUtils::getAccessoryTypes($type)); } } @@ -2076,9 +2068,7 @@ private function resolveDatabaseInternalType(string $typeName, ?string $enumType } if ($enumType !== null) { - $enumTypes = array_map(static function ($enumType) { - return ConstantTypeHelper::getTypeFromValue($enumType->value); - }, $enumType::cases()); + $enumTypes = array_map(static fn ($enumType) => ConstantTypeHelper::getTypeFromValue($enumType->value), $enumType::cases()); $enumType = TypeCombinator::union(...$enumTypes); $enumType = TypeCombinator::union($enumType, $enumType->toString()); $type = TypeCombinator::intersect($enumType, $type); diff --git a/src/Type/Doctrine/Query/QueryType.php b/src/Type/Doctrine/Query/QueryType.php index b0cb7968..53842dd2 100644 --- a/src/Type/Doctrine/Query/QueryType.php +++ b/src/Type/Doctrine/Query/QueryType.php @@ -2,8 +2,8 @@ namespace PHPStan\Type\Doctrine\Query; -use PHPStan\TrinaryLogic; use PHPStan\Type\Generic\GenericObjectType; +use PHPStan\Type\IsSuperTypeOfResult; use PHPStan\Type\MixedType; use PHPStan\Type\Type; @@ -11,14 +11,11 @@ class QueryType extends GenericObjectType { - /** @var Type */ - private $indexType; + private Type $indexType; - /** @var Type */ - private $resultType; + private Type $resultType; - /** @var string */ - private $dql; + private string $dql; public function __construct(string $dql, ?Type $indexType = null, ?Type $resultType = null, ?Type $subtractedType = null) { @@ -47,10 +44,10 @@ public function changeSubtractedType(?Type $subtractedType): Type return new self('Doctrine\ORM\Query', $this->indexType, $this->resultType, $subtractedType); } - public function isSuperTypeOf(Type $type): TrinaryLogic + public function isSuperTypeOf(Type $type): IsSuperTypeOfResult { if ($type instanceof self) { - return TrinaryLogic::createFromBoolean($this->equals($type)); + return IsSuperTypeOfResult::createFromBoolean($this->equals($type)); } return parent::isSuperTypeOf($type); diff --git a/src/Type/Doctrine/QueryBuilder/BranchingQueryBuilderType.php b/src/Type/Doctrine/QueryBuilder/BranchingQueryBuilderType.php index e9c7bfb8..473dffb5 100644 --- a/src/Type/Doctrine/QueryBuilder/BranchingQueryBuilderType.php +++ b/src/Type/Doctrine/QueryBuilder/BranchingQueryBuilderType.php @@ -2,7 +2,7 @@ namespace PHPStan\Type\Doctrine\QueryBuilder; -use PHPStan\TrinaryLogic; +use PHPStan\Type\IsSuperTypeOfResult; use PHPStan\Type\Type; use function array_keys; use function count; @@ -35,10 +35,10 @@ public function equals(Type $type): bool return parent::equals($type); } - public function isSuperTypeOf(Type $type): TrinaryLogic + public function isSuperTypeOf(Type $type): IsSuperTypeOfResult { if ($type instanceof parent) { - return TrinaryLogic::createFromBoolean($this->equals($type)); + return IsSuperTypeOfResult::createFromBoolean($this->equals($type)); } return parent::isSuperTypeOf($type); diff --git a/src/Type/Doctrine/QueryBuilder/CreateQueryBuilderDynamicReturnTypeExtension.php b/src/Type/Doctrine/QueryBuilder/CreateQueryBuilderDynamicReturnTypeExtension.php index 263f2284..3fe7e9b1 100644 --- a/src/Type/Doctrine/QueryBuilder/CreateQueryBuilderDynamicReturnTypeExtension.php +++ b/src/Type/Doctrine/QueryBuilder/CreateQueryBuilderDynamicReturnTypeExtension.php @@ -11,19 +11,13 @@ class CreateQueryBuilderDynamicReturnTypeExtension implements DynamicMethodReturnTypeExtension { - /** @var string|null */ - private $queryBuilderClass; - - /** @var bool */ - private $fasterVersion; + private ?string $queryBuilderClass = null; public function __construct( - ?string $queryBuilderClass, - bool $fasterVersion + ?string $queryBuilderClass ) { $this->queryBuilderClass = $queryBuilderClass; - $this->fasterVersion = $fasterVersion; } public function getClass(): string @@ -42,13 +36,8 @@ public function getTypeFromMethodCall( Scope $scope ): Type { - $class = SimpleQueryBuilderType::class; - if (!$this->fasterVersion) { - $class = BranchingQueryBuilderType::class; - } - - return new $class( - $this->queryBuilderClass ?? 'Doctrine\ORM\QueryBuilder' + return new BranchingQueryBuilderType( + $this->queryBuilderClass ?? 'Doctrine\ORM\QueryBuilder', ); } diff --git a/src/Type/Doctrine/QueryBuilder/EntityRepositoryCreateQueryBuilderDynamicReturnTypeExtension.php b/src/Type/Doctrine/QueryBuilder/EntityRepositoryCreateQueryBuilderDynamicReturnTypeExtension.php index f170b550..44201e45 100644 --- a/src/Type/Doctrine/QueryBuilder/EntityRepositoryCreateQueryBuilderDynamicReturnTypeExtension.php +++ b/src/Type/Doctrine/QueryBuilder/EntityRepositoryCreateQueryBuilderDynamicReturnTypeExtension.php @@ -35,7 +35,7 @@ public function getTypeFromMethodCall( $entityNameExpr = new MethodCall($methodCall->var, new Identifier('getEntityName')); $entityNameExprType = $scope->getType($entityNameExpr); - if ($entityNameExprType->isClassStringType()->yes() && count($entityNameExprType->getClassStringObjectType()->getObjectClassNames()) === 1) { + if ($entityNameExprType->isClassString()->yes() && count($entityNameExprType->getClassStringObjectType()->getObjectClassNames()) === 1) { $entityNameExpr = new String_($entityNameExprType->getClassStringObjectType()->getObjectClassNames()[0]); } diff --git a/src/Type/Doctrine/QueryBuilder/Expr/BaseExpressionDynamicReturnTypeExtension.php b/src/Type/Doctrine/QueryBuilder/Expr/BaseExpressionDynamicReturnTypeExtension.php index d797b45f..7dd9729e 100644 --- a/src/Type/Doctrine/QueryBuilder/Expr/BaseExpressionDynamicReturnTypeExtension.php +++ b/src/Type/Doctrine/QueryBuilder/Expr/BaseExpressionDynamicReturnTypeExtension.php @@ -17,8 +17,7 @@ class BaseExpressionDynamicReturnTypeExtension implements DynamicMethodReturnTypeExtension { - /** @var ArgumentsProcessor */ - private $argumentsProcessor; + private ArgumentsProcessor $argumentsProcessor; public function __construct( ArgumentsProcessor $argumentsProcessor diff --git a/src/Type/Doctrine/QueryBuilder/Expr/ExprType.php b/src/Type/Doctrine/QueryBuilder/Expr/ExprType.php index 00610d03..30a97a59 100644 --- a/src/Type/Doctrine/QueryBuilder/Expr/ExprType.php +++ b/src/Type/Doctrine/QueryBuilder/Expr/ExprType.php @@ -8,8 +8,7 @@ class ExprType extends ObjectType { - /** @var object */ - private $exprObject; + private object $exprObject; /** * @param object $exprObject diff --git a/src/Type/Doctrine/QueryBuilder/Expr/ExpressionBuilderDynamicReturnTypeExtension.php b/src/Type/Doctrine/QueryBuilder/Expr/ExpressionBuilderDynamicReturnTypeExtension.php index fae7cd28..a6a6896a 100644 --- a/src/Type/Doctrine/QueryBuilder/Expr/ExpressionBuilderDynamicReturnTypeExtension.php +++ b/src/Type/Doctrine/QueryBuilder/Expr/ExpressionBuilderDynamicReturnTypeExtension.php @@ -18,11 +18,9 @@ class ExpressionBuilderDynamicReturnTypeExtension implements DynamicMethodReturnTypeExtension { - /** @var ObjectMetadataResolver */ - private $objectMetadataResolver; + private ObjectMetadataResolver $objectMetadataResolver; - /** @var ArgumentsProcessor */ - private $argumentsProcessor; + private ArgumentsProcessor $argumentsProcessor; public function __construct( ObjectMetadataResolver $objectMetadataResolver, diff --git a/src/Type/Doctrine/QueryBuilder/Expr/NewExprDynamicReturnTypeExtension.php b/src/Type/Doctrine/QueryBuilder/Expr/NewExprDynamicReturnTypeExtension.php index 1690c63c..79206e1c 100644 --- a/src/Type/Doctrine/QueryBuilder/Expr/NewExprDynamicReturnTypeExtension.php +++ b/src/Type/Doctrine/QueryBuilder/Expr/NewExprDynamicReturnTypeExtension.php @@ -18,15 +18,16 @@ class NewExprDynamicReturnTypeExtension implements DynamicStaticMethodReturnTypeExtension { - /** @var ArgumentsProcessor */ - private $argumentsProcessor; + private ArgumentsProcessor $argumentsProcessor; - /** @var string */ - private $class; + /** @var class-string */ + private string $class; - /** @var ReflectionProvider */ - private $reflectionProvider; + private ReflectionProvider $reflectionProvider; + /** + * @param class-string $class + */ public function __construct( ArgumentsProcessor $argumentsProcessor, string $class, @@ -68,8 +69,8 @@ public function getTypeFromStaticMethodCall(MethodReflection $methodReflection, ...$this->argumentsProcessor->processArgs( $scope, $methodReflection->getName(), - $methodCall->getArgs() - ) + $methodCall->getArgs(), + ), ); } catch (DynamicQueryBuilderArgumentException $e) { return new ObjectType($this->reflectionProvider->getClassName($className)); diff --git a/src/Type/Doctrine/QueryBuilder/OtherMethodQueryBuilderParser.php b/src/Type/Doctrine/QueryBuilder/OtherMethodQueryBuilderParser.php index 4375c17a..153291f5 100644 --- a/src/Type/Doctrine/QueryBuilder/OtherMethodQueryBuilderParser.php +++ b/src/Type/Doctrine/QueryBuilder/OtherMethodQueryBuilderParser.php @@ -28,25 +28,19 @@ class OtherMethodQueryBuilderParser { - /** @var bool */ - private $descendIntoOtherMethods; + private Parser $parser; - /** @var Parser */ - private $parser; - - /** @var Container */ - private $container; + private Container $container; /** * Null if the method is currently being processed * * @var array|null> */ - private $cache = []; + private array $cache = []; - public function __construct(bool $descendIntoOtherMethods, Parser $parser, Container $container) + public function __construct(Parser $parser, Container $container) { - $this->descendIntoOtherMethods = $descendIntoOtherMethods; $this->parser = $parser; $this->container = $container; } @@ -56,10 +50,6 @@ public function __construct(bool $descendIntoOtherMethods, Parser $parser, Conta */ public function findQueryBuilderTypesInCalledMethod(Scope $scope, MethodReflection $methodReflection): array { - if (!$this->descendIntoOtherMethods) { - return []; - } - $methodName = $methodReflection->getName(); $className = $methodReflection->getDeclaringClass()->getName(); $fileName = $methodReflection->getDeclaringClass()->getFileName(); diff --git a/src/Type/Doctrine/QueryBuilder/QueryBuilderGetDqlDynamicReturnTypeExtension.php b/src/Type/Doctrine/QueryBuilder/QueryBuilderGetDqlDynamicReturnTypeExtension.php index 3b7dfb19..69ceb824 100644 --- a/src/Type/Doctrine/QueryBuilder/QueryBuilderGetDqlDynamicReturnTypeExtension.php +++ b/src/Type/Doctrine/QueryBuilder/QueryBuilderGetDqlDynamicReturnTypeExtension.php @@ -13,9 +13,12 @@ class QueryBuilderGetDqlDynamicReturnTypeExtension implements DynamicMethodReturnTypeExtension { - /** @var string|null */ - private $queryBuilderClass; + /** @var class-string|null */ + private ?string $queryBuilderClass = null; + /** + * @param class-string|null $queryBuilderClass + */ public function __construct( ?string $queryBuilderClass ) @@ -41,7 +44,7 @@ public function getTypeFromMethodCall( { $type = $scope->getType(new MethodCall( new MethodCall($methodCall->var, new Identifier('getQuery')), - new Identifier('getDQL') + new Identifier('getDQL'), )); return TypeCombinator::removeNull($type); diff --git a/src/Type/Doctrine/QueryBuilder/QueryBuilderGetQueryDynamicReturnTypeExtension.php b/src/Type/Doctrine/QueryBuilder/QueryBuilderGetQueryDynamicReturnTypeExtension.php index 366eaa60..98fdefb3 100644 --- a/src/Type/Doctrine/QueryBuilder/QueryBuilderGetQueryDynamicReturnTypeExtension.php +++ b/src/Type/Doctrine/QueryBuilder/QueryBuilderGetQueryDynamicReturnTypeExtension.php @@ -55,24 +55,22 @@ class QueryBuilderGetQueryDynamicReturnTypeExtension implements DynamicMethodRet 'orhaving', ]; - /** @var ObjectMetadataResolver */ - private $objectMetadataResolver; + private ObjectMetadataResolver $objectMetadataResolver; - /** @var ArgumentsProcessor */ - private $argumentsProcessor; + private ArgumentsProcessor $argumentsProcessor; - /** @var string|null */ - private $queryBuilderClass; + /** @var class-string|null */ + private ?string $queryBuilderClass = null; - /** @var DescriptorRegistry */ - private $descriptorRegistry; + private DescriptorRegistry $descriptorRegistry; - /** @var PhpVersion */ - private $phpVersion; + private PhpVersion $phpVersion; - /** @var DriverDetector */ - private $driverDetector; + private DriverDetector $driverDetector; + /** + * @param class-string|null $queryBuilderClass + */ public function __construct( ObjectMetadataResolver $objectMetadataResolver, ArgumentsProcessor $argumentsProcessor, diff --git a/src/Type/Doctrine/QueryBuilder/QueryBuilderMethodDynamicReturnTypeExtension.php b/src/Type/Doctrine/QueryBuilder/QueryBuilderMethodDynamicReturnTypeExtension.php index cb76ba29..0c6d9266 100644 --- a/src/Type/Doctrine/QueryBuilder/QueryBuilderMethodDynamicReturnTypeExtension.php +++ b/src/Type/Doctrine/QueryBuilder/QueryBuilderMethodDynamicReturnTypeExtension.php @@ -7,7 +7,6 @@ use PhpParser\Node\Identifier; use PHPStan\Analyser\Scope; use PHPStan\Reflection\MethodReflection; -use PHPStan\Reflection\ParametersAcceptorSelector; use PHPStan\Type\Doctrine\DoctrineTypeUtils; use PHPStan\Type\DynamicMethodReturnTypeExtension; use PHPStan\Type\MixedType; @@ -23,9 +22,12 @@ class QueryBuilderMethodDynamicReturnTypeExtension implements DynamicMethodRetur private const MAX_COMBINATIONS = 16; - /** @var string|null */ - private $queryBuilderClass; + /** @var class-string|null */ + private ?string $queryBuilderClass = null; + /** + * @param class-string|null $queryBuilderClass + */ public function __construct( ?string $queryBuilderClass ) @@ -40,9 +42,7 @@ public function getClass(): string public function isMethodSupported(MethodReflection $methodReflection): bool { - $returnType = ParametersAcceptorSelector::selectSingle( - $methodReflection->getVariants() - )->getReturnType(); + $returnType = $methodReflection->getVariants()[0]->getReturnType(); if ($returnType instanceof MixedType) { return false; } diff --git a/src/Type/Doctrine/QueryBuilder/QueryBuilderType.php b/src/Type/Doctrine/QueryBuilder/QueryBuilderType.php index 729cda17..f707888c 100644 --- a/src/Type/Doctrine/QueryBuilder/QueryBuilderType.php +++ b/src/Type/Doctrine/QueryBuilder/QueryBuilderType.php @@ -14,7 +14,7 @@ abstract class QueryBuilderType extends ObjectType { /** @var array */ - private $methodCalls = []; + private array $methodCalls = []; final public function __construct( string $className, diff --git a/src/Type/Doctrine/QueryBuilder/QueryBuilderTypeSpecifyingExtension.php b/src/Type/Doctrine/QueryBuilder/QueryBuilderTypeSpecifyingExtension.php index 4b72f650..66b18f71 100644 --- a/src/Type/Doctrine/QueryBuilder/QueryBuilderTypeSpecifyingExtension.php +++ b/src/Type/Doctrine/QueryBuilder/QueryBuilderTypeSpecifyingExtension.php @@ -24,12 +24,14 @@ class QueryBuilderTypeSpecifyingExtension implements MethodTypeSpecifyingExtensi private const MAX_COMBINATIONS = 16; - /** @var string|null */ - private $queryBuilderClass; + /** @var class-string|null */ + private ?string $queryBuilderClass = null; - /** @var TypeSpecifier */ - private $typeSpecifier; + private TypeSpecifier $typeSpecifier; + /** + * @param class-string|null $queryBuilderClass + */ public function __construct(?string $queryBuilderClass) { $this->queryBuilderClass = $queryBuilderClass; @@ -62,7 +64,7 @@ public function specifyTypes(MethodReflection $methodReflection, MethodCall $nod $returnType = ParametersAcceptorSelector::selectFromArgs( $scope, $node->getArgs(), - $methodReflection->getVariants() + $methodReflection->getVariants(), )->getReturnType(); if ($returnType instanceof MixedType) { return new SpecifiedTypes([]); @@ -100,8 +102,8 @@ public function specifyTypes(MethodReflection $methodReflection, MethodCall $nod $queryBuilderNode, TypeCombinator::union(...$resultTypes), TypeSpecifierContext::createTruthy(), - true - ); + $scope, + )->setAlwaysOverwriteTypes(); } } diff --git a/src/Type/Doctrine/QueryBuilder/ReturnQueryBuilderExpressionTypeResolverExtension.php b/src/Type/Doctrine/QueryBuilder/ReturnQueryBuilderExpressionTypeResolverExtension.php index 2f780f22..5f308ba1 100644 --- a/src/Type/Doctrine/QueryBuilder/ReturnQueryBuilderExpressionTypeResolverExtension.php +++ b/src/Type/Doctrine/QueryBuilder/ReturnQueryBuilderExpressionTypeResolverExtension.php @@ -23,8 +23,7 @@ class ReturnQueryBuilderExpressionTypeResolverExtension implements ExpressionTypeResolverExtension { - /** @var OtherMethodQueryBuilderParser */ - private $otherMethodQueryBuilderParser; + private OtherMethodQueryBuilderParser $otherMethodQueryBuilderParser; public function __construct( OtherMethodQueryBuilderParser $otherMethodQueryBuilderParser diff --git a/src/Type/Doctrine/QueryBuilder/SimpleQueryBuilderType.php b/src/Type/Doctrine/QueryBuilder/SimpleQueryBuilderType.php deleted file mode 100644 index 98660de8..00000000 --- a/src/Type/Doctrine/QueryBuilder/SimpleQueryBuilderType.php +++ /dev/null @@ -1,33 +0,0 @@ -getMethodCalls()) === count($type->getMethodCalls()); - } - - return parent::equals($type); - } - - public function isSuperTypeOf(Type $type): TrinaryLogic - { - if ($type instanceof parent) { - $thisCount = count($this->getMethodCalls()); - $thatCount = count($type->getMethodCalls()); - - return TrinaryLogic::createFromBoolean($thisCount === $thatCount); - } - - return parent::isSuperTypeOf($type); - } - -} diff --git a/stubs/EntityRepository.stub b/stubs/EntityRepository.stub index 4dcde8bf..784b14c8 100644 --- a/stubs/EntityRepository.stub +++ b/stubs/EntityRepository.stub @@ -42,7 +42,7 @@ class EntityRepository implements ObjectRepository * @phpstan-param array|null $orderBy * @phpstan-return TEntityClass|null */ - public function findOneBy(array $criteria, array $orderBy = null); + public function findOneBy(array $criteria, ?array $orderBy = null); /** * @phpstan-return class-string diff --git a/stubs/MongoClassMetadataInfo.stub b/stubs/MongoClassMetadataInfo.stub index cfdba938..65cfa40f 100644 --- a/stubs/MongoClassMetadataInfo.stub +++ b/stubs/MongoClassMetadataInfo.stub @@ -16,6 +16,7 @@ class ClassMetadata implements BaseClassMetadata public $customRepositoryClassName; /** + * @readonly * @var class-string */ public $name; diff --git a/tests/BackedEnumStubExtension.php b/tests/BackedEnumStubExtension.php new file mode 100644 index 00000000..80cf36f4 --- /dev/null +++ b/tests/BackedEnumStubExtension.php @@ -0,0 +1,22 @@ += 80100) { + return []; + } + + return [ + __DIR__ . '/../compatibility/BackedEnum.stub', + ]; + } + +} diff --git a/tests/Classes/DoctrineProxyForbiddenClassNamesExtensionTest.php b/tests/Classes/DoctrineProxyForbiddenClassNamesExtensionTest.php index f1f7dd32..7c92d905 100644 --- a/tests/Classes/DoctrineProxyForbiddenClassNamesExtensionTest.php +++ b/tests/Classes/DoctrineProxyForbiddenClassNamesExtensionTest.php @@ -33,7 +33,7 @@ public function testForbiddenClassNameExtension(): void 20, 'This is most likely unintentional. Did you mean to type \TestPhpStanEntity?', ], - ] + ], ); } diff --git a/tests/Classes/entity-manager.php b/tests/Classes/entity-manager.php index a84bdc54..9c0301d1 100644 --- a/tests/Classes/entity-manager.php +++ b/tests/Classes/entity-manager.php @@ -19,13 +19,13 @@ $metadataDriver = new MappingDriverChain(); $metadataDriver->addDriver(new AnnotationDriver( new AnnotationReader(), - [__DIR__ . '/data'] + [__DIR__ . '/data'], ), 'PHPStan\\Rules\\Doctrine\\ORM\\'); if (PHP_VERSION_ID >= 80100) { $metadataDriver->addDriver( new AttributeDriver([__DIR__ . '/data-attributes']), - 'PHPStan\\Rules\\Doctrine\\ORMAttributes\\' + 'PHPStan\\Rules\\Doctrine\\ORMAttributes\\', ); } @@ -33,7 +33,7 @@ Type::overrideType( 'date', - DateTimeImmutableType::class + DateTimeImmutableType::class, ); return new EntityManager( @@ -41,5 +41,5 @@ 'driver' => 'pdo_sqlite', 'memory' => true, ]), - $config + $config, ); diff --git a/tests/DoctrineIntegration/ODM/document-manager.php b/tests/DoctrineIntegration/ODM/document-manager.php index bfdb4141..d104e205 100644 --- a/tests/DoctrineIntegration/ODM/document-manager.php +++ b/tests/DoctrineIntegration/ODM/document-manager.php @@ -16,11 +16,11 @@ $config->setMetadataDriverImpl( new AnnotationDriver( new AnnotationReader(), - [__DIR__ . '/data'] - ) + [__DIR__ . '/data'], + ), ); return DocumentManager::create( null, - $config + $config, ); diff --git a/tests/DoctrineIntegration/ORM/EntityRepositoryDynamicReturnIntegrationTest.php b/tests/DoctrineIntegration/ORM/EntityRepositoryDynamicReturnIntegrationTest.php index e64f096d..de7910fc 100644 --- a/tests/DoctrineIntegration/ORM/EntityRepositoryDynamicReturnIntegrationTest.php +++ b/tests/DoctrineIntegration/ORM/EntityRepositoryDynamicReturnIntegrationTest.php @@ -10,7 +10,7 @@ final class EntityRepositoryDynamicReturnIntegrationTest extends LevelsTestCase /** * @return string[][] */ - public function dataTopics(): array + public static function dataTopics(): array { return [ ['entityRepositoryDynamicReturn'], diff --git a/tests/DoctrineIntegration/ORM/EntityRepositoryWithoutObjectManagerLoaderDynamicReturnIntegrationTest.php b/tests/DoctrineIntegration/ORM/EntityRepositoryWithoutObjectManagerLoaderDynamicReturnIntegrationTest.php index bb2d04c1..ea596a6e 100644 --- a/tests/DoctrineIntegration/ORM/EntityRepositoryWithoutObjectManagerLoaderDynamicReturnIntegrationTest.php +++ b/tests/DoctrineIntegration/ORM/EntityRepositoryWithoutObjectManagerLoaderDynamicReturnIntegrationTest.php @@ -10,7 +10,7 @@ final class EntityRepositoryWithoutObjectManagerLoaderDynamicReturnIntegrationTe /** * @return string[][] */ - public function dataTopics(): array + public static function dataTopics(): array { return [ ['entityRepositoryDynamicReturn'], diff --git a/tests/DoctrineIntegration/ORM/entity-manager.php b/tests/DoctrineIntegration/ORM/entity-manager.php index 23f27436..fb21532a 100644 --- a/tests/DoctrineIntegration/ORM/entity-manager.php +++ b/tests/DoctrineIntegration/ORM/entity-manager.php @@ -15,8 +15,8 @@ $config->setMetadataDriverImpl( new AnnotationDriver( new AnnotationReader(), - [__DIR__ . '/data'] - ) + [__DIR__ . '/data'], + ), ); return new EntityManager( @@ -24,5 +24,5 @@ 'driver' => 'pdo_sqlite', 'memory' => true, ]), - $config + $config, ); diff --git a/tests/Platform/Entity/PlatformEntity.php b/tests/Platform/Entity/PlatformEntity.php index 6da280e9..efc1f68d 100644 --- a/tests/Platform/Entity/PlatformEntity.php +++ b/tests/Platform/Entity/PlatformEntity.php @@ -17,90 +17,58 @@ class PlatformEntity /** * @ORM\Id * @ORM\Column(type="string",nullable=false) - * @var string */ #[ORM\Id] #[ORM\Column(type: 'string', nullable: false)] - public $id; + public string $id; /** * @ORM\ManyToOne(targetEntity=PlatformRelatedEntity::class) * @ORM\JoinColumn(name="related_entity_id", referencedColumnName="id", nullable=false) - * @var PlatformRelatedEntity */ #[ORM\ManyToOne(targetEntity: PlatformRelatedEntity::class)] #[ORM\JoinColumn(name: 'related_entity_id', referencedColumnName: 'id', nullable: false)] - public $related_entity; + public PlatformRelatedEntity $related_entity; - /** - * @ORM\Column(type="string", name="col_string", nullable=false) - * @var string - */ + /** @ORM\Column(type="string", name="col_string", nullable=false) */ #[ORM\Column(type: 'string', name: 'col_string', nullable: false)] - public $col_string; + public string $col_string; - /** - * @ORM\Column(type="string", name="col_string_nullable", nullable=true) - * @var string|null - */ + /** @ORM\Column(type="string", name="col_string_nullable", nullable=true) */ #[ORM\Column(type: 'string', name: 'col_string_nullable', nullable: true)] - public $col_string_nullable; + public ?string $col_string_nullable = null; - /** - * @ORM\Column(type="boolean", name="col_bool", nullable=false) - * @var bool - */ + /** @ORM\Column(type="boolean", name="col_bool", nullable=false) */ #[ORM\Column(type: 'boolean', name: 'col_bool', nullable: false)] - public $col_bool; + public bool $col_bool; - /** - * @ORM\Column(type="boolean", name="col_bool_nullable", nullable=true) - * @var bool|null - */ + /** @ORM\Column(type="boolean", name="col_bool_nullable", nullable=true) */ #[ORM\Column(type: 'boolean', name: 'col_bool_nullable', nullable: true)] - public $col_bool_nullable; + public ?bool $col_bool_nullable = null; - /** - * @ORM\Column(type="float", name="col_float", nullable=false) - * @var float - */ + /** @ORM\Column(type="float", name="col_float", nullable=false) */ #[ORM\Column(type: 'float', name: 'col_float', nullable: false)] - public $col_float; + public float $col_float; - /** - * @ORM\Column(type="float", name="col_float_nullable", nullable=true) - * @var float|null - */ + /** @ORM\Column(type="float", name="col_float_nullable", nullable=true) */ #[ORM\Column(type: 'float', name: 'col_float_nullable', nullable: true)] - public $col_float_nullable; + public ?float $col_float_nullable = null; - /** - * @ORM\Column(type="decimal", name="col_decimal", nullable=false, scale=1, precision=2) - * @var string - */ + /** @ORM\Column(type="decimal", name="col_decimal", nullable=false, scale=1, precision=2) */ #[ORM\Column(type: 'decimal', name: 'col_decimal', nullable: false, scale: 1, precision: 2)] - public $col_decimal; + public string $col_decimal; - /** - * @ORM\Column(type="decimal", name="col_decimal_nullable", nullable=true, scale=1, precision=2) - * @var string|null - */ + /** @ORM\Column(type="decimal", name="col_decimal_nullable", nullable=true, scale=1, precision=2) */ #[ORM\Column(type: 'decimal', name: 'col_decimal_nullable', nullable: true, scale: 1, precision: 2)] - public $col_decimal_nullable; + public ?string $col_decimal_nullable = null; - /** - * @ORM\Column(type="integer", name="col_int", nullable=false) - * @var int - */ + /** @ORM\Column(type="integer", name="col_int", nullable=false) */ #[ORM\Column(type: 'integer', name: 'col_int', nullable: false)] - public $col_int; + public int $col_int; - /** - * @ORM\Column(type="integer", name="col_int_nullable", nullable=true) - * @var int|null - */ + /** @ORM\Column(type="integer", name="col_int_nullable", nullable=true) */ #[ORM\Column(type: 'integer', name: 'col_int_nullable', nullable: true)] - public $col_int_nullable; + public ?int $col_int_nullable = null; /** * @ORM\Column(type="bigint", name="col_bigint", nullable=false) @@ -123,11 +91,8 @@ class PlatformEntity #[ORM\Column(type: 'mixed', name: 'col_mixed', nullable: false)] public $col_mixed; - /** - * @ORM\Column(type="datetime", name="col_datetime", nullable=false) - * @var DateTimeInterface - */ + /** @ORM\Column(type="datetime", name="col_datetime", nullable=false) */ #[ORM\Column(type: 'datetime', name: 'col_datetime', nullable: false)] - public $col_datetime; + public DateTimeInterface $col_datetime; } diff --git a/tests/Platform/Entity/PlatformRelatedEntity.php b/tests/Platform/Entity/PlatformRelatedEntity.php index 86c4b00a..fec1a0a5 100644 --- a/tests/Platform/Entity/PlatformRelatedEntity.php +++ b/tests/Platform/Entity/PlatformRelatedEntity.php @@ -16,10 +16,9 @@ class PlatformRelatedEntity /** * @ORM\Id * @ORM\Column(type="integer", nullable=false) - * @var int */ #[ORM\Id] #[ORM\Column(type: 'integer', nullable: false)] - public $id; + public int $id; } diff --git a/tests/Platform/QueryResultTypeWalkerFetchTypeMatrixTest.php b/tests/Platform/QueryResultTypeWalkerFetchTypeMatrixTest.php index 03e5ed12..48846980 100644 --- a/tests/Platform/QueryResultTypeWalkerFetchTypeMatrixTest.php +++ b/tests/Platform/QueryResultTypeWalkerFetchTypeMatrixTest.php @@ -137,7 +137,7 @@ public function testPdoMysqlDefault( PHP_VERSION_ID, $mysqlExpectedType, $mysqlExpectedResult, - $stringify + $stringify, ); } @@ -177,7 +177,7 @@ public function testPdoMysqlStringify( PHP_VERSION_ID, $mysqlExpectedType, $mysqlExpectedResult, - $stringify + $stringify, ); } @@ -217,7 +217,7 @@ public function testPdoMysqlNoEmulate( PHP_VERSION_ID, $mysqlExpectedType, $mysqlExpectedResult, - $stringify + $stringify, ); } @@ -257,7 +257,7 @@ public function testPdoMysqlStringifyNoEmulate( PHP_VERSION_ID, $mysqlExpectedType, $mysqlExpectedResult, - $stringify + $stringify, ); } @@ -297,7 +297,7 @@ public function testPdoMysqliDefault( PHP_VERSION_ID, $mysqlExpectedType, $mysqlExpectedResult, - $stringify + $stringify, ); } @@ -337,7 +337,7 @@ public function testPdoSqliteDefault( PHP_VERSION_ID, $sqliteExpectedType, $sqliteExpectedResult, - $stringify + $stringify, ); } @@ -377,7 +377,7 @@ public function testPdoSqliteStringify( PHP_VERSION_ID, $sqliteExpectedType, $sqliteExpectedResult, - $stringify + $stringify, ); } @@ -417,7 +417,7 @@ public function testPdoSqlite3( PHP_VERSION_ID, $sqliteExpectedType, $sqliteExpectedResult, - $stringify + $stringify, ); } @@ -457,7 +457,7 @@ public function testPdoPgsqlDefault( PHP_VERSION_ID, $pdoPgsqlExpectedType, $pdoPgsqlExpectedResult, - $stringify + $stringify, ); } @@ -497,7 +497,7 @@ public function testPdoPgsqlStringify( PHP_VERSION_ID, $pdoPgsqlExpectedType, $pdoPgsqlExpectedResult, - $stringify + $stringify, ); } @@ -537,7 +537,7 @@ public function testPgsql( PHP_VERSION_ID, $pgsqlExpectedType, $pgsqlExpectedResult, - $stringify + $stringify, ); } @@ -577,7 +577,7 @@ public function testUnsupportedDriver( PHP_VERSION_ID, $mssqlExpectedType, $mssqlExpectedResult, - $stringify + $stringify, ); } @@ -618,7 +618,7 @@ public function testUnknownDriver( $this->determineTypeForUnknownDriverUnknownSetup($mysqlExpectedType, $stringify), $mysqlExpectedResult, $stringify, - true + true, ); } @@ -659,7 +659,7 @@ public function testUnknownDriverStringify( $this->determineTypeForUnknownDriverUnknownSetup($mysqlExpectedType, $stringify), $mysqlExpectedResult, $stringify, - true + true, ); } @@ -4530,7 +4530,7 @@ private function performDriverTest( $dql, $sql, $realResultType->describe(VerbosityLevel::precise()), - $inferredType->describe(VerbosityLevel::precise()) + $inferredType->describe(VerbosityLevel::precise()), )); } @@ -4636,7 +4636,7 @@ private function getInferredType(Query $query): Type $typeBuilder, self::getContainer()->getByType(DescriptorRegistry::class), $phpVersion, - new DriverDetector() + new DriverDetector(), ); return $typeBuilder->getResultType(); @@ -4678,8 +4678,8 @@ private function assertRealResultMatchesExpected( $dataset, $dql, $humanReadablePhpVersion, - $realFirstResult - ) + $realFirstResult, + ), ); } @@ -4695,8 +4695,8 @@ private function assertRealResultMatchesExpected( $sql, $humanReadablePhpVersion, $realFirstResult, - $expectedFirstResultExported - ) + $expectedFirstResultExported, + ), ); } @@ -4730,8 +4730,8 @@ private function assertRealResultMatchesInferred( $this->getHumanReadablePhpVersion($phpVersion), $realFirstResult, $inferredType->describe(VerbosityLevel::precise()), - $realType->describe(VerbosityLevel::precise()) - ) + $realType->describe(VerbosityLevel::precise()), + ), ); } @@ -4768,8 +4768,8 @@ private function assertInferredResultMatchesExpected( $this->getHumanReadablePhpVersion($phpVersion), $realFirstResult, $inferredFirstItemType->describe(VerbosityLevel::precise()), - $expectedFirstItemType->describe(VerbosityLevel::precise()) - ) + $expectedFirstItemType->describe(VerbosityLevel::precise()), + ), ); } diff --git a/tests/Platform/data/config.neon b/tests/Platform/data/config.neon index 38f26ed7..e6dd2808 100644 --- a/tests/Platform/data/config.neon +++ b/tests/Platform/data/config.neon @@ -1,5 +1,2 @@ includes: - ../../../extension.neon -parameters: - featureToggles: - listType: true diff --git a/tests/Platform/docker/Dockerfile84 b/tests/Platform/docker/Dockerfile84 index 81ac9834..30b47ed2 100644 --- a/tests/Platform/docker/Dockerfile84 +++ b/tests/Platform/docker/Dockerfile84 @@ -1,4 +1,4 @@ -FROM php:8.4.0beta4-cli +FROM php:8.4-cli # MSSQL RUN apt update \ @@ -12,13 +12,8 @@ RUN apt update \ && pecl install pdo_sqlsrv \ && docker-php-ext-enable sqlsrv pdo_sqlsrv -RUN set -ex \ - && apt update \ - && apt install -y bash zip libpq-dev libsqlite3-dev \ - && pecl install xdebug-3.4 mongodb \ - && docker-php-ext-configure pgsql -with-pgsql=/usr/local/pgsql \ - && docker-php-ext-install pdo mysqli pgsql pdo_mysql pdo_pgsql pdo_sqlite \ - && docker-php-ext-enable mongodb # TODO xdebug not yet supported here +COPY ./docker-setup.sh /opt/src/scripts/setup.sh +RUN /opt/src/scripts/setup.sh COPY --from=composer:2 /usr/bin/composer /usr/local/bin/composer diff --git a/tests/Reflection/Doctrine/DoctrineSelectableClassReflectionExtensionTest.php b/tests/Reflection/Doctrine/DoctrineSelectableClassReflectionExtensionTest.php index 1debe15e..61c90e4f 100644 --- a/tests/Reflection/Doctrine/DoctrineSelectableClassReflectionExtensionTest.php +++ b/tests/Reflection/Doctrine/DoctrineSelectableClassReflectionExtensionTest.php @@ -9,11 +9,9 @@ final class DoctrineSelectableClassReflectionExtensionTest extends PHPStanTestCase { - /** @var ReflectionProvider */ - private $reflectionProvider; + private ReflectionProvider $reflectionProvider; - /** @var DoctrineSelectableClassReflectionExtension */ - private $extension; + private DoctrineSelectableClassReflectionExtension $extension; protected function setUp(): void { diff --git a/tests/Rules/DeadCode/UnusedPrivatePropertyRuleTest.php b/tests/Rules/DeadCode/UnusedPrivatePropertyRuleTest.php index 8c582618..e7a88b28 100644 --- a/tests/Rules/DeadCode/UnusedPrivatePropertyRuleTest.php +++ b/tests/Rules/DeadCode/UnusedPrivatePropertyRuleTest.php @@ -27,10 +27,6 @@ public static function getAdditionalConfigFiles(): array public function testRule(): void { - if (PHP_VERSION_ID < 70400) { - self::markTestSkipped('Test requires PHP 7.4.'); - } - $this->analyse([__DIR__ . '/data/unused-private-property.php'], [ [ 'Property PHPStan\Rules\Doctrine\ORM\UnusedPrivateProperty\EntityWithAGeneratedId::$unused is never written, only read.', diff --git a/tests/Rules/DeadCode/entity-manager.php b/tests/Rules/DeadCode/entity-manager.php index bc0d5ccb..30eeec97 100644 --- a/tests/Rules/DeadCode/entity-manager.php +++ b/tests/Rules/DeadCode/entity-manager.php @@ -17,12 +17,12 @@ $metadataDriver = new MappingDriverChain(); $metadataDriver->addDriver(new AnnotationDriver( new AnnotationReader(), - [__DIR__ . '/data'] + [__DIR__ . '/data'], ), 'PHPStan\\Rules\\Doctrine\\ORM\\'); if (PHP_VERSION_ID >= 80100) { $metadataDriver->addDriver( new AttributeDriver([__DIR__ . '/data']), - 'PHPStan\\Rules\\Doctrine\\ORMAttributes\\' + 'PHPStan\\Rules\\Doctrine\\ORMAttributes\\', ); } @@ -33,5 +33,5 @@ 'driver' => 'pdo_sqlite', 'memory' => true, ]), - $config + $config, ); diff --git a/tests/Rules/Doctrine/ORM/EntityColumnRuleTest.php b/tests/Rules/Doctrine/ORM/EntityColumnRuleTest.php index c7de7957..f0a799e6 100644 --- a/tests/Rules/Doctrine/ORM/EntityColumnRuleTest.php +++ b/tests/Rules/Doctrine/ORM/EntityColumnRuleTest.php @@ -35,11 +35,9 @@ class EntityColumnRuleTest extends RuleTestCase { - /** @var bool */ - private $allowNullablePropertyForRequiredField; + private bool $allowNullablePropertyForRequiredField; - /** @var string|null */ - private $objectManagerLoader; + private ?string $objectManagerLoader = null; protected function getRule(): Rule { @@ -77,15 +75,14 @@ protected function getRule(): Rule new StringType(), new SimpleArrayType(), new UuidTypeDescriptor(FakeTestingUuidType::class), - new ReflectionDescriptor(CarbonImmutableType::class, $this->createBroker(), self::getContainer()), - new ReflectionDescriptor(CarbonType::class, $this->createBroker(), self::getContainer()), - new ReflectionDescriptor(CustomType::class, $this->createBroker(), self::getContainer()), - new ReflectionDescriptor(CustomNumericType::class, $this->createBroker(), self::getContainer()), + new ReflectionDescriptor(CarbonImmutableType::class, $this->createReflectionProvider(), self::getContainer()), + new ReflectionDescriptor(CarbonType::class, $this->createReflectionProvider(), self::getContainer()), + new ReflectionDescriptor(CustomType::class, $this->createReflectionProvider(), self::getContainer()), + new ReflectionDescriptor(CustomNumericType::class, $this->createReflectionProvider(), self::getContainer()), ]), $this->createReflectionProvider(), true, $this->allowNullablePropertyForRequiredField, - true ); } @@ -162,7 +159,7 @@ public function testRule(?string $objectManagerLoader): void 156, ], [ - 'Property PHPStan\Rules\Doctrine\ORM\MyBrokenEntity::$invalidSimpleArray type mapping mismatch: database can contain array but property expects array.', + 'Property PHPStan\Rules\Doctrine\ORM\MyBrokenEntity::$invalidSimpleArray type mapping mismatch: database can contain list but property expects array.', 162, ], [ @@ -233,7 +230,7 @@ public function testRuleWithAllowedNullableProperty(?string $objectManagerLoader 156, ], [ - 'Property PHPStan\Rules\Doctrine\ORM\MyBrokenEntity::$invalidSimpleArray type mapping mismatch: database can contain array but property expects array.', + 'Property PHPStan\Rules\Doctrine\ORM\MyBrokenEntity::$invalidSimpleArray type mapping mismatch: database can contain list but property expects array.', 162, ], [ @@ -402,7 +399,7 @@ public function testEnumType(?string $objectManagerLoader): void 45, ], [ - 'Property PHPStan\Rules\Doctrine\ORMAttributes\Foo::$type5 type mapping mismatch: database can contain array but property expects PHPStan\Rules\Doctrine\ORMAttributes\FooEnum.', + 'Property PHPStan\Rules\Doctrine\ORMAttributes\Foo::$type5 type mapping mismatch: database can contain list but property expects PHPStan\Rules\Doctrine\ORMAttributes\FooEnum.', 51, ], [ diff --git a/tests/Rules/Doctrine/ORM/EntityConstructorNotFinalRuleTest.php b/tests/Rules/Doctrine/ORM/EntityConstructorNotFinalRuleTest.php index 7647704b..a94fdfde 100644 --- a/tests/Rules/Doctrine/ORM/EntityConstructorNotFinalRuleTest.php +++ b/tests/Rules/Doctrine/ORM/EntityConstructorNotFinalRuleTest.php @@ -13,13 +13,12 @@ class EntityConstructorNotFinalRuleTest extends RuleTestCase { - /** @var string|null */ - private $objectManagerLoader; + private ?string $objectManagerLoader = null; protected function getRule(): Rule { return new EntityConstructorNotFinalRule( - new ObjectMetadataResolver($this->objectManagerLoader, __DIR__ . '/../../../../tmp') + new ObjectMetadataResolver($this->objectManagerLoader, __DIR__ . '/../../../../tmp'), ); } diff --git a/tests/Rules/Doctrine/ORM/EntityMappingExceptionRuleTest.php b/tests/Rules/Doctrine/ORM/EntityMappingExceptionRuleTest.php index 26a4e744..65b8f209 100644 --- a/tests/Rules/Doctrine/ORM/EntityMappingExceptionRuleTest.php +++ b/tests/Rules/Doctrine/ORM/EntityMappingExceptionRuleTest.php @@ -16,7 +16,7 @@ class EntityMappingExceptionRuleTest extends RuleTestCase protected function getRule(): Rule { return new EntityMappingExceptionRule( - new ObjectMetadataResolver(__DIR__ . '/entity-manager.php', __DIR__ . '/../../../../tmp') + new ObjectMetadataResolver(__DIR__ . '/entity-manager.php', __DIR__ . '/../../../../tmp'), ); } diff --git a/tests/Rules/Doctrine/ORM/EntityNotFinalRuleTest.php b/tests/Rules/Doctrine/ORM/EntityNotFinalRuleTest.php index 9f1494a7..d3f05395 100644 --- a/tests/Rules/Doctrine/ORM/EntityNotFinalRuleTest.php +++ b/tests/Rules/Doctrine/ORM/EntityNotFinalRuleTest.php @@ -13,13 +13,12 @@ class EntityNotFinalRuleTest extends RuleTestCase { - /** @var string|null */ - private $objectManagerLoader; + private ?string $objectManagerLoader = null; protected function getRule(): Rule { return new EntityNotFinalRule( - new ObjectMetadataResolver($this->objectManagerLoader, __DIR__ . '/../../../../tmp') + new ObjectMetadataResolver($this->objectManagerLoader, __DIR__ . '/../../../../tmp'), ); } diff --git a/tests/Rules/Doctrine/ORM/EntityRelationRuleTest.php b/tests/Rules/Doctrine/ORM/EntityRelationRuleTest.php index cd83bebe..7e81545f 100644 --- a/tests/Rules/Doctrine/ORM/EntityRelationRuleTest.php +++ b/tests/Rules/Doctrine/ORM/EntityRelationRuleTest.php @@ -14,18 +14,15 @@ class EntityRelationRuleTest extends RuleTestCase { - /** @var bool */ - private $allowNullablePropertyForRequiredField; + private bool $allowNullablePropertyForRequiredField; - /** @var string|null */ - private $objectManagerLoader; + private ?string $objectManagerLoader = null; protected function getRule(): Rule { return new EntityRelationRule( new ObjectMetadataResolver($this->objectManagerLoader, __DIR__ . '/../../../../tmp'), $this->allowNullablePropertyForRequiredField, - true ); } diff --git a/tests/Rules/Doctrine/ORM/FakeTestingUuidType.php b/tests/Rules/Doctrine/ORM/FakeTestingUuidType.php index fcb28f7e..f6255563 100644 --- a/tests/Rules/Doctrine/ORM/FakeTestingUuidType.php +++ b/tests/Rules/Doctrine/ORM/FakeTestingUuidType.php @@ -47,6 +47,7 @@ public function convertToDatabaseValue($value, AbstractPlatform $platform): ?str return null; } + /** @throws ConversionException */ return (string) $value; } diff --git a/tests/Rules/Doctrine/ORM/QueryBuilderDqlRuleSlowTest.php b/tests/Rules/Doctrine/ORM/QueryBuilderDqlRuleSlowTest.php deleted file mode 100644 index adad87ee..00000000 --- a/tests/Rules/Doctrine/ORM/QueryBuilderDqlRuleSlowTest.php +++ /dev/null @@ -1,151 +0,0 @@ - - */ -class QueryBuilderDqlRuleSlowTest extends RuleTestCase -{ - - protected function getRule(): Rule - { - return new QueryBuilderDqlRule( - new ObjectMetadataResolver(__DIR__ . '/entity-manager.php', __DIR__ . '/../../../../tmp'), - true - ); - } - - public function testRule(): void - { - if (PHP_VERSION_ID < 70300) { - self::markTestSkipped('For some reason PHP 7.2 cannot recover from Trying to get property value of non-object'); - } - $this->analyse([__DIR__ . '/data/query-builder-dql.php'], [ - [ - "QueryBuilder: [Syntax Error] line 0, col 66: Error: Expected end of string, got ')'\nDQL: SELECT e FROM PHPStan\Rules\Doctrine\ORM\MyEntity e WHERE e.id = 1)", - 31, - ], - [ - "QueryBuilder: [Syntax Error] line 0, col 68: Error: Expected end of string, got ')'\nDQL: SELECT e FROM PHPStan\Rules\Doctrine\ORM\MyEntity e WHERE e.id = :id)", - 43, - ], - [ - "QueryBuilder: [Syntax Error] line 0, col 68: Error: Expected end of string, got ')'\nDQL: SELECT e FROM PHPStan\Rules\Doctrine\ORM\MyEntity e WHERE e.id = :id)", - 55, - ], - [ - 'QueryBuilder: [Semantical Error] line 0, col 60 near \'transient = \': Error: Class PHPStan\Rules\Doctrine\ORM\MyEntity has no field or association named transient', - 62, - ], - [ - 'QueryBuilder: [Semantical Error] line 0, col 14 near \'Foo e\': Error: Class \'Foo\' is not defined.', - 71, - ], - [ - 'Could not analyse QueryBuilder with dynamic arguments.', - 99, - ], - [ - 'QueryBuilder: [Semantical Error] line 0, col 60 near \'transient = \': Error: Class PHPStan\Rules\Doctrine\ORM\MyEntity has no field or association named transient', - 107, - ], - [ - "QueryBuilder: [Syntax Error] line 0, col 82: Error: Expected end of string, got ')'\nDQL: SELECT e FROM PHPStan\Rules\Doctrine\ORM\MyEntity e WHERE e.id = 1 ORDER BY e.name) ASC", - 129, - ], - [ - 'QueryBuilder: [Semantical Error] line 0, col 78 near \'name ASC\': Error: Class PHPStan\Rules\Doctrine\ORM\MyEntity has no field or association named name', - 139, - ], - [ - 'QueryBuilder: [Semantical Error] line 0, col 78 near \'name ASC\': Error: Class PHPStan\Rules\Doctrine\ORM\MyEntity has no field or association named name', - 160, - ], - [ - 'QueryBuilder: [Semantical Error] line 0, col 60 near \'transient = 1\': Error: Class PHPStan\Rules\Doctrine\ORM\MyEntity has no field or association named transient', - 170, - ], - [ - 'QueryBuilder: [Semantical Error] line 0, col 72 near \'nickname LIKE\': Error: Class PHPStan\Rules\Doctrine\ORM\MyEntity has no field or association named nickname', - 194, - ], - [ - 'QueryBuilder: [Semantical Error] line 0, col 72 near \'nickname IS \': Error: Class PHPStan\Rules\Doctrine\ORM\MyEntity has no field or association named nickname', - 206, - ], - [ - "QueryBuilder: [Syntax Error] line 0, col 80: Error: Expected =, <, <=, <>, >, >=, !=, got ')'\nDQL: SELECT e FROM PHPStan\Rules\Doctrine\ORM\MyEntity e WHERE e.id = 1 OR e.nickname) IS NULL", - 218, - ], - [ - 'QueryBuilder: [Semantical Error] line 0, col 60 near \'transient = \': Error: Class PHPStan\Rules\Doctrine\ORM\MyEntity has no field or association named transient', - 234, - ], - [ - 'QueryBuilder: [Semantical Error] line 0, col 60 near \'nonexistent =\': Error: Class PHPStan\Rules\Doctrine\ORM\MyEntity has no field or association named nonexistent', - 251, - ], - [ - "QueryBuilder: [Syntax Error] line 0, col -1: Error: Expected =, <, <=, <>, >, >=, !=, got end of string.\nDQL: SELECT e FROM PHPStan\Rules\Doctrine\ORM\MyEntity e WHERE foo", - 281, - ], - ]); - } - - public function testRuleBranches(): void - { - $errors = [ - [ - 'QueryBuilder: [Semantical Error] line 0, col 58 near \'p.id = 1\': Error: \'p\' is not defined.', - 31, - ], - [ - 'QueryBuilder: [Semantical Error] line 0, col 58 near \'p.id = 1\': Error: \'p\' is not defined.', - 45, - ], - [ - 'QueryBuilder: [Semantical Error] line 0, col 58 near \'p.id = 1\': Error: \'p\' is not defined.', - 59, - 'Detected from DQL branch: SELECT e FROM PHPStan\Rules\Doctrine\ORM\MyEntity e WHERE p.id = 1', - ], - [ - 'QueryBuilder: [Semantical Error] line 0, col 93 near \'t.id = 1\': Error: \'t\' is not defined.', - 90, - 'Detected from DQL branch: SELECT e FROM PHPStan\Rules\Doctrine\ORM\MyEntity e INNER JOIN e.parent p WHERE p.id = 1 AND t.id = 1', - ], - [ - 'QueryBuilder: [Semantical Error] line 0, col 95 near \'foo = 1\': Error: Class PHPStan\Rules\Doctrine\ORM\MyEntity has no field or association named foo', - 107, - 'Detected from DQL branch: SELECT e FROM PHPStan\Rules\Doctrine\ORM\MyEntity e INNER JOIN e.parent p WHERE p.id = 1 AND e.foo = 1', - ], - [ - 'QueryBuilder: [Semantical Error] line 0, col 93 near \'t.id = 1\': Error: \'t\' is not defined.', - 107, - 'Detected from DQL branch: SELECT e FROM PHPStan\Rules\Doctrine\ORM\MyEntity e INNER JOIN e.parent p WHERE p.id = 1 AND t.id = 1', - ], - ]; - $this->analyse([__DIR__ . '/data/query-builder-branches-dql.php'], $errors); - } - - public static function getAdditionalConfigFiles(): array - { - return [ - __DIR__ . '/../../../../extension.neon', - __DIR__ . '/entity-manager.neon', - __DIR__ . '/slow.neon', - ]; - } - - protected function shouldFailOnPhpErrors(): bool - { - // doctrine/orm/src/Query/Parser.php throws assert($peek !== null) failed - return false; - } - -} diff --git a/tests/Rules/Doctrine/ORM/QueryBuilderDqlRuleTest.php b/tests/Rules/Doctrine/ORM/QueryBuilderDqlRuleTest.php index ec3dafb7..65fd38d6 100644 --- a/tests/Rules/Doctrine/ORM/QueryBuilderDqlRuleTest.php +++ b/tests/Rules/Doctrine/ORM/QueryBuilderDqlRuleTest.php @@ -5,7 +5,6 @@ use PHPStan\Rules\Rule; use PHPStan\Testing\RuleTestCase; use PHPStan\Type\Doctrine\ObjectMetadataResolver; -use const PHP_VERSION_ID; /** * @extends RuleTestCase @@ -17,16 +16,12 @@ protected function getRule(): Rule { return new QueryBuilderDqlRule( new ObjectMetadataResolver(__DIR__ . '/entity-manager.php', __DIR__ . '/../../../../tmp'), - true + true, ); } public function testRule(): void { - if (PHP_VERSION_ID < 70300) { - self::markTestSkipped('For some reason PHP 7.2 cannot recover from Trying to get property value of non-object'); - } - $this->analyse([__DIR__ . '/data/query-builder-dql.php'], [ [ "QueryBuilder: [Syntax Error] line 0, col 66: Error: Expected end of string, got ')'\nDQL: SELECT e FROM PHPStan\Rules\Doctrine\ORM\MyEntity e WHERE e.id = 1)", diff --git a/tests/Rules/Doctrine/ORM/entity-manager.php b/tests/Rules/Doctrine/ORM/entity-manager.php index 9181f8b8..500a2029 100644 --- a/tests/Rules/Doctrine/ORM/entity-manager.php +++ b/tests/Rules/Doctrine/ORM/entity-manager.php @@ -19,13 +19,13 @@ $metadataDriver = new MappingDriverChain(); $metadataDriver->addDriver(new AnnotationDriver( new AnnotationReader(), - [__DIR__ . '/data'] + [__DIR__ . '/data'], ), 'PHPStan\\Rules\\Doctrine\\ORM\\'); if (PHP_VERSION_ID >= 80100) { $metadataDriver->addDriver( new AttributeDriver([__DIR__ . '/data-attributes']), - 'PHPStan\\Rules\\Doctrine\\ORMAttributes\\' + 'PHPStan\\Rules\\Doctrine\\ORMAttributes\\', ); } @@ -33,7 +33,7 @@ Type::overrideType( 'date', - DateTimeImmutableType::class + DateTimeImmutableType::class, ); return new EntityManager( @@ -41,5 +41,5 @@ 'driver' => 'pdo_sqlite', 'memory' => true, ]), - $config + $config, ); diff --git a/tests/Rules/Doctrine/ORM/slow.neon b/tests/Rules/Doctrine/ORM/slow.neon deleted file mode 100644 index bfda5b8a..00000000 --- a/tests/Rules/Doctrine/ORM/slow.neon +++ /dev/null @@ -1,3 +0,0 @@ -parameters: - doctrine: - queryBuilderFastAlgorithm: false diff --git a/tests/Rules/Properties/MissingGedmoByPhpDocPropertyAssignRuleTest.php b/tests/Rules/Properties/MissingGedmoByPhpDocPropertyAssignRuleTest.php index 683ddff3..7b66451e 100644 --- a/tests/Rules/Properties/MissingGedmoByPhpDocPropertyAssignRuleTest.php +++ b/tests/Rules/Properties/MissingGedmoByPhpDocPropertyAssignRuleTest.php @@ -7,7 +7,6 @@ use PHPStan\Rules\Rule; use PHPStan\Testing\RuleTestCase; use PHPStan\Type\Doctrine\ObjectMetadataResolver; -use const PHP_VERSION_ID; /** * @extends RuleTestCase @@ -34,10 +33,6 @@ public static function getAdditionalConfigFiles(): array public function testRule(): void { - if (PHP_VERSION_ID < 70400) { - self::markTestSkipped('Test requires PHP 7.4.'); - } - $this->analyse([__DIR__ . '/data/gedmo-property-assign-phpdoc.php'], [ // No errors expected ]); diff --git a/tests/Rules/Properties/MissingReadOnlyByPhpDocPropertyAssignRuleTest.php b/tests/Rules/Properties/MissingReadOnlyByPhpDocPropertyAssignRuleTest.php index 2f42a9a4..8a72494f 100644 --- a/tests/Rules/Properties/MissingReadOnlyByPhpDocPropertyAssignRuleTest.php +++ b/tests/Rules/Properties/MissingReadOnlyByPhpDocPropertyAssignRuleTest.php @@ -4,7 +4,6 @@ use PHPStan\Rules\Rule; use PHPStan\Testing\RuleTestCase; -use const PHP_VERSION_ID; /** * @extends RuleTestCase @@ -24,10 +23,6 @@ public static function getAdditionalConfigFiles(): array public function testRule(): void { - if (PHP_VERSION_ID < 70400) { - self::markTestSkipped('Test requires PHP 7.4.'); - } - $this->analyse([__DIR__ . '/data/missing-readonly-property-assign-phpdoc.php'], [ [ 'Class MissingReadOnlyPropertyAssignPhpDoc\EntityWithAGeneratedId has an uninitialized @readonly property $unassigned. Assign it in the constructor.', diff --git a/tests/Rules/Properties/entity-manager.php b/tests/Rules/Properties/entity-manager.php index 99f7a07e..f36730f8 100644 --- a/tests/Rules/Properties/entity-manager.php +++ b/tests/Rules/Properties/entity-manager.php @@ -17,13 +17,13 @@ $metadataDriver = new MappingDriverChain(); $metadataDriver->addDriver(new AnnotationDriver( new AnnotationReader(), - [__DIR__ . '/data'] + [__DIR__ . '/data'], ), 'PHPStan\\Rules\\Doctrine\\ORM\\'); if (PHP_VERSION_ID >= 80100) { $metadataDriver->addDriver( new AttributeDriver([__DIR__ . '/data']), - 'PHPStan\\Rules\\Doctrine\\ORMAttributes\\' + 'PHPStan\\Rules\\Doctrine\\ORMAttributes\\', ); } @@ -34,5 +34,5 @@ 'driver' => 'pdo_sqlite', 'memory' => true, ]), - $config + $config, ); diff --git a/tests/Type/Doctrine/DBAL/MysqliResultRowCountReturnTypeTest.php b/tests/Type/Doctrine/DBAL/MysqliResultRowCountReturnTypeTest.php index cdfa8490..89ac5eb6 100644 --- a/tests/Type/Doctrine/DBAL/MysqliResultRowCountReturnTypeTest.php +++ b/tests/Type/Doctrine/DBAL/MysqliResultRowCountReturnTypeTest.php @@ -15,10 +15,8 @@ public function dataFileAsserts(): iterable $versionParser = new VersionParser(); if (InstalledVersions::satisfies($versionParser, 'doctrine/dbal', '>=4.0')) { yield from $this->gatherAssertTypes(__DIR__ . '/data/mysqli-result-row-count.php'); - } elseif (InstalledVersions::satisfies($versionParser, 'doctrine/dbal', '>=3.0')) { - yield from $this->gatherAssertTypes(__DIR__ . '/data/mysqli-result-row-count-dbal-3.php'); } else { - yield from $this->gatherAssertTypes(__DIR__ . '/data/mysqli-result-row-count-dbal-2.php'); + yield from $this->gatherAssertTypes(__DIR__ . '/data/mysqli-result-row-count-dbal-3.php'); } } diff --git a/tests/Type/Doctrine/DBAL/PDOResultRowCountReturnTypeTest.php b/tests/Type/Doctrine/DBAL/PDOResultRowCountReturnTypeTest.php index d10ef8ab..0b6aa6bc 100644 --- a/tests/Type/Doctrine/DBAL/PDOResultRowCountReturnTypeTest.php +++ b/tests/Type/Doctrine/DBAL/PDOResultRowCountReturnTypeTest.php @@ -2,8 +2,6 @@ namespace PHPStan\Type\Doctrine\DBAL; -use Composer\InstalledVersions; -use Composer\Semver\VersionParser; use PHPStan\Testing\TypeInferenceTestCase; class PDOResultRowCountReturnTypeTest extends TypeInferenceTestCase @@ -12,12 +10,7 @@ class PDOResultRowCountReturnTypeTest extends TypeInferenceTestCase /** @return iterable */ public function dataFileAsserts(): iterable { - $versionParser = new VersionParser(); - if (InstalledVersions::satisfies($versionParser, 'doctrine/dbal', '<3')) { - yield from $this->gatherAssertTypes(__DIR__ . '/data/pdo-result-row-count-dbal-2.php'); - } else { - yield from $this->gatherAssertTypes(__DIR__ . '/data/pdo-result-row-count.php'); - } + yield from $this->gatherAssertTypes(__DIR__ . '/data/pdo-result-row-count.php'); } /** diff --git a/tests/Type/Doctrine/DBAL/data/mysqli-result-row-count-dbal-2.php b/tests/Type/Doctrine/DBAL/data/mysqli-result-row-count-dbal-2.php deleted file mode 100644 index 235e6142..00000000 --- a/tests/Type/Doctrine/DBAL/data/mysqli-result-row-count-dbal-2.php +++ /dev/null @@ -1,15 +0,0 @@ -rowCount()); -}; - -function (DriverResult $r): void { - assertType('int|string', $r->rowCount()); -}; diff --git a/tests/Type/Doctrine/DBAL/data/pdo-result-row-count-dbal-2.php b/tests/Type/Doctrine/DBAL/data/pdo-result-row-count-dbal-2.php deleted file mode 100644 index ff6a8cf8..00000000 --- a/tests/Type/Doctrine/DBAL/data/pdo-result-row-count-dbal-2.php +++ /dev/null @@ -1,15 +0,0 @@ -rowCount()); -}; - -function (DriverResult $r): void { - assertType('int|string', $r->rowCount()); -}; diff --git a/tests/Type/Doctrine/DBAL/mysqli.php b/tests/Type/Doctrine/DBAL/mysqli.php index 2bc11294..ce3859e5 100644 --- a/tests/Type/Doctrine/DBAL/mysqli.php +++ b/tests/Type/Doctrine/DBAL/mysqli.php @@ -13,7 +13,7 @@ $config->setMetadataCache(new ArrayCachePool()); $config->setMetadataDriverImpl(new AnnotationDriver( new AnnotationReader(), - [__DIR__ . '/data'] + [__DIR__ . '/data'], )); return new EntityManager( @@ -21,5 +21,5 @@ 'driver' => 'mysqli', 'memory' => true, ]), - $config + $config, ); diff --git a/tests/Type/Doctrine/DBAL/pdo.php b/tests/Type/Doctrine/DBAL/pdo.php index c7e48751..7b6b0da3 100644 --- a/tests/Type/Doctrine/DBAL/pdo.php +++ b/tests/Type/Doctrine/DBAL/pdo.php @@ -13,7 +13,7 @@ $config->setMetadataCache(new ArrayCachePool()); $config->setMetadataDriverImpl(new AnnotationDriver( new AnnotationReader(), - [__DIR__ . '/data'] + [__DIR__ . '/data'], )); return new EntityManager( @@ -21,5 +21,5 @@ 'driver' => 'pdo_pgsql', 'memory' => true, ]), - $config + $config, ); diff --git a/tests/Type/Doctrine/DoctrineSelectableDynamicReturnTypeExtensionTest.php b/tests/Type/Doctrine/DoctrineSelectableDynamicReturnTypeExtensionTest.php index a34c7b22..01b66d7b 100644 --- a/tests/Type/Doctrine/DoctrineSelectableDynamicReturnTypeExtensionTest.php +++ b/tests/Type/Doctrine/DoctrineSelectableDynamicReturnTypeExtensionTest.php @@ -15,8 +15,7 @@ final class DoctrineSelectableDynamicReturnTypeExtensionTest extends TestCase { - /** @var DoctrineSelectableDynamicReturnTypeExtension */ - private $extension; + private DoctrineSelectableDynamicReturnTypeExtension $extension; protected function setUp(): void { @@ -52,10 +51,8 @@ public function testGetTypeFromMethodCall(): void $scope = $this->createMock(Scope::class); $scope->method('getType')->will( self::returnCallback( - static function (): Type { - return new ObjectType(Collection::class); - } - ) + static fn (): Type => new ObjectType(Collection::class), + ), ); $var = $this->createMock(Expr::class); diff --git a/tests/Type/Doctrine/Query/QueryResultTypeWalkerHydrationModeTest.php b/tests/Type/Doctrine/Query/QueryResultTypeWalkerHydrationModeTest.php index d29f86ec..11cf5016 100644 --- a/tests/Type/Doctrine/Query/QueryResultTypeWalkerHydrationModeTest.php +++ b/tests/Type/Doctrine/Query/QueryResultTypeWalkerHydrationModeTest.php @@ -81,7 +81,7 @@ public function test(Type $expectedType, string $dql, string $methodName, ?int $ $typeBuilder, self::getContainer()->getByType(DescriptorRegistry::class), self::getContainer()->getByType(PhpVersion::class), - self::getContainer()->getByType(DriverDetector::class) + self::getContainer()->getByType(DriverDetector::class), ); $resolver = self::getContainer()->getByType(HydrationModeReturnTypeResolver::class); @@ -91,12 +91,12 @@ public function test(Type $expectedType, string $dql, string $methodName, ?int $ new ConstantIntegerType($this->getRealHydrationMode($methodName, $hydrationMode)), $typeBuilder->getIndexType(), $typeBuilder->getResultType(), - $entityManager + $entityManager, ) ?? new MixedType(); self::assertSame( $expectedType->describe(VerbosityLevel::precise()), - $type->describe(VerbosityLevel::precise()) + $type->describe(VerbosityLevel::precise()), ); $query = $entityManager->createQuery($dql); @@ -108,8 +108,8 @@ public function test(Type $expectedType, string $dql, string $methodName, ?int $ sprintf( "The inferred type\n%s\nshould accept actual type\n%s", $type->describe(VerbosityLevel::precise()), - $resultType->describe(VerbosityLevel::precise()) - ) + $resultType->describe(VerbosityLevel::precise()), + ), ); } @@ -118,8 +118,6 @@ public function test(Type $expectedType, string $dql, string $methodName, ?int $ */ public static function getTestData(): iterable { - AccessoryArrayListType::setListTypeEnabled(true); - yield 'getResult(object), full entity' => [ self::list(new ObjectType(Simple::class)), ' @@ -307,7 +305,7 @@ private static function constantArray(array $elements): Type private static function list(Type $values): Type { - return AccessoryArrayListType::intersectWith(new ArrayType(new IntegerType(), $values)); + return TypeCombinator::intersect(new ArrayType(new IntegerType(), $values), new AccessoryArrayListType()); } private static function numericString(bool $lowercase = false, bool $uppercase = false): Type diff --git a/tests/Type/Doctrine/Query/QueryResultTypeWalkerTest.php b/tests/Type/Doctrine/Query/QueryResultTypeWalkerTest.php index aa0ce591..2b8a3c14 100644 --- a/tests/Type/Doctrine/Query/QueryResultTypeWalkerTest.php +++ b/tests/Type/Doctrine/Query/QueryResultTypeWalkerTest.php @@ -63,11 +63,9 @@ final class QueryResultTypeWalkerTest extends PHPStanTestCase { - /** @var EntityManagerInterface */ - private static $em; + private static EntityManagerInterface $em; - /** @var DescriptorRegistry */ - private $descriptorRegistry; + private DescriptorRegistry $descriptorRegistry; public static function getAdditionalConfigFiles(): array { @@ -203,7 +201,7 @@ public function setUp(): void } /** @dataProvider getTestData */ - public function test(Type $expectedType, string $dql, ?string $expectedExceptionMessage = null, ?string $expectedDeprecationMessage = null): void + public function test(Type $expectedType, string $dql, ?string $expectedExceptionMessage = null): void { $em = self::$em; @@ -214,9 +212,6 @@ public function test(Type $expectedType, string $dql, ?string $expectedException if ($expectedExceptionMessage !== null) { $this->expectException(Throwable::class); $this->expectExceptionMessage($expectedExceptionMessage); - } elseif ($expectedDeprecationMessage !== null) { - $this->expectDeprecation(); - $this->expectDeprecationMessage($expectedDeprecationMessage); } QueryResultTypeWalker::walk( @@ -224,14 +219,14 @@ public function test(Type $expectedType, string $dql, ?string $expectedException $typeBuilder, $this->descriptorRegistry, self::getContainer()->getByType(PhpVersion::class), - self::getContainer()->getByType(DriverDetector::class) + self::getContainer()->getByType(DriverDetector::class), ); $type = $typeBuilder->getResultType(); self::assertSame( $expectedType->describe(VerbosityLevel::precise()), - $type->describe(VerbosityLevel::precise()) + $type->describe(VerbosityLevel::precise()), ); // Double-check our expectations @@ -248,8 +243,8 @@ public function test(Type $expectedType, string $dql, ?string $expectedException sprintf( "The inferred type\n%s\nshould accept actual type\n%s", $type->describe(VerbosityLevel::precise()), - $rowType->describe(VerbosityLevel::precise()) - ) + $rowType->describe(VerbosityLevel::precise()), + ), ); } } @@ -295,7 +290,7 @@ public function getTestData(): iterable yield 'arbitrary left join, selected' => [ TypeCombinator::union( new ObjectType(Many::class), - TypeCombinator::addNull(new ObjectType(One::class)) + TypeCombinator::addNull(new ObjectType(One::class)), ), ' SELECT m, o @@ -308,7 +303,7 @@ public function getTestData(): iterable yield 'arbitrary inner join, selected' => [ TypeCombinator::union( new ObjectType(Many::class), - new ObjectType(One::class) + new ObjectType(One::class), ), ' SELECT m, o @@ -325,7 +320,7 @@ public function getTestData(): iterable ]), $this->constantArray([ [new ConstantIntegerType(0), TypeCombinator::addNull(new ObjectType(One::class))], - ]) + ]), ), ' SELECT m AS many, o @@ -342,7 +337,7 @@ public function getTestData(): iterable ]), $this->constantArray([ [new ConstantStringType('one'), TypeCombinator::addNull(new ObjectType(One::class))], - ]) + ]), ), ' SELECT m AS many, o AS one @@ -359,7 +354,7 @@ public function getTestData(): iterable ]), $this->constantArray([ [new ConstantStringType('one'), new ObjectType(One::class)], - ]) + ]), ), ' SELECT m AS many, o AS one @@ -380,7 +375,7 @@ public function getTestData(): iterable [new ConstantIntegerType(0), new ObjectType(One::class)], [new ConstantStringType('id'), $hasDbal4 ? new IntegerType() : $this->numericString(true, true)], [new ConstantStringType('intColumn'), new IntegerType()], - ]) + ]), ), ' SELECT m, o, m.id, o.intColumn @@ -402,7 +397,7 @@ public function getTestData(): iterable [new ConstantIntegerType(0), new ObjectType(Many::class)], [new ConstantStringType('id'), $hasDbal4 ? new IntegerType() : $this->numericString(true, true)], [new ConstantStringType('intColumn'), new IntegerType()], - ]) + ]), ), ' SELECT o, m2, m, m.id, o.intColumn @@ -423,7 +418,7 @@ public function getTestData(): iterable [new ConstantStringType('one'), new ObjectType(One::class)], [new ConstantStringType('id'), $hasDbal4 ? new IntegerType() : $this->numericString(true, true)], [new ConstantStringType('intColumn'), new IntegerType()], - ]) + ]), ), ' SELECT m AS many, o AS one, m.id, o.intColumn @@ -676,42 +671,42 @@ public function getTestData(): iterable new ConstantIntegerType(1), TypeCombinator::union( $this->intOrStringified(), - new NullType() + new NullType(), ), ], [ new ConstantIntegerType(2), TypeCombinator::union( $this->intOrStringified(), - new NullType() + new NullType(), ), ], [ new ConstantIntegerType(3), TypeCombinator::union( $this->intOrStringified(), - new NullType() + new NullType(), ), ], [ new ConstantIntegerType(4), TypeCombinator::union( $this->intOrStringified(), - new NullType() + new NullType(), ), ], [ new ConstantIntegerType(5), TypeCombinator::union( $this->floatOrStringified(), - new NullType() + new NullType(), ), ], [ new ConstantIntegerType(6), TypeCombinator::union( $this->floatOrStringified(), - new NullType() + new NullType(), ), ], [ @@ -756,7 +751,7 @@ public function getTestData(): iterable new ConstantIntegerType(1), TypeCombinator::union( $this->stringifies() ? new ConstantStringType('1') : new ConstantIntegerType(1), - new NullType() + new NullType(), ), ], ]), @@ -772,14 +767,14 @@ public function getTestData(): iterable new ConstantIntegerType(1), TypeCombinator::union( new StringType(), - $this->intOrStringified() + $this->intOrStringified(), ), ], [ new ConstantIntegerType(2), TypeCombinator::union( new StringType(), - new NullType() + new NullType(), ), ], [ @@ -792,7 +787,7 @@ public function getTestData(): iterable ? $this->numericString(false, true) : TypeCombinator::union( new IntegerType(), - new FloatType() + new FloatType(), ), ], ]), @@ -811,7 +806,7 @@ public function getTestData(): iterable new ConstantIntegerType(1), TypeCombinator::union( new StringType(), - $this->stringifies() ? new ConstantStringType('0') : new ConstantIntegerType(0) + $this->stringifies() ? new ConstantStringType('0') : new ConstantIntegerType(0), ), ], ]), @@ -831,7 +826,7 @@ public function getTestData(): iterable new ConstantIntegerType(1), TypeCombinator::union( new StringType(), - $this->stringifies() ? new ConstantStringType('0') : new ConstantIntegerType(0) + $this->stringifies() ? new ConstantStringType('0') : new ConstantIntegerType(0), ), ], ]), @@ -851,7 +846,7 @@ public function getTestData(): iterable new ConstantIntegerType(1), TypeCombinator::union( $this->stringifies() ? new ConstantStringType('0') : new ConstantIntegerType(0), - $this->stringifies() ? new ConstantStringType('1') : new ConstantIntegerType(1) + $this->stringifies() ? new ConstantStringType('1') : new ConstantIntegerType(1), ), ], ]), @@ -870,7 +865,7 @@ public function getTestData(): iterable new ConstantIntegerType(1), TypeCombinator::union( $this->stringifies() ? new ConstantStringType('0') : new ConstantIntegerType(0), - $this->stringifies() ? new ConstantStringType('1') : new ConstantIntegerType(1) + $this->stringifies() ? new ConstantStringType('1') : new ConstantIntegerType(1), ), ], ]), @@ -1085,7 +1080,7 @@ public function getTestData(): iterable new ConstantIntegerType(1), new ObjectType(OneId::class), ], - ]) + ]), ), ' SELECT NEW QueryResult\Entities\ManyId(m.id), @@ -1504,7 +1499,7 @@ private function yieldConditionalDataset(): iterable $this->constantArray([ [new ConstantStringType('stringEnumColumn'), new ObjectType(StringEnum::class)], [new ConstantStringType('intEnumColumn'), new ObjectType(IntEnum::class)], - [new ConstantStringType('stringEnumListColumn'), AccessoryArrayListType::intersectWith(new ArrayType(new IntegerType(), new ObjectType(StringEnum::class)))], + [new ConstantStringType('stringEnumListColumn'), TypeCombinator::intersect(new ArrayType(new IntegerType(), new ObjectType(StringEnum::class)), new AccessoryArrayListType())], ]), ' SELECT e.stringEnumColumn, e.intEnumColumn, e.stringEnumListColumn @@ -1537,36 +1532,6 @@ private function yieldConditionalDataset(): iterable ]; } - if (PHP_VERSION_ID >= 70400) { - yield 'locate function' => [ - $this->constantArray([ - [new ConstantIntegerType(1), $this->uintOrStringified()], - [new ConstantIntegerType(2), TypeCombinator::addNull($this->uintOrStringified())], - [new ConstantIntegerType(3), TypeCombinator::addNull($this->uintOrStringified())], - [new ConstantIntegerType(4), $this->uintOrStringified()], - ]), - ' - SELECT LOCATE(m.stringColumn, m.stringColumn, 0), - LOCATE(m.stringNullColumn, m.stringColumn, 0), - LOCATE(m.stringColumn, m.stringNullColumn, 0), - LOCATE(\'f\', \'foo\', 0) - FROM QueryResult\Entities\Many m - ', - null, - InstalledVersions::satisfies(new VersionParser(), 'doctrine/dbal', '>=3.4') - ? null - : ( - PHP_VERSION_ID >= 80100 - ? 'strpos(): Passing null to parameter #2 ($needle) of type string is deprecated' - : ( - PHP_VERSION_ID < 80000 - ? 'strpos(): Non-string needles will be interpreted as strings in the future. Use an explicit chr() call to preserve the current behavior' - : null - ) - ), - ]; - } - $ormVersion = InstalledVersions::getVersion('doctrine/orm'); $hasOrm3 = $ormVersion !== null && strpos($ormVersion, '3.') === 0; diff --git a/tests/Type/Doctrine/data/QueryResult/config.neon b/tests/Type/Doctrine/data/QueryResult/config.neon index 5ce3210a..147e4f94 100644 --- a/tests/Type/Doctrine/data/QueryResult/config.neon +++ b/tests/Type/Doctrine/data/QueryResult/config.neon @@ -3,5 +3,3 @@ includes: parameters: doctrine: objectManagerLoader: entity-manager.php - featureToggles: - listType: true diff --git a/tests/Type/Doctrine/data/QueryResult/queryResult.php b/tests/Type/Doctrine/data/QueryResult/queryResult.php index de4cc5bf..54eef205 100644 --- a/tests/Type/Doctrine/data/QueryResult/queryResult.php +++ b/tests/Type/Doctrine/data/QueryResult/queryResult.php @@ -169,7 +169,7 @@ public function testReturnTypeOfQueryMethodsWithExplicitArrayHydrationMode(Entit ); assertType( - 'array', + 'array', $query->getArrayResult() ); assertType(