Files
UnrealEngineUWP/Engine/Source/Programs/UnrealHeaderTool/Private/ParserHelper.h
aurel cordonnier fc542f6cfd Merge from Release-Engine-Staging @ 18081189 to Release-Engine-Test
This represents UE4/Main @18073326, Release-5.0 @18081140 and Dev-PerfTest @18045971

[CL 18081471 by aurel cordonnier in ue5-release-engine-test branch]
2021-11-07 23:43:01 -05:00

725 lines
19 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "UObject/Package.h"
#include "UObject/MetaData.h"
#include "UObject/TextProperty.h"
#include "UObject/EnumProperty.h"
#include "UObject/FieldPathProperty.h"
#include "UObject/Stack.h"
#include "UnrealHeaderToolGlobals.h"
#include "Templates/UniqueObj.h"
#include "Templates/UniquePtr.h"
#include "RigVMDefines.h"
class UEnum;
class UScriptStruct;
class FProperty;
class FUnrealSourceFile;
class UObject;
class UField;
class UMetaData;
class FHeaderParser;
class FUnrealPropertyDefinitionInfo;
class FUnrealTypeDefinitionInfo;
class FUnrealEnumDefinitionInfo;
class FUnrealClassDefinitionInfo;
class FUnrealScriptStructDefinitionInfo;
class FUnrealFunctionDefinitionInfo;
/*-----------------------------------------------------------------------------
FPropertyBase.
-----------------------------------------------------------------------------*/
enum EFunctionExportFlags
{
FUNCEXPORT_Final =0x00000001, // function declaration included "final" keyword. Used to differentiate between functions that have FUNC_Final only because they're private
// =0x00000002,
// =0x00000004,
FUNCEXPORT_RequiredAPI =0x00000008, // Function should be exported as a public API function
FUNCEXPORT_Inline =0x00000010, // export as an inline static C++ function
FUNCEXPORT_CppStatic =0x00000020, // Export as a real C++ static function, causing thunks to call via ClassName::FuncName instead of this->FuncName
FUNCEXPORT_CustomThunk =0x00000040, // Export no thunk function; the user will manually define a custom one
// =0x00000080,
// =0x00000100,
};
enum EPropertyHeaderExportFlags
{
PROPEXPORT_Public =0x00000001, // property should be exported as public
PROPEXPORT_Private =0x00000002, // property should be exported as private
PROPEXPORT_Protected =0x00000004, // property should be exported as protected
};
struct EPointerType
{
enum Type
{
None,
Native
};
};
struct EArrayType
{
enum Type
{
None,
Static,
Dynamic,
Set
};
};
struct ERefQualifier
{
enum Type
{
None,
ConstRef,
NonConstRef
};
};
enum class EIntType
{
None,
Sized, // e.g. int32, int16
Unsized // e.g. int, unsigned int
};
enum class EAllocatorType
{
Default,
MemoryImage
};
/** Types access specifiers. */
enum EAccessSpecifier
{
ACCESS_NotAnAccessSpecifier = 0,
ACCESS_Public,
ACCESS_Private,
ACCESS_Protected,
ACCESS_Num,
};
enum class EUHTPropertyType : uint8
{
None = CPT_None,
Byte = CPT_Byte,
UInt16 = CPT_UInt16,
UInt32 = CPT_UInt32,
UInt64 = CPT_UInt64,
Int8 = CPT_Int8,
Int16 = CPT_Int16,
Int = CPT_Int,
Int64 = CPT_Int64,
Bool = CPT_Bool,
Bool8 = CPT_Bool8,
Bool16 = CPT_Bool16,
Bool32 = CPT_Bool32,
Bool64 = CPT_Bool64,
Float = CPT_Float,
ObjectReference = CPT_ObjectReference,
Name = CPT_Name,
Delegate = CPT_Delegate,
Interface = CPT_Interface,
Struct = CPT_Struct,
String = CPT_String,
Text = CPT_Text,
MulticastDelegate = CPT_MulticastDelegate,
WeakObjectReference = CPT_WeakObjectReference,
LazyObjectReference = CPT_LazyObjectReference,
ObjectPtrReference = CPT_ObjectPtrReference,
SoftObjectReference = CPT_SoftObjectReference,
Double = CPT_Double,
Map = CPT_Map,
Set = CPT_Set,
FieldPath = CPT_FieldPath,
LargeWorldCoordinatesReal = CPT_FLargeWorldCoordinatesReal,
Enum,
DynamicArray,
MAX,
};
inline bool IsBool(EPropertyType Type)
{
return Type == CPT_Bool || Type == CPT_Bool8 || Type == CPT_Bool16 || Type == CPT_Bool32 || Type == CPT_Bool64;
}
inline bool IsNumeric(EPropertyType Type)
{
return Type == CPT_Byte || Type == CPT_UInt16 || Type == CPT_UInt32 || Type == CPT_UInt64 || Type == CPT_Int8 || Type == CPT_Int16 || Type == CPT_Int || Type == CPT_Int64 || Type == CPT_Float || Type == CPT_Double;
}
inline bool IsObjectOrInterface(EPropertyType Type)
{
return Type == CPT_ObjectReference || Type == CPT_Interface || Type == CPT_WeakObjectReference || Type == CPT_LazyObjectReference || Type == CPT_ObjectPtrReference || Type == CPT_SoftObjectReference;
}
/**
* Basic information describing a type.
*/
class FPropertyBase : public TSharedFromThis<FPropertyBase>
{
public:
// Variables.
EPropertyType Type = EPropertyType::CPT_None;
EArrayType::Type ArrayType = EArrayType::None;
EAllocatorType AllocatorType = EAllocatorType::Default;
EPropertyFlags PropertyFlags = CPF_None;
EPropertyFlags ImpliedPropertyFlags = CPF_None;
EPropertyFlags DisallowFlags = ~CPF_None;
ERefQualifier::Type RefQualifier = ERefQualifier::None; // This is needed because of legacy stuff - FString mangles the flags for reasons that have become lost in time but we need this info for testing for invalid replicated function signatures.
TSharedPtr<FPropertyBase> MapKeyProp;
/**
* A mask of EPropertyHeaderExportFlags which are used for modifying how this property is exported to the native class header
*/
uint32 PropertyExportFlags = PROPEXPORT_Public;
union
{
FUnrealTypeDefinitionInfo* TypeDef = nullptr;
FUnrealEnumDefinitionInfo* EnumDef;
FUnrealScriptStructDefinitionInfo* ScriptStructDef;
FUnrealClassDefinitionInfo* ClassDef;
FUnrealFunctionDefinitionInfo* FunctionDef;
};
FName FieldClassName = NAME_None;
FUnrealClassDefinitionInfo* MetaClassDef = nullptr;
FName DelegateName = NAME_None;
FUnrealClassDefinitionInfo* DelegateSignatureOwnerClassDef = nullptr;
FName RepNotifyName = NAME_None;
/** Raw string (not type-checked) used for specifying special text when exporting a property to the *Classes.h file */
FString ExportInfo;
/** Map of key value pairs that will be added to the package's UMetaData for this property */
TMap<FName, FString> MetaData;
EPointerType::Type PointerType = EPointerType::None;
EIntType IntType = EIntType::None;
public:
/** @name Constructors */
//@{
FPropertyBase(const FPropertyBase&) = default;
FPropertyBase(FPropertyBase&&) = default;
FPropertyBase& operator=(const FPropertyBase&) = default;
FPropertyBase& operator=(FPropertyBase&&) = default;
explicit FPropertyBase(EPropertyType InType);
explicit FPropertyBase(EPropertyType InType, EIntType InIntType);
explicit FPropertyBase(FUnrealEnumDefinitionInfo& InEnumDef, EPropertyType InType);
explicit FPropertyBase(FUnrealClassDefinitionInfo& InClassDef, EPropertyType InType, bool bWeakIsAuto = false);
explicit FPropertyBase(FUnrealScriptStructDefinitionInfo& InStructDef);
explicit FPropertyBase(FName InFieldClassName, EPropertyType InType);
//@}
/** @name Functions */
//@{
/**
* Returns whether this token represents an object reference
*/
bool IsObjectOrInterface() const
{
return ::IsObjectOrInterface(Type);
}
bool IsBool() const
{
return ::IsBool(Type);
}
bool IsContainer() const
{
return (ArrayType != EArrayType::None || MapKeyProp.IsValid());
}
bool IsPrimitiveOrPrimitiveStaticArray() const
{
return (ArrayType == EArrayType::None || ArrayType == EArrayType::Static) && !MapKeyProp.IsValid();
}
bool IsBooleanOrBooleanStaticArray() const
{
return IsBool() && IsPrimitiveOrPrimitiveStaticArray();
}
bool IsStructOrStructStaticArray() const
{
return Type == CPT_Struct && IsPrimitiveOrPrimitiveStaticArray();
}
bool IsObjectRefOrObjectRefStaticArray() const
{
return (Type == CPT_ObjectReference || Type == CPT_ObjectPtrReference) && IsPrimitiveOrPrimitiveStaticArray();
}
bool IsClassRefOrClassRefStaticArray() const;
bool IsInterfaceOrInterfaceStaticArray() const
{
return Type == CPT_Interface && IsPrimitiveOrPrimitiveStaticArray();
}
bool IsByteEnumOrByteEnumStaticArray() const;
bool IsNumericOrNumericStaticArray() const
{
return IsNumeric(Type) && IsPrimitiveOrPrimitiveStaticArray();
}
bool IsDelegateOrDelegateStaticArray() const
{
return Type == CPT_Delegate && IsPrimitiveOrPrimitiveStaticArray();
}
bool IsMulticastDelegateOrMulticastDelegateStaticArray() const
{
return Type == CPT_Delegate && IsPrimitiveOrPrimitiveStaticArray();
}
bool PassCPPArgsByRef() const
{
if (ArrayType == EArrayType::Dynamic || ArrayType == EArrayType::Set || MapKeyProp.IsValid())
{
return true;
}
switch (Type)
{
//case CPT_Struct:
case CPT_String:
case CPT_Text:
case CPT_Delegate:
case CPT_MulticastDelegate:
case CPT_WeakObjectReference:
case CPT_LazyObjectReference:
case CPT_ObjectPtrReference:
case CPT_SoftObjectReference:
case CPT_Map:
case CPT_Set:
return true;
default:
return false;
}
}
FUnrealEnumDefinitionInfo* AsEnum() const;
bool IsEnum() const;
/**
* Determines whether this token's type is compatible with another token's type.
*
* @param Other the token to check against this one.
* Given the following example expressions, VarA is Other and VarB is 'this':
* VarA = VarB;
*
* function func(type VarB) {}
* func(VarA);
*
* static operator==(type VarB_1, type VarB_2) {}
* if ( VarA_1 == VarA_2 ) {}
*
* @param bDisallowGeneralization controls whether it should be considered a match if this token's type is a generalization
* of the other token's type (or vice versa, when dealing with structs
* @param bIgnoreImplementedInterfaces controls whether two types can be considered a match if one type is an interface implemented
* by the other type.
* @param bEmulateSameType If true, perform slightly different validation as per FProperty::SameType. Implementation is not
* complete.
*/
bool MatchesType(const FPropertyBase& Other, bool bDisallowGeneralization, bool bIgnoreImplementedInterfaces = false, bool bEmulateSameType = false) const;
//@}
EIntType GetSizedIntTypeFromPropertyType(EPropertyType PropType)
{
switch (PropType)
{
case CPT_Byte:
case CPT_UInt16:
case CPT_UInt32:
case CPT_UInt64:
case CPT_Int8:
case CPT_Int16:
case CPT_Int:
case CPT_Int64:
return EIntType::Sized;
default:
return EIntType::None;
}
}
EUHTPropertyType GetUHTPropertyType() const;
friend struct FPropertyBaseArchiveProxy;
};
/**
* Information about a function being compiled.
*/
struct FFuncInfo
{
/** @name Variables */
//@{
/** Function flags. */
EFunctionFlags FunctionFlags = FUNC_None;
/** Function flags which are only required for exporting */
uint32 FunctionExportFlags = 0;
/** Number of parameters expected for operator. */
int32 ExpectParms = 0;
/** Name of the wrapper function that marshalls the arguments and does the indirect call **/
FString MarshallAndCallName;
/** Name of the actual implementation **/
FString CppImplName;
/** Name of the actual validation implementation **/
FString CppValidationImplName;
/** Name for callback-style names **/
FString UnMarshallAndCallName;
/** Endpoint name */
FString EndpointName;
/** Identifier for an RPC call to a platform service */
uint16 RPCId = 0;
/** Identifier for an RPC call expecting a response */
uint16 RPCResponseId = 0;
/** Delegate macro line in header. */
int32 MacroLine = -1;
/** Position in file where this function was declared. Points to first char of function name. */
int32 InputPos = -1;
/** Whether this function represents a sealed event */
bool bSealedEvent = false;
/** TRUE if the function is being forced to be considered as impure by the user */
bool bForceBlueprintImpure = false;
//@}
/** Set the internal function names based on flags **/
void SetFunctionNames(FUnrealFunctionDefinitionInfo& FunctionDef);
};
/*-----------------------------------------------------------------------------
Retry points.
-----------------------------------------------------------------------------*/
/**
* A point in the header parsing state that can be set and returned to
* using InitScriptLocation() and ReturnToLocation(). This is used in cases such as testing
* to see which overridden operator should be used, where code must be compiled
* and then "undone" if it was found not to match.
* <p>
* Retries are not allowed to cross command boundaries (and thus nesting
* boundaries). Retries can occur across a single command or expressions and
* subexpressions within a command.
*/
struct FScriptLocation
{
/** the text buffer for the class associated with this retry point */
const TCHAR* Input;
/** the position into the Input buffer where this retry point is located */
int32 InputPos;
/** the LineNumber of the compiler when this retry point was created */
int32 InputLine;
};
/////////////////////////////////////////////////////
// FAdvancedDisplayParameterHandler - used by FHeaderParser::ParseParameterList, to check if a property if a function parameter has 'AdvancedDisplay' flag
/**
* AdvancedDisplay can be used in two ways:
* 1. 'AdvancedDisplay = "3"' - the number tells how many parameters (from beginning) should NOT BE marked
* 2. 'AdvancedDisplay = "AttachPointName, Location, LocationType"' - list the parameters, that should BE marked
*/
class FAdvancedDisplayParameterHandler
{
TArray<FString> ParametersNames;
int32 NumberLeaveUnmarked;
int32 AlreadyLeft;
bool bUseNumber;
public:
FAdvancedDisplayParameterHandler(const TMap<FName, FString>* MetaData);
/**
* return if given parameter should be marked as Advance View,
* the function should be called only once for any parameter
*/
bool ShouldMarkParameter(const FString& ParameterName);
/** return if more parameters can be marked */
bool CanMarkMore() const;
};
/**
* The FRigVMParameter represents a single parameter of a method
* marked up with RIGVM_METHOD.
* Each parameter can be marked with Constant, Input or Output
* metadata - this struct simplifies access to that information.
*/
struct FRigVMParameter
{
FRigVMParameter()
: Name()
, Type()
, bConstant(false)
, bInput(false)
, bOutput(false)
, bSingleton(false)
#if UE_RIGVM_UCLASS_BASED_STORAGE_DISABLED
, ArraySize()
#endif
, Getter()
, CastName()
, CastType()
, bEditorOnly(false)
, bIsEnum(false)
{
}
FString Name;
FString Type;
bool bConstant;
bool bInput;
bool bOutput;
bool bSingleton;
#if UE_RIGVM_UCLASS_BASED_STORAGE_DISABLED
FString ArraySize;
#endif
FString Getter;
FString CastName;
FString CastType;
bool bEditorOnly;
bool bIsEnum;
const FString& NameOriginal(bool bCastName = false) const
{
return (bCastName && !CastName.IsEmpty()) ? CastName : Name;
}
const FString& TypeOriginal(bool bCastType = false) const
{
return (bCastType && !CastType.IsEmpty()) ? CastType : Type;
}
FString Declaration(bool bCastType = false, bool bCastName = false) const
{
return FString::Printf(TEXT("%s %s"), *TypeOriginal(bCastType), *NameOriginal(bCastName));
}
FString BaseType(bool bCastType = false) const
{
const FString& String = TypeOriginal(bCastType);
int32 LesserPos = 0;
if (String.FindChar(TEXT('<'), LesserPos))
{
return String.Mid(0, LesserPos);
}
return String;
}
FString ExtendedType(bool bCastType = false) const
{
const FString& String = TypeOriginal(bCastType);
int32 LesserPos = 0;
if (String.FindChar(TEXT('<'), LesserPos))
{
return String.Mid(LesserPos);
}
return String;
}
FString TypeConstRef(bool bCastType = false) const
{
const FString& String = TypeNoRef(bCastType);
if (String.StartsWith(TEXT("T"), ESearchCase::CaseSensitive) || String.StartsWith(TEXT("F"), ESearchCase::CaseSensitive))
{
return FString::Printf(TEXT("const %s&"), *String);
}
return FString::Printf(TEXT("const %s"), *String);
}
FString TypeRef(bool bCastType = false) const
{
const FString& String = TypeNoRef(bCastType);
return FString::Printf(TEXT("%s&"), *String);
}
FString TypeNoRef(bool bCastType = false) const
{
const FString& String = TypeOriginal(bCastType);
if (String.EndsWith(TEXT("&")))
{
return String.LeftChop(1);
}
return String;
}
FString TypeVariableRef(bool bCastType = false) const
{
return IsConst() ? TypeConstRef(bCastType) : TypeRef(bCastType);
}
FString Variable(bool bCastType = false, bool bCastName = false) const
{
return FString::Printf(TEXT("%s %s"), *TypeVariableRef(bCastType), *NameOriginal(bCastName));
}
bool IsConst() const
{
return bConstant || (bInput && !bOutput);
}
bool IsArray() const
{
return BaseType().Equals(TEXT("TArray"));
}
#if UE_RIGVM_UCLASS_BASED_STORAGE_DISABLED
bool IsDynamic() const
{
return ArraySize.IsEmpty() && !bInput && !bOutput && !bSingleton;
}
bool IsDynamicArray() const
{
return IsArray() && IsDynamic();
}
#endif
bool RequiresCast() const
{
return !CastType.IsEmpty() && !CastName.IsEmpty();
}
};
/**
* The FRigVMParameterArray represents the parameters in a notation
* of a function marked with RIGVM_METHOD. The parameter array can
* produce a comma separated list of names or parameter declarations.
*/
struct FRigVMParameterArray
{
public:
int32 Num() const { return Parameters.Num(); }
const FRigVMParameter& operator[](int32 InIndex) const { return Parameters[InIndex]; }
FRigVMParameter& operator[](int32 InIndex) { return Parameters[InIndex]; }
TArray<FRigVMParameter>::RangedForConstIteratorType begin() const { return Parameters.begin(); }
TArray<FRigVMParameter>::RangedForConstIteratorType end() const { return Parameters.end(); }
TArray<FRigVMParameter>::RangedForIteratorType begin() { return Parameters.begin(); }
TArray<FRigVMParameter>::RangedForIteratorType end() { return Parameters.end(); }
int32 Add(const FRigVMParameter& InParameter)
{
return Parameters.Add(InParameter);
}
FString Names(bool bLeadingSeparator = false, const TCHAR* Separator = TEXT(", "), bool bCastType = false, bool bIncludeEditorOnly = true) const
{
if (Parameters.Num() == 0)
{
return FString();
}
TArray<FString> NameArray;
for (const FRigVMParameter& Parameter : Parameters)
{
if (!bIncludeEditorOnly && Parameter.bEditorOnly)
{
continue;
}
NameArray.Add(Parameter.NameOriginal(bCastType));
}
if (NameArray.Num() == 0)
{
return FString();
}
FString Joined = FString::Join(NameArray, Separator);
if (bLeadingSeparator)
{
return FString::Printf(TEXT("%s%s"), Separator, *Joined);
}
return Joined;
}
FString Declarations(bool bLeadingSeparator = false, const TCHAR* Separator = TEXT(", "), bool bCastType = false, bool bCastName = false, bool bIncludeEditorOnly = true) const
{
if (Parameters.Num() == 0)
{
return FString();
}
TArray<FString> DeclarationArray;
for (const FRigVMParameter& Parameter : Parameters)
{
if (!bIncludeEditorOnly && Parameter.bEditorOnly)
{
continue;
}
DeclarationArray.Add(Parameter.Variable(bCastType, bCastName));
}
if (DeclarationArray.Num() == 0)
{
return FString();
}
FString Joined = FString::Join(DeclarationArray, Separator);
if (bLeadingSeparator)
{
return FString::Printf(TEXT("%s%s"), Separator, *Joined);
}
return Joined;
}
private:
TArray<FRigVMParameter> Parameters;
};
/**
* A single info dataset for a function marked with RIGVM_METHOD.
* This struct provides access to its name, the return type and all parameters.
*/
struct FRigVMMethodInfo
{
FString ReturnType;
FString Name;
FRigVMParameterArray Parameters;
FString ReturnPrefix() const
{
return (ReturnType.IsEmpty() || (ReturnType == TEXT("void"))) ? TEXT("") : TEXT("return ");
}
};
/**
* An info dataset providing access to all functions marked with RIGVM_METHOD
* for each struct.
*/
struct FRigVMStructInfo
{
bool bHasRigVM = false;
FString Name;
FRigVMParameterArray Members;
TArray<FRigVMMethodInfo> Methods;
};