From 9c20c6add3a8e05bee4326424daa56a4352ca50e Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Wed, 13 Dec 2017 23:19:22 +0100 Subject: [PATCH 01/30] Add rules for checking deprecated functions and methods --- .../CallToDeprecatedFunctionRule.php | 56 ++++++++++++++ .../CallToDeprecatedMethodRule.php | 69 ++++++++++++++++++ .../CallToDeprecatedStaticMethodRule.php | 73 +++++++++++++++++++ .../CallToDeprecatedFunctionRuleTest.php | 32 ++++++++ .../CallToDeprecatedMethodRuleTest.php | 32 ++++++++ .../CallToDeprecatedStaticMethodRuleTest.php | 32 ++++++++ ...call-to-deprecated-function-definition.php | 14 ++++ .../data/call-to-deprecated-function.php | 11 +++ .../call-to-deprecated-method-definition.php | 35 +++++++++ .../data/call-to-deprecated-method.php | 11 +++ ...to-deprecated-static-method-definition.php | 35 +++++++++ .../data/call-to-deprecated-static-method.php | 9 +++ 12 files changed, 409 insertions(+) create mode 100644 src/Rules/Deprecations/CallToDeprecatedFunctionRule.php create mode 100644 src/Rules/Deprecations/CallToDeprecatedMethodRule.php create mode 100644 src/Rules/Deprecations/CallToDeprecatedStaticMethodRule.php create mode 100644 tests/Rules/Deprecations/CallToDeprecatedFunctionRuleTest.php create mode 100644 tests/Rules/Deprecations/CallToDeprecatedMethodRuleTest.php create mode 100644 tests/Rules/Deprecations/CallToDeprecatedStaticMethodRuleTest.php create mode 100644 tests/Rules/Deprecations/data/call-to-deprecated-function-definition.php create mode 100644 tests/Rules/Deprecations/data/call-to-deprecated-function.php create mode 100644 tests/Rules/Deprecations/data/call-to-deprecated-method-definition.php create mode 100644 tests/Rules/Deprecations/data/call-to-deprecated-method.php create mode 100644 tests/Rules/Deprecations/data/call-to-deprecated-static-method-definition.php create mode 100644 tests/Rules/Deprecations/data/call-to-deprecated-static-method.php diff --git a/src/Rules/Deprecations/CallToDeprecatedFunctionRule.php b/src/Rules/Deprecations/CallToDeprecatedFunctionRule.php new file mode 100644 index 00000000..c5a7c077 --- /dev/null +++ b/src/Rules/Deprecations/CallToDeprecatedFunctionRule.php @@ -0,0 +1,56 @@ +broker = $broker; + } + + public function getNodeType(): string + { + return FuncCall::class; + } + + /** + * @param FuncCall $node + * @param \PHPStan\Analyser\Scope $scope + * @return string[] errors + */ + public function processNode(Node $node, Scope $scope): array + { + if (!($node->name instanceof \PhpParser\Node\Name)) { + return []; + } + + try { + $function = $this->broker->getFunction($node->name, $scope); + } catch (\PHPStan\Broker\FunctionNotFoundException $e) { + // Other rules will notify if the function is not found + return []; + } + + if ($function->isDeprecated()) { + return [sprintf( + 'Call to deprecated function %s().', + $function->getName() + )]; + } + + return []; + } + +} diff --git a/src/Rules/Deprecations/CallToDeprecatedMethodRule.php b/src/Rules/Deprecations/CallToDeprecatedMethodRule.php new file mode 100644 index 00000000..be53f12c --- /dev/null +++ b/src/Rules/Deprecations/CallToDeprecatedMethodRule.php @@ -0,0 +1,69 @@ +broker = $broker; + } + + public function getNodeType(): string + { + return MethodCall::class; + } + + /** + * @param MethodCall $node + * @param \PHPStan\Analyser\Scope $scope + * @return string[] errors + */ + public function processNode(Node $node, Scope $scope): array + { + if (!is_string($node->name)) { + return []; + } + + $methodCalledOnType = $scope->getType($node->var); + $referencedClasses = $methodCalledOnType->getReferencedClasses(); + + foreach ($referencedClasses as $referencedClass) { + try { + $classReflection = $this->broker->getClass($referencedClass); + $methodReflection = $classReflection->getMethod($node->name, $scope); + + if (!$methodReflection instanceof DeprecatableReflection) { + continue; + } + + if ($methodReflection->isDeprecated()) { + return [sprintf( + 'Call to deprecated method %s() of class %s.', + $methodReflection->getName(), + $methodReflection->getDeclaringClass()->getName() + )]; + } + } catch (\PHPStan\Broker\ClassNotFoundException $e) { + // Other rules will notify if the class is not found + } catch (\PHPStan\Reflection\MissingMethodFromReflectionException $e) { + // Other rules will notify if the the method is not found + } + } + + return []; + } + +} diff --git a/src/Rules/Deprecations/CallToDeprecatedStaticMethodRule.php b/src/Rules/Deprecations/CallToDeprecatedStaticMethodRule.php new file mode 100644 index 00000000..0c871110 --- /dev/null +++ b/src/Rules/Deprecations/CallToDeprecatedStaticMethodRule.php @@ -0,0 +1,73 @@ +broker = $broker; + } + + public function getNodeType(): string + { + return StaticCall::class; + } + + /** + * @param StaticCall $node + * @param \PHPStan\Analyser\Scope $scope + * @return string[] errors + */ + public function processNode(Node $node, Scope $scope): array + { + if (!is_string($node->name)) { + return []; + } + + $class = $node->class; + + if (!$class instanceof Name) { + return []; + } + + $className = (string) $class; + + try { + $classReflection = $this->broker->getClass($className); + $methodReflection = $classReflection->getMethod($node->name, $scope); + + if (!$methodReflection instanceof DeprecatableReflection) { + return []; + } + + if ($methodReflection->isDeprecated()) { + return [sprintf( + 'Call to deprecated method %s() of class %s.', + $methodReflection->getName(), + $methodReflection->getDeclaringClass()->getName() + )]; + } + } catch (\PHPStan\Broker\ClassNotFoundException $e) { + // Other rules will notify if the class is not found + } catch (\PHPStan\Reflection\MissingMethodFromReflectionException $e) { + // Other rules will notify if the the method is not found + } + + return []; + } + +} diff --git a/tests/Rules/Deprecations/CallToDeprecatedFunctionRuleTest.php b/tests/Rules/Deprecations/CallToDeprecatedFunctionRuleTest.php new file mode 100644 index 00000000..61641808 --- /dev/null +++ b/tests/Rules/Deprecations/CallToDeprecatedFunctionRuleTest.php @@ -0,0 +1,32 @@ +createBroker(); + return new CallToDeprecatedFunctionRule($broker); + } + + public function testDeprecatedFunctionCall() + { + require_once __DIR__ . '/data/call-to-deprecated-function-definition.php'; + $this->analyse( + [__DIR__ . '/data/call-to-deprecated-function.php'], + [ + [ + 'Call to deprecated function CheckDeprecatedFunctionCall\deprecated_foo().', + 8, + ], + [ + 'Call to deprecated function CheckDeprecatedFunctionCall\deprecated_foo().', + 9, + ], + ] + ); + } + +} diff --git a/tests/Rules/Deprecations/CallToDeprecatedMethodRuleTest.php b/tests/Rules/Deprecations/CallToDeprecatedMethodRuleTest.php new file mode 100644 index 00000000..116b2869 --- /dev/null +++ b/tests/Rules/Deprecations/CallToDeprecatedMethodRuleTest.php @@ -0,0 +1,32 @@ +createBroker(); + return new CallToDeprecatedMethodRule($broker); + } + + public function testDeprecatedMethodCall() + { + require_once __DIR__ . '/data/call-to-deprecated-method-definition.php'; + $this->analyse( + [__DIR__ . '/data/call-to-deprecated-method.php'], + [ + [ + 'Call to deprecated method deprecatedFoo() of class CheckDeprecatedMethodCall\Foo.', + 7, + ], + [ + 'Call to deprecated method deprecatedFoo2() of class CheckDeprecatedMethodCall\Foo.', + 11, + ], + ] + ); + } + +} diff --git a/tests/Rules/Deprecations/CallToDeprecatedStaticMethodRuleTest.php b/tests/Rules/Deprecations/CallToDeprecatedStaticMethodRuleTest.php new file mode 100644 index 00000000..18eb0517 --- /dev/null +++ b/tests/Rules/Deprecations/CallToDeprecatedStaticMethodRuleTest.php @@ -0,0 +1,32 @@ +createBroker(); + return new CallToDeprecatedStaticMethodRule($broker); + } + + public function testDeprecatedStaticMethodCall() + { + require_once __DIR__ . '/data/call-to-deprecated-static-method-definition.php'; + $this->analyse( + [__DIR__ . '/data/call-to-deprecated-static-method.php'], + [ + [ + 'Call to deprecated method deprecatedFoo() of class CheckDeprecatedStaticMethodCall\Foo.', + 6, + ], + [ + 'Call to deprecated method deprecatedFoo2() of class CheckDeprecatedStaticMethodCall\Foo.', + 9, + ], + ] + ); + } + +} diff --git a/tests/Rules/Deprecations/data/call-to-deprecated-function-definition.php b/tests/Rules/Deprecations/data/call-to-deprecated-function-definition.php new file mode 100644 index 00000000..d5213e9e --- /dev/null +++ b/tests/Rules/Deprecations/data/call-to-deprecated-function-definition.php @@ -0,0 +1,14 @@ +foo(); +$foo->deprecatedFoo(); + +$bar = new Bar(); +$bar->deprecatedFoo(); +$bar->deprecatedFoo2(); diff --git a/tests/Rules/Deprecations/data/call-to-deprecated-static-method-definition.php b/tests/Rules/Deprecations/data/call-to-deprecated-static-method-definition.php new file mode 100644 index 00000000..9eb97da5 --- /dev/null +++ b/tests/Rules/Deprecations/data/call-to-deprecated-static-method-definition.php @@ -0,0 +1,35 @@ + Date: Thu, 14 Dec 2017 00:12:16 +0100 Subject: [PATCH 02/30] Implement rule to check deprecated properties --- .../AccessDeprecatedPropertyRule.php | 69 +++++++++++++++++++ .../AccessDeprecatedPropertyRuleTest.php | 32 +++++++++ .../access-deprecated-property-definition.php | 14 ++++ .../data/access-deprecated-property.php | 11 +++ 4 files changed, 126 insertions(+) create mode 100644 src/Rules/Deprecations/AccessDeprecatedPropertyRule.php create mode 100644 tests/Rules/Deprecations/AccessDeprecatedPropertyRuleTest.php create mode 100644 tests/Rules/Deprecations/data/access-deprecated-property-definition.php create mode 100644 tests/Rules/Deprecations/data/access-deprecated-property.php diff --git a/src/Rules/Deprecations/AccessDeprecatedPropertyRule.php b/src/Rules/Deprecations/AccessDeprecatedPropertyRule.php new file mode 100644 index 00000000..d84cc87a --- /dev/null +++ b/src/Rules/Deprecations/AccessDeprecatedPropertyRule.php @@ -0,0 +1,69 @@ +broker = $broker; + } + + public function getNodeType(): string + { + return PropertyFetch::class; + } + + /** + * @param PropertyFetch $node + * @param \PHPStan\Analyser\Scope $scope + * @return string[] errors + */ + public function processNode(Node $node, Scope $scope): array + { + if (!is_string($node->name)) { + return []; + } + + $propertyAccessedOnType = $scope->getType($node->var); + $referencedClasses = $propertyAccessedOnType->getReferencedClasses(); + + foreach ($referencedClasses as $referencedClass) { + try { + $classReflection = $this->broker->getClass($referencedClass); + $propertyReflection = $classReflection->getProperty($node->name, $scope); + + if (!$propertyReflection instanceof DeprecatableReflection) { + continue; + } + + if ($propertyReflection->isDeprecated()) { + return [sprintf( + 'Access to deprecated property %s of class %s.', + $node->name, + $propertyReflection->getDeclaringClass()->getName() + )]; + } + } catch (\PHPStan\Broker\ClassNotFoundException $e) { + // Other rules will notify if the class is not found + } catch (\PHPStan\Reflection\MissingPropertyFromReflectionException $e) { + // Other rules will notify if the property is not found + } + } + + return []; + } + +} diff --git a/tests/Rules/Deprecations/AccessDeprecatedPropertyRuleTest.php b/tests/Rules/Deprecations/AccessDeprecatedPropertyRuleTest.php new file mode 100644 index 00000000..3d3f3db9 --- /dev/null +++ b/tests/Rules/Deprecations/AccessDeprecatedPropertyRuleTest.php @@ -0,0 +1,32 @@ +createBroker(); + return new AccessDeprecatedPropertyRule($broker); + } + + public function testAccessDeprecatedProperty() + { + require_once __DIR__ . '/data/access-deprecated-property-definition.php'; + $this->analyse( + [__DIR__ . '/data/access-deprecated-property.php'], + [ + [ + 'Access to deprecated property deprecatedFoo of class AccessDeprecatedProperty\Foo.', + 10, + ], + [ + 'Access to deprecated property deprecatedFoo of class AccessDeprecatedProperty\Foo.', + 11, + ], + ] + ); + } + +} diff --git a/tests/Rules/Deprecations/data/access-deprecated-property-definition.php b/tests/Rules/Deprecations/data/access-deprecated-property-definition.php new file mode 100644 index 00000000..56500070 --- /dev/null +++ b/tests/Rules/Deprecations/data/access-deprecated-property-definition.php @@ -0,0 +1,14 @@ +foo = 'foo'; +echo $foo->foo; + +$foo->deprecatedFoo = 'deprecatedFoo'; +echo $foo->deprecatedFoo; From 96f3edb2471fd95c50e56d36179bfcf8253d5973 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Fri, 15 Dec 2017 20:51:46 +0100 Subject: [PATCH 03/30] Implement warning when implementing a deprecated interface --- ...mplementationOfDeprecatedInterfaceRule.php | 75 +++++++++++++++++++ ...mentationOfDeprecatedInterfaceRuleTest.php | 60 +++++++++++++++ ...ion-of-deprecated-interface-definition.php | 24 ++++++ ...recated-interface-in-anonymous-classes.php | 15 ++++ ...ion-of-deprecated-interface-in-classes.php | 18 +++++ 5 files changed, 192 insertions(+) create mode 100644 src/Rules/Deprecations/ImplementationOfDeprecatedInterfaceRule.php create mode 100644 tests/Rules/Deprecations/ImplementationOfDeprecatedInterfaceRuleTest.php create mode 100644 tests/Rules/Deprecations/data/implementation-of-deprecated-interface-definition.php create mode 100644 tests/Rules/Deprecations/data/implementation-of-deprecated-interface-in-anonymous-classes.php create mode 100644 tests/Rules/Deprecations/data/implementation-of-deprecated-interface-in-classes.php diff --git a/src/Rules/Deprecations/ImplementationOfDeprecatedInterfaceRule.php b/src/Rules/Deprecations/ImplementationOfDeprecatedInterfaceRule.php new file mode 100644 index 00000000..21b08dfb --- /dev/null +++ b/src/Rules/Deprecations/ImplementationOfDeprecatedInterfaceRule.php @@ -0,0 +1,75 @@ +broker = $broker; + } + + public function getNodeType(): string + { + return Class_::class; + } + + /** + * @param Class_ $node + * @param \PHPStan\Analyser\Scope $scope + * @return string[] errors + */ + public function processNode(Node $node, Scope $scope): array + { + $errors = []; + + $className = isset($node->namespacedName) + ? (string) $node->namespacedName + : (string) $node->name; + + try { + $class = $this->broker->getClass($className); + } catch (\PHPStan\Broker\ClassNotFoundException $e) { + return []; + } + + foreach ($node->implements as $implement) { + $interfaceName = (string) $implement; + + try { + $interface = $this->broker->getClass($interfaceName); + + if ($interface->isDeprecated()) { + if (!$class->getNativeReflection()->isAnonymous()) { + $errors[] = sprintf( + 'Implementation of deprecated interface %s in class %s.', + $interfaceName, + $className + ); + } else { + $errors[] = sprintf( + 'Implementation of deprecated interface %s in an anonymous class.', + $interfaceName + ); + } + } + } catch (\PHPStan\Broker\ClassNotFoundException $e) { + // Other rules will notify if the interface is not found + } + } + + return $errors; + } + +} diff --git a/tests/Rules/Deprecations/ImplementationOfDeprecatedInterfaceRuleTest.php b/tests/Rules/Deprecations/ImplementationOfDeprecatedInterfaceRuleTest.php new file mode 100644 index 00000000..58ba54be --- /dev/null +++ b/tests/Rules/Deprecations/ImplementationOfDeprecatedInterfaceRuleTest.php @@ -0,0 +1,60 @@ +createBroker(); + return new ImplementationOfDeprecatedInterfaceRule($broker); + } + + public function testImplementationOfDeprecatedInterfacesInClasses() + { + require_once __DIR__ . '/data/implementation-of-deprecated-interface-definition.php'; + $this->analyse( + [__DIR__ . '/data/implementation-of-deprecated-interface-in-classes.php'], + [ + [ + 'Implementation of deprecated interface ImplementationOfDeprecatedInterface\DeprecatedFooable in class ImplementationOfDeprecatedInterface\Foo2.', + 10, + ], + [ + 'Implementation of deprecated interface ImplementationOfDeprecatedInterface\DeprecatedFooable in class ImplementationOfDeprecatedInterface\Foo3.', + 15, + ], + [ + 'Implementation of deprecated interface ImplementationOfDeprecatedInterface\DeprecatedFooable2 in class ImplementationOfDeprecatedInterface\Foo3.', + 15, + ], + ] + ); + } + + public function testImplementationOfDeprecatedInterfacesInAnonymousClasses() + { + $this->markTestSkipped('The `isAnonymous` method in the ReflectionClass doesn\'t work for some reason.'); + + require_once __DIR__ . '/data/implementation-of-deprecated-interface-definition.php'; + $this->analyse( + [__DIR__ . '/data/implementation-of-deprecated-interface-in-anonymous-classes.php'], + [ + [ + 'Implementation of deprecated interface ImplementationOfDeprecatedInterface\DeprecatedFooable in an anonymous class.', + 9, + ], + [ + 'Implementation of deprecated interface ImplementationOfDeprecatedInterface\DeprecatedFooable in an anonymous class.', + 13, + ], + [ + 'Implementation of deprecated interface ImplementationOfDeprecatedInterface\DeprecatedFooable2 in an anonymous class.', + 13, + ], + ] + ); + } + +} diff --git a/tests/Rules/Deprecations/data/implementation-of-deprecated-interface-definition.php b/tests/Rules/Deprecations/data/implementation-of-deprecated-interface-definition.php new file mode 100644 index 00000000..5ca2310d --- /dev/null +++ b/tests/Rules/Deprecations/data/implementation-of-deprecated-interface-definition.php @@ -0,0 +1,24 @@ + Date: Fri, 15 Dec 2017 21:48:09 +0100 Subject: [PATCH 04/30] Implement warnings when accessing deprecated static properties --- .../AccessDeprecatedStaticPropertyRule.php | 85 +++++++++++++++++++ ...AccessDeprecatedStaticPropertyRuleTest.php | 44 ++++++++++ ...-deprecated-static-property-definition.php | 14 +++ .../access-deprecated-static-property.php | 17 ++++ 4 files changed, 160 insertions(+) create mode 100644 src/Rules/Deprecations/AccessDeprecatedStaticPropertyRule.php create mode 100644 tests/Rules/Deprecations/AccessDeprecatedStaticPropertyRuleTest.php create mode 100644 tests/Rules/Deprecations/data/access-deprecated-static-property-definition.php create mode 100644 tests/Rules/Deprecations/data/access-deprecated-static-property.php diff --git a/src/Rules/Deprecations/AccessDeprecatedStaticPropertyRule.php b/src/Rules/Deprecations/AccessDeprecatedStaticPropertyRule.php new file mode 100644 index 00000000..d21f1593 --- /dev/null +++ b/src/Rules/Deprecations/AccessDeprecatedStaticPropertyRule.php @@ -0,0 +1,85 @@ +broker = $broker; + $this->ruleLevelHelper = $ruleLevelHelper; + } + + public function getNodeType(): string + { + return StaticPropertyFetch::class; + } + + /** + * @param StaticPropertyFetch $node + * @param \PHPStan\Analyser\Scope $scope + * @return string[] errors + */ + public function processNode(Node $node, Scope $scope): array + { + if (!is_string($node->name)) { + return []; + } + + $propertyName = $node->name; + $referredClasses = []; + + if ($node->class instanceof Name) { + $referredClasses[] = (string) $node->class; + } else { + $classTypeResult = $this->ruleLevelHelper->findTypeToCheck( + $scope, + $node->class, + '%s' // We don't care about the error message + ); + + $referredClasses = $classTypeResult->getReferencedClasses(); + } + + foreach ($referredClasses as $referredClass) { + try { + $class = $this->broker->getClass($referredClass); + $property = $class->getProperty($propertyName, $scope); + } catch (\PHPStan\Broker\ClassNotFoundException $e) { + return []; + } catch (\PHPStan\Reflection\MissingPropertyFromReflectionException $e) { + return []; + } + + if ($property instanceof DeprecatableReflection && $property->isDeprecated()) { + return [sprintf( + 'Access to deprecated static property %s of class %s.', + $node->name, + $referredClass + )]; + } + } + + return []; + } + +} diff --git a/tests/Rules/Deprecations/AccessDeprecatedStaticPropertyRuleTest.php b/tests/Rules/Deprecations/AccessDeprecatedStaticPropertyRuleTest.php new file mode 100644 index 00000000..9e932d3b --- /dev/null +++ b/tests/Rules/Deprecations/AccessDeprecatedStaticPropertyRuleTest.php @@ -0,0 +1,44 @@ +createBroker(); + $ruleLevelHelper = new RuleLevelHelper($this->createBroker(), true, false, true); + + return new AccessDeprecatedStaticPropertyRule($broker, $ruleLevelHelper); + } + + public function testAccessDeprecatedStaticProperty() + { + require_once __DIR__ . '/data/access-deprecated-static-property-definition.php'; + $this->analyse( + [__DIR__ . '/data/access-deprecated-static-property.php'], + [ + [ + 'Access to deprecated static property deprecatedFoo of class AccessDeprecatedStaticProperty\Foo.', + 8, + ], + [ + 'Access to deprecated static property deprecatedFoo of class AccessDeprecatedStaticProperty\Foo.', + 9, + ], + [ + 'Access to deprecated static property deprecatedFoo of class AccessDeprecatedStaticProperty\Foo.', + 16, + ], + [ + 'Access to deprecated static property deprecatedFoo of class AccessDeprecatedStaticProperty\Foo.', + 17, + ], + ] + ); + } + +} diff --git a/tests/Rules/Deprecations/data/access-deprecated-static-property-definition.php b/tests/Rules/Deprecations/data/access-deprecated-static-property-definition.php new file mode 100644 index 00000000..563f1d5b --- /dev/null +++ b/tests/Rules/Deprecations/data/access-deprecated-static-property-definition.php @@ -0,0 +1,14 @@ + Date: Fri, 15 Dec 2017 21:53:35 +0100 Subject: [PATCH 05/30] Also test traits in AccessDeprecatedStaticPropertyRule --- .../AccessDeprecatedStaticPropertyRuleTest.php | 16 ++++++++++++++++ ...ess-deprecated-static-property-definition.php | 13 +++++++++++++ .../data/access-deprecated-static-property.php | 15 +++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/tests/Rules/Deprecations/AccessDeprecatedStaticPropertyRuleTest.php b/tests/Rules/Deprecations/AccessDeprecatedStaticPropertyRuleTest.php index 9e932d3b..8f50813b 100644 --- a/tests/Rules/Deprecations/AccessDeprecatedStaticPropertyRuleTest.php +++ b/tests/Rules/Deprecations/AccessDeprecatedStaticPropertyRuleTest.php @@ -37,6 +37,22 @@ public function testAccessDeprecatedStaticProperty() 'Access to deprecated static property deprecatedFoo of class AccessDeprecatedStaticProperty\Foo.', 17, ], + [ + 'Access to deprecated static property deprecatedFooFromTrait of class AccessDeprecatedStaticProperty\FooTrait.', + 22, + ], + [ + 'Access to deprecated static property deprecatedFooFromTrait of class AccessDeprecatedStaticProperty\FooTrait.', + 23, + ], + [ + 'Access to deprecated static property deprecatedFooFromTrait of class AccessDeprecatedStaticProperty\Foo.', + 30, + ], + [ + 'Access to deprecated static property deprecatedFooFromTrait of class AccessDeprecatedStaticProperty\Foo.', + 31, + ], ] ); } diff --git a/tests/Rules/Deprecations/data/access-deprecated-static-property-definition.php b/tests/Rules/Deprecations/data/access-deprecated-static-property-definition.php index 563f1d5b..36be08c3 100644 --- a/tests/Rules/Deprecations/data/access-deprecated-static-property-definition.php +++ b/tests/Rules/Deprecations/data/access-deprecated-static-property-definition.php @@ -2,8 +2,21 @@ namespace AccessDeprecatedStaticProperty; +trait FooTrait { + + public static $fooFromTrait; + + /** + * @deprecated + */ + public static $deprecatedFooFromTrait; + +} + class Foo { + use FooTrait; + public static $foo; /** diff --git a/tests/Rules/Deprecations/data/access-deprecated-static-property.php b/tests/Rules/Deprecations/data/access-deprecated-static-property.php index 3de385e9..79cc222d 100644 --- a/tests/Rules/Deprecations/data/access-deprecated-static-property.php +++ b/tests/Rules/Deprecations/data/access-deprecated-static-property.php @@ -15,3 +15,18 @@ $foo::$deprecatedFoo = 'foo'; echo $foo::$deprecatedFoo; + +FooTrait::$fooFromTrait = 'foo'; +echo FooTrait::$fooFromTrait; + +FooTrait::$deprecatedFooFromTrait = 'foo'; +echo FooTrait::$deprecatedFooFromTrait; + +$foo = new Foo(); + +$foo::$fooFromTrait = 'foo'; +echo $foo::$fooFromTrait; + +$foo::$deprecatedFooFromTrait = 'foo'; +echo $foo::$deprecatedFooFromTrait; + From 6d4c7b12f6f86b1f186ef48a8db420db97526439 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Sat, 16 Dec 2017 12:04:53 +0100 Subject: [PATCH 06/30] Add tests for deprecated properties from traits --- .../AccessDeprecatedPropertyRuleTest.php | 8 ++++++++ .../data/access-deprecated-property-definition.php | 14 ++++++++++++++ .../data/access-deprecated-property.php | 7 +++++++ 3 files changed, 29 insertions(+) diff --git a/tests/Rules/Deprecations/AccessDeprecatedPropertyRuleTest.php b/tests/Rules/Deprecations/AccessDeprecatedPropertyRuleTest.php index 3d3f3db9..fd0c2ddc 100644 --- a/tests/Rules/Deprecations/AccessDeprecatedPropertyRuleTest.php +++ b/tests/Rules/Deprecations/AccessDeprecatedPropertyRuleTest.php @@ -25,6 +25,14 @@ public function testAccessDeprecatedProperty() 'Access to deprecated property deprecatedFoo of class AccessDeprecatedProperty\Foo.', 11, ], + [ + 'Access to deprecated property deprecatedFooFromTrait of class AccessDeprecatedProperty\Foo.', + 16, + ], + [ + 'Access to deprecated property deprecatedFooFromTrait of class AccessDeprecatedProperty\Foo.', + 17, + ], ] ); } diff --git a/tests/Rules/Deprecations/data/access-deprecated-property-definition.php b/tests/Rules/Deprecations/data/access-deprecated-property-definition.php index 56500070..8049813b 100644 --- a/tests/Rules/Deprecations/data/access-deprecated-property-definition.php +++ b/tests/Rules/Deprecations/data/access-deprecated-property-definition.php @@ -2,8 +2,22 @@ namespace AccessDeprecatedProperty; +trait FooTrait +{ + + public $fooFromTrait; + + /** + * @deprecated + */ + public $deprecatedFooFromTrait; + +} + class Foo { + use FooTrait; + public $foo; /** diff --git a/tests/Rules/Deprecations/data/access-deprecated-property.php b/tests/Rules/Deprecations/data/access-deprecated-property.php index bf76c21f..e1cc8b54 100644 --- a/tests/Rules/Deprecations/data/access-deprecated-property.php +++ b/tests/Rules/Deprecations/data/access-deprecated-property.php @@ -9,3 +9,10 @@ $foo->deprecatedFoo = 'deprecatedFoo'; echo $foo->deprecatedFoo; + +$foo->fooFromTrait = 'fooFromTrait'; +echo $foo->fooFromTrait; + +$foo->deprecatedFooFromTrait = 'deprecatedFooFromTrait'; +echo $foo->deprecatedFooFromTrait; + From 6fab32ed4a53861f579a34ee67eb5c9181cd876b Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Sat, 16 Dec 2017 12:08:44 +0100 Subject: [PATCH 07/30] Add tests for deprecated methods from traits --- .../CallToDeprecatedMethodRuleTest.php | 4 ++++ .../call-to-deprecated-method-definition.php | 24 +++++++++++++++++-- .../data/call-to-deprecated-method.php | 3 +++ 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/tests/Rules/Deprecations/CallToDeprecatedMethodRuleTest.php b/tests/Rules/Deprecations/CallToDeprecatedMethodRuleTest.php index 116b2869..5240d3dc 100644 --- a/tests/Rules/Deprecations/CallToDeprecatedMethodRuleTest.php +++ b/tests/Rules/Deprecations/CallToDeprecatedMethodRuleTest.php @@ -25,6 +25,10 @@ public function testDeprecatedMethodCall() 'Call to deprecated method deprecatedFoo2() of class CheckDeprecatedMethodCall\Foo.', 11, ], + [ + 'Call to deprecated method deprecatedFooFromTrait() of class CheckDeprecatedMethodCall\Foo.', + 14, + ], ] ); } diff --git a/tests/Rules/Deprecations/data/call-to-deprecated-method-definition.php b/tests/Rules/Deprecations/data/call-to-deprecated-method-definition.php index 5f2a2f77..9e0889a2 100644 --- a/tests/Rules/Deprecations/data/call-to-deprecated-method-definition.php +++ b/tests/Rules/Deprecations/data/call-to-deprecated-method-definition.php @@ -2,7 +2,28 @@ namespace CheckDeprecatedMethodCall; -class Foo { +trait FooTrait +{ + + public function fooFromTrait() + { + + } + + /** + * @deprecated + */ + public function deprecatedFooFromTrait() + { + + } + +} + +class Foo +{ + + use FooTrait; public function foo() { @@ -32,4 +53,3 @@ public function deprecatedFoo() } } - diff --git a/tests/Rules/Deprecations/data/call-to-deprecated-method.php b/tests/Rules/Deprecations/data/call-to-deprecated-method.php index a322d077..4e57eab5 100644 --- a/tests/Rules/Deprecations/data/call-to-deprecated-method.php +++ b/tests/Rules/Deprecations/data/call-to-deprecated-method.php @@ -9,3 +9,6 @@ $bar = new Bar(); $bar->deprecatedFoo(); $bar->deprecatedFoo2(); + +$foo->fooFromTrait(); +$foo->deprecatedFooFromTrait(); From a2ef842bf2df872879e93fd2652c684d85776419 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Sat, 16 Dec 2017 12:15:31 +0100 Subject: [PATCH 08/30] Fix spacing in deprecation tests --- .../data/call-to-deprecated-function-definition.php | 2 ++ .../data/call-to-deprecated-method-definition.php | 4 ++++ .../data/call-to-deprecated-static-method-definition.php | 4 ++++ 3 files changed, 10 insertions(+) diff --git a/tests/Rules/Deprecations/data/call-to-deprecated-function-definition.php b/tests/Rules/Deprecations/data/call-to-deprecated-function-definition.php index d5213e9e..c56fd194 100644 --- a/tests/Rules/Deprecations/data/call-to-deprecated-function-definition.php +++ b/tests/Rules/Deprecations/data/call-to-deprecated-function-definition.php @@ -4,6 +4,7 @@ function foo() { + } /** @@ -11,4 +12,5 @@ function foo() */ function deprecated_foo() { + } diff --git a/tests/Rules/Deprecations/data/call-to-deprecated-method-definition.php b/tests/Rules/Deprecations/data/call-to-deprecated-method-definition.php index 9e0889a2..598309f4 100644 --- a/tests/Rules/Deprecations/data/call-to-deprecated-method-definition.php +++ b/tests/Rules/Deprecations/data/call-to-deprecated-method-definition.php @@ -27,6 +27,7 @@ class Foo public function foo() { + } /** @@ -34,6 +35,7 @@ public function foo() */ public function deprecatedFoo() { + } /** @@ -41,6 +43,7 @@ public function deprecatedFoo() */ public function deprecatedFoo2() { + } } @@ -50,6 +53,7 @@ class Bar extends Foo public function deprecatedFoo() { + } } diff --git a/tests/Rules/Deprecations/data/call-to-deprecated-static-method-definition.php b/tests/Rules/Deprecations/data/call-to-deprecated-static-method-definition.php index 9eb97da5..1525caf5 100644 --- a/tests/Rules/Deprecations/data/call-to-deprecated-static-method-definition.php +++ b/tests/Rules/Deprecations/data/call-to-deprecated-static-method-definition.php @@ -6,6 +6,7 @@ class Foo { public static function foo() { + } /** @@ -13,6 +14,7 @@ public static function foo() */ public static function deprecatedFoo() { + } /** @@ -20,6 +22,7 @@ public static function deprecatedFoo() */ public static function deprecatedFoo2() { + } } @@ -29,6 +32,7 @@ class Bar extends Foo public static function deprecatedFoo() { + } } From e104c5b14f5248e741b47c0b49b3d860dcb740a7 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Sat, 16 Dec 2017 12:46:04 +0100 Subject: [PATCH 09/30] Add rule to notify when inheriting from a deprecated class --- .../InheritanceOfDeprecatedClassRule.php | 77 +++++++++++++++++++ .../InheritanceOfDeprecatedClassRuleTest.php | 44 +++++++++++ ...ritance-of-deprecated-class-definition.php | 16 ++++ ...-deprecated-class-in-anonymous-classes.php | 11 +++ ...ritance-of-deprecated-class-in-classes.php | 13 ++++ 5 files changed, 161 insertions(+) create mode 100644 src/Rules/Deprecations/InheritanceOfDeprecatedClassRule.php create mode 100644 tests/Rules/Deprecations/InheritanceOfDeprecatedClassRuleTest.php create mode 100644 tests/Rules/Deprecations/data/Inheritance-of-deprecated-class-definition.php create mode 100644 tests/Rules/Deprecations/data/inheritance-of-deprecated-class-in-anonymous-classes.php create mode 100644 tests/Rules/Deprecations/data/inheritance-of-deprecated-class-in-classes.php diff --git a/src/Rules/Deprecations/InheritanceOfDeprecatedClassRule.php b/src/Rules/Deprecations/InheritanceOfDeprecatedClassRule.php new file mode 100644 index 00000000..d18aa543 --- /dev/null +++ b/src/Rules/Deprecations/InheritanceOfDeprecatedClassRule.php @@ -0,0 +1,77 @@ +broker = $broker; + } + + public function getNodeType(): string + { + return Class_::class; + } + + /** + * @param Class_ $node + * @param \PHPStan\Analyser\Scope $scope + * @return string[] errors + */ + public function processNode(Node $node, Scope $scope): array + { + if ($node->extends === null) { + return []; + } + + $errors = []; + + $className = isset($node->namespacedName) + ? (string) $node->namespacedName + : (string) $node->name; + + try { + $class = $this->broker->getClass($className); + } catch (\PHPStan\Broker\ClassNotFoundException $e) { + return []; + } + + $parentClassName = (string) $node->extends; + + try { + $parentClass = $this->broker->getClass($parentClassName); + + if ($parentClass->isDeprecated()) { + if (!$class->getNativeReflection()->isAnonymous()) { + $errors[] = sprintf( + 'Inheritance of deprecated class %s in class %s.', + $parentClassName, + $className + ); + } else { + $errors[] = sprintf( + 'Inheritance of deprecated class %s in an anonymous class.', + $parentClassName + ); + } + } + } catch (\PHPStan\Broker\ClassNotFoundException $e) { + // Other rules will notify if the interface is not found + } + + return $errors; + } + +} diff --git a/tests/Rules/Deprecations/InheritanceOfDeprecatedClassRuleTest.php b/tests/Rules/Deprecations/InheritanceOfDeprecatedClassRuleTest.php new file mode 100644 index 00000000..ef6d076a --- /dev/null +++ b/tests/Rules/Deprecations/InheritanceOfDeprecatedClassRuleTest.php @@ -0,0 +1,44 @@ +createBroker(); + return new InheritanceOfDeprecatedClassRule($broker); + } + + public function testImplementationOfDeprecatedInterfacesInClasses() + { + require_once __DIR__ . '/data/inheritance-of-deprecated-class-definition.php'; + $this->analyse( + [__DIR__ . '/data/inheritance-of-deprecated-class-in-classes.php'], + [ + [ + 'Inheritance of deprecated class InheritanceOfDeprecatedClass\DeprecatedFoo in class InheritanceOfDeprecatedClass\Bar2.', + 10, + ], + ] + ); + } + + public function testImplementationOfDeprecatedInterfacesInAnonymousClasses() + { + $this->markTestSkipped('The `isAnonymous` method in the ReflectionClass doesn\'t work for some reason.'); + + require_once __DIR__ . '/data/inheritance-of-deprecated-class-definition.php'; + $this->analyse( + [__DIR__ . '/data/inheritance-of-deprecated-class-in-anonymous-classes.php'], + [ + [ + 'Inheritance of deprecated class InheritanceOfDeprecatedClass\DeprecatedFoo in an anonymous class.', + 9, + ], + ] + ); + } + +} diff --git a/tests/Rules/Deprecations/data/Inheritance-of-deprecated-class-definition.php b/tests/Rules/Deprecations/data/Inheritance-of-deprecated-class-definition.php new file mode 100644 index 00000000..85bbc8d0 --- /dev/null +++ b/tests/Rules/Deprecations/data/Inheritance-of-deprecated-class-definition.php @@ -0,0 +1,16 @@ + Date: Sat, 16 Dec 2017 13:31:14 +0100 Subject: [PATCH 10/30] Add rules to warn when instantiating deprecated classes --- .../InstantiationOfDeprecatedClassRule.php | 59 +++++++++++++++++++ ...InstantiationOfDeprecatedClassRuleTest.php | 28 +++++++++ ...tiation-of-deprecated-class-definition.php | 16 +++++ .../instantiation-of-deprecated-class.php | 6 ++ 4 files changed, 109 insertions(+) create mode 100644 src/Rules/Deprecations/InstantiationOfDeprecatedClassRule.php create mode 100644 tests/Rules/Deprecations/InstantiationOfDeprecatedClassRuleTest.php create mode 100644 tests/Rules/Deprecations/data/instantiation-of-deprecated-class-definition.php create mode 100644 tests/Rules/Deprecations/data/instantiation-of-deprecated-class.php diff --git a/src/Rules/Deprecations/InstantiationOfDeprecatedClassRule.php b/src/Rules/Deprecations/InstantiationOfDeprecatedClassRule.php new file mode 100644 index 00000000..78fbf461 --- /dev/null +++ b/src/Rules/Deprecations/InstantiationOfDeprecatedClassRule.php @@ -0,0 +1,59 @@ +broker = $broker; + } + + public function getNodeType(): string + { + return New_::class; + } + + /** + * @param New_ $node + * @param \PHPStan\Analyser\Scope $scope + * @return string[] errors + */ + public function processNode(Node $node, Scope $scope): array + { + if (!$node->class instanceof Name) { + return []; + } + + $className = (string) $node->class; + + try { + $class = $this->broker->getClass($className); + } catch (ClassNotFoundException $e) { + return []; + } + + if (!$class->isDeprecated()) { + return []; + } + + return [sprintf( + 'Instantiation of deprecated class %s.', + $className + )]; + } + +} diff --git a/tests/Rules/Deprecations/InstantiationOfDeprecatedClassRuleTest.php b/tests/Rules/Deprecations/InstantiationOfDeprecatedClassRuleTest.php new file mode 100644 index 00000000..9fb86628 --- /dev/null +++ b/tests/Rules/Deprecations/InstantiationOfDeprecatedClassRuleTest.php @@ -0,0 +1,28 @@ +createBroker(); + return new InstantiationOfDeprecatedClassRule($broker); + } + + public function testInstantiationOfDeprecatedClass() + { + require_once __DIR__ . '/data/instantiation-of-deprecated-class-definition.php'; + $this->analyse( + [__DIR__ . '/data/instantiation-of-deprecated-class.php'], + [ + [ + 'Instantiation of deprecated class InstantiationOfDeprecatedClass\DeprecatedFoo.', + 6, + ], + ] + ); + } + +} diff --git a/tests/Rules/Deprecations/data/instantiation-of-deprecated-class-definition.php b/tests/Rules/Deprecations/data/instantiation-of-deprecated-class-definition.php new file mode 100644 index 00000000..6b1cc5fc --- /dev/null +++ b/tests/Rules/Deprecations/data/instantiation-of-deprecated-class-definition.php @@ -0,0 +1,16 @@ + Date: Sat, 16 Dec 2017 13:33:29 +0100 Subject: [PATCH 11/30] Fix formatting and naming --- src/Rules/Deprecations/InstantiationOfDeprecatedClassRule.php | 3 +-- .../Deprecations/InheritanceOfDeprecatedClassRuleTest.php | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Rules/Deprecations/InstantiationOfDeprecatedClassRule.php b/src/Rules/Deprecations/InstantiationOfDeprecatedClassRule.php index 78fbf461..ce8b8d9f 100644 --- a/src/Rules/Deprecations/InstantiationOfDeprecatedClassRule.php +++ b/src/Rules/Deprecations/InstantiationOfDeprecatedClassRule.php @@ -7,7 +7,6 @@ use PhpParser\Node\Name; use PHPStan\Analyser\Scope; use PHPStan\Broker\Broker; -use PHPStan\Broker\ClassNotFoundException; class InstantiationOfDeprecatedClassRule implements \PHPStan\Rules\Rule { @@ -42,7 +41,7 @@ public function processNode(Node $node, Scope $scope): array try { $class = $this->broker->getClass($className); - } catch (ClassNotFoundException $e) { + } catch (\PHPStan\Broker\ClassNotFoundException $e) { return []; } diff --git a/tests/Rules/Deprecations/InheritanceOfDeprecatedClassRuleTest.php b/tests/Rules/Deprecations/InheritanceOfDeprecatedClassRuleTest.php index ef6d076a..633774ba 100644 --- a/tests/Rules/Deprecations/InheritanceOfDeprecatedClassRuleTest.php +++ b/tests/Rules/Deprecations/InheritanceOfDeprecatedClassRuleTest.php @@ -11,7 +11,7 @@ protected function getRule(): \PHPStan\Rules\Rule return new InheritanceOfDeprecatedClassRule($broker); } - public function testImplementationOfDeprecatedInterfacesInClasses() + public function testInheritanceOfDeprecatedClassInClasses() { require_once __DIR__ . '/data/inheritance-of-deprecated-class-definition.php'; $this->analyse( @@ -25,7 +25,7 @@ public function testImplementationOfDeprecatedInterfacesInClasses() ); } - public function testImplementationOfDeprecatedInterfacesInAnonymousClasses() + public function testInheritanceOfDeprecatedClassInAnonymousClasses() { $this->markTestSkipped('The `isAnonymous` method in the ReflectionClass doesn\'t work for some reason.'); From 2ca155a3f7324340d409c333dd33fb575b8be7b7 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Sat, 16 Dec 2017 14:13:15 +0100 Subject: [PATCH 12/30] Add rule to notify when using a deprecated trait --- .../UsageOfDeprecatedTraitRule.php | 59 +++++++++++++++++++ .../UsageOfDeprecatedTraitRuleTest.php | 32 ++++++++++ .../usage-of-deprecated-trait-definition.php | 16 +++++ .../data/usage-of-deprecated-trait.php | 19 ++++++ 4 files changed, 126 insertions(+) create mode 100644 src/Rules/Deprecations/UsageOfDeprecatedTraitRule.php create mode 100644 tests/Rules/Deprecations/UsageOfDeprecatedTraitRuleTest.php create mode 100644 tests/Rules/Deprecations/data/usage-of-deprecated-trait-definition.php create mode 100644 tests/Rules/Deprecations/data/usage-of-deprecated-trait.php diff --git a/src/Rules/Deprecations/UsageOfDeprecatedTraitRule.php b/src/Rules/Deprecations/UsageOfDeprecatedTraitRule.php new file mode 100644 index 00000000..e915f311 --- /dev/null +++ b/src/Rules/Deprecations/UsageOfDeprecatedTraitRule.php @@ -0,0 +1,59 @@ +broker = $broker; + } + + public function getNodeType(): string + { + return TraitUse::class; + } + + /** + * @param TraitUse $node + * @param \PHPStan\Analyser\Scope $scope + * @return string[] errors + */ + public function processNode(Node $node, Scope $scope): array + { + $errors = []; + $className = $scope->getClassReflection()->getName(); + + foreach ($node->traits as $traitNameNode) { + $traitName = (string) $traitNameNode; + + try { + $trait = $this->broker->getClass($traitName); + + if ($trait->isDeprecated()) { + $errors[] = sprintf( + 'Usage of deprecated trait %s in class %s.', + $traitName, + $className + ); + } + } catch (\PHPStan\Broker\ClassNotFoundException $e) { + continue; + } + } + + return $errors; + } + +} diff --git a/tests/Rules/Deprecations/UsageOfDeprecatedTraitRuleTest.php b/tests/Rules/Deprecations/UsageOfDeprecatedTraitRuleTest.php new file mode 100644 index 00000000..d0050a91 --- /dev/null +++ b/tests/Rules/Deprecations/UsageOfDeprecatedTraitRuleTest.php @@ -0,0 +1,32 @@ +createBroker(); + return new UsageOfDeprecatedTraitRule($broker); + } + + public function testUsageOfDeprecatedTrait() + { + require_once __DIR__ . '/data/usage-of-deprecated-trait-definition.php'; + $this->analyse( + [__DIR__ . '/data/usage-of-deprecated-trait.php'], + [ + [ + 'Usage of deprecated trait UsageOfDeprecatedTrait\DeprecatedFooTrait in class UsageOfDeprecatedTrait\Foo.', + 9, + ], + [ + 'Usage of deprecated trait UsageOfDeprecatedTrait\DeprecatedFooTrait in class UsageOfDeprecatedTrait\Foo2.', + 16, + ], + ] + ); + } + +} diff --git a/tests/Rules/Deprecations/data/usage-of-deprecated-trait-definition.php b/tests/Rules/Deprecations/data/usage-of-deprecated-trait-definition.php new file mode 100644 index 00000000..03113170 --- /dev/null +++ b/tests/Rules/Deprecations/data/usage-of-deprecated-trait-definition.php @@ -0,0 +1,16 @@ + Date: Sat, 16 Dec 2017 15:46:30 +0100 Subject: [PATCH 13/30] Add support for parent static method calls in deprecation check --- .../CallToDeprecatedStaticMethodRule.php | 38 +++++++++++-------- .../CallToDeprecatedStaticMethodRuleTest.php | 4 ++ ...to-deprecated-static-method-definition.php | 3 +- .../data/call-to-deprecated-static-method.php | 10 +++++ 4 files changed, 38 insertions(+), 17 deletions(-) diff --git a/src/Rules/Deprecations/CallToDeprecatedStaticMethodRule.php b/src/Rules/Deprecations/CallToDeprecatedStaticMethodRule.php index 0c871110..798a2f31 100644 --- a/src/Rules/Deprecations/CallToDeprecatedStaticMethodRule.php +++ b/src/Rules/Deprecations/CallToDeprecatedStaticMethodRule.php @@ -38,36 +38,42 @@ public function processNode(Node $node, Scope $scope): array return []; } - $class = $node->class; - - if (!$class instanceof Name) { + if (!$node->class instanceof Name) { return []; } - $className = (string) $class; + $className = (string) $node->class; + + if ($className === 'parent') { + $class = $scope->getClassReflection(); + $class = $class->getParentClass(); + } else { + try { + $class = $this->broker->getClass($className); + }catch (\PHPStan\Broker\ClassNotFoundException $e) { + return []; + } + } try { - $classReflection = $this->broker->getClass($className); - $methodReflection = $classReflection->getMethod($node->name, $scope); + $methodReflection = $class->getMethod($node->name, $scope); if (!$methodReflection instanceof DeprecatableReflection) { return []; } - if ($methodReflection->isDeprecated()) { - return [sprintf( - 'Call to deprecated method %s() of class %s.', - $methodReflection->getName(), - $methodReflection->getDeclaringClass()->getName() - )]; + if (!$methodReflection->isDeprecated()) { + return []; } - } catch (\PHPStan\Broker\ClassNotFoundException $e) { - // Other rules will notify if the class is not found } catch (\PHPStan\Reflection\MissingMethodFromReflectionException $e) { - // Other rules will notify if the the method is not found + return []; } - return []; + return [sprintf( + 'Call to deprecated method %s() of class %s.', + $methodReflection->getName(), + $methodReflection->getDeclaringClass()->getName() + )]; } } diff --git a/tests/Rules/Deprecations/CallToDeprecatedStaticMethodRuleTest.php b/tests/Rules/Deprecations/CallToDeprecatedStaticMethodRuleTest.php index 18eb0517..64276f0f 100644 --- a/tests/Rules/Deprecations/CallToDeprecatedStaticMethodRuleTest.php +++ b/tests/Rules/Deprecations/CallToDeprecatedStaticMethodRuleTest.php @@ -25,6 +25,10 @@ public function testDeprecatedStaticMethodCall() 'Call to deprecated method deprecatedFoo2() of class CheckDeprecatedStaticMethodCall\Foo.', 9, ], + [ + 'Call to deprecated method deprecatedFoo() of class CheckDeprecatedStaticMethodCall\Foo.', + 16, + ], ] ); } diff --git a/tests/Rules/Deprecations/data/call-to-deprecated-static-method-definition.php b/tests/Rules/Deprecations/data/call-to-deprecated-static-method-definition.php index 1525caf5..b4c3cac2 100644 --- a/tests/Rules/Deprecations/data/call-to-deprecated-static-method-definition.php +++ b/tests/Rules/Deprecations/data/call-to-deprecated-static-method-definition.php @@ -2,7 +2,8 @@ namespace CheckDeprecatedStaticMethodCall; -class Foo { +class Foo +{ public static function foo() { diff --git a/tests/Rules/Deprecations/data/call-to-deprecated-static-method.php b/tests/Rules/Deprecations/data/call-to-deprecated-static-method.php index 4441a9df..c49eaa28 100644 --- a/tests/Rules/Deprecations/data/call-to-deprecated-static-method.php +++ b/tests/Rules/Deprecations/data/call-to-deprecated-static-method.php @@ -7,3 +7,13 @@ Bar::deprecatedFoo(); Bar::deprecatedFoo2(); + +class Bar2 extends Foo +{ + + public static function deprecatedFoo() + { + parent::deprecatedFoo(); + } + +} From 31a8dc29cf09e4846d2a7f50e03fc8e3d838f719 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Sat, 16 Dec 2017 15:49:03 +0100 Subject: [PATCH 14/30] Add check for false positive in static parent method call --- .../Rules/Deprecations/CallToDeprecatedStaticMethodRuleTest.php | 2 +- .../Deprecations/data/call-to-deprecated-static-method.php | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/Rules/Deprecations/CallToDeprecatedStaticMethodRuleTest.php b/tests/Rules/Deprecations/CallToDeprecatedStaticMethodRuleTest.php index 64276f0f..c12e10ad 100644 --- a/tests/Rules/Deprecations/CallToDeprecatedStaticMethodRuleTest.php +++ b/tests/Rules/Deprecations/CallToDeprecatedStaticMethodRuleTest.php @@ -27,7 +27,7 @@ public function testDeprecatedStaticMethodCall() ], [ 'Call to deprecated method deprecatedFoo() of class CheckDeprecatedStaticMethodCall\Foo.', - 16, + 17, ], ] ); diff --git a/tests/Rules/Deprecations/data/call-to-deprecated-static-method.php b/tests/Rules/Deprecations/data/call-to-deprecated-static-method.php index c49eaa28..0fa6390a 100644 --- a/tests/Rules/Deprecations/data/call-to-deprecated-static-method.php +++ b/tests/Rules/Deprecations/data/call-to-deprecated-static-method.php @@ -13,6 +13,7 @@ class Bar2 extends Foo public static function deprecatedFoo() { + parent::foo(); parent::deprecatedFoo(); } From 40a2227b8915d724ff736dc82f0439c3e2d04dc9 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Sat, 16 Dec 2017 16:20:07 +0100 Subject: [PATCH 15/30] Fix possible null pointer in CallToDeprecatedStaticMethodRule --- src/Rules/Deprecations/CallToDeprecatedStaticMethodRule.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Rules/Deprecations/CallToDeprecatedStaticMethodRule.php b/src/Rules/Deprecations/CallToDeprecatedStaticMethodRule.php index 798a2f31..076b3c96 100644 --- a/src/Rules/Deprecations/CallToDeprecatedStaticMethodRule.php +++ b/src/Rules/Deprecations/CallToDeprecatedStaticMethodRule.php @@ -47,10 +47,14 @@ public function processNode(Node $node, Scope $scope): array if ($className === 'parent') { $class = $scope->getClassReflection(); $class = $class->getParentClass(); + + if ($class === false) { + return []; + } } else { try { $class = $this->broker->getClass($className); - }catch (\PHPStan\Broker\ClassNotFoundException $e) { + } catch (\PHPStan\Broker\ClassNotFoundException $e) { return []; } } From 49f33529ffb4616207c08738aafa1c8d12f70820 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Sat, 16 Dec 2017 16:39:02 +0100 Subject: [PATCH 16/30] Add test to notify when fetching class constant of deprecated class --- ...etchingClassConstOfDeprecatedClassRule.php | 58 +++++++++++++++++++ ...ingClassConstOfDeprecatedClassRuleTest.php | 28 +++++++++ ...s-const-of-deprecated-class-definition.php | 16 +++++ ...tching-class-const-of-deprecated-class.php | 6 ++ 4 files changed, 108 insertions(+) create mode 100644 src/Rules/Deprecations/FetchingClassConstOfDeprecatedClassRule.php create mode 100644 tests/Rules/Deprecations/FetchingClassConstOfDeprecatedClassRuleTest.php create mode 100644 tests/Rules/Deprecations/data/fetching-class-const-of-deprecated-class-definition.php create mode 100644 tests/Rules/Deprecations/data/fetching-class-const-of-deprecated-class.php diff --git a/src/Rules/Deprecations/FetchingClassConstOfDeprecatedClassRule.php b/src/Rules/Deprecations/FetchingClassConstOfDeprecatedClassRule.php new file mode 100644 index 00000000..def830f7 --- /dev/null +++ b/src/Rules/Deprecations/FetchingClassConstOfDeprecatedClassRule.php @@ -0,0 +1,58 @@ +broker = $broker; + } + + public function getNodeType(): string + { + return ClassConstFetch::class; + } + + /** + * @param ClassConstFetch $node + * @param \PHPStan\Analyser\Scope $scope + * @return string[] errors + */ + public function processNode(Node $node, Scope $scope): array + { + if (!$node->class instanceof Name) { + return []; + } + + $className = (string) $node->class; + + try { + $class = $this->broker->getClass($className); + } catch (\PHPStan\Broker\ClassNotFoundException $e) { + return []; + } + + if (!$class->isDeprecated()) { + return []; + } + + return [sprintf( + 'Fetching class constant of deprecated class %s.', + $className + )]; + } + +} diff --git a/tests/Rules/Deprecations/FetchingClassConstOfDeprecatedClassRuleTest.php b/tests/Rules/Deprecations/FetchingClassConstOfDeprecatedClassRuleTest.php new file mode 100644 index 00000000..cea64835 --- /dev/null +++ b/tests/Rules/Deprecations/FetchingClassConstOfDeprecatedClassRuleTest.php @@ -0,0 +1,28 @@ +createBroker(); + return new FetchingClassConstOfDeprecatedClassRule($broker); + } + + public function testFetchingClassConstOfDeprecatedClass() + { + require_once __DIR__ . '/data/fetching-class-const-of-deprecated-class-definition.php'; + $this->analyse( + [__DIR__ . '/data/fetching-class-const-of-deprecated-class.php'], + [ + [ + 'Fetching class constant of deprecated class FetchingClassConstOfDeprecatedClass\DeprecatedFoo.', + 6, + ], + ] + ); + } + +} diff --git a/tests/Rules/Deprecations/data/fetching-class-const-of-deprecated-class-definition.php b/tests/Rules/Deprecations/data/fetching-class-const-of-deprecated-class-definition.php new file mode 100644 index 00000000..3e1fcdeb --- /dev/null +++ b/tests/Rules/Deprecations/data/fetching-class-const-of-deprecated-class-definition.php @@ -0,0 +1,16 @@ + Date: Mon, 18 Dec 2017 22:10:05 +0100 Subject: [PATCH 17/30] Notify when calling method on deprecated class --- .../CallToDeprecatedStaticMethodRule.php | 74 ++++++++++++------- .../CallToDeprecatedStaticMethodRuleTest.php | 22 +++++- ...to-deprecated-static-method-definition.php | 7 ++ .../data/call-to-deprecated-static-method.php | 4 + 4 files changed, 81 insertions(+), 26 deletions(-) diff --git a/src/Rules/Deprecations/CallToDeprecatedStaticMethodRule.php b/src/Rules/Deprecations/CallToDeprecatedStaticMethodRule.php index 076b3c96..476fe3f0 100644 --- a/src/Rules/Deprecations/CallToDeprecatedStaticMethodRule.php +++ b/src/Rules/Deprecations/CallToDeprecatedStaticMethodRule.php @@ -7,6 +7,7 @@ use PhpParser\Node\Name; use PHPStan\Analyser\Scope; use PHPStan\Broker\Broker; +use PHPStan\Reflection\ClassReflection; use PHPStan\Reflection\DeprecatableReflection; class CallToDeprecatedStaticMethodRule implements \PHPStan\Rules\Rule @@ -43,41 +44,64 @@ public function processNode(Node $node, Scope $scope): array } $className = (string) $node->class; + $class = $this->getClassWithClassName($className, $scope); - if ($className === 'parent') { - $class = $scope->getClassReflection(); - $class = $class->getParentClass(); - - if ($class === false) { - return []; - } - } else { - try { - $class = $this->broker->getClass($className); - } catch (\PHPStan\Broker\ClassNotFoundException $e) { - return []; - } + if ($class === null) { + return []; } try { $methodReflection = $class->getMethod($node->name, $scope); + } catch (\PHPStan\Reflection\MissingMethodFromReflectionException $e) { + return []; + } - if (!$methodReflection instanceof DeprecatableReflection) { - return []; - } + $errors = []; + + if ($class->isDeprecated()) { + $errors[] = sprintf( + 'Call to method %s() of deprecated class %s.', + $methodReflection->getName(), + $methodReflection->getDeclaringClass()->getName() + ); + } + + if ($methodReflection instanceof DeprecatableReflection && $methodReflection->isDeprecated()) { + $errors[] = sprintf( + 'Call to deprecated method %s() of class %s.', + $methodReflection->getName(), + $methodReflection->getDeclaringClass()->getName() + ); + } - if (!$methodReflection->isDeprecated()) { - return []; + return $errors; + } + + /** + * @param string $className + * @param Scope $scope + * @return ClassReflection|null + */ + private function getClassWithClassName(string $className, Scope $scope) + { + if ($className === 'parent') { + if (!$scope->isInClass()) { + return null; } - } catch (\PHPStan\Reflection\MissingMethodFromReflectionException $e) { - return []; + + $class = $scope->getClassReflection(); + $class = $class->getParentClass(); + + return $class !== false + ? $class + : null; } - return [sprintf( - 'Call to deprecated method %s() of class %s.', - $methodReflection->getName(), - $methodReflection->getDeclaringClass()->getName() - )]; + try { + return $this->broker->getClass($className); + } catch (\PHPStan\Broker\ClassNotFoundException $e) { + return null; + } } } diff --git a/tests/Rules/Deprecations/CallToDeprecatedStaticMethodRuleTest.php b/tests/Rules/Deprecations/CallToDeprecatedStaticMethodRuleTest.php index c12e10ad..f5f8d96e 100644 --- a/tests/Rules/Deprecations/CallToDeprecatedStaticMethodRuleTest.php +++ b/tests/Rules/Deprecations/CallToDeprecatedStaticMethodRuleTest.php @@ -25,9 +25,29 @@ public function testDeprecatedStaticMethodCall() 'Call to deprecated method deprecatedFoo2() of class CheckDeprecatedStaticMethodCall\Foo.', 9, ], + [ + 'Call to method foo() of deprecated class CheckDeprecatedStaticMethodCall\Foo.', + 11, + ], + [ + 'Call to method deprecatedFoo() of deprecated class CheckDeprecatedStaticMethodCall\Foo.', + 12, + ], + [ + 'Call to deprecated method deprecatedFoo() of class CheckDeprecatedStaticMethodCall\Foo.', + 12, + ], + [ + 'Call to method deprecatedFoo2() of deprecated class CheckDeprecatedStaticMethodCall\Foo.', + 13, + ], + [ + 'Call to deprecated method deprecatedFoo2() of class CheckDeprecatedStaticMethodCall\Foo.', + 13, + ], [ 'Call to deprecated method deprecatedFoo() of class CheckDeprecatedStaticMethodCall\Foo.', - 17, + 21, ], ] ); diff --git a/tests/Rules/Deprecations/data/call-to-deprecated-static-method-definition.php b/tests/Rules/Deprecations/data/call-to-deprecated-static-method-definition.php index b4c3cac2..0ec9d461 100644 --- a/tests/Rules/Deprecations/data/call-to-deprecated-static-method-definition.php +++ b/tests/Rules/Deprecations/data/call-to-deprecated-static-method-definition.php @@ -38,3 +38,10 @@ public static function deprecatedFoo() } +/** + * @deprecated + */ +class DeprecatedBar extends Foo +{ + +} diff --git a/tests/Rules/Deprecations/data/call-to-deprecated-static-method.php b/tests/Rules/Deprecations/data/call-to-deprecated-static-method.php index 0fa6390a..804ef678 100644 --- a/tests/Rules/Deprecations/data/call-to-deprecated-static-method.php +++ b/tests/Rules/Deprecations/data/call-to-deprecated-static-method.php @@ -8,6 +8,10 @@ Bar::deprecatedFoo(); Bar::deprecatedFoo2(); +DeprecatedBar::foo(); +DeprecatedBar::deprecatedFoo(); +DeprecatedBar::deprecatedFoo2(); + class Bar2 extends Foo { From 7ce5d3e53466c0b49c9442ccced6054fb35935af Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Sun, 6 May 2018 16:55:37 +0200 Subject: [PATCH 18/30] Fix phpcs errors --- .../Deprecations/AccessDeprecatedPropertyRule.php | 4 +--- .../AccessDeprecatedStaticPropertyRule.php | 8 ++------ .../Deprecations/CallToDeprecatedFunctionRule.php | 4 +--- src/Rules/Deprecations/CallToDeprecatedMethodRule.php | 4 +--- .../Deprecations/CallToDeprecatedStaticMethodRule.php | 11 ++--------- .../FetchingClassConstOfDeprecatedClassRule.php | 4 +--- .../ImplementationOfDeprecatedInterfaceRule.php | 4 +--- .../Deprecations/InheritanceOfDeprecatedClassRule.php | 4 +--- .../InstantiationOfDeprecatedClassRule.php | 4 +--- src/Rules/Deprecations/UsageOfDeprecatedTraitRule.php | 4 +--- .../Deprecations/AccessDeprecatedPropertyRuleTest.php | 2 +- .../AccessDeprecatedStaticPropertyRuleTest.php | 2 +- .../Deprecations/CallToDeprecatedFunctionRuleTest.php | 2 +- .../Deprecations/CallToDeprecatedMethodRuleTest.php | 2 +- .../CallToDeprecatedStaticMethodRuleTest.php | 2 +- .../FetchingClassConstOfDeprecatedClassRuleTest.php | 2 +- .../ImplementationOfDeprecatedInterfaceRuleTest.php | 4 ++-- .../InheritanceOfDeprecatedClassRuleTest.php | 4 ++-- .../InstantiationOfDeprecatedClassRuleTest.php | 2 +- .../Deprecations/UsageOfDeprecatedTraitRuleTest.php | 2 +- 20 files changed, 24 insertions(+), 51 deletions(-) diff --git a/src/Rules/Deprecations/AccessDeprecatedPropertyRule.php b/src/Rules/Deprecations/AccessDeprecatedPropertyRule.php index d84cc87a..19e219c3 100644 --- a/src/Rules/Deprecations/AccessDeprecatedPropertyRule.php +++ b/src/Rules/Deprecations/AccessDeprecatedPropertyRule.php @@ -11,9 +11,7 @@ class AccessDeprecatedPropertyRule implements \PHPStan\Rules\Rule { - /** - * @var Broker - */ + /** @var Broker */ private $broker; public function __construct(Broker $broker) diff --git a/src/Rules/Deprecations/AccessDeprecatedStaticPropertyRule.php b/src/Rules/Deprecations/AccessDeprecatedStaticPropertyRule.php index d21f1593..9a84ac3e 100644 --- a/src/Rules/Deprecations/AccessDeprecatedStaticPropertyRule.php +++ b/src/Rules/Deprecations/AccessDeprecatedStaticPropertyRule.php @@ -13,14 +13,10 @@ class AccessDeprecatedStaticPropertyRule implements \PHPStan\Rules\Rule { - /** - * @var Broker - */ + /** @var Broker */ private $broker; - /** - * @var RuleLevelHelper - */ + /** @var RuleLevelHelper */ private $ruleLevelHelper; public function __construct(Broker $broker, RuleLevelHelper $ruleLevelHelper) diff --git a/src/Rules/Deprecations/CallToDeprecatedFunctionRule.php b/src/Rules/Deprecations/CallToDeprecatedFunctionRule.php index c5a7c077..e6516f5a 100644 --- a/src/Rules/Deprecations/CallToDeprecatedFunctionRule.php +++ b/src/Rules/Deprecations/CallToDeprecatedFunctionRule.php @@ -10,9 +10,7 @@ class CallToDeprecatedFunctionRule implements \PHPStan\Rules\Rule { - /** - * @var Broker - */ + /** @var Broker */ private $broker; public function __construct(Broker $broker) diff --git a/src/Rules/Deprecations/CallToDeprecatedMethodRule.php b/src/Rules/Deprecations/CallToDeprecatedMethodRule.php index be53f12c..146a8af8 100644 --- a/src/Rules/Deprecations/CallToDeprecatedMethodRule.php +++ b/src/Rules/Deprecations/CallToDeprecatedMethodRule.php @@ -11,9 +11,7 @@ class CallToDeprecatedMethodRule implements \PHPStan\Rules\Rule { - /** - * @var Broker - */ + /** @var Broker */ private $broker; public function __construct(Broker $broker) diff --git a/src/Rules/Deprecations/CallToDeprecatedStaticMethodRule.php b/src/Rules/Deprecations/CallToDeprecatedStaticMethodRule.php index 476fe3f0..8da72ebc 100644 --- a/src/Rules/Deprecations/CallToDeprecatedStaticMethodRule.php +++ b/src/Rules/Deprecations/CallToDeprecatedStaticMethodRule.php @@ -13,9 +13,7 @@ class CallToDeprecatedStaticMethodRule implements \PHPStan\Rules\Rule { - /** - * @var Broker - */ + /** @var Broker */ private $broker; public function __construct(Broker $broker) @@ -77,12 +75,7 @@ public function processNode(Node $node, Scope $scope): array return $errors; } - /** - * @param string $className - * @param Scope $scope - * @return ClassReflection|null - */ - private function getClassWithClassName(string $className, Scope $scope) + private function getClassWithClassName(string $className, Scope $scope): ?ClassReflection { if ($className === 'parent') { if (!$scope->isInClass()) { diff --git a/src/Rules/Deprecations/FetchingClassConstOfDeprecatedClassRule.php b/src/Rules/Deprecations/FetchingClassConstOfDeprecatedClassRule.php index def830f7..897a8811 100644 --- a/src/Rules/Deprecations/FetchingClassConstOfDeprecatedClassRule.php +++ b/src/Rules/Deprecations/FetchingClassConstOfDeprecatedClassRule.php @@ -11,9 +11,7 @@ class FetchingClassConstOfDeprecatedClassRule implements \PHPStan\Rules\Rule { - /** - * @var Broker - */ + /** @var Broker */ private $broker; public function __construct(Broker $broker) diff --git a/src/Rules/Deprecations/ImplementationOfDeprecatedInterfaceRule.php b/src/Rules/Deprecations/ImplementationOfDeprecatedInterfaceRule.php index 21b08dfb..24da4686 100644 --- a/src/Rules/Deprecations/ImplementationOfDeprecatedInterfaceRule.php +++ b/src/Rules/Deprecations/ImplementationOfDeprecatedInterfaceRule.php @@ -10,9 +10,7 @@ class ImplementationOfDeprecatedInterfaceRule implements \PHPStan\Rules\Rule { - /** - * @var Broker - */ + /** @var Broker */ private $broker; public function __construct(Broker $broker) diff --git a/src/Rules/Deprecations/InheritanceOfDeprecatedClassRule.php b/src/Rules/Deprecations/InheritanceOfDeprecatedClassRule.php index d18aa543..0e8b0b39 100644 --- a/src/Rules/Deprecations/InheritanceOfDeprecatedClassRule.php +++ b/src/Rules/Deprecations/InheritanceOfDeprecatedClassRule.php @@ -10,9 +10,7 @@ class InheritanceOfDeprecatedClassRule implements \PHPStan\Rules\Rule { - /** - * @var Broker - */ + /** @var Broker */ private $broker; public function __construct(Broker $broker) diff --git a/src/Rules/Deprecations/InstantiationOfDeprecatedClassRule.php b/src/Rules/Deprecations/InstantiationOfDeprecatedClassRule.php index ce8b8d9f..ff9e8ad5 100644 --- a/src/Rules/Deprecations/InstantiationOfDeprecatedClassRule.php +++ b/src/Rules/Deprecations/InstantiationOfDeprecatedClassRule.php @@ -11,9 +11,7 @@ class InstantiationOfDeprecatedClassRule implements \PHPStan\Rules\Rule { - /** - * @var Broker - */ + /** @var Broker */ private $broker; public function __construct(Broker $broker) diff --git a/src/Rules/Deprecations/UsageOfDeprecatedTraitRule.php b/src/Rules/Deprecations/UsageOfDeprecatedTraitRule.php index e915f311..a4e3844f 100644 --- a/src/Rules/Deprecations/UsageOfDeprecatedTraitRule.php +++ b/src/Rules/Deprecations/UsageOfDeprecatedTraitRule.php @@ -10,9 +10,7 @@ class UsageOfDeprecatedTraitRule implements \PHPStan\Rules\Rule { - /** - * @var Broker - */ + /** @var Broker */ private $broker; public function __construct(Broker $broker) diff --git a/tests/Rules/Deprecations/AccessDeprecatedPropertyRuleTest.php b/tests/Rules/Deprecations/AccessDeprecatedPropertyRuleTest.php index fd0c2ddc..9a2997dd 100644 --- a/tests/Rules/Deprecations/AccessDeprecatedPropertyRuleTest.php +++ b/tests/Rules/Deprecations/AccessDeprecatedPropertyRuleTest.php @@ -11,7 +11,7 @@ protected function getRule(): \PHPStan\Rules\Rule return new AccessDeprecatedPropertyRule($broker); } - public function testAccessDeprecatedProperty() + public function testAccessDeprecatedProperty(): void { require_once __DIR__ . '/data/access-deprecated-property-definition.php'; $this->analyse( diff --git a/tests/Rules/Deprecations/AccessDeprecatedStaticPropertyRuleTest.php b/tests/Rules/Deprecations/AccessDeprecatedStaticPropertyRuleTest.php index 8f50813b..77efeb31 100644 --- a/tests/Rules/Deprecations/AccessDeprecatedStaticPropertyRuleTest.php +++ b/tests/Rules/Deprecations/AccessDeprecatedStaticPropertyRuleTest.php @@ -15,7 +15,7 @@ protected function getRule(): \PHPStan\Rules\Rule return new AccessDeprecatedStaticPropertyRule($broker, $ruleLevelHelper); } - public function testAccessDeprecatedStaticProperty() + public function testAccessDeprecatedStaticProperty(): void { require_once __DIR__ . '/data/access-deprecated-static-property-definition.php'; $this->analyse( diff --git a/tests/Rules/Deprecations/CallToDeprecatedFunctionRuleTest.php b/tests/Rules/Deprecations/CallToDeprecatedFunctionRuleTest.php index 61641808..291e76a6 100644 --- a/tests/Rules/Deprecations/CallToDeprecatedFunctionRuleTest.php +++ b/tests/Rules/Deprecations/CallToDeprecatedFunctionRuleTest.php @@ -11,7 +11,7 @@ protected function getRule(): \PHPStan\Rules\Rule return new CallToDeprecatedFunctionRule($broker); } - public function testDeprecatedFunctionCall() + public function testDeprecatedFunctionCall(): void { require_once __DIR__ . '/data/call-to-deprecated-function-definition.php'; $this->analyse( diff --git a/tests/Rules/Deprecations/CallToDeprecatedMethodRuleTest.php b/tests/Rules/Deprecations/CallToDeprecatedMethodRuleTest.php index 5240d3dc..38e2e13d 100644 --- a/tests/Rules/Deprecations/CallToDeprecatedMethodRuleTest.php +++ b/tests/Rules/Deprecations/CallToDeprecatedMethodRuleTest.php @@ -11,7 +11,7 @@ protected function getRule(): \PHPStan\Rules\Rule return new CallToDeprecatedMethodRule($broker); } - public function testDeprecatedMethodCall() + public function testDeprecatedMethodCall(): void { require_once __DIR__ . '/data/call-to-deprecated-method-definition.php'; $this->analyse( diff --git a/tests/Rules/Deprecations/CallToDeprecatedStaticMethodRuleTest.php b/tests/Rules/Deprecations/CallToDeprecatedStaticMethodRuleTest.php index f5f8d96e..669b835c 100644 --- a/tests/Rules/Deprecations/CallToDeprecatedStaticMethodRuleTest.php +++ b/tests/Rules/Deprecations/CallToDeprecatedStaticMethodRuleTest.php @@ -11,7 +11,7 @@ protected function getRule(): \PHPStan\Rules\Rule return new CallToDeprecatedStaticMethodRule($broker); } - public function testDeprecatedStaticMethodCall() + public function testDeprecatedStaticMethodCall(): void { require_once __DIR__ . '/data/call-to-deprecated-static-method-definition.php'; $this->analyse( diff --git a/tests/Rules/Deprecations/FetchingClassConstOfDeprecatedClassRuleTest.php b/tests/Rules/Deprecations/FetchingClassConstOfDeprecatedClassRuleTest.php index cea64835..f93ad82b 100644 --- a/tests/Rules/Deprecations/FetchingClassConstOfDeprecatedClassRuleTest.php +++ b/tests/Rules/Deprecations/FetchingClassConstOfDeprecatedClassRuleTest.php @@ -11,7 +11,7 @@ protected function getRule(): \PHPStan\Rules\Rule return new FetchingClassConstOfDeprecatedClassRule($broker); } - public function testFetchingClassConstOfDeprecatedClass() + public function testFetchingClassConstOfDeprecatedClass(): void { require_once __DIR__ . '/data/fetching-class-const-of-deprecated-class-definition.php'; $this->analyse( diff --git a/tests/Rules/Deprecations/ImplementationOfDeprecatedInterfaceRuleTest.php b/tests/Rules/Deprecations/ImplementationOfDeprecatedInterfaceRuleTest.php index 58ba54be..19d3c9cf 100644 --- a/tests/Rules/Deprecations/ImplementationOfDeprecatedInterfaceRuleTest.php +++ b/tests/Rules/Deprecations/ImplementationOfDeprecatedInterfaceRuleTest.php @@ -11,7 +11,7 @@ protected function getRule(): \PHPStan\Rules\Rule return new ImplementationOfDeprecatedInterfaceRule($broker); } - public function testImplementationOfDeprecatedInterfacesInClasses() + public function testImplementationOfDeprecatedInterfacesInClasses(): void { require_once __DIR__ . '/data/implementation-of-deprecated-interface-definition.php'; $this->analyse( @@ -33,7 +33,7 @@ public function testImplementationOfDeprecatedInterfacesInClasses() ); } - public function testImplementationOfDeprecatedInterfacesInAnonymousClasses() + public function testImplementationOfDeprecatedInterfacesInAnonymousClasses(): void { $this->markTestSkipped('The `isAnonymous` method in the ReflectionClass doesn\'t work for some reason.'); diff --git a/tests/Rules/Deprecations/InheritanceOfDeprecatedClassRuleTest.php b/tests/Rules/Deprecations/InheritanceOfDeprecatedClassRuleTest.php index 633774ba..166c65ba 100644 --- a/tests/Rules/Deprecations/InheritanceOfDeprecatedClassRuleTest.php +++ b/tests/Rules/Deprecations/InheritanceOfDeprecatedClassRuleTest.php @@ -11,7 +11,7 @@ protected function getRule(): \PHPStan\Rules\Rule return new InheritanceOfDeprecatedClassRule($broker); } - public function testInheritanceOfDeprecatedClassInClasses() + public function testInheritanceOfDeprecatedClassInClasses(): void { require_once __DIR__ . '/data/inheritance-of-deprecated-class-definition.php'; $this->analyse( @@ -25,7 +25,7 @@ public function testInheritanceOfDeprecatedClassInClasses() ); } - public function testInheritanceOfDeprecatedClassInAnonymousClasses() + public function testInheritanceOfDeprecatedClassInAnonymousClasses(): void { $this->markTestSkipped('The `isAnonymous` method in the ReflectionClass doesn\'t work for some reason.'); diff --git a/tests/Rules/Deprecations/InstantiationOfDeprecatedClassRuleTest.php b/tests/Rules/Deprecations/InstantiationOfDeprecatedClassRuleTest.php index 9fb86628..9efcdff5 100644 --- a/tests/Rules/Deprecations/InstantiationOfDeprecatedClassRuleTest.php +++ b/tests/Rules/Deprecations/InstantiationOfDeprecatedClassRuleTest.php @@ -11,7 +11,7 @@ protected function getRule(): \PHPStan\Rules\Rule return new InstantiationOfDeprecatedClassRule($broker); } - public function testInstantiationOfDeprecatedClass() + public function testInstantiationOfDeprecatedClass(): void { require_once __DIR__ . '/data/instantiation-of-deprecated-class-definition.php'; $this->analyse( diff --git a/tests/Rules/Deprecations/UsageOfDeprecatedTraitRuleTest.php b/tests/Rules/Deprecations/UsageOfDeprecatedTraitRuleTest.php index d0050a91..7bceaddd 100644 --- a/tests/Rules/Deprecations/UsageOfDeprecatedTraitRuleTest.php +++ b/tests/Rules/Deprecations/UsageOfDeprecatedTraitRuleTest.php @@ -11,7 +11,7 @@ protected function getRule(): \PHPStan\Rules\Rule return new UsageOfDeprecatedTraitRule($broker); } - public function testUsageOfDeprecatedTrait() + public function testUsageOfDeprecatedTrait(): void { require_once __DIR__ . '/data/usage-of-deprecated-trait-definition.php'; $this->analyse( From 74b25d0242ddf04c221dd91dcc00ec9f431c01b8 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Sun, 6 May 2018 18:31:37 +0200 Subject: [PATCH 19/30] Ignore all deprecation errors in deprecated scopes --- .../AccessDeprecatedPropertyRule.php | 4 ++ .../AccessDeprecatedStaticPropertyRule.php | 4 ++ .../CallToDeprecatedFunctionRule.php | 4 ++ .../CallToDeprecatedMethodRule.php | 4 ++ .../CallToDeprecatedStaticMethodRule.php | 4 ++ .../Deprecations/DeprecatedScopeHelper.php | 26 +++++++ ...etchingClassConstOfDeprecatedClassRule.php | 4 ++ ...mplementationOfDeprecatedInterfaceRule.php | 4 ++ .../InheritanceOfDeprecatedClassRule.php | 4 ++ .../InstantiationOfDeprecatedClassRule.php | 4 ++ .../UsageOfDeprecatedTraitRule.php | 4 ++ .../data/access-deprecated-property.php | 44 ++++++++++++ .../access-deprecated-static-property.php | 72 +++++++++++++++++++ .../data/call-to-deprecated-function.php | 23 +++++- .../data/call-to-deprecated-method.php | 40 +++++++++++ .../data/call-to-deprecated-static-method.php | 25 +++++++ ...tching-class-const-of-deprecated-class.php | 23 ++++++ ...recated-interface-in-anonymous-classes.php | 41 +++++++++++ ...ion-of-deprecated-interface-in-classes.php | 24 +++++++ ...-deprecated-class-in-anonymous-classes.php | 33 +++++++++ .../instantiation-of-deprecated-class.php | 21 ++++++ .../data/usage-of-deprecated-trait.php | 22 ++++++ 22 files changed, 433 insertions(+), 1 deletion(-) create mode 100644 src/Rules/Deprecations/DeprecatedScopeHelper.php diff --git a/src/Rules/Deprecations/AccessDeprecatedPropertyRule.php b/src/Rules/Deprecations/AccessDeprecatedPropertyRule.php index 19e219c3..702514f4 100644 --- a/src/Rules/Deprecations/AccessDeprecatedPropertyRule.php +++ b/src/Rules/Deprecations/AccessDeprecatedPropertyRule.php @@ -31,6 +31,10 @@ public function getNodeType(): string */ public function processNode(Node $node, Scope $scope): array { + if (DeprecatedScopeHelper::isScopeDeprecated($scope)) { + return []; + } + if (!is_string($node->name)) { return []; } diff --git a/src/Rules/Deprecations/AccessDeprecatedStaticPropertyRule.php b/src/Rules/Deprecations/AccessDeprecatedStaticPropertyRule.php index 9a84ac3e..428bdc41 100644 --- a/src/Rules/Deprecations/AccessDeprecatedStaticPropertyRule.php +++ b/src/Rules/Deprecations/AccessDeprecatedStaticPropertyRule.php @@ -37,6 +37,10 @@ public function getNodeType(): string */ public function processNode(Node $node, Scope $scope): array { + if (DeprecatedScopeHelper::isScopeDeprecated($scope)) { + return []; + } + if (!is_string($node->name)) { return []; } diff --git a/src/Rules/Deprecations/CallToDeprecatedFunctionRule.php b/src/Rules/Deprecations/CallToDeprecatedFunctionRule.php index e6516f5a..fd4fbad0 100644 --- a/src/Rules/Deprecations/CallToDeprecatedFunctionRule.php +++ b/src/Rules/Deprecations/CallToDeprecatedFunctionRule.php @@ -30,6 +30,10 @@ public function getNodeType(): string */ public function processNode(Node $node, Scope $scope): array { + if (DeprecatedScopeHelper::isScopeDeprecated($scope)) { + return []; + } + if (!($node->name instanceof \PhpParser\Node\Name)) { return []; } diff --git a/src/Rules/Deprecations/CallToDeprecatedMethodRule.php b/src/Rules/Deprecations/CallToDeprecatedMethodRule.php index 146a8af8..58719d41 100644 --- a/src/Rules/Deprecations/CallToDeprecatedMethodRule.php +++ b/src/Rules/Deprecations/CallToDeprecatedMethodRule.php @@ -31,6 +31,10 @@ public function getNodeType(): string */ public function processNode(Node $node, Scope $scope): array { + if (DeprecatedScopeHelper::isScopeDeprecated($scope)) { + return []; + } + if (!is_string($node->name)) { return []; } diff --git a/src/Rules/Deprecations/CallToDeprecatedStaticMethodRule.php b/src/Rules/Deprecations/CallToDeprecatedStaticMethodRule.php index 8da72ebc..db374528 100644 --- a/src/Rules/Deprecations/CallToDeprecatedStaticMethodRule.php +++ b/src/Rules/Deprecations/CallToDeprecatedStaticMethodRule.php @@ -33,6 +33,10 @@ public function getNodeType(): string */ public function processNode(Node $node, Scope $scope): array { + if (DeprecatedScopeHelper::isScopeDeprecated($scope)) { + return []; + } + if (!is_string($node->name)) { return []; } diff --git a/src/Rules/Deprecations/DeprecatedScopeHelper.php b/src/Rules/Deprecations/DeprecatedScopeHelper.php new file mode 100644 index 00000000..583c1d68 --- /dev/null +++ b/src/Rules/Deprecations/DeprecatedScopeHelper.php @@ -0,0 +1,26 @@ +getClassReflection(); + if ($class !== null && $class->isDeprecated()) { + return true; + } + + $function = $scope->getFunction(); + if ($function instanceof DeprecatableReflection && $function->isDeprecated()) { + return true; + } + + return false; + } + +} diff --git a/src/Rules/Deprecations/FetchingClassConstOfDeprecatedClassRule.php b/src/Rules/Deprecations/FetchingClassConstOfDeprecatedClassRule.php index 897a8811..a67e8c51 100644 --- a/src/Rules/Deprecations/FetchingClassConstOfDeprecatedClassRule.php +++ b/src/Rules/Deprecations/FetchingClassConstOfDeprecatedClassRule.php @@ -31,6 +31,10 @@ public function getNodeType(): string */ public function processNode(Node $node, Scope $scope): array { + if (DeprecatedScopeHelper::isScopeDeprecated($scope)) { + return []; + } + if (!$node->class instanceof Name) { return []; } diff --git a/src/Rules/Deprecations/ImplementationOfDeprecatedInterfaceRule.php b/src/Rules/Deprecations/ImplementationOfDeprecatedInterfaceRule.php index 24da4686..43cbc82a 100644 --- a/src/Rules/Deprecations/ImplementationOfDeprecatedInterfaceRule.php +++ b/src/Rules/Deprecations/ImplementationOfDeprecatedInterfaceRule.php @@ -42,6 +42,10 @@ public function processNode(Node $node, Scope $scope): array return []; } + if ($class->isDeprecated()) { + return []; + } + foreach ($node->implements as $implement) { $interfaceName = (string) $implement; diff --git a/src/Rules/Deprecations/InheritanceOfDeprecatedClassRule.php b/src/Rules/Deprecations/InheritanceOfDeprecatedClassRule.php index 0e8b0b39..c954cbb8 100644 --- a/src/Rules/Deprecations/InheritanceOfDeprecatedClassRule.php +++ b/src/Rules/Deprecations/InheritanceOfDeprecatedClassRule.php @@ -30,6 +30,10 @@ public function getNodeType(): string */ public function processNode(Node $node, Scope $scope): array { + if (DeprecatedScopeHelper::isScopeDeprecated($scope)) { + return []; + } + if ($node->extends === null) { return []; } diff --git a/src/Rules/Deprecations/InstantiationOfDeprecatedClassRule.php b/src/Rules/Deprecations/InstantiationOfDeprecatedClassRule.php index ff9e8ad5..f33f36ab 100644 --- a/src/Rules/Deprecations/InstantiationOfDeprecatedClassRule.php +++ b/src/Rules/Deprecations/InstantiationOfDeprecatedClassRule.php @@ -31,6 +31,10 @@ public function getNodeType(): string */ public function processNode(Node $node, Scope $scope): array { + if (DeprecatedScopeHelper::isScopeDeprecated($scope)) { + return []; + } + if (!$node->class instanceof Name) { return []; } diff --git a/src/Rules/Deprecations/UsageOfDeprecatedTraitRule.php b/src/Rules/Deprecations/UsageOfDeprecatedTraitRule.php index a4e3844f..fb7d35c2 100644 --- a/src/Rules/Deprecations/UsageOfDeprecatedTraitRule.php +++ b/src/Rules/Deprecations/UsageOfDeprecatedTraitRule.php @@ -30,6 +30,10 @@ public function getNodeType(): string */ public function processNode(Node $node, Scope $scope): array { + if (DeprecatedScopeHelper::isScopeDeprecated($scope)) { + return []; + } + $errors = []; $className = $scope->getClassReflection()->getName(); diff --git a/tests/Rules/Deprecations/data/access-deprecated-property.php b/tests/Rules/Deprecations/data/access-deprecated-property.php index e1cc8b54..f99e53c6 100644 --- a/tests/Rules/Deprecations/data/access-deprecated-property.php +++ b/tests/Rules/Deprecations/data/access-deprecated-property.php @@ -16,3 +16,47 @@ $foo->deprecatedFooFromTrait = 'deprecatedFooFromTrait'; echo $foo->deprecatedFooFromTrait; +/** + * @deprecated + */ +function deprecated_scope() +{ + $foo = new Foo(); + + $foo->foo = 'foo'; + echo $foo->foo; + + $foo->deprecatedFoo = 'deprecatedFoo'; + echo $foo->deprecatedFoo; + + $foo->fooFromTrait = 'fooFromTrait'; + echo $foo->fooFromTrait; + + $foo->deprecatedFooFromTrait = 'deprecatedFooFromTrait'; + echo $foo->deprecatedFooFromTrait; +} + +/** + * @deprecated + */ +class DeprecatedScope +{ + + public function foo() + { + $foo = new Foo(); + + $foo->foo = 'foo'; + echo $foo->foo; + + $foo->deprecatedFoo = 'deprecatedFoo'; + echo $foo->deprecatedFoo; + + $foo->fooFromTrait = 'fooFromTrait'; + echo $foo->fooFromTrait; + + $foo->deprecatedFooFromTrait = 'deprecatedFooFromTrait'; + echo $foo->deprecatedFooFromTrait; + } + +} diff --git a/tests/Rules/Deprecations/data/access-deprecated-static-property.php b/tests/Rules/Deprecations/data/access-deprecated-static-property.php index 79cc222d..df3043a8 100644 --- a/tests/Rules/Deprecations/data/access-deprecated-static-property.php +++ b/tests/Rules/Deprecations/data/access-deprecated-static-property.php @@ -30,3 +30,75 @@ $foo::$deprecatedFooFromTrait = 'foo'; echo $foo::$deprecatedFooFromTrait; +/** + * @deprecated + */ +function deprecated_scope() +{ + Foo::$foo = 'foo'; + echo Foo::$foo; + + Foo::$deprecatedFoo = 'foo'; + echo Foo::$deprecatedFoo; + + $foo = new Foo(); + + $foo::$foo = 'foo'; + echo $foo::$foo; + + $foo::$deprecatedFoo = 'foo'; + echo $foo::$deprecatedFoo; + + FooTrait::$fooFromTrait = 'foo'; + echo FooTrait::$fooFromTrait; + + FooTrait::$deprecatedFooFromTrait = 'foo'; + echo FooTrait::$deprecatedFooFromTrait; + + $foo = new Foo(); + + $foo::$fooFromTrait = 'foo'; + echo $foo::$fooFromTrait; + + $foo::$deprecatedFooFromTrait = 'foo'; + echo $foo::$deprecatedFooFromTrait; +} + +/** + * @deprecated + */ +class DeprecatedScope +{ + + public function foo() + { + Foo::$foo = 'foo'; + echo Foo::$foo; + + Foo::$deprecatedFoo = 'foo'; + echo Foo::$deprecatedFoo; + + $foo = new Foo(); + + $foo::$foo = 'foo'; + echo $foo::$foo; + + $foo::$deprecatedFoo = 'foo'; + echo $foo::$deprecatedFoo; + + FooTrait::$fooFromTrait = 'foo'; + echo FooTrait::$fooFromTrait; + + FooTrait::$deprecatedFooFromTrait = 'foo'; + echo FooTrait::$deprecatedFooFromTrait; + + $foo = new Foo(); + + $foo::$fooFromTrait = 'foo'; + echo $foo::$fooFromTrait; + + $foo::$deprecatedFooFromTrait = 'foo'; + echo $foo::$deprecatedFooFromTrait; + } + +} diff --git a/tests/Rules/Deprecations/data/call-to-deprecated-function.php b/tests/Rules/Deprecations/data/call-to-deprecated-function.php index 34f06dc3..5e2a317c 100644 --- a/tests/Rules/Deprecations/data/call-to-deprecated-function.php +++ b/tests/Rules/Deprecations/data/call-to-deprecated-function.php @@ -8,4 +8,25 @@ deprecated_foo(); \CheckDeprecatedFunctionCall\deprecated_foo(); -non_existent_func(); +/** + * @deprecated + */ +function deprecated_scope() +{ + deprecated_foo(); + \CheckDeprecatedFunctionCall\deprecated_foo(); +} + +/** + * @deprecated + */ +class DeprecatedScope +{ + + function foo() + { + deprecated_foo(); + \CheckDeprecatedFunctionCall\deprecated_foo(); + } + +} diff --git a/tests/Rules/Deprecations/data/call-to-deprecated-method.php b/tests/Rules/Deprecations/data/call-to-deprecated-method.php index 4e57eab5..7b283ee6 100644 --- a/tests/Rules/Deprecations/data/call-to-deprecated-method.php +++ b/tests/Rules/Deprecations/data/call-to-deprecated-method.php @@ -12,3 +12,43 @@ $foo->fooFromTrait(); $foo->deprecatedFooFromTrait(); + +/** + * @deprecated + */ +function deprecated_scope() +{ + $foo = new Foo(); + $foo->foo(); + $foo->deprecatedFoo(); + + $bar = new Bar(); + $bar->deprecatedFoo(); + $bar->deprecatedFoo2(); + + $foo->fooFromTrait(); + $foo->deprecatedFooFromTrait(); + +} + +/** + * @deprecated + */ +class DeprecatedScope +{ + + public function foo() + { + $foo = new Foo(); + $foo->foo(); + $foo->deprecatedFoo(); + + $bar = new Bar(); + $bar->deprecatedFoo(); + $bar->deprecatedFoo2(); + + $foo->fooFromTrait(); + $foo->deprecatedFooFromTrait(); + } + +} diff --git a/tests/Rules/Deprecations/data/call-to-deprecated-static-method.php b/tests/Rules/Deprecations/data/call-to-deprecated-static-method.php index 804ef678..b24a8018 100644 --- a/tests/Rules/Deprecations/data/call-to-deprecated-static-method.php +++ b/tests/Rules/Deprecations/data/call-to-deprecated-static-method.php @@ -22,3 +22,28 @@ public static function deprecatedFoo() } } + +/** + * @deprecated + */ +function deprecated_scope() +{ + Foo::foo(); + Foo::deprecatedFoo(); + Foo::deprecatedFoo2(); +} + +/** + * @deprecated + */ +class DeprecatedScope +{ + + public static function foo() + { + Foo::foo(); + Foo::deprecatedFoo(); + Foo::deprecatedFoo2(); + } + +} diff --git a/tests/Rules/Deprecations/data/fetching-class-const-of-deprecated-class.php b/tests/Rules/Deprecations/data/fetching-class-const-of-deprecated-class.php index b4704ae2..3cdbd665 100644 --- a/tests/Rules/Deprecations/data/fetching-class-const-of-deprecated-class.php +++ b/tests/Rules/Deprecations/data/fetching-class-const-of-deprecated-class.php @@ -4,3 +4,26 @@ echo Foo::class; echo DeprecatedFoo::class; + +/** + * @deprecated + */ +function deprecated_scope() +{ + echo Foo::class; + echo DeprecatedFoo::class; +} + +/** + * @deprecated + */ +class DeprecatedScope +{ + + function foo() + { + echo Foo::class; + echo DeprecatedFoo::class; + } + +} diff --git a/tests/Rules/Deprecations/data/implementation-of-deprecated-interface-in-anonymous-classes.php b/tests/Rules/Deprecations/data/implementation-of-deprecated-interface-in-anonymous-classes.php index d00aad3b..2cdeaceb 100644 --- a/tests/Rules/Deprecations/data/implementation-of-deprecated-interface-in-anonymous-classes.php +++ b/tests/Rules/Deprecations/data/implementation-of-deprecated-interface-in-anonymous-classes.php @@ -13,3 +13,44 @@ $fooable3 = new class implements Fooable, DeprecatedFooable, DeprecatedFooable2 { }; + +/** + * @deprecated + */ +function deprecated_scope() +{ + $fooable = new class implements Fooable { + + }; + + $fooable2 = new class implements DeprecatedFooable { + + }; + + $fooable3 = new class implements Fooable, DeprecatedFooable, DeprecatedFooable2 { + + }; +} + +/** + * @deprecated + */ +class DeprecatedScope +{ + + public function foo() + { + $fooable = new class implements Fooable { + + }; + + $fooable2 = new class implements DeprecatedFooable { + + }; + + $fooable3 = new class implements Fooable, DeprecatedFooable, DeprecatedFooable2 { + + }; + } + +} diff --git a/tests/Rules/Deprecations/data/implementation-of-deprecated-interface-in-classes.php b/tests/Rules/Deprecations/data/implementation-of-deprecated-interface-in-classes.php index 9bc83399..65a4efbc 100644 --- a/tests/Rules/Deprecations/data/implementation-of-deprecated-interface-in-classes.php +++ b/tests/Rules/Deprecations/data/implementation-of-deprecated-interface-in-classes.php @@ -16,3 +16,27 @@ class Foo3 implements Fooable, DeprecatedFooable, DeprecatedFooable2 { } + +/** + * @deprecated + */ +class DeprecatedFoo implements Fooable +{ + +} + +/** + * @deprecated + */ +class DeprecatedFoo2 implements DeprecatedFooable +{ + +} + +/** + * @deprecated + */ +class DeprecatedFoo3 implements Fooable, DeprecatedFooable, DeprecatedFooable2 +{ + +} diff --git a/tests/Rules/Deprecations/data/inheritance-of-deprecated-class-in-anonymous-classes.php b/tests/Rules/Deprecations/data/inheritance-of-deprecated-class-in-anonymous-classes.php index 13d3d5f4..b8e9b9cb 100644 --- a/tests/Rules/Deprecations/data/inheritance-of-deprecated-class-in-anonymous-classes.php +++ b/tests/Rules/Deprecations/data/inheritance-of-deprecated-class-in-anonymous-classes.php @@ -9,3 +9,36 @@ $deprecatedFoo = new class extends DeprecatedFoo { }; + +/** + * @deprecated + */ +function deprecated_scope() +{ + $foo = new class extends Foo { + + }; + + $deprecatedFoo = new class extends DeprecatedFoo { + + }; +} + +/** + * @deprecated + */ +class DeprecatedScope +{ + + public function foo() + { + $foo = new class extends Foo { + + }; + + $deprecatedFoo = new class extends DeprecatedFoo { + + }; + } + +} diff --git a/tests/Rules/Deprecations/data/instantiation-of-deprecated-class.php b/tests/Rules/Deprecations/data/instantiation-of-deprecated-class.php index 81cc9af5..048c299c 100644 --- a/tests/Rules/Deprecations/data/instantiation-of-deprecated-class.php +++ b/tests/Rules/Deprecations/data/instantiation-of-deprecated-class.php @@ -4,3 +4,24 @@ $foo = new Foo(); $deprecatedFoo = new DeprecatedFoo(); + +/** + * @deprecated + */ +function deprecated_scope() +{ + $foo = new Foo(); + $deprecatedFoo = new DeprecatedFoo(); +} + +/** + * @deprecated + */ +class DeprecatedScope +{ + public function foo() + { + $foo = new Foo(); + $deprecatedFoo = new DeprecatedFoo(); + } +} diff --git a/tests/Rules/Deprecations/data/usage-of-deprecated-trait.php b/tests/Rules/Deprecations/data/usage-of-deprecated-trait.php index 1d78cb34..a0f6ff15 100644 --- a/tests/Rules/Deprecations/data/usage-of-deprecated-trait.php +++ b/tests/Rules/Deprecations/data/usage-of-deprecated-trait.php @@ -17,3 +17,25 @@ class Foo2 DeprecatedFooTrait; } + +/** + * @deprecated + */ +class DeprecatedFoo +{ + + use FooTrait; + use DeprecatedFooTrait; + +} + +/** + * @deprecated + */ +class DeprecatedFoo2 +{ + + use FooTrait, + DeprecatedFooTrait; + +} From a46a26a707e993d1d87bf6bb5c521ce413514df7 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Sun, 6 May 2018 18:58:11 +0200 Subject: [PATCH 20/30] Remove `echo` in tests --- .../data/access-deprecated-property.php | 24 +++++----- .../access-deprecated-static-property.php | 48 +++++++++---------- ...tching-class-const-of-deprecated-class.php | 12 ++--- 3 files changed, 42 insertions(+), 42 deletions(-) diff --git a/tests/Rules/Deprecations/data/access-deprecated-property.php b/tests/Rules/Deprecations/data/access-deprecated-property.php index f99e53c6..704f2176 100644 --- a/tests/Rules/Deprecations/data/access-deprecated-property.php +++ b/tests/Rules/Deprecations/data/access-deprecated-property.php @@ -5,16 +5,16 @@ $foo = new Foo(); $foo->foo = 'foo'; -echo $foo->foo; +$foo->foo; $foo->deprecatedFoo = 'deprecatedFoo'; -echo $foo->deprecatedFoo; +$foo->deprecatedFoo; $foo->fooFromTrait = 'fooFromTrait'; -echo $foo->fooFromTrait; +$foo->fooFromTrait; $foo->deprecatedFooFromTrait = 'deprecatedFooFromTrait'; -echo $foo->deprecatedFooFromTrait; +$foo->deprecatedFooFromTrait; /** * @deprecated @@ -24,16 +24,16 @@ function deprecated_scope() $foo = new Foo(); $foo->foo = 'foo'; - echo $foo->foo; + $foo->foo; $foo->deprecatedFoo = 'deprecatedFoo'; - echo $foo->deprecatedFoo; + $foo->deprecatedFoo; $foo->fooFromTrait = 'fooFromTrait'; - echo $foo->fooFromTrait; + $foo->fooFromTrait; $foo->deprecatedFooFromTrait = 'deprecatedFooFromTrait'; - echo $foo->deprecatedFooFromTrait; + $foo->deprecatedFooFromTrait; } /** @@ -47,16 +47,16 @@ public function foo() $foo = new Foo(); $foo->foo = 'foo'; - echo $foo->foo; + $foo->foo; $foo->deprecatedFoo = 'deprecatedFoo'; - echo $foo->deprecatedFoo; + $foo->deprecatedFoo; $foo->fooFromTrait = 'fooFromTrait'; - echo $foo->fooFromTrait; + $foo->fooFromTrait; $foo->deprecatedFooFromTrait = 'deprecatedFooFromTrait'; - echo $foo->deprecatedFooFromTrait; + $foo->deprecatedFooFromTrait; } } diff --git a/tests/Rules/Deprecations/data/access-deprecated-static-property.php b/tests/Rules/Deprecations/data/access-deprecated-static-property.php index df3043a8..b33db7bb 100644 --- a/tests/Rules/Deprecations/data/access-deprecated-static-property.php +++ b/tests/Rules/Deprecations/data/access-deprecated-static-property.php @@ -3,32 +3,32 @@ namespace AccessDeprecatedStaticProperty; Foo::$foo = 'foo'; -echo Foo::$foo; +Foo::$foo; Foo::$deprecatedFoo = 'foo'; -echo Foo::$deprecatedFoo; +Foo::$deprecatedFoo; $foo = new Foo(); $foo::$foo = 'foo'; -echo $foo::$foo; +$foo::$foo; $foo::$deprecatedFoo = 'foo'; -echo $foo::$deprecatedFoo; +$foo::$deprecatedFoo; FooTrait::$fooFromTrait = 'foo'; -echo FooTrait::$fooFromTrait; +FooTrait::$fooFromTrait; FooTrait::$deprecatedFooFromTrait = 'foo'; -echo FooTrait::$deprecatedFooFromTrait; +FooTrait::$deprecatedFooFromTrait; $foo = new Foo(); $foo::$fooFromTrait = 'foo'; -echo $foo::$fooFromTrait; +$foo::$fooFromTrait; $foo::$deprecatedFooFromTrait = 'foo'; -echo $foo::$deprecatedFooFromTrait; +$foo::$deprecatedFooFromTrait; /** * @deprecated @@ -36,32 +36,32 @@ function deprecated_scope() { Foo::$foo = 'foo'; - echo Foo::$foo; + Foo::$foo; Foo::$deprecatedFoo = 'foo'; - echo Foo::$deprecatedFoo; + Foo::$deprecatedFoo; $foo = new Foo(); $foo::$foo = 'foo'; - echo $foo::$foo; + $foo::$foo; $foo::$deprecatedFoo = 'foo'; - echo $foo::$deprecatedFoo; + $foo::$deprecatedFoo; FooTrait::$fooFromTrait = 'foo'; - echo FooTrait::$fooFromTrait; + FooTrait::$fooFromTrait; FooTrait::$deprecatedFooFromTrait = 'foo'; - echo FooTrait::$deprecatedFooFromTrait; + FooTrait::$deprecatedFooFromTrait; $foo = new Foo(); $foo::$fooFromTrait = 'foo'; - echo $foo::$fooFromTrait; + $foo::$fooFromTrait; $foo::$deprecatedFooFromTrait = 'foo'; - echo $foo::$deprecatedFooFromTrait; + $foo::$deprecatedFooFromTrait; } /** @@ -73,32 +73,32 @@ class DeprecatedScope public function foo() { Foo::$foo = 'foo'; - echo Foo::$foo; + Foo::$foo; Foo::$deprecatedFoo = 'foo'; - echo Foo::$deprecatedFoo; + Foo::$deprecatedFoo; $foo = new Foo(); $foo::$foo = 'foo'; - echo $foo::$foo; + $foo::$foo; $foo::$deprecatedFoo = 'foo'; - echo $foo::$deprecatedFoo; + $foo::$deprecatedFoo; FooTrait::$fooFromTrait = 'foo'; - echo FooTrait::$fooFromTrait; + FooTrait::$fooFromTrait; FooTrait::$deprecatedFooFromTrait = 'foo'; - echo FooTrait::$deprecatedFooFromTrait; + FooTrait::$deprecatedFooFromTrait; $foo = new Foo(); $foo::$fooFromTrait = 'foo'; - echo $foo::$fooFromTrait; + $foo::$fooFromTrait; $foo::$deprecatedFooFromTrait = 'foo'; - echo $foo::$deprecatedFooFromTrait; + $foo::$deprecatedFooFromTrait; } } diff --git a/tests/Rules/Deprecations/data/fetching-class-const-of-deprecated-class.php b/tests/Rules/Deprecations/data/fetching-class-const-of-deprecated-class.php index 3cdbd665..27dae6e7 100644 --- a/tests/Rules/Deprecations/data/fetching-class-const-of-deprecated-class.php +++ b/tests/Rules/Deprecations/data/fetching-class-const-of-deprecated-class.php @@ -2,16 +2,16 @@ namespace FetchingClassConstOfDeprecatedClass; -echo Foo::class; -echo DeprecatedFoo::class; +Foo::class; +DeprecatedFoo::class; /** * @deprecated */ function deprecated_scope() { - echo Foo::class; - echo DeprecatedFoo::class; + Foo::class; + DeprecatedFoo::class; } /** @@ -22,8 +22,8 @@ class DeprecatedScope function foo() { - echo Foo::class; - echo DeprecatedFoo::class; + Foo::class; + DeprecatedFoo::class; } } From b9755b8d04a371ed91b7b037a6437f261ba0fd8a Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Sun, 6 May 2018 19:02:23 +0200 Subject: [PATCH 21/30] Fix incorrectly cased file name --- ...inition.php => inheritance-of-deprecated-class-definition.php} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/Rules/Deprecations/data/{Inheritance-of-deprecated-class-definition.php => inheritance-of-deprecated-class-definition.php} (100%) diff --git a/tests/Rules/Deprecations/data/Inheritance-of-deprecated-class-definition.php b/tests/Rules/Deprecations/data/inheritance-of-deprecated-class-definition.php similarity index 100% rename from tests/Rules/Deprecations/data/Inheritance-of-deprecated-class-definition.php rename to tests/Rules/Deprecations/data/inheritance-of-deprecated-class-definition.php From afc0d17d71a6ea69c4843c9c671c211a599c8ce8 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Sun, 6 May 2018 19:08:59 +0200 Subject: [PATCH 22/30] Fix errors reported by PHPStan --- src/Rules/Deprecations/UsageOfDeprecatedTraitRule.php | 7 ++++++- .../ImplementationOfDeprecatedInterfaceRuleTest.php | 2 +- .../Deprecations/InheritanceOfDeprecatedClassRuleTest.php | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/Rules/Deprecations/UsageOfDeprecatedTraitRule.php b/src/Rules/Deprecations/UsageOfDeprecatedTraitRule.php index fb7d35c2..19018ce3 100644 --- a/src/Rules/Deprecations/UsageOfDeprecatedTraitRule.php +++ b/src/Rules/Deprecations/UsageOfDeprecatedTraitRule.php @@ -34,8 +34,13 @@ public function processNode(Node $node, Scope $scope): array return []; } + $classReflection = $scope->getClassReflection(); + if ($classReflection === null) { + throw new \PHPStan\ShouldNotHappenException(); + } + $errors = []; - $className = $scope->getClassReflection()->getName(); + $className = $classReflection->getName(); foreach ($node->traits as $traitNameNode) { $traitName = (string) $traitNameNode; diff --git a/tests/Rules/Deprecations/ImplementationOfDeprecatedInterfaceRuleTest.php b/tests/Rules/Deprecations/ImplementationOfDeprecatedInterfaceRuleTest.php index 19d3c9cf..fe63dd03 100644 --- a/tests/Rules/Deprecations/ImplementationOfDeprecatedInterfaceRuleTest.php +++ b/tests/Rules/Deprecations/ImplementationOfDeprecatedInterfaceRuleTest.php @@ -35,7 +35,7 @@ public function testImplementationOfDeprecatedInterfacesInClasses(): void public function testImplementationOfDeprecatedInterfacesInAnonymousClasses(): void { - $this->markTestSkipped('The `isAnonymous` method in the ReflectionClass doesn\'t work for some reason.'); + static::markTestSkipped('The `isAnonymous` method in the ReflectionClass doesn\'t work for some reason.'); require_once __DIR__ . '/data/implementation-of-deprecated-interface-definition.php'; $this->analyse( diff --git a/tests/Rules/Deprecations/InheritanceOfDeprecatedClassRuleTest.php b/tests/Rules/Deprecations/InheritanceOfDeprecatedClassRuleTest.php index 166c65ba..b44a5dfb 100644 --- a/tests/Rules/Deprecations/InheritanceOfDeprecatedClassRuleTest.php +++ b/tests/Rules/Deprecations/InheritanceOfDeprecatedClassRuleTest.php @@ -27,7 +27,7 @@ public function testInheritanceOfDeprecatedClassInClasses(): void public function testInheritanceOfDeprecatedClassInAnonymousClasses(): void { - $this->markTestSkipped('The `isAnonymous` method in the ReflectionClass doesn\'t work for some reason.'); + static::markTestSkipped('The `isAnonymous` method in the ReflectionClass doesn\'t work for some reason.'); require_once __DIR__ . '/data/inheritance-of-deprecated-class-definition.php'; $this->analyse( From 5af1a6d44b9b29dda8d6acf6248c6b7d10aa8645 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Sun, 6 May 2018 19:21:47 +0200 Subject: [PATCH 23/30] Move DeprecatedScopeHelper to Analyzer namespace --- src/{Rules/Deprecations => Analyzer}/DeprecatedScopeHelper.php | 2 +- src/Rules/Deprecations/AccessDeprecatedPropertyRule.php | 1 + src/Rules/Deprecations/AccessDeprecatedStaticPropertyRule.php | 1 + src/Rules/Deprecations/CallToDeprecatedFunctionRule.php | 1 + src/Rules/Deprecations/CallToDeprecatedMethodRule.php | 1 + src/Rules/Deprecations/CallToDeprecatedStaticMethodRule.php | 1 + .../Deprecations/FetchingClassConstOfDeprecatedClassRule.php | 1 + src/Rules/Deprecations/InheritanceOfDeprecatedClassRule.php | 1 + src/Rules/Deprecations/InstantiationOfDeprecatedClassRule.php | 1 + src/Rules/Deprecations/UsageOfDeprecatedTraitRule.php | 1 + 10 files changed, 10 insertions(+), 1 deletion(-) rename src/{Rules/Deprecations => Analyzer}/DeprecatedScopeHelper.php (92%) diff --git a/src/Rules/Deprecations/DeprecatedScopeHelper.php b/src/Analyzer/DeprecatedScopeHelper.php similarity index 92% rename from src/Rules/Deprecations/DeprecatedScopeHelper.php rename to src/Analyzer/DeprecatedScopeHelper.php index 583c1d68..0eb8a736 100644 --- a/src/Rules/Deprecations/DeprecatedScopeHelper.php +++ b/src/Analyzer/DeprecatedScopeHelper.php @@ -1,6 +1,6 @@ Date: Sun, 6 May 2018 19:22:06 +0200 Subject: [PATCH 24/30] Add deprecation rules to rules.neon file --- rules.neon | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/rules.neon b/rules.neon index a5bc9d92..88acdf47 100644 --- a/rules.neon +++ b/rules.neon @@ -12,6 +12,16 @@ rules: - PHPStan\Rules\BooleansInConditions\BooleanInElseIfConditionRule - PHPStan\Rules\BooleansInConditions\BooleanInIfConditionRule - PHPStan\Rules\BooleansInConditions\BooleanInTernaryOperatorRule + - PHPStan\Rules\Deprecations\AccessDeprecatedPropertyRule + - PHPStan\Rules\Deprecations\AccessDeprecatedStaticPropertyRule + - PHPStan\Rules\Deprecations\CallToDeprecatedFunctionRule + - PHPStan\Rules\Deprecations\CallToDeprecatedMethodRule + - PHPStan\Rules\Deprecations\CallToDeprecatedStaticMethodRule + - PHPStan\Rules\Deprecations\FetchingClassConstOfDeprecatedClassRule + - PHPStan\Rules\Deprecations\ImplementationOfDeprecatedInterfaceRule + - PHPStan\Rules\Deprecations\InheritanceOfDeprecatedClassRule + - PHPStan\Rules\Deprecations\InstantiationOfDeprecatedClassRule + - PHPStan\Rules\Deprecations\UsageOfDeprecatedTraitRule - PHPStan\Rules\DisallowedConstructs\DisallowedEmptyRule - PHPStan\Rules\DisallowedConstructs\DisallowedImplicitArrayCreationRule - PHPStan\Rules\Functions\MissingFunctionParameterTypehintRule From e84b84b9d9162bf9ed125acab587243480cf50bf Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Fri, 22 Jun 2018 16:55:32 +0200 Subject: [PATCH 25/30] Fix issues with new PhpParser version --- .../AccessDeprecatedPropertyRule.php | 8 +++++--- .../AccessDeprecatedStaticPropertyRule.php | 17 +++++++++++------ .../Deprecations/CallToDeprecatedMethodRule.php | 6 ++++-- .../CallToDeprecatedStaticMethodRule.php | 7 +++++-- 4 files changed, 25 insertions(+), 13 deletions(-) diff --git a/src/Rules/Deprecations/AccessDeprecatedPropertyRule.php b/src/Rules/Deprecations/AccessDeprecatedPropertyRule.php index cd8118c1..10cf279d 100644 --- a/src/Rules/Deprecations/AccessDeprecatedPropertyRule.php +++ b/src/Rules/Deprecations/AccessDeprecatedPropertyRule.php @@ -4,6 +4,7 @@ use PhpParser\Node; use PhpParser\Node\Expr\PropertyFetch; +use PhpParser\Node\Identifier; use PHPStan\Analyser\Scope; use PHPStan\Analyzer\DeprecatedScopeHelper; use PHPStan\Broker\Broker; @@ -36,17 +37,18 @@ public function processNode(Node $node, Scope $scope): array return []; } - if (!is_string($node->name)) { + if (!$node->name instanceof Identifier) { return []; } + $propertyName = $node->name->name; $propertyAccessedOnType = $scope->getType($node->var); $referencedClasses = $propertyAccessedOnType->getReferencedClasses(); foreach ($referencedClasses as $referencedClass) { try { $classReflection = $this->broker->getClass($referencedClass); - $propertyReflection = $classReflection->getProperty($node->name, $scope); + $propertyReflection = $classReflection->getProperty($propertyName, $scope); if (!$propertyReflection instanceof DeprecatableReflection) { continue; @@ -55,7 +57,7 @@ public function processNode(Node $node, Scope $scope): array if ($propertyReflection->isDeprecated()) { return [sprintf( 'Access to deprecated property %s of class %s.', - $node->name, + $propertyName, $propertyReflection->getDeclaringClass()->getName() )]; } diff --git a/src/Rules/Deprecations/AccessDeprecatedStaticPropertyRule.php b/src/Rules/Deprecations/AccessDeprecatedStaticPropertyRule.php index 370df299..6721f59a 100644 --- a/src/Rules/Deprecations/AccessDeprecatedStaticPropertyRule.php +++ b/src/Rules/Deprecations/AccessDeprecatedStaticPropertyRule.php @@ -4,12 +4,14 @@ use PhpParser\Node; use PhpParser\Node\Expr\StaticPropertyFetch; +use PhpParser\Node\Identifier; use PhpParser\Node\Name; use PHPStan\Analyser\Scope; use PHPStan\Analyzer\DeprecatedScopeHelper; use PHPStan\Broker\Broker; use PHPStan\Reflection\DeprecatableReflection; use PHPStan\Rules\RuleLevelHelper; +use PHPStan\Type\Type; class AccessDeprecatedStaticPropertyRule implements \PHPStan\Rules\Rule { @@ -42,11 +44,11 @@ public function processNode(Node $node, Scope $scope): array return []; } - if (!is_string($node->name)) { + if (!$node->name instanceof Identifier) { return []; } - $propertyName = $node->name; + $propertyName = $node->name->name; $referredClasses = []; if ($node->class instanceof Name) { @@ -55,7 +57,10 @@ public function processNode(Node $node, Scope $scope): array $classTypeResult = $this->ruleLevelHelper->findTypeToCheck( $scope, $node->class, - '%s' // We don't care about the error message + '', // We don't care about the error message + function (Type $type) use ($propertyName) { + return $type->canAccessProperties()->yes() && $type->hasProperty($propertyName); + } ); $referredClasses = $classTypeResult->getReferencedClasses(); @@ -66,15 +71,15 @@ public function processNode(Node $node, Scope $scope): array $class = $this->broker->getClass($referredClass); $property = $class->getProperty($propertyName, $scope); } catch (\PHPStan\Broker\ClassNotFoundException $e) { - return []; + continue; } catch (\PHPStan\Reflection\MissingPropertyFromReflectionException $e) { - return []; + continue; } if ($property instanceof DeprecatableReflection && $property->isDeprecated()) { return [sprintf( 'Access to deprecated static property %s of class %s.', - $node->name, + $propertyName, $referredClass )]; } diff --git a/src/Rules/Deprecations/CallToDeprecatedMethodRule.php b/src/Rules/Deprecations/CallToDeprecatedMethodRule.php index 9b1c507f..f9142615 100644 --- a/src/Rules/Deprecations/CallToDeprecatedMethodRule.php +++ b/src/Rules/Deprecations/CallToDeprecatedMethodRule.php @@ -4,6 +4,7 @@ use PhpParser\Node; use PhpParser\Node\Expr\MethodCall; +use PhpParser\Node\Identifier; use PHPStan\Analyser\Scope; use PHPStan\Analyzer\DeprecatedScopeHelper; use PHPStan\Broker\Broker; @@ -36,17 +37,18 @@ public function processNode(Node $node, Scope $scope): array return []; } - if (!is_string($node->name)) { + if (!$node->name instanceof Identifier) { return []; } + $methodName = $node->name->name; $methodCalledOnType = $scope->getType($node->var); $referencedClasses = $methodCalledOnType->getReferencedClasses(); foreach ($referencedClasses as $referencedClass) { try { $classReflection = $this->broker->getClass($referencedClass); - $methodReflection = $classReflection->getMethod($node->name, $scope); + $methodReflection = $classReflection->getMethod($methodName, $scope); if (!$methodReflection instanceof DeprecatableReflection) { continue; diff --git a/src/Rules/Deprecations/CallToDeprecatedStaticMethodRule.php b/src/Rules/Deprecations/CallToDeprecatedStaticMethodRule.php index ce817cb6..4e8477ea 100644 --- a/src/Rules/Deprecations/CallToDeprecatedStaticMethodRule.php +++ b/src/Rules/Deprecations/CallToDeprecatedStaticMethodRule.php @@ -4,6 +4,7 @@ use PhpParser\Node; use PhpParser\Node\Expr\StaticCall; +use PhpParser\Node\Identifier; use PhpParser\Node\Name; use PHPStan\Analyser\Scope; use PHPStan\Analyzer\DeprecatedScopeHelper; @@ -38,10 +39,12 @@ public function processNode(Node $node, Scope $scope): array return []; } - if (!is_string($node->name)) { + if (!$node->name instanceof Identifier) { return []; } + $methodName = $node->name->name; + if (!$node->class instanceof Name) { return []; } @@ -54,7 +57,7 @@ public function processNode(Node $node, Scope $scope): array } try { - $methodReflection = $class->getMethod($node->name, $scope); + $methodReflection = $class->getMethod($methodName, $scope); } catch (\PHPStan\Reflection\MissingMethodFromReflectionException $e) { return []; } From e5a44080ec7f1afbe9ba76d3678a595fe9d60ca2 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Fri, 22 Jun 2018 17:25:05 +0200 Subject: [PATCH 26/30] Fix code review issues for deprecation feature --- .../AccessDeprecatedPropertyRule.php | 6 +++--- .../AccessDeprecatedStaticPropertyRule.php | 20 +++++++++++-------- .../CallToDeprecatedFunctionRule.php | 1 - .../CallToDeprecatedMethodRule.php | 4 ++-- .../CallToDeprecatedStaticMethodRule.php | 1 - .../Deprecations}/DeprecatedScopeHelper.php | 2 +- ...etchingClassConstOfDeprecatedClassRule.php | 1 - ...mplementationOfDeprecatedInterfaceRule.php | 8 ++++---- .../InheritanceOfDeprecatedClassRule.php | 9 ++++----- .../InstantiationOfDeprecatedClassRule.php | 1 - .../UsageOfDeprecatedTraitRule.php | 1 - .../AccessDeprecatedPropertyRuleTest.php | 8 ++++---- ...AccessDeprecatedStaticPropertyRuleTest.php | 16 +++++++-------- ...mentationOfDeprecatedInterfaceRuleTest.php | 12 +++++------ .../InheritanceOfDeprecatedClassRuleTest.php | 4 ++-- 15 files changed, 46 insertions(+), 48 deletions(-) rename src/{Analyzer => Rules/Deprecations}/DeprecatedScopeHelper.php (92%) diff --git a/src/Rules/Deprecations/AccessDeprecatedPropertyRule.php b/src/Rules/Deprecations/AccessDeprecatedPropertyRule.php index 10cf279d..c0362024 100644 --- a/src/Rules/Deprecations/AccessDeprecatedPropertyRule.php +++ b/src/Rules/Deprecations/AccessDeprecatedPropertyRule.php @@ -6,9 +6,9 @@ use PhpParser\Node\Expr\PropertyFetch; use PhpParser\Node\Identifier; use PHPStan\Analyser\Scope; -use PHPStan\Analyzer\DeprecatedScopeHelper; use PHPStan\Broker\Broker; use PHPStan\Reflection\DeprecatableReflection; +use PHPStan\Type\TypeUtils; class AccessDeprecatedPropertyRule implements \PHPStan\Rules\Rule { @@ -43,7 +43,7 @@ public function processNode(Node $node, Scope $scope): array $propertyName = $node->name->name; $propertyAccessedOnType = $scope->getType($node->var); - $referencedClasses = $propertyAccessedOnType->getReferencedClasses(); + $referencedClasses = TypeUtils::getDirectClassNames($propertyAccessedOnType); foreach ($referencedClasses as $referencedClass) { try { @@ -56,7 +56,7 @@ public function processNode(Node $node, Scope $scope): array if ($propertyReflection->isDeprecated()) { return [sprintf( - 'Access to deprecated property %s of class %s.', + 'Access to deprecated property $%s of class %s.', $propertyName, $propertyReflection->getDeclaringClass()->getName() )]; diff --git a/src/Rules/Deprecations/AccessDeprecatedStaticPropertyRule.php b/src/Rules/Deprecations/AccessDeprecatedStaticPropertyRule.php index 6721f59a..c4768b26 100644 --- a/src/Rules/Deprecations/AccessDeprecatedStaticPropertyRule.php +++ b/src/Rules/Deprecations/AccessDeprecatedStaticPropertyRule.php @@ -7,10 +7,10 @@ use PhpParser\Node\Identifier; use PhpParser\Node\Name; use PHPStan\Analyser\Scope; -use PHPStan\Analyzer\DeprecatedScopeHelper; use PHPStan\Broker\Broker; use PHPStan\Reflection\DeprecatableReflection; use PHPStan\Rules\RuleLevelHelper; +use PHPStan\Type\ErrorType; use PHPStan\Type\Type; class AccessDeprecatedStaticPropertyRule implements \PHPStan\Rules\Rule @@ -49,10 +49,10 @@ public function processNode(Node $node, Scope $scope): array } $propertyName = $node->name->name; - $referredClasses = []; + $referencedClasses = []; if ($node->class instanceof Name) { - $referredClasses[] = (string) $node->class; + $referencedClasses[] = (string) $node->class; } else { $classTypeResult = $this->ruleLevelHelper->findTypeToCheck( $scope, @@ -63,12 +63,16 @@ function (Type $type) use ($propertyName) { } ); - $referredClasses = $classTypeResult->getReferencedClasses(); + if ($classTypeResult->getType() instanceof ErrorType) { + return []; + } + + $referencedClasses = $classTypeResult->getReferencedClasses(); } - foreach ($referredClasses as $referredClass) { + foreach ($referencedClasses as $referencedClass) { try { - $class = $this->broker->getClass($referredClass); + $class = $this->broker->getClass($referencedClass); $property = $class->getProperty($propertyName, $scope); } catch (\PHPStan\Broker\ClassNotFoundException $e) { continue; @@ -78,9 +82,9 @@ function (Type $type) use ($propertyName) { if ($property instanceof DeprecatableReflection && $property->isDeprecated()) { return [sprintf( - 'Access to deprecated static property %s of class %s.', + 'Access to deprecated static property $%s of class %s.', $propertyName, - $referredClass + $referencedClass )]; } } diff --git a/src/Rules/Deprecations/CallToDeprecatedFunctionRule.php b/src/Rules/Deprecations/CallToDeprecatedFunctionRule.php index f8b1db00..fd4fbad0 100644 --- a/src/Rules/Deprecations/CallToDeprecatedFunctionRule.php +++ b/src/Rules/Deprecations/CallToDeprecatedFunctionRule.php @@ -5,7 +5,6 @@ use PhpParser\Node; use PhpParser\Node\Expr\FuncCall; use PHPStan\Analyser\Scope; -use PHPStan\Analyzer\DeprecatedScopeHelper; use PHPStan\Broker\Broker; class CallToDeprecatedFunctionRule implements \PHPStan\Rules\Rule diff --git a/src/Rules/Deprecations/CallToDeprecatedMethodRule.php b/src/Rules/Deprecations/CallToDeprecatedMethodRule.php index f9142615..5870176c 100644 --- a/src/Rules/Deprecations/CallToDeprecatedMethodRule.php +++ b/src/Rules/Deprecations/CallToDeprecatedMethodRule.php @@ -6,9 +6,9 @@ use PhpParser\Node\Expr\MethodCall; use PhpParser\Node\Identifier; use PHPStan\Analyser\Scope; -use PHPStan\Analyzer\DeprecatedScopeHelper; use PHPStan\Broker\Broker; use PHPStan\Reflection\DeprecatableReflection; +use PHPStan\Type\TypeUtils; class CallToDeprecatedMethodRule implements \PHPStan\Rules\Rule { @@ -43,7 +43,7 @@ public function processNode(Node $node, Scope $scope): array $methodName = $node->name->name; $methodCalledOnType = $scope->getType($node->var); - $referencedClasses = $methodCalledOnType->getReferencedClasses(); + $referencedClasses = TypeUtils::getDirectClassNames($methodCalledOnType); foreach ($referencedClasses as $referencedClass) { try { diff --git a/src/Rules/Deprecations/CallToDeprecatedStaticMethodRule.php b/src/Rules/Deprecations/CallToDeprecatedStaticMethodRule.php index 4e8477ea..cdddc8dc 100644 --- a/src/Rules/Deprecations/CallToDeprecatedStaticMethodRule.php +++ b/src/Rules/Deprecations/CallToDeprecatedStaticMethodRule.php @@ -7,7 +7,6 @@ use PhpParser\Node\Identifier; use PhpParser\Node\Name; use PHPStan\Analyser\Scope; -use PHPStan\Analyzer\DeprecatedScopeHelper; use PHPStan\Broker\Broker; use PHPStan\Reflection\ClassReflection; use PHPStan\Reflection\DeprecatableReflection; diff --git a/src/Analyzer/DeprecatedScopeHelper.php b/src/Rules/Deprecations/DeprecatedScopeHelper.php similarity index 92% rename from src/Analyzer/DeprecatedScopeHelper.php rename to src/Rules/Deprecations/DeprecatedScopeHelper.php index 0eb8a736..583c1d68 100644 --- a/src/Analyzer/DeprecatedScopeHelper.php +++ b/src/Rules/Deprecations/DeprecatedScopeHelper.php @@ -1,6 +1,6 @@ isDeprecated()) { if (!$class->getNativeReflection()->isAnonymous()) { $errors[] = sprintf( - 'Implementation of deprecated interface %s in class %s.', - $interfaceName, - $className + 'Class %s implements deprecated interface %s.', + $className, + $interfaceName ); } else { $errors[] = sprintf( - 'Implementation of deprecated interface %s in an anonymous class.', + 'Anonymous class implements deprecated interface %s.', $interfaceName ); } diff --git a/src/Rules/Deprecations/InheritanceOfDeprecatedClassRule.php b/src/Rules/Deprecations/InheritanceOfDeprecatedClassRule.php index 71e7a754..161ae423 100644 --- a/src/Rules/Deprecations/InheritanceOfDeprecatedClassRule.php +++ b/src/Rules/Deprecations/InheritanceOfDeprecatedClassRule.php @@ -5,7 +5,6 @@ use PhpParser\Node; use PhpParser\Node\Stmt\Class_; use PHPStan\Analyser\Scope; -use PHPStan\Analyzer\DeprecatedScopeHelper; use PHPStan\Broker\Broker; class InheritanceOfDeprecatedClassRule implements \PHPStan\Rules\Rule @@ -59,13 +58,13 @@ public function processNode(Node $node, Scope $scope): array if ($parentClass->isDeprecated()) { if (!$class->getNativeReflection()->isAnonymous()) { $errors[] = sprintf( - 'Inheritance of deprecated class %s in class %s.', - $parentClassName, - $className + 'Class %s extends deprecated class %s.', + $className, + $parentClassName ); } else { $errors[] = sprintf( - 'Inheritance of deprecated class %s in an anonymous class.', + 'Anonymous class extends deprecated class %s.', $parentClassName ); } diff --git a/src/Rules/Deprecations/InstantiationOfDeprecatedClassRule.php b/src/Rules/Deprecations/InstantiationOfDeprecatedClassRule.php index e3aa2176..f33f36ab 100644 --- a/src/Rules/Deprecations/InstantiationOfDeprecatedClassRule.php +++ b/src/Rules/Deprecations/InstantiationOfDeprecatedClassRule.php @@ -6,7 +6,6 @@ use PhpParser\Node\Expr\New_; use PhpParser\Node\Name; use PHPStan\Analyser\Scope; -use PHPStan\Analyzer\DeprecatedScopeHelper; use PHPStan\Broker\Broker; class InstantiationOfDeprecatedClassRule implements \PHPStan\Rules\Rule diff --git a/src/Rules/Deprecations/UsageOfDeprecatedTraitRule.php b/src/Rules/Deprecations/UsageOfDeprecatedTraitRule.php index 7a358078..19018ce3 100644 --- a/src/Rules/Deprecations/UsageOfDeprecatedTraitRule.php +++ b/src/Rules/Deprecations/UsageOfDeprecatedTraitRule.php @@ -5,7 +5,6 @@ use PhpParser\Node; use PhpParser\Node\Stmt\TraitUse; use PHPStan\Analyser\Scope; -use PHPStan\Analyzer\DeprecatedScopeHelper; use PHPStan\Broker\Broker; class UsageOfDeprecatedTraitRule implements \PHPStan\Rules\Rule diff --git a/tests/Rules/Deprecations/AccessDeprecatedPropertyRuleTest.php b/tests/Rules/Deprecations/AccessDeprecatedPropertyRuleTest.php index 9a2997dd..74a43c5a 100644 --- a/tests/Rules/Deprecations/AccessDeprecatedPropertyRuleTest.php +++ b/tests/Rules/Deprecations/AccessDeprecatedPropertyRuleTest.php @@ -18,19 +18,19 @@ public function testAccessDeprecatedProperty(): void [__DIR__ . '/data/access-deprecated-property.php'], [ [ - 'Access to deprecated property deprecatedFoo of class AccessDeprecatedProperty\Foo.', + 'Access to deprecated property $deprecatedFoo of class AccessDeprecatedProperty\Foo.', 10, ], [ - 'Access to deprecated property deprecatedFoo of class AccessDeprecatedProperty\Foo.', + 'Access to deprecated property $deprecatedFoo of class AccessDeprecatedProperty\Foo.', 11, ], [ - 'Access to deprecated property deprecatedFooFromTrait of class AccessDeprecatedProperty\Foo.', + 'Access to deprecated property $deprecatedFooFromTrait of class AccessDeprecatedProperty\Foo.', 16, ], [ - 'Access to deprecated property deprecatedFooFromTrait of class AccessDeprecatedProperty\Foo.', + 'Access to deprecated property $deprecatedFooFromTrait of class AccessDeprecatedProperty\Foo.', 17, ], ] diff --git a/tests/Rules/Deprecations/AccessDeprecatedStaticPropertyRuleTest.php b/tests/Rules/Deprecations/AccessDeprecatedStaticPropertyRuleTest.php index 77efeb31..75bc1bd6 100644 --- a/tests/Rules/Deprecations/AccessDeprecatedStaticPropertyRuleTest.php +++ b/tests/Rules/Deprecations/AccessDeprecatedStaticPropertyRuleTest.php @@ -22,35 +22,35 @@ public function testAccessDeprecatedStaticProperty(): void [__DIR__ . '/data/access-deprecated-static-property.php'], [ [ - 'Access to deprecated static property deprecatedFoo of class AccessDeprecatedStaticProperty\Foo.', + 'Access to deprecated static property $deprecatedFoo of class AccessDeprecatedStaticProperty\Foo.', 8, ], [ - 'Access to deprecated static property deprecatedFoo of class AccessDeprecatedStaticProperty\Foo.', + 'Access to deprecated static property $deprecatedFoo of class AccessDeprecatedStaticProperty\Foo.', 9, ], [ - 'Access to deprecated static property deprecatedFoo of class AccessDeprecatedStaticProperty\Foo.', + 'Access to deprecated static property $deprecatedFoo of class AccessDeprecatedStaticProperty\Foo.', 16, ], [ - 'Access to deprecated static property deprecatedFoo of class AccessDeprecatedStaticProperty\Foo.', + 'Access to deprecated static property $deprecatedFoo of class AccessDeprecatedStaticProperty\Foo.', 17, ], [ - 'Access to deprecated static property deprecatedFooFromTrait of class AccessDeprecatedStaticProperty\FooTrait.', + 'Access to deprecated static property $deprecatedFooFromTrait of class AccessDeprecatedStaticProperty\FooTrait.', 22, ], [ - 'Access to deprecated static property deprecatedFooFromTrait of class AccessDeprecatedStaticProperty\FooTrait.', + 'Access to deprecated static property $deprecatedFooFromTrait of class AccessDeprecatedStaticProperty\FooTrait.', 23, ], [ - 'Access to deprecated static property deprecatedFooFromTrait of class AccessDeprecatedStaticProperty\Foo.', + 'Access to deprecated static property $deprecatedFooFromTrait of class AccessDeprecatedStaticProperty\Foo.', 30, ], [ - 'Access to deprecated static property deprecatedFooFromTrait of class AccessDeprecatedStaticProperty\Foo.', + 'Access to deprecated static property $deprecatedFooFromTrait of class AccessDeprecatedStaticProperty\Foo.', 31, ], ] diff --git a/tests/Rules/Deprecations/ImplementationOfDeprecatedInterfaceRuleTest.php b/tests/Rules/Deprecations/ImplementationOfDeprecatedInterfaceRuleTest.php index fe63dd03..3a5c3673 100644 --- a/tests/Rules/Deprecations/ImplementationOfDeprecatedInterfaceRuleTest.php +++ b/tests/Rules/Deprecations/ImplementationOfDeprecatedInterfaceRuleTest.php @@ -18,15 +18,15 @@ public function testImplementationOfDeprecatedInterfacesInClasses(): void [__DIR__ . '/data/implementation-of-deprecated-interface-in-classes.php'], [ [ - 'Implementation of deprecated interface ImplementationOfDeprecatedInterface\DeprecatedFooable in class ImplementationOfDeprecatedInterface\Foo2.', + 'Class ImplementationOfDeprecatedInterface\Foo2 implements deprecated interface ImplementationOfDeprecatedInterface\DeprecatedFooable.', 10, ], [ - 'Implementation of deprecated interface ImplementationOfDeprecatedInterface\DeprecatedFooable in class ImplementationOfDeprecatedInterface\Foo3.', + 'Class ImplementationOfDeprecatedInterface\Foo3 implements deprecated interface ImplementationOfDeprecatedInterface\DeprecatedFooable.', 15, ], [ - 'Implementation of deprecated interface ImplementationOfDeprecatedInterface\DeprecatedFooable2 in class ImplementationOfDeprecatedInterface\Foo3.', + 'Class ImplementationOfDeprecatedInterface\Foo3 implements deprecated interface ImplementationOfDeprecatedInterface\DeprecatedFooable2.', 15, ], ] @@ -42,15 +42,15 @@ public function testImplementationOfDeprecatedInterfacesInAnonymousClasses(): vo [__DIR__ . '/data/implementation-of-deprecated-interface-in-anonymous-classes.php'], [ [ - 'Implementation of deprecated interface ImplementationOfDeprecatedInterface\DeprecatedFooable in an anonymous class.', + 'Anonymous class implements deprecated interface ImplementationOfDeprecatedInterface\DeprecatedFooable.', 9, ], [ - 'Implementation of deprecated interface ImplementationOfDeprecatedInterface\DeprecatedFooable in an anonymous class.', + 'Anonymous class implements deprecated interface ImplementationOfDeprecatedInterface\DeprecatedFooable.', 13, ], [ - 'Implementation of deprecated interface ImplementationOfDeprecatedInterface\DeprecatedFooable2 in an anonymous class.', + 'Anonymous class implements deprecated interface ImplementationOfDeprecatedInterface\DeprecatedFooable2.', 13, ], ] diff --git a/tests/Rules/Deprecations/InheritanceOfDeprecatedClassRuleTest.php b/tests/Rules/Deprecations/InheritanceOfDeprecatedClassRuleTest.php index b44a5dfb..9b6f41d3 100644 --- a/tests/Rules/Deprecations/InheritanceOfDeprecatedClassRuleTest.php +++ b/tests/Rules/Deprecations/InheritanceOfDeprecatedClassRuleTest.php @@ -18,7 +18,7 @@ public function testInheritanceOfDeprecatedClassInClasses(): void [__DIR__ . '/data/inheritance-of-deprecated-class-in-classes.php'], [ [ - 'Inheritance of deprecated class InheritanceOfDeprecatedClass\DeprecatedFoo in class InheritanceOfDeprecatedClass\Bar2.', + 'Class InheritanceOfDeprecatedClass\Bar2 extends deprecated class InheritanceOfDeprecatedClass\DeprecatedFoo.', 10, ], ] @@ -34,7 +34,7 @@ public function testInheritanceOfDeprecatedClassInAnonymousClasses(): void [__DIR__ . '/data/inheritance-of-deprecated-class-in-anonymous-classes.php'], [ [ - 'Inheritance of deprecated class InheritanceOfDeprecatedClass\DeprecatedFoo in an anonymous class.', + 'Anonymous class extends deprecated class InheritanceOfDeprecatedClass\DeprecatedFoo.', 9, ], ] From 7a8f54bbae4eaa3c7070a53fd73ad208a5de0d53 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Sat, 23 Jun 2018 15:52:50 +0200 Subject: [PATCH 27/30] Use RuleLevelHelper::findTypeToCheck when symbol is not a Name --- .../CallToDeprecatedStaticMethodRule.php | 92 +++++++++---------- ...etchingClassConstOfDeprecatedClassRule.php | 76 ++++++++++++--- .../InstantiationOfDeprecatedClassRule.php | 60 +++++++++--- .../CallToDeprecatedStaticMethodRuleTest.php | 6 +- ...ingClassConstOfDeprecatedClassRuleTest.php | 20 +++- ...InstantiationOfDeprecatedClassRuleTest.php | 6 +- ...s-const-of-deprecated-class-definition.php | 14 +++ ...tching-class-const-of-deprecated-class.php | 6 ++ 8 files changed, 202 insertions(+), 78 deletions(-) diff --git a/src/Rules/Deprecations/CallToDeprecatedStaticMethodRule.php b/src/Rules/Deprecations/CallToDeprecatedStaticMethodRule.php index cdddc8dc..47184892 100644 --- a/src/Rules/Deprecations/CallToDeprecatedStaticMethodRule.php +++ b/src/Rules/Deprecations/CallToDeprecatedStaticMethodRule.php @@ -8,8 +8,10 @@ use PhpParser\Node\Name; use PHPStan\Analyser\Scope; use PHPStan\Broker\Broker; -use PHPStan\Reflection\ClassReflection; use PHPStan\Reflection\DeprecatableReflection; +use PHPStan\Rules\RuleLevelHelper; +use PHPStan\Type\ErrorType; +use PHPStan\Type\Type; class CallToDeprecatedStaticMethodRule implements \PHPStan\Rules\Rule { @@ -17,9 +19,13 @@ class CallToDeprecatedStaticMethodRule implements \PHPStan\Rules\Rule /** @var Broker */ private $broker; - public function __construct(Broker $broker) + /** @var RuleLevelHelper */ + private $ruleLevelHelper; + + public function __construct(Broker $broker, RuleLevelHelper $ruleLevelHelper) { $this->broker = $broker; + $this->ruleLevelHelper = $ruleLevelHelper; } public function getNodeType(): string @@ -43,35 +49,51 @@ public function processNode(Node $node, Scope $scope): array } $methodName = $node->name->name; + $referencedClasses = []; + + if ($node->class instanceof Name) { + $referencedClasses[] = $scope->resolveName($node->class); + } else { + $classTypeResult = $this->ruleLevelHelper->findTypeToCheck( + $scope, + $node->class, + '', // We don't care about the error message + function (Type $type) use ($methodName) { + return $type->canCallMethods()->yes() && $type->hasMethod($methodName); + } + ); - if (!$node->class instanceof Name) { - return []; - } - - $className = (string) $node->class; - $class = $this->getClassWithClassName($className, $scope); - - if ($class === null) { - return []; - } + if ($classTypeResult->getType() instanceof ErrorType) { + return []; + } - try { - $methodReflection = $class->getMethod($methodName, $scope); - } catch (\PHPStan\Reflection\MissingMethodFromReflectionException $e) { - return []; + $referencedClasses = $classTypeResult->getReferencedClasses(); } $errors = []; - if ($class->isDeprecated()) { - $errors[] = sprintf( - 'Call to method %s() of deprecated class %s.', - $methodReflection->getName(), - $methodReflection->getDeclaringClass()->getName() - ); - } + foreach ($referencedClasses as $referencedClass) { + try { + $class = $this->broker->getClass($referencedClass); + $methodReflection = $class->getMethod($methodName, $scope); + } catch (\PHPStan\Broker\ClassNotFoundException $e) { + continue; + } catch (\PHPStan\Reflection\MissingMethodFromReflectionException $e) { + continue; + } + + if ($class->isDeprecated()) { + $errors[] = sprintf( + 'Call to method %s() of deprecated class %s.', + $methodReflection->getName(), + $methodReflection->getDeclaringClass()->getName() + ); + } + + if (!$methodReflection instanceof DeprecatableReflection || !$methodReflection->isDeprecated()) { + continue; + } - if ($methodReflection instanceof DeprecatableReflection && $methodReflection->isDeprecated()) { $errors[] = sprintf( 'Call to deprecated method %s() of class %s.', $methodReflection->getName(), @@ -82,26 +104,4 @@ public function processNode(Node $node, Scope $scope): array return $errors; } - private function getClassWithClassName(string $className, Scope $scope): ?ClassReflection - { - if ($className === 'parent') { - if (!$scope->isInClass()) { - return null; - } - - $class = $scope->getClassReflection(); - $class = $class->getParentClass(); - - return $class !== false - ? $class - : null; - } - - try { - return $this->broker->getClass($className); - } catch (\PHPStan\Broker\ClassNotFoundException $e) { - return null; - } - } - } diff --git a/src/Rules/Deprecations/FetchingClassConstOfDeprecatedClassRule.php b/src/Rules/Deprecations/FetchingClassConstOfDeprecatedClassRule.php index a67e8c51..7bac6b1e 100644 --- a/src/Rules/Deprecations/FetchingClassConstOfDeprecatedClassRule.php +++ b/src/Rules/Deprecations/FetchingClassConstOfDeprecatedClassRule.php @@ -4,9 +4,14 @@ use PhpParser\Node; use PhpParser\Node\Expr\ClassConstFetch; +use PhpParser\Node\Identifier; use PhpParser\Node\Name; use PHPStan\Analyser\Scope; use PHPStan\Broker\Broker; +use PHPStan\Reflection\DeprecatableReflection; +use PHPStan\Rules\RuleLevelHelper; +use PHPStan\Type\ErrorType; +use PHPStan\Type\Type; class FetchingClassConstOfDeprecatedClassRule implements \PHPStan\Rules\Rule { @@ -14,9 +19,13 @@ class FetchingClassConstOfDeprecatedClassRule implements \PHPStan\Rules\Rule /** @var Broker */ private $broker; - public function __construct(Broker $broker) + /** @var RuleLevelHelper */ + private $ruleLevelHelper; + + public function __construct(Broker $broker, RuleLevelHelper $ruleLevelHelper) { $this->broker = $broker; + $this->ruleLevelHelper = $ruleLevelHelper; } public function getNodeType(): string @@ -35,26 +44,67 @@ public function processNode(Node $node, Scope $scope): array return []; } - if (!$node->class instanceof Name) { + if (!$node->name instanceof Identifier) { return []; } - $className = (string) $node->class; + $constantName = $node->name->name; + $referencedClasses = []; - try { - $class = $this->broker->getClass($className); - } catch (\PHPStan\Broker\ClassNotFoundException $e) { - return []; + if ($node->class instanceof Name) { + $referencedClasses[] = $scope->resolveName($node->class); + } else { + $classTypeResult = $this->ruleLevelHelper->findTypeToCheck( + $scope, + $node->class, + '', // We don't care about the error message + function (Type $type) use ($constantName) { + return $type->canAccessConstants()->yes() && $type->hasConstant($constantName); + } + ); + + if ($classTypeResult->getType() instanceof ErrorType) { + return []; + } + + $referencedClasses = $classTypeResult->getReferencedClasses(); } - if (!$class->isDeprecated()) { - return []; + $errors = []; + + foreach ($referencedClasses as $referencedClass) { + try { + $class = $this->broker->getClass($referencedClass); + } catch (\PHPStan\Broker\ClassNotFoundException $e) { + continue; + } + + if ($class->isDeprecated()) { + $errors[] = sprintf( + 'Fetching class constant %s of deprecated class %s.', + $constantName, + $referencedClass + ); + } + + if (!$class->hasConstant($constantName)) { + continue; + } + + $constantReflection = $class->getConstant($constantName); + + if (!$constantReflection instanceof DeprecatableReflection || !$constantReflection->isDeprecated()) { + continue; + } + + $errors[] = sprintf( + 'Fetching deprecated class constant %s of class %s.', + $constantName, + $referencedClass + ); } - return [sprintf( - 'Fetching class constant of deprecated class %s.', - $className - )]; + return $errors; } } diff --git a/src/Rules/Deprecations/InstantiationOfDeprecatedClassRule.php b/src/Rules/Deprecations/InstantiationOfDeprecatedClassRule.php index f33f36ab..363b03ca 100644 --- a/src/Rules/Deprecations/InstantiationOfDeprecatedClassRule.php +++ b/src/Rules/Deprecations/InstantiationOfDeprecatedClassRule.php @@ -5,8 +5,11 @@ use PhpParser\Node; use PhpParser\Node\Expr\New_; use PhpParser\Node\Name; +use PhpParser\Node\Stmt\Class_; use PHPStan\Analyser\Scope; use PHPStan\Broker\Broker; +use PHPStan\Rules\RuleLevelHelper; +use PHPStan\Type\ErrorType; class InstantiationOfDeprecatedClassRule implements \PHPStan\Rules\Rule { @@ -14,9 +17,13 @@ class InstantiationOfDeprecatedClassRule implements \PHPStan\Rules\Rule /** @var Broker */ private $broker; - public function __construct(Broker $broker) + /** @var RuleLevelHelper */ + private $ruleLevelHelper; + + public function __construct(Broker $broker, RuleLevelHelper $ruleLevelHelper) { $this->broker = $broker; + $this->ruleLevelHelper = $ruleLevelHelper; } public function getNodeType(): string @@ -35,26 +42,49 @@ public function processNode(Node $node, Scope $scope): array return []; } - if (!$node->class instanceof Name) { - return []; - } + $referencedClasses = []; - $className = (string) $node->class; + if ($node->class instanceof Name) { + $referencedClasses[] = $scope->resolveName($node->class); + } elseif ($node->class instanceof Class_) { + $referencedClasses[] = $scope->resolveName($node->class->namespacedName); + } else { + $classTypeResult = $this->ruleLevelHelper->findTypeToCheck( + $scope, + $node->class, + '', // We don't care about the error message + function () { + return true; + } + ); - try { - $class = $this->broker->getClass($className); - } catch (\PHPStan\Broker\ClassNotFoundException $e) { - return []; + if ($classTypeResult->getType() instanceof ErrorType) { + return []; + } + + $referencedClasses = $classTypeResult->getReferencedClasses(); } - if (!$class->isDeprecated()) { - return []; + $errors = []; + + foreach ($referencedClasses as $referencedClass) { + try { + $class = $this->broker->getClass($referencedClass); + } catch (\PHPStan\Broker\ClassNotFoundException $e) { + continue; + } + + if (!$class->isDeprecated()) { + continue; + } + + $errors[] = sprintf( + 'Instantiation of deprecated class %s.', + $referencedClass + ); } - return [sprintf( - 'Instantiation of deprecated class %s.', - $className - )]; + return $errors; } } diff --git a/tests/Rules/Deprecations/CallToDeprecatedStaticMethodRuleTest.php b/tests/Rules/Deprecations/CallToDeprecatedStaticMethodRuleTest.php index 669b835c..e5b586db 100644 --- a/tests/Rules/Deprecations/CallToDeprecatedStaticMethodRuleTest.php +++ b/tests/Rules/Deprecations/CallToDeprecatedStaticMethodRuleTest.php @@ -2,13 +2,17 @@ namespace PHPStan\Rules\Deprecations; +use PHPStan\Rules\RuleLevelHelper; + class CallToDeprecatedStaticMethodRuleTest extends \PHPStan\Testing\RuleTestCase { protected function getRule(): \PHPStan\Rules\Rule { $broker = $this->createBroker(); - return new CallToDeprecatedStaticMethodRule($broker); + $ruleLevelHelper = new RuleLevelHelper($this->createBroker(), true, false, true); + + return new CallToDeprecatedStaticMethodRule($broker, $ruleLevelHelper); } public function testDeprecatedStaticMethodCall(): void diff --git a/tests/Rules/Deprecations/FetchingClassConstOfDeprecatedClassRuleTest.php b/tests/Rules/Deprecations/FetchingClassConstOfDeprecatedClassRuleTest.php index f93ad82b..d64551c3 100644 --- a/tests/Rules/Deprecations/FetchingClassConstOfDeprecatedClassRuleTest.php +++ b/tests/Rules/Deprecations/FetchingClassConstOfDeprecatedClassRuleTest.php @@ -2,13 +2,17 @@ namespace PHPStan\Rules\Deprecations; +use PHPStan\Rules\RuleLevelHelper; + class FetchingClassConstOfDeprecatedClassRuleTest extends \PHPStan\Testing\RuleTestCase { protected function getRule(): \PHPStan\Rules\Rule { $broker = $this->createBroker(); - return new FetchingClassConstOfDeprecatedClassRule($broker); + $ruleLevelHelper = new RuleLevelHelper($this->createBroker(), true, false, true); + + return new FetchingClassConstOfDeprecatedClassRule($broker, $ruleLevelHelper); } public function testFetchingClassConstOfDeprecatedClass(): void @@ -18,9 +22,21 @@ public function testFetchingClassConstOfDeprecatedClass(): void [__DIR__ . '/data/fetching-class-const-of-deprecated-class.php'], [ [ - 'Fetching class constant of deprecated class FetchingClassConstOfDeprecatedClass\DeprecatedFoo.', + 'Fetching class constant class of deprecated class FetchingClassConstOfDeprecatedClass\DeprecatedFoo.', 6, ], + [ + 'Fetching deprecated class constant DEPRECATED_FOO of class FetchingClassConstOfDeprecatedClass\Foo.', + 9, + ], + [ + 'Fetching class constant class of deprecated class FetchingClassConstOfDeprecatedClass\DeprecatedFoo.', + 11, + ], + [ + 'Fetching class constant class of deprecated class FetchingClassConstOfDeprecatedClass\DeprecatedFoo.', + 12, + ], ] ); } diff --git a/tests/Rules/Deprecations/InstantiationOfDeprecatedClassRuleTest.php b/tests/Rules/Deprecations/InstantiationOfDeprecatedClassRuleTest.php index 9efcdff5..9b3a8fd4 100644 --- a/tests/Rules/Deprecations/InstantiationOfDeprecatedClassRuleTest.php +++ b/tests/Rules/Deprecations/InstantiationOfDeprecatedClassRuleTest.php @@ -2,13 +2,17 @@ namespace PHPStan\Rules\Deprecations; +use PHPStan\Rules\RuleLevelHelper; + class InstantiationOfDeprecatedClassRuleTest extends \PHPStan\Testing\RuleTestCase { protected function getRule(): \PHPStan\Rules\Rule { $broker = $this->createBroker(); - return new InstantiationOfDeprecatedClassRule($broker); + $ruleLevelHelper = new RuleLevelHelper($this->createBroker(), true, false, true); + + return new InstantiationOfDeprecatedClassRule($broker, $ruleLevelHelper); } public function testInstantiationOfDeprecatedClass(): void diff --git a/tests/Rules/Deprecations/data/fetching-class-const-of-deprecated-class-definition.php b/tests/Rules/Deprecations/data/fetching-class-const-of-deprecated-class-definition.php index 3e1fcdeb..f872a9a1 100644 --- a/tests/Rules/Deprecations/data/fetching-class-const-of-deprecated-class-definition.php +++ b/tests/Rules/Deprecations/data/fetching-class-const-of-deprecated-class-definition.php @@ -5,6 +5,13 @@ class Foo { + public const FOO = 'FOO'; + + /** + * @deprecated + */ + public const DEPRECATED_FOO = 'FOO'; + } /** @@ -13,4 +20,11 @@ class Foo class DeprecatedFoo { + public const FOO = 'FOO'; + + /** + * @deprecated + */ + public const DEPRECATED_FOO = 'FOO'; + } diff --git a/tests/Rules/Deprecations/data/fetching-class-const-of-deprecated-class.php b/tests/Rules/Deprecations/data/fetching-class-const-of-deprecated-class.php index 27dae6e7..45f7fa65 100644 --- a/tests/Rules/Deprecations/data/fetching-class-const-of-deprecated-class.php +++ b/tests/Rules/Deprecations/data/fetching-class-const-of-deprecated-class.php @@ -5,6 +5,12 @@ Foo::class; DeprecatedFoo::class; +Foo::FOO; +Foo::DEPRECATED_FOO; + +DeprecatedFoo::class; +DeprecatedFoo::class; + /** * @deprecated */ From 028e681d6632db4df186e0a5cefe75dac8ae8037 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Sat, 23 Jun 2018 16:04:16 +0200 Subject: [PATCH 28/30] Extend DeprecatedScopeHelper to check traits --- src/Rules/Deprecations/DeprecatedScopeHelper.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Rules/Deprecations/DeprecatedScopeHelper.php b/src/Rules/Deprecations/DeprecatedScopeHelper.php index 583c1d68..bd99a418 100644 --- a/src/Rules/Deprecations/DeprecatedScopeHelper.php +++ b/src/Rules/Deprecations/DeprecatedScopeHelper.php @@ -15,6 +15,11 @@ public static function isScopeDeprecated(Scope $scope): bool return true; } + $trait = $scope->getTraitReflection(); + if ($trait !== null && $trait->isDeprecated()) { + return true; + } + $function = $scope->getFunction(); if ($function instanceof DeprecatableReflection && $function->isDeprecated()) { return true; From 0e86531b9ae00da33267f2e28009592ae51e1346 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Sat, 23 Jun 2018 17:51:53 +0200 Subject: [PATCH 29/30] Add rule to check for inheritance of deprecated interfaces in interfaces --- rules.neon | 1 + .../InheritanceOfDeprecatedInterfaceRule.php | 74 +++++++++++++++++++ ...heritanceOfDeprecatedInterfaceRuleTest.php | 36 +++++++++ ...nce-of-deprecated-interface-definition.php | 24 ++++++ .../inheritance-of-deprecated-interface.php | 42 +++++++++++ 5 files changed, 177 insertions(+) create mode 100644 src/Rules/Deprecations/InheritanceOfDeprecatedInterfaceRule.php create mode 100644 tests/Rules/Deprecations/InheritanceOfDeprecatedInterfaceRuleTest.php create mode 100644 tests/Rules/Deprecations/data/inheritance-of-deprecated-interface-definition.php create mode 100644 tests/Rules/Deprecations/data/inheritance-of-deprecated-interface.php diff --git a/rules.neon b/rules.neon index 88acdf47..dd4dd5b0 100644 --- a/rules.neon +++ b/rules.neon @@ -20,6 +20,7 @@ rules: - PHPStan\Rules\Deprecations\FetchingClassConstOfDeprecatedClassRule - PHPStan\Rules\Deprecations\ImplementationOfDeprecatedInterfaceRule - PHPStan\Rules\Deprecations\InheritanceOfDeprecatedClassRule + - PHPStan\Rules\Deprecations\InheritanceOfDeprecatedInterfaceRule - PHPStan\Rules\Deprecations\InstantiationOfDeprecatedClassRule - PHPStan\Rules\Deprecations\UsageOfDeprecatedTraitRule - PHPStan\Rules\DisallowedConstructs\DisallowedEmptyRule diff --git a/src/Rules/Deprecations/InheritanceOfDeprecatedInterfaceRule.php b/src/Rules/Deprecations/InheritanceOfDeprecatedInterfaceRule.php new file mode 100644 index 00000000..9cc2b8b1 --- /dev/null +++ b/src/Rules/Deprecations/InheritanceOfDeprecatedInterfaceRule.php @@ -0,0 +1,74 @@ +broker = $broker; + } + + public function getNodeType(): string + { + return Interface_::class; + } + + /** + * @param Interface_ $node + * @param \PHPStan\Analyser\Scope $scope + * @return string[] errors + */ + public function processNode(Node $node, Scope $scope): array + { + if ($node->extends === null) { + return []; + } + + $interfaceName = isset($node->namespacedName) + ? (string) $node->namespacedName + : (string) $node->name; + + try { + $interface = $this->broker->getClass($interfaceName); + } catch (\PHPStan\Broker\ClassNotFoundException $e) { + return []; + } + + if ($interface->isDeprecated()) { + return []; + } + + $errors = []; + + foreach ($node->extends as $parentInterfaceName) { + $parentInterfaceName = (string) $parentInterfaceName; + + try { + $parentInterface = $this->broker->getClass($parentInterfaceName); + + if ($parentInterface->isDeprecated()) { + $errors[] = sprintf( + 'Interface %s extends deprecated interface %s.', + $interfaceName, + $parentInterfaceName + ); + } + } catch (\PHPStan\Broker\ClassNotFoundException $e) { + // Other rules will notify if the interface is not found + } + } + + return $errors; + } + +} diff --git a/tests/Rules/Deprecations/InheritanceOfDeprecatedInterfaceRuleTest.php b/tests/Rules/Deprecations/InheritanceOfDeprecatedInterfaceRuleTest.php new file mode 100644 index 00000000..769892b6 --- /dev/null +++ b/tests/Rules/Deprecations/InheritanceOfDeprecatedInterfaceRuleTest.php @@ -0,0 +1,36 @@ +createBroker(); + return new InheritanceOfDeprecatedInterfaceRule($broker); + } + + public function testInheritanceOfDeprecatedInterfaces(): void + { + require_once __DIR__ . '/data/inheritance-of-deprecated-interface-definition.php'; + $this->analyse( + [__DIR__ . '/data/inheritance-of-deprecated-interface.php'], + [ + [ + 'Interface InheritanceOfDeprecatedInterface\Foo2 extends deprecated interface InheritanceOfDeprecatedInterface\DeprecatedFooable.', + 10, + ], + [ + 'Interface InheritanceOfDeprecatedInterface\Foo3 extends deprecated interface InheritanceOfDeprecatedInterface\DeprecatedFooable.', + 15, + ], + [ + 'Interface InheritanceOfDeprecatedInterface\Foo3 extends deprecated interface InheritanceOfDeprecatedInterface\DeprecatedFooable2.', + 15, + ], + ] + ); + } + +} diff --git a/tests/Rules/Deprecations/data/inheritance-of-deprecated-interface-definition.php b/tests/Rules/Deprecations/data/inheritance-of-deprecated-interface-definition.php new file mode 100644 index 00000000..42833782 --- /dev/null +++ b/tests/Rules/Deprecations/data/inheritance-of-deprecated-interface-definition.php @@ -0,0 +1,24 @@ + Date: Sat, 23 Jun 2018 17:55:34 +0200 Subject: [PATCH 30/30] Add deprecation feature to README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index d22abcf8..151899f3 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ * Always true `instanceof`, type-checking `is_*` functions and strict comparisons `===`/`!==`. These checks can be turned off by setting `checkAlwaysTrueInstanceof`/`checkAlwaysTrueCheckTypeFunctionCall`/`checkAlwaysTrueStrictComparison` to false. * Correct case for referenced and called function names. * Correct case for inherited and implemented method names. +* Disallows the usage of deprecated code. Additional rules are coming in subsequent releases!