Fix various small errors when running in the Swift 6 language mode (#4109)

* Fix various small errors when running in the Swift 6 language mode

* Make the `TargetConfiguration` run on the main actor.

* Fixed a comment

* Add a comment as to why we can't make the whole NSE a main actor.

* Fix the unit tests

* Fix `blankLinesAtStartOfScope` swiftformat error.
This commit is contained in:
Stefan Ceriu
2025-05-13 11:43:47 +03:00
committed by GitHub
parent e1984ccdc0
commit 5af330cf6e
11 changed files with 47 additions and 45 deletions
@@ -7,6 +7,7 @@
import MatrixRustSDK import MatrixRustSDK
@MainActor
enum Target: String { enum Target: String {
case mainApp = "elementx" case mainApp = "elementx"
case nse case nse
@@ -11,7 +11,7 @@ enum ExpiringTaskRunnerError: Error {
case timeout case timeout
} }
actor ExpiringTaskRunner<T> { actor ExpiringTaskRunner<T: Sendable> {
private var continuation: CheckedContinuation<T, Error>? private var continuation: CheckedContinuation<T, Error>?
private var task: () async throws -> T private var task: () async throws -> T
@@ -9,34 +9,34 @@ import Foundation
enum BlockquoteAttribute: AttributedStringKey { enum BlockquoteAttribute: AttributedStringKey {
typealias Value = Bool typealias Value = Bool
static var name = "MXBlockquoteAttribute" static let name = "MXBlockquoteAttribute"
} }
enum UserIDAttribute: AttributedStringKey { enum UserIDAttribute: AttributedStringKey {
typealias Value = String typealias Value = String
static var name = "MXUserIDAttribute" static let name = "MXUserIDAttribute"
} }
/// This attribute is used to help the composer convert a mention into to a markdown link before sending /// This attribute is used to help the composer convert a mention into to a markdown link before sending
/// the message. It doesn't interact mention pills, as these fetch display names live from the room. /// the message. It doesn't interact mention pills, as these fetch display names live from the room.
enum UserDisplayNameAttribute: AttributedStringKey { enum UserDisplayNameAttribute: AttributedStringKey {
typealias Value = String typealias Value = String
static var name = "MXUserDisplayNameAttribute" static let name = "MXUserDisplayNameAttribute"
} }
enum RoomDisplayNameAttribute: AttributedStringKey { enum RoomDisplayNameAttribute: AttributedStringKey {
typealias Value = String typealias Value = String
static var name = "MXRoomDisplayNameAttribute" static let name = "MXRoomDisplayNameAttribute"
} }
enum RoomIDAttribute: AttributedStringKey { enum RoomIDAttribute: AttributedStringKey {
typealias Value = String typealias Value = String
static var name = "MXRoomIDAttribute" static let name = "MXRoomIDAttribute"
} }
enum RoomAliasAttribute: AttributedStringKey { enum RoomAliasAttribute: AttributedStringKey {
typealias Value = String typealias Value = String
static var name = "MXRoomAliasAttribute" static let name = "MXRoomAliasAttribute"
} }
enum EventOnRoomIDAttribute: AttributedStringKey { enum EventOnRoomIDAttribute: AttributedStringKey {
@@ -45,7 +45,7 @@ enum EventOnRoomIDAttribute: AttributedStringKey {
let eventID: String let eventID: String
} }
static var name = "MXEventOnRoomIDAttribute" static let name = "MXEventOnRoomIDAttribute"
} }
enum EventOnRoomAliasAttribute: AttributedStringKey { enum EventOnRoomAliasAttribute: AttributedStringKey {
@@ -54,12 +54,12 @@ enum EventOnRoomAliasAttribute: AttributedStringKey {
let eventID: String let eventID: String
} }
static var name = "MXEventOnRoomAliasAttribute" static let name = "MXEventOnRoomAliasAttribute"
} }
enum AllUsersMentionAttribute: AttributedStringKey { enum AllUsersMentionAttribute: AttributedStringKey {
typealias Value = Bool typealias Value = Bool
static var name = "MXAllUsersMentionAttribute" static let name = "MXAllUsersMentionAttribute"
} }
// periphery: ignore - required to make NSAttributedString to AttributedString conversion even if not used directly // periphery: ignore - required to make NSAttributedString to AttributedString conversion even if not used directly
+4 -6
View File
@@ -9,13 +9,11 @@
import Foundation import Foundation
import MatrixRustSDK import MatrixRustSDK
/** /// Logging utility that provies multiple logging levels as well as file output and rolling.
Logging utility that provies multiple logging levels as well as file output and rolling. /// Its purpose is to provide a common entry for customizing logging and should be used throughout the code.
Its purpose is to provide a common entry for customizing logging and should be used throughout the code.
*/
enum MXLog { enum MXLog {
private static var rootSpan: Span! private nonisolated(unsafe) static var rootSpan: Span!
private static var currentTarget: String! private nonisolated(unsafe) static var currentTarget: String!
static func configure(currentTarget: String) { static func configure(currentTarget: String) {
self.currentTarget = currentTarget self.currentTarget = currentTarget
@@ -32,12 +32,12 @@ enum MatrixEntityRegex: String {
} }
// swiftlint:disable force_try // swiftlint:disable force_try
static var homeserverRegex = try! NSRegularExpression(pattern: MatrixEntityRegex.homeserver.rawValue, options: .caseInsensitive) static let homeserverRegex = try! NSRegularExpression(pattern: MatrixEntityRegex.homeserver.rawValue, options: .caseInsensitive)
static var userIdentifierRegex = try! NSRegularExpression(pattern: MatrixEntityRegex.userID.rawValue, options: .caseInsensitive) static let userIdentifierRegex = try! NSRegularExpression(pattern: MatrixEntityRegex.userID.rawValue, options: .caseInsensitive)
static var roomAliasRegex = try! NSRegularExpression(pattern: MatrixEntityRegex.roomAlias.rawValue, options: .caseInsensitive) static let roomAliasRegex = try! NSRegularExpression(pattern: MatrixEntityRegex.roomAlias.rawValue, options: .caseInsensitive)
static var uriRegex = try! NSRegularExpression(pattern: MatrixEntityRegex.uri.rawValue, options: .caseInsensitive) static let uriRegex = try! NSRegularExpression(pattern: MatrixEntityRegex.uri.rawValue, options: .caseInsensitive)
static var allUsersRegex = try! NSRegularExpression(pattern: MatrixEntityRegex.allUsers.rawValue) static let allUsersRegex = try! NSRegularExpression(pattern: MatrixEntityRegex.allUsers.rawValue)
static var linkRegex = try! NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue) static let linkRegex = try! NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue)
// swiftlint:enable force_try // swiftlint:enable force_try
static func isMatrixHomeserver(_ homeserver: String) -> Bool { static func isMatrixHomeserver(_ homeserver: String) -> Bool {
@@ -55,7 +55,6 @@ class EmojiPickerScreenViewModel: EmojiPickerScreenViewModelType, EmojiPickerScr
private func convert(emojiCategories: [EmojiCategory]) -> [EmojiPickerEmojiCategoryViewData] { private func convert(emojiCategories: [EmojiCategory]) -> [EmojiPickerEmojiCategoryViewData] {
emojiCategories.compactMap { emojiCategory in emojiCategories.compactMap { emojiCategory in
let emojisViewData: [EmojiPickerEmojiViewData] = emojiCategory.emojis.compactMap { emojiItem in let emojisViewData: [EmojiPickerEmojiViewData] = emojiCategory.emojis.compactMap { emojiItem in
EmojiPickerEmojiViewData(id: emojiItem.id, value: emojiItem.unicode) EmojiPickerEmojiViewData(id: emojiItem.id, value: emojiItem.unicode)
} }
@@ -6,11 +6,12 @@
// //
import Foundation import Foundation
import MatrixRustSDK
@preconcurrency import MatrixRustSDK
/// A wrapper around Rust's `MediaFileHandle` type that provides us with a /// A wrapper around Rust's `MediaFileHandle` type that provides us with a
/// media file that is stored unencrypted in a temporary location for previewing. /// media file that is stored unencrypted in a temporary location for previewing.
class MediaFileHandleProxy { final class MediaFileHandleProxy: Sendable {
/// The underlying handle for the file. /// The underlying handle for the file.
private let handle: MediaFileHandleProtocol private let handle: MediaFileHandleProtocol
@@ -7,9 +7,10 @@
import Combine import Combine
import Foundation import Foundation
import MatrixRustSDK
import UIKit import UIKit
@preconcurrency import MatrixRustSDK
private final class MediaRequest { private final class MediaRequest {
var continuations: [CheckedContinuation<Data, Error>] = [] var continuations: [CheckedContinuation<Data, Error>] = []
} }
@@ -6,9 +6,9 @@
// //
import Foundation import Foundation
import MatrixRustSDK @preconcurrency import MatrixRustSDK
struct MediaSourceProxy: Hashable { struct MediaSourceProxy: Hashable, Sendable {
/// The media source provided by Rust. /// The media source provided by Rust.
let underlyingSource: MediaSource let underlyingSource: MediaSource
/// The media's mime type, used when loading the media's file. /// The media's mime type, used when loading the media's file.
@@ -27,16 +27,18 @@ import UserNotifications
// called on the same instance of `NotificationService` as a previous // called on the same instance of `NotificationService` as a previous
// notification. // notification.
private let settings: CommonSettingsProtocol = AppSettings()
private let keychainController = KeychainController(service: .sessions,
accessGroup: InfoPlistReader.main.keychainAccessGroupIdentifier)
class NotificationServiceExtension: UNNotificationServiceExtension { class NotificationServiceExtension: UNNotificationServiceExtension {
private var notificationHandler: NotificationHandler? private var notificationHandler: NotificationHandler?
private let appHooks = AppHooks() private let appHooks = AppHooks()
private let settings: CommonSettingsProtocol = AppSettings()
private let keychainController = KeychainController(service: .sessions,
accessGroup: InfoPlistReader.main.keychainAccessGroupIdentifier)
// We can make the whole NSE a MainActor after https://github.com/swiftlang/swift-evolution/blob/main/proposals/0371-isolated-synchronous-deinit.md
// otherwise we wouldn't be able to log the tag in the deinit.
deinit { deinit {
ExtensionLogger.logMemory(with: tag) ExtensionLogger.logMemory(with: tag)
MXLog.info("\(tag) deinit") MXLog.info("\(tag) deinit")
@@ -61,7 +63,8 @@ class NotificationServiceExtension: UNNotificationServiceExtension {
return contentHandler(request.content) return contentHandler(request.content)
} }
Target.nse.configure(logLevel: settings.logLevel, traceLogPacks: settings.traceLogPacks) Task {
await Target.nse.configure(logLevel: settings.logLevel, traceLogPacks: settings.traceLogPacks)
MXLog.info("\(tag) #########################################") MXLog.info("\(tag) #########################################")
@@ -69,7 +72,6 @@ class NotificationServiceExtension: UNNotificationServiceExtension {
MXLog.info("\(tag) Received payload: \(request.content.userInfo)") MXLog.info("\(tag) Received payload: \(request.content.userInfo)")
Task {
do { do {
let userSession = try await NSEUserSession(credentials: credentials, let userSession = try await NSEUserSession(credentials: credentials,
roomID: roomID, roomID: roomID,
+4 -4
View File
@@ -22,7 +22,7 @@ class LoggingTests: XCTestCase {
let target = "tests" let target = "tests"
XCTAssertTrue(Tracing.logFiles.isEmpty) XCTAssertTrue(Tracing.logFiles.isEmpty)
Target.tests.configure(logLevel: .info, traceLogPacks: []) await Target.tests.configure(logLevel: .info, traceLogPacks: [])
// There is something weird with Rust logging where the file writing handle doesn't // There is something weird with Rust logging where the file writing handle doesn't
// notice that the file it is writing to was deleted, so we can't run these checks // notice that the file it is writing to was deleted, so we can't run these checks
@@ -34,7 +34,7 @@ class LoggingTests: XCTestCase {
try validateTargetName(target) try validateTargetName(target)
try validateRoomSummaryContentIsRedacted() try validateRoomSummaryContentIsRedacted()
try validateTimelineContentIsRedacted() try await validateTimelineContentIsRedacted()
try validateRustMessageContentIsRedacted() try validateRustMessageContentIsRedacted()
} }
@@ -114,7 +114,7 @@ class LoggingTests: XCTestCase {
XCTAssertFalse(content.contains(heroName)) XCTAssertFalse(content.contains(heroName))
} }
func validateTimelineContentIsRedacted() throws { func validateTimelineContentIsRedacted() async throws {
// Given timeline items that contain text // Given timeline items that contain text
let textAttributedString = "TextAttributed" let textAttributedString = "TextAttributed"
let textMessage = TextRoomTimelineItem(id: .randomEvent, let textMessage = TextRoomTimelineItem(id: .randomEvent,
@@ -174,7 +174,7 @@ class LoggingTests: XCTestCase {
contentType: nil)) contentType: nil))
// When logging that value // When logging that value
Target.tests.configure(logLevel: .info, traceLogPacks: []) await Target.tests.configure(logLevel: .info, traceLogPacks: [])
MXLog.info(textMessage) MXLog.info(textMessage)
MXLog.info(noticeMessage) MXLog.info(noticeMessage)