diff --git a/conf/bleedingEdge.neon b/conf/bleedingEdge.neon index 00e7b08f18..a9f20432b2 100644 --- a/conf/bleedingEdge.neon +++ b/conf/bleedingEdge.neon @@ -61,5 +61,6 @@ parameters: noImplicitWildcard: true tooWidePropertyType: true explicitThrow: true + absentTypeChecks: true stubFiles: - ../stubs/bleedingEdge/Rule.stub diff --git a/conf/config.neon b/conf/config.neon index bb384e9511..4097e0d85d 100644 --- a/conf/config.neon +++ b/conf/config.neon @@ -97,6 +97,7 @@ parameters: narrowPregMatches: true tooWidePropertyType: false explicitThrow: false + absentTypeChecks: false fileExtensions: - php checkAdvancedIsset: false @@ -970,6 +971,7 @@ services: arguments: checkClassCaseSensitivity: %checkClassCaseSensitivity% checkThisOnly: %checkThisOnly% + absentTypeChecks: %featureToggles.absentTypeChecks% - class: PHPStan\Rules\FunctionReturnTypeCheck diff --git a/conf/parametersSchema.neon b/conf/parametersSchema.neon index 3518d5ba4a..2f3ef3b668 100644 --- a/conf/parametersSchema.neon +++ b/conf/parametersSchema.neon @@ -92,6 +92,7 @@ parametersSchema: narrowPregMatches: bool() tooWidePropertyType: bool() explicitThrow: bool() + absentTypeChecks: bool() ]) fileExtensions: listOf(string()) checkAdvancedIsset: bool() diff --git a/src/Rules/FunctionDefinitionCheck.php b/src/Rules/FunctionDefinitionCheck.php index fbedaffbd7..50a0c99e85 100644 --- a/src/Rules/FunctionDefinitionCheck.php +++ b/src/Rules/FunctionDefinitionCheck.php @@ -52,6 +52,7 @@ public function __construct( private PhpVersion $phpVersion, private bool $checkClassCaseSensitivity, private bool $checkThisOnly, + private bool $absentTypeChecks, ) { } @@ -583,9 +584,15 @@ private function getParameterReferencedClasses(ParameterReflection $parameter): return $parameter->getNativeType()->getReferencedClasses(); } + $outTypeClasses = []; + if ($parameter->getOutType() !== null && $this->absentTypeChecks) { + $outTypeClasses = $parameter->getOutType()->getReferencedClasses(); + } + return array_merge( $parameter->getNativeType()->getReferencedClasses(), $parameter->getPhpDocType()->getReferencedClasses(), + $outTypeClasses, ); } diff --git a/tests/PHPStan/Rules/Functions/ExistingClassesInArrowFunctionTypehintsRuleTest.php b/tests/PHPStan/Rules/Functions/ExistingClassesInArrowFunctionTypehintsRuleTest.php index 2b2cec639b..2417944d1a 100644 --- a/tests/PHPStan/Rules/Functions/ExistingClassesInArrowFunctionTypehintsRuleTest.php +++ b/tests/PHPStan/Rules/Functions/ExistingClassesInArrowFunctionTypehintsRuleTest.php @@ -34,6 +34,7 @@ protected function getRule(): Rule new PhpVersion($this->phpVersionId), true, false, + true, ), new PhpVersion(PHP_VERSION_ID), ); diff --git a/tests/PHPStan/Rules/Functions/ExistingClassesInClosureTypehintsRuleTest.php b/tests/PHPStan/Rules/Functions/ExistingClassesInClosureTypehintsRuleTest.php index 439f5bdd71..86f8725573 100644 --- a/tests/PHPStan/Rules/Functions/ExistingClassesInClosureTypehintsRuleTest.php +++ b/tests/PHPStan/Rules/Functions/ExistingClassesInClosureTypehintsRuleTest.php @@ -34,6 +34,7 @@ protected function getRule(): Rule new PhpVersion($this->phpVersionId), true, false, + true, ), ); } diff --git a/tests/PHPStan/Rules/Functions/ExistingClassesInTypehintsRuleTest.php b/tests/PHPStan/Rules/Functions/ExistingClassesInTypehintsRuleTest.php index 227044f2d7..5cbe1c95eb 100644 --- a/tests/PHPStan/Rules/Functions/ExistingClassesInTypehintsRuleTest.php +++ b/tests/PHPStan/Rules/Functions/ExistingClassesInTypehintsRuleTest.php @@ -34,6 +34,7 @@ protected function getRule(): Rule new PhpVersion($this->phpVersionId), true, false, + true, ), ); } @@ -451,4 +452,22 @@ public function testTemplateInParamOut(): void ]); } + public function testParamOutClasses(): void + { + $this->analyse([__DIR__ . '/data/param-out-classes.php'], [ + [ + 'Parameter $p of function ParamOutClasses\doFoo() has invalid type ParamOutClasses\Nonexistent.', + 20, + ], + [ + 'Parameter $q of function ParamOutClasses\doFoo() has invalid type ParamOutClasses\FooTrait.', + 20, + ], + [ + 'Class ParamOutClasses\Foo referenced with incorrect case: ParamOutClasses\fOO.', + 20, + ], + ]); + } + } diff --git a/tests/PHPStan/Rules/Functions/data/param-out-classes.php b/tests/PHPStan/Rules/Functions/data/param-out-classes.php new file mode 100644 index 0000000000..8bb5c9da96 --- /dev/null +++ b/tests/PHPStan/Rules/Functions/data/param-out-classes.php @@ -0,0 +1,23 @@ +phpVersionId), true, false, + true, ), ); } @@ -471,4 +472,22 @@ public function testTemplateInParamOut(): void ]); } + public function testParamOutClasses(): void + { + $this->analyse([__DIR__ . '/data/param-out-classes.php'], [ + [ + 'Parameter $p of method ParamOutClassesMethods\Bar::doFoo() has invalid type ParamOutClassesMethods\Nonexistent.', + 23, + ], + [ + 'Parameter $q of method ParamOutClassesMethods\Bar::doFoo() has invalid type ParamOutClassesMethods\FooTrait.', + 23, + ], + [ + 'Class ParamOutClassesMethods\Foo referenced with incorrect case: ParamOutClassesMethods\fOO.', + 23, + ], + ]); + } + } diff --git a/tests/PHPStan/Rules/Methods/data/param-out-classes.php b/tests/PHPStan/Rules/Methods/data/param-out-classes.php new file mode 100644 index 0000000000..8141c6b1f8 --- /dev/null +++ b/tests/PHPStan/Rules/Methods/data/param-out-classes.php @@ -0,0 +1,29 @@ +