You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
Removed GetEnum as much as possible. #rb self #rnx #preflight 60aba9191d02bb00011bb579 [CL 16435208 by Tim Smith in ue5-main branch]
444 lines
14 KiB
C++
444 lines
14 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
|
|
#include "ParserHelper.h"
|
|
#include "UnrealHeaderTool.h"
|
|
#include "Algo/Find.h"
|
|
#include "Misc/DefaultValueHelper.h"
|
|
#include "UnrealTypeDefinitionInfo.h"
|
|
#include "ClassMaps.h"
|
|
|
|
/////////////////////////////////////////////////////
|
|
// FPropertyBase
|
|
|
|
FPropertyBase::FPropertyBase(FUnrealEnumDefinitionInfo& InEnumDef, EPropertyType InType)
|
|
: Type(InType)
|
|
, ArrayType(EArrayType::None)
|
|
, PropertyFlags(CPF_None)
|
|
, ImpliedPropertyFlags(CPF_None)
|
|
, RefQualifier(ERefQualifier::None)
|
|
, PropertyExportFlags(PROPEXPORT_Public)
|
|
, EnumDef(&InEnumDef)
|
|
, DelegateName(NAME_None)
|
|
, DelegateSignatureOwnerClass(nullptr)
|
|
, RepNotifyName(NAME_None)
|
|
, PointerType(EPointerType::None)
|
|
, IntType(GetSizedIntTypeFromPropertyType(InType))
|
|
{
|
|
}
|
|
|
|
FPropertyBase::FPropertyBase(FUnrealClassDefinitionInfo& InClassDef, EPropertyType InType, bool bWeakIsAuto/* = false*/)
|
|
: Type(InType)
|
|
, ArrayType(EArrayType::None)
|
|
, PropertyFlags(CPF_None)
|
|
, ImpliedPropertyFlags(CPF_None)
|
|
, RefQualifier(ERefQualifier::None)
|
|
, PropertyExportFlags(PROPEXPORT_Public)
|
|
, ClassDef(&InClassDef)
|
|
, DelegateName(NAME_None)
|
|
, DelegateSignatureOwnerClass(nullptr)
|
|
, RepNotifyName(NAME_None)
|
|
, PointerType(EPointerType::None)
|
|
, IntType(EIntType::None)
|
|
{
|
|
if ((Type == CPT_WeakObjectReference) && bWeakIsAuto)
|
|
{
|
|
PropertyFlags |= CPF_AutoWeak;
|
|
}
|
|
}
|
|
|
|
FPropertyBase::FPropertyBase(FUnrealScriptStructDefinitionInfo& InStructDef)
|
|
: Type(CPT_Struct)
|
|
, ArrayType(EArrayType::None)
|
|
, PropertyFlags(CPF_None)
|
|
, ImpliedPropertyFlags(CPF_None)
|
|
, RefQualifier(ERefQualifier::None)
|
|
, PropertyExportFlags(PROPEXPORT_Public)
|
|
, ScriptStructDef(&InStructDef)
|
|
, DelegateName(NAME_None)
|
|
, DelegateSignatureOwnerClass(nullptr)
|
|
, RepNotifyName(NAME_None)
|
|
, PointerType(EPointerType::None)
|
|
, IntType(EIntType::None)
|
|
{
|
|
}
|
|
|
|
const TCHAR* FPropertyBase::GetPropertyTypeText( EPropertyType Type )
|
|
{
|
|
switch ( Type )
|
|
{
|
|
CASE_TEXT(CPT_None);
|
|
CASE_TEXT(CPT_Byte);
|
|
CASE_TEXT(CPT_Int8);
|
|
CASE_TEXT(CPT_Int16);
|
|
CASE_TEXT(CPT_Int);
|
|
CASE_TEXT(CPT_Int64);
|
|
CASE_TEXT(CPT_UInt16);
|
|
CASE_TEXT(CPT_UInt32);
|
|
CASE_TEXT(CPT_UInt64);
|
|
CASE_TEXT(CPT_Bool);
|
|
CASE_TEXT(CPT_Bool8);
|
|
CASE_TEXT(CPT_Bool16);
|
|
CASE_TEXT(CPT_Bool32);
|
|
CASE_TEXT(CPT_Bool64);
|
|
CASE_TEXT(CPT_Float);
|
|
CASE_TEXT(CPT_Double);
|
|
CASE_TEXT(CPT_ObjectReference);
|
|
CASE_TEXT(CPT_Interface);
|
|
CASE_TEXT(CPT_Name);
|
|
CASE_TEXT(CPT_Delegate);
|
|
CASE_TEXT(CPT_Struct);
|
|
CASE_TEXT(CPT_String);
|
|
CASE_TEXT(CPT_Text);
|
|
CASE_TEXT(CPT_MulticastDelegate);
|
|
CASE_TEXT(CPT_SoftObjectReference);
|
|
CASE_TEXT(CPT_WeakObjectReference);
|
|
CASE_TEXT(CPT_LazyObjectReference);
|
|
CASE_TEXT(CPT_ObjectPtrReference);
|
|
CASE_TEXT(CPT_Map);
|
|
CASE_TEXT(CPT_Set);
|
|
CASE_TEXT(CPT_FieldPath);
|
|
CASE_TEXT(CPT_MAX);
|
|
}
|
|
|
|
return TEXT("");
|
|
}
|
|
|
|
bool FPropertyBase::MatchesType(const FPropertyBase& Other, bool bDisallowGeneralization, bool bIgnoreImplementedInterfaces/* = false*/) const
|
|
{
|
|
check(Type != CPT_None || !bDisallowGeneralization);
|
|
|
|
bool bIsObjectType = IsObject();
|
|
bool bOtherIsObjectType = Other.IsObject();
|
|
bool bIsObjectComparison = bIsObjectType && bOtherIsObjectType;
|
|
bool bReverseClassChainCheck = true;
|
|
|
|
// If converting to an l-value, we require an exact match with an l-value.
|
|
if ((PropertyFlags & CPF_OutParm) != 0)
|
|
{
|
|
// if the other type is not an l-value, disallow
|
|
if ((Other.PropertyFlags & CPF_OutParm) == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// if the other type is const and we are not const, disallow
|
|
if ((Other.PropertyFlags & CPF_ConstParm) != 0 && (PropertyFlags & CPF_ConstParm) == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (Type == CPT_Struct)
|
|
{
|
|
// Allow derived structs to be passed by reference, unless this is a dynamic array of structs
|
|
bDisallowGeneralization = bDisallowGeneralization || ArrayType == EArrayType::Dynamic || Other.ArrayType == EArrayType::Dynamic;
|
|
}
|
|
|
|
// if Type == CPT_ObjectReference, out object function parm; allow derived classes to be passed in
|
|
// if Type == CPT_Interface, out interface function parm; allow derived classes to be passed in
|
|
else if ((PropertyFlags & CPF_ConstParm) == 0 || !IsObject())
|
|
{
|
|
// all other variable types must match exactly when passed as the value to an 'out' parameter
|
|
bDisallowGeneralization = true;
|
|
}
|
|
|
|
// both types are objects, but one is an interface and one is an object reference
|
|
else if (bIsObjectComparison && Type != Other.Type)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else if ((Type == CPT_ObjectReference || Type == CPT_WeakObjectReference || Type == CPT_LazyObjectReference || Type == CPT_ObjectPtrReference || Type == CPT_SoftObjectReference) && Other.Type != CPT_Interface && (PropertyFlags & CPF_ReturnParm))
|
|
{
|
|
bReverseClassChainCheck = false;
|
|
}
|
|
|
|
// Check everything.
|
|
if (Type == CPT_None && (Other.Type == CPT_None || !bDisallowGeneralization))
|
|
{
|
|
// If Other has no type, accept anything.
|
|
return true;
|
|
}
|
|
else if (Type != Other.Type && !bIsObjectComparison)
|
|
{
|
|
// Mismatched base types.
|
|
return false;
|
|
}
|
|
else if (ArrayType != Other.ArrayType)
|
|
{
|
|
// Mismatched array types.
|
|
return false;
|
|
}
|
|
else if (Type == CPT_Byte)
|
|
{
|
|
// Make sure enums match, or we're generalizing.
|
|
return EnumDef == Other.EnumDef || (EnumDef == NULL && !bDisallowGeneralization);
|
|
}
|
|
else if (bIsObjectType)
|
|
{
|
|
check(ClassDef != NULL);
|
|
|
|
// Make sure object types match, or we're generalizing.
|
|
if (bDisallowGeneralization)
|
|
{
|
|
// Exact match required.
|
|
return ClassDef == Other.ClassDef && MetaClassDef == Other.MetaClassDef;
|
|
}
|
|
else if (Other.ClassDef == NULL)
|
|
{
|
|
// Cannonical 'None' matches all object classes.
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
UClass* PropertyClass = ClassDef->GetClass();
|
|
UClass* OtherPropertyClass = Other.ClassDef->GetClass();
|
|
UClass* MetaClass = MetaClassDef ? MetaClassDef->GetClass() : nullptr;
|
|
UClass* OtherMetaClass = Other.MetaClassDef ? Other.MetaClassDef->GetClass() : nullptr;
|
|
// Generalization is ok (typical example of this check would look like: VarA = VarB;, where this is VarB and Other is VarA)
|
|
if (OtherPropertyClass->IsChildOf(PropertyClass))
|
|
{
|
|
if (!bIgnoreImplementedInterfaces || ((Type == CPT_Interface) == (Other.Type == CPT_Interface)))
|
|
{
|
|
if (!PropertyClass->IsChildOf(UClass::StaticClass()) || MetaClass == NULL || OtherMetaClass->IsChildOf(MetaClass) ||
|
|
(bReverseClassChainCheck && (OtherMetaClass == NULL || MetaClass->IsChildOf(OtherMetaClass))))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
// check the opposite class chain for object types
|
|
else if (bReverseClassChainCheck && Type != CPT_Interface && bIsObjectComparison && PropertyClass != NULL && PropertyClass->IsChildOf(OtherPropertyClass))
|
|
{
|
|
if (!OtherPropertyClass->IsChildOf(UClass::StaticClass()) || MetaClass == NULL || OtherMetaClass == NULL || MetaClass->IsChildOf(OtherMetaClass) || OtherMetaClass->IsChildOf(MetaClass))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (PropertyClass->HasAnyClassFlags(CLASS_Interface) && !bIgnoreImplementedInterfaces)
|
|
{
|
|
if (OtherPropertyClass->ImplementsInterface(PropertyClass))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
else if (Type == CPT_Struct)
|
|
{
|
|
check(ScriptStructDef != NULL);
|
|
check(Other.ScriptStructDef != NULL);
|
|
|
|
if (ScriptStructDef == Other.ScriptStructDef)
|
|
{
|
|
// struct types match exactly
|
|
return true;
|
|
}
|
|
|
|
// returning false here prevents structs related through inheritance from being used interchangeably, such as passing a derived struct as the value for a parameter
|
|
// that expects the base struct, or vice versa. An easier example is assignment (e.g. Vector = Plane or Plane = Vector).
|
|
// there are two cases to consider (let's use vector and plane for the example):
|
|
// - Vector = Plane;
|
|
// in this expression, 'this' is the vector, and Other is the plane. This is an unsafe conversion, as the destination property type is used to copy the r-value to the l-value
|
|
// so in this case, the VM would call CopyCompleteValue on the FPlane struct, which would copy 16 bytes into the l-value's buffer; However, the l-value buffer will only be
|
|
// 12 bytes because that is the size of FVector
|
|
// - Plane = Vector;
|
|
// in this expression, 'this' is the plane, and Other is the vector. This is a safe conversion, since only 12 bytes would be copied from the r-value into the l-value's buffer
|
|
// (which would be 16 bytes). The problem with allowing this conversion is that what to do with the extra member (e.g. Plane.W); should it be left alone? should it be zeroed?
|
|
// difficult to say what the correct behavior should be, so let's just ignore inheritance for the sake of determining whether two structs are identical
|
|
|
|
// Previously, the logic for determining whether this is a generalization of Other was reversed; this is very likely the culprit behind all current issues with
|
|
// using derived structs interchangeably with their base versions. The inheritance check has been fixed; for now, allow struct generalization and see if we can find any further
|
|
// issues with allowing conversion. If so, then we disable all struct generalization by returning false here.
|
|
// return false;
|
|
|
|
if (bDisallowGeneralization)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
UScriptStruct* Struct = ScriptStructDef->GetScriptStruct();
|
|
UScriptStruct* OtherStruct = Other.ScriptStructDef->GetScriptStruct();
|
|
|
|
// Generalization is ok if this is not a dynamic array
|
|
if (ArrayType != EArrayType::Dynamic && Other.ArrayType != EArrayType::Dynamic)
|
|
{
|
|
if (!OtherStruct->IsChildOf(Struct) && Struct->IsChildOf(OtherStruct))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
// General match.
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////
|
|
// FToken
|
|
|
|
/**
|
|
* Copies the properties from this token into another.
|
|
*
|
|
* @param Other the token to copy this token's properties to.
|
|
*/
|
|
FToken& FToken::operator=(const FToken& Other)
|
|
{
|
|
ConstantType = Other.ConstantType;
|
|
TokenType = Other.TokenType;
|
|
StartPos = Other.StartPos;
|
|
StartLine = Other.StartLine;
|
|
|
|
FCString::Strncpy(Identifier, Other.Identifier, NAME_SIZE);
|
|
FMemory::Memcpy(String, Other.String, sizeof(String));
|
|
|
|
return *this;
|
|
}
|
|
|
|
FToken& FToken::operator=(FToken&& Other)
|
|
{
|
|
ConstantType = Other.ConstantType;
|
|
TokenType = Other.TokenType;
|
|
StartPos = Other.StartPos;
|
|
StartLine = Other.StartLine;
|
|
|
|
FCString::Strncpy(Identifier, Other.Identifier, NAME_SIZE);
|
|
FMemory::Memcpy(String, Other.String, sizeof(String));
|
|
|
|
return *this;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////
|
|
// FFuncData
|
|
|
|
void FFuncInfo::SetFunctionNames(FUnrealFunctionDefinitionInfo& FunctionDef)
|
|
{
|
|
UFunction* FunctionReference = FunctionDef.GetFunction();
|
|
FString FunctionName = FunctionReference->GetName();
|
|
if (FunctionDef.HasAnyFunctionFlags(FUNC_Delegate))
|
|
{
|
|
FunctionName.LeftChopInline(FString(HEADER_GENERATED_DELEGATE_SIGNATURE_SUFFIX).Len(), false);
|
|
}
|
|
UnMarshallAndCallName = FString(TEXT("exec")) + FunctionName;
|
|
|
|
if (FunctionDef.HasAnyFunctionFlags(FUNC_BlueprintEvent))
|
|
{
|
|
MarshallAndCallName = FunctionName;
|
|
}
|
|
else
|
|
{
|
|
MarshallAndCallName = FString(TEXT("event")) + FunctionName;
|
|
}
|
|
|
|
if (FunctionDef.HasAllFunctionFlags(FUNC_Native | FUNC_Net))
|
|
{
|
|
MarshallAndCallName = FunctionName;
|
|
if (FunctionDef.HasAllFunctionFlags(FUNC_NetResponse))
|
|
{
|
|
// Response function implemented by programmer and called directly from thunk
|
|
CppImplName = FunctionReference->GetName();
|
|
}
|
|
else
|
|
{
|
|
if (CppImplName.IsEmpty())
|
|
{
|
|
CppImplName = FunctionReference->GetName() + TEXT("_Implementation");
|
|
}
|
|
else if (CppImplName == FunctionName)
|
|
{
|
|
FError::Throwf(TEXT("Native implementation function must be different than original function name."));
|
|
}
|
|
|
|
if (CppValidationImplName.IsEmpty() && FunctionDef.HasAllFunctionFlags(FUNC_NetValidate))
|
|
{
|
|
CppValidationImplName = FunctionReference->GetName() + TEXT("_Validate");
|
|
}
|
|
else if (CppValidationImplName == FunctionName)
|
|
{
|
|
FError::Throwf(TEXT("Validation function must be different than original function name."));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (FunctionDef.HasAllFunctionFlags(FUNC_Delegate))
|
|
{
|
|
MarshallAndCallName = FString(TEXT("delegate")) + FunctionName;
|
|
}
|
|
|
|
if (FunctionDef.HasAllFunctionFlags(FUNC_BlueprintEvent | FUNC_Native))
|
|
{
|
|
MarshallAndCallName = FunctionName;
|
|
CppImplName = FunctionReference->GetName() + TEXT("_Implementation");
|
|
}
|
|
|
|
if (CppImplName.IsEmpty())
|
|
{
|
|
CppImplName = FunctionName;
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////
|
|
// FAdvancedDisplayParameterHandler
|
|
static const FName NAME_AdvancedDisplay(TEXT("AdvancedDisplay"));
|
|
|
|
FAdvancedDisplayParameterHandler::FAdvancedDisplayParameterHandler(const TMap<FName, FString>* MetaData)
|
|
: NumberLeaveUnmarked(-1), AlreadyLeft(0), bUseNumber(false)
|
|
{
|
|
if(MetaData)
|
|
{
|
|
const FString* FoundString = MetaData->Find(NAME_AdvancedDisplay);
|
|
if(FoundString)
|
|
{
|
|
FoundString->ParseIntoArray(ParametersNames, TEXT(","), true);
|
|
for(int32 NameIndex = 0; NameIndex < ParametersNames.Num();)
|
|
{
|
|
FString& ParameterName = ParametersNames[NameIndex];
|
|
ParameterName.TrimStartAndEndInline();
|
|
if(ParameterName.IsEmpty())
|
|
{
|
|
ParametersNames.RemoveAtSwap(NameIndex);
|
|
}
|
|
else
|
|
{
|
|
++NameIndex;
|
|
}
|
|
}
|
|
if(1 == ParametersNames.Num())
|
|
{
|
|
bUseNumber = FDefaultValueHelper::ParseInt(ParametersNames[0], NumberLeaveUnmarked);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool FAdvancedDisplayParameterHandler::ShouldMarkParameter(const FString& ParameterName)
|
|
{
|
|
if(bUseNumber)
|
|
{
|
|
if(NumberLeaveUnmarked < 0)
|
|
{
|
|
return false;
|
|
}
|
|
if(AlreadyLeft < NumberLeaveUnmarked)
|
|
{
|
|
AlreadyLeft++;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
return ParametersNames.Contains(ParameterName);
|
|
}
|
|
|
|
bool FAdvancedDisplayParameterHandler::CanMarkMore() const
|
|
{
|
|
return bUseNumber ? (NumberLeaveUnmarked > 0) : (0 != ParametersNames.Num());
|
|
}
|