From d4c863d1094180a77bc9c312180f7023f357f6ca Mon Sep 17 00:00:00 2001 From: provokateurin Date: Mon, 4 May 2026 10:16:45 +0200 Subject: [PATCH 1/5] refactor(Group): Use more strict types Signed-off-by: provokateurin --- lib/private/Group/Group.php | 4 +++- lib/public/IGroup.php | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/private/Group/Group.php b/lib/private/Group/Group.php index 65aff5d225b4a..4061e464635b1 100644 --- a/lib/private/Group/Group.php +++ b/lib/private/Group/Group.php @@ -42,12 +42,14 @@ class Group implements IGroup { private bool $usersLoaded = false; public function __construct( + /** @var non-empty-string $gid */ private string $gid, /** @var list */ private array $backends, private IEventDispatcher $dispatcher, private IUserManager $userManager, private ?PublicEmitter $emitter = null, + /** @var ?non-empty-string $displayName */ protected ?string $displayName = null, ) { } @@ -63,7 +65,7 @@ public function getDisplayName(): string { foreach ($this->backends as $backend) { if ($backend instanceof IGetDisplayNameBackend) { $displayName = $backend->getDisplayName($this->gid); - if (trim($displayName) !== '') { + if ($displayName !== '') { $this->displayName = $displayName; return $this->displayName; } diff --git a/lib/public/IGroup.php b/lib/public/IGroup.php index ff98cfc8d4c07..448b9f4c8f8ce 100644 --- a/lib/public/IGroup.php +++ b/lib/public/IGroup.php @@ -16,7 +16,7 @@ */ interface IGroup { /** - * @return string + * @return non-empty-string * @since 8.0.0 */ public function getGID(): string; @@ -24,7 +24,7 @@ public function getGID(): string; /** * Returns the group display name * - * @return string + * @return non-empty-string * @since 12.0.0 */ public function getDisplayName(): string; From c428052510328140809d235e856700e5662fe327 Mon Sep 17 00:00:00 2001 From: provokateurin Date: Mon, 4 May 2026 10:17:48 +0200 Subject: [PATCH 2/5] refactor(User): Use more strict types Signed-off-by: provokateurin --- lib/private/User/DisplayNameCache.php | 3 +++ lib/private/User/LazyUser.php | 2 ++ lib/private/User/User.php | 2 ++ lib/public/IUser.php | 2 ++ lib/public/IUserManager.php | 2 +- 5 files changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/private/User/DisplayNameCache.php b/lib/private/User/DisplayNameCache.php index 674c3d14cebc9..374e8faf5758d 100644 --- a/lib/private/User/DisplayNameCache.php +++ b/lib/private/User/DisplayNameCache.php @@ -38,6 +38,9 @@ public function __construct( $this->memCache = $cacheFactory->createDistributed('displayNameMappingCache'); } + /** + * @return ?non-empty-string + */ public function getDisplayName(string $userId): ?string { if (isset($this->cache[$userId])) { return $this->cache[$userId]; diff --git a/lib/private/User/LazyUser.php b/lib/private/User/LazyUser.php index 89168b49dfd78..be1b1e14b4095 100644 --- a/lib/private/User/LazyUser.php +++ b/lib/private/User/LazyUser.php @@ -19,8 +19,10 @@ class LazyUser implements IUser { private ?IUser $user = null; public function __construct( + /** @var non-empty-string $uid */ private string $uid, private IUserManager $userManager, + /** @var ?non-empty-string $displayName */ private ?string $displayName = null, private ?UserInterface $backend = null, ) { diff --git a/lib/private/User/User.php b/lib/private/User/User.php index e54ac397b3efe..9b1361d1b569d 100644 --- a/lib/private/User/User.php +++ b/lib/private/User/User.php @@ -56,6 +56,7 @@ class User implements IUser { private IAssertion $assertion; protected ?IAccountManager $accountManager = null; + /** @var ?non-empty-string $displayName */ private ?string $displayName = null; private ?bool $enabled = null; private ?string $home = null; @@ -65,6 +66,7 @@ class User implements IUser { private ?IAvatarManager $avatarManager = null; public function __construct( + /** @var non-empty-string $uid */ private string $uid, private ?UserInterface $backend, private IEventDispatcher $dispatcher, diff --git a/lib/public/IUser.php b/lib/public/IUser.php index afbcfd2df087b..a5699b74faee5 100644 --- a/lib/public/IUser.php +++ b/lib/public/IUser.php @@ -27,6 +27,7 @@ interface IUser { /** * get the user id * + * @return non-empty-string * @since 8.0.0 */ public function getUID(): string; @@ -34,6 +35,7 @@ public function getUID(): string; /** * get the display name for the user, if no specific display name is set it will fallback to the user id * + * @return non-empty-string * @since 8.0.0 */ public function getDisplayName(): string; diff --git a/lib/public/IUserManager.php b/lib/public/IUserManager.php index 863b000e9d4ad..d37d47c9a7e85 100644 --- a/lib/public/IUserManager.php +++ b/lib/public/IUserManager.php @@ -76,7 +76,7 @@ public function get($uid); * Get the display name of a user * * @param string $uid - * @return string|null + * @return non-empty-string|null * @since 25.0.0 */ public function getDisplayName(string $uid): ?string; From 5771f4326c552149cfd25ff2f754838c394e0e5a Mon Sep 17 00:00:00 2001 From: provokateurin Date: Mon, 4 May 2026 10:18:50 +0200 Subject: [PATCH 3/5] refactor(Snowflake): Use more strict types Signed-off-by: provokateurin --- lib/private/Snowflake/SnowflakeGenerator.php | 13 +++++++++++++ lib/public/Snowflake/ISnowflakeGenerator.php | 2 ++ 2 files changed, 15 insertions(+) diff --git a/lib/private/Snowflake/SnowflakeGenerator.php b/lib/private/Snowflake/SnowflakeGenerator.php index a247700ebdee5..6e07bd72d6f61 100644 --- a/lib/private/Snowflake/SnowflakeGenerator.php +++ b/lib/private/Snowflake/SnowflakeGenerator.php @@ -13,6 +13,7 @@ use OCP\IServerInfo; use OCP\Snowflake\ISnowflakeGenerator; use Override; +use RuntimeException; /** * Nextcloud Snowflake ID generator @@ -59,10 +60,15 @@ public function minForTimeId(int $timestamp): string { return $this->packSnowflakeId($timestamp - self::TS_OFFSET, 0, 0, 0, 0); } + /** + * @psalm-suppress MoreSpecificReturnType + * @return non-empty-string + */ private function packSnowflakeId($seconds, $milliseconds, $serverId, $isCli, $sequenceId): string { if (PHP_INT_SIZE === 8) { $firstHalf = $seconds & 0x7FFFFFFF; $secondHalf = (($milliseconds & 0x3FF) << 22) | ($serverId << 13) | ($isCli << 12) | $sequenceId; + /** @psalm-suppress LessSpecificReturnStatement */ return (string)($firstHalf << 32 | $secondHalf); } @@ -85,6 +91,9 @@ private function packSnowflakeId($seconds, $milliseconds, $serverId, $isCli, $se /** * Mostly copied from Symfony: * https://github.com/symfony/symfony/blob/v7.3.4/src/Symfony/Component/Uid/BinaryUtil.php#L49 + * + * @param non-empty-list $bytes + * @return non-empty-string */ private function convertToDecimal(array $bytes): string { $base = 10; @@ -108,6 +117,10 @@ private function convertToDecimal(array $bytes): string { $bytes = $quotient; } + if ($digits === '') { + throw new RuntimeException('Empty digits: ' . var_export($bytes, true)); + } + return $digits; } diff --git a/lib/public/Snowflake/ISnowflakeGenerator.php b/lib/public/Snowflake/ISnowflakeGenerator.php index f3a8a4cabd85f..ee9a02bc486fa 100644 --- a/lib/public/Snowflake/ISnowflakeGenerator.php +++ b/lib/public/Snowflake/ISnowflakeGenerator.php @@ -39,6 +39,8 @@ interface ISnowflakeGenerator { * * Each call to this method is guaranteed to return a different ID. * + * @return non-empty-string + * * @since 33.0 */ public function nextId(): string; From 0c02e13e8a3263d2d7e2268303444ea94cae5886 Mon Sep 17 00:00:00 2001 From: provokateurin Date: Mon, 4 May 2026 10:19:07 +0200 Subject: [PATCH 4/5] refactor(L10N): Use more strict types Signed-off-by: provokateurin --- lib/private/L10N/L10N.php | 9 --------- lib/private/L10N/L10NString.php | 10 +++++++++- lib/public/IL10N.php | 6 +++--- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/lib/private/L10N/L10N.php b/lib/private/L10N/L10N.php index 25d3caab2e9ae..87740567c8359 100644 --- a/lib/private/L10N/L10N.php +++ b/lib/private/L10N/L10N.php @@ -57,15 +57,6 @@ public function getLocaleCode(): string { return $this->locale ?? ''; } - /** - * Translating - * @param string $text The text we need a translation for - * @param array|string $parameters default:array() Parameters for sprintf - * @return string Translation or the same text - * - * Returns the translation. If no translation is found, $text will be - * returned. - */ #[\Override] public function t(string $text, $parameters = []): string { if (!\is_array($parameters)) { diff --git a/lib/private/L10N/L10NString.php b/lib/private/L10N/L10NString.php index 4eeab67daa127..0d07c48f12537 100644 --- a/lib/private/L10N/L10NString.php +++ b/lib/private/L10N/L10NString.php @@ -20,6 +20,9 @@ public function __construct( ) { } + /** + * @return non-empty-string + */ public function __toString(): string { $translations = $this->l10n->getTranslations(); $identityTranslator = $this->l10n->getIdentityTranslator(); @@ -52,7 +55,12 @@ public function __toString(): string { // $count as %count% as per \Symfony\Contracts\Translation\TranslatorInterface $text = $identityTranslator->trans($identity, $parameters); - return vsprintf($text, $this->parameters); + $text = vsprintf($text, $this->parameters); + if ($text === '') { + throw new \RuntimeException('The translated text is empty: ' . $this->text); + } + + return $text; } #[\Override] diff --git a/lib/public/IL10N.php b/lib/public/IL10N.php index fcb4a1f915ce5..6c4690f9fe70a 100644 --- a/lib/public/IL10N.php +++ b/lib/public/IL10N.php @@ -19,9 +19,9 @@ interface IL10N { /** * Translating - * @param string $text The text we need a translation for - * @param array|string $parameters default:array() Parameters for sprintf - * @return string Translation or the same text + * @param non-empty-string $text The text we need a translation for + * @param array|non-empty-string $parameters default:array() Parameters for sprintf + * @return non-empty-string Translation or the same text * * Returns the translation. If no translation is found, $text will be * returned. From 667577c2bf568c2d4d4292ee62d58e2712ae9376 Mon Sep 17 00:00:00 2001 From: provokateurin Date: Tue, 7 Jul 2026 15:40:56 +0200 Subject: [PATCH 5/5] refactor(Team): Use more strict types Signed-off-by: provokateurin --- lib/public/Teams/Team.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/public/Teams/Team.php b/lib/public/Teams/Team.php index a0a2a3c8c9e59..de85a21184a97 100644 --- a/lib/public/Teams/Team.php +++ b/lib/public/Teams/Team.php @@ -20,15 +20,18 @@ class Team implements \JsonSerializable { * @since 29.0.0 */ public function __construct( + /** @var non-empty-string */ private string $teamId, + /** @var non-empty-string */ private string $displayName, + /** @var ?non-empty-string */ private ?string $link, ) { } /** * Unique identifier of the team (singleId of the circle) - * + * @return non-empty-string * @since 29.0.0 */ public function getId(): string { @@ -36,6 +39,7 @@ public function getId(): string { } /** + * @return non-empty-string * @since 29.0.0 */ public function getDisplayName(): string { @@ -43,6 +47,7 @@ public function getDisplayName(): string { } /** + * @return ?non-empty-string * @since 29.0.0 */ public function getLink(): ?string {