Ver código fonte

Added PHPStan rule that checks we don't use $this in closures.

Adam Žurek 5 anos atrás
pai
commit
e5b13b4c8f

+ 1 - 0
.gitattributes

@@ -15,3 +15,4 @@
 .travis.yml export-ignore
 appveyor.yml export-ignore
 phpunit.xml.dist export-ignore
+/phpstan/ export-ignore

+ 7 - 2
composer.json

@@ -66,8 +66,13 @@
     },
     "autoload-dev": {
         "psr-4": {
-            "Composer\\Test\\": "tests/Composer/Test"
-        }
+            "Composer\\Test\\": "tests/Composer/Test",
+            "Composer\\PHPStanRules\\": "phpstan/Rules/src",
+            "Composer\\PHPStanRulesTests\\": "phpstan/Rules/tests"
+        },
+        "classmap": [
+            "phpstan/Rules/tests/data"
+        ]
     },
     "bin": [
         "bin/composer"

+ 46 - 0
phpstan/Rules/src/AnonymousFunctionWithThisRule.php

@@ -0,0 +1,46 @@
+<?php declare(strict_types = 1);
+
+namespace Composer\PHPStanRules;
+
+use PhpParser\Node;
+use PHPStan\Analyser\Scope;
+use PHPStan\Rules\Rule;
+
+/**
+ * @phpstan-implements Rule<\PhpParser\Node\Expr\Variable>
+ */
+final class AnonymousFunctionWithThisRule implements Rule
+{
+    /**
+     * @inheritDoc
+     */
+    public function getNodeType(): string
+    {
+        return \PhpParser\Node\Expr\Variable::class;
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function processNode(Node $node, Scope $scope): array
+    {
+        if (!\is_string($node->name) || $node->name !== 'this') {
+            return [];
+        }
+
+        if ($scope->isInClosureBind()) {
+            return [];
+        }
+
+        if (!$scope->isInClass()) {
+            // reported in other standard rule on level 0
+            return [];
+        }
+
+        if ($scope->isInAnonymousFunction()) {
+            return ['Using $this inside anonymous function is prohibited because of PHP 5.3 support.'];
+        }
+
+        return [];
+    }
+}

+ 28 - 0
phpstan/Rules/tests/AnonymousFunctionWithThisRuleTest.php

@@ -0,0 +1,28 @@
+<?php declare(strict_types = 1);
+
+namespace Composer\PHPStanRulesTests;
+
+use Composer\PHPStanRules\AnonymousFunctionWithThisRule;
+use PHPStan\Testing\RuleTestCase;
+
+/**
+ * @phpstan-extends RuleTestCase<AnonymousFunctionWithThisRule>
+ */
+final class AnonymousFunctionWithThisRuleTest extends RuleTestCase
+{
+    /**
+     * @inheritDoc
+     */
+    protected function getRule(): \PHPStan\Rules\Rule
+    {
+        return new AnonymousFunctionWithThisRule();
+    }
+
+    public function testWithThis(): void
+    {
+        $this->analyse([__DIR__ . '/data/method-with-this.php'], [
+            ['Using $this inside anonymous function is prohibited because of PHP 5.3 support.', 13],
+            ['Using $this inside anonymous function is prohibited because of PHP 5.3 support.', 17],
+        ]);
+    }
+}

+ 34 - 0
phpstan/Rules/tests/data/method-with-this.php

@@ -0,0 +1,34 @@
+<?php
+
+class FirstClass
+{
+    /**
+     * @var int
+     */
+    private $firstProp = 9;
+
+    public function funMethod()
+    {
+        function() {
+            $this->firstProp;
+        };
+
+        call_user_func(function() {
+            $this->funMethod();
+        }, $this);
+
+        $bind = 'bind';
+        function() use($bind) {
+
+        };
+    }
+}
+
+function global_ok() {
+    $_SERVER['REMOTE_ADDR'];
+}
+
+function global_this() {
+    // not checked by our rule, it is checked with standard phpstan rule on level 0
+    $this['REMOTE_ADDR'];
+}

+ 9 - 0
phpstan/config.neon

@@ -23,6 +23,15 @@ parameters:
 
         # we don't have different constructors for parent/child
         - '~^Unsafe usage of new static\(\)\.$~'
+
+        # hhvm should have support for $this in closures
+        -
+            count: 1
+            message: '~^Using \$this inside anonymous function is prohibited because of PHP 5\.3 support\.$~'
+            path: '../tests/Composer/Test/Repository/PlatformRepositoryTest.php'
     paths:
         - ../src
         - ../tests
+
+rules:
+    - Composer\PHPStanRules\AnonymousFunctionWithThisRule