You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
Moving the UHTConfig to BaseParser along with a support routine to be used by a future change. #rb trivial #rnx #preflight 607764150af8c60001c4a435 [CL 16013445 by Tim Smith in ue5-main branch]
1089 lines
33 KiB
C++
1089 lines
33 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#pragma once
|
|
|
|
#include "CoreMinimal.h"
|
|
#include "ParserHelper.h"
|
|
#include "BaseParser.h"
|
|
#include "Misc/CompilationResult.h"
|
|
#include "Scope.h"
|
|
|
|
class UClass;
|
|
enum class EGeneratedCodeVersion : uint8;
|
|
class FFeedbackContext;
|
|
class UPackage;
|
|
struct FManifestModule;
|
|
class IScriptGeneratorPluginInterface;
|
|
class FStringOutputDevice;
|
|
class FProperty;
|
|
class FUnrealSourceFile;
|
|
class UFunction;
|
|
class UEnum;
|
|
class UScriptStruct;
|
|
class UDelegateFunction;
|
|
class UStruct;
|
|
class FClass;
|
|
class FClasses;
|
|
class FScope;
|
|
class FHeaderProvider;
|
|
|
|
extern double GPluginOverheadTime;
|
|
extern double GHeaderCodeGenTime;
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
Constants & types.
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
enum {MAX_NEST_LEVELS = 16};
|
|
|
|
/* Code nesting types. */
|
|
enum class ENestType
|
|
{
|
|
GlobalScope,
|
|
Class,
|
|
FunctionDeclaration,
|
|
Interface,
|
|
NativeInterface
|
|
};
|
|
|
|
/** Types of statements to allow within a particular nesting block. */
|
|
enum class ENestAllowFlags
|
|
{
|
|
None = 0,
|
|
Function = 1, // Allow Event declarations at this level.
|
|
VarDecl = 2, // Allow variable declarations at this level.
|
|
Class = 4, // Allow class definition heading.
|
|
Return = 8, // Allow 'return' within a function.
|
|
TypeDecl = 16, // Allow declarations which do not affect memory layout, such as structs, enums, and consts, but not implicit delegates
|
|
ImplicitDelegateDecl = 32, // Allow implicit delegates (i.e. those not decorated with UDELEGATE) to be declared
|
|
};
|
|
|
|
ENUM_CLASS_FLAGS(ENestAllowFlags)
|
|
|
|
namespace EDelegateSpecifierAction
|
|
{
|
|
enum Type
|
|
{
|
|
DontParse,
|
|
Parse
|
|
};
|
|
}
|
|
|
|
/** The category of variable declaration being parsed */
|
|
namespace EVariableCategory
|
|
{
|
|
enum Type
|
|
{
|
|
RegularParameter,
|
|
ReplicatedParameter,
|
|
Return,
|
|
Member
|
|
};
|
|
}
|
|
|
|
enum class ELayoutMacroType
|
|
{
|
|
None = -1,
|
|
Array,
|
|
ArrayEditorOnly,
|
|
Bitfield,
|
|
BitfieldEditorOnly,
|
|
Field,
|
|
FieldEditorOnly,
|
|
FieldInitialized,
|
|
};
|
|
|
|
/** Information for a particular nesting level. */
|
|
class FNestInfo
|
|
{
|
|
/** Link to the stack node. */
|
|
FScope* Scope;
|
|
|
|
public:
|
|
/**
|
|
* Gets nesting scope.
|
|
*/
|
|
FScope* GetScope() const
|
|
{
|
|
return Scope;
|
|
}
|
|
|
|
/**
|
|
* Sets nesting scope.
|
|
*/
|
|
void SetScope(FScope* InScope)
|
|
{
|
|
this->Scope = InScope;
|
|
}
|
|
|
|
/** Statement that caused the nesting. */
|
|
ENestType NestType;
|
|
|
|
/** Types of statements to allow at this nesting level. */
|
|
ENestAllowFlags Allow;
|
|
};
|
|
|
|
struct FIndexRange
|
|
{
|
|
int32 StartIndex;
|
|
int32 Count;
|
|
};
|
|
|
|
/**
|
|
* 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)
|
|
, ArraySize()
|
|
, Getter()
|
|
, CastName()
|
|
, CastType()
|
|
, bEditorOnly(false)
|
|
, bIsEnum(false)
|
|
{
|
|
}
|
|
|
|
FString Name;
|
|
FString Type;
|
|
bool bConstant;
|
|
bool bInput;
|
|
bool bOutput;
|
|
bool bSingleton;
|
|
FString ArraySize;
|
|
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('<', 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('<', 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 IsDynamic() const
|
|
{
|
|
return ArraySize.IsEmpty() && !bInput && !bOutput && !bSingleton;
|
|
}
|
|
|
|
bool IsDynamicArray() const
|
|
{
|
|
return IsArray() && IsDynamic();
|
|
}
|
|
|
|
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
|
|
{
|
|
FString Name;
|
|
FRigVMParameterArray Members;
|
|
TArray<FRigVMMethodInfo> Methods;
|
|
};
|
|
|
|
typedef TMap<UStruct*, FRigVMStructInfo> FRigVMStructMap;
|
|
|
|
struct ClassDefinitionRange
|
|
{
|
|
ClassDefinitionRange(const TCHAR* InStart, const TCHAR* InEnd)
|
|
: Start(InStart)
|
|
, End(InEnd)
|
|
, bHasGeneratedBody(false)
|
|
{ }
|
|
|
|
ClassDefinitionRange()
|
|
: Start(nullptr)
|
|
, End(nullptr)
|
|
, bHasGeneratedBody(false)
|
|
{ }
|
|
|
|
void Validate()
|
|
{
|
|
if (End <= Start)
|
|
{
|
|
FError::Throwf(TEXT("The class definition range is invalid. Most probably caused by previous parsing error."));
|
|
}
|
|
}
|
|
|
|
const TCHAR* Start;
|
|
const TCHAR* End;
|
|
bool bHasGeneratedBody;
|
|
};
|
|
|
|
extern TMap<UClass*, ClassDefinitionRange> ClassDefinitionRanges;
|
|
|
|
#ifndef UHT_DOCUMENTATION_POLICY_DEFAULT
|
|
#define UHT_DOCUMENTATION_POLICY_DEFAULT false
|
|
#endif
|
|
|
|
struct FDocumentationPolicy
|
|
{
|
|
bool bClassOrStructCommentRequired = UHT_DOCUMENTATION_POLICY_DEFAULT;
|
|
bool bFunctionToolTipsRequired = UHT_DOCUMENTATION_POLICY_DEFAULT;
|
|
bool bMemberToolTipsRequired = UHT_DOCUMENTATION_POLICY_DEFAULT;
|
|
bool bParameterToolTipsRequired = UHT_DOCUMENTATION_POLICY_DEFAULT;
|
|
bool bFloatRangesRequired = UHT_DOCUMENTATION_POLICY_DEFAULT;
|
|
};
|
|
|
|
/////////////////////////////////////////////////////
|
|
// FHeaderParser
|
|
|
|
//
|
|
// Header parser class. Extracts metadata from annotated C++ headers and gathers enough
|
|
// information to autogenerate additional headers and other boilerplate code.
|
|
//
|
|
class FHeaderParser : public FBaseParser, public FContextSupplier
|
|
{
|
|
public:
|
|
// Compute the function parameter size and save the return offset
|
|
static void ComputeFunctionParametersSize(UClass* InClass);
|
|
|
|
// Parse all headers for classes that are inside LimitOuter.
|
|
static ECompilationResult::Type ParseAllHeadersInside(
|
|
FClasses& ModuleClasses,
|
|
FFeedbackContext* Warn,
|
|
UPackage* LimitOuter,
|
|
const FManifestModule& Module,
|
|
TArray<class IScriptGeneratorPluginInterface*>& ScriptPlugins
|
|
);
|
|
|
|
// Performs a preliminary parse of the text in the specified buffer, pulling out:
|
|
// Class name and parent class name
|
|
// Is it an interface
|
|
// The list of other classes/interfaces it is dependent on
|
|
//
|
|
// It also splits the buffer up into:
|
|
// ScriptText (text outside of #if CPP and #if DEFAULTS blocks)
|
|
static void SimplifiedClassParse(const TCHAR* Filename, const TCHAR* Buffer, TArray<FSimplifiedParsingClassInfo>& OutParsedClassArray, TArray<FHeaderProvider>& DependentOn, FStringOutputDevice& ScriptText);
|
|
|
|
/**
|
|
* Returns True if the given class name includes a valid Unreal prefix and matches up with the given original class Name.
|
|
*
|
|
* @param InNameToCheck - Name w/ potential prefix to check
|
|
* @param OriginalClassName - Name of class w/ no prefix to check against
|
|
*/
|
|
static bool ClassNameHasValidPrefix(const FString& InNameToCheck, const FString& OriginalClassName);
|
|
|
|
/**
|
|
* Tries to convert the header file name to a class name (with 'U' prefix)
|
|
*
|
|
* @param HeaderFilename Filename.
|
|
* @param OutClass The resulting class name (if successfull)
|
|
* @return true if the filename was a header filename (.h), false otherwise (in which case OutClassName is unmodified).
|
|
*/
|
|
static bool DependentClassNameFromHeader(const TCHAR* HeaderFilename, FString& OutClassName);
|
|
|
|
/**
|
|
* Transforms CPP-formated string containing default value, to inner formated string
|
|
* If it cannot be transformed empty string is returned.
|
|
*
|
|
* @param Property The property that owns the default value.
|
|
* @param CppForm A CPP-formated string.
|
|
* @param out InnerForm Inner formated string
|
|
* @return true on success, false otherwise.
|
|
*/
|
|
static bool DefaultValueStringCppFormatToInnerFormat(const FProperty* Property, const FString& CppForm, FString &InnerForm);
|
|
|
|
/**
|
|
* Parse Class's annotated headers and optionally its child classes. Marks the class as CLASS_Parsed.
|
|
*
|
|
* @param HeaderParser the header parser
|
|
* @param SourceFile Source file info.
|
|
*
|
|
* @return Result enumeration.
|
|
*/
|
|
static ECompilationResult::Type ParseHeaders(FHeaderParser& HeaderParser, FUnrealSourceFile* SourceFile);
|
|
|
|
protected:
|
|
friend struct FScriptLocation;
|
|
friend struct FNativeClassHeaderGenerator;
|
|
|
|
// For compiling messages and errors.
|
|
FFeedbackContext* Warn;
|
|
|
|
// Filename currently being parsed
|
|
FString Filename;
|
|
|
|
// Was the first include in the file a validly formed auto-generated header include?
|
|
bool bSpottedAutogeneratedHeaderInclude;
|
|
|
|
// Current nest level, starts at 0.
|
|
int32 NestLevel;
|
|
|
|
// Top nesting level.
|
|
FNestInfo* TopNest;
|
|
|
|
/**
|
|
* Gets current nesting scope.
|
|
*/
|
|
FScope* GetCurrentScope() const
|
|
{
|
|
return TopNest->GetScope();
|
|
}
|
|
|
|
/**
|
|
* Gets current file scope.
|
|
*/
|
|
FFileScope* GetCurrentFileScope() const
|
|
{
|
|
int32 Index = 0;
|
|
if (!TopNest)
|
|
{
|
|
check(!NestLevel);
|
|
return nullptr;
|
|
}
|
|
while (TopNest[Index].NestType != ENestType::GlobalScope)
|
|
{
|
|
--Index;
|
|
}
|
|
|
|
return (FFileScope*)TopNest[Index].GetScope();
|
|
}
|
|
|
|
/**
|
|
* Gets current source file.
|
|
*/
|
|
FUnrealSourceFile* GetCurrentSourceFile() const
|
|
{
|
|
return CurrentSourceFile;
|
|
}
|
|
|
|
void SetCurrentSourceFile(FUnrealSourceFile* UnrealSourceFile)
|
|
{
|
|
CurrentSourceFile = UnrealSourceFile;
|
|
}
|
|
|
|
/**
|
|
* Gets current class scope.
|
|
*/
|
|
FStructScope* GetCurrentClassScope() const
|
|
{
|
|
check(TopNest->NestType == ENestType::Class || TopNest->NestType == ENestType::Interface || TopNest->NestType == ENestType::NativeInterface);
|
|
|
|
return (FStructScope*)TopNest->GetScope();
|
|
}
|
|
|
|
/**
|
|
* Tells if parser is currently in a class.
|
|
*/
|
|
bool IsInAClass() const
|
|
{
|
|
int32 Index = 0;
|
|
while (TopNest[Index].NestType != ENestType::GlobalScope)
|
|
{
|
|
if (TopNest[Index].NestType == ENestType::Class || TopNest->NestType == ENestType::Interface || TopNest->NestType == ENestType::NativeInterface)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
--Index;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Gets current class.
|
|
*/
|
|
UClass* GetCurrentClass() const
|
|
{
|
|
return (UClass*)GetCurrentClassScope()->GetStruct();
|
|
}
|
|
|
|
/**
|
|
* Gets current class's metadata.
|
|
*/
|
|
FClassMetaData* GetCurrentClassData()
|
|
{
|
|
return GScriptHelper.FindClassData(GetCurrentClass());
|
|
}
|
|
|
|
// Information about all nesting levels.
|
|
FNestInfo Nest[MAX_NEST_LEVELS];
|
|
|
|
// enum for complier directives used to build up the directive stack
|
|
struct ECompilerDirective
|
|
{
|
|
enum Type
|
|
{
|
|
// this directive is insignificant and does not change the code generation at all
|
|
Insignificant = 0,
|
|
// this indicates we are in a WITH_EDITOR #if-Block
|
|
WithEditor = 1<<0,
|
|
// this indicates we are in a WITH_EDITORONLY_DATA #if-Block
|
|
WithEditorOnlyData = 1<<1,
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Compiler directive nest in which the parser currently is
|
|
* NOTE: compiler directives are combined when more are added onto the stack, so
|
|
* checking the only the top of stack is enough to determine in which #if-Block(s) the current code
|
|
* is.
|
|
*
|
|
* ex. Stack.Num() == 1 while entering #if WITH_EDITOR:
|
|
* CompilerDirectiveStack[1] == CompilerDirectiveStack[0] | ECompilerDirective::WithEditor ==
|
|
* CompilerDirecitveStack[1] == CompilerDirectiveStack.Num()-1 | ECompilerDirective::WithEditor
|
|
*
|
|
* ex. Stack.Num() == 2 while entering #if WITH_EDITOR:
|
|
* CompilerDirectiveStack[3] == CompilerDirectiveStack[0] | CompilerDirectiveStack[1] | CompilerDirectiveStack[2] | ECompilerDirective::WithEditor ==
|
|
* CompilerDirecitveStack[3] == CompilerDirectiveStack.Num()-1 | ECompilerDirective::WithEditor
|
|
*/
|
|
TArray<uint32> CompilerDirectiveStack;
|
|
|
|
// Pushes the Directive specified to the CompilerDirectiveStack according to the rules described above
|
|
void FORCEINLINE PushCompilerDirective(ECompilerDirective::Type Directive)
|
|
{
|
|
CompilerDirectiveStack.Push(CompilerDirectiveStack.Num()>0 ? (CompilerDirectiveStack[CompilerDirectiveStack.Num()-1] | Directive) : Directive);
|
|
}
|
|
|
|
/**
|
|
* The starting class flags (i.e. the class flags that were set before the
|
|
* CLASS_RecompilerClear mask was applied) for the class currently being compiled
|
|
*/
|
|
uint32 PreviousClassFlags;
|
|
|
|
// For new-style classes, used to keep track of an unmatched {} pair
|
|
bool bEncounteredNewStyleClass_UnmatchedBrackets;
|
|
|
|
// Indicates that UCLASS/USTRUCT/UINTERFACE has already been parsed in this .h file..
|
|
bool bHaveSeenUClass;
|
|
|
|
// Indicates that a GENERATED_UCLASS_BODY or GENERATED_BODY has been found in the UClass.
|
|
bool bClassHasGeneratedBody;
|
|
|
|
// Indicates that a GENERATED_UINTERFACE_BODY has been found in the UClass.
|
|
bool bClassHasGeneratedUInterfaceBody;
|
|
|
|
// Indicates that a GENERATED_IINTERFACE_BODY has been found in the UClass.
|
|
bool bClassHasGeneratedIInterfaceBody;
|
|
|
|
// public, private, etc at the current parse spot
|
|
EAccessSpecifier CurrentAccessSpecifier;
|
|
|
|
////////////////////////////////////////////////////
|
|
|
|
// List of all used identifiers for net service function declarations (every function must be unique)
|
|
TMap<int32, FString> UsedRPCIds;
|
|
// List of all net service functions with undeclared response functions
|
|
TMap<int32, FString> RPCsNeedingHookup;
|
|
|
|
// List of all multiplex methods defined on structs
|
|
static FRigVMStructMap StructRigVMMap;
|
|
|
|
// Constructor.
|
|
explicit FHeaderParser(FFeedbackContext* InWarn, const FManifestModule& InModule);
|
|
|
|
// Returns true if the token is a dynamic delegate declaration
|
|
bool IsValidDelegateDeclaration(const FToken& Token) const;
|
|
|
|
// Returns true if the current token is a bitfield type
|
|
bool IsBitfieldProperty(ELayoutMacroType LayoutMacroType);
|
|
|
|
// Parse the parameter list of a function or delegate declaration
|
|
void ParseParameterList(UFunction* Function, bool bExpectCommaBeforeName = false, TMap<FName, FString>* MetaData = NULL);
|
|
|
|
public:
|
|
// Throws if a specifier value wasn't provided
|
|
static void RequireSpecifierValue(const FPropertySpecifier& Specifier, bool bRequireExactlyOne = false);
|
|
static FString RequireExactlyOneSpecifierValue(const FPropertySpecifier& Specifier);
|
|
|
|
/**
|
|
* Find a field in the specified context. Starts with the specified scope, then iterates
|
|
* through the Outer chain until the field is found.
|
|
*
|
|
* @param InScope scope to start searching for the field in
|
|
* @param InIdentifier name of the field we're searching for
|
|
* @param bIncludeParents whether to allow searching in the scope of a parent struct
|
|
* @param FieldClass class of the field to search for. used to e.g. search for functions only
|
|
* @param Thing hint text that will be used in the error message if an error is encountered
|
|
*
|
|
* @return a pointer to a UField with a name matching InIdentifier, or NULL if it wasn't found
|
|
*/
|
|
static UField* FindField( UStruct* InScope, const TCHAR* InIdentifier, bool bIncludeParents=true, UClass* FieldClass=UField::StaticClass(), const TCHAR* Thing=nullptr );
|
|
static FField* FindProperty(UStruct* InScope, const TCHAR* InIdentifier, bool bIncludeParents = true, FFieldClass* FieldClass = FField::StaticClass(), const TCHAR* Thing = nullptr);
|
|
|
|
// Checks ToValidate to make sure that its associated sparse class data struct, if one exists, is a valid structure to use for storing sparse class data.
|
|
static void CheckSparseClassData(const UStruct* ToValidate);
|
|
|
|
protected:
|
|
|
|
/**
|
|
* Parse rest of the module's source files.
|
|
*
|
|
* @param ModulePackage Current package.
|
|
* @param HeaderParser The header parser.
|
|
*
|
|
* @return Result enumeration.
|
|
*/
|
|
static ECompilationResult::Type ParseRestOfModulesSourceFiles(UPackage* ModulePackage, FHeaderParser& HeaderParser);
|
|
|
|
//@TODO: Remove this method
|
|
static void ParseClassName(const TCHAR* Temp, FString& ClassName);
|
|
|
|
/**
|
|
* @param Input An input string, expected to be a script comment.
|
|
* @return The input string, reformatted in such a way as to be appropriate for use as a tooltip.
|
|
*/
|
|
static FString FormatCommentForToolTip(const FString& Input);
|
|
|
|
/**
|
|
* Retrieves parameter comments / tooltips from the function comment
|
|
* @param Input An input string, expected to be a script comment.
|
|
* @return The map of parameter name to comment per parameter
|
|
*/
|
|
static TMap<FName, FString> GetParameterToolTipsFromFunctionComment(const FString& Input);
|
|
|
|
/**
|
|
* Begins the process of exporting C++ class declarations for native classes in the specified package
|
|
*
|
|
* @param CurrentPackage The package being compiled.
|
|
* @param AllClasses The class tree for CurrentPackage.
|
|
* @param Module Currently exported module.
|
|
*/
|
|
static void ExportNativeHeaders(
|
|
UPackage* CurrentPackage,
|
|
FClasses& AllClasses,
|
|
bool bAllowSaveExportedHeaders,
|
|
const FManifestModule& Module
|
|
);
|
|
|
|
FString GetSourceFileContext() const;
|
|
|
|
// FContextSupplier interface.
|
|
virtual FString GetContext() override;
|
|
// End of FContextSupplier interface.
|
|
|
|
// High-level compiling functions.
|
|
/**
|
|
* Parses given source file.
|
|
*
|
|
* @param SourceFile Source file to parse.
|
|
*
|
|
* @returns Compilation result enum.
|
|
*/
|
|
ECompilationResult::Type ParseHeader(FUnrealSourceFile* SourceFile);
|
|
void CompileDirective();
|
|
void FinalizeScriptExposedFunctions(UClass* Class);
|
|
UEnum* CompileEnum();
|
|
UScriptStruct* CompileStructDeclaration();
|
|
bool CompileDeclaration(TArray<UDelegateFunction*>& DelegatesToFixup, FToken& Token);
|
|
|
|
/** Skip C++ (noexport) declaration. */
|
|
bool SkipDeclaration(FToken& Token);
|
|
/** Similar to MatchSymbol() but will return to the exact location as on entry if the symbol was not found. */
|
|
bool SafeMatchSymbol(const TCHAR Match);
|
|
void HandleOneInheritedClass(UClass* Class, FString&& InterfaceName);
|
|
FClass* ParseClassNameDeclaration(FString& DeclaredClassName, FString& RequiredAPIMacroIfPresent);
|
|
|
|
/** The property style of a variable declaration being parsed */
|
|
struct EPropertyDeclarationStyle
|
|
{
|
|
enum Type
|
|
{
|
|
None,
|
|
UPROPERTY
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Resets current class data back to its defaults.
|
|
*/
|
|
void ResetClassData();
|
|
|
|
/**
|
|
* Create new function object based on given info structure.
|
|
*/
|
|
UFunction* CreateFunction(const FFuncInfo &FuncInfo) const;
|
|
|
|
/**
|
|
* Create new delegate function object based on given info structure.
|
|
*/
|
|
template<typename T>
|
|
UDelegateFunction* CreateDelegateFunction(const FFuncInfo &FuncInfo) const;
|
|
|
|
UClass* CompileClassDeclaration();
|
|
UDelegateFunction* CompileDelegateDeclaration(const TCHAR* DelegateIdentifier, EDelegateSpecifierAction::Type SpecifierAction = EDelegateSpecifierAction::DontParse);
|
|
void CompileFunctionDeclaration();
|
|
void CompileVariableDeclaration (UStruct* Struct);
|
|
void CompileInterfaceDeclaration();
|
|
void CompileRigVMMethodDeclaration(UStruct* Struct);
|
|
void ParseRigVMMethodParameters(UStruct* Struct);
|
|
|
|
FClass* ParseInterfaceNameDeclaration(FString& DeclaredInterfaceName, FString& RequiredAPIMacroIfPresent);
|
|
bool TryParseIInterfaceClass();
|
|
|
|
bool CompileStatement(TArray<UDelegateFunction*>& DelegatesToFixup);
|
|
|
|
// Checks to see if a particular kind of command is allowed on this nesting level.
|
|
bool IsAllowedInThisNesting(ENestAllowFlags AllowFlags);
|
|
|
|
// Make sure that a particular kind of command is allowed on this nesting level.
|
|
// If it's not, issues a compiler error referring to the token and the current
|
|
// nesting level.
|
|
void CheckAllow(const TCHAR* Thing, ENestAllowFlags AllowFlags);
|
|
|
|
UStruct* GetSuperScope( UStruct* CurrentScope, const FName& SearchName );
|
|
|
|
void SkipStatements( int32 SubCount, const TCHAR* ErrorTag );
|
|
|
|
/**
|
|
* Parses a variable or return value declaration and determines the variable type and property flags.
|
|
*
|
|
* @param Scope struct to create the property in
|
|
* @param VarProperty will be filled in with type and property flag data for the property declaration that was parsed
|
|
* @param Disallow contains a mask of variable modifiers that are disallowed in this context
|
|
* @param OuterPropertyType only specified when compiling the inner properties for arrays or maps. corresponds to the FToken for the outer property declaration.
|
|
* @param PropertyDeclarationStyle if the variable is defined with a UPROPERTY
|
|
* @param VariableCategory what kind of variable is being parsed
|
|
* @param ParsedVarIndexRange The source text [Start, End) index range for the parsed type.
|
|
*/
|
|
void GetVarType(
|
|
FScope* Scope,
|
|
FPropertyBase& VarProperty,
|
|
EPropertyFlags Disallow,
|
|
const FToken* OuterPropertyType,
|
|
EPropertyDeclarationStyle::Type PropertyDeclarationStyle,
|
|
EVariableCategory::Type VariableCategory,
|
|
FIndexRange* ParsedVarIndexRange = nullptr,
|
|
ELayoutMacroType* OutLayoutMacroType = nullptr);
|
|
|
|
/**
|
|
* Parses a variable name declaration and creates a new FProperty object.
|
|
*
|
|
* @param Scope struct to create the property in
|
|
* @param VarProperty type and propertyflag info for the new property (inout)
|
|
* @param VariableCategory what kind of variable is being created
|
|
*
|
|
* @return a pointer to the new FProperty if successful, or NULL if there was no property to parse
|
|
*/
|
|
FProperty* GetVarNameAndDim(
|
|
UStruct* Struct,
|
|
FToken& VarProperty,
|
|
EVariableCategory::Type VariableCategory,
|
|
ELayoutMacroType LayoutMacroType = ELayoutMacroType::None);
|
|
|
|
/**
|
|
* Returns whether the specified class can be referenced from the class currently being compiled.
|
|
*
|
|
* @param Scope The scope we are currently parsing.
|
|
* @param CheckClass The class we want to reference.
|
|
*
|
|
* @return true if the specified class is an intrinsic type or if the class has successfully been parsed
|
|
*/
|
|
bool AllowReferenceToClass(UStruct* Scope, UClass* CheckClass) const;
|
|
|
|
/**
|
|
* @return true if Scope has FProperty objects in its list of fields
|
|
*/
|
|
static bool HasMemberProperties( const UStruct* Scope );
|
|
|
|
/**
|
|
* Parses optional metadata text.
|
|
*
|
|
* @param MetaData the metadata map to store parsed metadata in
|
|
* @param FieldName the field being parsed (used for logging)
|
|
*
|
|
* @return true if metadata was specified
|
|
*/
|
|
void ParseFieldMetaData(TMap<FName, FString>& MetaData, const TCHAR* FieldName);
|
|
|
|
/**
|
|
* Formats the current comment, if any, and adds it to the metadata as a tooltip.
|
|
*
|
|
* @param MetaData the metadata map to store the tooltip in
|
|
*/
|
|
void AddFormattedPrevCommentAsTooltipMetaData(TMap<FName, FString>& MetaData);
|
|
|
|
/**
|
|
* Tries to parse the token as an access protection specifier (public:, protected:, or private:)
|
|
*
|
|
* @return EAccessSpecifier this is, or zero if it is none
|
|
*/
|
|
EAccessSpecifier ParseAccessProtectionSpecifier(const FToken& Token);
|
|
|
|
const TCHAR* NestTypeName( ENestType NestType );
|
|
|
|
FClass* GetQualifiedClass(const TCHAR* Thing);
|
|
|
|
/**
|
|
* Increase the nesting level, setting the new top nesting level to
|
|
* the one specified. If pushing a function or state and it overrides a similar
|
|
* thing declared on a lower nesting level, verifies that the override is legal.
|
|
*
|
|
* @param NestType the new nesting type
|
|
* @param InNode @todo
|
|
*/
|
|
void PushNest(ENestType NestType, UStruct* InNode, FUnrealSourceFile* SourceFile = nullptr);
|
|
void PopNest(ENestType NestType, const TCHAR* Descr);
|
|
|
|
/**
|
|
* Tasks that need to be done after popping function declaration
|
|
* from parsing stack.
|
|
*
|
|
* @param PoppedFunction Function that have just been popped.
|
|
*/
|
|
void PostPopFunctionDeclaration(UFunction* PoppedFunction);
|
|
|
|
/**
|
|
* Tasks that need to be done after popping interface definition
|
|
* from parsing stack.
|
|
*
|
|
* @param CurrentInterface Interface that have just been popped.
|
|
*/
|
|
void PostPopNestInterface(UClass* CurrentInterface);
|
|
|
|
/**
|
|
* Tasks that need to be done after popping class definition
|
|
* from parsing stack.
|
|
*
|
|
* @param CurrentClass Class that have just been popped.
|
|
*/
|
|
void PostPopNestClass(UClass* CurrentClass);
|
|
|
|
/**
|
|
* Binds all delegate properties declared in ValidationScope the delegate functions specified in the variable declaration, verifying that the function is a valid delegate
|
|
* within the current scope. This must be done once the entire class has been parsed because instance delegate properties must be declared before the delegate declaration itself.
|
|
*
|
|
* @todo: this function will no longer be required once the post-parse fixup phase is added (TTPRO #13256)
|
|
*
|
|
* @param Struct the struct to validate delegate properties for
|
|
* @param Scope the current scope
|
|
* @param DelegateCache cached map of delegates that have already been found; used for faster lookup.
|
|
*/
|
|
void FixupDelegateProperties(UStruct* ValidationScope, FScope& Scope, TMap<FName, UFunction*>& DelegateCache);
|
|
|
|
// Retry functions.
|
|
void InitScriptLocation( FScriptLocation& Retry );
|
|
void ReturnToLocation( const FScriptLocation& Retry, bool Binary=1, bool Text=1 );
|
|
|
|
static void ValidatePropertyIsDeprecatedIfNecessary(const FPropertyBase& VarProperty, const FToken* OuterPropertyType);
|
|
|
|
// Cache of ScriptStructs that have been validated for Net Replication and RPC
|
|
TSet<UScriptStruct*> ScriptStructsValidForNet;
|
|
|
|
/**
|
|
* Validate that a ScriptStruct is ok to be Replicated or Sent in an RPC.
|
|
*
|
|
* @param OriginStructName The Name of the ScriptStruct to check
|
|
* @param InStruct The ScriptStruct to check
|
|
*/
|
|
bool ValidateScriptStructOkForNet(const FString& OriginStructName, UScriptStruct* InStruct);
|
|
|
|
private:
|
|
// Source file currently parsed by UHT.
|
|
FUnrealSourceFile* CurrentSourceFile;
|
|
|
|
// Module currently parsed by UHT.
|
|
const FManifestModule* CurrentlyParsedModule;
|
|
|
|
// True if the module currently being parsed is part of the engine, as opposed to being part of a game
|
|
bool bIsCurrentModulePartOfEngine;
|
|
|
|
/**
|
|
* Tries to match constructor parameter list. Assumes that constructor
|
|
* name is already matched.
|
|
*
|
|
* If fails it reverts all parsing done.
|
|
*
|
|
* @param Token Token to start parsing from.
|
|
*
|
|
* @returns True if matched. False otherwise.
|
|
*/
|
|
bool TryToMatchConstructorParameterList(FToken Token);
|
|
|
|
// Parses possible version declaration in generated code, e.g. GENERATED_BODY(<some_version>).
|
|
void CompileVersionDeclaration(UStruct* Struct);
|
|
|
|
// Verifies that all specified class's UProperties with function associations have valid targets
|
|
void VerifyPropertyMarkups( UClass* TargetClass );
|
|
|
|
// Verifies the target function meets the criteria for a blueprint property getter
|
|
void VerifyBlueprintPropertyGetter(FProperty* Property, UFunction* TargetFunction);
|
|
|
|
// Verifies the target function meets the criteria for a blueprint property setter
|
|
void VerifyBlueprintPropertySetter(FProperty* Property, UFunction* TargetFunction);
|
|
|
|
// Verifies the target function meets the criteria for a replication notify callback
|
|
void VerifyRepNotifyCallback(FProperty* Property, UFunction* TargetFunction);
|
|
|
|
// Constructs the policy from a string
|
|
static FDocumentationPolicy GetDocumentationPolicyFromName(const FString& PolicyName);
|
|
|
|
// Constructs the policy for documentation checks for a given struct
|
|
static FDocumentationPolicy GetDocumentationPolicyForStruct(UStruct* Struct);
|
|
|
|
// Property types to provide UI Min and Max ranges
|
|
static TArray<FString> PropertyCPPTypesRequiringUIRanges;
|
|
|
|
// Returns true if a given CPP types required ui checking
|
|
static bool DoesCPPTypeRequireDocumentation(const FString& CPPType);
|
|
|
|
// Validates the documentation for a given enum
|
|
void CheckDocumentationPolicyForEnum(UEnum* Enum, const TMap<FName, FString>& MetaData, const TArray<TMap<FName, FString>>& Entries);
|
|
|
|
// Validates the documentation for a given struct
|
|
void CheckDocumentationPolicyForStruct(UStruct* Struct);
|
|
|
|
// Validates the documentation for a given method
|
|
void CheckDocumentationPolicyForFunc(UClass* Class, UFunction* Func);
|
|
|
|
// Checks if a valid range has been found on the provided metadata
|
|
bool CheckUIMinMaxRangeFromMetaData(const FString& UIMin, const FString& UIMax);
|
|
|
|
// Checks if a valid range has been found on the provided metadata
|
|
void ConditionalLogPointerUsage(EPointerMemberBehavior PointerMemberBehavior, const TCHAR* PointerTypeDesc, FString&& PointerTypeDecl);
|
|
|
|
// Names that cannot be used enums, UStructs, or UClasses
|
|
static TArray<FString> ReservedTypeNames;
|
|
|
|
public:
|
|
/**
|
|
* Checks if the given token uses one of the reserved type names.
|
|
*
|
|
* @param TypeName String of the type to check (For UObject/UClass, use the stripped name)
|
|
* @return True if the TypeName is a reserved name
|
|
*/
|
|
static bool IsReservedTypeName(const FString& TypeName);
|
|
|
|
/**
|
|
* Checks if the given token uses one of the reserved type names.
|
|
*
|
|
* @param Token The token to check
|
|
* @return True if the Token is using a reserved name
|
|
*/
|
|
static bool IsReservedTypeName(const FToken& Token);
|
|
|
|
static const FName NAME_InputText;
|
|
static const FName NAME_OutputText;
|
|
static const FName NAME_ConstantText;
|
|
static const FName NAME_VisibleText;
|
|
static const FName NAME_ArraySizeText;
|
|
static const FName NAME_SingletonText;
|
|
static const TCHAR* TArrayText;
|
|
static const TCHAR* TEnumAsByteText;
|
|
static const TCHAR* FFixedArrayText;
|
|
static const TCHAR* FDynamicArrayText;
|
|
static const TCHAR* GetRefText;
|
|
static const TCHAR* GetFixedArrayText;
|
|
static const TCHAR* GetDynamicArrayText;
|
|
};
|
|
|
|
/////////////////////////////////////////////////////
|
|
// FHeaderPreParser
|
|
|
|
class FHeaderPreParser : public FBaseParser
|
|
{
|
|
public:
|
|
FHeaderPreParser()
|
|
{
|
|
}
|
|
|
|
void ParseClassDeclaration(
|
|
const TCHAR* Filename,
|
|
const TCHAR* InputText,
|
|
int32 InLineNumber,
|
|
const TCHAR*
|
|
StartingMatchID,
|
|
FName& out_StrippedClassName,
|
|
FString& out_ClassName,
|
|
FString& out_BaseClassName,
|
|
TArray<FHeaderProvider>& out_ClassNames,
|
|
const TArray<FSimplifiedParsingClassInfo>& ParsedClassArray
|
|
);
|
|
};
|