diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 71f1aff..e58db2e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,9 +18,9 @@ jobs: name: macOS strategy: matrix: - xcode: ['15.1'] + xcode: ['15.4'] config: ['debug', 'release'] - runs-on: macos-13 + runs-on: macos-14 steps: - uses: actions/checkout@v4 - name: Select Xcode ${{ matrix.xcode }} diff --git a/Example/Example.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Example/Example.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 5c01b15..5da8db0 100644 --- a/Example/Example.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Example/Example.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,12 +1,21 @@ { "pins" : [ + { + "identity" : "swift-issue-reporting", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-issue-reporting", + "state" : { + "revision" : "926f43898706eaa127db79ac42138e1ad7e85a3f", + "version" : "1.2.0" + } + }, { "identity" : "swift-macro-testing", "kind" : "remoteSourceControl", "location" : "https://github.com/pointfreeco/swift-macro-testing", "state" : { - "revision" : "35acd9468d40ae87e75991a18af6271e8124c261", - "version" : "0.2.1" + "revision" : "a35257b7e9ce44e92636447003a8eeefb77b145c", + "version" : "0.5.1" } }, { @@ -14,8 +23,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/pointfreeco/swift-snapshot-testing", "state" : { - "revision" : "bb0ea08db8e73324fe6c3727f755ca41a23ff2f4", - "version" : "1.14.2" + "revision" : "c097f955b4e724690f0fc8ffb7a6d4b881c9c4e3", + "version" : "1.17.2" } }, { @@ -23,17 +32,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/swiftlang/swift-syntax", "state" : { - "revision" : "74203046135342e4a4a627476dd6caf8b28fe11b", - "version" : "509.0.0" - } - }, - { - "identity" : "xctest-dynamic-overlay", - "kind" : "remoteSourceControl", - "location" : "https://github.com/pointfreeco/xctest-dynamic-overlay", - "state" : { - "revision" : "23cbf2294e350076ea4dbd7d5d047c1e76b03631", - "version" : "1.0.2" + "revision" : "4c6cc0a3b9e8f14b3ae2307c5ccae4de6167ac2c", + "version" : "600.0.0-prerelease-2024-06-12" } } ], diff --git a/Package.resolved b/Package.resolved index 93894d8..5da8db0 100644 --- a/Package.resolved +++ b/Package.resolved @@ -1,12 +1,21 @@ { "pins" : [ + { + "identity" : "swift-issue-reporting", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-issue-reporting", + "state" : { + "revision" : "926f43898706eaa127db79ac42138e1ad7e85a3f", + "version" : "1.2.0" + } + }, { "identity" : "swift-macro-testing", "kind" : "remoteSourceControl", "location" : "https://github.com/pointfreeco/swift-macro-testing", "state" : { - "revision" : "851c8b6bde2000d8051dc9aca1efee04dcc37411", - "version" : "0.4.1" + "revision" : "a35257b7e9ce44e92636447003a8eeefb77b145c", + "version" : "0.5.1" } }, { @@ -14,8 +23,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/pointfreeco/swift-snapshot-testing", "state" : { - "revision" : "8ddd519780452729c6634ad6bd0d2595938e9ea3", - "version" : "1.16.1" + "revision" : "c097f955b4e724690f0fc8ffb7a6d4b881c9c4e3", + "version" : "1.17.2" } }, { @@ -23,17 +32,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/swiftlang/swift-syntax", "state" : { - "revision" : "08a2f0a9a30e0f705f79c9cfaca1f68b71bdc775", - "version" : "510.0.0" - } - }, - { - "identity" : "xctest-dynamic-overlay", - "kind" : "remoteSourceControl", - "location" : "https://github.com/pointfreeco/xctest-dynamic-overlay", - "state" : { - "revision" : "b13b1d1a8e787a5ffc71ac19dcaf52183ab27ba2", - "version" : "1.1.1" + "revision" : "4c6cc0a3b9e8f14b3ae2307c5ccae4de6167ac2c", + "version" : "600.0.0-prerelease-2024-06-12" } } ], diff --git a/Package.swift b/Package.swift index cbc1f62..66a603f 100644 --- a/Package.swift +++ b/Package.swift @@ -15,8 +15,8 @@ let package = Package( .library(name: "Perception", targets: ["Perception"]) ], dependencies: [ + .package(url: "https://github.com/pointfreeco/swift-issue-reporting", from: "1.2.0"), .package(url: "https://github.com/pointfreeco/swift-macro-testing", from: "0.1.0"), - .package(url: "https://github.com/pointfreeco/xctest-dynamic-overlay", from: "1.0.0"), .package(url: "https://github.com/swiftlang/swift-syntax", "509.0.0"..<"601.0.0-prerelease"), ], targets: [ @@ -24,7 +24,7 @@ let package = Package( name: "Perception", dependencies: [ "PerceptionMacros", - .product(name: "XCTestDynamicOverlay", package: "xctest-dynamic-overlay"), + .product(name: "IssueReporting", package: "swift-issue-reporting"), ] ), .testTarget( diff --git a/Sources/Perception/Internal/RuntimeWarning.swift b/Sources/Perception/Internal/RuntimeWarning.swift deleted file mode 100644 index bdad673..0000000 --- a/Sources/Perception/Internal/RuntimeWarning.swift +++ /dev/null @@ -1,67 +0,0 @@ -import Foundation - -@_transparent -@usableFromInline -@inline(__always) -func runtimeWarn( - _ message: @autoclosure () -> String, - category: String? = "Perception" -) { - #if DEBUG - let message = message() - let category = category ?? "Runtime Warning" - if _XCTIsTesting { - XCTFail(message) - } else { - #if canImport(os) - os_log( - .fault, - dso: dso.value, - log: OSLog(subsystem: "com.apple.runtime-issues", category: category), - "%@", - message - ) - #else - fputs("\(formatter.string(from: Date())) [\(category)] \(message)\n", stderr) - #endif - } - #endif -} - -#if DEBUG - import XCTestDynamicOverlay - - #if canImport(os) - import os - - // NB: Xcode runtime warnings offer a much better experience than traditional assertions and - // breakpoints, but Apple provides no means of creating custom runtime warnings ourselves. - // To work around this, we hook into SwiftUI's runtime issue delivery mechanism, instead. - // - // Feedback filed: https://gist.github.com/stephencelis/a8d06383ed6ccde3e5ef5d1b3ad52bbc - @usableFromInline - let dso = UncheckedSendable({ - let count = _dyld_image_count() - for i in 0..( _ subject: Subject, keyPath: KeyPath, - file: StaticString = #file, - line: UInt = #line + fileID: StaticString = #fileID, + filePath: StaticString = #filePath, + line: UInt = #line, + column: UInt = #column ) { #if DEBUG && canImport(SwiftUI) - self.perceptionCheck(file: file, line: line) + self.perceptionCheck( + fileID: fileID, + filePath: filePath, + line: line, + column: column + ) #endif #if canImport(Observation) if #available(iOS 17, macOS 14, tvOS 17, watchOS 10, *), !isObservationBeta { @@ -191,14 +199,19 @@ extension PerceptionRegistrar: Hashable { #if DEBUG && canImport(SwiftUI) extension PerceptionRegistrar { - fileprivate func perceptionCheck(file: StaticString, line: UInt) { + fileprivate func perceptionCheck( + fileID: StaticString, + filePath: StaticString, + line: UInt, + column: UInt + ) { if self.isPerceptionCheckingEnabled, Perception.isPerceptionCheckingEnabled, !_PerceptionLocals.isInPerceptionTracking, !_PerceptionLocals.skipPerceptionChecking, - self.isInSwiftUIBody(file: file, line: line) + self.isInSwiftUIBody(file: filePath, line: line) { - runtimeWarn( + reportIssue( """ Perceptible state was accessed but is not being tracked. Track changes to state by \ wrapping your view in a 'WithPerceptionTracking' view. diff --git a/Sources/PerceptionMacros/PerceptibleMacro.swift b/Sources/PerceptionMacros/PerceptibleMacro.swift index efce422..9691ec1 100644 --- a/Sources/PerceptionMacros/PerceptibleMacro.swift +++ b/Sources/PerceptionMacros/PerceptibleMacro.swift @@ -49,10 +49,19 @@ public struct PerceptibleMacro { """ internal nonisolated func access( keyPath: KeyPath<\(perceptibleType), Member>, - file: StaticString = #file, - line: UInt = #line + fileID: StaticString = #fileID, + filePath: StaticString = #filePath, + line: UInt = #line, + column: UInt = #column ) { - \(raw: registrarVariableName).access(self, keyPath: keyPath, file: file, line: line) + \(raw: registrarVariableName).access( + self, + keyPath: keyPath, + fileID: fileID, + filePath: filePath, + line: line, + column: column + ) } """ } diff --git a/Tests/PerceptionMacrosTests/PerceptionMacrosTests.swift b/Tests/PerceptionMacrosTests/PerceptionMacrosTests.swift index e6abb37..c760e5f 100644 --- a/Tests/PerceptionMacrosTests/PerceptionMacrosTests.swift +++ b/Tests/PerceptionMacrosTests/PerceptionMacrosTests.swift @@ -56,10 +56,19 @@ internal nonisolated func access( keyPath: KeyPath, - file: StaticString = #file, - line: UInt = #line + fileID: StaticString = #fileID, + filePath: StaticString = #filePath, + line: UInt = #line, + column: UInt = #column ) { - _$perceptionRegistrar.access(self, keyPath: keyPath, file: file, line: line) + _$perceptionRegistrar.access( + self, + keyPath: keyPath, + fileID: fileID, + filePath: filePath, + line: line, + column: column + ) } internal nonisolated func withMutation( diff --git a/Tests/PerceptionTests/RuntimeWarningTests.swift b/Tests/PerceptionTests/RuntimeWarningTests.swift index fa7bf23..3e14f39 100644 --- a/Tests/PerceptionTests/RuntimeWarningTests.swift +++ b/Tests/PerceptionTests/RuntimeWarningTests.swift @@ -612,8 +612,8 @@ private func expectRuntimeWarning(failingBlock: () -> R) -> R { XCTExpectFailure(failingBlock: failingBlock) { $0.compactDescription == """ - Perceptible state was accessed but is not being tracked. Track changes to state by \ - wrapping your view in a 'WithPerceptionTracking' view. + failed - Perceptible state was accessed but is not being tracked. Track changes to state \ + by wrapping your view in a 'WithPerceptionTracking' view. """ } }