[TOOLS] Fix errors reported by PHPStan at level 4

This commit is contained in:
Hugo Sales 2021-12-26 22:17:26 +00:00
parent edd996d281
commit b84315c95b
Signed by: someonewithpc
GPG Key ID: 7D0C7EAFC9D835A0
19 changed files with 75 additions and 66 deletions

View File

@ -79,16 +79,16 @@ abstract class Parser
$note_res = null; $note_res = null;
$actor_res = null; $actor_res = null;
Event::handle('SearchCreateExpression', [$eb, $term, $language, $actor, &$note_res, &$actor_res]); Event::handle('SearchCreateExpression', [$eb, $term, $language, $actor, &$note_res, &$actor_res]);
if (\is_null($note_res) && \is_null($actor_res)) { if (\is_null($note_res) && \is_null($actor_res)) { // @phpstan-ignore-line
throw new ServerException("No one claimed responsibility for a match term: {$term}"); throw new ServerException("No one claimed responsibility for a match term: {$term}");
} }
if (!\is_null($note_res) && !empty($note_res)) { if (!\is_null($note_res) && !empty($note_res)) { // @phpstan-ignore-line
if (\is_array($note_res)) { if (\is_array($note_res)) {
$note_res = $eb->orX(...$note_res); $note_res = $eb->orX(...$note_res);
} }
$note_parts[] = $note_res; $note_parts[] = $note_res;
} }
if (!\is_null($actor_res) && !empty($note_res)) { if (!\is_null($actor_res) && !empty($actor_res)) {
if (\is_array($actor_res)) { if (\is_array($actor_res)) {
$actor_res = $eb->orX(...$actor_res); $actor_res = $eb->orX(...$actor_res);
} }
@ -103,10 +103,11 @@ abstract class Parser
$last_op = $delimiter; $last_op = $delimiter;
} }
$match = true; $match = true;
continue 2; break;
} }
} }
if (!$match) { // TODO
if (!$match) { // @phpstan-ignore-line
++$right; ++$right;
} }
} }

View File

@ -1,5 +1,5 @@
parameters: parameters:
level: 3 level: 4
bootstrapFiles: bootstrapFiles:
- config/bootstrap.php - config/bootstrap.php
paths: paths:
@ -9,6 +9,7 @@ parameters:
- plugins - plugins
excludePaths: excludePaths:
- plugins/ActivityPub - plugins/ActivityPub
- plugins/Poll
- components/FreeNetwork - components/FreeNetwork
earlyTerminatingMethodCalls: earlyTerminatingMethodCalls:
App\Core\Log: App\Core\Log:
@ -18,6 +19,11 @@ parameters:
message: '/Access to an undefined property App\\Util\\Bitmap::\$\w+/' message: '/Access to an undefined property App\\Util\\Bitmap::\$\w+/'
paths: paths:
- * - *
-
message: '/^Property App\\PHPStan\\ClassFromTableNameDynamicStaticMethodReturnTypeExtension::\$provider is never read, only written\./'
path: src/PHPStan/ClassFromTableNameDynamicStaticMethodReturnTypeExtension.php
# - # -
# message: '/has no return typehint specified/' # message: '/has no return typehint specified/'
# paths: # paths:

View File

