Example #1
0
        /// <summary>
        /// This will check for conflicts when finding interface functions. If there is a conflict
        /// the code output is likely to be undesirable.
        /// </summary>
        private void ValidateNoInterfaceFunctionConflict(UClass unrealClass, UFunction function,
                                                         UClass skipInterface, bool skipSelf)
        {
            FName     functionName     = function.GetFName();
            UFunction conflictFunction = null;

            foreach (FImplementedInterface implementedInterface in unrealClass.Interfaces)
            {
                UClass interfaceClass = implementedInterface.InterfaceClass;
                if (interfaceClass != null && interfaceClass != skipInterface)
                {
                    if ((conflictFunction = interfaceClass.FindFunctionByName(functionName, true)) != null)
                    {
                        break;
                    }
                }
            }

            if (conflictFunction == null && !skipSelf)
            {
                conflictFunction = unrealClass.FindFunctionByName(functionName, false);
            }

            if (conflictFunction == null)
            {
                UClass parentClass = unrealClass.GetSuperClass();
                if (parentClass != null)
                {
                    // Search the rest of the hierarchy
                    conflictFunction = parentClass.FindFunctionByName(functionName, true);
                }
            }

            if (conflictFunction != null)
            {
                string warning = "Function redefined in hierarchy where interfaces are used. This is likely going to produce " +
                                 "unexpected results and should be avoided where possible. ImplementedInClass: '" + unrealClass.GetPathName() +
                                 "' InterfaceFunc: '" + function.GetPathName() + "' ConflictFunc: '" + conflictFunction.GetPathName() + "'";
                FMessage.Log(ELogVerbosity.Warning, warning, "USharp-CodeGenerator");
            }
        }
