<commit_before>//  Copyright © 2017 Schibsted. All rights reserved.

import UIKit

extension NSObject {
    private static var propertiesKey = 0

    private class func localPropertyTypes() -> [String: RuntimeType] {
        // Check for memoized props
        if let memoized = objc_getAssociatedObject(self, &propertiesKey) as? [String: RuntimeType] {
            return memoized
        }
        let name = "\(self)"
        if !name.hasPrefix("("), name.contains("_") { // We don't want to mess with private stuff
            return [:]
        }
        var allProperties = [String: RuntimeType]()
        func addProperty(_ name: String, _ type: RuntimeType) {
            allProperties[name] = type
            let availability = type.availability
            switch type.type {
            case let .struct(type):
                switch type {
                case "CGPoint":
                    allProperties[name] = RuntimeType(CGPoint.self, availability)
                    for key in ["x", "y"] {
                        allProperties["\(name).\(key)"] = RuntimeType(CGFloat.self, availability)
                    }
                case "CGSize":
                    allProperties[name] = RuntimeType(CGSize.self, availability)
                    for key in ["width", "height"] {
                        allProperties["\(name).\(key)"] = RuntimeType(CGFloat.self, availability)
                    }
                case "CGVector":
                    allProperties[name] = RuntimeType(CGVector.self, availability)
                    for key in ["dx", "dy"] {
                        allProperties["\(name).\(key)"] = RuntimeType(CGFloat.self, availability)
                    }
                case "CGRect":
                    allProperties[name] = RuntimeType(CGRect.self, availability)
                    allProperties["\(name).origin"] = RuntimeType(CGPoint.self, availability)
                    allProperties["\(name).size"] = RuntimeType(CGSize.self, availability)
                    for key in [
                        "x", "y",
                        "width", "height",
                        "origin.x", "origin.y",
                        "size.width", "size.height",
                    ] {
                        allProperties["\(name).\(key)"] = RuntimeType(CGFloat.self, availability)
                    }
                case "CGAffineTransform":
                    allProperties[name] = RuntimeType(CGAffineTransform.self, availability)
                    for key in [
                        "rotation",
                        "scale", "scale.x", "scale.y",
                        "translation.x", "translation.y",
                    ] {
                        allProperties["\(name).\(key)"] = RuntimeType(CGFloat.self, availability)
                    }
                case "CATransform3D":
                    allProperties[name] = RuntimeType(CATransform3D.self, availability)
                    for key in [
                        "rotation", "rotation.x", "rotation.y", "rotation.z",
                        "scale", "scale.x", "scale.y", "scale.z",
                        "translation.x", "translation.y", "translation.z",
                        "m34", // Used for perspective
                    ] {
                        allProperties["\(name).\(key)"] = RuntimeType(CGFloat.self, availability)
                    }
                case "UIEdgeInsets":
                    allProperties[name] = RuntimeType(UIEdgeInsets.self, availability)
                    for key in ["top", "left", "bottom", "right"] {
                        allProperties["\(name).\(key)"] = RuntimeType(CGFloat.self, availability)
                    }
                case "UIOffset":
                    allProperties[name] = RuntimeType(UIOffset.self, availability)
                    for key in ["horizontal", "vertical"] {
                        allProperties["\(name).\(key)"] = RuntimeType(CGFloat.self, availability)
                    }
                case "NSDirectionalEdgeInsets":
                    if #available(iOS 11.0, *) {
                        allProperties[name] = RuntimeType(NSDirectionalEdgeInsets.self, availability)
                        for key in ["top", "leading", "bottom", "trailing"] {
                            allProperties["\(name).\(key)"] = RuntimeType(CGFloat.self, availability)
                        }
                    }
                default:
                    break
                }
            default:
                break
            }
        }
        // Gather properties
        var numberOfProperties: CUnsignedInt = 0
        if let properties = class_copyPropertyList(self, &numberOfProperties) {
            for i in 0 ..< Int(numberOfProperties) {
                let cprop = properties[i]
                let cname: UnsafePointer<Int8> = property_getName(cprop)
                if let cattribs = property_getAttributes(cprop) {
                    var name = String(cString: cname)
                    guard !name.contains("_"), // We don't want to mess with private stuff
                        allProperties[name] == nil else {
                        continue
                    }
                    // Get attributes
                    let setter = "set\(name.capitalized()):"
                    guard instancesRespond(to: Selector(setter)) else {
                        continue
                    }
                    let attribs = String(cString: cattribs).components(separatedBy: ",")
                    let objCType = String(attribs[0].unicodeScalars.dropFirst())
                    guard let type = RuntimeType(objCType: objCType) else {
                        continue
                    }
                    if case let .any(type) = type.type, type is Bool.Type,
                        let attrib = attribs.first(where: { $0.hasPrefix("Gis") }) {
                        name = String(attrib.unicodeScalars.dropFirst())
                    }
                    let typeName = type.description
                    if !typeName.hasPrefix("("), typeName.contains("_") { // We don't want to mess with private stuff
                        continue
                    }
                    addProperty(name, type)
                }
            }
        }
        // Gather setter methods
        var numberOfMethods: CUnsignedInt = 0
        if let methods = class_copyMethodList(self, &numberOfMethods) {
            let maxChars = 256
            let ctype = UnsafeMutablePointer<Int8>.allocate(capacity: maxChars)
            for i in 0 ..< Int(numberOfMethods) {
                let method = methods[i]
                let selector: Selector = method_getName(method)
                var name = "\(selector)"
                guard name.hasPrefix("set"), let colonRange = name.range(of: ":"),
                    colonRange.upperBound == name.endIndex, !name.hasPrefix("set_") else {
                    continue
                }
                name = String(name["set".endIndex ..< colonRange.lowerBound])
                let isName = "is\(name)"
                guard allProperties[isName] == nil else {
                    continue
                }
                let characters = name.unicodeScalars
                name = (characters.first.map { String($0) } ?? "").lowercased() + String(characters.dropFirst())
                guard allProperties[name] == nil else {
                    continue
                }
                method_getArgumentType(method, 2, ctype, maxChars)
                var objCType = String(cString: ctype)
                if objCType == "@", name.hasSuffix("olor") {
                    objCType = "@\"UIColor\"" // Workaround for runtime not knowing the type
                }
                guard let type = RuntimeType(objCType: objCType) else {
                    continue
                }
                if case let .any(type) = type.type, type is Bool.Type,
                    instancesRespond(to: Selector(isName)) {
                    name = isName
                }
                addProperty(name, type)
            }
            ctype.deallocate(capacity: maxChars)
        }
        // Accessibility properties (TODO: find a way to automate this)
        if conforms(to: UIAccessibilityIdentification.self) {
            addProperty("accessibilityIdentifier", .string)
        }
        addProperty("isAccessibilityElement", .bool)
        addProperty("accessibilityLabel", .string)
        // TODO: iOS 11 addProperty("accessibilityAttributedLabel", .nsAttributedString)
        addProperty("accessibilityHint", .string)
        // TODO: iOS 11 addProperty("accessibilityAttributedHint", .nsAttributedString)
        addProperty("accessibilityValue", .string)
        // TODO: iOS 11 addProperty("accessibilityAttributedValue", .nsAttributedString)
        addProperty("accessibilityTraits", .uiAccessibilityTraits)
        addProperty("accessibilityFrame", .cgRect)
        addProperty("accessibilityPath", .uiBezierPath)
        addProperty("accessibilityActivationPoint", .cgPoint)
        addProperty("accessibilityLanguage", .string)
        addProperty("accessibilityElementsHidden", .bool)
        addProperty("accessibilityViewIsModal", .bool)
        addProperty("shouldGroupAccessibilityChildren", .bool)
        addProperty("accessibilityNavigationStyle", .uiAccessibilityNavigationStyle)

