diff --git a/src/Composer/Repository/RepositoryInterface.php b/src/Composer/Repository/RepositoryInterface.php index 4223d12fb..f5f1204d0 100644 --- a/src/Composer/Repository/RepositoryInterface.php +++ b/src/Composer/Repository/RepositoryInterface.php @@ -86,8 +86,8 @@ interface RepositoryInterface extends \Countable * @param int $mode a set of SEARCH_* constants to search on, implementations should do a best effort only * @param string $type The type of package to search for. Defaults to all types of packages * - * @return array[] an array of array('name' => '...', 'description' => '...') - * @phpstan-return list + * @return array[] an array of array('name' => '...', 'description' => '...'|null) + * @phpstan-return list */ public function search($query, $mode = 0, $type = null); diff --git a/src/Composer/Repository/Vcs/HgBitbucketDriver.php b/src/Composer/Repository/Vcs/HgBitbucketDriver.php index 71505cf52..42adcb918 100644 --- a/src/Composer/Repository/Vcs/HgBitbucketDriver.php +++ b/src/Composer/Repository/Vcs/HgBitbucketDriver.php @@ -31,10 +31,12 @@ class HgBitbucketDriver extends BitbucketDriver if (null === $this->rootIdentifier) { if (!$this->getRepoData()) { + // @phpstan-ignore-next-line if (!$this->fallbackDriver) { throw new \LogicException('A fallback driver should be setup if getRepoData returns false'); } + // @phpstan-ignore-next-line return $this->fallbackDriver->getRootIdentifier(); } diff --git a/src/Composer/Repository/Vcs/VcsDriver.php b/src/Composer/Repository/Vcs/VcsDriver.php index 4e92658d7..8927a0dcc 100644 --- a/src/Composer/Repository/Vcs/VcsDriver.php +++ b/src/Composer/Repository/Vcs/VcsDriver.php @@ -45,7 +45,7 @@ abstract class VcsDriver implements VcsDriverInterface protected $httpDownloader; /** @var array */ protected $infoCache = array(); - /** @var Cache */ + /** @var ?Cache */ protected $cache; /** diff --git a/src/Composer/Repository/VcsRepository.php b/src/Composer/Repository/VcsRepository.php index 80d24f7a1..2456baaea 100644 --- a/src/Composer/Repository/VcsRepository.php +++ b/src/Composer/Repository/VcsRepository.php @@ -46,9 +46,9 @@ class VcsRepository extends ArrayRepository implements ConfigurableRepositoryInt protected $processExecutor; protected $branchErrorOccurred = false; private $drivers; - /** @var VcsDriverInterface */ + /** @var ?VcsDriverInterface */ private $driver; - /** @var VersionCacheInterface */ + /** @var ?VersionCacheInterface */ private $versionCache; private $emptyReferences = array(); private $versionTransportExceptions = array(); diff --git a/src/Composer/Script/Event.php b/src/Composer/Script/Event.php index 5ab431e75..af8bf55e7 100644 --- a/src/Composer/Script/Event.php +++ b/src/Composer/Script/Event.php @@ -95,7 +95,7 @@ class Event extends BaseEvent /** * Set the originating event. * - * @return \Composer\EventDispatcher\Event|null + * @return ?BaseEvent */ public function getOriginatingEvent() { @@ -105,7 +105,7 @@ class Event extends BaseEvent /** * Set the originating event. * - * @param \Composer\EventDispatcher\Event $event + * @param BaseEvent $event * @return $this */ public function setOriginatingEvent(BaseEvent $event) @@ -118,8 +118,8 @@ class Event extends BaseEvent /** * Returns the upper-most event in chain. * - * @param \Composer\EventDispatcher\Event $event - * @return \Composer\EventDispatcher\Event + * @param BaseEvent $event + * @return BaseEvent */ private function calculateOriginatingEvent(BaseEvent $event) { diff --git a/src/Composer/Util/AuthHelper.php b/src/Composer/Util/AuthHelper.php index fa00e5bd6..abbc76cf7 100644 --- a/src/Composer/Util/AuthHelper.php +++ b/src/Composer/Util/AuthHelper.php @@ -210,7 +210,7 @@ class AuthHelper if ($auth['password'] === 'oauth2') { $headers[] = 'Authorization: Bearer '.$auth['username']; $authenticationDisplayMessage = 'Using GitLab OAuth token authentication'; - } elseif ($auth['password'] === 'private-token' || $auth['password'] === 'gitlab-ci-token') { + } else { $headers[] = 'PRIVATE-TOKEN: '.$auth['username']; $authenticationDisplayMessage = 'Using GitLab private token authentication'; } diff --git a/src/Composer/Util/Bitbucket.php b/src/Composer/Util/Bitbucket.php index 38611ac55..5970aa631 100644 --- a/src/Composer/Util/Bitbucket.php +++ b/src/Composer/Util/Bitbucket.php @@ -103,7 +103,12 @@ class Bitbucket ), )); - $this->token = $response->decodeJson(); + $token = $response->decodeJson(); + if (!isset($token['expires_in']) || !isset($token['access_token'])) { + throw new \LogicException('Expected a token configured with expires_in and access_token present, got '.json_encode($token)); + } + + $this->token = $token; } catch (TransportException $e) { if ($e->getCode() === 400) { $this->io->writeError('Invalid OAuth consumer provided.'); @@ -202,10 +207,12 @@ class Bitbucket $this->storeInAuthConfig($originUrl, $consumerKey, $consumerSecret); - if (!isset($this->token['expires_in']) || !isset($this->token['access_token'])) { - throw new \LogicException('Expected a token configured with expires_in and access_token present, got '.json_encode($this->token)); + if (!isset($this->token['access_token'])) { + throw new \LogicException('Failed to initialize token above'); } + // side effect above caused this, https://github.com/phpstan/phpstan/issues/5129 + // @phpstan-ignore-next-line return $this->token['access_token']; } @@ -219,8 +226,8 @@ class Bitbucket { $this->config->getConfigSource()->removeConfigSetting('bitbucket-oauth.'.$originUrl); - if (!isset($this->token['expires_in']) || !isset($this->token['access_token'])) { - throw new \LogicException('Expected a token configured with expires_in and access_token present, got '.json_encode($this->token)); + if (null === $this->token || !isset($this->token['expires_in'])) { + throw new \LogicException('Expected a token configured with expires_in present, got '.json_encode($this->token)); } $time = null === $this->time ? time() : $this->time; diff --git a/src/Composer/Util/Filesystem.php b/src/Composer/Util/Filesystem.php index 6b1da6a52..f1c8d38eb 100644 --- a/src/Composer/Util/Filesystem.php +++ b/src/Composer/Util/Filesystem.php @@ -24,7 +24,7 @@ use Symfony\Component\Finder\Finder; */ class Filesystem { - /** @var ProcessExecutor */ + /** @var ?ProcessExecutor */ private $processExecutor; public function __construct(ProcessExecutor $executor = null) diff --git a/src/Composer/Util/Http/CurlDownloader.php b/src/Composer/Util/Http/CurlDownloader.php index 83c55f945..f511f17d3 100644 --- a/src/Composer/Util/Http/CurlDownloader.php +++ b/src/Composer/Util/Http/CurlDownloader.php @@ -466,7 +466,7 @@ class CurlDownloader // check for gitlab 404 when downloading archives if ( $response->getStatusCode() === 404 - && $this->config && in_array($job['origin'], $this->config->get('gitlab-domains'), true) + && in_array($job['origin'], $this->config->get('gitlab-domains'), true) && false !== strpos($job['url'], 'archive.zip') ) { $needsAuthRetry = 'GitLab requires authentication and it was not provided'; diff --git a/src/Composer/Util/Loop.php b/src/Composer/Util/Loop.php index eb6461a33..00130a472 100644 --- a/src/Composer/Util/Loop.php +++ b/src/Composer/Util/Loop.php @@ -76,9 +76,7 @@ class Loop if ($progress) { $totalJobs = 0; - if ($this->httpDownloader) { - $totalJobs += $this->httpDownloader->countActiveJobs(); - } + $totalJobs += $this->httpDownloader->countActiveJobs(); if ($this->processExecutor) { $totalJobs += $this->processExecutor->countActiveJobs(); } @@ -89,9 +87,7 @@ class Loop while (true) { $activeJobs = 0; - if ($this->httpDownloader) { - $activeJobs += $this->httpDownloader->countActiveJobs(); - } + $activeJobs += $this->httpDownloader->countActiveJobs(); if ($this->processExecutor) { $activeJobs += $this->processExecutor->countActiveJobs(); } diff --git a/src/Composer/Util/Perforce.php b/src/Composer/Util/Perforce.php index d399e4c78..1187b06c3 100644 --- a/src/Composer/Util/Perforce.php +++ b/src/Composer/Util/Perforce.php @@ -208,6 +208,8 @@ class Perforce return; } $this->p4User = $this->getP4variable('P4USER'); + // https://github.com/phpstan/phpstan/issues/5129 + // @phpstan-ignore-next-line if (strlen($this->p4User) > 0) { return; } @@ -220,6 +222,10 @@ class Perforce $this->executeCommand($command); } + /** + * @param string $name + * @return ?string + */ protected function getP4variable($name) { if ($this->windowsFlag) { diff --git a/src/Composer/Util/RemoteFilesystem.php b/src/Composer/Util/RemoteFilesystem.php index 9aed13ac2..8b16bb456 100644 --- a/src/Composer/Util/RemoteFilesystem.php +++ b/src/Composer/Util/RemoteFilesystem.php @@ -550,8 +550,8 @@ class RemoteFilesystem // passing `null` to file_get_contents will convert `null` to `0` and return 0 bytes $result = file_get_contents($fileUrl, false, $context); } - } catch (\Throwable $e) { } catch (\Exception $e) { + } catch (\Throwable $e) { } if ($maxFileSize !== null && Platform::strlen($result) >= $maxFileSize) { diff --git a/src/Composer/Util/TlsHelper.php b/src/Composer/Util/TlsHelper.php index cfe89870a..6fa70f0cc 100644 --- a/src/Composer/Util/TlsHelper.php +++ b/src/Composer/Util/TlsHelper.php @@ -162,7 +162,7 @@ final class TlsHelper * * @param string $certName CN/SAN * - * @return callable|void + * @return callable|null */ private static function certNameMatcher($certName) { @@ -180,14 +180,14 @@ final class TlsHelper if (3 > count($components)) { // Must have 3+ components - return; + return null; } $firstComponent = $components[0]; // Wildcard must be the last character. if ('*' !== $firstComponent[strlen($firstComponent) - 1]) { - return; + return null; } $wildcardRegex = preg_quote($certName); @@ -198,5 +198,7 @@ final class TlsHelper return 1 === preg_match($wildcardRegex, $hostname); }; } + + return null; } } diff --git a/src/Composer/Util/Zip.php b/src/Composer/Util/Zip.php index 2e4bc3774..7b1f6285c 100644 --- a/src/Composer/Util/Zip.php +++ b/src/Composer/Util/Zip.php @@ -42,11 +42,6 @@ class Zip } $foundFileIndex = self::locateFile($zip, 'composer.json'); - if (false === $foundFileIndex) { - $zip->close(); - - return null; - } $content = null; $configurationFileName = $zip->getNameIndex($foundFileIndex); diff --git a/tests/Composer/Test/InstallerTest.php b/tests/Composer/Test/InstallerTest.php index 3ab4d6e39..3732941f0 100644 --- a/tests/Composer/Test/InstallerTest.php +++ b/tests/Composer/Test/InstallerTest.php @@ -82,6 +82,7 @@ class InstallerTest extends TestCase $installationManager = new InstallationManagerMock(); // emulate a writable lock file + /** @var ?string $lockData */ $lockData = null; $lockJsonMock = $this->getMockBuilder('Composer\Json\JsonFile')->disableOriginalConstructor()->getMock(); $lockJsonMock->expects($this->any()) diff --git a/tests/Composer/Test/Platform/HhvmDetectorTest.php b/tests/Composer/Test/Platform/HhvmDetectorTest.php index 68dc4a879..51926156c 100644 --- a/tests/Composer/Test/Platform/HhvmDetectorTest.php +++ b/tests/Composer/Test/Platform/HhvmDetectorTest.php @@ -32,8 +32,6 @@ class HhvmDetectorTest extends TestCase { if (!defined('HHVM_VERSION_ID')) { self::markTestSkipped('Not running with HHVM'); - - return; } $version = $this->hhvmDetector->getVersion(); self::assertSame(self::versionIdToVersion(), $version); @@ -43,18 +41,12 @@ class HhvmDetectorTest extends TestCase { if (defined('HHVM_VERSION_ID')) { self::markTestSkipped('Running with HHVM'); - - return; } if (PHP_VERSION_ID < 50400) { self::markTestSkipped('Test only works on PHP 5.4+'); - - return; } if (Platform::isWindows()) { self::markTestSkipped('Test does not run on Windows'); - - return; } $finder = new ExecutableFinder(); $hhvm = $finder->find('hhvm'); diff --git a/tests/Composer/Test/Script/EventTest.php b/tests/Composer/Test/Script/EventTest.php index b7c8cd9ff..6a4c3b678 100644 --- a/tests/Composer/Test/Script/EventTest.php +++ b/tests/Composer/Test/Script/EventTest.php @@ -35,6 +35,7 @@ class EventTest extends TestCase $scriptEvent->setOriginatingEvent($originatingEvent); + // @phpstan-ignore-next-line $this->assertSame( $originatingEvent, $scriptEvent->getOriginatingEvent(), diff --git a/tests/Composer/Test/Util/ErrorHandlerTest.php b/tests/Composer/Test/Util/ErrorHandlerTest.php index 89e97f653..551daaa25 100644 --- a/tests/Composer/Test/Util/ErrorHandlerTest.php +++ b/tests/Composer/Test/Util/ErrorHandlerTest.php @@ -57,6 +57,7 @@ class ErrorHandlerTest extends TestCase $this->setExpectedException('ErrorException', 'array_merge'); } + // @phpstan-ignore-next-line array_merge(array(), 'string'); } diff --git a/tests/Composer/Test/Util/ZipTest.php b/tests/Composer/Test/Util/ZipTest.php index 16fc5827d..32fff6a5c 100644 --- a/tests/Composer/Test/Util/ZipTest.php +++ b/tests/Composer/Test/Util/ZipTest.php @@ -35,8 +35,6 @@ class ZipTest extends TestCase { if (!extension_loaded('zip')) { $this->markTestSkipped('The PHP zip extension is not loaded.'); - - return; } $result = Zip::getComposerJson(__DIR__.'/Fixtures/Zip/invalid.zip'); @@ -48,8 +46,6 @@ class ZipTest extends TestCase { if (!extension_loaded('zip')) { $this->markTestSkipped('The PHP zip extension is not loaded.'); - - return; } $result = Zip::getComposerJson(__DIR__.'/Fixtures/Zip/empty.zip'); @@ -61,8 +57,6 @@ class ZipTest extends TestCase { if (!extension_loaded('zip')) { $this->markTestSkipped('The PHP zip extension is not loaded.'); - - return; } $this->setExpectedException('\RuntimeException', 'No composer.json found either at the top level or within the topmost directory'); @@ -74,8 +68,6 @@ class ZipTest extends TestCase { if (!extension_loaded('zip')) { $this->markTestSkipped('The PHP zip extension is not loaded.'); - - return; } $this->setExpectedException('\RuntimeException', 'No composer.json found either at the top level or within the topmost directory'); @@ -87,8 +79,6 @@ class ZipTest extends TestCase { if (!extension_loaded('zip')) { $this->markTestSkipped('The PHP zip extension is not loaded.'); - - return; } $result = Zip::getComposerJson(__DIR__.'/Fixtures/Zip/root.zip'); @@ -100,8 +90,6 @@ class ZipTest extends TestCase { if (!extension_loaded('zip')) { $this->markTestSkipped('The PHP zip extension is not loaded.'); - - return; } $result = Zip::getComposerJson(__DIR__.'/Fixtures/Zip/folder.zip'); @@ -112,8 +100,6 @@ class ZipTest extends TestCase { if (!extension_loaded('zip')) { $this->markTestSkipped('The PHP zip extension is not loaded.'); - - return; } $this->setExpectedException('\RuntimeException', 'Archive has more than one top level directories, and no composer.json was found on the top level, so it\'s an invalid archive. Top level paths found were: folder1/,folder2/'); @@ -125,8 +111,6 @@ class ZipTest extends TestCase { if (!extension_loaded('zip')) { $this->markTestSkipped('The PHP zip extension is not loaded.'); - - return; } $result = Zip::getComposerJson(__DIR__.'/Fixtures/Zip/single-sub.zip');