@ -285,7 +285,7 @@ class Embed extends Plugin
$root_url = "{$root_url['scheme']}://{$root_url['host']}"; $root_url = "{$root_url['scheme']}://{$root_url['host']}";
$metadata['author_url'] = $info->authorUrl ? (string) $info->authorUrl : $root_url; $metadata['author_url'] = $info->authorUrl ? (string) $info->authorUrl : $root_url;
$metadata['provider_name'] = $info->providerName; $metadata['provider_name'] = $info->providerName;
$metadata['provider_url'] = (string) $info->providerUrl ?? $metadata['author_name']; $metadata['provider_url'] = (string) ($info->providerUrl ?? $metadata['author_name']);
if (!\is_null($info->image)) { if (!\is_null($info->image)) {
$thumbnail_url = (string) $info->image; $thumbnail_url = (string) $info->image;

View File

@ -61,7 +61,7 @@ class Oomox
* *
* @throws ServerException * @throws ServerException
*/ */
public function getOomoxForm(?EntityOomox $current_oomox_settings, bool $is_light): FormInterface public static function getOomoxForm(?EntityOomox $current_oomox_settings, bool $is_light): FormInterface
{ {
$theme = $is_light ? 'light' : 'dark'; $theme = $is_light ? 'light' : 'dark';
$foreground = 'colour_foreground_' . $theme; $foreground = 'colour_foreground_' . $theme;
@ -144,15 +144,15 @@ class Oomox
$actor_id = $user->getId(); $actor_id = $user->getId();
$current_oomox_settings = PluginOomox::getEntity($user); $current_oomox_settings = PluginOomox::getEntity($user);
$form_light = (new self)->getOomoxForm($current_oomox_settings, true); $form_light = self::getOomoxForm($current_oomox_settings, true);
$form_light->handleRequest($request); $form_light->handleRequest($request);
if ($form_light->isSubmitted() && $form_light->isValid()) { if ($form_light->isSubmitted() && $form_light->isValid()) {
/** @var SubmitButton $reset_button */ /** @var SubmitButton $reset_button */
$reset_button = $form_light->get('colour_reset_light'); $reset_button = $form_light->get('colour_reset_light');
if ($reset_button->isClicked()) { if ($reset_button->isClicked()) {
if (isset($current_oomox_settings)) { if (!\is_null($current_oomox_settings)) {
$current_oomox_settings?->resetTheme(true); $current_oomox_settings->resetTheme(true);
} }
} else { } else {
$data = $form_light->getData(); $data = $form_light->getData();
@ -190,7 +190,7 @@ class Oomox
$actor_id = $user->getId(); $actor_id = $user->getId();
$current_oomox_settings = PluginOomox::getEntity($user); $current_oomox_settings = PluginOomox::getEntity($user);
$form_dark = (new self)->getOomoxForm($current_oomox_settings, false); $form_dark = self::getOomoxForm($current_oomox_settings, false);
$form_dark->handleRequest($request); $form_dark->handleRequest($request);
if ($form_dark->isSubmitted() && $form_dark->isValid()) { if ($form_dark->isSubmitted() && $form_dark->isValid()) {

View File

@ -74,17 +74,11 @@ class RepeatNote extends NoteHandlerPlugin
process_note_content_extra_args: $extra_args, process_note_content_extra_args: $extra_args,
); );
// Find the id of the note we just created DB::persist(NoteRepeat::create([
$repeat_id = $repeat?->getId(); 'note_id' => $repeat->getId(),
'actor_id' => $actor_id,
// Add it to note_repeat table 'repeat_of' => $og_id,
if (!\is_null($repeat_id)) { ]));
DB::persist(NoteRepeat::create([
'note_id' => $repeat_id,
'actor_id' => $actor_id,
'repeat_of' => $og_id,
]));
}
// Log an activity // Log an activity
$repeat_activity = Activity::create([ $repeat_activity = Activity::create([

View File

@ -109,7 +109,6 @@ class StoreRemoteMedia extends Plugin
} }
// Have we handled it already? // Have we handled it already?
/** @var AttachmentToLink */
$attachment_to_link = DB::find( $attachment_to_link = DB::find(
'attachment_to_link', 'attachment_to_link',
['link_id' => $link->getId()], ['link_id' => $link->getId()],

View File

@ -224,7 +224,7 @@ class UserPanel extends Controller
unset($form_defs['placeholder']); unset($form_defs['placeholder']);
$tabbed_forms = []; $tabbed_forms = [];
foreach ($form_defs as $transport_name => $f) { foreach ($form_defs as $transport_name => $f) { // @phpstan-ignore-line
unset($f['save']); unset($f['save']);
$form = Form::create($f); $form = Form::create($f);
$tabbed_forms[$transport_name]['title'] = $transport_name; $tabbed_forms[$transport_name]['title'] = $transport_name;

View File

@ -179,6 +179,9 @@ abstract class Cache
} }
} }
/**
* @param callable(mixed, bool &$save): mixed $calculate
*/
public static function get(string $key, callable $calculate, string $pool = 'default', float $beta = 1.0) public static function get(string $key, callable $calculate, string $pool = 'default', float $beta = 1.0)
{ {
if (isset(self::$redis[$pool])) { if (isset(self::$redis[$pool])) {

View File

@ -35,6 +35,7 @@ namespace App\Core;
use function App\Core\I18n\_m; use function App\Core\I18n\_m;
use App\Util\Common; use App\Util\Common;
use App\Util\Exception\BugFoundException;
use App\Util\Exception\ClientException; use App\Util\Exception\ClientException;
use App\Util\Exception\RedirectException; use App\Util\Exception\RedirectException;
use App\Util\Exception\ServerException; use App\Util\Exception\ServerException;
@ -54,11 +55,11 @@ use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Validator\Exception\ValidatorException; use Symfony\Component\Validator\Exception\ValidatorException;
/** /**
* @method int int(string $param) * @method ?int int(string $param)
* @method bool bool(string $param) * @method ?bool bool(string $param)
* @method string string(string $param) * @method ?string string(string $param)
* @method string params(string $param) * @method ?string params(string $param)
* @method mixed handle(Request $request, mixed ...$extra) * @method mixed handle(Request $request, mixed ...$extra)
*/ */
abstract class Controller extends AbstractController implements EventSubscriberInterface abstract class Controller extends AbstractController implements EventSubscriberInterface
{ {
@ -176,11 +177,9 @@ abstract class Controller extends AbstractController implements EventSubscriberI
} }
} else { } else {
if (\is_null($potential_response)) { if (\is_null($potential_response)) {
// TODO BugFoundException throw new BugFoundException("ControllerResponseInFormat for route '{$route}' returned Event::stop but didn't provide a response");
Log::critical($m = "ControllerResponseInFormat for route '{$route}' returned Event::stop but didn't provide a response");
throw new ServerException(_m($m, ['route' => $route]));
} }
$event->setResponse($potential_response); $event->setResponse($potential_response); // @phpstan-ignore-line
} }
Event::handle('CleanupModule'); Event::handle('CleanupModule');

View File

@ -51,14 +51,14 @@ use Functional as F;
* @mixin EntityManager * @mixin EntityManager
* @template T * @template T
* *
* @method static T find(string $class, array<string, mixed> $values) // Finds an Entity by its identifier. * @method static ?T find(string $class, array<string, mixed> $values) // Finds an Entity by its identifier.
* @method static T getReference(string $class, array<string, mixed> $values) // Special cases: It's like find but does not load the object if it has not been loaded yet, it only returns a proxy to the object. (https://www.doctrine-project.org/projects/doctrine-orm/en/2.10/reference/unitofwork.html) * @method static ?T getReference(string $class, array<string, mixed> $values) // Special cases: It's like find but does not load the object if it has not been loaded yet, it only returns a proxy to the object. (https://www.doctrine-project.org/projects/doctrine-orm/en/2.10/reference/unitofwork.html)
* @method static void remove(object $entity) // Removes an entity instance. * @method static void remove(object $entity) // Removes an entity instance.
* @method static T merge(object $entity) // Merges the state of a detached entity into the persistence context * @method static T merge(object $entity) // Merges the state of a detached entity into the persistence context
* @method static void persist(object $entity) // Tells the EntityManager to make an instance managed and persistent. * @method static void persist(object $entity) // Tells the EntityManager to make an instance managed and persistent.
* @method static bool contains(object $entity) // Determines whether an entity instance is managed in this EntityManager. * @method static bool contains(object $entity) // Determines whether an entity instance is managed in this EntityManager.
* @method static void flush() // Flushes the in-memory state of persisted objects to the database. * @method static void flush() // Flushes the in-memory state of persisted objects to the database.
* @method mixed wrapInTransaction(callable $func) // Executes a function in a transaction. Warning: suppresses exceptions * @method mixed wrapInTransaction(callable $func) // Executes a function in a transaction. Warning: suppresses exceptions
*/ */
class DB class DB
{ {
@ -206,8 +206,6 @@ class DB
$expr = self::buildExpression($eb, $exp); $expr = self::buildExpression($eb, $exp);
if (\is_array($expr)) { if (\is_array($expr)) {
$expressions[] = $eb->{$method}(...$expr); $expressions[] = $eb->{$method}(...$expr);
} else {
$expressions[] = $eb->{$method}($expr);
} }
} elseif ($op == 'is_null') { } elseif ($op == 'is_null') {
$expressions[] = $eb->isNull($exp); $expressions[] = $eb->isNull($exp);

View File

@ -29,4 +29,4 @@ enum VisibilityScope: int // having an int is just convenient
case GROUP = 8; // Only in the Group feed case GROUP = 8; // Only in the Group feed
case COLLECTION = 16; // Only for the collection to see (same as addressee but not available in feeds, notifications only) case COLLECTION = 16; // Only for the collection to see (same as addressee but not available in feeds, notifications only)
case MESSAGE = 32; // Direct Message (same as Collection, but also with dedicated plugin) case MESSAGE = 32; // Direct Message (same as Collection, but also with dedicated plugin)
} };

View File

@ -116,6 +116,7 @@ class SchemaDefDriver extends StaticPHPDriver implements CompilerPassInterface
} }
} }
// @phpstan-ignore-next-line
if (false && $opts['foreign key'] ?? false) { if (false && $opts['foreign key'] ?? false) {
// @codeCoverageIgnoreStart // @codeCoverageIgnoreStart
// TODO: Get foreign keys working // TODO: Get foreign keys working

View File

@ -394,7 +394,7 @@ class Note extends Entity
// Only for the collection to see // Only for the collection to see
return !\is_null($actor) && in_array($actor->getId(), $this->getNotificationTargetIds()); return !\is_null($actor) && in_array($actor->getId(), $this->getNotificationTargetIds());
default: default:
Log::error("Unknown scope found: {$this->getScope()}."); Log::error("Unknown scope found: {$this->getScope()->value}.");
} }
return false; return false;
} }

View File

@ -11,13 +11,13 @@ use PhpParser\Node\Scalar\String_;
use PHPStan\Analyser\Scope; use PHPStan\Analyser\Scope;
use PHPStan\Reflection\MethodReflection; use PHPStan\Reflection\MethodReflection;
use PHPStan\Type\DynamicStaticMethodReturnTypeExtension; use PHPStan\Type\DynamicStaticMethodReturnTypeExtension;
use PHPStan\Type\NullType;
use PHPStan\Type\UnionType;
class ClassFromTableNameDynamicStaticMethodReturnTypeExtension implements DynamicStaticMethodReturnTypeExtension class ClassFromTableNameDynamicStaticMethodReturnTypeExtension implements DynamicStaticMethodReturnTypeExtension
{ {
private ?GNUsocialProvider $provider = null; public function __construct(private ?GNUsocialProvider $provider = null)
public function __construct(GNUsocialProvider $provider)
{ {
$this->provider = $provider;
} }
public function getClass(): string public function getClass(): string
@ -43,7 +43,10 @@ class ClassFromTableNameDynamicStaticMethodReturnTypeExtension implements Dynami
): \PHPStan\Type\Type { ): \PHPStan\Type\Type {
if (isset($_ENV['PHPSTAN_BOOT_KERNEL']) && \count($staticCall->args) >= 1 && ($arg = $staticCall->args[0]->value) instanceof String_) { if (isset($_ENV['PHPSTAN_BOOT_KERNEL']) && \count($staticCall->args) >= 1 && ($arg = $staticCall->args[0]->value) instanceof String_) {
// If called with the first argument as a string, it's a table name // If called with the first argument as a string, it's a table name
return $scope->resolveTypeByName(new Name(DB::filterTableName($staticCall->name->toString(), [$arg->value]))); return new UnionType([
$scope->resolveTypeByName(new Name(DB::filterTableName($staticCall->name->toString(), [$arg->value]))),
new NullType(),
]);
} else { } else {
// Let PHPStan handle it normally // Let PHPStan handle it normally
return \PHPStan\Reflection\ParametersAcceptorSelector::selectFromArgs($scope, $staticCall->args, $methodReflection->getVariants())->getReturnType(); return \PHPStan\Reflection\ParametersAcceptorSelector::selectFromArgs($scope, $staticCall->args, $methodReflection->getVariants())->getReturnType();

View File

@ -69,4 +69,9 @@ class GNUsocialTestCase extends WebTestCase
); );
self::$social = new GNUsocial(...$services); self::$social = new GNUsocial(...$services);
} }
protected function getGNUsocial(): GNUsocial
{
return self::$social;
}
} }

View File

@ -161,7 +161,6 @@ class Nickname
// @codeCoverageIgnoreStart // @codeCoverageIgnoreStart
case self::CHECK_LOCAL_GROUP: case self::CHECK_LOCAL_GROUP:
throw new NotImplementedException(); throw new NotImplementedException();
break;
default: default:
throw new InvalidArgumentException(); throw new InvalidArgumentException();
// @codeCoverageIgnoreEnd // @codeCoverageIgnoreEnd

View File

@ -45,18 +45,20 @@ class Notification
public const DM = 7; public const DM = 7;
/** /**
* One of the above constants * @param int $type One of the above constants
* @param Actor $actor Who caused this notification
*/ */
private int $type; public function __construct(private int $type, private Actor $actor)
/**
* Who caused this notification
*/
private Actor $actor;
public function __construct(int $type, Actor $actor)
{ {
$this->type = $type; }
$this->actor = $actor;
public function getType(): int
{
return $this->type;
}
public function getActor(): Actor
{
return $this->actor;
} }
} }

