Преглед на файлове

Fix bugs in our keyword conversion support for objectivec

We have code for converting C/C++/Objc keywords that appear in protos
to convert them so that they can be compiled.
One of the things we need to be careful of is accidentally overriding methods
that Apple declares in NSObject. It turns out that we have run into issues
where we conflict with "hidden" methods in NSObject or methods added by
categories. method_dump.sh collects all of the methods we care about for
macOS and iOS and dumps them into objectivec_nsobject_methods.h which
is then included in objectivec_helpers.cc as part of the build.

Added a pile of tests to verify that conversions are happening as expected.
Dave MacLachlan преди 7 години
родител
ревизия
be83b29bdd

+ 45 - 0
objectivec/Tests/GPBMessageTests.m

@@ -1980,6 +1980,51 @@
                  EnumTestMsg_MyEnum_NegTwo);
 }
 
+- (void)testReservedWordNaming {
+  // objectivec_helpers.cc has some special handing to make sure that
+  // some "reserved" objc names get renamed in a way so they
+  // don't conflict.
+  //
+  // This "test" confirms that the expected names are generated,
+  // otherwise the test itself will fail to compile.
+  self_Class *msg = [self_Class message];
+
+  // Some ObjC/C/C++ keywords.
+  msg.className_p = msg.hasClassName_p;
+  msg.cmd = msg.hasCmd;
+  msg.nullable_p = msg.hasNullable_p;
+  msg.typeof_p = msg.hasTypeof_p;
+  msg.instancetype_p = msg.hasInstancetype_p;
+  msg.nil_p = msg.hasNil_p;
+  msg.instancetype_p = msg.hasInstancetype_p;
+  msg.public_p = msg.hasPublic_p;
+
+  // Some that would override NSObject methods
+  msg.camltype = msg.hasCamltype;
+  msg.isNsdictionary = msg.hasIsNsdictionary;
+  msg.dealloc_p = msg.hasDealloc_p;
+  msg.zone_p = msg.hasZone_p;
+  msg.accessibilityLabel_p = msg.hasAccessibilityLabel_p;
+
+  // Some that we shouldn't need to handle.
+  msg.atomic = msg.hasAtomic;
+  msg.nonatomic = msg.hasNonatomic;
+  msg.strong = msg.hasStrong;
+  msg.nullResettable = msg.hasNullResettable;
+
+  // Some that would override GPBMessage methods
+  msg.clear_p = msg.hasClear_p;
+  msg.data_p = msg.hasData_p;
+
+  // Some MacTypes
+  msg.fixed = msg.hasFixed;
+  msg.style = msg.hasStyle;
+
+  // Some C Identifiers
+  msg.generic = msg.hasGeneric;
+  msg.block = msg.hasBlock;
+}
+
 - (void)testOneBasedEnumHolder {
   // Test case for https://github.com/protocolbuffers/protobuf/issues/1453
   // Message with no explicit defaults, but a non zero default for an enum.

+ 86 - 34
objectivec/Tests/unittest_objc.proto

@@ -103,37 +103,89 @@ message self {
   }
 
   // Singular
-  optional   bool id                =  1;
-  optional   bool _cmd              =  2;
-  optional   bool in                =  3;
-  optional   bool out               =  4;
-  optional   bool inout             =  5;
-  optional   bool bycopy            =  6;
-  optional   bool byref             =  7;
-  optional   bool oneway            =  8;
-  optional   bool dealloc           =  9;
-  optional   bool zone              = 10;
-  optional   bool isProxy           = 11;
-  optional   bool copy              = 12;
-  optional   bool readonly          = 13;
-  optional   bool default           = 14;
-  optional   bool assign            = 15;
-  optional   bool getter            = 16;
-  optional   bool setter            = 17;
-  optional   bool weak              = 18;
-  optional   bool public            = 19;
-  optional   bool case              = 20;
-
-  optional   autorelease SubEnum    = 25;
-
- optional group New = 50 {
-   optional string copy = 51;
- }
-  optional group MutableCopy = 60 {
-    optional int32 extensionRegistry = 61;
+  // Objective C Keywords
+  optional bool id                =  1;
+  optional bool _cmd              =  2;
+  // super is used as submessage above
+  optional bool in                =  4;
+  optional bool out               =  5;
+  optional bool inout             =  6;
+  optional bool bycopy            =  7;
+  optional bool byref             =  8;
+  optional bool oneway            =  9;
+  optional bool self              =  10;
+  optional bool instancetype      =  11;
+  optional bool nullable          =  12;
+  optional bool nonnull           =  13;
+  optional bool nil               =  14;
+  // Nil and nil can't be in the same message
+  optional bool YES               =  16;
+  optional bool NO                =  17;
+  optional bool weak              =  18;
+
+  // Some C/C++ Keywords
+  optional bool case              = 30;
+  optional bool if                = 31;
+  optional bool and_eq            = 32;
+  optional bool public            = 33;
+  optional bool private           = 34;
+  optional bool typename          = 35;
+  optional bool static_cast       = 36;
+  optional bool typeof            = 37;
+  optional bool restrict          = 38;
+  optional bool NULL              = 39;
+
+  // Some NSObject Methods
+  optional bool dealloc           = 110;
+  optional bool isProxy           = 111;
+  optional bool copy              = 112;
+  optional bool description       = 113;
+  optional bool zone              = 114;
+  optional bool className         = 115;
+  optional bool __retain_OA       = 116;
+  optional bool CAMLType          = 117;
+  optional bool isNSDictionary__  = 118;
+  optional bool accessibilityLabel = 119;
+
+  // Some Objc "keywords" that we shouldn't
+  // have to worry about because they
+  // can only appear in specialized areas.
+  optional bool assign            = 200;
+  optional bool getter            = 201;
+  optional bool setter            = 202;
+  optional bool atomic            = 203;
+  optional bool nonatomic         = 204;
+  optional bool strong            = 205;
+  optional bool null_resettable   = 206;
+  optional bool readonly          = 207;
+
+  // Some GPBMessage methods
+  optional bool clear             = 300;
+  optional bool data              = 301;
+  optional bool descriptor        = 302;
+  optional bool delimitedData     = 303;
+
+  // Some MacTypes
+  optional bool Fixed             = 400;
+  optional bool Point             = 401;
+  optional bool FixedPoint        = 402;
+  optional bool Style             = 403;
+
+  // C/C++ reserved identifiers
+  optional bool _Generic          = 500;
+  optional bool __block           = 501;
+
+  // Try a keyword as a type
+  optional autorelease SubEnum    = 1000;
+
+  optional group New = 2000 {
+   optional string copy = 1;
+  }
+  optional group MutableCopy = 2001 {
+    optional int32 extensionRegistry = 1;
   }
 
-  extensions 90 to 94;
+  extensions 3000 to 3999;
 
 }
 
@@ -177,11 +229,11 @@ enum Time {
 }
 
 extend self {
-  repeated    int32 debugDescription    =  90 [packed = true];
-  repeated    int64 finalize            =  91 [packed = true];
-  repeated   uint32 hash                =  92 [packed = true];
-  repeated   uint64 classForCoder       =  93 [packed = true];
-  repeated   sint32 byref               =  94 [packed = true];
+  repeated    int32 debugDescription    =  3000 [packed = true];
+  repeated    int64 finalize            =  3001 [packed = true];
+  repeated   uint32 hash                =  3002 [packed = true];
+  repeated   uint64 classForCoder       =  3003 [packed = true];
+  repeated   sint32 byref               =  3004 [packed = true];
 }
 
 // Test handing of fields that start with init* since Xcode 5's ARC support

+ 1 - 0
src/Makefile.am

@@ -426,6 +426,7 @@ libprotoc_la_SOURCES =                                         \
   google/protobuf/compiler/objectivec/objectivec_message.h     \
   google/protobuf/compiler/objectivec/objectivec_message_field.cc \
   google/protobuf/compiler/objectivec/objectivec_message_field.h \
+  google/protobuf/compiler/objectivec/objectivec_nsobject_methods.h  \
   google/protobuf/compiler/objectivec/objectivec_oneof.cc      \
   google/protobuf/compiler/objectivec/objectivec_oneof.h       \
   google/protobuf/compiler/objectivec/objectivec_primitive_field.cc \

+ 179 - 0
src/google/protobuf/compiler/objectivec/method_dump.sh

@@ -0,0 +1,179 @@
+#!/bin/bash
+
+# Updates objectivec_nsobject_methods.h by generating a list of all of the properties
+# and methods on NSObject that Protobufs should not overload from iOS and macOS combined.
+#
+# The rules:
+#   - No property should ever be overloaded.
+#   - Do not overload any methods that have 0 args such as "autorelease".
+#   - Do not overload any methods that start with "set[A-Z]" and have 1 arg such as
+#     "setValuesForKeysWithDictionary:". Note that these will end up in the list as just
+#     the "proto field" name, so "setValuesForKeysWithDictionary:" will become
+#     "valuesForKeysWithDictionary".
+
+set -eu
+
+trim() {
+    local var="$*"
+    # remove leading whitespace characters
+    var="${var#"${var%%[![:space:]]*}"}"
+    # remove trailing whitespace characters
+    var="${var%"${var##*[![:space:]]}"}"
+    echo -n "$var"
+}
+
+objc_code=$(cat <<'END_CODE'
+#import <Foundation/Foundation.h>
+#import <objc/runtime.h>
+
+int main(int argc, const char * argv[]) {
+  @autoreleasepool {
+    Class cls = [NSObject class];
+
+    // List out the protocols on NSObject just so we are aware if they change.
+    unsigned int protocolCount;
+    __unsafe_unretained Protocol **protocols =
+        class_copyProtocolList(cls, &protocolCount);
+    for (unsigned int i = 0; i < protocolCount; i++) {
+      printf("// Protocol: %s\n", protocol_getName(protocols[i]));
+    }
+    free(protocols);
+
+    // Grab all the properties.
+    unsigned int propCount;
+    objc_property_t *props = class_copyPropertyList(cls, &propCount);
+    NSMutableSet *reservedNames = [[NSMutableSet alloc] init];
+    for (unsigned int i = 0; i < propCount; ++i) {
+      NSString *propertyName = [NSString stringWithUTF8String:property_getName(props[i])];
+      [reservedNames addObject:propertyName];
+    }
+    free(props);
+
+    // Note that methods have 2 defaults args (_cmd and SEL) so a method "0 arg method"
+    // actually has 2.
+    unsigned int methodCount;
+    Method *methods = class_copyMethodList(cls, &methodCount);
+    for (unsigned int i = 0; i < methodCount; ++i) {
+      int argCount = method_getNumberOfArguments(methods[i]);
+      NSString *methodName =
+          [NSString stringWithUTF8String:sel_getName(method_getName(methods[i]))];
+      if (argCount == 2) {
+        [reservedNames addObject:methodName];
+      }
+      if (argCount == 3 && [methodName hasPrefix:@"set"] && methodName.length > 4) {
+        NSString *firstLetter = [methodName substringWithRange:NSMakeRange(3,1)];
+        NSString *lowerFirstLetter = [firstLetter lowercaseString];
+        if ([lowerFirstLetter isEqual:firstLetter]) {
+          // Make sure the next letter is a capital letter so we do not take things like
+          // settingSomething:
+          continue;
+        }
+        // -5 because 3 for set, 1 for the firstLetter and 1 for the colon on the end.
+        NSString *restOfString =
+            [methodName substringWithRange:NSMakeRange(4, methodName.length - 5)];
+        methodName = [lowerFirstLetter stringByAppendingString:restOfString];
+        [reservedNames addObject:methodName];
+      }
+    }
+    free(methods);
+
+    SEL sortSelector = @selector(caseInsensitiveCompare:);
+    NSArray *array = [reservedNames.allObjects sortedArrayUsingSelector:sortSelector];
+    for (NSString *item in array) {
+      // Some items with _ in them get returned in quotes, so do not add more.
+      if ([item hasPrefix:@"\""]) {
+        printf("\t%s,\n", item.UTF8String);
+      } else {
+        printf("\t\"%s\",\n", item.UTF8String);
+      }
+    }
+  }
+  return 0;
+}
+END_CODE
+)
+
+file_header=$(cat <<'END_HEADER'
+// NSObject methods
+// Autogenerated by method_dump.sh. Do not edit by hand.
+// Date: %DATE%
+// macOS: %MACOS%
+// iOS: %IOS%
+
+const char* const kNSObjectMethodsList[] = {
+END_HEADER
+)
+
+file_footer=$(cat <<'END_FOOTER'
+};
+END_FOOTER
+)
+
+# Check to make sure we are updating the correct file.
+if [[ ! -e "objectivec_nsobject_methods.h" ]]; then
+  echo "error: Must be run in the src/google/protobuf/compiler/objectivec directory"
+  exit 1
+fi
+
+temp_dir=$(mktemp -d)
+
+echo "$objc_code" >> "$temp_dir"/method_dump.m
+
+# Compile up iphonesimulator and macos version of cmd line app.
+iphone_simulator_sdk=$(xcrun --sdk iphonesimulator --show-sdk-path)
+clang -isysroot "$iphone_simulator_sdk" -o "$temp_dir"/method_dump_ios \
+    -framework Foundation -framework UIKit "$temp_dir"/method_dump.m
+macos_sdk=$(xcrun --sdk macosx --show-sdk-path)
+clang -isysroot "$macos_sdk" -o "$temp_dir"/method_dump_macos -framework Foundation \
+    -framework Cocoa "$temp_dir"/method_dump.m
+
+# Create a device of the latest phone and iphonesimulator SDK and run our iOS cmd line.
+device_type=$(xcrun simctl list devicetypes | grep \.iPhone- | tail -1 | sed 's/.*(\(.*\))/\1/')
+# runtimes come with a space at the end (for Xcode 10) so let's trim all of our input to
+# be safe.
+device_type=$(trim "$device_type")
+runtime=$(xcrun simctl list runtimes | grep \.iOS- | tail -1 | \
+    sed 's/.*\(com\.apple.\CoreSimulator\.SimRuntime\.iOS.*\)/\1/')
+runtime=$(trim "$runtime")
+uuid=$(uuidgen)
+device_name="method_dump_device_$uuid"
+device=$(xcrun simctl create "$device_name" "$device_type" "$runtime")
+xcrun simctl spawn "$device" "$temp_dir"/method_dump_ios > "$temp_dir"/methods_unsorted_ios.txt
+xcrun simctl delete "$device"
+
+# Run the Mac version
+"$temp_dir"/method_dump_macos >> "$temp_dir"/methods_unsorted_macos.txt
+
+# Generate sorted output
+echo "$file_header" | sed -e "s|%DATE%|$(date)|" -e "s|%MACOS%|$(basename $macos_sdk)|" \
+    -e "s|%IOS%|$(basename $iphone_simulator_sdk)|" > "$temp_dir"/methods_sorted.txt
+sort -u "$temp_dir"/methods_unsorted_ios.txt \
+    "$temp_dir"/methods_unsorted_macos.txt >> "$temp_dir"/methods_sorted.txt
+echo $"$file_footer" >> "$temp_dir"/methods_sorted.txt
+
+# Check for differences. Turn off error checking because we expect diff to fail when
+# there are no differences.
+set +e
+diff_out=$(diff -I "^//.*$" "$temp_dir"/methods_sorted.txt objectivec_nsobject_methods.h)
+removed_methods=$(echo "$diff_out" | grep '^>.*$')
+set -e
+if [[ -n "$removed_methods" ]]; then
+  echo "error: Methods removed from NSObject"
+  echo "It appears that some methods may have been removed from NSObject."
+  echo "This could mean that there may be some backwards compatibility issues."
+  echo "You could potentially build apps that may not work on earlier systems than:"
+  echo "$iphone_simulator_sdk"
+  echo "$macos_sdk"
+  echo "If they declare protobuf types that use any of the following as names:"
+  echo "$removed_methods"
+  echo ""
+  echo "New Version: $temp_dir/methods_sorted.txt"
+  echo "Old Version: objectivec_nsobject_methods.h"
+  exit 1
+fi
+if [[ -n "$diff_out" ]]; then
+  echo "Added Methods:"
+  echo "$(echo "$diff_out" | grep '^<.*$' | sed -e 's/^< "\(.*\)",$/  \1/')"
+fi;
+cp "$temp_dir"/methods_sorted.txt objectivec_nsobject_methods.h
+rm -rf "$temp_dir"

+ 79 - 53
src/google/protobuf/compiler/objectivec/objectivec_helpers.cc

@@ -43,6 +43,7 @@
 
 #include <google/protobuf/stubs/hash.h>
 #include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
+#include <google/protobuf/compiler/objectivec/objectivec_nsobject_methods.h>
 #include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/io/printer.h>
@@ -170,65 +171,90 @@ string UnderscoresToCamelCase(const string& input, bool first_capitalized) {
 }
 
 const char* const kReservedWordList[] = {
-    // Objective C "keywords" that aren't in C
-    // From
-    // http://stackoverflow.com/questions/1873630/reserved-keywords-in-objective-c
-    "id", "_cmd", "super", "in", "out", "inout", "bycopy", "byref", "oneway",
-    "self",
-
-    // C/C++ keywords (Incl C++ 0x11)
-    // From http://en.cppreference.com/w/cpp/keywords
-    "and", "and_eq", "alignas", "alignof", "asm", "auto", "bitand", "bitor",
-    "bool", "break", "case", "catch", "char", "char16_t", "char32_t", "class",
-    "compl", "const", "constexpr", "const_cast", "continue", "decltype",
-    "default", "delete", "double", "dynamic_cast", "else", "enum", "explicit",
-    "export", "extern ", "false", "float", "for", "friend", "goto", "if",
-    "inline", "int", "long", "mutable", "namespace", "new", "noexcept", "not",
-    "not_eq", "nullptr", "operator", "or", "or_eq", "private", "protected",
-    "public", "register", "reinterpret_cast", "return", "short", "signed",
-    "sizeof", "static", "static_assert", "static_cast", "struct", "switch",
-    "template", "this", "thread_local", "throw", "true", "try", "typedef",
-    "typeid", "typename", "union", "unsigned", "using", "virtual", "void",
-    "volatile", "wchar_t", "while", "xor", "xor_eq",
-
-    // C99 keywords
-    // From
-    // http://publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8l.doc%2Flanguage%2Fref%2Fkeyw.htm
-    "restrict",
-
-    // Objective-C Runtime typedefs
-    // From <obc/runtime.h>
-    "Category", "Ivar", "Method", "Protocol",
-
-    // NSObject Methods
-    // new is covered by C++ keywords.
-    "description", "debugDescription", "finalize", "hash", "dealloc", "init",
-    "class", "superclass", "retain", "release", "autorelease", "retainCount",
-    "zone", "isProxy", "copy", "mutableCopy", "classForCoder",
-
-    // GPBMessage Methods
-    // Only need to add instance methods that may conflict with
-    // method declared in protos. The main cases are methods
-    // that take no arguments, or setFoo:/hasFoo: type methods.
-    "clear", "data", "delimitedData", "descriptor", "extensionRegistry",
-    "extensionsCurrentlySet", "initialized", "isInitialized", "serializedSize",
-    "sortedExtensionsInUse", "unknownFields",
-
-    // MacTypes.h names
-    "Fixed", "Fract", "Size", "LogicalAddress", "PhysicalAddress", "ByteCount",
-    "ByteOffset", "Duration", "AbsoluteTime", "OptionBits", "ItemCount",
-    "PBVersion", "ScriptCode", "LangCode", "RegionCode", "OSType",
-    "ProcessSerialNumber", "Point", "Rect", "FixedPoint", "FixedRect", "Style",
-    "StyleParameter", "StyleField", "TimeScale", "TimeBase", "TimeRecord",
+  // Note NSObject Methods:
+  // These are brought in from objectivec_nsobject_methods.h that is generated
+  // using method_dump.sh. See kNSObjectMethods below.
+
+  // Objective C "keywords" that aren't in C
+  // From
+  // http://stackoverflow.com/questions/1873630/reserved-keywords-in-objective-c
+  // with some others added on.
+  "id", "_cmd", "super", "in", "out", "inout", "bycopy", "byref", "oneway",
+  "self", "instancetype", "nullable", "nonnull", "nil", "Nil",
+  "YES", "NO", "weak",
+
+  // C/C++ keywords (Incl C++ 0x11)
+  // From http://en.cppreference.com/w/cpp/keywords
+  "and", "and_eq", "alignas", "alignof", "asm", "auto", "bitand", "bitor",
+  "bool", "break", "case", "catch", "char", "char16_t", "char32_t", "class",
+  "compl", "const", "constexpr", "const_cast", "continue", "decltype",
+  "default", "delete", "double", "dynamic_cast", "else", "enum", "explicit",
+  "export", "extern ", "false", "float", "for", "friend", "goto", "if",
+  "inline", "int", "long", "mutable", "namespace", "new", "noexcept", "not",
+  "not_eq", "nullptr", "operator", "or", "or_eq", "private", "protected",
+  "public", "register", "reinterpret_cast", "return", "short", "signed",
+  "sizeof", "static", "static_assert", "static_cast", "struct", "switch",
+  "template", "this", "thread_local", "throw", "true", "try", "typedef",
+  "typeid", "typename", "union", "unsigned", "using", "virtual", "void",
+  "volatile", "wchar_t", "while", "xor", "xor_eq",
+
+  // C99 keywords
+  // From
+  // http://publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8l.doc%2Flanguage%2Fref%2Fkeyw.htm
+  "restrict",
+
+  // GCC/Clang extension
+  "typeof",
+
+  // Not a keyword, but will break you
+  "NULL",
+
+  // Objective-C Runtime typedefs
+  // From <obc/runtime.h>
+  "Category", "Ivar", "Method", "Protocol",
+
+  // GPBMessage Methods
+  // Only need to add instance methods that may conflict with
+  // method declared in protos. The main cases are methods
+  // that take no arguments, or setFoo:/hasFoo: type methods.
+  "clear", "data", "delimitedData", "descriptor", "extensionRegistry",
+  "extensionsCurrentlySet", "initialized", "isInitialized", "serializedSize",
+  "sortedExtensionsInUse", "unknownFields",
+
+  // MacTypes.h names
+  "Fixed", "Fract", "Size", "LogicalAddress", "PhysicalAddress", "ByteCount",
+  "ByteOffset", "Duration", "AbsoluteTime", "OptionBits", "ItemCount",
+  "PBVersion", "ScriptCode", "LangCode", "RegionCode", "OSType",
+  "ProcessSerialNumber", "Point", "Rect", "FixedPoint", "FixedRect", "Style",
+  "StyleParameter", "StyleField", "TimeScale", "TimeBase", "TimeRecord",
 };
 
-std::unordered_set<string> kReservedWords =
-    MakeWordsMap(kReservedWordList, GOOGLE_ARRAYSIZE(kReservedWordList));
+// returns true is input starts with __ or _[A-Z] which are reserved identifiers
+// in C/ C++. All calls should go through UnderscoresToCamelCase before getting here
+// but this verifies and allows for future expansion if we decide to redefine what a
+// reserved C identifier is (for example the GNU list
+// https://www.gnu.org/software/libc/manual/html_node/Reserved-Names.html )
+bool IsReservedCIdentifier(const string& input) {
+  if (input.length() > 2) {
+    if (input.at(0) == '_') {
+      if (isupper(input.at(1)) || input.at(1) == '_') {
+        return true;
+      }
+    }
+  }
+  return false;
+}
 
 string SanitizeNameForObjC(const string& input,
                            const string& extension,
                            string* out_suffix_added) {
-  if (kReservedWords.count(input) > 0) {
+  static const std::unordered_set<string> kReservedWords =
+      MakeWordsMap(kReservedWordList, GOOGLE_ARRAYSIZE(kReservedWordList));
+  static const std::unordered_set<string> kNSObjectMethods =
+      MakeWordsMap(kNSObjectMethodsList, GOOGLE_ARRAYSIZE(kNSObjectMethodsList));
+  if (IsReservedCIdentifier(input) ||
+      (kReservedWords.count(input) > 0) ||
+      (kNSObjectMethods.count(input) > 0)) {
     if (out_suffix_added) *out_suffix_added = extension;
     return input + extension;
   }

+ 197 - 0
src/google/protobuf/compiler/objectivec/objectivec_nsobject_methods.h

@@ -0,0 +1,197 @@
+// NSObject methods
+// Autogenerated by method_dump.sh. Do not edit by hand.
+// Date: Thu Nov  1 14:12:16 PDT 2018
+// macOS: MacOSX10.14.sdk
+// iOS: iPhoneSimulator12.1.sdk
+
+const char* const kNSObjectMethodsList[] = {
+	"CAMLType",
+	"CA_copyRenderValue",
+	"CA_prepareRenderValue",
+	"NS_copyCGImage",
+	"NS_tiledLayerVisibleRect",
+	"___tryRetain_OA",
+	"__autorelease_OA",
+	"__dealloc_zombie",
+	"__release_OA",
+	"__retain_OA",
+	"_accessibilityFinalize",
+	"_accessibilityIsTableViewDescendant",
+	"_accessibilityUIElementSpecifier",
+	"_accessibilityUseConvenienceAPI",
+	"_allowsDirectEncoding",
+	"_asScriptTerminologyNameArray",
+	"_asScriptTerminologyNameString",
+	"_bindingAdaptor",
+	"_cfTypeID",
+	"_copyDescription",
+	"_destroyObserverList",
+	"_didEndKeyValueObserving",
+	"_implicitObservationInfo",
+	"_internalAccessibilityAttributedHint",
+	"_internalAccessibilityAttributedLabel",
+	"_internalAccessibilityAttributedValue",
+	"_isAXConnector",
+	"_isAccessibilityContainerSectionCandidate",
+	"_isAccessibilityContentNavigatorSectionCandidate",
+	"_isAccessibilityContentSectionCandidate",
+	"_isAccessibilityTopLevelNavigatorSectionCandidate",
+	"_isDeallocating",
+	"_isKVOA",
+	"_isToManyChangeInformation",
+	"_ivarDescription",
+	"_localClassNameForClass",
+	"_methodDescription",
+	"_observerStorage",
+	"_overrideUseFastBlockObservers",
+	"_propertyDescription",
+	"_releaseBindingAdaptor",
+	"_scriptingCount",
+	"_scriptingCountNonrecursively",
+	"_scriptingDebugDescription",
+	"_scriptingExists",
+	"_scriptingShouldCheckObjectIndexes",
+	"_shortMethodDescription",
+	"_shouldSearchChildrenForSection",
+	"_traitStorageList",
+	"_tryRetain",
+	"_ui_descriptionBuilder",
+	"_uikit_variesByTraitCollections",
+	"_web_description",
+	"_webkit_invokeOnMainThread",
+	"_willBeginKeyValueObserving",
+	"accessibilityActivate",
+	"accessibilityActivationPoint",
+	"accessibilityAllowsOverriddenAttributesWhenIgnored",
+	"accessibilityAssistiveTechnologyFocusedIdentifiers",
+	"accessibilityAttributedHint",
+	"accessibilityAttributedLabel",
+	"accessibilityAttributedValue",
+	"accessibilityContainer",
+	"accessibilityContainerType",
+	"accessibilityCustomActions",
+	"accessibilityCustomRotors",
+	"accessibilityDecrement",
+	"accessibilityDragSourceDescriptors",
+	"accessibilityDropPointDescriptors",
+	"accessibilityElementCount",
+	"accessibilityElementDidBecomeFocused",
+	"accessibilityElementDidLoseFocus",
+	"accessibilityElementIsFocused",
+	"accessibilityElements",
+	"accessibilityElementsHidden",
+	"accessibilityFrame",
+	"accessibilityHeaderElements",
+	"accessibilityHint",
+	"accessibilityIdentification",
+	"accessibilityIdentifier",
+	"accessibilityIncrement",
+	"accessibilityLabel",
+	"accessibilityLanguage",
+	"accessibilityLocalizedStringKey",
+	"accessibilityNavigationStyle",
+	"accessibilityOverriddenAttributes",
+	"accessibilityParameterizedAttributeNames",
+	"accessibilityPath",
+	"accessibilityPerformEscape",
+	"accessibilityPerformMagicTap",
+	"accessibilityPresenterProcessIdentifier",
+	"accessibilityShouldUseUniqueId",
+	"accessibilitySupportsNotifications",
+	"accessibilitySupportsOverriddenAttributes",
+	"accessibilityTemporaryChildren",
+	"accessibilityTraits",
+	"accessibilityValue",
+	"accessibilityViewIsModal",
+	"accessibilityVisibleArea",
+	"allPropertyKeys",
+	"allowsWeakReference",
+	"attributeKeys",
+	"autoContentAccessingProxy",
+	"autorelease",
+	"awakeFromNib",
+	"boolValueSafe",
+	"bs_encoded",
+	"bs_isPlistableType",
+	"bs_secureEncoded",
+	"cl_json_serializeKey",
+	"class",
+	"classCode",
+	"classDescription",
+	"classForArchiver",
+	"classForCoder",
+	"classForKeyedArchiver",
+	"classForPortCoder",
+	"className",
+	"clearProperties",
+	"copy",
+	"dealloc",
+	"debugDescription",
+	"defaultAccessibilityTraits",
+	"description",
+	"doubleValueSafe",
+	"entityName",
+	"exposedBindings",
+	"finalize",
+	"finishObserving",
+	"flushKeyBindings",
+	"hash",
+	"init",
+	"int64ValueSafe",
+	"isAccessibilityElement",
+	"isAccessibilityElementByDefault",
+	"isElementAccessibilityExposedToInterfaceBuilder",
+	"isFault",
+	"isNSArray__",
+	"isNSCFConstantString__",
+	"isNSData__",
+	"isNSDate__",
+	"isNSDictionary__",
+	"isNSNumber__",
+	"isNSObject__",
+	"isNSOrderedSet__",
+	"isNSSet__",
+	"isNSString__",
+	"isNSTimeZone__",
+	"isNSValue__",
+	"isProxy",
+	"mutableCopy",
+	"nilValueForKey",
+	"objectSpecifier",
+	"observationInfo",
+	"pep_onDetachedThread",
+	"pep_onMainThread",
+	"pep_onMainThreadIfNecessary",
+	"prepareForInterfaceBuilder",
+	"release",
+	"releaseOnMainThread",
+	"retain",
+	"retainCount",
+	"retainWeakReference",
+	"scriptingProperties",
+	"self",
+	"shouldGroupAccessibilityChildren",
+	"storedAccessibilityActivationPoint",
+	"storedAccessibilityContainerType",
+	"storedAccessibilityElementsHidden",
+	"storedAccessibilityFrame",
+	"storedAccessibilityNavigationStyle",
+	"storedAccessibilityTraits",
+	"storedAccessibilityViewIsModal",
+	"storedIsAccessibilityElement",
+	"storedShouldGroupAccessibilityChildren",
+	"stringValueSafe",
+	"superclass",
+	"toManyRelationshipKeys",
+	"toOneRelationshipKeys",
+	"traitStorageList",
+	"un_safeBoolValue",
+	"userInterfaceItemIdentifier",
+	"utf8ValueSafe",
+	"valuesForKeysWithDictionary",
+	"zone",
+// Protocol: CAAnimatableValue
+// Protocol: CARenderValue
+// Protocol: NSObject
+// Protocol: ROCKRemoteInvocationInterface
+};