Files
UnrealEngineUWP/Engine/Source/Programs/UnrealHeaderTool/Private/ParserHelper.h
Thomas Sarkanen 98c834dfd7 Control rig and RigVM changes to allow for data interface prototype to be further developed
This removes some of the dependencies on UControlRigBlueprint and replaces them with 'host' interfaces for URigVMController and URigVMGraph.
Also adds support for TScriptInterfaces in RigVM. This includes a modification of the RigVM parts of UHT.
Some of these changes are due to be reworked later to allow RigVM-hosting systems to not have to be also implemented in terms of control rig.

#rb Helge.Mathee,Sara.Schvartzman
#fyi Helge.Mathee,Sara.Schvartzman
#preflight 624d857aa64871f1a11ef3f9

[CL 19645705 by Thomas Sarkanen in ue5-main branch]
2022-04-06 08:26:45 -04:00

744 lines
20 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;
}
inline bool IsObject(EPropertyType Type)
{
return Type == CPT_ObjectReference || Type == CPT_WeakObjectReference || Type == CPT_LazyObjectReference || Type == CPT_ObjectPtrReference || Type == CPT_SoftObjectReference;
}
inline bool IsInterface(EPropertyType Type)
{
return Type == CPT_Interface;
}
/**
* 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;
/** Setter function name. Either specified in the UPROPERTY macro or autogenerated while parsing class declaration */
FString SetterName;
/** Getter function name. Either specified in the UPROPERTY macro or autogenerated while parsing class declaration */
FString GetterName;
/** True if the property was marked as having a setter */
bool bSetterTagFound = false;
/** True if the property was marked as having a getter */
bool bGetterTagFound = false;
/** True if setter function declaration was found while parsing class header */
bool bSetterFunctionFound = false;
/** True if getter function declaration was found while parsing class header */
bool bGetterFunctionFound = false;
/** True if the property is declared as FieldNotify. */
bool bFieldNotify = false;
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 IsObject() const
{
return ::IsObject(Type);
}
bool IsInterface() const
{
return ::IsInterface(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;
/** TRUE generate the entry for the FieldNotificationClassDescriptor. */
bool bFieldNotify = 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)
, Getter()
, CastName()
, CastType()
, bEditorOnly(false)
, bIsEnum(false)
{
}
FString Name;
FString Type;
bool bConstant;
bool bInput;
bool bOutput;
bool bSingleton;
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"));
}
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;
bool bHasGetUpgradeInfoMethod = false;
bool bHasGetNextAggregateNameMethod = false;
FString Name;
FRigVMParameterArray Members;
TArray<FRigVMMethodInfo> Methods;
};