Example #2
0
        private string GetFunctionSignature(UnrealModuleInfo module, UFunction function, UStruct owner, string customFunctionName,
                                            string customModifiers, bool stripAdditionalText, bool isImplementationMethod, List <string> namespaces)
        {
            bool isInterface     = owner != null && owner.IsChildOf <UInterface>();
            bool isDelegate      = function.HasAnyFunctionFlags(EFunctionFlags.Delegate | EFunctionFlags.MulticastDelegate);
            bool isStatic        = function.HasAnyFunctionFlags(EFunctionFlags.Static);
            bool isBlueprintType = owner != null && owner.IsA <UBlueprintGeneratedClass>();

            StringBuilder modifiers = new StringBuilder();

            if (!string.IsNullOrEmpty(customModifiers))
            {
                modifiers.Append(customModifiers);
            }
            else if (isInterface)
            {
                // Don't provide any modifiers for interfaces if there isn't one already provided
            }
            else
            {
                UFunction originalFunction;
                // NOTE: "isImplementationMethod" is talking about "_Implementation" methods.
                //       "isInterfaceImplementation" is talking about regular methods which are implementations for a interface.
                bool   isInterfaceImplementation;
                UClass originalOwner = GetOriginalFunctionOwner(function, out originalFunction, out isInterfaceImplementation);
                // All interface functions in the chain need to be public
                bool isInterfaceFunc = originalOwner != owner && originalOwner.HasAnyClassFlags(EClassFlags.Interface);

                if (isImplementationMethod || (function.HasAnyFunctionFlags(EFunctionFlags.Protected) &&
                                               !isInterfaceFunc && !isDelegate))
                {
                    modifiers.Append("protected");
                }
                else
                {
                    modifiers.Append("public");
                }
                if (isDelegate)
                {
                    modifiers.Append(" delegate");
                }
                if (isStatic)
                {
                    modifiers.Append(" static");
                }
                if (!isDelegate && !isStatic)
                {
                    if (function.HasAnyFunctionFlags(EFunctionFlags.BlueprintEvent))
                    {
                        UFunction superFunc = function.GetSuperFunction();
                        if (superFunc != null)
                        {
                            modifiers.Append(" override");
                        }
                        else
                        {
                            // This have should been filtered out in CanExportFunction()
                            Debug.Assert(originalOwner == owner || isInterfaceImplementation);

                            // Explicit will have the _Implementation as virtual and the function declaration as
                            // non-virtual (which is the same as C++)
                            if (!Settings.UseExplicitImplementationMethods || isImplementationMethod)
                            {
                                modifiers.Append(" virtual");
                            }
                        }
                    }
                    else
                    {
                        if (originalOwner != owner && !isInterfaceFunc)
                        {
                            // Add "new" if the parent class has a function with the same name but not BlueprintEvent.
                            // (don't do this for interface functions as we are implementing the function not redefining it)
                            modifiers.Append(" new");
                        }
                    }
                }
            }

            string returnType = "void";
            int    numReturns = 0;

            StringBuilder parameters = new StringBuilder();

            // index is the index into parameters string
            Dictionary <int, string> parameterDefaultsByIndex = new Dictionary <int, string>();

            // Once this is true all parameters from that point should also have defaults
            bool hasDefaultParameters = false;

            // Blueprint can define ref/out parameters with default values, this can't be translated to code
            bool invalidDefaultParams = false;

            // Info so we can avoid param name conflicts
            Dictionary <UProperty, string> paramNames = GetParamNames(function);

            // Generic array parameters
            string[] arrayParamNames = function.GetCommaSeperatedMetaData("ArrayParam");

            // Generic parameters depending on array type
            string[] arrayTypeDependentParamNames = function.GetCommaSeperatedMetaData("ArrayTypeDependentParams");

            // AutoCreateRefTerm will force ref on given parameter names (comma seperated)
            string[] autoRefParamNames = function.GetCommaSeperatedMetaData("AutoCreateRefTerm");

            // If this is a blueprint type try and getting the return value from the first out param (if there is only one out)
            UProperty blueprintReturnProperty = function.GetBlueprintReturnProperty();

            bool firstParameter = true;

            foreach (KeyValuePair <UProperty, string> param in paramNames)
            {
                UProperty parameter = param.Key;
                string    paramName = param.Value;

                string rawParamName = parameter.GetName();

                if (!parameter.HasAnyPropertyFlags(EPropertyFlags.Parm))
                {
                    continue;
                }

                if (parameter.HasAnyPropertyFlags(EPropertyFlags.ReturnParm) || parameter == blueprintReturnProperty)
                {
                    returnType = GetTypeName(parameter, namespaces);
                    numReturns++;
                }
                else
                {
                    if (firstParameter)
                    {
                        firstParameter = false;
                    }
                    else
                    {
                        parameters.Append(", ");
                    }

                    if (!parameter.HasAnyPropertyFlags(EPropertyFlags.ConstParm))
                    {
                        if (parameter.HasAnyPropertyFlags(EPropertyFlags.ReferenceParm) || autoRefParamNames.Contains(rawParamName))
                        {
                            parameters.Append("ref ");
                        }
                        else if (parameter.HasAnyPropertyFlags(EPropertyFlags.OutParm))
                        {
                            parameters.Append("out ");
                        }
                    }

                    string paramTypeName = GetTypeName(parameter, namespaces);
                    if (arrayParamNames.Contains(rawParamName))
                    {
                        int genericsIndex = paramTypeName.IndexOf('<');
                        if (genericsIndex >= 0)
                        {
                            paramTypeName = paramTypeName.Substring(0, genericsIndex) + "<T>";
                        }
                    }
                    else if (arrayTypeDependentParamNames.Contains(rawParamName))
                    {
                        paramTypeName = "T";
                    }

                    parameters.Append(paramTypeName + " " + paramName);

                    if (!invalidDefaultParams)
                    {
                        string defaultValue = GetParamDefaultValue(function, parameter, paramTypeName, ref hasDefaultParameters, ref invalidDefaultParams);
                        if (!string.IsNullOrEmpty(defaultValue) && !invalidDefaultParams)
                        {
                            if (isBlueprintType &&
                                (parameter.HasAnyPropertyFlags(EPropertyFlags.ReferenceParm | EPropertyFlags.OutParm) ||
                                 autoRefParamNames.Contains(rawParamName)))
                            {
                                invalidDefaultParams = true;
                            }
                            else
                            {
                                if (!hasDefaultParameters)
                                {
                                    hasDefaultParameters = true;
                                }
                                parameterDefaultsByIndex[parameters.Length] = " = " + defaultValue;
                            }
                        }
                    }
                }
            }

            if (numReturns > 1)
            {
                FMessage.Log(ELogVerbosity.Error, "More than 1 return on function '" + function.GetPathName() + "'");
            }

            // Insert the default parameters if they aren't invalid
            if (!invalidDefaultParams)
            {
                int offset = 0;
                foreach (KeyValuePair <int, string> parameterDefault in parameterDefaultsByIndex)
                {
                    parameters.Insert(parameterDefault.Key + offset, parameterDefault.Value);
                    offset += parameterDefault.Value.Length;
                }
            }

            string functionName = GetFunctionName(function);

            string additionalStr = string.Empty;

            if (isDelegate)
            {
                functionName  = GetTypeNameDelegate(function);
                additionalStr = ";";
            }
            //if (isInterface)
            //{
            //    additionalStr = ";";
            //}

            if (isImplementationMethod)
            {
                functionName += Settings.VarNames.ImplementationMethod;
            }

            if (!string.IsNullOrEmpty(customFunctionName))
            {
                functionName = customFunctionName;
            }
            if (stripAdditionalText)
            {
                additionalStr = string.Empty;
            }

            string generics = string.Empty;

            if (arrayParamNames.Length > 0 || arrayTypeDependentParamNames.Length > 0)
            {
                generics = "<T>";
            }

            if (modifiers.Length > 0)
            {
                modifiers.Append(' ');
            }
            return(string.Format("{0}{1} {2}{3}({4}){5}", modifiers, returnType, functionName, generics, parameters, additionalStr));
        }
