From 28d31c97f81ff82481e9b4f3e6c9f8a66ac45834 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 7 Jan 2025 22:05:01 +0000 Subject: [PATCH 01/19] Server: fixup PHPStan 2.x reported issues --- src/Server.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Server.php b/src/Server.php index 9003a7f9cf..5a72ad0489 100644 --- a/src/Server.php +++ b/src/Server.php @@ -138,6 +138,7 @@ use function filemtime; use function fopen; use function get_class; +use function gettype; use function ini_set; use function is_array; use function is_dir; @@ -918,6 +919,7 @@ public function __construct( TimingsHandler::getCollectCallbacks()->add(function() : array{ $promises = []; foreach($this->asyncPool->getRunningWorkers() as $workerId){ + /** @phpstan-var PromiseResolver> $resolver */ $resolver = new PromiseResolver(); $this->asyncPool->submitTaskToWorker(new TimingsCollectionTask($resolver), $workerId); @@ -1013,7 +1015,11 @@ public function __construct( copy(Path::join(\pocketmine\RESOURCE_PATH, 'plugin_list.yml'), $graylistFile); } try{ - $pluginGraylist = PluginGraylist::fromArray(yaml_parse(Filesystem::fileGetContents($graylistFile))); + $array = yaml_parse(Filesystem::fileGetContents($graylistFile)); + if(!is_array($array)){ + throw new \InvalidArgumentException("Expected array for root, but have " . gettype($array)); + } + $pluginGraylist = PluginGraylist::fromArray($array); }catch(\InvalidArgumentException $e){ $this->logger->emergency("Failed to load $graylistFile: " . $e->getMessage()); $this->forceShutdownExit(); @@ -1174,7 +1180,7 @@ private function startupPrepareWorlds() : bool{ if($this->worldManager->getDefaultWorld() === null){ $default = $this->configGroup->getConfigString(ServerProperties::DEFAULT_WORLD_NAME, "world"); - if(trim($default) == ""){ + if(trim($default) === ""){ $this->logger->warning("level-name cannot be null, using default"); $default = "world"; $this->configGroup->setConfigString(ServerProperties::DEFAULT_WORLD_NAME, "world"); From 7b1b35ab1f0bcfb2df1acf0670d286e9a19a130f Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 7 Jan 2025 22:07:38 +0000 Subject: [PATCH 02/19] generator: fixup issues reported by PHPStan 2.0 --- src/world/generator/FlatGeneratorOptions.php | 3 +-- src/world/generator/normal/Normal.php | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/world/generator/FlatGeneratorOptions.php b/src/world/generator/FlatGeneratorOptions.php index ab10c8a475..ba89cefb7e 100644 --- a/src/world/generator/FlatGeneratorOptions.php +++ b/src/world/generator/FlatGeneratorOptions.php @@ -75,8 +75,7 @@ public static function parseLayers(string $layers) : array{ $y = 0; $itemParser = LegacyStringToItemParser::getInstance(); foreach($split as $line){ - preg_match('#^(?:(\d+)[x|*])?(.+)$#', $line, $matches); - if(count($matches) !== 3){ + if(preg_match('#^(?:(\d+)[x|*])?(.+)$#', $line, $matches) !== 1){ throw new InvalidGeneratorOptionsException("Invalid preset layer \"$line\""); } diff --git a/src/world/generator/normal/Normal.php b/src/world/generator/normal/Normal.php index 1d4805e165..a440f1e5f8 100644 --- a/src/world/generator/normal/Normal.php +++ b/src/world/generator/normal/Normal.php @@ -126,10 +126,10 @@ private function pickBiome(int $x, int $z) : Biome{ $hash = (int) $hash; $xNoise = $hash >> 20 & 3; $zNoise = $hash >> 22 & 3; - if($xNoise == 3){ + if($xNoise === 3){ $xNoise = 1; } - if($zNoise == 3){ + if($zNoise === 3){ $zNoise = 1; } From cd59e272bcabcbcf97fdd380625bcf39969043f0 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 7 Jan 2025 22:10:42 +0000 Subject: [PATCH 03/19] PHPStan 2.0 fixes --- src/crafting/CraftingManager.php | 2 -- .../block/upgrade/BlockStateUpgradeSchemaUtils.php | 7 +++---- src/data/runtime/RuntimeEnumMetadata.php | 3 +-- src/event/HandlerListManager.php | 2 +- src/inventory/transaction/InventoryTransaction.php | 2 +- src/item/WritableBookBase.php | 5 +++-- src/item/enchantment/ItemEnchantmentTagRegistry.php | 6 ++++-- src/player/Player.php | 8 +++----- src/resourcepacks/ResourcePackManager.php | 11 +++++++++-- src/scheduler/BulkCurlTask.php | 5 ++++- src/timings/TimingsHandler.php | 2 ++ src/timings/TimingsRecord.php | 2 +- src/world/World.php | 11 +++++------ src/world/format/io/region/RegionWorldProvider.php | 10 ++++++---- 14 files changed, 43 insertions(+), 33 deletions(-) diff --git a/src/crafting/CraftingManager.php b/src/crafting/CraftingManager.php index ff2be69268..895eeacccd 100644 --- a/src/crafting/CraftingManager.php +++ b/src/crafting/CraftingManager.php @@ -110,7 +110,6 @@ public static function sort(Item $i1, Item $i2) : int{ /** * @param Item[] $items - * @phpstan-param list $items * * @return Item[] * @phpstan-return list @@ -135,7 +134,6 @@ private static function pack(array $items) : array{ /** * @param Item[] $outputs - * @phpstan-param list $outputs */ private static function hashOutputs(array $outputs) : string{ $outputs = self::pack($outputs); diff --git a/src/data/bedrock/block/upgrade/BlockStateUpgradeSchemaUtils.php b/src/data/bedrock/block/upgrade/BlockStateUpgradeSchemaUtils.php index 08eba89785..b4ed0dd261 100644 --- a/src/data/bedrock/block/upgrade/BlockStateUpgradeSchemaUtils.php +++ b/src/data/bedrock/block/upgrade/BlockStateUpgradeSchemaUtils.php @@ -37,7 +37,6 @@ use Symfony\Component\Filesystem\Path; use function array_key_last; use function array_map; -use function array_values; use function assert; use function count; use function get_debug_type; @@ -138,8 +137,8 @@ public static function fromJsonModel(BlockStateUpgradeSchemaModel $model, int $s $convertedRemappedValuesIndex = []; foreach(Utils::stringifyKeys($model->remappedPropertyValuesIndex ?? []) as $mappingKey => $mappingValues){ - foreach($mappingValues as $k => $oldNew){ - $convertedRemappedValuesIndex[$mappingKey][$k] = new BlockStateUpgradeSchemaValueRemap( + foreach($mappingValues as $oldNew){ + $convertedRemappedValuesIndex[$mappingKey][] = new BlockStateUpgradeSchemaValueRemap( self::jsonModelToTag($oldNew->old), self::jsonModelToTag($oldNew->new) ); @@ -361,7 +360,7 @@ public static function toJsonModel(BlockStateUpgradeSchema $schema) : BlockState //remaps with the same number of criteria should be sorted alphabetically, but this is not strictly necessary return json_encode($a->oldState ?? []) <=> json_encode($b->oldState ?? []); }); - $result->remappedStates[$oldBlockName] = array_values($keyedRemaps); + $result->remappedStates[$oldBlockName] = $keyedRemaps; //usort strips keys, so this is already a list } if(isset($result->remappedStates)){ ksort($result->remappedStates); diff --git a/src/data/runtime/RuntimeEnumMetadata.php b/src/data/runtime/RuntimeEnumMetadata.php index 261b7a1bc3..45f831b194 100644 --- a/src/data/runtime/RuntimeEnumMetadata.php +++ b/src/data/runtime/RuntimeEnumMetadata.php @@ -23,7 +23,6 @@ namespace pocketmine\data\runtime; -use function array_values; use function ceil; use function count; use function log; @@ -60,7 +59,7 @@ public function __construct( usort($members, fn(\UnitEnum $a, \UnitEnum $b) => $a->name <=> $b->name); //sort by name to ensure consistent ordering (and thus consistent bit assignments) $this->bits = (int) ceil(log(count($members), 2)); - $this->intToEnum = array_values($members); + $this->intToEnum = $members; //usort strips keys so this is already a list $reversed = []; foreach($this->intToEnum as $int => $enum){ diff --git a/src/event/HandlerListManager.php b/src/event/HandlerListManager.php index 605a387478..9437df37f9 100644 --- a/src/event/HandlerListManager.php +++ b/src/event/HandlerListManager.php @@ -119,7 +119,7 @@ public function getListFor(string $event) : HandlerList{ public function getHandlersFor(string $event) : array{ $cache = $this->handlerCaches[$event] ?? null; //getListFor() will populate the cache for the next call - return $cache?->list ?? $this->getListFor($event)->getListenerList(); + return $cache->list ?? $this->getListFor($event)->getListenerList(); } /** diff --git a/src/inventory/transaction/InventoryTransaction.php b/src/inventory/transaction/InventoryTransaction.php index 47290e4015..8f7b576109 100644 --- a/src/inventory/transaction/InventoryTransaction.php +++ b/src/inventory/transaction/InventoryTransaction.php @@ -232,7 +232,7 @@ protected function squashDuplicateSlotChanges() : void{ /** * @param SlotChangeAction[] $possibleActions - * @phpstan-param list $possibleActions + * @phpstan-param array $possibleActions */ protected function findResultItem(Item $needOrigin, array $possibleActions) : ?Item{ assert(count($possibleActions) > 0); diff --git a/src/item/WritableBookBase.php b/src/item/WritableBookBase.php index 6b7e55468c..d3b9b70610 100644 --- a/src/item/WritableBookBase.php +++ b/src/item/WritableBookBase.php @@ -101,8 +101,9 @@ public function addPage(int $pageId) : self{ * @return $this */ public function deletePage(int $pageId) : self{ - unset($this->pages[$pageId]); - $this->pages = array_values($this->pages); + $newPages = $this->pages; + unset($newPages[$pageId]); + $this->pages = array_values($newPages); return $this; } diff --git a/src/item/enchantment/ItemEnchantmentTagRegistry.php b/src/item/enchantment/ItemEnchantmentTagRegistry.php index 210cd8e864..b239f18a28 100644 --- a/src/item/enchantment/ItemEnchantmentTagRegistry.php +++ b/src/item/enchantment/ItemEnchantmentTagRegistry.php @@ -32,6 +32,7 @@ use function array_search; use function array_shift; use function array_unique; +use function array_values; use function count; /** @@ -103,7 +104,8 @@ public function unregister(string $tag) : void{ foreach(Utils::stringifyKeys($this->tagMap) as $key => $nestedTags){ if(($nestedKey = array_search($tag, $nestedTags, true)) !== false){ - unset($this->tagMap[$key][$nestedKey]); + unset($nestedTags[$nestedKey]); + $this->tagMap[$key] = array_values($nestedTags); } } } @@ -115,7 +117,7 @@ public function unregister(string $tag) : void{ */ public function removeNested(string $tag, array $nestedTags) : void{ $this->assertNotInternalTag($tag); - $this->tagMap[$tag] = array_diff($this->tagMap[$tag], $nestedTags); + $this->tagMap[$tag] = array_values(array_diff($this->tagMap[$tag], $nestedTags)); } /** diff --git a/src/player/Player.php b/src/player/Player.php index bf911a2ff2..66ba6f376f 100644 --- a/src/player/Player.php +++ b/src/player/Player.php @@ -147,7 +147,6 @@ use function explode; use function floor; use function get_class; -use function is_int; use function max; use function mb_strlen; use function microtime; @@ -826,7 +825,6 @@ protected function requestChunks() : void{ $X = null; $Z = null; World::getXZ($index, $X, $Z); - assert(is_int($X) && is_int($Z)); ++$count; @@ -1346,7 +1344,7 @@ private function actuallyHandleMovement(Vector3 $newPos) : void{ $this->nextChunkOrderRun = 0; } - if(!$revert && $distanceSquared != 0){ + if(!$revert && $distanceSquared !== 0.0){ $dx = $newPos->x - $oldPos->x; $dy = $newPos->y - $oldPos->y; $dz = $newPos->z - $oldPos->z; @@ -2319,7 +2317,7 @@ public function onPostDisconnect(Translatable|string $reason, Translatable|strin $ev = new PlayerQuitEvent($this, $quitMessage ?? $this->getLeaveMessage(), $reason); $ev->call(); - if(($quitMessage = $ev->getQuitMessage()) != ""){ + if(($quitMessage = $ev->getQuitMessage()) !== ""){ $this->server->broadcastMessage($quitMessage); } $this->save(); @@ -2460,7 +2458,7 @@ protected function onDeath() : void{ $this->xpManager->setXpAndProgress(0, 0.0); } - if($ev->getDeathMessage() != ""){ + if($ev->getDeathMessage() !== ""){ $this->server->broadcastMessage($ev->getDeathMessage()); } diff --git a/src/resourcepacks/ResourcePackManager.php b/src/resourcepacks/ResourcePackManager.php index baf16ca207..c4668eb2a7 100644 --- a/src/resourcepacks/ResourcePackManager.php +++ b/src/resourcepacks/ResourcePackManager.php @@ -47,10 +47,16 @@ class ResourcePackManager{ private string $path; private bool $serverForceResources = false; - /** @var ResourcePack[] */ + /** + * @var ResourcePack[] + * @phpstan-var list + */ private array $resourcePacks = []; - /** @var ResourcePack[] */ + /** + * @var ResourcePack[] + * @phpstan-var array + */ private array $uuidList = []; /** @@ -165,6 +171,7 @@ public function setResourcePacksRequired(bool $value) : void{ /** * Returns an array of resource packs in use, sorted in order of priority. * @return ResourcePack[] + * @phpstan-return list */ public function getResourceStack() : array{ return $this->resourcePacks; diff --git a/src/scheduler/BulkCurlTask.php b/src/scheduler/BulkCurlTask.php index ccc1b24664..21f144702e 100644 --- a/src/scheduler/BulkCurlTask.php +++ b/src/scheduler/BulkCurlTask.php @@ -77,7 +77,10 @@ public function onCompletion() : void{ * @phpstan-var \Closure(list) : void */ $callback = $this->fetchLocal(self::TLS_KEY_COMPLETION_CALLBACK); - /** @var InternetRequestResult[]|InternetException[] $results */ + /** + * @var InternetRequestResult[]|InternetException[] $results + * @phpstan-var list $results + */ $results = $this->getResult(); $callback($results); } diff --git a/src/timings/TimingsHandler.php b/src/timings/TimingsHandler.php index 95f7dbacc6..25f139d91d 100644 --- a/src/timings/TimingsHandler.php +++ b/src/timings/TimingsHandler.php @@ -123,6 +123,7 @@ public static function printCurrentThreadRecords() : array{ /** * @return string[] + * @phpstan-return list */ private static function printFooter() : array{ $result = []; @@ -173,6 +174,7 @@ public static function requestPrintTimings() : Promise{ } } + /** @phpstan-var PromiseResolver> $resolver */ $resolver = new PromiseResolver(); Promise::all($otherThreadRecordPromises)->onCompletion( function(array $promisedRecords) use ($resolver, $thisThreadRecords) : void{ diff --git a/src/timings/TimingsRecord.php b/src/timings/TimingsRecord.php index 2e4928d8a6..390ab74e51 100644 --- a/src/timings/TimingsRecord.php +++ b/src/timings/TimingsRecord.php @@ -131,7 +131,7 @@ public function startTiming(int $now) : void{ } public function stopTiming(int $now) : void{ - if($this->start == 0){ + if($this->start === 0){ return; } if(self::$currentRecord !== $this){ diff --git a/src/world/World.php b/src/world/World.php index b6df7f2a47..7395afa78f 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -113,6 +113,7 @@ use function array_map; use function array_merge; use function array_sum; +use function array_values; use function assert; use function cos; use function count; @@ -678,7 +679,6 @@ public function removeOnUnloadCallback(\Closure $callback) : void{ * Used for broadcasting sounds and particles with specific targets. * * @param Player[] $allowed - * @phpstan-param list $allowed * * @return array */ @@ -1089,7 +1089,6 @@ public function setSleepTicks(int $ticks) : void{ /** * @param Vector3[] $blocks - * @phpstan-param list $blocks * * @return ClientboundPacket[] * @phpstan-return list @@ -1456,8 +1455,8 @@ public function saveChunks() : void{ $this->provider->saveChunk($chunkX, $chunkZ, new ChunkData( $chunk->getSubChunks(), $chunk->isPopulated(), - array_map(fn(Entity $e) => $e->saveNBT(), array_filter($this->getChunkEntities($chunkX, $chunkZ), fn(Entity $e) => $e->canSaveWithChunk())), - array_map(fn(Tile $t) => $t->saveNBT(), $chunk->getTiles()), + array_map(fn(Entity $e) => $e->saveNBT(), array_values(array_filter($this->getChunkEntities($chunkX, $chunkZ), fn(Entity $e) => $e->canSaveWithChunk()))), + array_map(fn(Tile $t) => $t->saveNBT(), array_values($chunk->getTiles())), ), $chunk->getTerrainDirtyFlags()); $chunk->clearTerrainDirtyFlags(); } @@ -3019,8 +3018,8 @@ public function unloadChunk(int $x, int $z, bool $safe = true, bool $trySave = t $this->provider->saveChunk($x, $z, new ChunkData( $chunk->getSubChunks(), $chunk->isPopulated(), - array_map(fn(Entity $e) => $e->saveNBT(), array_filter($this->getChunkEntities($x, $z), fn(Entity $e) => $e->canSaveWithChunk())), - array_map(fn(Tile $t) => $t->saveNBT(), $chunk->getTiles()), + array_map(fn(Entity $e) => $e->saveNBT(), array_values(array_filter($this->getChunkEntities($x, $z), fn(Entity $e) => $e->canSaveWithChunk()))), + array_map(fn(Tile $t) => $t->saveNBT(), array_values($chunk->getTiles())), ), $chunk->getTerrainDirtyFlags()); }finally{ $this->timings->syncChunkSave->stopTiming(); diff --git a/src/world/format/io/region/RegionWorldProvider.php b/src/world/format/io/region/RegionWorldProvider.php index 0ab70300e7..7a4463f5d1 100644 --- a/src/world/format/io/region/RegionWorldProvider.php +++ b/src/world/format/io/region/RegionWorldProvider.php @@ -33,10 +33,8 @@ use pocketmine\world\format\io\LoadedChunkData; use pocketmine\world\format\io\WorldData; use Symfony\Component\Filesystem\Path; -use function assert; use function file_exists; use function is_dir; -use function is_int; use function morton2d_encode; use function rename; use function scandir; @@ -60,7 +58,12 @@ abstract protected static function getPcWorldFormatVersion() : int; public static function isValid(string $path) : bool{ if(file_exists(Path::join($path, "level.dat")) && is_dir($regionPath = Path::join($path, "region"))){ - foreach(scandir($regionPath, SCANDIR_SORT_NONE) as $file){ + $files = scandir($regionPath, SCANDIR_SORT_NONE); + if($files === false){ + //we can't tell the type if we don't have read perms + return false; + } + foreach($files as $file){ $extPos = strrpos($file, "."); if($extPos !== false && substr($file, $extPos + 1) === static::getRegionFileExtension()){ //we don't care if other region types exist, we only care if this format is possible @@ -199,7 +202,6 @@ protected static function readFixedSizeByteArray(CompoundTag $chunk, string $tag public function loadChunk(int $chunkX, int $chunkZ) : ?LoadedChunkData{ $regionX = $regionZ = null; self::getRegionIndex($chunkX, $chunkZ, $regionX, $regionZ); - assert(is_int($regionX) && is_int($regionZ)); if(!file_exists($this->pathToRegion($regionX, $regionZ))){ return null; From b1c7fc017a9f68b0eefde15380ec6c67ddfa59aa Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 7 Jan 2025 22:13:20 +0000 Subject: [PATCH 04/19] CS --- src/world/generator/FlatGeneratorOptions.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/world/generator/FlatGeneratorOptions.php b/src/world/generator/FlatGeneratorOptions.php index ba89cefb7e..b52d64658e 100644 --- a/src/world/generator/FlatGeneratorOptions.php +++ b/src/world/generator/FlatGeneratorOptions.php @@ -27,7 +27,6 @@ use pocketmine\item\LegacyStringToItemParser; use pocketmine\item\LegacyStringToItemParserException; use function array_map; -use function count; use function explode; use function preg_match; use function preg_match_all; From 47cb04f6a65eeed7e91e85d428f83b108bce218a Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 7 Jan 2025 22:15:50 +0000 Subject: [PATCH 05/19] tools: fix PHPStan 2.0 issues --- tools/blockstate-upgrade-schema-utils.php | 9 ++++++--- tools/compact-regions.php | 10 ++++++++-- tools/generate-bedrock-data-from-packets.php | 6 +++--- tools/generate-item-upgrade-schema.php | 15 +++++++++++---- tools/simulate-chunk-selector.php | 16 ++++++++++++++++ 5 files changed, 44 insertions(+), 12 deletions(-) diff --git a/tools/blockstate-upgrade-schema-utils.php b/tools/blockstate-upgrade-schema-utils.php index b7a9a4169d..4f5c8740cb 100644 --- a/tools/blockstate-upgrade-schema-utils.php +++ b/tools/blockstate-upgrade-schema-utils.php @@ -523,10 +523,12 @@ function processRemappedStates(array $upgradeTable) : array{ } } } + $orderedUnchanged = []; foreach(Utils::stringifyKeys($unchangedStatesByNewName) as $newName => $unchangedStates){ - ksort($unchangedStates); - $unchangedStatesByNewName[$newName] = $unchangedStates; + sort($unchangedStates); + $orderedUnchanged[$newName] = $unchangedStates; } + $unchangedStatesByNewName = $orderedUnchanged; $notFlattenedProperties = []; @@ -656,7 +658,8 @@ function processRemappedStates(array $upgradeTable) : array{ usort($list, function(BlockStateUpgradeSchemaBlockRemap $a, BlockStateUpgradeSchemaBlockRemap $b) : int{ return count($b->oldState) <=> count($a->oldState); }); - return array_values($list); + //usort discards keys, so this is already a list + return $list; } /** diff --git a/tools/compact-regions.php b/tools/compact-regions.php index 04ac3f0c94..ab80792d36 100644 --- a/tools/compact-regions.php +++ b/tools/compact-regions.php @@ -76,7 +76,12 @@ function find_regions_recursive(string $dir, array &$files) : void{ in_array(pathinfo($fullPath, PATHINFO_EXTENSION), SUPPORTED_EXTENSIONS, true) && is_file($fullPath) ){ - $files[$fullPath] = filesize($fullPath); + $size = filesize($fullPath); + if($size === false){ + //If we can't get the size of the file, we probably don't have perms to read it, so ignore it + continue; + } + $files[$fullPath] = $size; }elseif(is_dir($fullPath)){ find_regions_recursive($fullPath, $files); } @@ -165,7 +170,8 @@ function main(array $argv) : int{ clearstatcache(); $newSize = 0; foreach(Utils::stringifyKeys($files) as $file => $oldSize){ - $newSize += file_exists($file) ? filesize($file) : 0; + $size = file_exists($file) ? filesize($file) : 0; + $newSize += $size !== false ? $size : 0; } $diff = $currentSize - $newSize; $logger->info("Finished compaction of " . count($files) . " files. Freed " . number_format($diff) . " bytes of space (" . round(($diff / $currentSize) * 100, 2) . "% reduction)."); diff --git a/tools/generate-bedrock-data-from-packets.php b/tools/generate-bedrock-data-from-packets.php index 2c20e6099d..9aac5185ed 100644 --- a/tools/generate-bedrock-data-from-packets.php +++ b/tools/generate-bedrock-data-from-packets.php @@ -454,7 +454,7 @@ public function handleCraftingData(CraftingDataPacket $packet) : bool{ //this sorts the data into a canonical order to make diffs between versions reliable //how the data is ordered doesn't matter as long as it's reproducible - foreach($recipes as $_type => $entries){ + foreach(Utils::promoteKeys($recipes) as $_type => $entries){ $_sortedRecipes = []; $_seen = []; foreach($entries as $entry){ @@ -475,10 +475,10 @@ public function handleCraftingData(CraftingDataPacket $packet) : bool{ } ksort($recipes, SORT_STRING); - foreach($recipes as $type => $entries){ + foreach(Utils::promoteKeys($recipes) as $type => $entries){ echo "$type: " . count($entries) . "\n"; } - foreach($recipes as $type => $entries){ + foreach(Utils::promoteKeys($recipes) as $type => $entries){ file_put_contents(Path::join($recipesPath, $type . '.json'), json_encode($entries, JSON_PRETTY_PRINT) . "\n"); } diff --git a/tools/generate-item-upgrade-schema.php b/tools/generate-item-upgrade-schema.php index 4eee925392..7ad473b23b 100644 --- a/tools/generate-item-upgrade-schema.php +++ b/tools/generate-item-upgrade-schema.php @@ -31,10 +31,12 @@ use pocketmine\errorhandler\ErrorToExceptionHandler; use pocketmine\utils\Filesystem; +use pocketmine\utils\Utils; use Symfony\Component\Filesystem\Path; use function count; use function dirname; use function file_put_contents; +use function fwrite; use function is_array; use function json_decode; use function json_encode; @@ -45,6 +47,7 @@ use const JSON_THROW_ON_ERROR; use const SCANDIR_SORT_ASCENDING; use const SORT_STRING; +use const STDERR; require dirname(__DIR__) . '/vendor/autoload.php'; @@ -56,7 +59,7 @@ [, $mappingTableFile, $upgradeSchemasDir, $outputFile] = $argv; $target = json_decode(Filesystem::fileGetContents($mappingTableFile), true, JSON_THROW_ON_ERROR); -if(!is_array($target)){ +if(!is_array($target) || !isset($target["simple"]) || !is_array($target["simple"]) || !isset($target["complex"]) || !is_array($target["complex"])){ \GlobalLogger::get()->error("Invalid mapping table file"); exit(1); } @@ -93,7 +96,7 @@ $newDiff = []; -foreach($target["simple"] as $oldId => $newId){ +foreach(Utils::promoteKeys($target["simple"]) as $oldId => $newId){ $previousNewId = $merged["simple"][$oldId] ?? null; if( $previousNewId === $newId || //if previous schemas already accounted for this @@ -107,8 +110,12 @@ ksort($newDiff["renamedIds"], SORT_STRING); } -foreach($target["complex"] as $oldId => $mappings){ - foreach($mappings as $meta => $newId){ +foreach(Utils::promoteKeys($target["complex"]) as $oldId => $mappings){ + if(!is_array($mappings)){ + fwrite(STDERR, "Complex mapping for $oldId is not an array\n"); + exit(1); + } + foreach(Utils::promoteKeys($mappings) as $meta => $newId){ if(($merged["complex"][$oldId][$meta] ?? null) !== $newId){ if($oldId === "minecraft:spawn_egg" && $meta === 130 && ($newId === "minecraft:axolotl_bucket" || $newId === "minecraft:axolotl_spawn_egg")){ //TODO: hack for vanilla bug workaround diff --git a/tools/simulate-chunk-selector.php b/tools/simulate-chunk-selector.php index 0b279268ab..3d5e167cf8 100644 --- a/tools/simulate-chunk-selector.php +++ b/tools/simulate-chunk-selector.php @@ -53,6 +53,10 @@ require dirname(__DIR__) . '/vendor/autoload.php'; +/** + * @phpstan-param positive-int $scale + * @phpstan-param positive-int $radius + */ function newImage(int $scale, int $radius) : \GdImage{ $image = Utils::assumeNotFalse(imagecreatetruecolor($scale * $radius * 2, $scale * $radius * 2)); imagesavealpha($image, true); @@ -149,6 +153,18 @@ function render(int $radius, int $baseX, int $baseZ, int $chunksPerStep, int $sc fwrite(STDERR, "Please specify a radius using --radius\n"); exit(1); } +if($radius < 1){ + fwrite(STDERR, "Radius cannot be less than 1\n"); + exit(1); +} +if($scale < 1){ + fwrite(STDERR, "Scale cannot be less than 1\n"); + exit(1); +} +if($nChunksPerStep < 1){ + fwrite(STDERR, "Chunks per step cannot be less than 1\n"); + exit(1); +} $outputDirectory = null; if(isset($opts["output"])){ From 38441a6ba3818b7e3b96995c048a28fb1c77dd89 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 7 Jan 2025 22:23:16 +0000 Subject: [PATCH 06/19] build: avoid weak comparison --- build/server-phar.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/server-phar.php b/build/server-phar.php index f6bb29d514..7560fa5dae 100644 --- a/build/server-phar.php +++ b/build/server-phar.php @@ -129,7 +129,7 @@ function buildPhar(string $pharPath, string $basePath, array $includedPaths, arr } function main() : void{ - if(ini_get("phar.readonly") == 1){ + if(ini_get("phar.readonly") === "1"){ echo "Set phar.readonly to 0 with -dphar.readonly=0" . PHP_EOL; exit(1); } From d69a887b0d40320d18fa9d0950fbeb1a54d38ec2 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 7 Jan 2025 22:24:26 +0000 Subject: [PATCH 07/19] Utils: fix parameter doc for printableExceptionInfo() --- src/utils/Utils.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/utils/Utils.php b/src/utils/Utils.php index cc33e60e04..37cf543903 100644 --- a/src/utils/Utils.php +++ b/src/utils/Utils.php @@ -406,6 +406,7 @@ private static function printableExceptionMessage(\Throwable $e) : string{ /** * @param mixed[][] $trace + * @phpstan-param list>|null $trace * @return string[] */ public static function printableExceptionInfo(\Throwable $e, $trace = null) : array{ From d25ec58a6fd7151ad4a5dbf4035c9630caa1061b Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 7 Jan 2025 22:25:37 +0000 Subject: [PATCH 08/19] AsyncPoolTest: phpdoc --- tests/phpunit/scheduler/AsyncPoolTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/phpunit/scheduler/AsyncPoolTest.php b/tests/phpunit/scheduler/AsyncPoolTest.php index 53ec15c12b..88985cc399 100644 --- a/tests/phpunit/scheduler/AsyncPoolTest.php +++ b/tests/phpunit/scheduler/AsyncPoolTest.php @@ -71,6 +71,7 @@ public function testPublishProgressRace() : void{ } public function testThreadSafeSetResult() : void{ + /** @phpstan-var PromiseResolver> $resolver */ $resolver = new PromiseResolver(); $resolver->getPromise()->onCompletion( function(ThreadSafeArray $result) : void{ From 9633b7d8a79b90fcd7510ddb7bc765ad649361f3 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 7 Jan 2025 22:34:43 +0000 Subject: [PATCH 09/19] Update to PHPStan 2.x --- composer.json | 6 +- composer.lock | 58 +- phpstan.neon.dist | 2 + src/command/utils/CommandStringHelper.php | 3 +- src/utils/Utils.php | 9 +- .../format/io/region/RegionWorldProvider.php | 3 + src/world/generator/FlatGeneratorOptions.php | 2 +- tests/phpstan/DummyPluginOwned.php | 28 + tests/phpstan/configs/actual-problems.neon | 773 ++++++++++++------ .../phpstan/configs/dependency-problems.neon | 73 ++ .../phpstan/configs/impossible-generics.neon | 6 +- tests/phpstan/configs/phpstan-bugs.neon | 192 ++++- .../configs/spl-fixed-array-sucks.neon | 18 +- .../rules/DeprecatedLegacyEnumAccessRule.php | 27 +- .../rules/DisallowEnumComparisonRule.php | 15 +- .../rules/DisallowForeachByReferenceRule.php | 1 + .../rules/UnsafeForeachArrayOfStringRule.php | 2 +- tests/phpunit/utils/fixtures/TestTrait.php | 2 +- 18 files changed, 876 insertions(+), 344 deletions(-) create mode 100644 tests/phpstan/DummyPluginOwned.php create mode 100644 tests/phpstan/configs/dependency-problems.neon diff --git a/composer.json b/composer.json index e2ae641cac..a40f3733ef 100644 --- a/composer.json +++ b/composer.json @@ -52,9 +52,9 @@ "symfony/filesystem": "~6.4.0" }, "require-dev": { - "phpstan/phpstan": "1.11.11", - "phpstan/phpstan-phpunit": "^1.1.0", - "phpstan/phpstan-strict-rules": "^1.2.0", + "phpstan/phpstan": "2.1.1", + "phpstan/phpstan-phpunit": "^2.0.0", + "phpstan/phpstan-strict-rules": "^2.0.0", "phpunit/phpunit": "^10.5.24" }, "autoload": { diff --git a/composer.lock b/composer.lock index 54f65014f5..8df6c329dd 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "732102eca72dc1d29e7b67dfbce07653", + "content-hash": "994ccffe45f066768542019f6f9d237b", "packages": [ { "name": "adhocore/json-comment", @@ -1386,20 +1386,20 @@ }, { "name": "phpstan/phpstan", - "version": "1.11.11", + "version": "2.1.1", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "707c2aed5d8d0075666e673a5e71440c1d01a5a3" + "reference": "cd6e973e04b4c2b94c86e8612b5a65f0da0e08e7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/707c2aed5d8d0075666e673a5e71440c1d01a5a3", - "reference": "707c2aed5d8d0075666e673a5e71440c1d01a5a3", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/cd6e973e04b4c2b94c86e8612b5a65f0da0e08e7", + "reference": "cd6e973e04b4c2b94c86e8612b5a65f0da0e08e7", "shasum": "" }, "require": { - "php": "^7.2|^8.0" + "php": "^7.4|^8.0" }, "conflict": { "phpstan/phpstan-shim": "*" @@ -1440,34 +1440,33 @@ "type": "github" } ], - "time": "2024-08-19T14:37:29+00:00" + "time": "2025-01-05T16:43:48+00:00" }, { "name": "phpstan/phpstan-phpunit", - "version": "1.4.0", + "version": "2.0.3", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-phpunit.git", - "reference": "f3ea021866f4263f07ca3636bf22c64be9610c11" + "reference": "e32ac656788a5bf3dedda89e6a2cad5643bf1a18" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/f3ea021866f4263f07ca3636bf22c64be9610c11", - "reference": "f3ea021866f4263f07ca3636bf22c64be9610c11", + "url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/e32ac656788a5bf3dedda89e6a2cad5643bf1a18", + "reference": "e32ac656788a5bf3dedda89e6a2cad5643bf1a18", "shasum": "" }, "require": { - "php": "^7.2 || ^8.0", - "phpstan/phpstan": "^1.11" + "php": "^7.4 || ^8.0", + "phpstan/phpstan": "^2.0.4" }, "conflict": { "phpunit/phpunit": "<7.0" }, "require-dev": { - "nikic/php-parser": "^4.13.0", "php-parallel-lint/php-parallel-lint": "^1.2", - "phpstan/phpstan-strict-rules": "^1.5.1", - "phpunit/phpunit": "^9.5" + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^9.6" }, "type": "phpstan-extension", "extra": { @@ -1490,34 +1489,33 @@ "description": "PHPUnit extensions and rules for PHPStan", "support": { "issues": "https://github.com/phpstan/phpstan-phpunit/issues", - "source": "https://github.com/phpstan/phpstan-phpunit/tree/1.4.0" + "source": "https://github.com/phpstan/phpstan-phpunit/tree/2.0.3" }, - "time": "2024-04-20T06:39:00+00:00" + "time": "2024-12-19T09:14:43+00:00" }, { "name": "phpstan/phpstan-strict-rules", - "version": "1.6.0", + "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-strict-rules.git", - "reference": "363f921dd8441777d4fc137deb99beb486c77df1" + "reference": "ed6fea0ad4ad9c7e25f3ad2e7c4d420cf1e67fe3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/363f921dd8441777d4fc137deb99beb486c77df1", - "reference": "363f921dd8441777d4fc137deb99beb486c77df1", + "url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/ed6fea0ad4ad9c7e25f3ad2e7c4d420cf1e67fe3", + "reference": "ed6fea0ad4ad9c7e25f3ad2e7c4d420cf1e67fe3", "shasum": "" }, "require": { - "php": "^7.2 || ^8.0", - "phpstan/phpstan": "^1.11" + "php": "^7.4 || ^8.0", + "phpstan/phpstan": "^2.0.4" }, "require-dev": { - "nikic/php-parser": "^4.13.0", "php-parallel-lint/php-parallel-lint": "^1.2", - "phpstan/phpstan-deprecation-rules": "^1.1", - "phpstan/phpstan-phpunit": "^1.0", - "phpunit/phpunit": "^9.5" + "phpstan/phpstan-deprecation-rules": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpunit/phpunit": "^9.6" }, "type": "phpstan-extension", "extra": { @@ -1539,9 +1537,9 @@ "description": "Extra strict and opinionated rules for PHPStan", "support": { "issues": "https://github.com/phpstan/phpstan-strict-rules/issues", - "source": "https://github.com/phpstan/phpstan-strict-rules/tree/1.6.0" + "source": "https://github.com/phpstan/phpstan-strict-rules/tree/2.0.1" }, - "time": "2024-04-20T06:37:51+00:00" + "time": "2024-12-12T20:21:10+00:00" }, { "name": "phpunit/php-code-coverage", diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 6e85786525..dfaa964e4b 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -1,6 +1,7 @@ includes: - tests/phpstan/analyse-for-current-php-version.neon.php - tests/phpstan/configs/actual-problems.neon + - tests/phpstan/configs/dependency-problems.neon - tests/phpstan/configs/impossible-generics.neon - tests/phpstan/configs/php-bugs.neon - tests/phpstan/configs/phpstan-bugs.neon @@ -31,6 +32,7 @@ parameters: paths: - build - src + - tests/phpstan/DummyPluginOwned.php - tests/phpstan/rules - tests/phpunit - tests/plugins/TesterPlugin diff --git a/src/command/utils/CommandStringHelper.php b/src/command/utils/CommandStringHelper.php index eacc5d3d8b..76d70a9bba 100644 --- a/src/command/utils/CommandStringHelper.php +++ b/src/command/utils/CommandStringHelper.php @@ -51,9 +51,8 @@ public static function parseQuoteAware(string $commandLine) : array{ foreach($matches[0] as $k => $_){ for($i = 1; $i <= 2; ++$i){ if($matches[$i][$k] !== ""){ - /** @var string $match */ //phpstan can't understand preg_match and friends by itself :( $match = $matches[$i][$k]; - $args[(int) $k] = preg_replace('/\\\\([\\\\"])/u', '$1', $match) ?? throw new AssumptionFailedError(preg_last_error_msg()); + $args[] = preg_replace('/\\\\([\\\\"])/u', '$1', $match) ?? throw new AssumptionFailedError(preg_last_error_msg()); break; } } diff --git a/src/utils/Utils.php b/src/utils/Utils.php index 37cf543903..f557562c99 100644 --- a/src/utils/Utils.php +++ b/src/utils/Utils.php @@ -167,6 +167,7 @@ public static function getNiceClassName(object $obj) : string{ /** * @phpstan-return \Closure(object) : object + * @deprecated */ public static function cloneCallback() : \Closure{ return static function(object $o){ @@ -179,15 +180,13 @@ public static function cloneCallback() : \Closure{ * @phpstan-template TValue of object * * @param object[] $array - * @phpstan-param array $array + * @phpstan-param array|list $array * * @return object[] - * @phpstan-return array + * @phpstan-return ($array is list ? list : array) */ public static function cloneObjectArray(array $array) : array{ - /** @phpstan-var \Closure(TValue) : TValue $callback */ - $callback = self::cloneCallback(); - return array_map($callback, $array); + return array_map(fn(object $o) => clone $o, $array); } /** diff --git a/src/world/format/io/region/RegionWorldProvider.php b/src/world/format/io/region/RegionWorldProvider.php index 7a4463f5d1..8fe7928b81 100644 --- a/src/world/format/io/region/RegionWorldProvider.php +++ b/src/world/format/io/region/RegionWorldProvider.php @@ -215,6 +215,9 @@ public function loadChunk(int $chunkX, int $chunkZ) : ?LoadedChunkData{ return null; } + /** + * @phpstan-return \RegexIterator + */ private function createRegionIterator() : \RegexIterator{ return new \RegexIterator( new \FilesystemIterator( diff --git a/src/world/generator/FlatGeneratorOptions.php b/src/world/generator/FlatGeneratorOptions.php index b52d64658e..563297b00d 100644 --- a/src/world/generator/FlatGeneratorOptions.php +++ b/src/world/generator/FlatGeneratorOptions.php @@ -117,7 +117,7 @@ public static function parsePreset(string $presetString) : self{ } } } - $options[(string) $option] = $params; + $options[$option] = $params; } return new self($structure, $biomeId, $options); } diff --git a/tests/phpstan/DummyPluginOwned.php b/tests/phpstan/DummyPluginOwned.php new file mode 100644 index 0000000000..b63975dcfb --- /dev/null +++ b/tests/phpstan/DummyPluginOwned.php @@ -0,0 +1,28 @@ +, array\\ given\\.$#" + message: '#^Parameter \#1 \$strings of function pocketmine\\build\\server_phar\\preg_quote_array expects array\, array\ given\.$#' + identifier: argument.type count: 1 path: ../../../build/server-phar.php - - message: "#^Do\\-while loop condition is always false\\.$#" + message: '#^Do\-while loop condition is always false\.$#' + identifier: doWhile.alwaysFalse count: 1 path: ../../../src/PocketMine.php - - message: "#^Parameter \\#1 \\$array of static method pocketmine\\\\plugin\\\\PluginGraylist\\:\\:fromArray\\(\\) expects array, mixed given\\.$#" + message: '#^Cannot cast mixed to string\.$#' + identifier: cast.string count: 1 path: ../../../src/Server.php - - message: "#^Cannot cast mixed to int\\.$#" + message: '#^Method pocketmine\\Server\:\:getCommandAliases\(\) should return array\\> but returns array\\>\.$#' + identifier: return.type + count: 1 + path: ../../../src/Server.php + + - + message: '#^Parameter \#1 \$generatorName of closure expects string, mixed given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/Server.php + + - + message: '#^Cannot cast mixed to int\.$#' + identifier: cast.int count: 2 path: ../../../src/ServerConfigGroup.php - - message: "#^Cannot cast mixed to string\\.$#" + message: '#^Cannot cast mixed to string\.$#' + identifier: cast.string count: 2 path: ../../../src/ServerConfigGroup.php - - message: "#^Cannot access offset 'git' on mixed\\.$#" + message: '#^Cannot access offset ''git'' on mixed\.$#' + identifier: offsetAccess.nonOffsetAccessible count: 1 path: ../../../src/VersionInfo.php - - message: "#^Method pocketmine\\\\VersionInfo\\:\\:GIT_HASH\\(\\) should return string but returns mixed\\.$#" + message: '#^Method pocketmine\\VersionInfo\:\:GIT_HASH\(\) should return string but returns mixed\.$#' + identifier: return.type count: 1 path: ../../../src/VersionInfo.php - - message: "#^Static property pocketmine\\\\VersionInfo\\:\\:\\$gitHash \\(string\\|null\\) does not accept mixed\\.$#" + message: '#^Static property pocketmine\\VersionInfo\:\:\$gitHash \(string\|null\) does not accept mixed\.$#' + identifier: assign.propertyType count: 1 path: ../../../src/VersionInfo.php - - message: "#^Parameter \\#1 \\$x of method pocketmine\\\\world\\\\World\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#1 \$x of method pocketmine\\world\\World\:\:getBlockAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 3 path: ../../../src/block/Block.php - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\world\\\\World\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#2 \$y of method pocketmine\\world\\World\:\:getBlockAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 3 path: ../../../src/block/Block.php - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\world\\\\format\\\\Chunk\\:\\:setBlockStateId\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#2 \$y of method pocketmine\\world\\format\\Chunk\:\:setBlockStateId\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/Block.php - - message: "#^Parameter \\#3 \\$z of method pocketmine\\\\world\\\\World\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#3 \$z of method pocketmine\\world\\World\:\:getBlockAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 3 path: ../../../src/block/Block.php - - message: "#^Parameter \\#1 \\$x of method pocketmine\\\\world\\\\World\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#1 \$x of method pocketmine\\world\\World\:\:getBlockAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/Cactus.php - - message: "#^Parameter \\#1 \\$x of method pocketmine\\\\world\\\\World\\:\\:isInWorld\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#1 \$x of method pocketmine\\world\\World\:\:isInWorld\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/Cactus.php - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\world\\\\World\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#2 \$y of method pocketmine\\world\\World\:\:getBlockAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/Cactus.php - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\world\\\\World\\:\\:isInWorld\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#2 \$y of method pocketmine\\world\\World\:\:isInWorld\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/Cactus.php - - message: "#^Parameter \\#3 \\$z of method pocketmine\\\\world\\\\World\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#3 \$z of method pocketmine\\world\\World\:\:getBlockAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/Cactus.php - - message: "#^Parameter \\#3 \\$z of method pocketmine\\\\world\\\\World\\:\\:isInWorld\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#3 \$z of method pocketmine\\world\\World\:\:isInWorld\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/Cactus.php - - message: "#^Parameter \\#1 \\$x of method pocketmine\\\\world\\\\World\\:\\:isInWorld\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#1 \$x of method pocketmine\\world\\World\:\:isInWorld\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 2 path: ../../../src/block/ChorusFlower.php - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\world\\\\World\\:\\:isInWorld\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#2 \$y of method pocketmine\\world\\World\:\:isInWorld\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 2 path: ../../../src/block/ChorusFlower.php - - message: "#^Parameter \\#3 \\$z of method pocketmine\\\\world\\\\World\\:\\:isInWorld\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#3 \$z of method pocketmine\\world\\World\:\:isInWorld\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 2 path: ../../../src/block/ChorusFlower.php - - message: "#^Parameter \\#1 \\$x of method pocketmine\\\\world\\\\World\\:\\:getRealBlockSkyLightAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#1 \$x of method pocketmine\\world\\World\:\:getRealBlockSkyLightAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/DaylightSensor.php - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\world\\\\World\\:\\:getRealBlockSkyLightAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#2 \$y of method pocketmine\\world\\World\:\:getRealBlockSkyLightAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/DaylightSensor.php - - message: "#^Parameter \\#3 \\$z of method pocketmine\\\\world\\\\World\\:\\:getRealBlockSkyLightAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#3 \$z of method pocketmine\\world\\World\:\:getRealBlockSkyLightAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/DaylightSensor.php - - message: "#^Parameter \\#1 \\$x of method pocketmine\\\\world\\\\World\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#1 \$x of method pocketmine\\world\\World\:\:getBlockAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/DragonEgg.php - - message: "#^Parameter \\#1 \\$xDiff of class pocketmine\\\\world\\\\particle\\\\DragonEggTeleportParticle constructor expects int, float\\|int given\\.$#" + message: '#^Parameter \#1 \$xDiff of class pocketmine\\world\\particle\\DragonEggTeleportParticle constructor expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/DragonEgg.php - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\world\\\\World\\:\\:getBlockAt\\(\\) expects int, float\\|int\\<\\-64, 319\\> given\\.$#" + message: '#^Parameter \#2 \$y of method pocketmine\\world\\World\:\:getBlockAt\(\) expects int, float\|int\<\-64, 319\> given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/DragonEgg.php - - message: "#^Parameter \\#2 \\$yDiff of class pocketmine\\\\world\\\\particle\\\\DragonEggTeleportParticle constructor expects int, float\\|int given\\.$#" + message: '#^Parameter \#2 \$yDiff of class pocketmine\\world\\particle\\DragonEggTeleportParticle constructor expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/DragonEgg.php - - message: "#^Parameter \\#3 \\$z of method pocketmine\\\\world\\\\World\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#3 \$z of method pocketmine\\world\\World\:\:getBlockAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/DragonEgg.php - - message: "#^Parameter \\#3 \\$zDiff of class pocketmine\\\\world\\\\particle\\\\DragonEggTeleportParticle constructor expects int, float\\|int given\\.$#" + message: '#^Parameter \#3 \$zDiff of class pocketmine\\world\\particle\\DragonEggTeleportParticle constructor expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/DragonEgg.php - - message: "#^Parameter \\#1 \\$x of method pocketmine\\\\world\\\\World\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#1 \$x of method pocketmine\\world\\World\:\:getBlockAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/Fire.php - - message: "#^Parameter \\#1 \\$x of method pocketmine\\\\world\\\\World\\:\\:isInWorld\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#1 \$x of method pocketmine\\world\\World\:\:isInWorld\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/Fire.php - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\world\\\\World\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#2 \$y of method pocketmine\\world\\World\:\:getBlockAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/Fire.php - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\world\\\\World\\:\\:isInWorld\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#2 \$y of method pocketmine\\world\\World\:\:isInWorld\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/Fire.php - - message: "#^Parameter \\#3 \\$z of method pocketmine\\\\world\\\\World\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#3 \$z of method pocketmine\\world\\World\:\:getBlockAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/Fire.php - - message: "#^Parameter \\#3 \\$z of method pocketmine\\\\world\\\\World\\:\\:isInWorld\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#3 \$z of method pocketmine\\world\\World\:\:isInWorld\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/Fire.php - - message: "#^Parameter \\#1 \\$x of method pocketmine\\\\world\\\\World\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#1 \$x of method pocketmine\\world\\World\:\:getBlockAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/FrostedIce.php - - message: "#^Parameter \\#1 \\$x of method pocketmine\\\\world\\\\World\\:\\:getHighestAdjacentFullLightAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#1 \$x of method pocketmine\\world\\World\:\:getHighestAdjacentFullLightAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/FrostedIce.php - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\world\\\\World\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#2 \$y of method pocketmine\\world\\World\:\:getBlockAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/FrostedIce.php - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\world\\\\World\\:\\:getHighestAdjacentFullLightAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#2 \$y of method pocketmine\\world\\World\:\:getHighestAdjacentFullLightAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/FrostedIce.php - - message: "#^Parameter \\#3 \\$z of method pocketmine\\\\world\\\\World\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#3 \$z of method pocketmine\\world\\World\:\:getBlockAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/FrostedIce.php - - message: "#^Parameter \\#3 \\$z of method pocketmine\\\\world\\\\World\\:\\:getHighestAdjacentFullLightAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#3 \$z of method pocketmine\\world\\World\:\:getHighestAdjacentFullLightAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/FrostedIce.php - - message: "#^Parameter \\#1 \\$min of function mt_rand expects int, float\\|int given\\.$#" + message: '#^Parameter \#1 \$min of function mt_rand expects int, float\|int given\.$#' + identifier: argument.type count: 3 path: ../../../src/block/Grass.php - - message: "#^Parameter \\#1 \\$x of method pocketmine\\\\world\\\\World\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#1 \$x of method pocketmine\\world\\World\:\:getBlockAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/Grass.php - - message: "#^Parameter \\#1 \\$x of method pocketmine\\\\world\\\\World\\:\\:getFullLightAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#1 \$x of method pocketmine\\world\\World\:\:getFullLightAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/Grass.php - - message: "#^Parameter \\#2 \\$max of function mt_rand expects int, float\\|int given\\.$#" + message: '#^Parameter \#2 \$max of function mt_rand expects int, float\|int given\.$#' + identifier: argument.type count: 3 path: ../../../src/block/Grass.php - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\world\\\\World\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#2 \$y of method pocketmine\\world\\World\:\:getBlockAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/Grass.php - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\world\\\\World\\:\\:getFullLightAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#2 \$y of method pocketmine\\world\\World\:\:getFullLightAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/Grass.php - - message: "#^Parameter \\#3 \\$z of method pocketmine\\\\world\\\\World\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#3 \$z of method pocketmine\\world\\World\:\:getBlockAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/Grass.php - - message: "#^Parameter \\#3 \\$z of method pocketmine\\\\world\\\\World\\:\\:getFullLightAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#3 \$z of method pocketmine\\world\\World\:\:getFullLightAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/Grass.php - - message: "#^Parameter \\#1 \\$x of method pocketmine\\\\world\\\\World\\:\\:getHighestAdjacentBlockLight\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#1 \$x of method pocketmine\\world\\World\:\:getHighestAdjacentBlockLight\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/Ice.php - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\world\\\\World\\:\\:getHighestAdjacentBlockLight\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#2 \$y of method pocketmine\\world\\World\:\:getHighestAdjacentBlockLight\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/Ice.php - - message: "#^Parameter \\#3 \\$z of method pocketmine\\\\world\\\\World\\:\\:getHighestAdjacentBlockLight\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#3 \$z of method pocketmine\\world\\World\:\:getHighestAdjacentBlockLight\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/Ice.php - - message: "#^Parameter \\#1 \\$x of static method pocketmine\\\\world\\\\World\\:\\:blockHash\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#1 \$x of static method pocketmine\\world\\World\:\:blockHash\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/Leaves.php - - message: "#^Parameter \\#2 \\$y of static method pocketmine\\\\world\\\\World\\:\\:blockHash\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#2 \$y of static method pocketmine\\world\\World\:\:blockHash\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/Leaves.php - - message: "#^Parameter \\#3 \\$z of static method pocketmine\\\\world\\\\World\\:\\:blockHash\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#3 \$z of static method pocketmine\\world\\World\:\:blockHash\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/Leaves.php - - message: "#^Parameter \\#1 \\$x of method pocketmine\\\\world\\\\World\\:\\:isInWorld\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#1 \$x of method pocketmine\\world\\World\:\:isInWorld\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/Liquid.php - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\world\\\\World\\:\\:isInWorld\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#2 \$y of method pocketmine\\world\\World\:\:isInWorld\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/Liquid.php - - message: "#^Parameter \\#3 \\$z of method pocketmine\\\\world\\\\World\\:\\:isInWorld\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#3 \$z of method pocketmine\\world\\World\:\:isInWorld\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/Liquid.php - - message: "#^Parameter \\#1 \\$min of function mt_rand expects int, float\\|int given\\.$#" + message: '#^Parameter \#1 \$min of function mt_rand expects int, float\|int given\.$#' + identifier: argument.type count: 3 path: ../../../src/block/Mycelium.php - - message: "#^Parameter \\#2 \\$max of function mt_rand expects int, float\\|int given\\.$#" + message: '#^Parameter \#2 \$max of function mt_rand expects int, float\|int given\.$#' + identifier: argument.type count: 3 path: ../../../src/block/Mycelium.php - - message: "#^Parameter \\#1 \\$x of method pocketmine\\\\world\\\\World\\:\\:getFullLightAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#1 \$x of method pocketmine\\world\\World\:\:getFullLightAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/RedMushroom.php - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\world\\\\World\\:\\:getFullLightAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#2 \$y of method pocketmine\\world\\World\:\:getFullLightAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/RedMushroom.php - - message: "#^Parameter \\#3 \\$z of method pocketmine\\\\world\\\\World\\:\\:getFullLightAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#3 \$z of method pocketmine\\world\\World\:\:getFullLightAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/RedMushroom.php - - message: "#^Parameter \\#1 \\$x of method pocketmine\\\\world\\\\World\\:\\:getBlockLightAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#1 \$x of method pocketmine\\world\\World\:\:getBlockLightAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/SnowLayer.php - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\world\\\\World\\:\\:getBlockLightAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#2 \$y of method pocketmine\\world\\World\:\:getBlockLightAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/SnowLayer.php - - message: "#^Parameter \\#3 \\$z of method pocketmine\\\\world\\\\World\\:\\:getBlockLightAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#3 \$z of method pocketmine\\world\\World\:\:getBlockLightAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/SnowLayer.php - - message: "#^Parameter \\#1 \\$x of method pocketmine\\\\world\\\\World\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#1 \$x of method pocketmine\\world\\World\:\:getBlockAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/Sugarcane.php - - message: "#^Parameter \\#1 \\$x of method pocketmine\\\\world\\\\World\\:\\:isInWorld\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#1 \$x of method pocketmine\\world\\World\:\:isInWorld\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/Sugarcane.php - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\world\\\\World\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#2 \$y of method pocketmine\\world\\World\:\:getBlockAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/Sugarcane.php - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\world\\\\World\\:\\:isInWorld\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#2 \$y of method pocketmine\\world\\World\:\:isInWorld\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/Sugarcane.php - - message: "#^Parameter \\#3 \\$z of method pocketmine\\\\world\\\\World\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#3 \$z of method pocketmine\\world\\World\:\:getBlockAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/Sugarcane.php - - message: "#^Parameter \\#3 \\$z of method pocketmine\\\\world\\\\World\\:\\:isInWorld\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#3 \$z of method pocketmine\\world\\World\:\:isInWorld\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/Sugarcane.php - - message: "#^Parameter \\#1 \\$x of class pocketmine\\\\math\\\\Vector3 constructor expects float\\|int, int\\|null given\\.$#" + message: '#^Parameter \#1 \$x of class pocketmine\\math\\Vector3 constructor expects float\|int, int\|null given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/tile/Chest.php - - message: "#^Parameter \\#1 \\$x of method pocketmine\\\\world\\\\World\\:\\:getTileAt\\(\\) expects int, int\\|null given\\.$#" + message: '#^Parameter \#1 \$x of method pocketmine\\world\\World\:\:getTileAt\(\) expects int, int\|null given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/tile/Chest.php - - message: "#^Parameter \\#2 \\$value of method pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\:\\:setInt\\(\\) expects int, int\\|null given\\.$#" + message: '#^Parameter \#2 \$value of method pocketmine\\nbt\\tag\\CompoundTag\:\:setInt\(\) expects int, int\|null given\.$#' + identifier: argument.type count: 4 path: ../../../src/block/tile/Chest.php - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\world\\\\World\\:\\:getTileAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#2 \$y of method pocketmine\\world\\World\:\:getTileAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/tile/Chest.php - - message: "#^Parameter \\#3 \\$z of class pocketmine\\\\math\\\\Vector3 constructor expects float\\|int, int\\|null given\\.$#" + message: '#^Parameter \#3 \$z of class pocketmine\\math\\Vector3 constructor expects float\|int, int\|null given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/tile/Chest.php - - message: "#^Parameter \\#3 \\$z of method pocketmine\\\\world\\\\World\\:\\:getTileAt\\(\\) expects int, int\\|null given\\.$#" + message: '#^Parameter \#3 \$z of method pocketmine\\world\\World\:\:getTileAt\(\) expects int, int\|null given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/tile/Chest.php - - message: "#^Property pocketmine\\\\block\\\\tile\\\\Chest\\:\\:\\$pairX \\(int\\|null\\) does not accept float\\|int\\.$#" + message: '#^Property pocketmine\\block\\tile\\Chest\:\:\$pairX \(int\|null\) does not accept float\|int\.$#' + identifier: assign.propertyType count: 2 path: ../../../src/block/tile/Chest.php - - message: "#^Property pocketmine\\\\block\\\\tile\\\\Chest\\:\\:\\$pairZ \\(int\\|null\\) does not accept float\\|int\\.$#" + message: '#^Property pocketmine\\block\\tile\\Chest\:\:\$pairZ \(int\|null\) does not accept float\|int\.$#' + identifier: assign.propertyType count: 2 path: ../../../src/block/tile/Chest.php - - message: "#^Constant pocketmine\\\\block\\\\tile\\\\MobHead\\:\\:TAG_MOUTH_MOVING is unused\\.$#" + message: '#^Constant pocketmine\\block\\tile\\MobHead\:\:TAG_MOUTH_MOVING is unused\.$#' + identifier: classConstant.unused count: 1 path: ../../../src/block/tile/MobHead.php - - message: "#^Constant pocketmine\\\\block\\\\tile\\\\MobHead\\:\\:TAG_MOUTH_TICK_COUNT is unused\\.$#" + message: '#^Constant pocketmine\\block\\tile\\MobHead\:\:TAG_MOUTH_TICK_COUNT is unused\.$#' + identifier: classConstant.unused count: 1 path: ../../../src/block/tile/MobHead.php - - message: "#^Parameter \\#2 \\$value of method pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\:\\:setInt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#2 \$value of method pocketmine\\nbt\\tag\\CompoundTag\:\:setInt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 3 path: ../../../src/block/tile/Spawnable.php - - message: "#^Parameter \\#1 \\$x of method pocketmine\\\\world\\\\World\\:\\:getPotentialLightAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#1 \$x of method pocketmine\\world\\World\:\:getPotentialLightAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/utils/CropGrowthHelper.php - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\world\\\\World\\:\\:getPotentialLightAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#2 \$y of method pocketmine\\world\\World\:\:getPotentialLightAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/utils/CropGrowthHelper.php - - message: "#^Parameter \\#3 \\$z of method pocketmine\\\\world\\\\World\\:\\:getPotentialLightAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#3 \$z of method pocketmine\\world\\World\:\:getPotentialLightAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/block/utils/CropGrowthHelper.php - - message: "#^Cannot call method addParticle\\(\\) on pocketmine\\\\world\\\\World\\|null\\.$#" + message: '#^Cannot call method addParticle\(\) on pocketmine\\world\\World\|null\.$#' + identifier: method.nonObject count: 1 path: ../../../src/command/defaults/ParticleCommand.php - - message: "#^Cannot call method getSeed\\(\\) on pocketmine\\\\world\\\\World\\|null\\.$#" + message: '#^Cannot call method getSeed\(\) on pocketmine\\world\\World\|null\.$#' + identifier: method.nonObject count: 1 path: ../../../src/command/defaults/SeedCommand.php - - message: "#^Cannot call method setSpawnLocation\\(\\) on pocketmine\\\\world\\\\World\\|null\\.$#" + message: '#^Cannot call method setSpawnLocation\(\) on pocketmine\\world\\World\|null\.$#' + identifier: method.nonObject count: 1 path: ../../../src/command/defaults/SetWorldSpawnCommand.php - - message: "#^Cannot call method getTime\\(\\) on pocketmine\\\\world\\\\World\\|null\\.$#" + message: '#^Cannot call method getTime\(\) on pocketmine\\world\\World\|null\.$#' + identifier: method.nonObject count: 1 path: ../../../src/command/defaults/TimeCommand.php - - message: "#^Parameter \\#1 \\$path of static method pocketmine\\\\utils\\\\Filesystem\\:\\:cleanPath\\(\\) expects string, mixed given\\.$#" + message: '#^Parameter \#1 \$path of static method pocketmine\\utils\\Filesystem\:\:cleanPath\(\) expects string, mixed given\.$#' + identifier: argument.type count: 1 path: ../../../src/crash/CrashDump.php - - message: "#^Parameter \\#1 \\$x of method pocketmine\\\\world\\\\World\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Binary operation "\." between ''Error\: '' and mixed results in an error\.$#' + identifier: binaryOp.invalid + count: 1 + path: ../../../src/crash/CrashDumpRenderer.php + + - + message: '#^Binary operation "\." between ''File\: '' and mixed results in an error\.$#' + identifier: binaryOp.invalid + count: 1 + path: ../../../src/crash/CrashDumpRenderer.php + + - + message: '#^Binary operation "\." between ''Line\: '' and mixed results in an error\.$#' + identifier: binaryOp.invalid + count: 1 + path: ../../../src/crash/CrashDumpRenderer.php + + - + message: '#^Binary operation "\." between ''Type\: '' and mixed results in an error\.$#' + identifier: binaryOp.invalid + count: 1 + path: ../../../src/crash/CrashDumpRenderer.php + + - + message: '#^Parameter \#1 \$blockToItemId of class pocketmine\\data\\bedrock\\item\\BlockItemIdMap constructor expects array\, array\ given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/data/bedrock/item/BlockItemIdMap.php + + - + message: '#^Parameter \#1 \$x of method pocketmine\\world\\World\:\:getBlockAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/entity/Living.php - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\world\\\\World\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#2 \$y of method pocketmine\\world\\World\:\:getBlockAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/entity/Living.php - - message: "#^Parameter \\#3 \\$z of method pocketmine\\\\world\\\\World\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#3 \$z of method pocketmine\\world\\World\:\:getBlockAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/entity/Living.php - - message: "#^Parameter \\#2 \\$x of method pocketmine\\\\block\\\\Block\\:\\:position\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#2 \$x of method pocketmine\\block\\Block\:\:position\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/entity/object/FallingBlock.php - - message: "#^Parameter \\#3 \\$y of method pocketmine\\\\block\\\\Block\\:\\:position\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#3 \$y of method pocketmine\\block\\Block\:\:position\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/entity/object/FallingBlock.php - - message: "#^Parameter \\#4 \\$z of method pocketmine\\\\block\\\\Block\\:\\:position\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#4 \$z of method pocketmine\\block\\Block\:\:position\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/entity/object/FallingBlock.php - - message: "#^Parameter \\#1 \\$x of method pocketmine\\\\world\\\\World\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#1 \$x of method pocketmine\\world\\World\:\:getBlockAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/entity/object/Painting.php - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\world\\\\World\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#2 \$y of method pocketmine\\world\\World\:\:getBlockAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/entity/object/Painting.php - - message: "#^Parameter \\#3 \\$z of method pocketmine\\\\world\\\\World\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#3 \$z of method pocketmine\\world\\World\:\:getBlockAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/entity/object/Painting.php - - message: "#^Parameter \\#1 \\$x of method pocketmine\\\\world\\\\World\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#1 \$x of method pocketmine\\world\\World\:\:getBlockAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/entity/projectile/Projectile.php - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\world\\\\World\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#2 \$y of method pocketmine\\world\\World\:\:getBlockAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/entity/projectile/Projectile.php - - message: "#^Parameter \\#3 \\$z of method pocketmine\\\\world\\\\World\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#3 \$z of method pocketmine\\world\\World\:\:getBlockAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/entity/projectile/Projectile.php - - message: "#^Parameter \\#2 \\$recipe of class pocketmine\\\\event\\\\inventory\\\\CraftItemEvent constructor expects pocketmine\\\\crafting\\\\CraftingRecipe, pocketmine\\\\crafting\\\\CraftingRecipe\\|null given\\.$#" + message: '#^Parameter \#2 \$recipe of class pocketmine\\event\\inventory\\CraftItemEvent constructor expects pocketmine\\crafting\\CraftingRecipe, pocketmine\\crafting\\CraftingRecipe\|null given\.$#' + identifier: argument.type count: 1 path: ../../../src/inventory/transaction/CraftingTransaction.php - - message: "#^Parameter \\#3 \\$repetitions of class pocketmine\\\\event\\\\inventory\\\\CraftItemEvent constructor expects int, int\\|null given\\.$#" + message: '#^Parameter \#3 \$repetitions of class pocketmine\\event\\inventory\\CraftItemEvent constructor expects int, int\|null given\.$#' + identifier: argument.type count: 1 path: ../../../src/inventory/transaction/CraftingTransaction.php - - message: "#^Cannot cast mixed to int\\.$#" + message: '#^Parameter &\$haveItems @param\-out type of method pocketmine\\inventory\\transaction\\InventoryTransaction\:\:matchItems\(\) expects list\, array\, pocketmine\\item\\Item\> given\.$#' + identifier: paramOut.type + count: 1 + path: ../../../src/inventory/transaction/InventoryTransaction.php + + - + message: '#^Parameter &\$needItems @param\-out type of method pocketmine\\inventory\\transaction\\InventoryTransaction\:\:matchItems\(\) expects list\, array\, pocketmine\\item\\Item\> given\.$#' + identifier: paramOut.type + count: 1 + path: ../../../src/inventory/transaction/InventoryTransaction.php + + - + message: '#^Cannot cast mixed to int\.$#' + identifier: cast.int count: 2 path: ../../../src/item/Item.php - - message: "#^Parameter \\#1 \\$buffer of method pocketmine\\\\nbt\\\\BaseNbtSerializer\\:\\:read\\(\\) expects string, mixed given\\.$#" + message: '#^Parameter \#1 \$buffer of method pocketmine\\nbt\\BaseNbtSerializer\:\:read\(\) expects string, mixed given\.$#' + identifier: argument.type count: 1 path: ../../../src/item/Item.php - - message: "#^Parameter \\#1 \\$string of function base64_decode expects string, mixed given\\.$#" + message: '#^Parameter \#1 \$string of function base64_decode expects string, mixed given\.$#' + identifier: argument.type count: 1 path: ../../../src/item/Item.php - - message: "#^Parameter \\#1 \\$string of function hex2bin expects string, mixed given\\.$#" + message: '#^Parameter \#1 \$string of function hex2bin expects string, mixed given\.$#' + identifier: argument.type count: 1 path: ../../../src/item/Item.php - - message: "#^Parameter \\#1 \\$result of method pocketmine\\\\network\\\\mcpe\\\\compression\\\\CompressBatchPromise\\:\\:resolve\\(\\) expects string, mixed given\\.$#" + message: '#^Parameter \#1 \$result of method pocketmine\\network\\mcpe\\compression\\CompressBatchPromise\:\:resolve\(\) expects string, mixed given\.$#' + identifier: argument.type count: 1 path: ../../../src/network/mcpe/ChunkRequestTask.php - - message: "#^Cannot call method doFirstSpawn\\(\\) on pocketmine\\\\player\\\\Player\\|null\\.$#" + message: '#^Cannot call method doFirstSpawn\(\) on pocketmine\\player\\Player\|null\.$#' + identifier: method.nonObject count: 1 path: ../../../src/network/mcpe/NetworkSession.php - - message: "#^Cannot call method getAttributeMap\\(\\) on pocketmine\\\\player\\\\Player\\|null\\.$#" + message: '#^Cannot call method getAttributeMap\(\) on pocketmine\\player\\Player\|null\.$#' + identifier: method.nonObject count: 1 path: ../../../src/network/mcpe/NetworkSession.php - - message: "#^Cannot call method getLanguage\\(\\) on pocketmine\\\\player\\\\Player\\|null\\.$#" + message: '#^Cannot call method getLanguage\(\) on pocketmine\\player\\Player\|null\.$#' + identifier: method.nonObject count: 4 path: ../../../src/network/mcpe/NetworkSession.php - - message: "#^Cannot call method getLocation\\(\\) on pocketmine\\\\player\\\\Player\\|null\\.$#" + message: '#^Cannot call method getLocation\(\) on pocketmine\\player\\Player\|null\.$#' + identifier: method.nonObject count: 2 path: ../../../src/network/mcpe/NetworkSession.php - - message: "#^Cannot call method getUsedChunkStatus\\(\\) on pocketmine\\\\player\\\\Player\\|null\\.$#" + message: '#^Cannot call method getUsedChunkStatus\(\) on pocketmine\\player\\Player\|null\.$#' + identifier: method.nonObject count: 1 path: ../../../src/network/mcpe/NetworkSession.php - - message: "#^Cannot call method getUsername\\(\\) on pocketmine\\\\player\\\\PlayerInfo\\|null\\.$#" + message: '#^Cannot call method getUsername\(\) on pocketmine\\player\\PlayerInfo\|null\.$#' + identifier: method.nonObject count: 2 path: ../../../src/network/mcpe/NetworkSession.php - - message: "#^Cannot call method getUuid\\(\\) on pocketmine\\\\player\\\\PlayerInfo\\|null\\.$#" + message: '#^Cannot call method getUuid\(\) on pocketmine\\player\\PlayerInfo\|null\.$#' + identifier: method.nonObject count: 1 path: ../../../src/network/mcpe/NetworkSession.php - - message: "#^Cannot call method sendData\\(\\) on pocketmine\\\\player\\\\Player\\|null\\.$#" + message: '#^Cannot call method sendData\(\) on pocketmine\\player\\Player\|null\.$#' + identifier: method.nonObject count: 1 path: ../../../src/network/mcpe/NetworkSession.php - - message: "#^Cannot call method setNoClientPredictions\\(\\) on pocketmine\\\\player\\\\Player\\|null\\.$#" + message: '#^Cannot call method setNoClientPredictions\(\) on pocketmine\\player\\Player\|null\.$#' + identifier: method.nonObject count: 2 path: ../../../src/network/mcpe/NetworkSession.php - - message: "#^Cannot call method syncAll\\(\\) on pocketmine\\\\network\\\\mcpe\\\\InventoryManager\\|null\\.$#" + message: '#^Cannot call method syncAll\(\) on pocketmine\\network\\mcpe\\InventoryManager\|null\.$#' + identifier: method.nonObject count: 1 path: ../../../src/network/mcpe/NetworkSession.php - - message: "#^Parameter \\#1 \\$clientPub of class pocketmine\\\\network\\\\mcpe\\\\encryption\\\\PrepareEncryptionTask constructor expects string, string\\|null given\\.$#" + message: '#^Parameter \#1 \$clientPub of class pocketmine\\network\\mcpe\\encryption\\PrepareEncryptionTask constructor expects string, string\|null given\.$#' + identifier: argument.type count: 1 path: ../../../src/network/mcpe/NetworkSession.php - - message: "#^Parameter \\#1 \\$for of method pocketmine\\\\network\\\\mcpe\\\\NetworkSession\\:\\:syncAbilities\\(\\) expects pocketmine\\\\player\\\\Player, pocketmine\\\\player\\\\Player\\|null given\\.$#" + message: '#^Parameter \#1 \$for of method pocketmine\\network\\mcpe\\NetworkSession\:\:syncAbilities\(\) expects pocketmine\\player\\Player, pocketmine\\player\\Player\|null given\.$#' + identifier: argument.type count: 2 path: ../../../src/network/mcpe/NetworkSession.php - - message: "#^Parameter \\#1 \\$player of class pocketmine\\\\network\\\\mcpe\\\\handler\\\\DeathPacketHandler constructor expects pocketmine\\\\player\\\\Player, pocketmine\\\\player\\\\Player\\|null given\\.$#" + message: '#^Parameter \#1 \$player of class pocketmine\\network\\mcpe\\handler\\DeathPacketHandler constructor expects pocketmine\\player\\Player, pocketmine\\player\\Player\|null given\.$#' + identifier: argument.type count: 1 path: ../../../src/network/mcpe/NetworkSession.php - - message: "#^Parameter \\#1 \\$player of class pocketmine\\\\network\\\\mcpe\\\\handler\\\\InGamePacketHandler constructor expects pocketmine\\\\player\\\\Player, pocketmine\\\\player\\\\Player\\|null given\\.$#" + message: '#^Parameter \#1 \$player of class pocketmine\\network\\mcpe\\handler\\InGamePacketHandler constructor expects pocketmine\\player\\Player, pocketmine\\player\\Player\|null given\.$#' + identifier: argument.type count: 2 path: ../../../src/network/mcpe/NetworkSession.php - - message: "#^Parameter \\#1 \\$playerInfo of class pocketmine\\\\event\\\\player\\\\PlayerResourcePackOfferEvent constructor expects pocketmine\\\\player\\\\PlayerInfo, pocketmine\\\\player\\\\PlayerInfo\\|null given\\.$#" + message: '#^Parameter \#1 \$playerInfo of class pocketmine\\event\\player\\PlayerResourcePackOfferEvent constructor expects pocketmine\\player\\PlayerInfo, pocketmine\\player\\PlayerInfo\|null given\.$#' + identifier: argument.type count: 1 path: ../../../src/network/mcpe/NetworkSession.php - - message: "#^Parameter \\#1 \\$target of method pocketmine\\\\command\\\\Command\\:\\:testPermissionSilent\\(\\) expects pocketmine\\\\command\\\\CommandSender, pocketmine\\\\player\\\\Player\\|null given\\.$#" + message: '#^Parameter \#1 \$target of method pocketmine\\command\\Command\:\:testPermissionSilent\(\) expects pocketmine\\command\\CommandSender, pocketmine\\player\\Player\|null given\.$#' + identifier: argument.type count: 1 path: ../../../src/network/mcpe/NetworkSession.php - - message: "#^Parameter \\#2 \\$entity of method pocketmine\\\\network\\\\mcpe\\\\EntityEventBroadcaster\\:\\:onEntityEffectAdded\\(\\) expects pocketmine\\\\entity\\\\Living, pocketmine\\\\player\\\\Player\\|null given\\.$#" + message: '#^Parameter \#2 \$entity of method pocketmine\\network\\mcpe\\EntityEventBroadcaster\:\:onEntityEffectAdded\(\) expects pocketmine\\entity\\Living, pocketmine\\player\\Player\|null given\.$#' + identifier: argument.type count: 1 path: ../../../src/network/mcpe/NetworkSession.php - - message: "#^Parameter \\#2 \\$entity of method pocketmine\\\\network\\\\mcpe\\\\EntityEventBroadcaster\\:\\:onEntityEffectRemoved\\(\\) expects pocketmine\\\\entity\\\\Living, pocketmine\\\\player\\\\Player\\|null given\\.$#" + message: '#^Parameter \#2 \$entity of method pocketmine\\network\\mcpe\\EntityEventBroadcaster\:\:onEntityEffectRemoved\(\) expects pocketmine\\entity\\Living, pocketmine\\player\\Player\|null given\.$#' + identifier: argument.type count: 1 path: ../../../src/network/mcpe/NetworkSession.php - - message: "#^Parameter \\#2 \\$entity of method pocketmine\\\\network\\\\mcpe\\\\EntityEventBroadcaster\\:\\:syncAttributes\\(\\) expects pocketmine\\\\entity\\\\Living, pocketmine\\\\player\\\\Player\\|null given\\.$#" + message: '#^Parameter \#2 \$entity of method pocketmine\\network\\mcpe\\EntityEventBroadcaster\:\:syncAttributes\(\) expects pocketmine\\entity\\Living, pocketmine\\player\\Player\|null given\.$#' + identifier: argument.type count: 1 path: ../../../src/network/mcpe/NetworkSession.php - - message: "#^Parameter \\#2 \\$player of class pocketmine\\\\network\\\\mcpe\\\\handler\\\\PreSpawnPacketHandler constructor expects pocketmine\\\\player\\\\Player, pocketmine\\\\player\\\\Player\\|null given\\.$#" + message: '#^Parameter \#2 \$player of class pocketmine\\network\\mcpe\\handler\\PreSpawnPacketHandler constructor expects pocketmine\\player\\Player, pocketmine\\player\\Player\|null given\.$#' + identifier: argument.type count: 1 path: ../../../src/network/mcpe/NetworkSession.php - - message: "#^Parameter \\#2 \\$playerInfo of method pocketmine\\\\Server\\:\\:createPlayer\\(\\) expects pocketmine\\\\player\\\\PlayerInfo, pocketmine\\\\player\\\\PlayerInfo\\|null given\\.$#" + message: '#^Parameter \#2 \$playerInfo of method pocketmine\\Server\:\:createPlayer\(\) expects pocketmine\\player\\PlayerInfo, pocketmine\\player\\PlayerInfo\|null given\.$#' + identifier: argument.type count: 1 path: ../../../src/network/mcpe/NetworkSession.php - - message: "#^Parameter \\#3 \\$inventoryManager of class pocketmine\\\\network\\\\mcpe\\\\handler\\\\InGamePacketHandler constructor expects pocketmine\\\\network\\\\mcpe\\\\InventoryManager, pocketmine\\\\network\\\\mcpe\\\\InventoryManager\\|null given\\.$#" + message: '#^Parameter \#3 \$inventoryManager of class pocketmine\\network\\mcpe\\handler\\InGamePacketHandler constructor expects pocketmine\\network\\mcpe\\InventoryManager, pocketmine\\network\\mcpe\\InventoryManager\|null given\.$#' + identifier: argument.type count: 2 path: ../../../src/network/mcpe/NetworkSession.php - - message: "#^Parameter \\#4 \\$inventoryManager of class pocketmine\\\\network\\\\mcpe\\\\handler\\\\PreSpawnPacketHandler constructor expects pocketmine\\\\network\\\\mcpe\\\\InventoryManager, pocketmine\\\\network\\\\mcpe\\\\InventoryManager\\|null given\\.$#" + message: '#^Parameter \#4 \$inventoryManager of class pocketmine\\network\\mcpe\\handler\\PreSpawnPacketHandler constructor expects pocketmine\\network\\mcpe\\InventoryManager, pocketmine\\network\\mcpe\\InventoryManager\|null given\.$#' + identifier: argument.type count: 1 path: ../../../src/network/mcpe/NetworkSession.php - - message: "#^Property pocketmine\\\\network\\\\mcpe\\\\auth\\\\ProcessLoginTask\\:\\:\\$chain \\(string\\) does not accept string\\|null\\.$#" + message: '#^Property pocketmine\\network\\mcpe\\auth\\ProcessLoginTask\:\:\$chain \(string\) does not accept string\|null\.$#' + identifier: assign.propertyType count: 1 path: ../../../src/network/mcpe/auth/ProcessLoginTask.php - - message: "#^Parameter \\#1 \\$result of method pocketmine\\\\network\\\\mcpe\\\\compression\\\\CompressBatchPromise\\:\\:resolve\\(\\) expects string, mixed given\\.$#" + message: '#^Parameter \#1 \$result of method pocketmine\\network\\mcpe\\compression\\CompressBatchPromise\:\:resolve\(\) expects string, mixed given\.$#' + identifier: argument.type count: 1 path: ../../../src/network/mcpe/compression/CompressBatchTask.php - - message: "#^Property pocketmine\\\\network\\\\mcpe\\\\encryption\\\\PrepareEncryptionTask\\:\\:\\$serverPrivateKey \\(string\\) does not accept string\\|null\\.$#" + message: '#^Property pocketmine\\network\\mcpe\\encryption\\PrepareEncryptionTask\:\:\$serverPrivateKey \(string\) does not accept string\|null\.$#' + identifier: assign.propertyType count: 1 path: ../../../src/network/mcpe/encryption/PrepareEncryptionTask.php - - message: "#^Method pocketmine\\\\permission\\\\DefaultPermissions\\:\\:registerPermission\\(\\) should return pocketmine\\\\permission\\\\Permission but returns pocketmine\\\\permission\\\\Permission\\|null\\.$#" + message: '#^Method pocketmine\\permission\\DefaultPermissions\:\:registerPermission\(\) should return pocketmine\\permission\\Permission but returns pocketmine\\permission\\Permission\|null\.$#' + identifier: return.type count: 1 path: ../../../src/permission/DefaultPermissions.php - - message: "#^Parameter \\#1 \\$value of static method pocketmine\\\\permission\\\\PermissionParser\\:\\:defaultFromString\\(\\) expects bool\\|string, mixed given\\.$#" + message: '#^Parameter \#1 \$value of static method pocketmine\\permission\\PermissionParser\:\:defaultFromString\(\) expects bool\|string, mixed given\.$#' + identifier: argument.type count: 1 path: ../../../src/permission/PermissionParser.php - - message: "#^Parameter \\#2 \\$description of class pocketmine\\\\permission\\\\Permission constructor expects pocketmine\\\\lang\\\\Translatable\\|string\\|null, mixed given\\.$#" + message: '#^Parameter \#2 \$description of class pocketmine\\permission\\Permission constructor expects pocketmine\\lang\\Translatable\|string\|null, mixed given\.$#' + identifier: argument.type count: 1 path: ../../../src/permission/PermissionParser.php - - message: "#^Cannot call method getSpawnLocation\\(\\) on pocketmine\\\\world\\\\World\\|null\\.$#" + message: '#^Cannot call method getSpawnLocation\(\) on pocketmine\\world\\World\|null\.$#' + identifier: method.nonObject count: 1 path: ../../../src/player/Player.php - - message: "#^Method pocketmine\\\\player\\\\Player\\:\\:getSpawn\\(\\) should return pocketmine\\\\world\\\\Position but returns pocketmine\\\\world\\\\Position\\|null\\.$#" + message: '#^Method pocketmine\\player\\Player\:\:getSpawn\(\) should return pocketmine\\world\\Position but returns pocketmine\\world\\Position\|null\.$#' + identifier: return.type count: 1 path: ../../../src/player/Player.php - - message: "#^Method pocketmine\\\\plugin\\\\PluginBase\\:\\:getConfig\\(\\) should return pocketmine\\\\utils\\\\Config but returns pocketmine\\\\utils\\\\Config\\|null\\.$#" + message: '#^Method pocketmine\\plugin\\PluginBase\:\:getConfig\(\) should return pocketmine\\utils\\Config but returns pocketmine\\utils\\Config\|null\.$#' + identifier: return.type count: 1 path: ../../../src/plugin/PluginBase.php - - message: "#^Cannot cast mixed to string\\.$#" + message: '#^Cannot cast mixed to string\.$#' + identifier: cast.string count: 1 path: ../../../src/plugin/PluginDescription.php - - message: "#^Parameter \\#1 \\$haystack of function stripos expects string, mixed given\\.$#" + message: '#^Parameter \#1 \$haystack of function stripos expects string, mixed given\.$#' + identifier: argument.type count: 1 path: ../../../src/plugin/PluginDescription.php - - message: "#^Parameter \\#2 \\$subject of function preg_match expects string, mixed given\\.$#" + message: '#^Parameter \#2 \$subject of function preg_match expects string, mixed given\.$#' + identifier: argument.type count: 1 path: ../../../src/plugin/PluginDescription.php - - message: "#^Parameter \\#3 \\$subject of function str_replace expects array\\|string, mixed given\\.$#" + message: '#^Parameter \#3 \$subject of function str_replace expects array\\|string, mixed given\.$#' + identifier: argument.type count: 1 path: ../../../src/plugin/PluginDescription.php - - message: "#^Property pocketmine\\\\plugin\\\\PluginDescription\\:\\:\\$main \\(string\\) does not accept mixed\\.$#" + message: '#^Property pocketmine\\plugin\\PluginDescription\:\:\$authors \(array\\) does not accept list\\.$#' + identifier: assign.propertyType count: 1 path: ../../../src/plugin/PluginDescription.php - - message: "#^Property pocketmine\\\\plugin\\\\PluginDescription\\:\\:\\$name \\(string\\) does not accept mixed\\.$#" + message: '#^Property pocketmine\\plugin\\PluginDescription\:\:\$main \(string\) does not accept mixed\.$#' + identifier: assign.propertyType count: 1 path: ../../../src/plugin/PluginDescription.php - - message: "#^Cannot call method addChild\\(\\) on pocketmine\\\\permission\\\\Permission\\|null\\.$#" + message: '#^Property pocketmine\\plugin\\PluginDescription\:\:\$name \(string\) does not accept mixed\.$#' + identifier: assign.propertyType + count: 1 + path: ../../../src/plugin/PluginDescription.php + + - + message: '#^Cannot call method addChild\(\) on pocketmine\\permission\\Permission\|null\.$#' + identifier: method.nonObject count: 4 path: ../../../src/plugin/PluginManager.php - - message: "#^Method pocketmine\\\\resourcepacks\\\\ZippedResourcePack\\:\\:getPackSize\\(\\) should return int but returns int\\<0, max\\>\\|false\\.$#" + message: '#^Method pocketmine\\resourcepacks\\ZippedResourcePack\:\:getPackSize\(\) should return int but returns int\<0, max\>\|false\.$#' + identifier: return.type count: 1 path: ../../../src/resourcepacks/ZippedResourcePack.php - - message: "#^Method pocketmine\\\\resourcepacks\\\\ZippedResourcePack\\:\\:getSha256\\(\\) should return string but returns string\\|false\\.$#" + message: '#^Method pocketmine\\resourcepacks\\ZippedResourcePack\:\:getSha256\(\) should return string but returns string\|false\.$#' + identifier: return.type count: 1 path: ../../../src/resourcepacks/ZippedResourcePack.php - - message: "#^Property pocketmine\\\\resourcepacks\\\\ZippedResourcePack\\:\\:\\$fileResource \\(resource\\) does not accept resource\\|false\\.$#" + message: '#^Property pocketmine\\resourcepacks\\ZippedResourcePack\:\:\$fileResource \(resource\) does not accept resource\|false\.$#' + identifier: assign.propertyType count: 1 path: ../../../src/resourcepacks/ZippedResourcePack.php - - message: "#^Property pocketmine\\\\resourcepacks\\\\ZippedResourcePack\\:\\:\\$sha256 \\(string\\|null\\) does not accept string\\|false\\.$#" + message: '#^Property pocketmine\\resourcepacks\\ZippedResourcePack\:\:\$sha256 \(string\|null\) does not accept string\|false\.$#' + identifier: assign.propertyType count: 1 path: ../../../src/resourcepacks/ZippedResourcePack.php - - message: "#^Property pocketmine\\\\scheduler\\\\BulkCurlTask\\:\\:\\$operations \\(string\\) does not accept string\\|null\\.$#" + message: '#^Property pocketmine\\scheduler\\BulkCurlTask\:\:\$operations \(string\) does not accept string\|null\.$#' + identifier: assign.propertyType count: 1 path: ../../../src/scheduler/BulkCurlTask.php - - message: "#^Cannot call method getNextRun\\(\\) on array\\\\>\\|int\\|pocketmine\\\\scheduler\\\\TaskHandler\\\\.$#" + message: '#^Cannot call method getNextRun\(\) on array\\>\|int\|pocketmine\\scheduler\\TaskHandler\\.$#' + identifier: method.nonObject count: 1 path: ../../../src/scheduler/TaskScheduler.php - - message: "#^Cannot access offset string on mixed\\.$#" + message: '#^Cannot access offset string on mixed\.$#' + identifier: offsetAccess.nonOffsetAccessible count: 2 path: ../../../src/utils/Config.php - - message: "#^Method pocketmine\\\\utils\\\\Config\\:\\:fixYAMLIndexes\\(\\) should return string but returns string\\|null\\.$#" + message: '#^Method pocketmine\\utils\\Config\:\:fixYAMLIndexes\(\) should return string but returns string\|null\.$#' + identifier: return.type count: 1 path: ../../../src/utils/Config.php - - message: "#^Parameter \\#1 \\$config of static method pocketmine\\\\utils\\\\Config\\:\\:writeProperties\\(\\) expects array\\, array\\ given\\.$#" + message: '#^Parameter \#1 \$config of static method pocketmine\\utils\\Config\:\:writeProperties\(\) expects array\, array\ given\.$#' + identifier: argument.type count: 1 path: ../../../src/utils/Config.php - - message: "#^Parameter \\#1 \\$string of function trim expects string, string\\|false given\\.$#" + message: '#^Parameter \#1 \$string of function trim expects string, string\|false given\.$#' + identifier: argument.type count: 1 path: ../../../src/utils/Timezone.php - - message: "#^Cannot cast mixed to string\\.$#" + message: '#^Binary operation "\." between mixed and ''\-\>''\|''\:\:'' results in an error\.$#' + identifier: binaryOp.invalid count: 1 path: ../../../src/utils/Utils.php - - message: "#^Method pocketmine\\\\utils\\\\Utils\\:\\:printable\\(\\) should return string but returns string\\|null\\.$#" + message: '#^Binary operation "\." between non\-falsy\-string and mixed results in an error\.$#' + identifier: binaryOp.invalid + count: 2 + path: ../../../src/utils/Utils.php + + - + message: '#^Cannot cast mixed to string\.$#' + identifier: cast.string count: 1 path: ../../../src/utils/Utils.php - - message: "#^Parameter \\#1 \\$path of static method pocketmine\\\\utils\\\\Filesystem\\:\\:cleanPath\\(\\) expects string, mixed given\\.$#" + message: '#^Method pocketmine\\utils\\Utils\:\:printable\(\) should return string but returns string\|null\.$#' + identifier: return.type count: 1 path: ../../../src/utils/Utils.php - - message: "#^Parameter \\#2 \\$file of class pocketmine\\\\thread\\\\ThreadCrashInfoFrame constructor expects string\\|null, mixed given\\.$#" + message: '#^Parameter \#1 \$path of static method pocketmine\\utils\\Filesystem\:\:cleanPath\(\) expects string, mixed given\.$#' + identifier: argument.type count: 1 path: ../../../src/utils/Utils.php - - message: "#^Parameter \\#3 \\$line of class pocketmine\\\\thread\\\\ThreadCrashInfoFrame constructor expects int, mixed given\\.$#" + message: '#^Parameter \#2 \$file of class pocketmine\\thread\\ThreadCrashInfoFrame constructor expects string\|null, mixed given\.$#' + identifier: argument.type count: 1 path: ../../../src/utils/Utils.php - - message: "#^Parameter \\#1 \\$x of method pocketmine\\\\world\\\\World\\:\\:getTileAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#3 \$line of class pocketmine\\thread\\ThreadCrashInfoFrame constructor expects int, mixed given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/utils/Utils.php + + - + message: '#^Parameter \#1 \$x of method pocketmine\\world\\World\:\:getTileAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/world/Explosion.php - - message: "#^Parameter \\#1 \\$x of method pocketmine\\\\world\\\\World\\:\\:setBlockAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#1 \$x of method pocketmine\\world\\World\:\:setBlockAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/world/Explosion.php - - message: "#^Parameter \\#1 \\$x of static method pocketmine\\\\world\\\\World\\:\\:blockHash\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#1 \$x of static method pocketmine\\world\\World\:\:blockHash\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/world/Explosion.php - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\world\\\\World\\:\\:getTileAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#2 \$y of method pocketmine\\world\\World\:\:getTileAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/world/Explosion.php - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\world\\\\World\\:\\:setBlockAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#2 \$y of method pocketmine\\world\\World\:\:setBlockAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/world/Explosion.php - - message: "#^Parameter \\#2 \\$y of static method pocketmine\\\\world\\\\World\\:\\:blockHash\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#2 \$y of static method pocketmine\\world\\World\:\:blockHash\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/world/Explosion.php - - message: "#^Parameter \\#3 \\$z of method pocketmine\\\\world\\\\World\\:\\:getTileAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#3 \$z of method pocketmine\\world\\World\:\:getTileAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/world/Explosion.php - - message: "#^Parameter \\#3 \\$z of method pocketmine\\\\world\\\\World\\:\\:setBlockAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#3 \$z of method pocketmine\\world\\World\:\:setBlockAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/world/Explosion.php - - message: "#^Parameter \\#3 \\$z of static method pocketmine\\\\world\\\\World\\:\\:blockHash\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#3 \$z of static method pocketmine\\world\\World\:\:blockHash\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/world/Explosion.php - - message: "#^Argument of an invalid type mixed supplied for foreach, only iterables are supported\\.$#" + message: '#^Argument of an invalid type mixed supplied for foreach, only iterables are supported\.$#' + identifier: foreach.nonIterable count: 1 path: ../../../src/world/World.php - - message: "#^Cannot access offset 'data' on array\\{priority\\: int, data\\: pocketmine\\\\math\\\\Vector3\\}\\|int\\|pocketmine\\\\math\\\\Vector3\\.$#" + message: '#^Cannot access offset ''data'' on array\{priority\: int, data\: pocketmine\\math\\Vector3\}\|int\|pocketmine\\math\\Vector3\.$#' + identifier: offsetAccess.nonOffsetAccessible count: 1 path: ../../../src/world/World.php - - message: "#^Cannot access offset 'priority' on array\\{priority\\: int, data\\: pocketmine\\\\math\\\\Vector3\\}\\|int\\|pocketmine\\\\math\\\\Vector3\\.$#" + message: '#^Cannot access offset ''priority'' on array\{priority\: int, data\: pocketmine\\math\\Vector3\}\|int\|pocketmine\\math\\Vector3\.$#' + identifier: offsetAccess.nonOffsetAccessible count: 1 path: ../../../src/world/World.php - - message: "#^Cannot cast mixed to string\\.$#" + message: '#^Cannot cast mixed to string\.$#' + identifier: cast.string count: 1 path: ../../../src/world/World.php - - message: "#^Parameter \\#1 \\$x of method pocketmine\\\\world\\\\World\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#1 \$x of method pocketmine\\world\\World\:\:getBlockAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/world/World.php - - message: "#^Parameter \\#1 \\$x of method pocketmine\\\\world\\\\World\\:\\:getTileAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#1 \$x of method pocketmine\\world\\World\:\:getTileAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/world/World.php - - message: "#^Parameter \\#1 \\$x of method pocketmine\\\\world\\\\World\\:\\:isInWorld\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#1 \$x of method pocketmine\\world\\World\:\:isInWorld\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 2 path: ../../../src/world/World.php - - message: "#^Parameter \\#1 \\$x of static method pocketmine\\\\world\\\\World\\:\\:blockHash\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#1 \$x of static method pocketmine\\world\\World\:\:blockHash\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 2 path: ../../../src/world/World.php - - message: "#^Parameter \\#2 \\$x of method pocketmine\\\\block\\\\Block\\:\\:position\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#2 \$x of method pocketmine\\block\\Block\:\:position\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 2 path: ../../../src/world/World.php - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\world\\\\World\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#2 \$y of method pocketmine\\world\\World\:\:getBlockAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/world/World.php - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\world\\\\World\\:\\:getTileAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#2 \$y of method pocketmine\\world\\World\:\:getTileAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/world/World.php - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\world\\\\World\\:\\:isInWorld\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#2 \$y of method pocketmine\\world\\World\:\:isInWorld\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 2 path: ../../../src/world/World.php - - message: "#^Parameter \\#2 \\$y of static method pocketmine\\\\world\\\\World\\:\\:blockHash\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#2 \$y of static method pocketmine\\world\\World\:\:blockHash\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 2 path: ../../../src/world/World.php - - message: "#^Parameter \\#3 \\$y of method pocketmine\\\\block\\\\Block\\:\\:position\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#3 \$y of method pocketmine\\block\\Block\:\:position\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 2 path: ../../../src/world/World.php - - message: "#^Parameter \\#3 \\$z of method pocketmine\\\\world\\\\World\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#3 \$z of method pocketmine\\world\\World\:\:getBlockAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/world/World.php - - message: "#^Parameter \\#3 \\$z of method pocketmine\\\\world\\\\World\\:\\:getTileAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#3 \$z of method pocketmine\\world\\World\:\:getTileAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/world/World.php - - message: "#^Parameter \\#3 \\$z of method pocketmine\\\\world\\\\World\\:\\:isInWorld\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#3 \$z of method pocketmine\\world\\World\:\:isInWorld\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 2 path: ../../../src/world/World.php - - message: "#^Parameter \\#3 \\$z of static method pocketmine\\\\world\\\\World\\:\\:blockHash\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#3 \$z of static method pocketmine\\world\\World\:\:blockHash\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 2 path: ../../../src/world/World.php - - message: "#^Parameter \\#4 \\$z of method pocketmine\\\\block\\\\Block\\:\\:position\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#4 \$z of method pocketmine\\block\\Block\:\:position\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 2 path: ../../../src/world/World.php - - message: "#^Method pocketmine\\\\world\\\\biome\\\\BiomeRegistry\\:\\:getBiome\\(\\) should return pocketmine\\\\world\\\\biome\\\\Biome but returns pocketmine\\\\world\\\\biome\\\\Biome\\|null\\.$#" + message: '#^Method pocketmine\\world\\biome\\BiomeRegistry\:\:getBiome\(\) should return pocketmine\\world\\biome\\Biome but returns pocketmine\\world\\biome\\Biome\|null\.$#' + identifier: return.type count: 1 path: ../../../src/world/biome/BiomeRegistry.php - - message: "#^Method pocketmine\\\\world\\\\format\\\\Chunk\\:\\:getSubChunk\\(\\) should return pocketmine\\\\world\\\\format\\\\SubChunk but returns pocketmine\\\\world\\\\format\\\\SubChunk\\|null\\.$#" + message: '#^Method pocketmine\\world\\format\\Chunk\:\:getSubChunk\(\) should return pocketmine\\world\\format\\SubChunk but returns pocketmine\\world\\format\\SubChunk\|null\.$#' + identifier: return.type count: 1 path: ../../../src/world/format/Chunk.php - - message: "#^Parameter \\#1 \\$x of static method pocketmine\\\\world\\\\format\\\\Chunk\\:\\:blockHash\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#1 \$x of static method pocketmine\\world\\format\\Chunk\:\:blockHash\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 2 path: ../../../src/world/format/Chunk.php - - message: "#^Parameter \\#2 \\$y of static method pocketmine\\\\world\\\\format\\\\Chunk\\:\\:blockHash\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#2 \$y of static method pocketmine\\world\\format\\Chunk\:\:blockHash\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 2 path: ../../../src/world/format/Chunk.php - - message: "#^Parameter \\#3 \\$z of static method pocketmine\\\\world\\\\format\\\\Chunk\\:\\:blockHash\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#3 \$z of static method pocketmine\\world\\format\\Chunk\:\:blockHash\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 2 path: ../../../src/world/format/Chunk.php - - message: "#^Method pocketmine\\\\world\\\\format\\\\HeightArray\\:\\:get\\(\\) should return int but returns int\\|null\\.$#" + message: '#^Method pocketmine\\world\\format\\HeightArray\:\:get\(\) should return int but returns int\|null\.$#' + identifier: return.type count: 1 path: ../../../src/world/format/HeightArray.php - - message: "#^Only numeric types are allowed in %%, int\\<0, max\\>\\|false given on the left side\\.$#" + message: '#^Only numeric types are allowed in %%, int\<0, max\>\|false given on the left side\.$#' + identifier: mod.leftNonNumeric count: 1 path: ../../../src/world/format/io/region/RegionLoader.php - - message: "#^Parameter \\#2 \\$size of function ftruncate expects int\\<0, max\\>, int given\\.$#" + message: '#^Parameter \#2 \$size of function ftruncate expects int\<0, max\>, int given\.$#' + identifier: argument.type count: 1 path: ../../../src/world/format/io/region/RegionLoader.php - - message: "#^Argument of an invalid type array\\\\|false supplied for foreach, only iterables are supported\\.$#" - count: 1 - path: ../../../src/world/format/io/region/RegionWorldProvider.php - - - - message: "#^Cannot access offset 1 on mixed\\.$#" - count: 2 - path: ../../../src/world/format/io/region/RegionWorldProvider.php - - - - message: "#^Cannot access offset 2 on mixed\\.$#" - count: 2 - path: ../../../src/world/format/io/region/RegionWorldProvider.php - - - - message: "#^Cannot cast mixed to int\\.$#" - count: 4 - path: ../../../src/world/format/io/region/RegionWorldProvider.php - - - - message: "#^Method pocketmine\\\\world\\\\generator\\\\biome\\\\BiomeSelector\\:\\:pickBiome\\(\\) should return pocketmine\\\\world\\\\biome\\\\Biome but returns pocketmine\\\\world\\\\biome\\\\Biome\\|null\\.$#" + message: '#^Method pocketmine\\world\\generator\\biome\\BiomeSelector\:\:pickBiome\(\) should return pocketmine\\world\\biome\\Biome but returns pocketmine\\world\\biome\\Biome\|null\.$#' + identifier: return.type count: 1 path: ../../../src/world/generator/biome/BiomeSelector.php - - message: "#^Cannot call method getBiomeId\\(\\) on pocketmine\\\\world\\\\format\\\\Chunk\\|null\\.$#" + message: '#^Cannot call method getBiomeId\(\) on pocketmine\\world\\format\\Chunk\|null\.$#' + identifier: method.nonObject count: 1 path: ../../../src/world/generator/hell/Nether.php - - message: "#^Offset int does not exist on SplFixedArray\\\\|null\\.$#" - count: 4 - path: ../../../src/world/generator/noise/Noise.php - - - - message: "#^Parameter \\$q0 of static method pocketmine\\\\world\\\\generator\\\\noise\\\\Noise\\:\\:linearLerp\\(\\) expects float, float\\|null given\\.$#" + message: '#^Parameter \$q0 of static method pocketmine\\world\\generator\\noise\\Noise\:\:linearLerp\(\) expects float, float\|null given\.$#' + identifier: argument.type count: 1 path: ../../../src/world/generator/noise/Noise.php - - message: "#^Parameter \\$q1 of static method pocketmine\\\\world\\\\generator\\\\noise\\\\Noise\\:\\:linearLerp\\(\\) expects float, float\\|null given\\.$#" + message: '#^Parameter \$q1 of static method pocketmine\\world\\generator\\noise\\Noise\:\:linearLerp\(\) expects float, float\|null given\.$#' + identifier: argument.type count: 1 path: ../../../src/world/generator/noise/Noise.php - - message: "#^Cannot call method getBiomeId\\(\\) on pocketmine\\\\world\\\\format\\\\Chunk\\|null\\.$#" + message: '#^Cannot call method getBiomeId\(\) on pocketmine\\world\\format\\Chunk\|null\.$#' + identifier: method.nonObject count: 1 path: ../../../src/world/generator/normal/Normal.php - - message: "#^Parameter \\#1 \\$start of method pocketmine\\\\utils\\\\Random\\:\\:nextRange\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#1 \$start of method pocketmine\\utils\\Random\:\:nextRange\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 2 path: ../../../src/world/generator/object/TallGrass.php - - message: "#^Parameter \\#2 \\$end of method pocketmine\\\\utils\\\\Random\\:\\:nextRange\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#2 \$end of method pocketmine\\utils\\Random\:\:nextRange\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 2 path: ../../../src/world/generator/object/TallGrass.php - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\world\\\\ChunkManager\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#2 \$y of method pocketmine\\world\\ChunkManager\:\:getBlockAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 2 path: ../../../src/world/generator/object/TallGrass.php - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\world\\\\ChunkManager\\:\\:setBlockAt\\(\\) expects int, float\\|int given\\.$#" + message: '#^Parameter \#2 \$y of method pocketmine\\world\\ChunkManager\:\:setBlockAt\(\) expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: ../../../src/world/generator/object/TallGrass.php - - message: "#^Cannot call method getBlockLightArray\\(\\) on pocketmine\\\\world\\\\format\\\\SubChunk\\|null\\.$#" + message: '#^Cannot call method getBlockLightArray\(\) on pocketmine\\world\\format\\SubChunk\|null\.$#' + identifier: method.nonObject count: 1 path: ../../../src/world/light/BlockLightUpdate.php - - message: "#^Cannot call method getBlockStateId\\(\\) on pocketmine\\\\world\\\\format\\\\SubChunk\\|null\\.$#" + message: '#^Cannot call method getBlockStateId\(\) on pocketmine\\world\\format\\SubChunk\|null\.$#' + identifier: method.nonObject count: 1 path: ../../../src/world/light/BlockLightUpdate.php - - message: "#^Cannot call method getSubChunks\\(\\) on pocketmine\\\\world\\\\format\\\\Chunk\\|null\\.$#" + message: '#^Cannot call method getSubChunks\(\) on pocketmine\\world\\format\\Chunk\|null\.$#' + identifier: method.nonObject count: 1 path: ../../../src/world/light/BlockLightUpdate.php - - message: "#^Property pocketmine\\\\world\\\\light\\\\LightPopulationTask\\:\\:\\$resultBlockLightArrays \\(string\\) does not accept string\\|null\\.$#" + message: '#^Property pocketmine\\world\\light\\LightPopulationTask\:\:\$resultBlockLightArrays \(string\) does not accept string\|null\.$#' + identifier: assign.propertyType count: 1 path: ../../../src/world/light/LightPopulationTask.php - - message: "#^Property pocketmine\\\\world\\\\light\\\\LightPopulationTask\\:\\:\\$resultHeightMap \\(string\\) does not accept string\\|null\\.$#" + message: '#^Property pocketmine\\world\\light\\LightPopulationTask\:\:\$resultHeightMap \(string\) does not accept string\|null\.$#' + identifier: assign.propertyType count: 1 path: ../../../src/world/light/LightPopulationTask.php - - message: "#^Property pocketmine\\\\world\\\\light\\\\LightPopulationTask\\:\\:\\$resultSkyLightArrays \\(string\\) does not accept string\\|null\\.$#" + message: '#^Property pocketmine\\world\\light\\LightPopulationTask\:\:\$resultSkyLightArrays \(string\) does not accept string\|null\.$#' + identifier: assign.propertyType count: 1 path: ../../../src/world/light/LightPopulationTask.php - - message: "#^Cannot call method getBlockSkyLightArray\\(\\) on pocketmine\\\\world\\\\format\\\\SubChunk\\|null\\.$#" + message: '#^Cannot call method getBlockSkyLightArray\(\) on pocketmine\\world\\format\\SubChunk\|null\.$#' + identifier: method.nonObject count: 1 path: ../../../src/world/light/SkyLightUpdate.php - - message: "#^Cannot call method getBlockStateId\\(\\) on pocketmine\\\\world\\\\format\\\\SubChunk\\|null\\.$#" + message: '#^Cannot call method getBlockStateId\(\) on pocketmine\\world\\format\\SubChunk\|null\.$#' + identifier: method.nonObject count: 2 path: ../../../src/world/light/SkyLightUpdate.php - - message: "#^Cannot call method getHeightMap\\(\\) on pocketmine\\\\world\\\\format\\\\Chunk\\|null\\.$#" + message: '#^Cannot call method getHeightMap\(\) on pocketmine\\world\\format\\Chunk\|null\.$#' + identifier: method.nonObject count: 6 path: ../../../src/world/light/SkyLightUpdate.php - - message: "#^Cannot call method getHeightMapArray\\(\\) on pocketmine\\\\world\\\\format\\\\Chunk\\|null\\.$#" + message: '#^Cannot call method getHeightMapArray\(\) on pocketmine\\world\\format\\Chunk\|null\.$#' + identifier: method.nonObject count: 1 path: ../../../src/world/light/SkyLightUpdate.php - - message: "#^Cannot call method getSubChunk\\(\\) on pocketmine\\\\world\\\\format\\\\Chunk\\|null\\.$#" + message: '#^Cannot call method getSubChunk\(\) on pocketmine\\world\\format\\Chunk\|null\.$#' + identifier: method.nonObject count: 2 path: ../../../src/world/light/SkyLightUpdate.php - - message: "#^Cannot call method setHeightMap\\(\\) on pocketmine\\\\world\\\\format\\\\Chunk\\|null\\.$#" + message: '#^Cannot call method setHeightMap\(\) on pocketmine\\world\\format\\Chunk\|null\.$#' + identifier: method.nonObject count: 2 path: ../../../src/world/light/SkyLightUpdate.php - - message: "#^Cannot call method setHeightMapArray\\(\\) on pocketmine\\\\world\\\\format\\\\Chunk\\|null\\.$#" + message: '#^Cannot call method setHeightMapArray\(\) on pocketmine\\world\\format\\Chunk\|null\.$#' + identifier: method.nonObject count: 1 path: ../../../src/world/light/SkyLightUpdate.php - - message: "#^Parameter \\#1 \\$chunk of static method pocketmine\\\\world\\\\light\\\\SkyLightUpdate\\:\\:recalculateHeightMap\\(\\) expects pocketmine\\\\world\\\\format\\\\Chunk, pocketmine\\\\world\\\\format\\\\Chunk\\|null given\\.$#" + message: '#^Parameter \#1 \$chunk of static method pocketmine\\world\\light\\SkyLightUpdate\:\:recalculateHeightMap\(\) expects pocketmine\\world\\format\\Chunk, pocketmine\\world\\format\\Chunk\|null given\.$#' + identifier: argument.type count: 1 path: ../../../src/world/light/SkyLightUpdate.php - - message: "#^Parameter \\#1 \\$chunk of static method pocketmine\\\\world\\\\light\\\\SkyLightUpdate\\:\\:recalculateHeightMapColumn\\(\\) expects pocketmine\\\\world\\\\format\\\\Chunk, pocketmine\\\\world\\\\format\\\\Chunk\\|null given\\.$#" + message: '#^Parameter \#1 \$chunk of static method pocketmine\\world\\light\\SkyLightUpdate\:\:recalculateHeightMapColumn\(\) expects pocketmine\\world\\format\\Chunk, pocketmine\\world\\format\\Chunk\|null given\.$#' + identifier: argument.type count: 1 path: ../../../src/world/light/SkyLightUpdate.php - diff --git a/tests/phpstan/configs/dependency-problems.neon b/tests/phpstan/configs/dependency-problems.neon new file mode 100644 index 0000000000..dc2a491bfc --- /dev/null +++ b/tests/phpstan/configs/dependency-problems.neon @@ -0,0 +1,73 @@ +parameters: + ignoreErrors: + - + message: '#^Method pocketmine\\network\\mcpe\\convert\\BlockStateDictionary\:\:loadPaletteFromString\(\) should return list\ but returns array\\.$#' + identifier: return.type + count: 1 + path: ../../../src/network/mcpe/convert/BlockStateDictionary.php + + - + message: '#^Parameter \#3 \$entityNBT of class pocketmine\\world\\format\\io\\ChunkData constructor expects list\, array\ given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/world/format/io/leveldb/LevelDB.php + + - + message: '#^Parameter \#4 \$tileNBT of class pocketmine\\world\\format\\io\\ChunkData constructor expects list\, array\ given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/world/format/io/leveldb/LevelDB.php + + - + message: '#^Parameter \#1 \$array of static method pocketmine\\world\\format\\io\\ChunkUtils\:\:convertBiomeColors\(\) expects list\, array\ given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/world/format/io/region/Anvil.php + + - + message: '#^Parameter \#1 \$array of static method pocketmine\\world\\format\\io\\ChunkUtils\:\:convertBiomeColors\(\) expects list\, array\ given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/world/format/io/region/McRegion.php + + - + message: '#^Parameter \#1 \$array of static method pocketmine\\world\\format\\io\\ChunkUtils\:\:convertBiomeColors\(\) expects list\, array\ given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/world/format/io/region/PMAnvil.php + + - + message: '#^Parameter \#1 \$oldNewStateList of function pocketmine\\tools\\blockstate_upgrade_schema_utils\\buildUpgradeTableFromData expects list\, array\ given\.$#' + identifier: argument.type + count: 1 + path: ../../../tools/blockstate-upgrade-schema-utils.php + + - + message: '#^Parameter \#1 \$input of class pocketmine\\crafting\\json\\ShapelessRecipeData constructor expects list\, array\ given\.$#' + identifier: argument.type + count: 1 + path: ../../../tools/generate-bedrock-data-from-packets.php + + - + message: '#^Parameter \#2 \$output of class pocketmine\\crafting\\json\\ShapelessRecipeData constructor expects list\, array\ given\.$#' + identifier: argument.type + count: 1 + path: ../../../tools/generate-bedrock-data-from-packets.php + + - + message: '#^Parameter \#3 \$output of class pocketmine\\crafting\\json\\ShapedRecipeData constructor expects list\, array\ given\.$#' + identifier: argument.type + count: 1 + path: ../../../tools/generate-bedrock-data-from-packets.php + + - + message: '#^Parameter \#5 \$unlockingIngredients of class pocketmine\\crafting\\json\\ShapelessRecipeData constructor expects list\, array\ given\.$#' + identifier: argument.type + count: 1 + path: ../../../tools/generate-bedrock-data-from-packets.php + + - + message: '#^Parameter \#6 \$unlockingIngredients of class pocketmine\\crafting\\json\\ShapedRecipeData constructor expects list\, array\ given\.$#' + identifier: argument.type + count: 1 + path: ../../../tools/generate-bedrock-data-from-packets.php diff --git a/tests/phpstan/configs/impossible-generics.neon b/tests/phpstan/configs/impossible-generics.neon index b0e67d294b..e0b944e695 100644 --- a/tests/phpstan/configs/impossible-generics.neon +++ b/tests/phpstan/configs/impossible-generics.neon @@ -1,12 +1,14 @@ parameters: ignoreErrors: - - message: "#^Method pocketmine\\\\event\\\\RegisteredListener\\:\\:__construct\\(\\) has parameter \\$handler with no signature specified for Closure\\.$#" + message: '#^Method pocketmine\\event\\RegisteredListener\:\:__construct\(\) has parameter \$handler with no signature specified for Closure\.$#' + identifier: missingType.callable count: 1 path: ../../../src/event/RegisteredListener.php - - message: "#^Method pocketmine\\\\event\\\\RegisteredListener\\:\\:getHandler\\(\\) return type has no signature specified for Closure\\.$#" + message: '#^Method pocketmine\\event\\RegisteredListener\:\:getHandler\(\) return type has no signature specified for Closure\.$#' + identifier: missingType.callable count: 1 path: ../../../src/event/RegisteredListener.php diff --git a/tests/phpstan/configs/phpstan-bugs.neon b/tests/phpstan/configs/phpstan-bugs.neon index 0ee2b68a01..7e3484bc59 100644 --- a/tests/phpstan/configs/phpstan-bugs.neon +++ b/tests/phpstan/configs/phpstan-bugs.neon @@ -1,112 +1,260 @@ parameters: ignoreErrors: - - message: "#^Method pocketmine\\\\block\\\\DoubleTallGrass\\:\\:traitGetDropsForIncompatibleTool\\(\\) return type has no value type specified in iterable type array\\.$#" + message: '#^Access to an undefined property object\:\:\$crashId\.$#' + identifier: property.notFound + count: 1 + path: ../../../src/Server.php + + - + message: '#^Access to an undefined property object\:\:\$crashUrl\.$#' + identifier: property.notFound + count: 1 + path: ../../../src/Server.php + + - + message: '#^Access to an undefined property object\:\:\$error\.$#' + identifier: property.notFound + count: 1 + path: ../../../src/Server.php + + - + message: '#^Method pocketmine\\block\\Block\:\:readStateFromWorld\(\) is marked as impure but does not have any side effects\.$#' + identifier: impureMethod.pure + count: 1 + path: ../../../src/block/Block.php + + - + message: '#^Method pocketmine\\block\\DoubleTallGrass\:\:traitGetDropsForIncompatibleTool\(\) return type has no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue count: 1 path: ../../../src/block/DoubleTallGrass.php - - message: "#^Creating callable from a non\\-native static method pocketmine\\\\item\\\\VanillaItems\\:\\:ACACIA_SIGN\\(\\)\\.$#" + message: '#^Creating callable from a non\-native static method pocketmine\\item\\VanillaItems\:\:ACACIA_SIGN\(\)\.$#' + identifier: callable.nonNativeMethod count: 1 path: ../../../src/block/VanillaBlocks.php - - message: "#^Creating callable from a non\\-native static method pocketmine\\\\item\\\\VanillaItems\\:\\:BIRCH_SIGN\\(\\)\\.$#" + message: '#^Creating callable from a non\-native static method pocketmine\\item\\VanillaItems\:\:BIRCH_SIGN\(\)\.$#' + identifier: callable.nonNativeMethod count: 1 path: ../../../src/block/VanillaBlocks.php - - message: "#^Creating callable from a non\\-native static method pocketmine\\\\item\\\\VanillaItems\\:\\:CHERRY_SIGN\\(\\)\\.$#" + message: '#^Creating callable from a non\-native static method pocketmine\\item\\VanillaItems\:\:CHERRY_SIGN\(\)\.$#' + identifier: callable.nonNativeMethod count: 1 path: ../../../src/block/VanillaBlocks.php - - message: "#^Creating callable from a non\\-native static method pocketmine\\\\item\\\\VanillaItems\\:\\:CRIMSON_SIGN\\(\\)\\.$#" + message: '#^Creating callable from a non\-native static method pocketmine\\item\\VanillaItems\:\:CRIMSON_SIGN\(\)\.$#' + identifier: callable.nonNativeMethod count: 1 path: ../../../src/block/VanillaBlocks.php - - message: "#^Creating callable from a non\\-native static method pocketmine\\\\item\\\\VanillaItems\\:\\:DARK_OAK_SIGN\\(\\)\\.$#" + message: '#^Creating callable from a non\-native static method pocketmine\\item\\VanillaItems\:\:DARK_OAK_SIGN\(\)\.$#' + identifier: callable.nonNativeMethod count: 1 path: ../../../src/block/VanillaBlocks.php - - message: "#^Creating callable from a non\\-native static method pocketmine\\\\item\\\\VanillaItems\\:\\:JUNGLE_SIGN\\(\\)\\.$#" + message: '#^Creating callable from a non\-native static method pocketmine\\item\\VanillaItems\:\:JUNGLE_SIGN\(\)\.$#' + identifier: callable.nonNativeMethod count: 1 path: ../../../src/block/VanillaBlocks.php - - message: "#^Creating callable from a non\\-native static method pocketmine\\\\item\\\\VanillaItems\\:\\:MANGROVE_SIGN\\(\\)\\.$#" + message: '#^Creating callable from a non\-native static method pocketmine\\item\\VanillaItems\:\:MANGROVE_SIGN\(\)\.$#' + identifier: callable.nonNativeMethod count: 1 path: ../../../src/block/VanillaBlocks.php - - message: "#^Creating callable from a non\\-native static method pocketmine\\\\item\\\\VanillaItems\\:\\:OAK_SIGN\\(\\)\\.$#" + message: '#^Creating callable from a non\-native static method pocketmine\\item\\VanillaItems\:\:OAK_SIGN\(\)\.$#' + identifier: callable.nonNativeMethod count: 1 path: ../../../src/block/VanillaBlocks.php - - message: "#^Creating callable from a non\\-native static method pocketmine\\\\item\\\\VanillaItems\\:\\:PALE_OAK_SIGN\\(\\)\\.$#" + message: '#^Creating callable from a non\-native static method pocketmine\\item\\VanillaItems\:\:PALE_OAK_SIGN\(\)\.$#' + identifier: callable.nonNativeMethod count: 1 path: ../../../src/block/VanillaBlocks.php - - message: "#^Creating callable from a non\\-native static method pocketmine\\\\item\\\\VanillaItems\\:\\:SPRUCE_SIGN\\(\\)\\.$#" + message: '#^Creating callable from a non\-native static method pocketmine\\item\\VanillaItems\:\:SPRUCE_SIGN\(\)\.$#' + identifier: callable.nonNativeMethod count: 1 path: ../../../src/block/VanillaBlocks.php - - message: "#^Creating callable from a non\\-native static method pocketmine\\\\item\\\\VanillaItems\\:\\:WARPED_SIGN\\(\\)\\.$#" + message: '#^Creating callable from a non\-native static method pocketmine\\item\\VanillaItems\:\:WARPED_SIGN\(\)\.$#' + identifier: callable.nonNativeMethod count: 1 path: ../../../src/block/VanillaBlocks.php - - message: "#^Call to function assert\\(\\) with false and 'unknown hit type' will always evaluate to false\\.$#" + message: '#^Strict comparison using \=\=\= between \*NEVER\* and 5 will always evaluate to false\.$#' + identifier: identical.alwaysFalse + count: 1 + path: ../../../src/command/defaults/TeleportCommand.php + + - + message: '#^Method pocketmine\\crafting\\ShapedRecipe\:\:getIngredientMap\(\) should return list\\> but returns array\, non\-empty\-array\, pocketmine\\crafting\\RecipeIngredient\|null\>\>\.$#' + identifier: return.type + count: 1 + path: ../../../src/crafting/ShapedRecipe.php + + - + message: '#^Property pocketmine\\crash\\CrashDumpData\:\:\$parameters \(list\\) does not accept array\.$#' + identifier: assign.propertyType + count: 1 + path: ../../../src/crash/CrashDump.php + + - + message: '#^Call to function assert\(\) with false and ''unknown hit type'' will always evaluate to false\.$#' + identifier: function.impossibleType count: 1 path: ../../../src/entity/projectile/Projectile.php - - message: "#^Property pocketmine\\\\network\\\\mcpe\\\\raklib\\\\PthreadsChannelWriter\\:\\:\\$buffer is never read, only written\\.$#" + message: '#^Property pocketmine\\item\\WritableBookBase\:\:\$pages \(list\\) does not accept non\-empty\-array\\.$#' + identifier: assign.propertyType + count: 1 + path: ../../../src/item/WritableBookBase.php + + - + message: '#^Method pocketmine\\network\\mcpe\\compression\\ZlibCompressor\:\:getNetworkId\(\) never returns 1 so it can be removed from the return type\.$#' + identifier: return.unusedType + count: 1 + path: ../../../src/network/mcpe/compression/ZlibCompressor.php + + - + message: '#^Method pocketmine\\network\\mcpe\\compression\\ZlibCompressor\:\:getNetworkId\(\) never returns 255 so it can be removed from the return type\.$#' + identifier: return.unusedType + count: 1 + path: ../../../src/network/mcpe/compression/ZlibCompressor.php + + - + message: '#^Parameter \#1 \$states of class pocketmine\\network\\mcpe\\convert\\BlockStateDictionary constructor expects list\, array\, pocketmine\\network\\mcpe\\convert\\BlockStateDictionaryEntry\> given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/network/mcpe/convert/BlockStateDictionary.php + + - + message: '#^Cannot access offset ''default'' on mixed\.$#' + identifier: offsetAccess.nonOffsetAccessible + count: 1 + path: ../../../src/network/mcpe/convert/LegacySkinAdapter.php + + - + message: '#^Property pocketmine\\network\\mcpe\\raklib\\PthreadsChannelWriter\:\:\$buffer is never read, only written\.$#' + identifier: property.onlyWritten count: 1 path: ../../../src/network/mcpe/raklib/PthreadsChannelWriter.php - - message: "#^Property pocketmine\\\\network\\\\mcpe\\\\raklib\\\\SnoozeAwarePthreadsChannelWriter\\:\\:\\$buffer is never read, only written\\.$#" + message: '#^Property pocketmine\\network\\mcpe\\raklib\\SnoozeAwarePthreadsChannelWriter\:\:\$buffer is never read, only written\.$#' + identifier: property.onlyWritten count: 1 path: ../../../src/network/mcpe/raklib/SnoozeAwarePthreadsChannelWriter.php - - message: "#^Dead catch \\- RuntimeException is never thrown in the try block\\.$#" + message: '#^Dead catch \- RuntimeException is never thrown in the try block\.$#' + identifier: catch.neverThrown count: 1 path: ../../../src/plugin/PluginManager.php - - message: "#^Method pocketmine\\\\timings\\\\TimingsHandler\\:\\:lazyGetSet\\(\\) should return pocketmine\\\\utils\\\\ObjectSet\\ but returns pocketmine\\\\utils\\\\ObjectSet\\\\.$#" + message: '#^Binary operation "\." between mixed and ''/''\|''\\\\'' results in an error\.$#' + identifier: binaryOp.invalid + count: 1 + path: ../../../src/thread/ThreadSafeClassLoader.php + + - + message: '#^Binary operation "\." between mixed and non\-falsy\-string results in an error\.$#' + identifier: binaryOp.invalid + count: 1 + path: ../../../src/thread/ThreadSafeClassLoader.php + + - + message: '#^Method pocketmine\\timings\\TimingsHandler\:\:lazyGetSet\(\) should return pocketmine\\utils\\ObjectSet\ but returns pocketmine\\utils\\ObjectSet\\.$#' + identifier: return.type + count: 1 + path: ../../../src/timings/TimingsHandler.php + + - + message: '#^Parameter &\$where @param\-out type of method pocketmine\\timings\\TimingsHandler\:\:lazyGetSet\(\) expects pocketmine\\utils\\ObjectSet\, pocketmine\\utils\\ObjectSet\ given\.$#' + identifier: paramOut.type count: 1 path: ../../../src/timings/TimingsHandler.php - - message: "#^Casting to int something that's already int\\.$#" + message: '#^Binary operation "\*" between mixed and 3600 results in an error\.$#' + identifier: binaryOp.invalid + count: 1 + path: ../../../src/utils/Timezone.php + + - + message: '#^Binary operation "\*" between mixed and 60 results in an error\.$#' + identifier: binaryOp.invalid + count: 1 + path: ../../../src/utils/Timezone.php + + - + message: '#^Binary operation "\+" between \(float\|int\) and mixed results in an error\.$#' + identifier: binaryOp.invalid + count: 1 + path: ../../../src/utils/Timezone.php + + - + message: '#^Property pocketmine\\world\\format\\io\\region\\RegionLoader\:\:\$locationTable \(list\\) does not accept non\-empty\-array\\.$#' + identifier: assign.propertyType + count: 2 + path: ../../../src/world/format/io/region/RegionLoader.php + + - + message: '#^Property pocketmine\\world\\format\\io\\region\\RegionLoader\:\:\$locationTable \(list\\) does not accept non\-empty\-array\, pocketmine\\world\\format\\io\\region\\RegionLocationTableEntry\|null\>\.$#' + identifier: assign.propertyType + count: 3 + path: ../../../src/world/format/io/region/RegionLoader.php + + - + message: '#^Method pocketmine\\world\\format\\io\\region\\RegionWorldProvider\:\:createRegionIterator\(\) should return RegexIterator\ but returns RegexIterator\\>\.$#' + identifier: return.type + count: 1 + path: ../../../src/world/format/io/region/RegionWorldProvider.php + + - + message: '#^Casting to int something that''s already int\.$#' + identifier: cast.useless count: 1 path: ../../../src/world/generator/normal/Normal.php - - message: "#^Call to static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertFalse\\(\\) with false will always evaluate to true\\.$#" + message: '#^Call to static method PHPUnit\\Framework\\Assert\:\:assertFalse\(\) with false will always evaluate to true\.$#' + identifier: staticMethod.alreadyNarrowedType count: 1 path: ../../phpunit/promise/PromiseTest.php - - message: "#^Call to static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertTrue\\(\\) with false and 'All promise should…' will always evaluate to false\\.$#" + message: '#^Call to static method PHPUnit\\Framework\\Assert\:\:assertTrue\(\) with false and ''All promise should…'' will always evaluate to false\.$#' + identifier: staticMethod.impossibleType count: 1 path: ../../phpunit/promise/PromiseTest.php - - message: "#^Call to static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertTrue\\(\\) with false will always evaluate to false\\.$#" + message: '#^Call to static method PHPUnit\\Framework\\Assert\:\:assertTrue\(\) with false will always evaluate to false\.$#' + identifier: staticMethod.impossibleType count: 2 path: ../../phpunit/promise/PromiseTest.php - - message: "#^Strict comparison using \\=\\=\\= between 0 and 0 will always evaluate to true\\.$#" + message: '#^Strict comparison using \=\=\= between 0 and 0 will always evaluate to true\.$#' + identifier: identical.alwaysTrue count: 1 path: ../rules/UnsafeForeachArrayOfStringRule.php diff --git a/tests/phpstan/configs/spl-fixed-array-sucks.neon b/tests/phpstan/configs/spl-fixed-array-sucks.neon index 7c2b2b91a5..05524fb8ca 100644 --- a/tests/phpstan/configs/spl-fixed-array-sucks.neon +++ b/tests/phpstan/configs/spl-fixed-array-sucks.neon @@ -1,22 +1,32 @@ parameters: ignoreErrors: - - message: "#^Cannot call method collectGarbage\\(\\) on pocketmine\\\\world\\\\format\\\\SubChunk\\|null\\.$#" + message: '#^Cannot call method collectGarbage\(\) on pocketmine\\world\\format\\SubChunk\|null\.$#' + identifier: method.nonObject count: 1 path: ../../../src/world/format/Chunk.php - - message: "#^Method pocketmine\\\\world\\\\format\\\\Chunk\\:\\:getSubChunks\\(\\) should return array\\ but returns array\\\\.$#" + message: '#^Method pocketmine\\world\\format\\Chunk\:\:getSubChunks\(\) should return array\ but returns array\\.$#' + identifier: return.type count: 1 path: ../../../src/world/format/Chunk.php - - message: "#^Parameter \\#1 \\$callback of function array_map expects \\(callable\\(pocketmine\\\\world\\\\format\\\\SubChunk\\|null\\)\\: mixed\\)\\|null, Closure\\(pocketmine\\\\world\\\\format\\\\SubChunk\\)\\: pocketmine\\\\world\\\\format\\\\SubChunk given\\.$#" + message: '#^Parameter \#1 \$callback of function array_map expects \(callable\(pocketmine\\world\\format\\SubChunk\|null\)\: mixed\)\|null, Closure\(pocketmine\\world\\format\\SubChunk\)\: pocketmine\\world\\format\\SubChunk given\.$#' + identifier: argument.type count: 1 path: ../../../src/world/format/Chunk.php - - message: "#^Method pocketmine\\\\world\\\\format\\\\HeightArray\\:\\:getValues\\(\\) should return non\\-empty\\-array\\ but returns array\\\\.$#" + message: '#^Method pocketmine\\world\\format\\HeightArray\:\:getValues\(\) should return non\-empty\-list\ but returns array\\.$#' + identifier: return.type count: 1 path: ../../../src/world/format/HeightArray.php + - + message: '#^Offset int might not exist on SplFixedArray\\|null\.$#' + identifier: offsetAccess.notFound + count: 4 + path: ../../../src/world/generator/noise/Noise.php + diff --git a/tests/phpstan/rules/DeprecatedLegacyEnumAccessRule.php b/tests/phpstan/rules/DeprecatedLegacyEnumAccessRule.php index 4fa7670224..5753bb6280 100644 --- a/tests/phpstan/rules/DeprecatedLegacyEnumAccessRule.php +++ b/tests/phpstan/rules/DeprecatedLegacyEnumAccessRule.php @@ -28,7 +28,6 @@ use PHPStan\Analyser\Scope; use PHPStan\Rules\Rule; use PHPStan\Rules\RuleErrorBuilder; -use PHPStan\Type\TypeWithClassName; use pocketmine\utils\LegacyEnumShimTrait; use function sprintf; @@ -51,18 +50,15 @@ public function processNode(Node $node, Scope $scope) : array{ $scope->resolveTypeByName($node->class) : $scope->getType($node->class); - if(!$classType instanceof TypeWithClassName){ - return []; - } - - $reflection = $classType->getClassReflection(); - if($reflection === null || !$reflection->hasTraitUse(LegacyEnumShimTrait::class) || !$reflection->implementsInterface(\UnitEnum::class)){ - return []; - } + $errors = []; + $reflections = $classType->getObjectClassReflections(); + foreach($reflections as $reflection){ + if(!$reflection->hasTraitUse(LegacyEnumShimTrait::class) || !$reflection->implementsInterface(\UnitEnum::class)){ + continue; + } - if(!$reflection->hasNativeMethod($caseName)){ - return [ - RuleErrorBuilder::message(sprintf( + if(!$reflection->hasNativeMethod($caseName)){ + $errors[] = RuleErrorBuilder::message(sprintf( 'Use of legacy enum case accessor %s::%s().', $reflection->getName(), $caseName @@ -70,10 +66,11 @@ public function processNode(Node $node, Scope $scope) : array{ 'Access the enum constant directly instead (remove the brackets), e.g. %s::%s', $reflection->getName(), $caseName - ))->build() - ]; + ))->identifier('pocketmine.enum.deprecatedAccessor') + ->build(); + } } - return []; + return $errors; } } diff --git a/tests/phpstan/rules/DisallowEnumComparisonRule.php b/tests/phpstan/rules/DisallowEnumComparisonRule.php index fc5377173a..d73cc3972a 100644 --- a/tests/phpstan/rules/DisallowEnumComparisonRule.php +++ b/tests/phpstan/rules/DisallowEnumComparisonRule.php @@ -30,7 +30,6 @@ use PHPStan\Analyser\Scope; use PHPStan\Rules\Rule; use PHPStan\Rules\RuleErrorBuilder; -use PHPStan\Type\ObjectType; use PHPStan\Type\Type; use PHPStan\Type\UnionType; use PHPStan\Type\VerbosityLevel; @@ -61,7 +60,7 @@ public function processNode(Node $node, Scope $scope) : array{ $node instanceof Identical ? '===' : '!==', $leftType->describe(VerbosityLevel::value()), $rightType->describe(VerbosityLevel::value()) - ))->build()]; + ))->identifier('pocketmine.enum.badComparison')->build()]; } return []; } @@ -69,7 +68,7 @@ public function processNode(Node $node, Scope $scope) : array{ private function checkForEnumTypes(Type $comparedType) : bool{ //TODO: what we really want to do here is iterate over the contained types, but there's no universal way to //do that. This might break with other circumstances. - if($comparedType instanceof ObjectType){ + if($comparedType->isObject()->yes()){ $types = [$comparedType]; }elseif($comparedType instanceof UnionType){ $types = $comparedType->getTypes(); @@ -77,12 +76,14 @@ private function checkForEnumTypes(Type $comparedType) : bool{ return false; } foreach($types as $containedType){ - if(!($containedType instanceof ObjectType)){ + if(!($containedType->isObject()->yes())){ continue; } - $class = $containedType->getClassReflection(); - if($class !== null && $class->hasTraitUse(EnumTrait::class)){ - return true; + $classes = $containedType->getObjectClassReflections(); + foreach($classes as $class){ + if($class->hasTraitUse(EnumTrait::class)){ + return true; + } } } return false; diff --git a/tests/phpstan/rules/DisallowForeachByReferenceRule.php b/tests/phpstan/rules/DisallowForeachByReferenceRule.php index 79124d3283..eb65897057 100644 --- a/tests/phpstan/rules/DisallowForeachByReferenceRule.php +++ b/tests/phpstan/rules/DisallowForeachByReferenceRule.php @@ -44,6 +44,7 @@ public function processNode(Node $node, Scope $scope) : array{ return [ RuleErrorBuilder::message("Foreach by-reference is not allowed, because it has surprising behaviour.") ->tip("If the value variable is used outside of the foreach construct (e.g. in a second foreach), the iterable's contents will be unexpectedly altered.") + ->identifier('pocketmine.foreach.byRef') ->build() ]; } diff --git a/tests/phpstan/rules/UnsafeForeachArrayOfStringRule.php b/tests/phpstan/rules/UnsafeForeachArrayOfStringRule.php index 745cf2109d..34056131b5 100644 --- a/tests/phpstan/rules/UnsafeForeachArrayOfStringRule.php +++ b/tests/phpstan/rules/UnsafeForeachArrayOfStringRule.php @@ -101,7 +101,7 @@ public function processNode(Node $node, Scope $scope) : array{ RuleErrorBuilder::message(sprintf( "Unsafe foreach on array with key type %s (they might be casted to int).", $iterableType->getIterableKeyType()->describe(VerbosityLevel::value()) - ))->tip($tip)->build() + ))->tip($tip)->identifier('pocketmine.foreach.stringKeys')->build() ]; } return []; diff --git a/tests/phpunit/utils/fixtures/TestTrait.php b/tests/phpunit/utils/fixtures/TestTrait.php index bc32c0cff6..3e749c0b1d 100644 --- a/tests/phpunit/utils/fixtures/TestTrait.php +++ b/tests/phpunit/utils/fixtures/TestTrait.php @@ -23,6 +23,6 @@ namespace pocketmine\utils\fixtures; -trait TestTrait{ +trait TestTrait{ // @phpstan-ignore trait.unused } From 794641c0f80eba3bd1670e70503f1cc5e0fc18ab Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 7 Jan 2025 22:35:19 +0000 Subject: [PATCH 10/19] Utils: split some horrifying code across multiple lines --- src/utils/Utils.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/utils/Utils.php b/src/utils/Utils.php index f557562c99..b1f7e2842c 100644 --- a/src/utils/Utils.php +++ b/src/utils/Utils.php @@ -469,7 +469,15 @@ public static function printableTrace(array $trace, int $maxStringLength = 80) : } $params = implode(", ", $paramsList); } - $messages[] = "#$i " . (isset($trace[$i]["file"]) ? Filesystem::cleanPath($trace[$i]["file"]) : "") . "(" . (isset($trace[$i]["line"]) ? $trace[$i]["line"] : "") . "): " . (isset($trace[$i]["class"]) ? $trace[$i]["class"] . (($trace[$i]["type"] === "dynamic" || $trace[$i]["type"] === "->") ? "->" : "::") : "") . $trace[$i]["function"] . "(" . Utils::printable($params) . ")"; + $messages[] = "#$i " . + (isset($trace[$i]["file"]) ? Filesystem::cleanPath($trace[$i]["file"]) : "") . + "(" . (isset($trace[$i]["line"]) ? $trace[$i]["line"] : "") . "): " . + (isset($trace[$i]["class"]) ? + $trace[$i]["class"] . (($trace[$i]["type"] === "dynamic" || $trace[$i]["type"] === "->") ? "->" : "::") : + "" + ) . + $trace[$i]["function"] . + "(" . Utils::printable($params) . ")"; } return $messages; } From 689a7996b96869bdab6555b58a9e77b253d1a591 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 7 Jan 2025 22:51:38 +0000 Subject: [PATCH 11/19] Update NBT dependency --- composer.lock | 16 +++++----- .../phpstan/configs/dependency-problems.neon | 30 ------------------- 2 files changed, 8 insertions(+), 38 deletions(-) diff --git a/composer.lock b/composer.lock index 8df6c329dd..25c42d2971 100644 --- a/composer.lock +++ b/composer.lock @@ -576,16 +576,16 @@ }, { "name": "pocketmine/nbt", - "version": "1.0.0", + "version": "1.0.1", "source": { "type": "git", "url": "https://github.com/pmmp/NBT.git", - "reference": "20540271cb59e04672cb163dca73366f207974f1" + "reference": "53db37487bc5ddbfbd84247966e1a073bdcfdb7d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/NBT/zipball/20540271cb59e04672cb163dca73366f207974f1", - "reference": "20540271cb59e04672cb163dca73366f207974f1", + "url": "https://api.github.com/repos/pmmp/NBT/zipball/53db37487bc5ddbfbd84247966e1a073bdcfdb7d", + "reference": "53db37487bc5ddbfbd84247966e1a073bdcfdb7d", "shasum": "" }, "require": { @@ -595,8 +595,8 @@ }, "require-dev": { "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "1.10.25", - "phpstan/phpstan-strict-rules": "^1.0", + "phpstan/phpstan": "2.1.0", + "phpstan/phpstan-strict-rules": "^2.0", "phpunit/phpunit": "^9.5" }, "type": "library", @@ -612,9 +612,9 @@ "description": "PHP library for working with Named Binary Tags", "support": { "issues": "https://github.com/pmmp/NBT/issues", - "source": "https://github.com/pmmp/NBT/tree/1.0.0" + "source": "https://github.com/pmmp/NBT/tree/1.0.1" }, - "time": "2023-07-14T13:01:49+00:00" + "time": "2025-01-07T22:47:46+00:00" }, { "name": "pocketmine/raklib", diff --git a/tests/phpstan/configs/dependency-problems.neon b/tests/phpstan/configs/dependency-problems.neon index dc2a491bfc..c1c0fceea0 100644 --- a/tests/phpstan/configs/dependency-problems.neon +++ b/tests/phpstan/configs/dependency-problems.neon @@ -1,11 +1,5 @@ parameters: ignoreErrors: - - - message: '#^Method pocketmine\\network\\mcpe\\convert\\BlockStateDictionary\:\:loadPaletteFromString\(\) should return list\ but returns array\\.$#' - identifier: return.type - count: 1 - path: ../../../src/network/mcpe/convert/BlockStateDictionary.php - - message: '#^Parameter \#3 \$entityNBT of class pocketmine\\world\\format\\io\\ChunkData constructor expects list\, array\ given\.$#' identifier: argument.type @@ -18,30 +12,6 @@ parameters: count: 1 path: ../../../src/world/format/io/leveldb/LevelDB.php - - - message: '#^Parameter \#1 \$array of static method pocketmine\\world\\format\\io\\ChunkUtils\:\:convertBiomeColors\(\) expects list\, array\ given\.$#' - identifier: argument.type - count: 1 - path: ../../../src/world/format/io/region/Anvil.php - - - - message: '#^Parameter \#1 \$array of static method pocketmine\\world\\format\\io\\ChunkUtils\:\:convertBiomeColors\(\) expects list\, array\ given\.$#' - identifier: argument.type - count: 1 - path: ../../../src/world/format/io/region/McRegion.php - - - - message: '#^Parameter \#1 \$array of static method pocketmine\\world\\format\\io\\ChunkUtils\:\:convertBiomeColors\(\) expects list\, array\ given\.$#' - identifier: argument.type - count: 1 - path: ../../../src/world/format/io/region/PMAnvil.php - - - - message: '#^Parameter \#1 \$oldNewStateList of function pocketmine\\tools\\blockstate_upgrade_schema_utils\\buildUpgradeTableFromData expects list\, array\ given\.$#' - identifier: argument.type - count: 1 - path: ../../../tools/blockstate-upgrade-schema-utils.php - - message: '#^Parameter \#1 \$input of class pocketmine\\crafting\\json\\ShapelessRecipeData constructor expects list\, array\ given\.$#' identifier: argument.type From e8c4b743b5e62554fd0e728d14d0c8817ee6099e Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 7 Jan 2025 22:54:10 +0000 Subject: [PATCH 12/19] LevelDB: stop overriding types from NBT NBT has better quality type info already --- src/world/format/io/leveldb/LevelDB.php | 2 -- tests/phpstan/configs/dependency-problems.neon | 12 ------------ 2 files changed, 14 deletions(-) diff --git a/src/world/format/io/leveldb/LevelDB.php b/src/world/format/io/leveldb/LevelDB.php index dda489d317..41c4778670 100644 --- a/src/world/format/io/leveldb/LevelDB.php +++ b/src/world/format/io/leveldb/LevelDB.php @@ -711,7 +711,6 @@ public function loadChunk(int $chunkX, int $chunkZ) : ?LoadedChunkData{ $nbt = new LittleEndianNbtSerializer(); - /** @var CompoundTag[] $entities */ $entities = []; if(($entityData = $this->db->get($index . ChunkDataKey::ENTITIES)) !== false && $entityData !== ""){ try{ @@ -721,7 +720,6 @@ public function loadChunk(int $chunkX, int $chunkZ) : ?LoadedChunkData{ } } - /** @var CompoundTag[] $tiles */ $tiles = []; if(($tileData = $this->db->get($index . ChunkDataKey::BLOCK_ENTITIES)) !== false && $tileData !== ""){ try{ diff --git a/tests/phpstan/configs/dependency-problems.neon b/tests/phpstan/configs/dependency-problems.neon index c1c0fceea0..e95fcd79c2 100644 --- a/tests/phpstan/configs/dependency-problems.neon +++ b/tests/phpstan/configs/dependency-problems.neon @@ -1,17 +1,5 @@ parameters: ignoreErrors: - - - message: '#^Parameter \#3 \$entityNBT of class pocketmine\\world\\format\\io\\ChunkData constructor expects list\, array\ given\.$#' - identifier: argument.type - count: 1 - path: ../../../src/world/format/io/leveldb/LevelDB.php - - - - message: '#^Parameter \#4 \$tileNBT of class pocketmine\\world\\format\\io\\ChunkData constructor expects list\, array\ given\.$#' - identifier: argument.type - count: 1 - path: ../../../src/world/format/io/leveldb/LevelDB.php - - message: '#^Parameter \#1 \$input of class pocketmine\\crafting\\json\\ShapelessRecipeData constructor expects list\, array\ given\.$#' identifier: argument.type From e34f34f9f42aa3aaf0b145291a75e8cc4b6c879f Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 7 Jan 2025 23:09:28 +0000 Subject: [PATCH 13/19] Update BedrockProtocol dependency --- composer.lock | 20 ++++++------ phpstan.neon.dist | 1 - .../phpstan/configs/dependency-problems.neon | 31 ------------------- tests/phpstan/configs/phpstan-bugs.neon | 6 ++++ 4 files changed, 16 insertions(+), 42 deletions(-) delete mode 100644 tests/phpstan/configs/dependency-problems.neon diff --git a/composer.lock b/composer.lock index 25c42d2971..d59c107271 100644 --- a/composer.lock +++ b/composer.lock @@ -256,16 +256,16 @@ }, { "name": "pocketmine/bedrock-protocol", - "version": "35.0.0+bedrock-1.21.50", + "version": "35.0.3+bedrock-1.21.50", "source": { "type": "git", "url": "https://github.com/pmmp/BedrockProtocol.git", - "reference": "bd1ec79bae8c88aa984e1c5f0c3313be5ae9b435" + "reference": "c4d62581cb62d29ec426914c6b4d7e0ff835da9c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/bd1ec79bae8c88aa984e1c5f0c3313be5ae9b435", - "reference": "bd1ec79bae8c88aa984e1c5f0c3313be5ae9b435", + "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/c4d62581cb62d29ec426914c6b4d7e0ff835da9c", + "reference": "c4d62581cb62d29ec426914c6b4d7e0ff835da9c", "shasum": "" }, "require": { @@ -278,10 +278,10 @@ "ramsey/uuid": "^4.1" }, "require-dev": { - "phpstan/phpstan": "1.11.9", - "phpstan/phpstan-phpunit": "^1.0.0", - "phpstan/phpstan-strict-rules": "^1.0.0", - "phpunit/phpunit": "^9.5 || ^10.0" + "phpstan/phpstan": "2.1.0", + "phpstan/phpstan-phpunit": "^2.0.0", + "phpstan/phpstan-strict-rules": "^2.0.0", + "phpunit/phpunit": "^9.5 || ^10.0 || ^11.0" }, "type": "library", "autoload": { @@ -296,9 +296,9 @@ "description": "An implementation of the Minecraft: Bedrock Edition protocol in PHP", "support": { "issues": "https://github.com/pmmp/BedrockProtocol/issues", - "source": "https://github.com/pmmp/BedrockProtocol/tree/35.0.0+bedrock-1.21.50" + "source": "https://github.com/pmmp/BedrockProtocol/tree/35.0.3+bedrock-1.21.50" }, - "time": "2024-12-04T13:02:00+00:00" + "time": "2025-01-07T23:06:29+00:00" }, { "name": "pocketmine/binaryutils", diff --git a/phpstan.neon.dist b/phpstan.neon.dist index dfaa964e4b..63155cbc47 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -1,7 +1,6 @@ includes: - tests/phpstan/analyse-for-current-php-version.neon.php - tests/phpstan/configs/actual-problems.neon - - tests/phpstan/configs/dependency-problems.neon - tests/phpstan/configs/impossible-generics.neon - tests/phpstan/configs/php-bugs.neon - tests/phpstan/configs/phpstan-bugs.neon diff --git a/tests/phpstan/configs/dependency-problems.neon b/tests/phpstan/configs/dependency-problems.neon deleted file mode 100644 index e95fcd79c2..0000000000 --- a/tests/phpstan/configs/dependency-problems.neon +++ /dev/null @@ -1,31 +0,0 @@ -parameters: - ignoreErrors: - - - message: '#^Parameter \#1 \$input of class pocketmine\\crafting\\json\\ShapelessRecipeData constructor expects list\, array\ given\.$#' - identifier: argument.type - count: 1 - path: ../../../tools/generate-bedrock-data-from-packets.php - - - - message: '#^Parameter \#2 \$output of class pocketmine\\crafting\\json\\ShapelessRecipeData constructor expects list\, array\ given\.$#' - identifier: argument.type - count: 1 - path: ../../../tools/generate-bedrock-data-from-packets.php - - - - message: '#^Parameter \#3 \$output of class pocketmine\\crafting\\json\\ShapedRecipeData constructor expects list\, array\ given\.$#' - identifier: argument.type - count: 1 - path: ../../../tools/generate-bedrock-data-from-packets.php - - - - message: '#^Parameter \#5 \$unlockingIngredients of class pocketmine\\crafting\\json\\ShapelessRecipeData constructor expects list\, array\ given\.$#' - identifier: argument.type - count: 1 - path: ../../../tools/generate-bedrock-data-from-packets.php - - - - message: '#^Parameter \#6 \$unlockingIngredients of class pocketmine\\crafting\\json\\ShapedRecipeData constructor expects list\, array\ given\.$#' - identifier: argument.type - count: 1 - path: ../../../tools/generate-bedrock-data-from-packets.php diff --git a/tests/phpstan/configs/phpstan-bugs.neon b/tests/phpstan/configs/phpstan-bugs.neon index 7e3484bc59..9ab1257639 100644 --- a/tests/phpstan/configs/phpstan-bugs.neon +++ b/tests/phpstan/configs/phpstan-bugs.neon @@ -126,6 +126,12 @@ parameters: count: 1 path: ../../../src/item/WritableBookBase.php + - + message: '#^Parameter \#3 \$input of class pocketmine\\network\\mcpe\\protocol\\types\\recipe\\ShapedRecipe constructor expects list\\>, array\, non\-empty\-array\, pocketmine\\network\\mcpe\\protocol\\types\\recipe\\RecipeIngredient\>\> given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/network/mcpe/cache/CraftingDataCache.php + - message: '#^Method pocketmine\\network\\mcpe\\compression\\ZlibCompressor\:\:getNetworkId\(\) never returns 1 so it can be removed from the return type\.$#' identifier: return.unusedType From 0a16daa61924581bec2ef35fee651e2b598a80a0 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 8 Jan 2025 01:45:28 +0000 Subject: [PATCH 14/19] Avoid dodgy array_flip hash building the conventional way is using array_keys and array_fill_keys. Behaviour is more predictable & also avoids benevolent union fuckery from PHPStan. --- src/item/enchantment/ProtectionEnchantment.php | 10 +++++++--- src/plugin/PluginGraylist.php | 14 ++++++++++---- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/item/enchantment/ProtectionEnchantment.php b/src/item/enchantment/ProtectionEnchantment.php index be78a23065..8174668754 100644 --- a/src/item/enchantment/ProtectionEnchantment.php +++ b/src/item/enchantment/ProtectionEnchantment.php @@ -25,18 +25,22 @@ use pocketmine\event\entity\EntityDamageEvent; use pocketmine\lang\Translatable; -use function array_flip; +use function array_fill_keys; use function floor; class ProtectionEnchantment extends Enchantment{ protected float $typeModifier; - /** @var int[]|null */ + /** + * @var true[]|null + * @phpstan-var array + */ protected ?array $applicableDamageTypes = null; /** * ProtectionEnchantment constructor. * * @phpstan-param null|(\Closure(int $level) : int) $minEnchantingPower + * @phpstan-param list|null $applicableDamageTypes * * @param int $primaryItemFlags @deprecated * @param int $secondaryItemFlags @deprecated @@ -48,7 +52,7 @@ public function __construct(Translatable|string $name, int $rarity, int $primary $this->typeModifier = $typeModifier; if($applicableDamageTypes !== null){ - $this->applicableDamageTypes = array_flip($applicableDamageTypes); + $this->applicableDamageTypes = array_fill_keys($applicableDamageTypes, true); } } diff --git a/src/plugin/PluginGraylist.php b/src/plugin/PluginGraylist.php index ff9d718322..f3c9cf2a3b 100644 --- a/src/plugin/PluginGraylist.php +++ b/src/plugin/PluginGraylist.php @@ -24,7 +24,8 @@ namespace pocketmine\plugin; use pocketmine\utils\Utils; -use function array_flip; +use function array_fill_keys; +use function array_keys; use function is_array; use function is_float; use function is_int; @@ -32,23 +33,28 @@ class PluginGraylist{ - /** @var string[] */ + /** + * @var true[] + * @phpstan-var array + */ private array $plugins; private bool $isWhitelist = false; /** * @param string[] $plugins + * @phpstan-param list $plugins */ public function __construct(array $plugins = [], bool $whitelist = false){ - $this->plugins = array_flip($plugins); + $this->plugins = array_fill_keys($plugins, true); $this->isWhitelist = $whitelist; } /** * @return string[] + * @phpstan-return list */ public function getPlugins() : array{ - return array_flip($this->plugins); + return array_keys($this->plugins); } public function isWhitelist() : bool{ From 4a83920db9a1bc5b7deef6a605b7cf5f68a17866 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 8 Jan 2025 01:47:04 +0000 Subject: [PATCH 15/19] PlayerPreLoginEvent: improve array type info --- src/event/player/PlayerPreLoginEvent.php | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/event/player/PlayerPreLoginEvent.php b/src/event/player/PlayerPreLoginEvent.php index 5a69c0e175..4af0cdd891 100644 --- a/src/event/player/PlayerPreLoginEvent.php +++ b/src/event/player/PlayerPreLoginEvent.php @@ -52,9 +52,15 @@ class PlayerPreLoginEvent extends Event{ self::KICK_FLAG_BANNED ]; - /** @var Translatable[]|string[] reason const => associated message */ + /** + * @var Translatable[]|string[] reason const => associated message + * @phpstan-var array + */ protected array $disconnectReasons = []; - /** @var Translatable[]|string[] */ + /** + * @var Translatable[]|string[] + * @phpstan-var array + */ protected array $disconnectScreenMessages = []; public function __construct( @@ -93,6 +99,7 @@ public function setAuthRequired(bool $v) : void{ * Returns an array of kick flags currently assigned. * * @return int[] + * @phpstan-return list */ public function getKickFlags() : array{ return array_keys($this->disconnectReasons); From 5e0f03dff0e46ea5bfb54069e0f1f4ab8fcdd4cd Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 8 Jan 2025 01:48:15 +0000 Subject: [PATCH 16/19] Stub PalettedBlockArray functions that work with arrays and workaround PHPStan stupidity --- phpstan.neon.dist | 1 + src/world/format/io/BaseWorldProvider.php | 4 ++-- tests/phpstan/stubs/chunkutils2.stub | 15 +++++++++++++++ 3 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 tests/phpstan/stubs/chunkutils2.stub diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 63155cbc47..5e917dc750 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -45,6 +45,7 @@ parameters: - pocketmine\DEBUG - pocketmine\IS_DEVELOPMENT_BUILD stubFiles: + - tests/phpstan/stubs/chunkutils2.stub - tests/phpstan/stubs/JsonMapper.stub - tests/phpstan/stubs/leveldb.stub - tests/phpstan/stubs/pmmpthread.stub diff --git a/src/world/format/io/BaseWorldProvider.php b/src/world/format/io/BaseWorldProvider.php index 79f6875a4b..6fcb8e10be 100644 --- a/src/world/format/io/BaseWorldProvider.php +++ b/src/world/format/io/BaseWorldProvider.php @@ -83,11 +83,11 @@ private function translatePalette(PalettedBlockArray $blockArray, \Logger $logge } try{ - $newPalette[$k] = $this->blockStateDeserializer->deserialize($newStateData); + $newPalette[] = $this->blockStateDeserializer->deserialize($newStateData); }catch(BlockStateDeserializeException $e){ //this should never happen anyway - if the upgrader returned an invalid state, we have bigger problems $blockDecodeErrors[] = "Palette offset $k / Failed to deserialize upgraded state $id:$meta: " . $e->getMessage(); - $newPalette[$k] = $this->blockStateDeserializer->deserialize(GlobalBlockStateHandlers::getUnknownBlockStateData()); + $newPalette[] = $this->blockStateDeserializer->deserialize(GlobalBlockStateHandlers::getUnknownBlockStateData()); } } diff --git a/tests/phpstan/stubs/chunkutils2.stub b/tests/phpstan/stubs/chunkutils2.stub new file mode 100644 index 0000000000..b23e4a7fd0 --- /dev/null +++ b/tests/phpstan/stubs/chunkutils2.stub @@ -0,0 +1,15 @@ + $palette + */ + public static function fromData(int $bitsPerBlock, string $wordArray, array $palette): PalettedBlockArray {} + + /** + * @return list + */ + public function getPalette(): array {} +} From d42ec06647dbac8f8fa7634159286bceec9507ed Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 8 Jan 2025 01:48:55 +0000 Subject: [PATCH 17/19] ZippedResourcePack: don't pass exception code to new exception this is a BUT (int|string) under PHPStan, and we don't need the errors. We don't care about this code anyway. --- src/resourcepacks/ZippedResourcePack.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/resourcepacks/ZippedResourcePack.php b/src/resourcepacks/ZippedResourcePack.php index c4daeedf7b..4fcf204d94 100644 --- a/src/resourcepacks/ZippedResourcePack.php +++ b/src/resourcepacks/ZippedResourcePack.php @@ -100,7 +100,7 @@ public function __construct(string $zipPath){ try{ $manifest = (new CommentedJsonDecoder())->decode($manifestData); }catch(\RuntimeException $e){ - throw new ResourcePackException("Failed to parse manifest.json: " . $e->getMessage(), $e->getCode(), $e); + throw new ResourcePackException("Failed to parse manifest.json: " . $e->getMessage(), 0, $e); } if(!($manifest instanceof \stdClass)){ throw new ResourcePackException("manifest.json should contain a JSON object, not " . gettype($manifest)); From 847ae26cad24df4ad3e30f911f913574684cb11d Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 8 Jan 2025 02:04:06 +0000 Subject: [PATCH 18/19] PHPStan: don't remember possibly-impure function return values I don't think we get much benefit from this, and the assumption that functions with a return value are pure is sketchy. In any case, it's better to avoid these repeated calls anyway. --- phpstan.neon.dist | 1 + src/entity/projectile/Projectile.php | 5 +++-- src/permission/BanEntry.php | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 5e917dc750..5a816f81c5 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -19,6 +19,7 @@ rules: parameters: level: 9 checkMissingCallableSignature: true + rememberPossiblyImpureFunctionValues: false #risky to remember these, better for performance to avoid repeated calls anyway treatPhpDocTypesAsCertain: false bootstrapFiles: - tests/phpstan/bootstrap.php diff --git a/src/entity/projectile/Projectile.php b/src/entity/projectile/Projectile.php index 0abc274b5d..d6ab1c1753 100644 --- a/src/entity/projectile/Projectile.php +++ b/src/entity/projectile/Projectile.php @@ -290,10 +290,11 @@ protected function onHitEntity(Entity $entityHit, RayTraceResult $hitResult) : v $damage = $this->getResultDamage(); if($damage >= 0){ - if($this->getOwningEntity() === null){ + $owner = $this->getOwningEntity(); + if($owner === null){ $ev = new EntityDamageByEntityEvent($this, $entityHit, EntityDamageEvent::CAUSE_PROJECTILE, $damage); }else{ - $ev = new EntityDamageByChildEntityEvent($this->getOwningEntity(), $this, $entityHit, EntityDamageEvent::CAUSE_PROJECTILE, $damage); + $ev = new EntityDamageByChildEntityEvent($owner, $this, $entityHit, EntityDamageEvent::CAUSE_PROJECTILE, $damage); } $entityHit->attack($ev); diff --git a/src/permission/BanEntry.php b/src/permission/BanEntry.php index 0d5ed0c76b..5f235f1a99 100644 --- a/src/permission/BanEntry.php +++ b/src/permission/BanEntry.php @@ -101,11 +101,12 @@ public function setReason(string $reason) : void{ } public function getString() : string{ + $expires = $this->getExpires(); return implode("|", [ $this->getName(), $this->getCreated()->format(self::$format), $this->getSource(), - $this->getExpires() === null ? "Forever" : $this->getExpires()->format(self::$format), + $expires === null ? "Forever" : $expires->format(self::$format), $this->getReason() ]); } From b3f15435cc9dc50fb93c3cf2c8023c0b8a27d3db Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 8 Jan 2025 02:31:50 +0000 Subject: [PATCH 19/19] Projectile: clean up dodgy code --- src/entity/projectile/Projectile.php | 35 +++++++++------------------- 1 file changed, 11 insertions(+), 24 deletions(-) diff --git a/src/entity/projectile/Projectile.php b/src/entity/projectile/Projectile.php index d6ab1c1753..68b6c47637 100644 --- a/src/entity/projectile/Projectile.php +++ b/src/entity/projectile/Projectile.php @@ -44,7 +44,6 @@ use pocketmine\nbt\tag\IntTag; use pocketmine\nbt\tag\ListTag; use pocketmine\timings\Timings; -use function assert; use function atan2; use function ceil; use function count; @@ -170,8 +169,6 @@ protected function move(float $dx, float $dy, float $dz) : void{ $start = $this->location->asVector3(); $end = $start->add($dx, $dy, $dz); - $blockHit = null; - $entityHit = null; $hitResult = null; $world = $this->getWorld(); @@ -181,8 +178,7 @@ protected function move(float $dx, float $dy, float $dz) : void{ $blockHitResult = $this->calculateInterceptWithBlock($block, $start, $end); if($blockHitResult !== null){ $end = $blockHitResult->hitVector; - $blockHit = $block; - $hitResult = $blockHitResult; + $hitResult = [$block, $blockHitResult]; break; } } @@ -206,8 +202,7 @@ protected function move(float $dx, float $dy, float $dz) : void{ if($distance < $entityDistance){ $entityDistance = $distance; - $entityHit = $entity; - $hitResult = $entityHitResult; + $hitResult = [$entity, $entityHitResult]; $end = $entityHitResult->hitVector; } } @@ -223,26 +218,18 @@ protected function move(float $dx, float $dy, float $dz) : void{ $this->recalculateBoundingBox(); if($hitResult !== null){ - /** @var ProjectileHitEvent|null $ev */ - $ev = null; - if($entityHit !== null){ - $ev = new ProjectileHitEntityEvent($this, $hitResult, $entityHit); - }elseif($blockHit !== null){ - $ev = new ProjectileHitBlockEvent($this, $hitResult, $blockHit); + [$objectHit, $rayTraceResult] = $hitResult; + if($objectHit instanceof Entity){ + $ev = new ProjectileHitEntityEvent($this, $rayTraceResult, $objectHit); + $specificHitFunc = fn() => $this->onHitEntity($objectHit, $rayTraceResult); }else{ - assert(false, "unknown hit type"); + $ev = new ProjectileHitBlockEvent($this, $rayTraceResult, $objectHit); + $specificHitFunc = fn() => $this->onHitBlock($objectHit, $rayTraceResult); } - if($ev !== null){ - $ev->call(); - $this->onHit($ev); - - if($ev instanceof ProjectileHitEntityEvent){ - $this->onHitEntity($ev->getEntityHit(), $ev->getRayTraceResult()); - }elseif($ev instanceof ProjectileHitBlockEvent){ - $this->onHitBlock($ev->getBlockHit(), $ev->getRayTraceResult()); - } - } + $ev->call(); + $this->onHit($ev); + $specificHitFunc(); $this->isCollided = $this->onGround = true; $this->motion = Vector3::zero();