/// <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"); } }
/// <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); }