Skip to content

Commit 1735724

Browse files
committed
Add orion:supr_tramp
1 parent 225c463 commit 1735724

File tree

6 files changed

+45
-23
lines changed

6 files changed

+45
-23
lines changed

Sources/Orion/ClassHook+Deinit.swift

+4
Original file line numberDiff line numberDiff line change
@@ -68,4 +68,8 @@ extension _GlueClassHookTrampoline {
6868
public func deinitSuprError(file: StaticString = #file, line: UInt = #line) -> Never {
6969
orionError("Do not call `supr.deinitializer()`.", file: file, line: line)
7070
}
71+
72+
public func trampOrigError(file: StaticString = #file, line: UInt = #line) -> Never {
73+
orionError("Attempted to call orig on a supr_tramp method.", file: file, line: line)
74+
}
7175
}

Sources/OrionProcessor/OrionData.swift

+14-10
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ public struct OrionData {
1717
}
1818
return text
1919
}
20+
21+
fileprivate func fetchDirective<T: OrionDirective>(ofType type: T.Type) -> T? {
22+
guard let dir = directives.compactMap({ $0 as? T }).last else { return nil }
23+
dir.setUsed()
24+
return dir
25+
}
2026
}
2127

2228
struct ClassHook {
@@ -35,16 +41,15 @@ public struct OrionData {
3541
var superClosure: Syntax // (UnsafeRawPointer, Selector, Blah) -> Blah
3642
var superClosureUnmanaged: Syntax // (UnsafeRawPointer, Selector, Blah) -> Unmanaged<Blah>
3743

38-
var isAddition: Bool {
39-
if let directive = function.directives.compactMap({ $0 as? OrionDirectives.New }).last {
40-
directive.setUsed()
41-
return true
42-
} else {
43-
return false
44-
}
44+
func isSuprTramp() -> Bool {
45+
function.fetchDirective(ofType: OrionDirectives.SuprTramp.self) != nil
46+
}
47+
48+
func isAddition() -> Bool {
49+
function.fetchDirective(ofType: OrionDirectives.New.self) != nil
4550
}
4651

47-
var returnsRetained: Bool {
52+
func returnsRetained() -> Bool {
4853
// https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html
4954
// explains when a method should return a retained value based on the selector. Swift computes
5055
// method selectors here:
@@ -53,8 +58,7 @@ public struct OrionData {
5358
// the method identifier (Swift could add a With/And but that's not relevant to any of our
5459
// prefixes, and additional selector parts have a colon before them.)
5560

56-
if let directive = function.directives.compactMap({ $0 as? OrionDirectives.ReturnsRetained }).last {
57-
directive.setUsed()
61+
if let directive = function.fetchDirective(ofType: OrionDirectives.ReturnsRetained.self) {
5862
return directive.mode == .retained
5963
}
6064

Sources/OrionProcessor/OrionDirective.swift

+15-2
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,8 @@ enum OrionDirectives {
146146
static let all: [OrionDirective.Type] = [
147147
ReturnsRetained.self,
148148
New.self,
149-
Disable.self
149+
Disable.self,
150+
SuprTramp.self
150151
]
151152

152153
struct ReturnsRetained: OrionDirective {
@@ -185,7 +186,7 @@ enum OrionDirectives {
185186
}
186187

187188
struct Disable: OrionDirective {
188-
static var matchRule: OrionDirectiveMatchRule = .exact("disable")
189+
static let matchRule: OrionDirectiveMatchRule = .exact("disable")
189190

190191
let base: OrionDirectiveBase
191192
init(base: OrionDirectiveBase) throws {
@@ -195,4 +196,16 @@ enum OrionDirectives {
195196
}
196197
}
197198
}
199+
200+
struct SuprTramp: OrionDirective {
201+
static let matchRule: OrionDirectiveMatchRule = .exact("supr_tramp")
202+
203+
let base: OrionDirectiveBase
204+
init(base: OrionDirectiveBase) throws {
205+
self.base = base
206+
guard base.arguments.isEmpty else {
207+
throw OrionDirectiveDiagnostic("supr_tramp directive expected zero arguments, got \(base.arguments.count)")
208+
}
209+
}
210+
}
198211
}

Sources/OrionProcessor/OrionGenerator.swift

+9-7
Original file line numberDiff line numberDiff line change
@@ -87,10 +87,10 @@ public final class OrionGenerator {
8787
from method: OrionData.ClassHook.Method,
8888
className: String,
8989
index: Int
90-
) -> (orig: String?, supr: String?, main: String, activation: String) {
90+
) -> (orig: String?, supr: String?, main: String, activation: String?) {
9191
let orig: String?
9292
let supr: String?
93-
let register: String
93+
let register: String?
9494

9595
let args = arguments(for: method.function)
9696
let argsList = args.joined(separator: ", ")
@@ -99,11 +99,11 @@ public final class OrionGenerator {
9999
// order of operands matters here; we don't want to evaluate isAddition
100100
// if it's a deinitializer, so that Orion can notify the user if they
101101
// have a pointless `// orion:new`
102-
let isAddition = !method.isDeinitializer && method.isAddition
102+
let isAddition = !method.isDeinitializer && method.isAddition()
103103
let origIdent = "orion_\(isAddition ? "imp" : "orig")\(index)"
104104
let selIdent = "orion_sel\(index)"
105105

106-
let returnsRetained = !method.isDeinitializer && method.returnsRetained
106+
let returnsRetained = !method.isDeinitializer && method.returnsRetained()
107107
let takeRetained = returnsRetained ? ".takeRetainedValue()" : ""
108108
let passRetained = returnsRetained ? "Unmanaged.passRetained" : ""
109109
let methodClosure = returnsRetained ? method.methodClosureUnmanaged : method.methodClosure
@@ -137,14 +137,16 @@ public final class OrionGenerator {
137137
addMethod(\(selIdent), \(origIdent), isClassMethod: \(method.isClassMethod))
138138
"""
139139
} else {
140+
let isTramp = method.isSuprTramp()
141+
140142
// While we don't need to add @objc due to the class being @objcMembers (and the #selector
141143
// failing if the function can't be represented in objc), this results in better diagnostics
142144
// than merely having an error on the #selector line
143145
let funcOverride = "\(method.objcAttribute == nil ? "@objc " : "")\(method.function.function)"
144146

145147
orig = """
146148
\(funcOverride) {
147-
_Glue.\(origIdent)(target, _Glue.\(selIdent)\(commaArgs))\(takeRetained)
149+
\(isTramp ? "trampOrigError()" : "_Glue.\(origIdent)(target, _Glue.\(selIdent)\(commaArgs))\(takeRetained)")
148150
}
149151
"""
150152

@@ -157,7 +159,7 @@ public final class OrionGenerator {
157159
}
158160
"""
159161

160-
register = """
162+
register = isTramp ? nil : """
161163
builder.addHook(\(selIdent), \(origIdent), isClassMethod: \(method.isClassMethod)) { \(origIdent) = $0 }
162164
"""
163165
}
@@ -209,7 +211,7 @@ public final class OrionGenerator {
209211
static let storage = initializeStorage()
210212
\(indentedMains)
211213
static func activate(withClassHookBuilder builder: inout _GlueClassHookBuilder) {
212-
\(registers.joined(separator: "\n "))
214+
\(registers.compactMap { $0 }.joined(separator: "\n "))
213215
}
214216
}
215217
}

Tests/OrionTests/ClassHookTests.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,8 @@ class InheritedHook: ClassHook<InheritedClass> {
7979
}
8080

8181
class InitHook: ClassHook<InitClass> {
82-
// just a placeholder to allow forwarding
83-
func `init`() -> Target { orig.`init`() }
82+
// orion:supr_tramp
83+
func `init`() -> Target { fatalError() }
8484

8585
func `init`(withX x: Int32) -> Target {
8686
let this = supr.`init`()

Tests/OrionTests/Generated.xc.swift

+1-2
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ extension InitHook {
221221

222222
final class OrigType: InitHook, _GlueClassHookTrampoline {
223223
@objc override func `init`() -> Target {
224-
_Glue.orion_orig1(target, _Glue.orion_sel1)
224+
trampOrigError()
225225
}
226226

227227
@objc override func `init`(withX arg1: Int32) -> Target {
@@ -256,7 +256,6 @@ extension InitHook {
256256
}
257257

258258
static func activate(withClassHookBuilder builder: inout _GlueClassHookBuilder) {
259-
builder.addHook(orion_sel1, orion_orig1, isClassMethod: false) { orion_orig1 = $0 }
260259
builder.addHook(orion_sel2, orion_orig2, isClassMethod: false) { orion_orig2 = $0 }
261260
}
262261
}

0 commit comments

Comments
 (0)