        // Memoize properties
        objc_setAssociatedObject(self, &propertiesKey, allProperties, .OBJC_ASSOCIATION_RETAIN)
        return allProperties
    }

    class func allPropertyTypes(excluding baseClass: NSObject.Type = NSObject.self) -> [String: RuntimeType] {
        assert(isSubclass(of: baseClass))
        var allProperties = [String: RuntimeType]()<commit_msg>Fixed `accessibilityIdentifier` support<commit_after>//  Copyright © 2017 Schibsted. All rights reserved.

import UIKit

extension NSObject {
    private static var propertiesKey = 0

    private class func localPropertyTypes() -> [String: RuntimeType] {
        // Check for memoized props
        if let memoized = objc_getAssociatedObject(self, &propertiesKey) as? [String: RuntimeType] {
            return memoized
        }
        let name = "\(self)"
        if !name.hasPrefix("("), name.contains("_") { // We don't want to mess with private stuff
            return [:]
        }
        var allProperties = [String: RuntimeType]()
        func addProperty(_ name: String, _ type: RuntimeType) {
            allProperties[name] = type
            let availability = type.availability
            switch type.type {
            case let .struct(type):
                switch type {
                case "CGPoint":
                    allProperties[name] = RuntimeType(CGPoint.self, availability)
                    for key in ["x", "y"] {
                        allProperties["\(name).\(key)"] = RuntimeType(CGFloat.self, availability)
                    }
                case "CGSize":
                    allProperties[name] = RuntimeType(CGSize.self, availability)
                    for key in ["width", "height"] {
                        allProperties["\(name).\(key)"] = RuntimeType(CGFloat.self, availability)
                    }
                case "CGVector":
                    allProperties[name] = RuntimeType(CGVector.self, availability)
                    for key in ["dx", "dy"] {
                        allProperties["\(name).\(key)"] = RuntimeType(CGFloat.self, availability)
                    }
                case "CGRect":
                    allProperties[name] = RuntimeType(CGRect.self, availability)
                    allProperties["\(name).origin"] = RuntimeType(CGPoint.self, availability)
                    allProperties["\(name).size"] = RuntimeType(CGSize.self, availability)
                    for key in [
                        "x", "y",
                        "width", "height",
                        "origin.x", "origin.y",
                        "size.width", "size.height",
                    ] {
                        allProperties["\(name).\(key)"] = RuntimeType(CGFloat.self, availability)
                    }
                case "CGAffineTransform":
                    allProperties[name] = RuntimeType(CGAffineTransform.self, availability)
                    for key in [
                        "rotation",
                        "scale", "scale.x", "scale.y",
                        "translation.x", "translation.y",
                    ] {
                        allProperties["\(name).\(key)"] = RuntimeType(CGFloat.self, availability)
                    }
                case "CATransform3D":
                    allProperties[name] = RuntimeType(CATransform3D.self, availability)
                    for key in [
                        "rotation", "rotation.x", "rotation.y", "rotation.z",
                        "scale", "scale.x", "scale.y", "scale.z",
                        "translation.x", "translation.y", "translation.z",
                        "m34", // Used for perspective
                    ] {
                        allProperties["\(name).\(key)"] = RuntimeType(CGFloat.self, availability)
                    }
                case "UIEdgeInsets":
                    allProperties[name] = RuntimeType(UIEdgeInsets.self, availability)
                    for key in ["top", "left", "bottom", "right"] {
                        allProperties["\(name).\(key)"] = RuntimeType(CGFloat.self, availability)
                    }
                case "UIOffset":
                    allProperties[name] = RuntimeType(UIOffset.self, availability)
                    for key in ["horizontal", "vertical"] {
                        allProperties["\(name).\(key)"] = RuntimeType(CGFloat.self, availability)
                    }
                case "NSDirectionalEdgeInsets":
                    if #available(iOS 11.0, *) {
                        allProperties[name] = RuntimeType(NSDirectionalEdgeInsets.self, availability)
                        for key in ["top", "leading", "bottom", "trailing"] {
                            allProperties["\(name).\(key)"] = RuntimeType(CGFloat.self, availability)
                        }
                    }
                default:
                    break
                }
            default:
                break
            }
        }
        // Gather properties
        var numberOfProperties: CUnsignedInt = 0
        if let properties = class_copyPropertyList(self, &numberOfProperties) {
            for i in 0 ..< Int(numberOfProperties) {
                let cprop = properties[i]
                let cname: UnsafePointer<Int8> = property_getName(cprop)
                if let cattribs = property_getAttributes(cprop) {
                    var name = String(cString: cname)
                    guard !name.contains("_"), // We don't want to mess with private stuff
                        allProperties[name] == nil else {
                        continue
                    }
                    // Get attributes
                    let setter = "set\(name.capitalized()):"
                    guard instancesRespond(to: Selector(setter)) else {
                        continue
                    }
                    let attribs = String(cString: cattribs).components(separatedBy: ",")
                    let objCType = String(attribs[0].unicodeScalars.dropFirst())
                    guard let type = RuntimeType(objCType: objCType) else {
                        continue
                    }
                    if case let .any(type) = type.type, type is Bool.Type,
                        let attrib = attribs.first(where: { $0.hasPrefix("Gis") }) {
                        name = String(attrib.unicodeScalars.dropFirst())
                    }
                    let typeName = type.description
                    if !typeName.hasPrefix("("), typeName.contains("_") { // We don't want to mess with private stuff
                        continue
                    }
                    addProperty(name, type)
                }
            }
        }
        // Gather setter methods
        var numberOfMethods: CUnsignedInt = 0
        if let methods = class_copyMethodList(self, &numberOfMethods) {
            let maxChars = 256
            let ctype = UnsafeMutablePointer<Int8>.allocate(capacity: maxChars)
            for i in 0 ..< Int(numberOfMethods) {
                let method = methods[i]
                let selector: Selector = method_getName(method)
                var name = "\(selector)"
                guard name.hasPrefix("set"), let colonRange = name.range(of: ":"),
                    colonRange.upperBound == name.endIndex, !name.hasPrefix("set_") else {
                    continue
                }
                name = String(name["set".endIndex ..< colonRange.lowerBound])
                let isName = "is\(name)"
                guard allProperties[isName] == nil else {
                    continue
                }
                let characters = name.unicodeScalars
                name = (characters.first.map { String($0) } ?? "").lowercased() + String(characters.dropFirst())
                guard allProperties[name] == nil else {
                    continue
                }
                method_getArgumentType(method, 2, ctype, maxChars)
                var objCType = String(cString: ctype)
                if objCType == "@", name.hasSuffix("olor") {
                    objCType = "@\"UIColor\"" // Workaround for runtime not knowing the type
                }
                guard let type = RuntimeType(objCType: objCType) else {
                    continue
                }
                if case let .any(type) = type.type, type is Bool.Type,
                    instancesRespond(to: Selector(isName)) {
                    name = isName
                }
                addProperty(name, type)
            }
            ctype.deallocate(capacity: maxChars)
        }
        // Accessibility properties (TODO: find a way to automate this)
        if conforms(to: UIAccessibilityIdentification.self) ||
            self is UIView.Type || self is UIBarItem.Type || self is UIImage.Type {
            addProperty("accessibilityIdentifier", .string)
        }
        addProperty("isAccessibilityElement", .bool)
        addProperty("accessibilityLabel", .string)
        // TODO: iOS 11 addProperty("accessibilityAttributedLabel", .nsAttributedString)
        addProperty("accessibilityHint", .string)
        // TODO: iOS 11 addProperty("accessibilityAttributedHint", .nsAttributedString)
        addProperty("accessibilityValue", .string)
        // TODO: iOS 11 addProperty("accessibilityAttributedValue", .nsAttributedString)
        addProperty("accessibilityTraits", .uiAccessibilityTraits)
        addProperty("accessibilityFrame", .cgRect)
        addProperty("accessibilityPath", .uiBezierPath)
        addProperty("accessibilityActivationPoint", .cgPoint)
        addProperty("accessibilityLanguage", .string)
        addProperty("accessibilityElementsHidden", .bool)
        addProperty("accessibilityViewIsModal", .bool)
        addProperty("shouldGroupAccessibilityChildren", .bool)
        addProperty("accessibilityNavigationStyle", .uiAccessibilityNavigationStyle)

        // Memoize properties
        objc_setAssociatedObject(self, &propertiesKey, allProperties, .OBJC_ASSOCIATION_RETAIN)
        return allProperties
    }

    class func allPropertyTypes(excluding baseClass: NSObject.Type = NSObject.self) -> [String: RuntimeType] {
        assert(isSubclass(of: baseClass))
        var allProperties = [String: RuntimeType]()
{'fraction_non_alphanumeric': 0.10399837423157039, 'fraction_numerical': 0.003149926332368033, 'mean_word_length': 1.5197132616487454, 'pattern_counts': {'":': 20, '<': 13, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2936232', 'n_tokens_mistral': 5015, 'n_tokens_neox': 4622, 'n_words': 1048}