/// <summary> /// Searches the class hierarchy to find the original owner of the given function (by function name) /// </summary> private UClass GetOriginalFunctionOwner(UFunction function, out UFunction originalFunction, out bool isInterfaceImplementation) { KeyValuePair <UFunction, bool> funcInfo; if (lazyOriginalFunctionCache.TryGetValue(function, out funcInfo)) { originalFunction = funcInfo.Key; isInterfaceImplementation = funcInfo.Value; return(originalFunction.GetOwnerClass()); } UClass result = GetOriginalFunctionOwnerInternal(function, out originalFunction, out isInterfaceImplementation); lazyOriginalFunctionCache.Add(function, new KeyValuePair <UFunction, bool>(originalFunction, isInterfaceImplementation)); return(result); }
private void AppendFunctionOffsets(CSharpTextBuilder builder, CSharpTextBuilder offsetsBuilder, UFunction function, bool isGetter, bool isSetter, List <string> namespaces) { bool isInterface = false; UClass owner = function.GetOwnerClass(); if (owner != null && owner.ClassFlags.HasFlag(EClassFlags.Interface)) { isInterface = true; } string functionName = GetFunctionName(function); if (isGetter) { functionName += "_getter"; } else if (isSetter) { functionName += "_setter"; } Dictionary <UProperty, string> paramNames = GetParamNames(function); if (Settings.GenerateIsValidSafeguards) { builder.AppendLine("static bool " + functionName + Settings.VarNames.IsValid + ";"); } if ((function.HasAnyFunctionFlags(EFunctionFlags.BlueprintEvent) && function.GetSuperFunction() == null) || isInterface) { builder.AppendLine("IntPtr " + functionName + Settings.VarNames.InstanceFunctionAddress + ";"); } builder.AppendLine("static IntPtr " + functionName + Settings.VarNames.FunctionAddress + ";"); builder.AppendLine("static int " + functionName + Settings.VarNames.ParamsSize + ";"); foreach (KeyValuePair <UProperty, string> param in paramNames) { UProperty parameter = param.Key; string paramName = param.Value; if (!parameter.HasAnyPropertyFlags(EPropertyFlags.Parm)) { continue; } AppendPropertyOffset(builder, functionName + "_" + paramName, parameter, true, namespaces); } offsetsBuilder.AppendLine(functionName + Settings.VarNames.FunctionAddress + " = " + Names.NativeReflectionCached_GetFunction + "(" + Settings.VarNames.ClassAddress + ", \"" + function.GetName() + "\");"); offsetsBuilder.AppendLine(functionName + Settings.VarNames.ParamsSize + " = " + Names.NativeReflection_GetFunctionParamsSize + "(" + functionName + Settings.VarNames.FunctionAddress + ");"); foreach (KeyValuePair <UProperty, string> param in paramNames) { UProperty parameter = param.Key; string paramName = param.Value; if (!parameter.HasAnyPropertyFlags(EPropertyFlags.Parm)) { continue; } AppendPropertyOffsetNativeTypeLoader(offsetsBuilder, functionName + "_" + paramName, parameter, functionName); } if (Settings.GenerateIsValidSafeguards) { // XXXX_IsValid = param1_IsValid && param2_IsValid && param3_IsValid; string paramsValid = string.Join(" && ", paramNames.Values.Select(x => functionName + "_" + x + Settings.VarNames.IsValid)); if (!string.IsNullOrEmpty(paramsValid)) { paramsValid = " && " + paramsValid; } offsetsBuilder.AppendLine(functionName + Settings.VarNames.IsValid + " = " + functionName + Settings.VarNames.FunctionAddress + " != IntPtr.Zero" + paramsValid + ";"); offsetsBuilder.AppendLine(Names.NativeReflection_LogFunctionIsValid + "(\"" + function.GetPathName() + "\", " + functionName + Settings.VarNames.IsValid + ");"); } }
/// <summary> /// Searches the class hierarchy to find the original owner of the given function (by function name) /// </summary> private UClass GetOriginalFunctionOwnerInternal(UFunction function, out UFunction originalFunction, out bool isInterfaceImplementation) { // Interfaces really mess up this function. Two interfaces could potentially provide the same function // in the class hierarchy. Or a class up the chain could provide a function but also an interface with // the same function name could exist. None of this maps to C# well in terms of ensuring this is all handled // properly AND with name conflict resolution (which is what GetOriginalFunctionOwner is partially used for). // - We ALWAYS want use the first interface found with the same function name in order to produce valid C#. // (even if this then technically isn't necessarily the original function / owner). // - We should log when we find this type of situation where there are functions are redefined in a // class / interface combo (regular class:class conflict should be fine). // - TODO: Handle interface hierarchy FName functionName = function.GetFName(); isInterfaceImplementation = false; originalFunction = function; UClass owner = function.GetOwnerClass(); if (owner != null) { // First check the interfaces of THIS class. foreach (FImplementedInterface implementedInterface in owner.Interfaces) { UClass interfaceClass = implementedInterface.InterfaceClass; if (interfaceClass != null) { UFunction interfaceFunction = interfaceClass.FindFunctionByName(functionName, false); if (interfaceFunction != null) { originalFunction = interfaceFunction; ValidateNoInterfaceFunctionConflict(owner, originalFunction, interfaceClass, true); // We found the original function directly within one of the implemented interfaces. // This means the input function is an implementation for one of the interfaces. isInterfaceImplementation = true; return(interfaceClass); } } } UClass parentClass = owner.GetSuperClass(); while (parentClass != null) { // Check the interfaces of the parent class. foreach (FImplementedInterface implementedInterface in parentClass.Interfaces) { UClass interfaceClass = implementedInterface.InterfaceClass; if (interfaceClass != null) { UFunction interfaceFunction = interfaceClass.FindFunctionByName(functionName, false); if (interfaceFunction != null) { originalFunction = interfaceFunction; ValidateNoInterfaceFunctionConflict(parentClass, originalFunction, interfaceClass, false); return(interfaceClass); } } } UFunction parentFunction = parentClass.FindFunctionByName(functionName, false); if (parentFunction == null) { break; } originalFunction = parentFunction; owner = parentClass; parentClass = parentClass.GetSuperClass(); } } return(owner); }