View File

@ -26,7 +26,6 @@ namespace App\Tests\Controller;
use App\Controller\Feeds; use App\Controller\Feeds;
use App\Core\DB\DB; use App\Core\DB\DB;
use App\Core\Security; use App\Core\Security;
use App\Core\VisibilityScope;
use App\Entity\Note; use App\Entity\Note;
use App\Util\Common; use App\Util\Common;
use App\Util\Exception\ClientException; use App\Util\Exception\ClientException;
@ -86,7 +85,7 @@ class FeedsTest extends GNUsocialTestCase
$notes = Common::flattenNoteArray($result['notes']); $notes = Common::flattenNoteArray($result['notes']);
foreach ($notes as $n) { foreach ($notes as $n) {
static::assertTrue(\get_class($n) == Note::class); static::assertTrue(\get_class($n) == Note::class);
$vis = VisibilityScope::create($n->getScope()); $vis = $n->getScope();
static::assertTrue($visibility($vis)); static::assertTrue($visibility($vis));
} }
} }

View File

@ -52,7 +52,7 @@ class NoteTest extends GNUsocialTestCase
$actor2 = DB::findOneBy('actor', ['nickname' => 'taken_group']); $actor2 = DB::findOneBy('actor', ['nickname' => 'taken_group']);
$actor3 = DB::findOneBy('actor', ['nickname' => 'some_user']); $actor3 = DB::findOneBy('actor', ['nickname' => 'some_user']);
$note_visible_to_1 = DB::findBy('note', ['actor_id' => $actor1->getId(), 'content' => 'private note', 'scope' => VisibilityScope::COLLECTION], limit: 1)[0]; $note_visible_to_1 = DB::findBy('note', ['actor_id' => $actor1->getId(), 'content' => 'private note', 'scope' => VisibilityScope::COLLECTION->value], limit: 1)[0];
static::assertTrue($note_visible_to_1->isVisibleTo($actor1)); static::assertTrue($note_visible_to_1->isVisibleTo($actor1));
static::assertFalse($note_visible_to_1->isVisibleTo($actor2)); static::assertFalse($note_visible_to_1->isVisibleTo($actor2));
static::assertFalse($note_visible_to_1->isVisibleTo($actor3)); static::assertFalse($note_visible_to_1->isVisibleTo($actor3));
@ -62,7 +62,7 @@ class NoteTest extends GNUsocialTestCase
static::assertTrue($note_public->isVisibleTo($actor2)); static::assertTrue($note_public->isVisibleTo($actor2));
static::assertTrue($note_public->isVisibleTo($actor3)); static::assertTrue($note_public->isVisibleTo($actor3));
$group_note = DB::findBy('note', ['actor_id' => $actor1->getId(), 'content' => 'group note', 'scope' => VisibilityScope::GROUP], limit: 1)[0]; $group_note = DB::findBy('note', ['actor_id' => $actor1->getId(), 'content' => 'group note', 'scope' => VisibilityScope::GROUP->value], limit: 1)[0];
static::assertTrue($group_note->isVisibleTo($actor3)); static::assertTrue($group_note->isVisibleTo($actor3));
static::assertFalse($group_note->isVisibleTo($actor2)); static::assertFalse($group_note->isVisibleTo($actor2));
static::assertFalse($group_note->isVisibleTo($actor1)); static::assertFalse($group_note->isVisibleTo($actor1));