diff --git a/phpstan.neon b/phpstan.neon index fc850f100..3c03a2e31 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,7 +1,10 @@ - +includes: + - tests/phpstan/configs/optional-com-dotnet.neon + - tests/phpstan/configs/phpstan-bugs.neon + - tests/phpstan/configs/pthreads-bugs.neon parameters: - level: 1 + level: 2 autoload_files: - tests/phpstan/bootstrap.php - src/PocketMine.php @@ -24,23 +27,6 @@ parameters: count: 1 path: src/network/mcpe/protocol/StartGamePacket.php - - - message: "#^Instantiated class COM not found\\.$#" - count: 1 - path: src/network/upnp/UPnP.php - comment: "only available on Windows" - - - - message: "#^Caught class com_exception not found\\.$#" - count: 2 - path: src/network/upnp/UPnP.php - comment: "only available on Windows" - - - - message: "#^Variable \\$GLOBALS in isset\\(\\) always exists and is not nullable\\.$#" - path: src/MemoryManager.php - comment: "this isn't defined on threads (thanks pthreads)" - - message: "#^Constant pocketmine\\\\COMPOSER_AUTOLOADER_PATH not found\\.$#" path: src @@ -64,3 +50,9 @@ parameters: - message: "#^Constant pocketmine\\\\VERSION not found\\.$#" path: src + + - + message: "#^Call to an undefined method pocketmine\\\\command\\\\CommandSender\\:\\:teleport\\(\\)\\.$#" + count: 1 + path: src/command/defaults/TeleportCommand.php + comment: "not actually possible, but high cost to fix warning" diff --git a/src/Server.php b/src/Server.php index 62b98bc5a..4c3dfab55 100644 --- a/src/Server.php +++ b/src/Server.php @@ -200,7 +200,7 @@ class Server{ * @var int */ private $tickCounter = 0; - /** @var int */ + /** @var float */ private $nextTick = 0; /** @var float[] */ private $tickAverage = [20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20]; @@ -938,7 +938,7 @@ class Server{ } /** - * @return string[] + * @return string[][] */ public function getCommandAliases() : array{ $section = $this->getProperty("aliases"); @@ -1323,7 +1323,7 @@ class Server{ return $this->broadcast($message, self::BROADCAST_CHANNEL_USERS); } - /** @var Player[] $recipients */ + /** @var CommandSender[] $recipients */ foreach($recipients as $recipient){ $recipient->sendMessage($message); } diff --git a/src/command/Command.php b/src/command/Command.php index 6d7628b63..87aae29c3 100644 --- a/src/command/Command.php +++ b/src/command/Command.php @@ -55,7 +55,7 @@ abstract class Command{ */ private $activeAliases = []; - /** @var CommandMap */ + /** @var CommandMap|null */ private $commandMap = null; /** @var string */ diff --git a/src/command/defaults/GamemodeCommand.php b/src/command/defaults/GamemodeCommand.php index d520f9879..eb239c206 100644 --- a/src/command/defaults/GamemodeCommand.php +++ b/src/command/defaults/GamemodeCommand.php @@ -59,7 +59,6 @@ class GamemodeCommand extends VanillaCommand{ return true; } - $target = $sender; if(isset($args[1])){ $target = $sender->getServer()->getPlayer($args[1]); if($target === null){ @@ -67,7 +66,9 @@ class GamemodeCommand extends VanillaCommand{ return true; } - }elseif(!($sender instanceof Player)){ + }elseif($sender instanceof Player){ + $target = $sender; + }else{ throw new InvalidCommandSyntaxException(); } diff --git a/src/crafting/CraftingManager.php b/src/crafting/CraftingManager.php index 1196f6aa3..b35e6b42c 100644 --- a/src/crafting/CraftingManager.php +++ b/src/crafting/CraftingManager.php @@ -44,7 +44,7 @@ class CraftingManager{ /** @var FurnaceRecipe[] */ protected $furnaceRecipes = []; - /** @var CompressBatchPromise */ + /** @var CompressBatchPromise|null */ private $craftingDataCache; public function __construct(){ diff --git a/src/entity/Entity.php b/src/entity/Entity.php index cb387ef06..c053aa161 100644 --- a/src/entity/Entity.php +++ b/src/entity/Entity.php @@ -99,8 +99,8 @@ abstract class Entity{ /** @var EntityDamageEvent|null */ protected $lastDamageCause = null; - /** @var Block[] */ - protected $blocksAround = []; + /** @var Block[]|null */ + protected $blocksAround; /** @var Location */ protected $location; diff --git a/src/entity/Squid.php b/src/entity/Squid.php index e78a7ad2f..09cae8408 100644 --- a/src/entity/Squid.php +++ b/src/entity/Squid.php @@ -41,7 +41,7 @@ class Squid extends WaterAnimal{ public $width = 0.95; public $height = 0.95; - /** @var Vector3 */ + /** @var Vector3|null */ public $swimDirection = null; public $swimSpeed = 0.1; diff --git a/src/event/player/PlayerChatEvent.php b/src/event/player/PlayerChatEvent.php index 9bafa319a..b5ee99ac4 100644 --- a/src/event/player/PlayerChatEvent.php +++ b/src/event/player/PlayerChatEvent.php @@ -23,11 +23,13 @@ declare(strict_types=1); namespace pocketmine\event\player; +use pocketmine\command\CommandSender; use pocketmine\event\Cancellable; use pocketmine\event\CancellableTrait; use pocketmine\permission\PermissionManager; use pocketmine\player\Player; use pocketmine\Server; +use function spl_object_id; /** * Called when a player chats something @@ -42,15 +44,15 @@ class PlayerChatEvent extends PlayerEvent implements Cancellable{ protected $format; /** - * @var Player[] + * @var CommandSender[] */ protected $recipients = []; /** - * @param Player $player - * @param string $message - * @param string $format - * @param Player[] $recipients + * @param Player $player + * @param string $message + * @param string $format + * @param CommandSender[] $recipients */ public function __construct(Player $player, string $message, string $format = "chat.type.text", ?array $recipients = null){ $this->player = $player; @@ -59,7 +61,11 @@ class PlayerChatEvent extends PlayerEvent implements Cancellable{ $this->format = $format; if($recipients === null){ - $this->recipients = PermissionManager::getInstance()->getPermissionSubscriptions(Server::BROADCAST_CHANNEL_USERS); + foreach(PermissionManager::getInstance()->getPermissionSubscriptions(Server::BROADCAST_CHANNEL_USERS) as $permissible){ + if($permissible instanceof CommandSender){ + $this->recipients[spl_object_id($permissible)] = $permissible; + } + } }else{ $this->recipients = $recipients; } @@ -103,14 +109,14 @@ class PlayerChatEvent extends PlayerEvent implements Cancellable{ } /** - * @return Player[] + * @return CommandSender[] */ public function getRecipients() : array{ return $this->recipients; } /** - * @param Player[] $recipients + * @param CommandSender[] $recipients */ public function setRecipients(array $recipients) : void{ $this->recipients = $recipients; diff --git a/src/event/player/PlayerCreationEvent.php b/src/event/player/PlayerCreationEvent.php index f3318058e..28f8290be 100644 --- a/src/event/player/PlayerCreationEvent.php +++ b/src/event/player/PlayerCreationEvent.php @@ -36,9 +36,9 @@ class PlayerCreationEvent extends Event{ /** @var NetworkSession */ private $session; - /** @var Player::class */ + /** @var string */ private $baseClass = Player::class; - /** @var Player::class */ + /** @var string */ private $playerClass = Player::class; @@ -71,14 +71,14 @@ class PlayerCreationEvent extends Event{ } /** - * @return Player::class + * @return string */ public function getBaseClass(){ return $this->baseClass; } /** - * @param Player::class $class + * @param string $class */ public function setBaseClass($class) : void{ if(!is_a($class, $this->baseClass, true)){ @@ -89,14 +89,14 @@ class PlayerCreationEvent extends Event{ } /** - * @return Player::class + * @return string */ public function getPlayerClass(){ return $this->playerClass; } /** - * @param Player::class $class + * @param string $class */ public function setPlayerClass($class) : void{ if(!is_a($class, $this->baseClass, true)){ diff --git a/src/inventory/BaseInventory.php b/src/inventory/BaseInventory.php index 1b9e5d298..6d5455dc9 100644 --- a/src/inventory/BaseInventory.php +++ b/src/inventory/BaseInventory.php @@ -37,7 +37,7 @@ abstract class BaseInventory implements Inventory{ /** @var int */ protected $maxStackSize = Inventory::MAX_STACK; /** @var \SplFixedArray|Item[] */ - protected $slots = []; + protected $slots; /** @var Player[] */ protected $viewers = []; /** @var InventoryChangeListener[] */ diff --git a/src/network/mcpe/protocol/AvailableCommandsPacket.php b/src/network/mcpe/protocol/AvailableCommandsPacket.php index c54461b23..185505262 100644 --- a/src/network/mcpe/protocol/AvailableCommandsPacket.php +++ b/src/network/mcpe/protocol/AvailableCommandsPacket.php @@ -234,6 +234,7 @@ class AvailableCommandsPacket extends DataPacket implements ClientboundPacket{ $overloads = []; for($overloadIndex = 0, $overloadCount = $this->getUnsignedVarInt(); $overloadIndex < $overloadCount; ++$overloadIndex){ + $overloads[$overloadIndex] = []; for($paramIndex = 0, $paramCount = $this->getUnsignedVarInt(); $paramIndex < $paramCount; ++$paramIndex){ $parameter = new CommandParameter(); $parameter->paramName = $this->getString(); diff --git a/src/network/mcpe/protocol/CraftingDataPacket.php b/src/network/mcpe/protocol/CraftingDataPacket.php index d337ca873..3f36da6d8 100644 --- a/src/network/mcpe/protocol/CraftingDataPacket.php +++ b/src/network/mcpe/protocol/CraftingDataPacket.php @@ -139,7 +139,7 @@ class CraftingDataPacket extends DataPacket implements ClientboundPacket{ } $this->decodedEntries[] = $entry; } - $this->getBool(); //cleanRecipes + $this->cleanRecipes = $this->getBool(); } private static function writeEntry($entry, NetworkBinaryStream $stream, int $pos) : int{ diff --git a/src/world/World.php b/src/world/World.php index f88fd4c5f..533524246 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -236,7 +236,7 @@ class World implements ChunkManager{ /** @var WorldTimings */ public $timings; - /** @var int */ + /** @var float */ public $tickRateTime = 0; /** @var bool */ diff --git a/src/world/format/Chunk.php b/src/world/format/Chunk.php index b91263130..63a92c27c 100644 --- a/src/world/format/Chunk.php +++ b/src/world/format/Chunk.php @@ -546,7 +546,7 @@ class Chunk{ * @param World $world */ public function initChunk(World $world) : void{ - if($this->NBTentities !== null){ + if(!empty($this->NBTentities)){ $this->dirtyFlags |= self::DIRTY_FLAG_ENTITIES; $world->timings->syncChunkLoadEntitiesTimer->startTiming(); foreach($this->NBTentities as $nbt){ @@ -564,10 +564,10 @@ class Chunk{ } } - $this->NBTentities = null; + $this->NBTentities = []; $world->timings->syncChunkLoadEntitiesTimer->stopTiming(); } - if($this->NBTtiles !== null){ + if(!empty($this->NBTtiles)){ $this->dirtyFlags |= self::DIRTY_FLAG_TILES; $world->timings->syncChunkLoadTileEntitiesTimer->startTiming(); foreach($this->NBTtiles as $nbt){ @@ -581,7 +581,7 @@ class Chunk{ } } - $this->NBTtiles = null; + $this->NBTtiles = []; $world->timings->syncChunkLoadTileEntitiesTimer->stopTiming(); } } diff --git a/tests/phpstan/configs/optional-com-dotnet.neon b/tests/phpstan/configs/optional-com-dotnet.neon new file mode 100644 index 000000000..efa2d82ab --- /dev/null +++ b/tests/phpstan/configs/optional-com-dotnet.neon @@ -0,0 +1,12 @@ +parameters: + ignoreErrors: + - + message: "#^Instantiated class COM not found\\.$#" + count: 2 + path: src/pocketmine/network/upnp/UPnP.php + + - + message: "#^Access to property \\$StaticPortMappingCollection on an unknown class COM\\.$#" + count: 4 + path: src/pocketmine/network/upnp/UPnP.php + diff --git a/tests/phpstan/configs/phpstan-bugs.neon b/tests/phpstan/configs/phpstan-bugs.neon new file mode 100644 index 000000000..90fef5cea --- /dev/null +++ b/tests/phpstan/configs/phpstan-bugs.neon @@ -0,0 +1,10 @@ +parameters: + ignoreErrors: + - + message: "#^PHPDoc tag @param has invalid value \\(.+\\)\\: Unexpected token \"&\", expected TOKEN_VARIABLE at offset \\d+$#" + path: src/pocketmine + + - + message: "#^Default value of the parameter \\#\\d+ \\$[A-Za-z\\d_]+ \\(\\-?\\d+\\) of method .+\\(\\) is incompatible with type float\\.$#" + path: src/pocketmine + diff --git a/tests/phpstan/configs/pthreads-bugs.neon b/tests/phpstan/configs/pthreads-bugs.neon new file mode 100644 index 000000000..987af95c0 --- /dev/null +++ b/tests/phpstan/configs/pthreads-bugs.neon @@ -0,0 +1,6 @@ +parameters: + ignoreErrors: + - + message: "#^Variable \\$GLOBALS in isset\\(\\) always exists and is not nullable\\.$#" + path: src/MemoryManager.php +