Example #3
0
        // Move this somewhere else? Where would this be more appropriate?
        public static Type GetTypeFromProperty(UProperty prop)
        {
            if (prop == null)
            {
                return(null);
            }

            switch (prop.PropertyType)
            {
            case EPropertyType.Bool:
                return(typeof(bool));

            case EPropertyType.Int8:
                return(typeof(sbyte));

            case EPropertyType.Byte:
                return(typeof(byte));

            case EPropertyType.Int16:
                return(typeof(short));

            case EPropertyType.UInt16:
                return(typeof(ushort));

            case EPropertyType.Int:
                return(typeof(int));

            case EPropertyType.UInt32:
                return(typeof(uint));

            case EPropertyType.Int64:
                return(typeof(long));

            case EPropertyType.UInt64:
                return(typeof(ulong));

            case EPropertyType.Float:
                return(typeof(float));

            case EPropertyType.Double:
                return(typeof(double));

            case EPropertyType.Enum:
            {
                UEnum unrealEnum = (prop as UEnumProperty).GetEnum();
                if (unrealEnum == null)
                {
                    return(null);
                }

                Type enumType;
                ManagedUnrealModuleInfo.AllKnownUnrealTypes.TryGetValue(unrealEnum.GetPathName(), out enumType);
                return(enumType);
            }

            case EPropertyType.Str:
                return(typeof(string));

            case EPropertyType.Name:
                return(typeof(FName));

            case EPropertyType.Text:
                return(typeof(FText));

            case EPropertyType.Interface:
            {
                UClass unrealClassInterface = (prop as UInterfaceProperty).InterfaceClass;
                if (unrealClassInterface == null)
                {
                    return(null);
                }

                Type interfaceType;
                ManagedUnrealModuleInfo.AllKnownUnrealTypes.TryGetValue(unrealClassInterface.GetPathName(), out interfaceType);
                return(interfaceType);
            }

            case EPropertyType.Struct:
            {
                UScriptStruct unrealStruct = (prop as UStructProperty).Struct;
                if (unrealStruct == null)
                {
                    return(null);
                }

                Type structType;
                ManagedUnrealModuleInfo.AllKnownUnrealTypes.TryGetValue(unrealStruct.GetPathName(), out structType);
                return(structType);
            }

            case EPropertyType.Class:
            case EPropertyType.Object:
            case EPropertyType.LazyObject:
            case EPropertyType.WeakObject:
            case EPropertyType.SoftClass:
            case EPropertyType.SoftObject:
            {
                UClass objectClass = (prop as UObjectPropertyBase).PropertyClass;
                switch (prop.PropertyType)
                {
                case EPropertyType.Class:
                    objectClass = (prop as UClassProperty).MetaClass;
                    break;

                case EPropertyType.SoftClass:
                    objectClass = (prop as USoftClassProperty).MetaClass;
                    break;
                }

                Type type = null;
                if (objectClass != null)
                {
                    // Could use UClass.GetType but using AllKnownUnrealTypes for slightly more coverage
                    // UClass.GetType(objectClass)
                    ManagedUnrealModuleInfo.AllKnownUnrealTypes.TryGetValue(objectClass.GetPathName(), out type);
                }

                if (type == null)
                {
                    //classType = typeof(UObject);// Fall back to UObject? Return null?
                    return(null);
                }
                switch (prop.PropertyType)
                {
                case EPropertyType.Class: return(typeof(TSubclassOf <>).MakeGenericType(type));

                case EPropertyType.LazyObject: return(typeof(TLazyObject <>).MakeGenericType(type));

                case EPropertyType.WeakObject: return(typeof(TWeakObject <>).MakeGenericType(type));

                case EPropertyType.SoftClass: return(typeof(TSoftClass <>).MakeGenericType(type));

                case EPropertyType.SoftObject: return(typeof(TSoftObject <>).MakeGenericType(type));

                case EPropertyType.Object: return(type);
                }
                return(type);
            }

            case EPropertyType.Delegate:
            case EPropertyType.MulticastDelegate:
                Type      delegateType  = null;
                UFunction signatureFunc = null;
                if (prop.PropertyType == EPropertyType.Delegate)
                {
                    signatureFunc = (prop as UDelegateProperty).SignatureFunction;
                }
                else if (prop.PropertyType == EPropertyType.MulticastDelegate)
                {
                    signatureFunc = (prop as UMulticastDelegateProperty).SignatureFunction;
                }
                if (signatureFunc != null)
                {
                    if (ManagedUnrealModuleInfo.AllKnownUnrealTypes.TryGetValue(signatureFunc.GetPathName(), out delegateType))
                    {
                        if (prop.PropertyType == EPropertyType.Delegate)
                        {
                            if (!delegateType.IsSameOrSubclassOfGeneric(typeof(FDelegate <>)))
                            {
                                delegateType = null;
                            }
                        }
                        else if (prop.PropertyType == EPropertyType.MulticastDelegate)
                        {
                            if (!delegateType.IsSameOrSubclassOfGeneric(typeof(FMulticastDelegate <>)))
                            {
                                delegateType = null;
                            }
                        }
                    }
                }
                return(delegateType);

            case EPropertyType.Array:
            {
                UArrayProperty arrayProp = prop as UArrayProperty;
                Type           innerType = GetTypeFromProperty(arrayProp.Inner);
                if (innerType != null)
                {
                    // Possibly handle IReadOnlyList?
                    return(typeof(IList <>).MakeGenericType(innerType));
                }
                return(null);
            }

            case EPropertyType.Set:
            {
                USetProperty setProp   = prop as USetProperty;
                Type         innerType = GetTypeFromProperty(setProp.ElementProp);
                if (innerType != null)
                {
                    return(typeof(ISet <>).MakeGenericType(innerType));
                }
                return(null);
            }

            case EPropertyType.Map:
            {
                UMapProperty mapProp   = prop as UMapProperty;
                Type         keyType   = GetTypeFromProperty(mapProp.KeyProp);
                Type         valueType = GetTypeFromProperty(mapProp.ValueProp);
                if (keyType != null && valueType != null)
                {
                    // Possibly handle IReadOnlyDictionary?
                    return(typeof(IDictionary <,>).MakeGenericType(keyType, valueType));
                }
                return(null);
            }
            }

            return(null);
        }