Browse Source

Merge pull request #8471 from adaamz/phpstan-0.12

updated phpstan to 0.12
Jordi Boggiano 5 years ago
parent
commit
9476ced398

+ 1 - 0
.gitattributes

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

+ 5 - 3
.travis.yml

@@ -25,7 +25,9 @@ matrix:
     - php: 7.1
     - php: 7.2
     - php: 7.3
-      env: PHPSTAN=1
+      env:
+        - deps=high
+        - PHPSTAN=1
     - php: 7.3
       env:
         - deps=high
@@ -64,8 +66,8 @@ script:
   - ls -d tests/Composer/Test/* | grep -v TestCase.php | parallel --gnu --keep-order 'echo "Running {} tests"; ./vendor/bin/phpunit -c tests/complete.phpunit.xml --colors=always {} || (echo -e "\e[41mFAILED\e[0m {}" && exit 1);'
   # Run PHPStan
   - if [[ $PHPSTAN == "1" ]]; then
-      bin/composer require --dev phpstan/phpstan-shim:^0.11 --ignore-platform-reqs &&
-      vendor/bin/phpstan.phar analyse --configuration=phpstan/config.neon;
+      bin/composer require --dev phpstan/phpstan:^0.12 &&
+      vendor/bin/phpstan analyse --configuration=phpstan/config.neon;
     fi
 
 before_deploy:

+ 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'];
+}

+ 16 - 25
phpstan/config.neon

@@ -1,24 +1,12 @@
 parameters:
     autoload_files:
-        - phpstan/autoload.php
+        - autoload.php
     level: 0
     excludes_analyse:
-        - 'tests/Composer/Test/Fixtures'
-        - 'tests/Composer/Test/Autoload/Fixtures'
-        - 'tests/Composer/Test/Plugin/Fixtures'
+       - '../tests/Composer/Test/Fixtures/*'
+       - '../tests/Composer/Test/Autoload/Fixtures/*'
+       - '../tests/Composer/Test/Plugin/Fixtures/*'
     ignoreErrors:
-        # unused parameters
-        - '~^Constructor of class Composer\\Repository\\VcsRepository has an unused parameter \$dispatcher\.$~'
-        - '~^Constructor of class Composer\\Repository\\PearRepository has an unused parameter \$dispatcher\.$~'
-        - '~^Constructor of class Composer\\Util\\Http\\CurlDownloader has an unused parameter \$disableTls\.$~'
-        - '~^Constructor of class Composer\\Util\\Http\\CurlDownloader has an unused parameter \$options\.$~'
-        - '~^Constructor of class Composer\\Repository\\PearRepository has an unused parameter \$config\.$~'
-
-        # unused uses
-        - '~^Anonymous function has an unused use \$io\.$~'
-        - '~^Anonymous function has an unused use \$cache\.$~'
-        - '~^Anonymous function has an unused use \$path\.$~'
-
         # ion cube is not installed
         - '~^Function ioncube_loader_\w+ not found\.$~'
         # rar is not installed
@@ -33,14 +21,17 @@ parameters:
         # variable defined in eval
         - '~^Undefined variable: \$res$~'
 
-        # always checked whether the class exists
-        - '~^Instantiated class Symfony\\Component\\Console\\Terminal not found\.$~'
-        - '~^Class Symfony\\Component\\Console\\Input\\StreamableInputInterface not found\.$~'
-        - '~^Call to an undefined static method Symfony\\Component\\Process\\Process::fromShellCommandline\(\).$~'
+        # we don't have different constructors for parent/child
+        - '~^Unsafe usage of new static\(\)\.$~'
 
-        # parent call in test mocks
-        - '~^Composer\\Test\\Mock\\HttpDownloaderMock::__construct\(\) does not call parent constructor from Composer\\Util\\HttpDownloader\.$~'
-        - '~^Composer\\Test\\Mock\\InstallationManagerMock::__construct\(\) does not call parent constructor from Composer\\Installer\\InstallationManager\.$~'
+        # 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
+        - ../src
+        - ../tests
+
+rules:
+    - Composer\PHPStanRules\AnonymousFunctionWithThisRule

+ 3 - 3
src/Composer/Downloader/FileDownloader.php

@@ -113,7 +113,7 @@ class FileDownloader implements DownloaderInterface, ChangeReportInterface
 
         $accept = null;
         $reject = null;
-        $download = function () use ($io, $output, $httpDownloader, $cache, $eventDispatcher, $package, $fileName, $path, &$urls, &$accept, &$reject) {
+        $download = function () use ($io, $output, $httpDownloader, $cache, $eventDispatcher, $package, $fileName, &$urls, &$accept, &$reject) {
             $url = reset($urls);
 
             if ($eventDispatcher) {
@@ -160,7 +160,7 @@ class FileDownloader implements DownloaderInterface, ChangeReportInterface
             });
         };
 
-        $accept = function ($response) use ($io, $cache, $package, $fileName, $path, $self, &$urls) {
+        $accept = function ($response) use ($cache, $package, $fileName, $self, &$urls) {
             $url = reset($urls);
             $cacheKey = $url['cacheKey'];
 
@@ -174,7 +174,7 @@ class FileDownloader implements DownloaderInterface, ChangeReportInterface
             return $fileName;
         };
 
-        $reject = function ($e) use ($io, &$urls, $download, $fileName, $path, $package, &$retries, $filesystem, $self) {
+        $reject = function ($e) use ($io, &$urls, $download, $fileName, $package, &$retries, $filesystem, $self) {
             // clean up
             if (file_exists($fileName)) {
                 $filesystem->unlink($fileName);

+ 1 - 1
src/Composer/Installer/InstallationManager.php

@@ -246,7 +246,7 @@ class InstallationManager
                     $dispatcher->dispatchPackageEvent(constant($event), $devMode, $repo, $operations, $operation);
                 }
             }, function ($e) use ($jobType, $installer, $package, $initialPackage, $loop, $io) {
-                $this->io->writeError('    <error>' . ucfirst($jobType) .' of '.$package->getPrettyName().' failed</error>');
+                $io->writeError('    <error>' . ucfirst($jobType) .' of '.$package->getPrettyName().' failed</error>');
 
                 $promise = $installer->cleanup($jobType, $package, $initialPackage);
                 if ($promise) {

+ 1 - 1
src/Composer/Repository/ComposerRepository.php

@@ -1119,7 +1119,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
             return $data;
         };
 
-        $reject = function ($e) use (&$retries, $httpDownloader, $filename, $options, &$reject, $accept, $io, $url, $cache, &$degradedMode) {
+        $reject = function ($e) use (&$retries, $httpDownloader, $filename, $options, &$reject, $accept, $io, $url, &$degradedMode) {
             if ($e instanceof TransportException && $e->getStatusCode() === 404) {
                 return false;
             }

+ 1 - 1
src/Composer/Util/HttpDownloader.php

@@ -190,7 +190,7 @@ class HttpDownloader
             $downloader->scheduleNextJob();
 
             return $response;
-        }, function ($e) use ($io, &$job, $downloader) {
+        }, function ($e) use (&$job, $downloader) {
             $job['status'] = HttpDownloader::STATUS_FAILED;
             $job['exception'] = $e;