diff --git a/Source/Tools/Flax.Build/Bindings/ApiTypeInfo.cs b/Source/Tools/Flax.Build/Bindings/ApiTypeInfo.cs index 3e2ad1b31..6667aab9f 100644 --- a/Source/Tools/Flax.Build/Bindings/ApiTypeInfo.cs +++ b/Source/Tools/Flax.Build/Bindings/ApiTypeInfo.cs @@ -71,6 +71,13 @@ namespace Flax.Build.Bindings } } + public void EnsureInited(Builder.BuildData buildData) + { + if (IsInited) + return; + Init(buildData); + } + public virtual void Init(Builder.BuildData buildData) { IsInited = true; diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Api.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Api.cs index 27c902a5c..ded954e5a 100644 --- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Api.cs +++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Api.cs @@ -261,7 +261,7 @@ namespace Flax.Build.Bindings { if (typeInfo == null) return null; - var result = FindApiTypeInfoInner(typeInfo, caller); + var result = FindApiTypeInfoInner(buildData, typeInfo, caller); if (result != null) return result; if (buildData.TypeCache.TryGetValue(typeInfo, out result)) @@ -274,7 +274,7 @@ namespace Flax.Build.Bindings // Find across all loaded modules for this build foreach (var e in buildData.ModulesInfo) { - result = FindApiTypeInfoInner(typeInfo, e.Value); + result = FindApiTypeInfoInner(buildData, typeInfo, e.Value); if (result != null) { buildData.TypeCache.Add(typeInfo, result); @@ -291,7 +291,7 @@ namespace Flax.Build.Bindings { if (result == null) return null; - result = FindApiTypeInfoInner(new TypeInfo { Type = nesting[i], }, result); + result = FindApiTypeInfoInner(buildData, new TypeInfo { Type = nesting[i], }, result); } return result; } @@ -301,14 +301,17 @@ namespace Flax.Build.Bindings return null; } - private static ApiTypeInfo FindApiTypeInfoInner(TypeInfo typeInfo, ApiTypeInfo parent) + private static ApiTypeInfo FindApiTypeInfoInner(BuildData buildData, TypeInfo typeInfo, ApiTypeInfo parent) { foreach (var child in parent.Children) { if (child.Name == typeInfo.Type) + { + child.EnsureInited(buildData); return child; + } - var result = FindApiTypeInfoInner(typeInfo, child); + var result = FindApiTypeInfoInner(buildData, typeInfo, child); if (result != null) return result; } diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs index 26fa55231..cf30bfae3 100644 --- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs +++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs @@ -14,7 +14,7 @@ namespace Flax.Build.Bindings private static readonly HashSet CSharpUsedNamespaces = new HashSet(); private static readonly List CSharpUsedNamespacesSorted = new List(); - private static readonly Dictionary CSharpNativeToManagedBasicTypes = new Dictionary() + internal static readonly Dictionary CSharpNativeToManagedBasicTypes = new Dictionary() { // Language types { "int8", "sbyte" }, @@ -32,7 +32,7 @@ namespace Flax.Build.Bindings { "double", "double" }, }; - private static readonly Dictionary CSharpNativeToManagedDefault = new Dictionary() + internal static readonly Dictionary CSharpNativeToManagedDefault = new Dictionary() { // Engine types { "String", "string" }, @@ -527,7 +527,7 @@ namespace Flax.Build.Bindings contents.Append("abstract "); contents.Append("unsafe partial class ").Append(classInfo.Name); if (classInfo.BaseType != null && !classInfo.IsBaseTypeHidden) - contents.Append(" : ").Append(GenerateCSharpNativeToManaged(buildData, classInfo.BaseType, classInfo)); + contents.Append(" : ").Append(GenerateCSharpNativeToManaged(buildData, new TypeInfo { Type = classInfo.BaseType.Name }, classInfo)); contents.AppendLine(); contents.Append(indent + "{"); indent += " "; @@ -861,7 +861,7 @@ namespace Flax.Build.Bindings contents.Append("private "); contents.Append("unsafe partial struct ").Append(structureInfo.Name); if (structureInfo.BaseType != null && structureInfo.IsPod) - contents.Append(" : ").Append(GenerateCSharpNativeToManaged(buildData, structureInfo.BaseType, structureInfo)); + contents.Append(" : ").Append(GenerateCSharpNativeToManaged(buildData, new TypeInfo { Type = structureInfo.BaseType.Name }, structureInfo)); contents.AppendLine(); contents.Append(indent + "{"); indent += " "; diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cache.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cache.cs index 8fc7d18f2..0bb1f4cc7 100644 --- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cache.cs +++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cache.cs @@ -19,7 +19,7 @@ namespace Flax.Build.Bindings partial class BindingsGenerator { private static readonly Dictionary TypeCache = new Dictionary(); - private const int CacheVersion = 7; + private const int CacheVersion = 8; internal static void Write(BinaryWriter writer, string e) { diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs index 78fd3df73..a2fffddd4 100644 --- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs +++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs @@ -1095,7 +1095,7 @@ namespace Flax.Build.Bindings var baseType = classInfo?.BaseType ?? structureInfo?.BaseType; if (classInfo != null && classInfo.IsBaseTypeHidden) baseType = null; - if (baseType != null && (baseType.Type == "PersistentScriptingObject" || baseType.Type == "ScriptingObject")) + if (baseType != null && (baseType.Name == "PersistentScriptingObject" || baseType.Name == "ScriptingObject")) baseType = null; CppAutoSerializeFields.Clear(); CppAutoSerializeProperties.Clear(); @@ -1105,7 +1105,7 @@ namespace Flax.Build.Bindings contents.Append($"void {typeNameNative}::Serialize(SerializeStream& stream, const void* otherObj)").AppendLine(); contents.Append('{').AppendLine(); if (baseType != null) - contents.Append($" {baseType}::Serialize(stream, otherObj);").AppendLine(); + contents.Append($" {baseType.FullNameNative}::Serialize(stream, otherObj);").AppendLine(); contents.Append($" SERIALIZE_GET_OTHER_OBJ({typeNameNative});").AppendLine(); if (classInfo != null) @@ -1161,7 +1161,7 @@ namespace Flax.Build.Bindings contents.Append($"void {typeNameNative}::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier)").AppendLine(); contents.Append('{').AppendLine(); if (baseType != null) - contents.Append($" {baseType}::Deserialize(stream, modifier);").AppendLine(); + contents.Append($" {baseType.FullNameNative}::Deserialize(stream, modifier);").AppendLine(); foreach (var fieldInfo in CppAutoSerializeFields) { @@ -1554,7 +1554,7 @@ namespace Flax.Build.Bindings else contents.Append($"(ScriptingType::SpawnHandler)&{classTypeNameNative}::Spawn, "); if (classInfo.BaseType != null && useScripting) - contents.Append($"&{classInfo.BaseType}::TypeInitializer, "); + contents.Append($"&{classInfo.BaseType.FullNameNative}::TypeInitializer, "); else contents.Append("nullptr, "); contents.Append(setupScriptVTable); @@ -1566,7 +1566,7 @@ namespace Flax.Build.Bindings else contents.Append($"&{classTypeNameInternal}Internal::Ctor, &{classTypeNameInternal}Internal::Dtor, "); if (classInfo.BaseType != null) - contents.Append($"&{classInfo.BaseType}::TypeInitializer"); + contents.Append($"&{classInfo.BaseType.FullNameNative}::TypeInitializer"); else contents.Append("nullptr"); } diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Parsing.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Parsing.cs index 67e90efa9..8ed4a1634 100644 --- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Parsing.cs +++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Parsing.cs @@ -416,38 +416,38 @@ namespace Flax.Build.Bindings token = accessToken; break; } - - var baseTypeInfo = new TypeInfo + var inheritType = new TypeInfo { Type = token.Value, }; - if (token.Value.Length > 2 && token.Value[0] == 'I' && char.IsUpper(token.Value[1])) - { - // Interface - if (desc.InterfaceNames == null) - desc.InterfaceNames = new List(); - desc.InterfaceNames.Add(baseTypeInfo); - token = context.Tokenizer.NextToken(); - continue; - } - - if (desc.BaseType != null) - { - // Allow for multiple base classes, just the first one needs to be a valid base type - break; - throw new Exception($"Invalid '{desc.Name}' inheritance (only single base class is allowed for scripting types, excluding interfaces)."); - } - desc.BaseType = baseTypeInfo; + if (desc.Inheritance == null) + desc.Inheritance = new List(); + desc.Inheritance.Add(inheritType); token = context.Tokenizer.NextToken(); if (token.Type == TokenType.LeftCurlyBrace) { break; } + if (token.Type == TokenType.Colon) + { + token = context.Tokenizer.ExpectToken(TokenType.Colon); + token = context.Tokenizer.NextToken(); + inheritType.Type = token.Value; + token = context.Tokenizer.NextToken(); + continue; + } + if (token.Type == TokenType.DoubleColon) + { + token = context.Tokenizer.NextToken(); + inheritType.Type += token.Value; + token = context.Tokenizer.NextToken(); + continue; + } if (token.Type == TokenType.LeftAngleBracket) { var genericType = context.Tokenizer.ExpectToken(TokenType.Identifier); token = context.Tokenizer.ExpectToken(TokenType.RightAngleBracket); - desc.BaseType.GenericArgs = new List + inheritType.GenericArgs = new List { new TypeInfo { @@ -456,9 +456,9 @@ namespace Flax.Build.Bindings }; // TODO: find better way to resolve this (custom base type attribute?) - if (desc.BaseType.Type == "ShaderAssetTypeBase") + if (inheritType.Type == "ShaderAssetTypeBase") { - desc.BaseType = desc.BaseType.GenericArgs[0]; + desc.Inheritance[desc.Inheritance.Count - 1] = inheritType.GenericArgs[0]; } token = context.Tokenizer.NextToken(); diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.cs index f8d26314f..fa219477a 100644 --- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.cs +++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; using System.IO; -using System.Linq; using System.Threading; using System.Threading.Tasks; using Flax.Build.NativeCpp; @@ -109,13 +108,6 @@ namespace Flax.Build.Bindings if (LoadCache(ref moduleInfo, moduleOptions, headerFiles)) { buildData.ModulesInfo[module] = moduleInfo; - - // Initialize API - using (new ProfileEventScope("Init")) - { - moduleInfo.Init(buildData); - } - return moduleInfo; } } @@ -164,12 +156,6 @@ namespace Flax.Build.Bindings } } - // Initialize API - using (new ProfileEventScope("Init")) - { - moduleInfo.Init(buildData); - } - return moduleInfo; } @@ -533,23 +519,10 @@ namespace Flax.Build.Bindings if (moduleInfo.IsFromCache) return; - // Process parsed API - using (new ProfileEventScope("Process")) + // Initialize parsed API + using (new ProfileEventScope("Init")) { - foreach (var child in moduleInfo.Children) - { - try - { - foreach (var apiTypeInfo in child.Children) - ProcessAndValidate(buildData, apiTypeInfo); - } - catch (Exception) - { - if (child is FileInfo fileInfo) - Log.Error($"Failed to validate '{fileInfo.Name}' file to generate bindings."); - throw; - } - } + moduleInfo.Init(buildData); } // Generate bindings for scripting @@ -583,122 +556,5 @@ namespace Flax.Build.Bindings } } } - - private static void ProcessAndValidate(BuildData buildData, ApiTypeInfo apiTypeInfo) - { - if (apiTypeInfo is ClassInfo classInfo) - ProcessAndValidate(buildData, classInfo); - else if (apiTypeInfo is StructureInfo structureInfo) - ProcessAndValidate(buildData, structureInfo); - - foreach (var child in apiTypeInfo.Children) - ProcessAndValidate(buildData, child); - } - - private static void ProcessAndValidate(BuildData buildData, ClassInfo classInfo) - { - if (classInfo.UniqueFunctionNames == null) - classInfo.UniqueFunctionNames = new HashSet(); - - foreach (var fieldInfo in classInfo.Fields) - { - if (fieldInfo.Access == AccessLevel.Private) - continue; - - fieldInfo.Getter = new FunctionInfo - { - Name = "Get" + fieldInfo.Name, - Comment = fieldInfo.Comment, - IsStatic = fieldInfo.IsStatic, - Access = fieldInfo.Access, - Attributes = fieldInfo.Attributes, - ReturnType = fieldInfo.Type, - Parameters = new List(), - IsVirtual = false, - IsConst = true, - Glue = new FunctionInfo.GlueInfo() - }; - ProcessAndValidate(classInfo, fieldInfo.Getter); - fieldInfo.Getter.Name = fieldInfo.Name; - - if (!fieldInfo.IsReadOnly) - { - fieldInfo.Setter = new FunctionInfo - { - Name = "Set" + fieldInfo.Name, - Comment = fieldInfo.Comment, - IsStatic = fieldInfo.IsStatic, - Access = fieldInfo.Access, - Attributes = fieldInfo.Attributes, - ReturnType = new TypeInfo - { - Type = "void", - }, - Parameters = new List - { - new FunctionInfo.ParameterInfo - { - Name = "value", - Type = fieldInfo.Type, - }, - }, - IsVirtual = false, - IsConst = true, - Glue = new FunctionInfo.GlueInfo() - }; - ProcessAndValidate(classInfo, fieldInfo.Setter); - fieldInfo.Setter.Name = fieldInfo.Name; - } - } - - foreach (var propertyInfo in classInfo.Properties) - { - if (propertyInfo.Getter != null) - ProcessAndValidate(classInfo, propertyInfo.Getter); - if (propertyInfo.Setter != null) - ProcessAndValidate(classInfo, propertyInfo.Setter); - } - - foreach (var functionInfo in classInfo.Functions) - ProcessAndValidate(classInfo, functionInfo); - } - - private static void ProcessAndValidate(BuildData buildData, StructureInfo structureInfo) - { - foreach (var fieldInfo in structureInfo.Fields) - { - if (fieldInfo.Type.IsBitField) - throw new NotImplementedException($"TODO: support bit-fields in structure fields (found field {fieldInfo} in structure {structureInfo.Name})"); - - // Pointers are fine - if (fieldInfo.Type.IsPtr) - continue; - - // In-build types - if (CSharpNativeToManagedBasicTypes.ContainsKey(fieldInfo.Type.Type)) - continue; - if (CSharpNativeToManagedDefault.ContainsKey(fieldInfo.Type.Type)) - continue; - - // Find API type info for this field type - var apiType = FindApiTypeInfo(buildData, fieldInfo.Type, structureInfo); - if (apiType != null) - continue; - - throw new Exception($"Unknown field type '{fieldInfo.Type} {fieldInfo.Name}' in structure '{structureInfo.Name}'."); - } - } - - private static void ProcessAndValidate(ClassInfo classInfo, FunctionInfo functionInfo) - { - // Ensure that methods have unique names for bindings - if (classInfo.UniqueFunctionNames == null) - classInfo.UniqueFunctionNames = new HashSet(); - int idx = 1; - functionInfo.UniqueName = functionInfo.Name; - while (classInfo.UniqueFunctionNames.Contains(functionInfo.UniqueName)) - functionInfo.UniqueName = functionInfo.Name + idx++; - classInfo.UniqueFunctionNames.Add(functionInfo.UniqueName); - } } } diff --git a/Source/Tools/Flax.Build/Bindings/ClassInfo.cs b/Source/Tools/Flax.Build/Bindings/ClassInfo.cs index c68ff1a59..ff0bb077b 100644 --- a/Source/Tools/Flax.Build/Bindings/ClassInfo.cs +++ b/Source/Tools/Flax.Build/Bindings/ClassInfo.cs @@ -57,22 +57,87 @@ namespace Flax.Build.Bindings _isScriptingObject = true; else if (BaseType == null) _isScriptingObject = false; - else if (InBuildScriptingObjectTypes.Contains(BaseType.Type)) + else if (InBuildScriptingObjectTypes.Contains(BaseType.Name)) _isScriptingObject = true; else + _isScriptingObject = BaseType != null && BaseType.IsScriptingObject; + + if (UniqueFunctionNames == null) + UniqueFunctionNames = new HashSet(); + + foreach (var fieldInfo in Fields) { - var baseApiTypeInfo = BindingsGenerator.FindApiTypeInfo(buildData, BaseType, this); - if (baseApiTypeInfo != null) + if (fieldInfo.Access == AccessLevel.Private) + continue; + + fieldInfo.Getter = new FunctionInfo { - if (!baseApiTypeInfo.IsInited) - baseApiTypeInfo.Init(buildData); - _isScriptingObject = baseApiTypeInfo.IsScriptingObject; - } - else + Name = "Get" + fieldInfo.Name, + Comment = fieldInfo.Comment, + IsStatic = fieldInfo.IsStatic, + Access = fieldInfo.Access, + Attributes = fieldInfo.Attributes, + ReturnType = fieldInfo.Type, + Parameters = new List(), + IsVirtual = false, + IsConst = true, + Glue = new FunctionInfo.GlueInfo() + }; + ProcessAndValidate(fieldInfo.Getter); + fieldInfo.Getter.Name = fieldInfo.Name; + + if (!fieldInfo.IsReadOnly) { - _isScriptingObject = false; + fieldInfo.Setter = new FunctionInfo + { + Name = "Set" + fieldInfo.Name, + Comment = fieldInfo.Comment, + IsStatic = fieldInfo.IsStatic, + Access = fieldInfo.Access, + Attributes = fieldInfo.Attributes, + ReturnType = new TypeInfo + { + Type = "void", + }, + Parameters = new List + { + new FunctionInfo.ParameterInfo + { + Name = "value", + Type = fieldInfo.Type, + }, + }, + IsVirtual = false, + IsConst = true, + Glue = new FunctionInfo.GlueInfo() + }; + ProcessAndValidate(fieldInfo.Setter); + fieldInfo.Setter.Name = fieldInfo.Name; } } + + foreach (var propertyInfo in Properties) + { + if (propertyInfo.Getter != null) + ProcessAndValidate(propertyInfo.Getter); + if (propertyInfo.Setter != null) + ProcessAndValidate(propertyInfo.Setter); + } + + foreach (var functionInfo in Functions) + ProcessAndValidate(functionInfo); + } + + private void ProcessAndValidate(FunctionInfo functionInfo) + { + // Ensure that methods have unique names for bindings + if (UniqueFunctionNames == null) + UniqueFunctionNames = new HashSet(); + int idx = 1; + functionInfo.UniqueName = functionInfo.Name; + while (UniqueFunctionNames.Contains(functionInfo.UniqueName)) + functionInfo.UniqueName = functionInfo.Name + idx++; + UniqueFunctionNames.Add(functionInfo.UniqueName); } public override void Write(BinaryWriter writer) @@ -113,7 +178,7 @@ namespace Flax.Build.Bindings { if (_scriptVTableSize == -1) { - if (BindingsGenerator.FindApiTypeInfo(buildData, BaseType, this) is ClassInfo baseApiTypeInfo) + if (BaseType is ClassInfo baseApiTypeInfo) { _scriptVTableOffset = baseApiTypeInfo.GetScriptVTableSize(buildData, out _); } diff --git a/Source/Tools/Flax.Build/Bindings/ClassStructInfo.cs b/Source/Tools/Flax.Build/Bindings/ClassStructInfo.cs index 2f0dad003..ca1bb9257 100644 --- a/Source/Tools/Flax.Build/Bindings/ClassStructInfo.cs +++ b/Source/Tools/Flax.Build/Bindings/ClassStructInfo.cs @@ -1,5 +1,6 @@ // Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. +using System; using System.Collections.Generic; using System.IO; @@ -12,29 +13,37 @@ namespace Flax.Build.Bindings { public AccessLevel Access; public AccessLevel BaseTypeInheritance; - public TypeInfo BaseType; - public List Interfaces; // Optional - public List InterfaceNames; // Optional + public ClassStructInfo BaseType; + public List Interfaces; + public List Inheritance; // Data from parsing, used to interfaces and base type construct in Init public override void Init(Builder.BuildData buildData) { base.Init(buildData); - if (Interfaces == null && InterfaceNames != null && InterfaceNames.Count != 0) + if (BaseType == null && Interfaces == null && Inheritance != null) { - Interfaces = new List(); - for (var i = 0; i < InterfaceNames.Count; i++) + // Extract base class and interfaces from inheritance info + for (int i = 0; i < Inheritance.Count; i++) { - var interfaceName = InterfaceNames[i]; - var apiTypeInfo = BindingsGenerator.FindApiTypeInfo(buildData, interfaceName, this); + var apiTypeInfo = BindingsGenerator.FindApiTypeInfo(buildData, Inheritance[i], Parent); if (apiTypeInfo is InterfaceInfo interfaceInfo) { + if (Interfaces == null) + Interfaces = new List(); Interfaces.Add(interfaceInfo); } + else if (apiTypeInfo is ClassStructInfo otherInfo) + { + if (otherInfo == this) + throw new Exception($"Type '{Name}' inherits from itself."); + if (BaseType != null) + throw new Exception($"Invalid '{Name}' inheritance (only single base class is allowed for scripting types, excluding interfaces)."); + BaseType = otherInfo; + } } - if (Interfaces.Count == 0) - Interfaces = null; } + BaseType?.EnsureInited(buildData); } public override void Write(BinaryWriter writer) @@ -42,7 +51,7 @@ namespace Flax.Build.Bindings writer.Write((byte)Access); writer.Write((byte)BaseTypeInheritance); BindingsGenerator.Write(writer, BaseType); - BindingsGenerator.Write(writer, InterfaceNames); + BindingsGenerator.Write(writer, Inheritance); base.Write(writer); } @@ -52,7 +61,7 @@ namespace Flax.Build.Bindings Access = (AccessLevel)reader.ReadByte(); BaseTypeInheritance = (AccessLevel)reader.ReadByte(); BaseType = BindingsGenerator.Read(reader, BaseType); - InterfaceNames = BindingsGenerator.Read(reader, InterfaceNames); + Inheritance = BindingsGenerator.Read(reader, Inheritance); base.Read(reader); } diff --git a/Source/Tools/Flax.Build/Bindings/FileInfo.cs b/Source/Tools/Flax.Build/Bindings/FileInfo.cs index 6c4b4dcfe..7a38c8d87 100644 --- a/Source/Tools/Flax.Build/Bindings/FileInfo.cs +++ b/Source/Tools/Flax.Build/Bindings/FileInfo.cs @@ -17,6 +17,19 @@ namespace Flax.Build.Bindings base.AddChild(apiTypeInfo); } + public override void Init(Builder.BuildData buildData) + { + try + { + base.Init(buildData); + } + catch (Exception) + { + Log.Error($"Failed to init '{Name}' file scripting API."); + throw; + } + } + public int CompareTo(FileInfo other) { return Name.CompareTo(other.Name); diff --git a/Source/Tools/Flax.Build/Bindings/StructureInfo.cs b/Source/Tools/Flax.Build/Bindings/StructureInfo.cs index 5b664cc09..7e6888d91 100644 --- a/Source/Tools/Flax.Build/Bindings/StructureInfo.cs +++ b/Source/Tools/Flax.Build/Bindings/StructureInfo.cs @@ -26,14 +26,14 @@ namespace Flax.Build.Bindings { base.Init(buildData); - if (ForceNoPod || (InterfaceNames != null && InterfaceNames.Count != 0)) + if (ForceNoPod || (Interfaces != null && Interfaces.Count != 0)) { _isPod = false; return; } // Structure is POD (plain old data) only if all of it's fields are (and has no base type ro base type is also POD) - _isPod = BaseType == null || (BindingsGenerator.FindApiTypeInfo(buildData, BaseType, Parent)?.IsPod ?? false); + _isPod = BaseType == null || (BaseType?.IsPod ?? false); for (int i = 0; _isPod && i < Fields.Count; i++) { var field = Fields[i]; @@ -42,6 +42,29 @@ namespace Flax.Build.Bindings _isPod = false; } } + + foreach (var fieldInfo in Fields) + { + if (fieldInfo.Type.IsBitField) + throw new NotImplementedException($"TODO: support bit-fields in structure fields (found field {fieldInfo} in structure {Name})"); + + // Pointers are fine + if (fieldInfo.Type.IsPtr) + continue; + + // In-build types + if (BindingsGenerator.CSharpNativeToManagedBasicTypes.ContainsKey(fieldInfo.Type.Type)) + continue; + if (BindingsGenerator.CSharpNativeToManagedDefault.ContainsKey(fieldInfo.Type.Type)) + continue; + + // Find API type info for this field type + var apiType = BindingsGenerator.FindApiTypeInfo(buildData, fieldInfo.Type, this); + if (apiType != null) + continue; + + throw new Exception($"Unknown field type '{fieldInfo.Type} {fieldInfo.Name}' in structure '{Name}'."); + } } public override void Write(BinaryWriter writer) diff --git a/Source/Tools/Flax.Build/Bindings/TypeInfo.cs b/Source/Tools/Flax.Build/Bindings/TypeInfo.cs index 443b0687a..9268e5998 100644 --- a/Source/Tools/Flax.Build/Bindings/TypeInfo.cs +++ b/Source/Tools/Flax.Build/Bindings/TypeInfo.cs @@ -36,8 +36,7 @@ namespace Flax.Build.Bindings var apiType = BindingsGenerator.FindApiTypeInfo(buildData, this, caller); if (apiType != null) { - if (!apiType.IsInited) - apiType.Init(buildData); + apiType.EnsureInited(buildData); return apiType.IsPod; }