iT邦幫忙

2023 iThome 鐵人賽

DAY 20
0

對一些特殊的 function,我們會想 skip 他

例如 DispatchQueue.main.async

我們需要取得一些很特定的屬性,才會有能力去 skip

  • function name
  • some class/struct/...
  • module

instance function

從 typename 可以再度證明 instance function 是 curry function

  • kind: refFunctionMethodInstance
  • name: a() -> a
  • typename: (A) -> () -> () -> A
struct A {
  func a() {}
}

static function

可以得知是 static method,且有 X.Type 的特性

  • kind: refFunctionMethodStatic
  • name:a() -> a
  • typename: (A.Type) -> () -> () -> A
 struct A {
  static func a() {}
}

Constructor

可以看出 A() 應該是 A.init() 的語法糖

以及定義很像 static function

  • secondary_symbols.kind: refFunctionConstructor
  • secondary_symbols.name: init() -> init
  • secondary_symbols.typename: (A.Type) -> () -> A -> A
A()
struct A {}

free function

這邊我們實作一個很像 static function 格式的 global function

可以發現 global function 是 .refFunctionFree

  • kind: refFunctionFree
  • name: a(_:) -> a
  • typename: (Any.Type) -> () -> () -> ``
func a(_ type: Any.Type) -> () -> () {
  return {}
}

Generic

這邊將 generic 以及 nested 一起說明

從 nested 角度來看 type 是 A.B
從 generic 角度來看 type 是 A<T>
從 generic & nested 角度來看 type 是 A<T>.B<U>
從使用者角度來看 A<T>.B<U> 還是改為 A.B 較為方便

  • kind: refFunctionMethodStatic
  • name: a(_:) -> a
  • typename: <T, U, V> (A<T>.B<U>.Type) -> (V) -> () -> A<T>.B<U> -> A.B
A<Int>.B<Int>.a(1)
struct A<T> {
  struct B<U> {
    static func a<V>(_ v: V) {}
  }
}

module

可以透過 key.modulename 取得

UIView.anmiate module 為 UIKit.UIView 而不是 UIKit


Test

最後再用測試驗證我們的想法無誤

final class SkipConceptTests: XCTestCase {
  final func testObjFunction() throws {
    let code = """
    A().a()
    struct A {
      func a() {}
    }
    """

    let client = SKClient(code: code, arguments: SDK.macosx.args)
    try prepare(client: client) { client in
      let res = try client(4)
      XCTAssertEqual(code[4 ... 6], "a()")
      
      XCTAssertEqual(res.name, "a()")
      XCTAssertEqual(res.typename, "(A) -> () -> ()")
      XCTAssertEqual(res.kind, .refFunctionMethodInstance)
    }
  }

  private func a(_ type: Any.Type) -> () -> () {
    return {}
  }

  private func temp() {
    let _ = a(Int.self)
  }

  final func testFunctionReturnClosure() throws {
    let code = """
    let x = a(Int.self)
    func a(_ type: Any.Type) -> () -> () {
      return {}
    }
    """

    let client = SKClient(code: code, arguments: SDK.macosx.args)
    try prepare(client: client) { client in
      let res = try client(8)
      XCTAssertEqual(code[8 ... 18], "a(Int.self)")
      
      XCTAssertEqual(res.name, "a(_:)")
      XCTAssertEqual(res.typename, "(Any.Type) -> () -> ()")
      XCTAssertEqual(res.kind, .refFunctionFree)
    }
  }
  
  final func testGenericFunction() throws {
    let code = """
    a(t: 1)
    func a<T>(t: T) {}
    """

    let client = SKClient(code: code, arguments: SDK.macosx.args)
    try prepare(client: client) { client in
      let res = try client(0)
      XCTAssertEqual(code[0 ... 6], "a(t: 1)")
      
      XCTAssertEqual(res.name, "a(t:)")
      XCTAssertEqual(res.typename, "<T> (t: T) -> ()")
      XCTAssertEqual(res.kind, .refFunctionFree)
    }
  }
  
  final func testStaticFunction() throws {
    let code = """
    A.a()
    struct A {
      static func a() {}
    }
    """

    let client = SKClient(code: code, arguments: SDK.macosx.args)
    try prepare(client: client) { client in
      let res = try client(2)
      XCTAssertEqual(code[2 ... 4], "a()")
      
      XCTAssertEqual(res.name, "a()")
      XCTAssertEqual(res.typename, "(A.Type) -> () -> ()")
      XCTAssertEqual(res.kind, .refFunctionMethodStatic)
    }
  }
  
  final func testGenericNestedType() throws {
    let code = """
    A<Int>.B<Int>.a(1)
    struct A<T> {
      struct B<U> {
        static func a<V>(_ v: V) {}
      }
    }
    """

    let client = SKClient(code: code, arguments: SDK.macosx.args)
    try prepare(client: client) { client in
      let res = try client(14)
      XCTAssertEqual(code[0 ... 17], "A<Int>.B<Int>.a(1)")
      
      XCTAssertEqual(res.name, "a(_:)")
      XCTAssertEqual(res.typename, "<T, U, V> (A<T>.B<U>.Type) -> (V) -> ()")
      XCTAssertEqual(res.kind, .refFunctionMethodStatic)
    }
  }
  
  
  final func testConstructor() throws {
    let code = """
    A()
    struct A {}
    """

    let client = SKClient(code: code, arguments: SDK.macosx.args)
    try prepare(client: client) { client in
      let res = try client(0)
      XCTAssertEqual(code[0 ... 2], "A()")
      
      XCTAssertEqual(res.secondary_symbols?.name, "init()")
      XCTAssertEqual(res.secondary_symbols?.typename, "(A.Type) -> () -> A")
      XCTAssertEqual(res.secondary_symbols?.kind, .refFunctionConstructor)
    }
  }
}

上一篇
Escaping Closure Detector
下一篇
實現 detect potential leak(capture)
系列文
自己的 Leak, 自己抓(swift)30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言