Add catchingExceptions method to replace runCatching (#4797)

- Add `runCatchingExceptions` and `mapCatchingExceptions` to replace `runCatching` and `mapCatching`.
- Make `tryOrNull { ... }` catch only exceptions too.
- Apply the changes to the whole project.
- Add new Rust fakes for tests to handle the code that's now unblocked - previously it just threw an `UnsatisfiedLinkError` which we ignored.
- Add a new `detekt-rules` project with a `RunCatchingRule` to prevent `runCatching` and `mapCatching` usages.
This commit is contained in:
Jorge Martin Espinosa 2025-06-04 09:02:26 +02:00 committed by GitHub
parent 7816529fd7
commit efdc10e60a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
144 changed files with 716 additions and 375 deletions

View file

@ -8,6 +8,7 @@
package io.element.android.libraries.push.impl.notifications
import com.squareup.anvil.annotations.ContributesBinding
import io.element.android.libraries.core.extensions.runCatchingExceptions
import io.element.android.libraries.di.AppScope
import io.element.android.libraries.matrix.api.MatrixClientProvider
import io.element.android.libraries.matrix.api.core.SessionId
@ -54,13 +55,13 @@ class DefaultCallNotificationEventResolver @Inject constructor(
sessionId: SessionId,
notificationData: NotificationData,
forceNotify: Boolean
): Result<NotifiableEvent> = runCatching {
): Result<NotifiableEvent> = runCatchingExceptions {
val content = notificationData.content as? NotificationContent.MessageLike.CallNotify
?: throw ResolvingException("content is not a call notify")
val previousRingingCallStatus = appForegroundStateService.hasRingingCall.value
// We need the sync service working to get the updated room info
val isRoomCallActive = runCatching {
val isRoomCallActive = runCatchingExceptions {
if (content.type == CallNotifyType.RING) {
appForegroundStateService.updateHasRingingCall(true)

View file

@ -11,6 +11,8 @@ import android.content.Context
import android.net.Uri
import androidx.core.content.FileProvider
import com.squareup.anvil.annotations.ContributesBinding
import io.element.android.libraries.core.extensions.mapCatchingExceptions
import io.element.android.libraries.core.extensions.runCatchingExceptions
import io.element.android.libraries.core.log.logger.LoggerTag
import io.element.android.libraries.di.AppScope
import io.element.android.libraries.di.ApplicationContext
@ -90,7 +92,7 @@ class DefaultNotifiableEventResolver @Inject constructor(
val ids = notificationEventRequests.groupBy { it.roomId }.mapValues { (_, value) -> value.map { it.eventId } }
// TODO this notificationData is not always valid at the moment, sometimes the Rust SDK can't fetch the matching event
val notifications = client.notificationService().getNotifications(ids).mapCatching { map ->
val notifications = client.notificationService().getNotifications(ids).mapCatchingExceptions { map ->
map.mapValues { (_, notificationData) ->
notificationData.asNotifiableEvent(client, sessionId)
}
@ -112,7 +114,7 @@ class DefaultNotifiableEventResolver @Inject constructor(
private suspend fun NotificationData.asNotifiableEvent(
client: MatrixClient,
userId: SessionId,
): Result<ResolvedPushEvent> = runCatching {
): Result<ResolvedPushEvent> = runCatchingExceptions {
when (val content = this.content) {
is NotificationContent.MessageLike.RoomMessage -> {
val senderDisambiguatedDisplayName = getDisambiguatedDisplayName(content.senderId)

View file

@ -208,7 +208,7 @@ class DefaultNotificationDrawerManager @Inject constructor(
private suspend fun MatrixClient.getSafeUserProfile(): MatrixUser {
return tryOrNull(
onError = { Timber.tag(loggerTag.value).e(it, "Unable to retrieve info for user ${sessionId.value}") },
onException = { Timber.tag(loggerTag.value).e(it, "Unable to retrieve info for user ${sessionId.value}") },
operation = {
val profile = getUserProfile().getOrNull()
// displayName cannot be empty else NotificationCompat.MessagingStyle() will crash

View file

@ -11,6 +11,7 @@ import com.squareup.anvil.annotations.ContributesBinding
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import io.element.android.libraries.core.extensions.mapCatchingExceptions
import io.element.android.libraries.di.AppScope
import io.element.android.libraries.di.CacheDirectory
import io.element.android.libraries.matrix.api.MatrixClient
@ -85,7 +86,7 @@ class DefaultNotificationMediaRepo @AssistedInject constructor(
source = mediaSource,
mimeType = mimeType,
filename = filename,
).mapCatching {
).mapCatchingExceptions {
it.use { mediaFile ->
val dest = cachedFile.apply { parentFile?.mkdirs() }
if (mediaFile.persist(dest.path)) {

View file

@ -63,6 +63,7 @@ class NotificationTest @Inject constructor(
notificationClickHandler.state.first()
Timber.d("Notification clicked!")
}
@Suppress("RunCatchingNotAllowed")
runCatching {
withTimeout(30.seconds) {
job.join()

View file

@ -76,6 +76,7 @@ class PushLoopbackTest @Inject constructor(
job.cancel()
return
}
@Suppress("RunCatchingNotAllowed")
runCatching {
withTimeout(10.seconds) {
completable.await()