diff --git a/TestFixtures/Api/TNSApi.h b/TestFixtures/Api/TNSApi.h index a4ea7e9f..58ed3b31 100644 --- a/TestFixtures/Api/TNSApi.h +++ b/TestFixtures/Api/TNSApi.h @@ -34,6 +34,12 @@ typedef UIColor NIKColor; - (BOOL)method:(NSInteger)errorCode error:(NSError**)outError; - (BOOL)methodNullable:(NSInteger)errorCode error:(NSError* _Nullable* _Nullable)outError; + +// The typedef carries its own nullability, so the parameter type ends up with +// nested nullability annotations (like BNNSFilterCreateLayerPadding in the SDK) +typedef NSError* _Nullable TNSNullableError; +- (BOOL)methodTypedefNullable:(NSInteger)errorCode + error:(TNSNullableError _Nullable* _Nullable)outError; @end @interface TNSConflictingSelectorTypes1 : NSObject diff --git a/TestFixtures/Api/TNSApi.m b/TestFixtures/Api/TNSApi.m index 0f007726..2085b567 100644 --- a/TestFixtures/Api/TNSApi.m +++ b/TestFixtures/Api/TNSApi.m @@ -56,6 +56,18 @@ - (BOOL)methodNullable:(NSInteger)errorCode error:(NSError* _Nullable* _Nullable return errorCode == 0; } +- (BOOL)methodTypedefNullable:(NSInteger)errorCode + error:(TNSNullableError _Nullable* _Nullable)outError { + if (outError) { + if (errorCode != 0) { + *outError = [NSError errorWithDomain:@"TNSErrorDomain" code:errorCode userInfo:nil]; + } else { + *outError = nil; + } + } + return errorCode == 0; +} + @end @implementation TNSConflictingSelectorTypes1 diff --git a/TestRunner/app/tests/Marshalling/ObjCTypesTests.js b/TestRunner/app/tests/Marshalling/ObjCTypesTests.js index c5dc8364..d1b4ca83 100644 --- a/TestRunner/app/tests/Marshalling/ObjCTypesTests.js +++ b/TestRunner/app/tests/Marshalling/ObjCTypesTests.js @@ -575,4 +575,23 @@ describe(module.id, function () { TNSApi.new().methodNullableError(1, errorRef); expect(errorRef.value instanceof NSError).toBe(true); }); + + it("NSErrorOutParameterWithNullabilityCarryingTypedef", function () { + expect(function () { + TNSApi.new().methodTypedefNullableError(0); + }).not.toThrow(); + + var isThrown = false; + try { + TNSApi.new().methodTypedefNullableError(1); + } catch (e) { + isThrown = true; + expect(e.stack).toEqual(jasmine.any(String)); + } + expect(isThrown).toBe(true); + + var errorRef = new interop.Reference(); + TNSApi.new().methodTypedefNullableError(1, errorRef); + expect(errorRef.value instanceof NSError).toBe(true); + }); }); diff --git a/metadata-generator/src/Meta/MetaFactory.cpp b/metadata-generator/src/Meta/MetaFactory.cpp index 326b4a7a..7f969a3f 100644 --- a/metadata-generator/src/Meta/MetaFactory.cpp +++ b/metadata-generator/src/Meta/MetaFactory.cpp @@ -269,7 +269,7 @@ void MetaFactory::createFromFunction(const clang::FunctionDecl& function, // Clang doesn't handle The Create Rule automatically like for methods, so we // have to do it manually if (!(returnsRetained || returnsNotRetained) && - functionMeta.signature[0]->is(TypeBridgedInterface)) { + functionMeta.signature[0]->stripNullability()->is(TypeBridgedInterface)) { if (function.hasAttr()) { std::string functionName = function.getNameAsString(); if (functionName.find("Create") != string::npos || @@ -490,23 +490,19 @@ void MetaFactory::createFromMethod(const clang::ObjCMethodDecl& method, isNullTerminatedVariadic); // set MethodHasErrorOutParameter flag + // Nullability annotations (`NSError * _Nullable * _Nullable`) are wrapper + // nodes in the type tree, so strip them before inspecting the structure. if (method.parameters().size() > 0) { clang::ParmVarDecl* lastParameter = method.parameters()[method.parameters().size() - 1]; Type* type = _typeFactory.create(lastParameter->getType()).get(); - if (type != nullptr && (type->is(TypeType::TypeNullable) || - type->is(TypeType::TypeNonNullable))) { - type = type->is(TypeType::TypeNullable) - ? type->as().innerType - : type->as().innerType; + if (type != nullptr) { + type = type->stripNullability(); } if (type != nullptr && type->is(TypeType::TypePointer)) { Type* innerType = type->as().innerType; - if (innerType != nullptr && (innerType->is(TypeType::TypeNullable) || - innerType->is(TypeType::TypeNonNullable))) { - innerType = innerType->is(TypeType::TypeNullable) - ? innerType->as().innerType - : innerType->as().innerType; + if (innerType != nullptr) { + innerType = innerType->stripNullability(); } if (innerType != nullptr && innerType->is(TypeType::TypeInterface) && innerType->as().interface->jsName == "NSError") { diff --git a/metadata-generator/src/Meta/TypeEntities.h b/metadata-generator/src/Meta/TypeEntities.h index 5f3b5d6a..ff4aa214 100644 --- a/metadata-generator/src/Meta/TypeEntities.h +++ b/metadata-generator/src/Meta/TypeEntities.h @@ -74,6 +74,15 @@ class Type { bool is(TypeType type) const { return this->type == type; } + // Returns the underlying type with any NullableType/NonNullableType wrappers + // removed (handles arbitrarily nested wrappers). Use this before inspecting + // the structure of a type (e.g. is(TypePointer), as()), since + // nullability annotations are represented as wrapper nodes in the type tree. + Type* stripNullability(); + const Type* stripNullability() const { + return const_cast(this)->stripNullability(); + } + template T visit(TypeVisitor& visitor) const { switch (this->type) { @@ -335,4 +344,20 @@ class NonNullableType : public Type { Type* innerType; }; + +inline Type* Type::stripNullability() { + Type* current = this; + while (true) { + Type* inner = nullptr; + if (current->is(TypeType::TypeNullable)) { + inner = current->as().innerType; + } else if (current->is(TypeType::TypeNonNullable)) { + inner = current->as().innerType; + } + if (inner == nullptr) { + return current; + } + current = inner; + } +} } // namespace Meta diff --git a/metadata-generator/src/Meta/TypeFactory.cpp b/metadata-generator/src/Meta/TypeFactory.cpp index 0b3de2f5..8e4bfc07 100644 --- a/metadata-generator/src/Meta/TypeFactory.cpp +++ b/metadata-generator/src/Meta/TypeFactory.cpp @@ -506,10 +506,14 @@ shared_ptr TypeFactory::createFromAttributedType( const clang::AttributedType* type) { auto innerType = this->create(type->getModifiedType()); if (auto nullability = type->getImmediateNullability()) { + // Strip any nullability wrapper the inner type may already carry (e.g. a + // typedef that has its own annotation) so wrappers never nest and the + // outermost annotation wins. The stripped type stays alive in _cache. + Type* unwrapped = innerType->stripNullability(); if (*nullability == clang::NullabilityKind::Nullable) { - return make_shared(innerType.get()); + return make_shared(unwrapped); } else if (*nullability == clang::NullabilityKind::NonNull) { - return make_shared(innerType.get()); + return make_shared(unwrapped); } } return innerType; diff --git a/metadata-generator/src/Meta/Utils.cpp b/metadata-generator/src/Meta/Utils.cpp index 73333b15..52706023 100644 --- a/metadata-generator/src/Meta/Utils.cpp +++ b/metadata-generator/src/Meta/Utils.cpp @@ -1,186 +1,201 @@ #include "Utils.h" + #include "TypeEntities.h" namespace Meta { -bool areRecordFieldListsEqual(const std::vector& vector1, const std::vector& vector2) -{ - if (vector1.size() != vector2.size()) { - return false; - } +bool areRecordFieldListsEqual(const std::vector& vector1, + const std::vector& vector2) { + if (vector1.size() != vector2.size()) { + return false; + } - for (std::vector::size_type i = 0; i < vector1.size(); i++) { - if ((vector1[i].name != vector2[i].name) || !Utils::areTypesEqual(*vector1[i].encoding, *vector2[i].encoding)) { - return false; - } + for (std::vector::size_type i = 0; i < vector1.size(); i++) { + if ((vector1[i].name != vector2[i].name) || + !Utils::areTypesEqual(*vector1[i].encoding, *vector2[i].encoding)) { + return false; } - return true; + } + return true; } // TODO: This logic should be moved in types (and meta entities) entites -bool Utils::areTypesEqual(const Type& type1, const Type& type2) -{ - if (type1.getType() != type2.getType()) - return false; +bool Utils::areTypesEqual(const Type& type1In, const Type& type2In) { + // Nullability annotations are wrapper nodes in the type tree and are not + // significant for equality (e.g. a protocol redeclaration differing only in + // _Nullable/_Nonnull is the same member), so compare the underlying types. + const Type& type1 = *type1In.stripNullability(); + const Type& type2 = *type2In.stripNullability(); + if (type1.getType() != type2.getType()) return false; - switch (type1.getType()) { + switch (type1.getType()) { case TypeType::TypeClass: { - const ClassType& classType1 = type1.as(); - const ClassType& classType2 = type2.as(); - return classType1.protocols == classType2.protocols; + const ClassType& classType1 = type1.as(); + const ClassType& classType2 = type2.as(); + return classType1.protocols == classType2.protocols; } case TypeType::TypeId: { - const IdType& idType1 = type1.as(); - const IdType& idType2 = type2.as(); - return idType1.protocols == idType2.protocols; + const IdType& idType1 = type1.as(); + const IdType& idType2 = type2.as(); + return idType1.protocols == idType2.protocols; }; case TypeType::TypeConstantArray: { - const ConstantArrayType& arrayType1 = type1.as(); - const ConstantArrayType& arrayType2 = type2.as(); - return arrayType1.size == arrayType2.size && areTypesEqual(*arrayType1.innerType, *arrayType2.innerType); + const ConstantArrayType& arrayType1 = type1.as(); + const ConstantArrayType& arrayType2 = type2.as(); + return arrayType1.size == arrayType2.size && + areTypesEqual(*arrayType1.innerType, *arrayType2.innerType); }; case TypeType::TypeExtVector: { - const ExtVectorType& arrayType1 = type1.as(); - const ExtVectorType& arrayType2 = type2.as(); - return arrayType1.size == arrayType2.size && areTypesEqual(*arrayType1.innerType, *arrayType2.innerType); + const ExtVectorType& arrayType1 = type1.as(); + const ExtVectorType& arrayType2 = type2.as(); + return arrayType1.size == arrayType2.size && + areTypesEqual(*arrayType1.innerType, *arrayType2.innerType); }; case TypeType::TypeIncompleteArray: { - const IncompleteArrayType& arrayType1 = type1.as(); - const IncompleteArrayType& arrayType2 = type2.as(); - return areTypesEqual(*arrayType1.innerType, *arrayType2.innerType); + const IncompleteArrayType& arrayType1 = type1.as(); + const IncompleteArrayType& arrayType2 = type2.as(); + return areTypesEqual(*arrayType1.innerType, *arrayType2.innerType); }; case TypeType::TypePointer: { - const PointerType& pointerType1 = type1.as(); - const PointerType& pointerType2 = type2.as(); - return areTypesEqual(*pointerType1.innerType, *pointerType2.innerType); + const PointerType& pointerType1 = type1.as(); + const PointerType& pointerType2 = type2.as(); + return areTypesEqual(*pointerType1.innerType, *pointerType2.innerType); }; case TypeType::TypeBlock: { - const BlockType& blockType1 = type1.as(); - const BlockType& blockType2 = type2.as(); - return Utils::areTypesEqual(blockType1.signature, blockType2.signature); + const BlockType& blockType1 = type1.as(); + const BlockType& blockType2 = type2.as(); + return Utils::areTypesEqual(blockType1.signature, blockType2.signature); }; case TypeType::TypeFunctionPointer: { - const FunctionPointerType& functionType1 = type1.as(); - const FunctionPointerType& functionType2 = type2.as(); - return Utils::areTypesEqual(functionType1.signature, functionType2.signature); + const FunctionPointerType& functionType1 = + type1.as(); + const FunctionPointerType& functionType2 = + type2.as(); + return Utils::areTypesEqual(functionType1.signature, + functionType2.signature); }; case TypeType::TypeInterface: { - const InterfaceType& interfaceType1 = type1.as(); - const InterfaceType& interfaceType2 = type2.as(); - return interfaceType1.interface == interfaceType2.interface && interfaceType1.protocols == interfaceType2.protocols; + const InterfaceType& interfaceType1 = type1.as(); + const InterfaceType& interfaceType2 = type2.as(); + return interfaceType1.interface == interfaceType2.interface && + interfaceType1.protocols == interfaceType2.protocols; }; case TypeType::TypeBridgedInterface: { - const BridgedInterfaceType& interfaceType1 = type1.as(); - const BridgedInterfaceType& interfaceType2 = type2.as(); - return interfaceType1.name == interfaceType2.name; + const BridgedInterfaceType& interfaceType1 = + type1.as(); + const BridgedInterfaceType& interfaceType2 = + type2.as(); + return interfaceType1.name == interfaceType2.name; }; case TypeType::TypeStruct: { - const StructType& structType1 = type1.as(); - const StructType& structType2 = type2.as(); - return structType1.structMeta == structType2.structMeta; + const StructType& structType1 = type1.as(); + const StructType& structType2 = type2.as(); + return structType1.structMeta == structType2.structMeta; }; case TypeType::TypeUnion: { - const UnionType& unionType1 = type1.as(); - const UnionType& unionType2 = type2.as(); - return unionType1.unionMeta == unionType2.unionMeta; + const UnionType& unionType1 = type1.as(); + const UnionType& unionType2 = type2.as(); + return unionType1.unionMeta == unionType2.unionMeta; }; case TypeType::TypeAnonymousStruct: { - const AnonymousStructType& structType1 = type1.as(); - const AnonymousStructType& structType2 = type2.as(); - return areRecordFieldListsEqual(structType1.fields, structType2.fields); + const AnonymousStructType& structType1 = type1.as(); + const AnonymousStructType& structType2 = type2.as(); + return areRecordFieldListsEqual(structType1.fields, structType2.fields); }; case TypeType::TypeAnonymousUnion: { - const AnonymousUnionType& unionType1 = type1.as(); - const AnonymousUnionType& unionType2 = type2.as(); - return areRecordFieldListsEqual(unionType1.fields, unionType2.fields); + const AnonymousUnionType& unionType1 = type1.as(); + const AnonymousUnionType& unionType2 = type2.as(); + return areRecordFieldListsEqual(unionType1.fields, unionType2.fields); }; case TypeType::TypeTypeArgument: { - const TypeArgumentType& argType1 = type1.as(); - const TypeArgumentType& argType2 = type2.as(); - return areTypesEqual(*argType1.underlyingType, *argType2.underlyingType); + const TypeArgumentType& argType1 = type1.as(); + const TypeArgumentType& argType2 = type2.as(); + return areTypesEqual(*argType1.underlyingType, *argType2.underlyingType); }; default: { - return true; - } + return true; } + } } -bool Utils::areTypesEqual(const std::vector& vector1, const std::vector& vector2) -{ - if (vector1.size() != vector2.size()) { - return false; - } +bool Utils::areTypesEqual(const std::vector& vector1, + const std::vector& vector2) { + if (vector1.size() != vector2.size()) { + return false; + } - for (std::vector::size_type i = 0; i < vector1.size(); i++) { - if (!Utils::areTypesEqual(*vector1[i], *vector2[i])) { - return false; - } + for (std::vector::size_type i = 0; i < vector1.size(); i++) { + if (!Utils::areTypesEqual(*vector1[i], *vector2[i])) { + return false; } - return true; + } + return true; } -static bool isalpha(const std::vector& strings, size_t index) -{ - for (auto& str : strings) { - if (!std::isalpha(str[index])) { - return false; - } +static bool isalpha(const std::vector& strings, size_t index) { + for (auto& str : strings) { + if (!std::isalpha(str[index])) { + return false; } - return true; + } + return true; } -static std::string createValidPrefix(const std::vector& fieldNames, const std::string& prefix) -{ - if (!prefix.empty()) { - for (const std::string& field : fieldNames) { - if (std::isdigit(field[prefix.size()])) { - int newPrefixLength = prefix.size(); - while (newPrefixLength > 0 && !std::isupper(field[newPrefixLength])) { - newPrefixLength--; - } - - std::string newPrefix = prefix.substr(0, newPrefixLength); - return createValidPrefix(fieldNames, newPrefix); - } +static std::string createValidPrefix(const std::vector& fieldNames, + const std::string& prefix) { + if (!prefix.empty()) { + for (const std::string& field : fieldNames) { + if (std::isdigit(field[prefix.size()])) { + int newPrefixLength = prefix.size(); + while (newPrefixLength > 0 && !std::isupper(field[newPrefixLength])) { + newPrefixLength--; } - bool allMembersStartWithUnderscore = true; - for (const std::string& field : fieldNames) { - if (field[prefix.size()] != '_') { - allMembersStartWithUnderscore = false; - break; - } - } - if (allMembersStartWithUnderscore) { - return createValidPrefix(fieldNames, prefix + '_'); - } + std::string newPrefix = prefix.substr(0, newPrefixLength); + return createValidPrefix(fieldNames, newPrefix); + } } - return prefix; + bool allMembersStartWithUnderscore = true; + for (const std::string& field : fieldNames) { + if (field[prefix.size()] != '_') { + allMembersStartWithUnderscore = false; + break; + } + } + if (allMembersStartWithUnderscore) { + return createValidPrefix(fieldNames, prefix + '_'); + } + } + + return prefix; } -std::string Utils::calculateEnumFieldsPrefix(const std::string& enumName, const std::vector& fields) -{ - for (size_t prefixLength = 0; prefixLength < enumName.size(); prefixLength++) { - char c = enumName[prefixLength]; - for (size_t i = 0; i < fields.size(); i++) { - if (prefixLength >= fields[i].size() || fields[i][prefixLength] != c) { - while (prefixLength > 0 && (!std::isupper(fields[i][prefixLength]) || !isalpha(fields, prefixLength))) { - prefixLength--; - } - return createValidPrefix(fields, fields[i].substr(0, prefixLength)); - } +std::string Utils::calculateEnumFieldsPrefix( + const std::string& enumName, const std::vector& fields) { + for (size_t prefixLength = 0; prefixLength < enumName.size(); + prefixLength++) { + char c = enumName[prefixLength]; + for (size_t i = 0; i < fields.size(); i++) { + if (prefixLength >= fields[i].size() || fields[i][prefixLength] != c) { + while (prefixLength > 0 && (!std::isupper(fields[i][prefixLength]) || + !isalpha(fields, prefixLength))) { + prefixLength--; } + return createValidPrefix(fields, fields[i].substr(0, prefixLength)); + } } + } - return createValidPrefix(fields, enumName); + return createValidPrefix(fields, enumName); } -void Utils::getAllLinkLibraries(clang::Module* module, std::vector& result) -{ - for (clang::Module::LinkLibrary lib : module->LinkLibraries) - result.push_back(lib); - for (clang::Module::submodule_const_iterator it = module->submodules().begin(); - it != module->submodules().end(); ++it) - getAllLinkLibraries(*it, result); -} +void Utils::getAllLinkLibraries( + clang::Module* module, std::vector& result) { + for (clang::Module::LinkLibrary lib : module->LinkLibraries) + result.push_back(lib); + for (clang::Module::submodule_const_iterator it = + module->submodules().begin(); + it != module->submodules().end(); ++it) + getAllLinkLibraries(*it, result); } +} // namespace Meta diff --git a/metadata-generator/src/TypeScript/DefinitionWriter.cpp b/metadata-generator/src/TypeScript/DefinitionWriter.cpp index 766b43bc..5a62003d 100644 --- a/metadata-generator/src/TypeScript/DefinitionWriter.cpp +++ b/metadata-generator/src/TypeScript/DefinitionWriter.cpp @@ -140,7 +140,7 @@ void DefinitionWriter::visit(InterfaceMeta* meta) { nullptr); for (auto& methodPair : inheritedStaticMethods) { MethodMeta* method = methodPair.second.second; - if (!method->signature[0]->is(TypeInstancetype)) { + if (!method->signature[0]->stripNullability()->is(TypeInstancetype)) { continue; } if (compoundStaticMethods.find(method->jsName) != @@ -561,7 +561,8 @@ std::string DefinitionWriter::writeConstructor( return output.str(); } -void getClosedGenericsIfAny(Type& type, std::vector& params) { +void getClosedGenericsIfAny(Type& typeIn, std::vector& params) { + Type& type = *typeIn.stripNullability(); if (type.is(TypeInterface)) { const InterfaceType& interfaceType = type.as(); for (size_t i = 0; i < interfaceType.typeArguments.size(); i++) { @@ -634,7 +635,7 @@ std::string DefinitionWriter::writeMethod(MethodMeta* meta, const Type* retType = meta->signature[0]; if (!methodDecl.isInstanceMethod() && owner->is(MetaType::Interface)) { - if ((retType->is(TypeInstancetype) || + if ((retType->stripNullability()->is(TypeInstancetype) || DefinitionWriter::hasClosedGenerics(*retType)) && !skipGenerics) { output << getTypeParametersStringOrEmpty( @@ -726,7 +727,8 @@ std::string DefinitionWriter::writeMethod( bool implementsProtocol = protocols.find(static_cast(memberOwner)) != protocols.end(); - bool returnsInstanceType = method->signature[0]->is(TypeInstancetype); + bool returnsInstanceType = + method->signature[0]->stripNullability()->is(TypeInstancetype); if (isOwnMethod || implementsProtocol || returnsInstanceType) { output << writeMethod(method, owner, canUseThisType); @@ -939,7 +941,8 @@ std::string DefinitionWriter::localizeReference(const ::Meta::Meta& meta) { return localizeReference(meta.jsName, meta.module->getFullModuleName()); } -bool DefinitionWriter::hasClosedGenerics(const Type& type) { +bool DefinitionWriter::hasClosedGenerics(const Type& typeIn) { + const Type& type = *typeIn.stripNullability(); if (type.is(TypeInterface)) { const InterfaceType& interfaceType = type.as(); return interfaceType.typeArguments.size(); @@ -1005,10 +1008,11 @@ std::string DefinitionWriter::tsifyType(const Type& type, tsifyType(*type.as().innerType) + ">"; case TypePointer: { const PointerType& pointerType = type.as(); - std::string result = (pointerType.innerType->is(TypeVoid)) - ? "interop.Pointer | interop.Reference" - : "interop.Pointer | interop.Reference<" + - tsifyType(*pointerType.innerType) + ">"; + std::string result = + (pointerType.innerType->stripNullability()->is(TypeVoid)) + ? "interop.Pointer | interop.Reference" + : "interop.Pointer | interop.Reference<" + + tsifyType(*pointerType.innerType) + ">"; if (isFuncParam) { result += " | ArrayBufferLike | ArrayBufferView"; } @@ -1134,7 +1138,7 @@ std::string DefinitionWriter::tsifyType(const Type& type, return type.as().name; case TypeNullable: { const NullableType& nullableType = type.as(); - if (nullableType.innerType->is(TypePointer)) { + if (nullableType.innerType->stripNullability()->is(TypePointer)) { return tsifyType(*nullableType.innerType, isFuncParam); } return tsifyType(*nullableType.innerType, isFuncParam) + " | null"; @@ -1157,7 +1161,7 @@ std::string DefinitionWriter::tsifyType(const Type& type, std::string DefinitionWriter::computeMethodReturnType( const Type* retType, const BaseClassMeta* owner, bool instanceMember) { std::ostringstream output; - if (retType->is(TypeInstancetype)) { + if (retType->stripNullability()->is(TypeInstancetype)) { if (instanceMember) { output << "this"; } else { diff --git a/metadata-generator/src/Yaml/MetaYamlTraits.h b/metadata-generator/src/Yaml/MetaYamlTraits.h index 698cc183..e9d07383 100644 --- a/metadata-generator/src/Yaml/MetaYamlTraits.h +++ b/metadata-generator/src/Yaml/MetaYamlTraits.h @@ -5,17 +5,15 @@ namespace llvm { namespace yaml { - bool operator==(Meta::Version& x, const Meta::Version& y) - { - return x.Major == y.Major && x.Minor == y.Minor && x.SubMinor == y.SubMinor; - } - - Meta::MetaFlags operator|(Meta::MetaFlags& value1, Meta::MetaFlags value2) - { - return (Meta::MetaFlags)((uint32_t)value1 | (uint32_t)value2); - } +bool operator==(Meta::Version& x, const Meta::Version& y) { + return x.Major == y.Major && x.Minor == y.Minor && x.SubMinor == y.SubMinor; } + +Meta::MetaFlags operator|(Meta::MetaFlags& value1, Meta::MetaFlags value2) { + return (Meta::MetaFlags)((uint32_t)value1 | (uint32_t)value2); } +} // namespace yaml +} // namespace llvm #include @@ -31,561 +29,563 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(Meta::EnumField) namespace llvm { namespace yaml { - // Version - template <> - struct ScalarTraits { - static void output(const Meta::Version& value, void* context, raw_ostream& out) - { - if (value.Major >= 0) { - out << value.Major; - if (value.Minor >= 0) { - out << "." << value.Minor; - if (value.SubMinor >= 0) { - out << "." << value.SubMinor; - } - } - } - } - - static StringRef input(StringRef stringValue, void* context, Meta::Version& value) - { - value = UNKNOWN_VERSION; - if (stringValue.size() == 0) { - return StringRef(); - } - std::string version = stringValue.str(); - - unsigned long firstDotIndex = version.find("."); - value.Major = (firstDotIndex != std::string::npos) ? std::stoi(version.substr(0, firstDotIndex)) : std::stoi(version); - if (firstDotIndex != std::string::npos) { - unsigned long secondDotIndex = version.find(".", firstDotIndex + 1); - value.Minor = std::stoi(version.substr(firstDotIndex + 1, (secondDotIndex != std::string::npos) ? secondDotIndex - firstDotIndex - 1 : std::string::npos)); - if (secondDotIndex != std::string::npos) { - value.SubMinor = std::stoi(version.substr(secondDotIndex + 1, std::string::npos)); - } - } - - // TODO: We can validate the version and return non-empty string if the yaml format of the version is invalid - return StringRef(); - } - // Determine if this scalar needs quotes. - static QuotingType mustQuote(StringRef) - { - return QuotingType::None; - } - }; - - // MetaFlags - template <> - struct ScalarBitSetTraits { - - static void bitset(IO& io, Meta::MetaFlags& value) - { - io.bitSetCase(value, "IsIosAppExtensionAvailable", Meta::MetaFlags::IsIosAppExtensionAvailable); - io.bitSetCase(value, "MemberIsOptional", Meta::MetaFlags::MemberIsOptional); - //io.bitSetCase(value, "HasName", Meta::MetaFlags::HasName); - - io.bitSetCase(value, "FunctionIsVariadic", Meta::MetaFlags::FunctionIsVariadic); - io.bitSetCase(value, "FunctionOwnsReturnedCocoaObject", Meta::MetaFlags::FunctionOwnsReturnedCocoaObject); - io.bitSetCase(value, "FunctionReturnsUnmanaged", Meta::MetaFlags::FunctionReturnsUnmanaged); - - io.bitSetCase(value, "MethodIsVariadic", Meta::MetaFlags::MethodIsVariadic); - io.bitSetCase(value, "MethodIsNullTerminatedVariadic", Meta::MetaFlags::MethodIsNullTerminatedVariadic); - io.bitSetCase(value, "MethodOwnsReturnedCocoaObject", Meta::MetaFlags::MethodOwnsReturnedCocoaObject); - io.bitSetCase(value, "MethodHasErrorOutParameter", Meta::MetaFlags::MethodHasErrorOutParameter); - io.bitSetCase(value, "MethodIsInitializer", Meta::MetaFlags::MethodIsInitializer); - } - }; - - // MetaType - template <> - struct ScalarEnumerationTraits { - static void enumeration(IO& io, Meta::MetaType& value) - { - io.enumCase(value, "Undefined", Meta::MetaType::Undefined); - io.enumCase(value, "Struct", Meta::MetaType::Struct); - io.enumCase(value, "Union", Meta::MetaType::Union); - io.enumCase(value, "Function", Meta::MetaType::Function); - io.enumCase(value, "Enum", Meta::MetaType::Enum); - io.enumCase(value, "EnumConstant", Meta::MetaType::EnumConstant); - io.enumCase(value, "Var", Meta::MetaType::Var); - io.enumCase(value, "Interface", Meta::MetaType::Interface); - io.enumCase(value, "Protocol", Meta::MetaType::Protocol); - io.enumCase(value, "Category", Meta::MetaType::Category); - io.enumCase(value, "Method", Meta::MetaType::Method); - io.enumCase(value, "Property", Meta::MetaType::Property); +// Version +template <> +struct ScalarTraits { + static void output(const Meta::Version& value, void* context, + raw_ostream& out) { + if (value.Major >= 0) { + out << value.Major; + if (value.Minor >= 0) { + out << "." << value.Minor; + if (value.SubMinor >= 0) { + out << "." << value.SubMinor; } - }; - - // TypeType - template <> - struct ScalarEnumerationTraits { - static void enumeration(IO& io, Meta::TypeType& value) - { - io.enumCase(value, "Void", Meta::TypeType::TypeVoid); - io.enumCase(value, "Bool", Meta::TypeType::TypeBool); - io.enumCase(value, "Short", Meta::TypeType::TypeShort); - io.enumCase(value, "Ushort", Meta::TypeType::TypeUShort); - io.enumCase(value, "Int", Meta::TypeType::TypeInt); - io.enumCase(value, "UInt", Meta::TypeType::TypeUInt); - io.enumCase(value, "Long", Meta::TypeType::TypeLong); - io.enumCase(value, "ULong", Meta::TypeType::TypeULong); - io.enumCase(value, "LongLong", Meta::TypeType::TypeLongLong); - io.enumCase(value, "ULongLong", Meta::TypeType::TypeULongLong); - io.enumCase(value, "Char", Meta::TypeType::TypeSignedChar); - io.enumCase(value, "UChar", Meta::TypeType::TypeUnsignedChar); - io.enumCase(value, "Unichar", Meta::TypeType::TypeUnichar); - io.enumCase(value, "CString", Meta::TypeType::TypeCString); - io.enumCase(value, "Float", Meta::TypeType::TypeFloat); - io.enumCase(value, "Double", Meta::TypeType::TypeDouble); - io.enumCase(value, "Selector", Meta::TypeType::TypeSelector); - io.enumCase(value, "Class", Meta::TypeType::TypeClass); - io.enumCase(value, "Instancetype", Meta::TypeType::TypeInstancetype); - io.enumCase(value, "Id", Meta::TypeType::TypeId); - io.enumCase(value, "ConstantArray", Meta::TypeType::TypeConstantArray); - io.enumCase(value, "IncompleteArray", Meta::TypeType::TypeIncompleteArray); - io.enumCase(value, "Interface", Meta::TypeType::TypeInterface); - io.enumCase(value, "BridgedInterface", Meta::TypeType::TypeBridgedInterface); - io.enumCase(value, "Pointer", Meta::TypeType::TypePointer); - io.enumCase(value, "FunctionPointer", Meta::TypeType::TypeFunctionPointer); - io.enumCase(value, "Block", Meta::TypeType::TypeBlock); - io.enumCase(value, "Struct", Meta::TypeType::TypeStruct); - io.enumCase(value, "Union", Meta::TypeType::TypeUnion); - io.enumCase(value, "AnonymousStruct", Meta::TypeType::TypeAnonymousStruct); - io.enumCase(value, "AnonymousUnion", Meta::TypeType::TypeAnonymousUnion); - io.enumCase(value, "Enum", Meta::TypeType::TypeEnum); - io.enumCase(value, "VaList", Meta::TypeType::TypeVaList); - io.enumCase(value, "Protocol", Meta::TypeType::TypeProtocol); - io.enumCase(value, "TypeArgument", Meta::TypeType::TypeTypeArgument); - } - }; - - // clang::Module::LinkLibrary - template <> - struct MappingTraits { - - static void mapping(IO& io, clang::Module::LinkLibrary& lib) - { - io.mapRequired("Library", lib.Library); - io.mapRequired("IsFramework", lib.IsFramework); - } - }; - - // clang::Module * - template <> - struct MappingTraits { - - static void mapping(IO& io, clang::Module*& module) - { - std::string fullModuleName = module->getFullModuleName(); - bool isPartOfFramework = module->isPartOfFramework(); - bool isSystem = module->IsSystem; - std::vector libs; - - Meta::Utils::getAllLinkLibraries(module, libs); - - io.mapRequired("FullName", fullModuleName); - io.mapRequired("IsPartOfFramework", isPartOfFramework); - io.mapRequired("IsSystemModule", isSystem); - io.mapRequired("Libraries", libs); - } - }; - - // std::pair> - template <> - struct MappingTraits > > { - - static void mapping(IO& io, std::pair >& module) - { - io.mapRequired("Module", module.first); - io.mapRequired("Items", module.second); - } - }; - - // Type * - template <> - struct MappingTraits { - - static void mapping(IO& io, Meta::Type*& type) - { - Meta::TypeType typeType = type->getType(); - io.mapRequired("Type", typeType); - - switch (typeType) { - case Meta::TypeType::TypeId: { - Meta::IdType& concreteType = type->as(); - std::vector protocols; - for (Meta::ProtocolMeta* protocol : concreteType.protocols) { - protocols.push_back(protocol->jsName); - } - io.mapRequired("WithProtocols", protocols); - break; - } - case Meta::TypeType::TypeConstantArray: { - Meta::ConstantArrayType& concreteType = type->as(); - io.mapRequired("ArrayType", concreteType.innerType); - io.mapRequired("Size", concreteType.size); - break; - } - case Meta::TypeType::TypeIncompleteArray: { - Meta::IncompleteArrayType& concreteType = type->as(); - io.mapRequired("ArrayType", concreteType.innerType); - break; - } - case Meta::TypeType::TypeInterface: { - Meta::InterfaceType& concreteType = type->as(); - io.mapRequired("Name", concreteType.interface->name); - if (concreteType.typeArguments.size() > 0) { - std::vector typeArguments; - for (Meta::Type* type : concreteType.typeArguments) { - typeArguments.push_back(type); - } - io.mapRequired("TypeParameters", typeArguments); - } - std::vector protocols; - for (Meta::ProtocolMeta* protocol : concreteType.protocols) { - protocols.push_back(protocol->jsName); - } - io.mapRequired("WithProtocols", protocols); - break; - } - case Meta::TypeType::TypeBridgedInterface: { - Meta::BridgedInterfaceType& concreteType = type->as(); - io.mapRequired("Name", concreteType.name); - std::string bridgedTo = concreteType.isId() ? "id" : (concreteType.bridgedInterface == nullptr ? "[None]" : concreteType.bridgedInterface->jsName); - io.mapRequired("BridgedTo", bridgedTo); - break; - } - case Meta::TypeType::TypePointer: { - Meta::PointerType& concreteType = type->as(); - io.mapRequired("PointerType", concreteType.innerType); - break; - } - case Meta::TypeType::TypeFunctionPointer: { - Meta::FunctionPointerType& concreteType = type->as(); - io.mapRequired("Signature", concreteType.signature); - break; - } - case Meta::TypeType::TypeBlock: { - Meta::BlockType& concreteType = type->as(); - io.mapRequired("Signature", concreteType.signature); - break; - } - case Meta::TypeType::TypeStruct: { - Meta::StructType& concreteType = type->as(); - std::string fullModuleName = concreteType.structMeta->module->getFullModuleName(); - io.mapRequired("Module", fullModuleName); - io.mapRequired("Name", concreteType.structMeta->name); - break; - } - case Meta::TypeType::TypeUnion: { - Meta::UnionType& concreteType = type->as(); - std::string fullModuleName = concreteType.unionMeta->module->getFullModuleName(); - io.mapRequired("Module", fullModuleName); - io.mapRequired("Name", concreteType.unionMeta->name); - break; - } - case Meta::TypeType::TypeAnonymousStruct: { - Meta::AnonymousStructType& concreteType = type->as(); - io.mapRequired("Fields", concreteType.fields); - break; - } - case Meta::TypeType::TypeAnonymousUnion: { - Meta::AnonymousUnionType& concreteType = type->as(); - io.mapRequired("Fields", concreteType.fields); - break; - } - case Meta::TypeType::TypeEnum: { - Meta::EnumType& concreteType = type->as(); - io.mapRequired("Name", concreteType.enumMeta->jsName); - break; - } - case Meta::TypeType::TypeTypeArgument: { - Meta::TypeArgumentType& concreteType = type->as(); - io.mapRequired("Name", concreteType.name); - io.mapRequired("UnderlyingType", concreteType.underlyingType); - std::vector protocols; - for (Meta::ProtocolMeta* protocol : concreteType.protocols) { - protocols.push_back(protocol->jsName); - } - if (protocols.size() > 0) { - io.mapRequired("WithProtocols", protocols); - } - break; - } - default: { - } - } - } - }; - - static void mapBaseMeta(IO& io, Meta::Meta* meta) - { - io.mapRequired("Name", meta->name); - io.mapRequired("JsName", meta->jsName); - if (!meta->demangledName.empty()) { - io.mapRequired("DemangledName", meta->demangledName); - } - io.mapRequired("Filename", meta->fileName); - io.mapRequired("Module", meta->module); - io.mapOptional("IntroducedIn", meta->introducedIn, (Meta::Version) UNKNOWN_VERSION); - io.mapRequired("Flags", meta->flags); - io.mapRequired("Type", meta->type); + } } + } - // MethodMeta * - template <> - struct MappingTraits { - - static void mapping(IO& io, Meta::MethodMeta*& meta) - { - mapBaseMeta(io, meta); - io.mapRequired("Signature", meta->signature); - } - }; - - // PropertyMeta * - template <> - struct MappingTraits { - - static void mapping(IO& io, Meta::PropertyMeta*& meta) - { - mapBaseMeta(io, meta); - - if (meta->getter) - io.mapRequired("Getter", meta->getter); - if (meta->setter) - io.mapRequired("Setter", meta->setter); - } - }; - - // BaseClassMeta * - template <> - struct MappingTraits { - - static void mapping(IO& io, Meta::BaseClassMeta*& meta) - { - mapBaseMeta(io, meta); - io.mapRequired("InstanceMethods", meta->instanceMethods); - io.mapRequired("StaticMethods", meta->staticMethods); - io.mapRequired("InstanceProperties", meta->instanceProperties); - io.mapRequired("StaticProperties", meta->staticProperties); - std::vector protocols; - for (Meta::ProtocolMeta* protocol : meta->protocols) { - protocols.push_back(protocol->jsName); - } - io.mapRequired("Protocols", protocols); - } - }; - - // FunctionMeta * - template <> - struct MappingTraits { - - static void mapping(IO& io, Meta::FunctionMeta*& meta) - { - mapBaseMeta(io, meta); - io.mapRequired("Signature", meta->signature); - } - }; - - // RecordField - template <> - struct MappingTraits { - - static void mapping(IO& io, Meta::RecordField& field) - { - io.mapRequired("Name", field.name); - io.mapRequired("Signature", field.encoding); - } - }; - - // RecordMeta * - template <> - struct MappingTraits { - - static void mapping(IO& io, Meta::RecordMeta*& meta) - { - mapBaseMeta(io, meta); - io.mapRequired("Fields", meta->fields); - } - }; - - // StructMeta * - template <> - struct MappingTraits { - - static void mapping(IO& io, Meta::StructMeta*& meta) - { - Meta::RecordMeta* recordMeta = &meta->as(); - MappingTraits::mapping(io, recordMeta); - } - }; - - // UnionMeta * - template <> - struct MappingTraits { - - static void mapping(IO& io, Meta::UnionMeta*& meta) - { - Meta::RecordMeta* recordMeta = &meta->as(); - MappingTraits::mapping(io, recordMeta); - } - }; - - // VarMeta * - template <> - struct MappingTraits { - - static void mapping(IO& io, Meta::VarMeta*& meta) - { - mapBaseMeta(io, meta); - io.mapRequired("Signature", meta->signature); - if (meta->hasValue) { - io.mapRequired("Value", meta->value); - } - } - }; - - // EnumField - template <> - struct MappingTraits { - - static void mapping(IO& io, Meta::EnumField& field) - { - io.mapRequired(field.name.c_str(), field.value); - } - }; - - // EnumMeta * - template <> - struct MappingTraits { - - static void mapping(IO& io, Meta::EnumMeta*& meta) - { - mapBaseMeta(io, meta); - io.mapRequired("FullNameFields", meta->fullNameFields); - io.mapRequired("SwiftNameFields", meta->swiftNameFields); - } - }; - - // EnumConstantMeta * - template <> - struct MappingTraits { + static StringRef input(StringRef stringValue, void* context, + Meta::Version& value) { + value = UNKNOWN_VERSION; + if (stringValue.size() == 0) { + return StringRef(); + } + std::string version = stringValue.str(); + + unsigned long firstDotIndex = version.find("."); + value.Major = (firstDotIndex != std::string::npos) + ? std::stoi(version.substr(0, firstDotIndex)) + : std::stoi(version); + if (firstDotIndex != std::string::npos) { + unsigned long secondDotIndex = version.find(".", firstDotIndex + 1); + value.Minor = std::stoi(version.substr( + firstDotIndex + 1, (secondDotIndex != std::string::npos) + ? secondDotIndex - firstDotIndex - 1 + : std::string::npos)); + if (secondDotIndex != std::string::npos) { + value.SubMinor = + std::stoi(version.substr(secondDotIndex + 1, std::string::npos)); + } + } - static void mapping(IO& io, Meta::EnumConstantMeta*& meta) - { - mapBaseMeta(io, meta); - io.mapRequired("Value", meta->value); + // TODO: We can validate the version and return non-empty string if the yaml + // format of the version is invalid + return StringRef(); + } + // Determine if this scalar needs quotes. + static QuotingType mustQuote(StringRef) { return QuotingType::None; } +}; + +// MetaFlags +template <> +struct ScalarBitSetTraits { + static void bitset(IO& io, Meta::MetaFlags& value) { + io.bitSetCase(value, "IsIosAppExtensionAvailable", + Meta::MetaFlags::IsIosAppExtensionAvailable); + io.bitSetCase(value, "MemberIsOptional", Meta::MetaFlags::MemberIsOptional); + // io.bitSetCase(value, "HasName", Meta::MetaFlags::HasName); + + io.bitSetCase(value, "FunctionIsVariadic", + Meta::MetaFlags::FunctionIsVariadic); + io.bitSetCase(value, "FunctionOwnsReturnedCocoaObject", + Meta::MetaFlags::FunctionOwnsReturnedCocoaObject); + io.bitSetCase(value, "FunctionReturnsUnmanaged", + Meta::MetaFlags::FunctionReturnsUnmanaged); + + io.bitSetCase(value, "MethodIsVariadic", Meta::MetaFlags::MethodIsVariadic); + io.bitSetCase(value, "MethodIsNullTerminatedVariadic", + Meta::MetaFlags::MethodIsNullTerminatedVariadic); + io.bitSetCase(value, "MethodOwnsReturnedCocoaObject", + Meta::MetaFlags::MethodOwnsReturnedCocoaObject); + io.bitSetCase(value, "MethodHasErrorOutParameter", + Meta::MetaFlags::MethodHasErrorOutParameter); + io.bitSetCase(value, "MethodIsInitializer", + Meta::MetaFlags::MethodIsInitializer); + } +}; + +// MetaType +template <> +struct ScalarEnumerationTraits { + static void enumeration(IO& io, Meta::MetaType& value) { + io.enumCase(value, "Undefined", Meta::MetaType::Undefined); + io.enumCase(value, "Struct", Meta::MetaType::Struct); + io.enumCase(value, "Union", Meta::MetaType::Union); + io.enumCase(value, "Function", Meta::MetaType::Function); + io.enumCase(value, "Enum", Meta::MetaType::Enum); + io.enumCase(value, "EnumConstant", Meta::MetaType::EnumConstant); + io.enumCase(value, "Var", Meta::MetaType::Var); + io.enumCase(value, "Interface", Meta::MetaType::Interface); + io.enumCase(value, "Protocol", Meta::MetaType::Protocol); + io.enumCase(value, "Category", Meta::MetaType::Category); + io.enumCase(value, "Method", Meta::MetaType::Method); + io.enumCase(value, "Property", Meta::MetaType::Property); + } +}; + +// TypeType +template <> +struct ScalarEnumerationTraits { + static void enumeration(IO& io, Meta::TypeType& value) { + io.enumCase(value, "Void", Meta::TypeType::TypeVoid); + io.enumCase(value, "Bool", Meta::TypeType::TypeBool); + io.enumCase(value, "Short", Meta::TypeType::TypeShort); + io.enumCase(value, "Ushort", Meta::TypeType::TypeUShort); + io.enumCase(value, "Int", Meta::TypeType::TypeInt); + io.enumCase(value, "UInt", Meta::TypeType::TypeUInt); + io.enumCase(value, "Long", Meta::TypeType::TypeLong); + io.enumCase(value, "ULong", Meta::TypeType::TypeULong); + io.enumCase(value, "LongLong", Meta::TypeType::TypeLongLong); + io.enumCase(value, "ULongLong", Meta::TypeType::TypeULongLong); + io.enumCase(value, "Char", Meta::TypeType::TypeSignedChar); + io.enumCase(value, "UChar", Meta::TypeType::TypeUnsignedChar); + io.enumCase(value, "Unichar", Meta::TypeType::TypeUnichar); + io.enumCase(value, "CString", Meta::TypeType::TypeCString); + io.enumCase(value, "Float", Meta::TypeType::TypeFloat); + io.enumCase(value, "Double", Meta::TypeType::TypeDouble); + io.enumCase(value, "Selector", Meta::TypeType::TypeSelector); + io.enumCase(value, "Class", Meta::TypeType::TypeClass); + io.enumCase(value, "Instancetype", Meta::TypeType::TypeInstancetype); + io.enumCase(value, "Id", Meta::TypeType::TypeId); + io.enumCase(value, "ConstantArray", Meta::TypeType::TypeConstantArray); + io.enumCase(value, "IncompleteArray", Meta::TypeType::TypeIncompleteArray); + io.enumCase(value, "Interface", Meta::TypeType::TypeInterface); + io.enumCase(value, "BridgedInterface", + Meta::TypeType::TypeBridgedInterface); + io.enumCase(value, "Pointer", Meta::TypeType::TypePointer); + io.enumCase(value, "FunctionPointer", Meta::TypeType::TypeFunctionPointer); + io.enumCase(value, "Block", Meta::TypeType::TypeBlock); + io.enumCase(value, "Struct", Meta::TypeType::TypeStruct); + io.enumCase(value, "Union", Meta::TypeType::TypeUnion); + io.enumCase(value, "AnonymousStruct", Meta::TypeType::TypeAnonymousStruct); + io.enumCase(value, "AnonymousUnion", Meta::TypeType::TypeAnonymousUnion); + io.enumCase(value, "Enum", Meta::TypeType::TypeEnum); + io.enumCase(value, "VaList", Meta::TypeType::TypeVaList); + io.enumCase(value, "Protocol", Meta::TypeType::TypeProtocol); + io.enumCase(value, "TypeArgument", Meta::TypeType::TypeTypeArgument); + io.enumCase(value, "ExtVector", Meta::TypeType::TypeExtVector); + io.enumCase(value, "Nullable", Meta::TypeType::TypeNullable); + io.enumCase(value, "NonNullable", Meta::TypeType::TypeNonNullable); + } +}; + +// clang::Module::LinkLibrary +template <> +struct MappingTraits { + static void mapping(IO& io, clang::Module::LinkLibrary& lib) { + io.mapRequired("Library", lib.Library); + io.mapRequired("IsFramework", lib.IsFramework); + } +}; + +// clang::Module * +template <> +struct MappingTraits { + static void mapping(IO& io, clang::Module*& module) { + std::string fullModuleName = module->getFullModuleName(); + bool isPartOfFramework = module->isPartOfFramework(); + bool isSystem = module->IsSystem; + std::vector libs; + + Meta::Utils::getAllLinkLibraries(module, libs); + + io.mapRequired("FullName", fullModuleName); + io.mapRequired("IsPartOfFramework", isPartOfFramework); + io.mapRequired("IsSystemModule", isSystem); + io.mapRequired("Libraries", libs); + } +}; + +// std::pair> +template <> +struct MappingTraits > > { + static void mapping( + IO& io, std::pair >& module) { + io.mapRequired("Module", module.first); + io.mapRequired("Items", module.second); + } +}; + +// Type * +template <> +struct MappingTraits { + static void mapping(IO& io, Meta::Type*& type) { + Meta::TypeType typeType = type->getType(); + io.mapRequired("Type", typeType); + + switch (typeType) { + case Meta::TypeType::TypeId: { + Meta::IdType& concreteType = type->as(); + std::vector protocols; + for (Meta::ProtocolMeta* protocol : concreteType.protocols) { + protocols.push_back(protocol->jsName); } - }; - - // InterfaceMeta * - template <> - struct MappingTraits { - - static void mapping(IO& io, Meta::InterfaceMeta*& meta) - { - Meta::BaseClassMeta* baseClassMeta = &meta->as(); - MappingTraits::mapping(io, baseClassMeta); - if (meta->base != nullptr) { - io.mapRequired("Base", meta->base->jsName); - } + io.mapRequired("WithProtocols", protocols); + break; + } + case Meta::TypeType::TypeConstantArray: { + Meta::ConstantArrayType& concreteType = + type->as(); + io.mapRequired("ArrayType", concreteType.innerType); + io.mapRequired("Size", concreteType.size); + break; + } + case Meta::TypeType::TypeIncompleteArray: { + Meta::IncompleteArrayType& concreteType = + type->as(); + io.mapRequired("ArrayType", concreteType.innerType); + break; + } + case Meta::TypeType::TypeInterface: { + Meta::InterfaceType& concreteType = type->as(); + io.mapRequired("Name", concreteType.interface->name); + if (concreteType.typeArguments.size() > 0) { + std::vector typeArguments; + for (Meta::Type* type : concreteType.typeArguments) { + typeArguments.push_back(type); + } + io.mapRequired("TypeParameters", typeArguments); } - }; - - // ProtocolMeta * - template <> - struct MappingTraits { - - static void mapping(IO& io, Meta::ProtocolMeta*& meta) - { - Meta::BaseClassMeta* baseClassMeta = &meta->as(); - MappingTraits::mapping(io, baseClassMeta); + std::vector protocols; + for (Meta::ProtocolMeta* protocol : concreteType.protocols) { + protocols.push_back(protocol->jsName); } - }; - - // CategoryMeta * - template <> - struct MappingTraits { - - static void mapping(IO& io, Meta::CategoryMeta*& meta) - { - Meta::BaseClassMeta* baseClassMeta = &meta->as(); - MappingTraits::mapping(io, baseClassMeta); - io.mapRequired("ExtendedInterface", meta->extendedInterface); + io.mapRequired("WithProtocols", protocols); + break; + } + case Meta::TypeType::TypeBridgedInterface: { + Meta::BridgedInterfaceType& concreteType = + type->as(); + io.mapRequired("Name", concreteType.name); + std::string bridgedTo = + concreteType.isId() ? "id" + : (concreteType.bridgedInterface == nullptr + ? "[None]" + : concreteType.bridgedInterface->jsName); + io.mapRequired("BridgedTo", bridgedTo); + break; + } + case Meta::TypeType::TypePointer: { + Meta::PointerType& concreteType = type->as(); + io.mapRequired("PointerType", concreteType.innerType); + break; + } + case Meta::TypeType::TypeFunctionPointer: { + Meta::FunctionPointerType& concreteType = + type->as(); + io.mapRequired("Signature", concreteType.signature); + break; + } + case Meta::TypeType::TypeBlock: { + Meta::BlockType& concreteType = type->as(); + io.mapRequired("Signature", concreteType.signature); + break; + } + case Meta::TypeType::TypeStruct: { + Meta::StructType& concreteType = type->as(); + std::string fullModuleName = + concreteType.structMeta->module->getFullModuleName(); + io.mapRequired("Module", fullModuleName); + io.mapRequired("Name", concreteType.structMeta->name); + break; + } + case Meta::TypeType::TypeUnion: { + Meta::UnionType& concreteType = type->as(); + std::string fullModuleName = + concreteType.unionMeta->module->getFullModuleName(); + io.mapRequired("Module", fullModuleName); + io.mapRequired("Name", concreteType.unionMeta->name); + break; + } + case Meta::TypeType::TypeAnonymousStruct: { + Meta::AnonymousStructType& concreteType = + type->as(); + io.mapRequired("Fields", concreteType.fields); + break; + } + case Meta::TypeType::TypeAnonymousUnion: { + Meta::AnonymousUnionType& concreteType = + type->as(); + io.mapRequired("Fields", concreteType.fields); + break; + } + case Meta::TypeType::TypeEnum: { + Meta::EnumType& concreteType = type->as(); + io.mapRequired("Name", concreteType.enumMeta->jsName); + break; + } + case Meta::TypeType::TypeTypeArgument: { + Meta::TypeArgumentType& concreteType = + type->as(); + io.mapRequired("Name", concreteType.name); + io.mapRequired("UnderlyingType", concreteType.underlyingType); + std::vector protocols; + for (Meta::ProtocolMeta* protocol : concreteType.protocols) { + protocols.push_back(protocol->jsName); } - }; - - // Meta * - // These traits check which is the actual run-time type of the meta and forward to the corresponding traits. - template <> - struct MappingTraits { - - static void mapping(IO& io, Meta::Meta*& meta) - { - switch (meta->type) { - case Meta::MetaType::Function: { - Meta::FunctionMeta* functionMeta = &meta->as(); - MappingTraits::mapping(io, functionMeta); - break; - } - case Meta::MetaType::Struct: { - Meta::StructMeta* structMeta = &meta->as(); - MappingTraits::mapping(io, structMeta); - break; - } - case Meta::MetaType::Union: { - Meta::UnionMeta* unionMeta = &meta->as(); - MappingTraits::mapping(io, unionMeta); - break; - } - case Meta::MetaType::Var: { - Meta::VarMeta* varMeta = &meta->as(); - MappingTraits::mapping(io, varMeta); - break; - } - case Meta::MetaType::Enum: { - Meta::EnumMeta* enumMeta = &meta->as(); - MappingTraits::mapping(io, enumMeta); - break; - } - case Meta::MetaType::EnumConstant: { - Meta::EnumConstantMeta* enumConstantMeta = &meta->as(); - MappingTraits::mapping(io, enumConstantMeta); - break; - } - case Meta::MetaType::Interface: { - Meta::InterfaceMeta* interfaceMeta = &meta->as(); - MappingTraits::mapping(io, interfaceMeta); - break; - } - case Meta::MetaType::Protocol: { - Meta::ProtocolMeta* protocolMeta = &meta->as(); - MappingTraits::mapping(io, protocolMeta); - break; - } - case Meta::MetaType::Category: { - Meta::CategoryMeta* categoryMeta = &meta->as(); - MappingTraits::mapping(io, categoryMeta); - break; - } - case Meta::MetaType::Method: { - Meta::MethodMeta* methodMeta = &meta->as(); - MappingTraits::mapping(io, methodMeta); - break; - } - case Meta::MetaType::Property: { - Meta::PropertyMeta* propertyMeta = &meta->as(); - MappingTraits::mapping(io, propertyMeta); - break; - } - case Meta::MetaType::Undefined: - default: { - throw std::runtime_error("Unknown type of meta object."); - } - } + if (protocols.size() > 0) { + io.mapRequired("WithProtocols", protocols); } - }; -} + break; + } + case Meta::TypeType::TypeExtVector: { + Meta::ExtVectorType& concreteType = type->as(); + io.mapRequired("ArrayType", concreteType.innerType); + io.mapRequired("Size", concreteType.size); + break; + } + case Meta::TypeType::TypeNullable: { + Meta::NullableType& concreteType = type->as(); + io.mapRequired("InnerType", concreteType.innerType); + break; + } + case Meta::TypeType::TypeNonNullable: { + Meta::NonNullableType& concreteType = type->as(); + io.mapRequired("InnerType", concreteType.innerType); + break; + } + default: { + } + } + } +}; + +static void mapBaseMeta(IO& io, Meta::Meta* meta) { + io.mapRequired("Name", meta->name); + io.mapRequired("JsName", meta->jsName); + if (!meta->demangledName.empty()) { + io.mapRequired("DemangledName", meta->demangledName); + } + io.mapRequired("Filename", meta->fileName); + io.mapRequired("Module", meta->module); + io.mapOptional("IntroducedIn", meta->introducedIn, + (Meta::Version)UNKNOWN_VERSION); + io.mapRequired("Flags", meta->flags); + io.mapRequired("Type", meta->type); } + +// MethodMeta * +template <> +struct MappingTraits { + static void mapping(IO& io, Meta::MethodMeta*& meta) { + mapBaseMeta(io, meta); + io.mapRequired("Signature", meta->signature); + } +}; + +// PropertyMeta * +template <> +struct MappingTraits { + static void mapping(IO& io, Meta::PropertyMeta*& meta) { + mapBaseMeta(io, meta); + + if (meta->getter) io.mapRequired("Getter", meta->getter); + if (meta->setter) io.mapRequired("Setter", meta->setter); + } +}; + +// BaseClassMeta * +template <> +struct MappingTraits { + static void mapping(IO& io, Meta::BaseClassMeta*& meta) { + mapBaseMeta(io, meta); + io.mapRequired("InstanceMethods", meta->instanceMethods); + io.mapRequired("StaticMethods", meta->staticMethods); + io.mapRequired("InstanceProperties", meta->instanceProperties); + io.mapRequired("StaticProperties", meta->staticProperties); + std::vector protocols; + for (Meta::ProtocolMeta* protocol : meta->protocols) { + protocols.push_back(protocol->jsName); + } + io.mapRequired("Protocols", protocols); + } +}; + +// FunctionMeta * +template <> +struct MappingTraits { + static void mapping(IO& io, Meta::FunctionMeta*& meta) { + mapBaseMeta(io, meta); + io.mapRequired("Signature", meta->signature); + } +}; + +// RecordField +template <> +struct MappingTraits { + static void mapping(IO& io, Meta::RecordField& field) { + io.mapRequired("Name", field.name); + io.mapRequired("Signature", field.encoding); + } +}; + +// RecordMeta * +template <> +struct MappingTraits { + static void mapping(IO& io, Meta::RecordMeta*& meta) { + mapBaseMeta(io, meta); + io.mapRequired("Fields", meta->fields); + } +}; + +// StructMeta * +template <> +struct MappingTraits { + static void mapping(IO& io, Meta::StructMeta*& meta) { + Meta::RecordMeta* recordMeta = &meta->as(); + MappingTraits::mapping(io, recordMeta); + } +}; + +// UnionMeta * +template <> +struct MappingTraits { + static void mapping(IO& io, Meta::UnionMeta*& meta) { + Meta::RecordMeta* recordMeta = &meta->as(); + MappingTraits::mapping(io, recordMeta); + } +}; + +// VarMeta * +template <> +struct MappingTraits { + static void mapping(IO& io, Meta::VarMeta*& meta) { + mapBaseMeta(io, meta); + io.mapRequired("Signature", meta->signature); + if (meta->hasValue) { + io.mapRequired("Value", meta->value); + } + } +}; + +// EnumField +template <> +struct MappingTraits { + static void mapping(IO& io, Meta::EnumField& field) { + io.mapRequired(field.name.c_str(), field.value); + } +}; + +// EnumMeta * +template <> +struct MappingTraits { + static void mapping(IO& io, Meta::EnumMeta*& meta) { + mapBaseMeta(io, meta); + io.mapRequired("FullNameFields", meta->fullNameFields); + io.mapRequired("SwiftNameFields", meta->swiftNameFields); + } +}; + +// EnumConstantMeta * +template <> +struct MappingTraits { + static void mapping(IO& io, Meta::EnumConstantMeta*& meta) { + mapBaseMeta(io, meta); + io.mapRequired("Value", meta->value); + } +}; + +// InterfaceMeta * +template <> +struct MappingTraits { + static void mapping(IO& io, Meta::InterfaceMeta*& meta) { + Meta::BaseClassMeta* baseClassMeta = &meta->as(); + MappingTraits::mapping(io, baseClassMeta); + if (meta->base != nullptr) { + io.mapRequired("Base", meta->base->jsName); + } + } +}; + +// ProtocolMeta * +template <> +struct MappingTraits { + static void mapping(IO& io, Meta::ProtocolMeta*& meta) { + Meta::BaseClassMeta* baseClassMeta = &meta->as(); + MappingTraits::mapping(io, baseClassMeta); + } +}; + +// CategoryMeta * +template <> +struct MappingTraits { + static void mapping(IO& io, Meta::CategoryMeta*& meta) { + Meta::BaseClassMeta* baseClassMeta = &meta->as(); + MappingTraits::mapping(io, baseClassMeta); + io.mapRequired("ExtendedInterface", meta->extendedInterface); + } +}; + +// Meta * +// These traits check which is the actual run-time type of the meta and forward +// to the corresponding traits. +template <> +struct MappingTraits { + static void mapping(IO& io, Meta::Meta*& meta) { + switch (meta->type) { + case Meta::MetaType::Function: { + Meta::FunctionMeta* functionMeta = &meta->as(); + MappingTraits::mapping(io, functionMeta); + break; + } + case Meta::MetaType::Struct: { + Meta::StructMeta* structMeta = &meta->as(); + MappingTraits::mapping(io, structMeta); + break; + } + case Meta::MetaType::Union: { + Meta::UnionMeta* unionMeta = &meta->as(); + MappingTraits::mapping(io, unionMeta); + break; + } + case Meta::MetaType::Var: { + Meta::VarMeta* varMeta = &meta->as(); + MappingTraits::mapping(io, varMeta); + break; + } + case Meta::MetaType::Enum: { + Meta::EnumMeta* enumMeta = &meta->as(); + MappingTraits::mapping(io, enumMeta); + break; + } + case Meta::MetaType::EnumConstant: { + Meta::EnumConstantMeta* enumConstantMeta = + &meta->as(); + MappingTraits::mapping(io, enumConstantMeta); + break; + } + case Meta::MetaType::Interface: { + Meta::InterfaceMeta* interfaceMeta = &meta->as(); + MappingTraits::mapping(io, interfaceMeta); + break; + } + case Meta::MetaType::Protocol: { + Meta::ProtocolMeta* protocolMeta = &meta->as(); + MappingTraits::mapping(io, protocolMeta); + break; + } + case Meta::MetaType::Category: { + Meta::CategoryMeta* categoryMeta = &meta->as(); + MappingTraits::mapping(io, categoryMeta); + break; + } + case Meta::MetaType::Method: { + Meta::MethodMeta* methodMeta = &meta->as(); + MappingTraits::mapping(io, methodMeta); + break; + } + case Meta::MetaType::Property: { + Meta::PropertyMeta* propertyMeta = &meta->as(); + MappingTraits::mapping(io, propertyMeta); + break; + } + case Meta::MetaType::Undefined: + default: { + throw std::runtime_error("Unknown type of meta object."); + } + } + } +}; +} // namespace yaml +} // namespace llvm