diff --git a/Sources/LeakDetect/Arguments+Ex.swift b/Sources/LeakDetect/Arguments+Ex.swift index a5918a5..75de123 100644 --- a/Sources/LeakDetect/Arguments+Ex.swift +++ b/Sources/LeakDetect/Arguments+Ex.swift @@ -10,26 +10,6 @@ import Foundation import SKClient import PathKit -extension Reporter: ExpressibleByArgument { - public init?(argument: String) { - - switch argument { - case "xcode": - self = .xcode - case "vscode": - self = .vscode - default: - self = .custom { _, _ in } - } - } - public var defaultValueDescription: String { "vscode" } - - public static var allValueStrings: [String] { ["xcode", "vscode", "custom"] } - public static var defaultCompletionKind: CompletionKind { .list(allValueStrings) } - - static let all: String = "xcode|vscode|custom" -} - extension SDK: ExpressibleByArgument {} public enum TargetType: String, CaseIterable, ExpressibleByArgument { diff --git a/Sources/LeakDetect/Command.swift b/Sources/LeakDetect/Command.swift index 1ebc83a..8d0befb 100644 --- a/Sources/LeakDetect/Command.swift +++ b/Sources/LeakDetect/Command.swift @@ -95,8 +95,8 @@ struct Command: AsyncParsableCommand { switch reporter { case .custom where github: let githubAction = GithubAtionReporter(base: base) - let reporter = Reporter.custom { [weak githubAction] location, _ in - githubAction?.add(location) + let reporter = Reporter.custom { [weak githubAction] result in + githubAction?.add(result) } return (reporter, githubAction) case .xcode: fallthrough diff --git a/Sources/LeakDetect/GitAction.swift b/Sources/LeakDetect/GitAction.swift index cf5c44f..f849ef7 100644 --- a/Sources/LeakDetect/GitAction.swift +++ b/Sources/LeakDetect/GitAction.swift @@ -1,5 +1,5 @@ // -// Env.swift +// GithubAtionReporter.swift // // // Created by Yume on 2023/8/28. @@ -7,6 +7,7 @@ import Foundation import PathKit +import LeakDetectKit import SKClient /// [Context](https://docs.github.com/en/actions/learn-github-actions/contexts#github-context) @@ -60,16 +61,16 @@ class GithubAtionReporter { let issue: String let auth: String - private(set) var codes: [CodeLocation] = [] - func add(_ code: CodeLocation) { - if let line = code.location.line, let col = code.location.column { - let path = rPath(code) - let target = code.syntax?.withoutTrivia().description ?? "_" + private(set) var codes: [LeakResult] = [] + func add(_ result: LeakResult) { + let location = result.location + if let line = location.location.line, let col = location.location.column { + let path = rPath(location) print(""" - ::warning file=\(path),line=\(line),col=\(col)::\(target)" + ::warning file=\(path),line=\(line),col=\(col)::\(result.reportReason) """) } - codes.append(code) + codes.append(result) } /// base: https://github.com/ @@ -78,7 +79,8 @@ class GithubAtionReporter { /// sha: 9fb49184787fe2bfbd0802bf87xxxxx /// file: Sources/LeakDetect/Command.swift /// line: #L10-L20 - private func path(_ code: CodeLocation) -> String { + private func path(_ result: LeakResult) -> String { + let code = result.location func lines(_ code: CodeLocation) -> String { guard let line = code.location.line else { return "" @@ -95,15 +97,17 @@ class GithubAtionReporter { """ } - private func comment(code: CodeLocation) -> String { + private func comment(_ result: LeakResult) -> String { + let code = result.location return """ - \(path(code)) + \(path(result)) > [!WARNING] > Line: \(code.location.line ?? -1) > Column: \(code.location.column ?? -1) - > Target: \(code.syntax?.withoutTrivia().description ?? "") + > Target: \(result.targetName ?? "") + > Reason: \(result.reason) """ } diff --git a/Sources/LeakDetect/Reporter.swift b/Sources/LeakDetect/Reporter.swift new file mode 100644 index 0000000..350fa98 --- /dev/null +++ b/Sources/LeakDetect/Reporter.swift @@ -0,0 +1,49 @@ +// +// File.swift +// +// +// Created by Yume on 2023/9/7. +// + +import Foundation +import LeakDetectKit +import ArgumentParser + +public enum Reporter { + public typealias R = (LeakResult) -> Void + + case xcode + case vscode + case custom(R) + + public func report(_ result: LeakResult) { + switch self { + case .vscode: + print("\(result.location.reportVSCode) \(result.reason)") + case .xcode: + print("\(result.location.reportXCode) \(result.reason)") + case let .custom(report): + report(result) + } + } +} + +extension Reporter: ExpressibleByArgument { + public init?(argument: String) { + + switch argument { + case "xcode": + self = .xcode + case "vscode": + self = .vscode + default: + self = .custom { _ in } + } + } + public var defaultValueDescription: String { "vscode" } + + public static var allValueStrings: [String] { ["xcode", "vscode", "custom"] } + public static var defaultCompletionKind: CompletionKind { .list(allValueStrings) } + + static let all: String = "xcode|vscode|custom" +} diff --git a/Sources/LeakDetectKit/LeakResult.swift b/Sources/LeakDetectKit/LeakResult.swift index cc1b53a..3cbb3db 100644 --- a/Sources/LeakDetectKit/LeakResult.swift +++ b/Sources/LeakDetectKit/LeakResult.swift @@ -19,14 +19,22 @@ public struct LeakResult { self.verbose = verbose } - var syntax: String? { + public var targetName: String? { location.syntax?.withoutTrivia().description } - var reportReason: String { - "Target: `\(syntax ?? "")`, Reason: \(reason)" + public var reportReason: String { + "Target: `\(targetName ?? "")`, Reason: \(reason)" + } + + public var testLocation: String? { + guard + let targetName, + let line = location.location.line, + let col = location.location.column + else {return nil} + return "\(targetName):\(line):\(col)" } - } public extension Reporter { diff --git a/Sources/LeakDetectKit/SourceKit/SDK+Target.swift b/Sources/LeakDetectKit/SourceKit/SDK+Target.swift index 1b017e1..222b19c 100644 --- a/Sources/LeakDetectKit/SourceKit/SDK+Target.swift +++ b/Sources/LeakDetectKit/SourceKit/SDK+Target.swift @@ -21,10 +21,10 @@ extension SDK { case .iphoneos: /// arm64-apple-ios11.0 - return ["-target", "arm64-apple-ios"] + return ["-target", "arm64-apple-ios11.0"] case .iphonesimulator: /// x86_64-apple-ios16.2-simulator - return ["-target", "x86_64-apple-ios-simulator"] + return ["-target", "x86_64-apple-ios11.0-simulator"] // TODO: case .watchos: diff --git a/Tests/LeakDetectTests/Assign/AssignClosureVisitorTests.swift b/Tests/LeakDetectTests/Assign/AssignClosureVisitorTests.swift index 3c97409..9baa492 100644 --- a/Tests/LeakDetectTests/Assign/AssignClosureVisitorTests.swift +++ b/Tests/LeakDetectTests/Assign/AssignClosureVisitorTests.swift @@ -13,19 +13,18 @@ import XCTest final class AssignClosureVisitorTests: XCTestCase { func testNormal() throws { let path: String = resource(file: "AssignClosure.swift.data") - let client = try SKClient(path: path) - let visitor = AssignClosureVisitor(client: client) - visitor.walk(client.sourceFile) - let results = visitor.results.map(\.location) + let pipeline = try Pipeline(path, SDK.iphoneos.args + [path]) + let results = try pipeline.detectAssign().map(\.testLocation) let espect = [ - CodeLocation(path: path, location: SourceLocation(offset: 171, converter: client.converter)), - CodeLocation(path: path, location: SourceLocation(offset: 191, converter: client.converter)), - CodeLocation(path: path, location: SourceLocation(offset: 216, converter: client.converter)), - CodeLocation(path: path, location: SourceLocation(offset: 231, converter: client.converter)), + "abc:11:27", + "abc:12:17", + "abc:14:21", + "abc:15:11", + "def:29:100", ] - - XCTAssertEqual(results.count, espect.count) + + XCTAssertEqual(results.count, 5) XCTAssertEqual(results, espect) } } diff --git a/Tests/LeakDetectTests/Resource/AssignClosure.swift.data b/Tests/LeakDetectTests/Resource/AssignClosure.swift.data index 8e18e35..e4f4e0c 100644 --- a/Tests/LeakDetectTests/Resource/AssignClosure.swift.data +++ b/Tests/LeakDetectTests/Resource/AssignClosure.swift.data @@ -25,10 +25,13 @@ class A { let tf = UITextField() tf.addTarget(self, action: #selector(self.abc), for: .editingChanged) + + NotificationCenter.default.addObserver(forName: .init(""), object: nil, queue: .main, using: def) } func def(_ block: Closure?) {} func def(_ sel: Selector) {} func def(a: A) {} func def(any: Any?) {} -} \ No newline at end of file + func def(_ noti: Notification) {} +}