2014-12-07 19:09:38 -05:00
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
2014-03-14 14:13:41 -04:00
# include "UnrealHeaderTool.h"
# include "UniquePtr.h"
# include "ParserHelper.h"
# include "NativeClassExporter.h"
# include "HeaderParser.h"
# include "ClassMaps.h"
2014-05-22 01:20:24 -04:00
# include "IScriptGeneratorPluginInterface.h"
2014-04-02 18:09:23 -04:00
# include "Manifest.h"
2014-04-23 18:46:37 -04:00
# include "StringUtils.h"
2014-06-30 06:19:02 -04:00
# include "IPluginManager.h"
2014-03-14 14:13:41 -04:00
/////////////////////////////////////////////////////
2014-04-02 18:09:23 -04:00
// Globals
2014-03-14 14:13:41 -04:00
2014-04-02 18:09:23 -04:00
FManifest GManifest ;
2014-03-14 14:13:41 -04:00
2015-03-27 17:16:51 -04:00
double GMacroizeTime = 0.0 ;
double GTabifyTime = 0.0 ;
2014-03-14 14:13:41 -04:00
static TArray < FString > ChangeMessages ;
static bool bWriteContents = false ;
static bool bVerifyContents = false ;
static const bool bMultiLineUFUNCTION = true ;
static const bool bMultiLineUPROPERTY = true ;
2015-03-27 17:16:51 -04:00
static TSharedRef < FUnrealSourceFile > PerformInitialParseOnHeader ( UPackage * InParent , const FString & FileName , EObjectFlags Flags , const TCHAR * Buffer ) ;
2014-03-14 14:13:41 -04:00
2014-06-02 07:02:29 -04:00
FCompilerMetadataManager GScriptHelper ;
2014-03-14 14:13:41 -04:00
/** C++ name lookup helper */
2014-06-02 07:02:29 -04:00
FNameLookupCPP NameLookupCPP ;
2014-03-14 14:13:41 -04:00
2015-03-27 18:10:52 -04:00
static const int32 MaxNumTabs = 64 ;
static const TCHAR TabString [ MaxNumTabs + 1 ] = TEXT ( " \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t " ) ;
const TCHAR * GetTabs ( int32 NumTabs )
{
checkSlow ( ( NumTabs > = 0 ) & & ( NumTabs < MaxNumTabs ) ) ;
const uint32 TabPos = MaxNumTabs - NumTabs ;
return TabString + TabPos ;
}
2015-04-20 06:19:21 -04:00
/**
* Finds exact match of Identifier in string . Returns nullptr if none is found .
*
* @ param StringBegin Start of string to search .
* @ param StringEnd End of string to search .
* @ param Identifier Identifier to find .
* @ return Pointer to Identifier match within string . nullptr if none found .
*/
const TCHAR * FindIdentifierExactMatch ( const TCHAR * StringBegin , const TCHAR * StringEnd , const FString & Identifier )
2015-04-10 06:02:22 -04:00
{
2015-04-20 06:19:21 -04:00
int32 StringLen = StringEnd - StringBegin ;
// Check for exact match first.
if ( FCString : : Strncmp ( StringBegin , * Identifier , StringLen ) = = 0 )
{
return StringBegin ;
}
auto FindLen = Identifier . Len ( ) ;
auto StringToSearch = StringBegin ;
2015-04-10 06:02:22 -04:00
for ( ; ; )
{
2015-04-20 06:19:21 -04:00
auto IdentifierStart = FCString : : Strstr ( StringToSearch , * Identifier ) ;
if ( IdentifierStart = = nullptr )
2015-04-10 06:02:22 -04:00
{
2015-04-20 06:19:21 -04:00
// Not found.
return nullptr ;
2015-04-10 06:02:22 -04:00
}
2015-04-20 06:19:21 -04:00
if ( ( IdentifierStart > StringEnd ) | | ( IdentifierStart + FindLen + 1 > StringEnd ) )
2015-04-10 06:02:22 -04:00
{
2015-04-20 06:19:21 -04:00
// Found match is out of string range.
return nullptr ;
2015-04-10 06:02:22 -04:00
}
2015-04-20 06:19:21 -04:00
if ( ( IdentifierStart = = StringBegin ) & & ( ! FChar : : IsIdentifier ( * ( IdentifierStart + FindLen + 1 ) ) ) )
{
// Found match is at the beginning of string.
return IdentifierStart ;
2015-04-17 04:04:20 -04:00
}
2015-04-20 06:19:21 -04:00
if ( ( IdentifierStart + FindLen = = StringEnd ) & & ( ! FChar : : IsIdentifier ( * ( IdentifierStart - 1 ) ) ) )
{
// Found match ends with end of string.
return IdentifierStart ;
}
if ( ( ! FChar : : IsIdentifier ( * ( IdentifierStart + FindLen ) ) )
& & ( ! FChar : : IsIdentifier ( * ( IdentifierStart - 1 ) ) ) )
{
// Found match is in the middle of string
return IdentifierStart ;
}
// Didn't find exact match, nor got to end of search string. Keep on searching.
StringToSearch = IdentifierStart + FindLen ;
}
2015-04-10 06:02:22 -04:00
// We should never get here.
checkNoEntry ( ) ;
2015-04-20 06:19:21 -04:00
return nullptr ;
}
/**
* Finds exact match of Identifier in string . Returns nullptr if none is found .
*
* @ param String String to search .
* @ param Identifier Identifier to find .
* @ return Index to Identifier match within String . INDEX_NONE if none found .
*/
int32 FindIdentifierExactMatch ( const FString & String , const FString & Identifier )
{
auto IdentifierPtr = FindIdentifierExactMatch ( * String , * String + String . Len ( ) , Identifier ) ;
if ( IdentifierPtr = = nullptr )
{
return INDEX_NONE ;
}
return IdentifierPtr - * String ;
}
/**
* Checks if exact match of Identifier is in String .
*
* @ param StringBegin Start of string to search .
* @ param StringEnd End of string to search .
* @ param Identifier Identifier to find .
* @ return true if Identifier is within string , false otherwise .
*/
bool HasIdentifierExactMatch ( const TCHAR * StringBegin , const TCHAR * StringEnd , const FString & Find )
{
return FindIdentifierExactMatch ( StringBegin , StringEnd , Find ) ! = nullptr ;
}
/**
* Checks if exact match of Identifier is in String .
*
* @ param String String to search .
* @ param Identifier Identifier to find .
* @ return true if Identifier is within String , false otherwise .
*/
bool HasIdentifierExactMatch ( const FString & String , const FString & Identifier )
{
return FindIdentifierExactMatch ( String , Identifier ) ! = INDEX_NONE ;
2015-04-10 06:02:22 -04:00
}
2014-03-14 14:13:41 -04:00
/////////////////////////////////////////////////////
// FFlagAudit
//@todo: UCREMOVAL this is all audit stuff
static struct FFlagAudit
{
struct Pair
{
FString Name ;
uint64 Flags ;
Pair ( UObject * Source , const TCHAR * FlagType , uint64 InFlags )
{
Name = Source - > GetFullName ( ) + TEXT ( " [ " ) + FlagType + TEXT ( " ] " ) ;
Flags = InFlags ;
}
} ;
TArray < Pair > Items ;
void Add ( UObject * Source , const TCHAR * FlagType , uint64 Flags )
{
new ( Items ) Pair ( Source , FlagType , Flags ) ;
}
void WriteResults ( )
{
bool bDoDiff = false ;
FString Filename ;
FString RefFilename = FString ( FPaths : : GameSavedDir ( ) ) / TEXT ( " ReferenceFlags.txt " ) ;
if ( ! FParse : : Param ( FCommandLine : : Get ( ) , TEXT ( " WRITEFLAGS " ) ) )
{
return ;
}
if ( FParse : : Param ( FCommandLine : : Get ( ) , TEXT ( " WRITEREF " ) ) )
{
Filename = RefFilename ;
}
else if ( FParse : : Param ( FCommandLine : : Get ( ) , TEXT ( " VERIFYREF " ) ) )
{
Filename = FString ( FPaths : : GameSavedDir ( ) ) / TEXT ( " VerifyFlags.txt " ) ;
bDoDiff = true ;
}
struct FComparePairByName
{
FORCEINLINE bool operator ( ) ( const FFlagAudit : : Pair & A , const FFlagAudit : : Pair & B ) const { return A . Name < B . Name ; }
} ;
Items . Sort ( FComparePairByName ( ) ) ;
int32 MaxLen = 0 ;
for ( int32 Index = 0 ; Index < Items . Num ( ) ; Index + + )
{
MaxLen = FMath : : Max < int32 > ( Items [ Index ] . Name . Len ( ) , MaxLen ) ;
}
MaxLen + = 4 ;
FStringOutputDevice File ;
for ( int32 Index = 0 ; Index < Items . Num ( ) ; Index + + )
{
File . Logf ( TEXT ( " %s%s0x%016llx \r \n " ) , * Items [ Index ] . Name , FCString : : Spc ( MaxLen - Items [ Index ] . Name . Len ( ) ) , Items [ Index ] . Flags ) ;
}
FFileHelper : : SaveStringToFile ( File , * Filename ) ;
if ( bDoDiff )
{
FString Verify = File ;
FString Ref ;
if ( FFileHelper : : LoadFileToString ( Ref , * RefFilename ) )
{
FStringOutputDevice MisMatches ;
TArray < FString > VerifyLines ;
2015-03-02 15:51:37 -05:00
Verify . ParseIntoArray ( VerifyLines , TEXT ( " \n " ) , true ) ;
2014-03-14 14:13:41 -04:00
TArray < FString > RefLines ;
2015-03-02 15:51:37 -05:00
Ref . ParseIntoArray ( RefLines , TEXT ( " \n " ) , true ) ;
2014-03-14 14:13:41 -04:00
check ( VerifyLines . Num ( ) = = RefLines . Num ( ) ) ; // we aren't doing a sophisticated diff
for ( int32 Index = 0 ; Index < RefLines . Num ( ) ; Index + + )
{
if ( RefLines [ Index ] ! = VerifyLines [ Index ] )
{
MisMatches . Logf ( TEXT ( " REF : %s " ) , * RefLines [ Index ] ) ;
MisMatches . Logf ( TEXT ( " VERIFY: %s " ) , * VerifyLines [ Index ] ) ;
}
}
FString DiffFilename = FString ( FPaths : : GameSavedDir ( ) ) / TEXT ( " FlagsDiff.txt " ) ;
FFileHelper : : SaveStringToFile ( MisMatches , * DiffFilename ) ;
}
}
}
} TheFlagAudit ;
2015-03-27 17:16:51 -04:00
static FString Tabify ( const TCHAR * Input )
2014-03-14 14:13:41 -04:00
{
2015-03-27 17:16:51 -04:00
FScopedDurationTimer Tracker ( GTabifyTime ) ;
2014-03-14 14:13:41 -04:00
FString Result ( Input ) ;
const int32 SpacesPerTab = 4 ;
2015-03-27 18:10:52 -04:00
Result . ReplaceInline ( TEXT ( " \r \n " ) , TEXT ( " \n " ) , ESearchCase : : CaseSensitive ) ;
2014-03-14 14:13:41 -04:00
TArray < FString > Lines ;
2015-03-27 18:10:52 -04:00
Result . ParseIntoArray ( Lines , TEXT ( " \n " ) , false ) ;
Result . Reset ( ) ;
2014-03-14 14:13:41 -04:00
for ( int32 Index = 0 ; Index < Lines . Num ( ) ; Index + + )
{
if ( Index )
{
Result + = TEXT ( " \r \n " ) ;
}
2015-03-27 18:10:52 -04:00
2014-03-14 14:13:41 -04:00
FString & Line = Lines [ Index ] ;
2015-03-27 18:10:52 -04:00
int32 NumSpaces = 0 ;
2014-03-14 14:13:41 -04:00
int32 FirstNonWS = 0 ;
2015-03-27 18:10:52 -04:00
int32 NumTrueTabs = 0 ;
2014-03-14 14:13:41 -04:00
while ( 1 )
{
TCHAR c = * ( * Line + FirstNonWS ) ;
2015-03-27 18:10:52 -04:00
if ( c = = TEXT ( ' \t ' ) )
{
+ + NumTrueTabs ;
NumSpaces + = SpacesPerTab ;
}
else if ( c = = TEXT ( ' ' ) )
{
+ + NumSpaces ;
}
else
2014-03-14 14:13:41 -04:00
{
break ;
}
FirstNonWS + + ;
}
2015-03-27 18:10:52 -04:00
const int32 NumTabs = NumSpaces / SpacesPerTab ;
const int32 LeftoverSpaces = NumSpaces % SpacesPerTab ;
if ( ( NumTrueTabs = = NumTabs ) & & ( LeftoverSpaces = = 0 ) )
2014-03-14 14:13:41 -04:00
{
2015-03-27 18:10:52 -04:00
Result + = Line ;
}
else
{
FString Remainder = * Line + FirstNonWS ;
for ( int32 Tab = 0 ; Tab < NumTabs ; Tab + + )
{
Result + = TEXT ( " \t " ) ;
}
if ( LeftoverSpaces > 0 )
{
Result + = FCString : : Spc ( LeftoverSpaces ) ;
}
Result + = Remainder ;
2014-03-14 14:13:41 -04:00
}
}
return Result ;
}
2014-05-19 06:57:00 -04:00
void ConvertToBuildIncludePath ( UPackage * Package , FString & LocalPath )
{
FPaths : : MakePathRelativeTo ( LocalPath , * GPackageToManifestModuleMap . FindChecked ( Package ) - > IncludeBase ) ;
}
2014-03-14 14:13:41 -04:00
/**
* Helper function for finding the location of a package
* This is required as source now lives in several possible directories
*
* @ param InPackage The name of the package of interest
* @ param OutLocation The location of the given package , if found
* @ param OutHeaderLocation The directory where generated headers should be placed
*
* @ return bool true if found , false if not
*/
2014-09-18 04:05:01 -04:00
bool FindPackageLocation ( const TCHAR * InPackage , FString & OutLocation , FString & OutHeaderLocation )
2014-03-14 14:13:41 -04:00
{
// Mapping of processed packages to their locations
// An empty location string means it was processed but not found
2014-04-23 20:18:55 -04:00
static TMap < FString , FManifestModule * > CheckedPackageList ;
2014-03-14 14:13:41 -04:00
FString CheckPackage ( InPackage ) ;
2014-04-02 18:09:23 -04:00
auto * ModuleInfoPtr = CheckedPackageList . FindRef ( CheckPackage ) ;
2014-03-14 14:13:41 -04:00
if ( ! ModuleInfoPtr )
{
2014-04-23 20:18:55 -04:00
auto * ModuleInfoPtr2 = GManifest . Modules . FindByPredicate ( [ & ] ( FManifestModule & Module ) { return Module . Name = = CheckPackage ; } ) ;
2014-03-14 14:13:41 -04:00
if ( ModuleInfoPtr2 & & IFileManager : : Get ( ) . DirectoryExists ( * ModuleInfoPtr2 - > BaseDirectory ) )
{
ModuleInfoPtr = ModuleInfoPtr2 ;
CheckedPackageList . Add ( CheckPackage , ModuleInfoPtr ) ;
}
}
if ( ! ModuleInfoPtr )
return false ;
OutLocation = ModuleInfoPtr - > BaseDirectory ;
OutHeaderLocation = ModuleInfoPtr - > GeneratedIncludeDirectory ;
return true ;
}
2015-03-27 17:16:51 -04:00
FString Macroize ( const TCHAR * MacroName , const TCHAR * StringToMacroize )
2014-03-14 14:13:41 -04:00
{
2015-03-27 17:16:51 -04:00
FScopedDurationTimer Tracker ( GMacroizeTime ) ;
2014-03-14 14:13:41 -04:00
FString Result = StringToMacroize ;
if ( Result . Len ( ) )
{
2015-03-27 18:10:52 -04:00
Result . ReplaceInline ( TEXT ( " \r \n " ) , TEXT ( " \n " ) , ESearchCase : : CaseSensitive ) ;
Result . ReplaceInline ( TEXT ( " \n " ) , TEXT ( " \\ \n " ) , ESearchCase : : CaseSensitive ) ;
checkSlow ( Result . EndsWith ( TEXT ( " \\ \n " ) , ESearchCase : : CaseSensitive ) ) ;
if ( Result . Len ( ) > = 3 )
{
for ( int32 Index = Result . Len ( ) - 3 ; Index < Result . Len ( ) ; + + Index )
{
Result [ Index ] = TEXT ( ' \n ' ) ;
}
}
else
{
Result = TEXT ( " \n \n \n " ) ;
}
Result . ReplaceInline ( TEXT ( " \n " ) , TEXT ( " \r \n " ) , ESearchCase : : CaseSensitive ) ;
2014-03-14 14:13:41 -04:00
}
return FString : : Printf ( TEXT ( " #define %s%s \r \n " ) , MacroName , Result . Len ( ) ? TEXT ( " \\ " ) : TEXT ( " " ) ) + Result ;
}
2014-10-30 09:53:47 -04:00
/** Generates a CRC tag string for the specified field */
static FString GetGeneratedCodeCRCTag ( UField * Field )
{
FString Tag ;
auto FieldCrc = GGeneratedCodeCRCs . Find ( Field ) ;
if ( FieldCrc )
{
Tag = FString : : Printf ( TEXT ( " // %u " ) , * FieldCrc ) ;
}
return Tag ;
}
2014-03-14 14:13:41 -04:00
struct FParmsAndReturnProperties
{
FParmsAndReturnProperties ( )
: Return ( NULL )
{
}
# if PLATFORM_COMPILER_HAS_DEFAULTED_FUNCTIONS
FParmsAndReturnProperties ( FParmsAndReturnProperties & & ) = default ;
FParmsAndReturnProperties ( const FParmsAndReturnProperties & ) = default ;
FParmsAndReturnProperties & operator = ( FParmsAndReturnProperties & & ) = default ;
FParmsAndReturnProperties & operator = ( const FParmsAndReturnProperties & ) = default ;
# else
FParmsAndReturnProperties ( FParmsAndReturnProperties & & Other ) : Parms ( MoveTemp ( Other . Parms ) ) , Return ( MoveTemp ( Other . Return ) ) { }
FParmsAndReturnProperties ( const FParmsAndReturnProperties & Other ) : Parms ( Other . Parms ) , Return ( Other . Return ) { }
FParmsAndReturnProperties & operator = ( FParmsAndReturnProperties & & Other ) { Parms = MoveTemp ( Other . Parms ) ; Return = MoveTemp ( Other . Return ) ; return * this ; }
FParmsAndReturnProperties & operator = ( const FParmsAndReturnProperties & Other ) { Parms = Other . Parms ; Return = Other . Return ; return * this ; }
# endif
bool HasParms ( ) const
{
return Parms . Num ( ) | | Return ;
}
TArray < UProperty * > Parms ;
UProperty * Return ;
} ;
/**
* Get parameters and return type for a given function .
*
* @ param Function The function to get the parameters for .
* @ return An aggregate containing the parameters and return type of that function .
*/
FParmsAndReturnProperties GetFunctionParmsAndReturn ( UFunction * Function )
{
FParmsAndReturnProperties Result ;
for ( TFieldIterator < UProperty > It ( Function ) ; It ; + + It )
{
UProperty * Field = * It ;
if ( ( It - > PropertyFlags & ( CPF_Parm | CPF_ReturnParm ) ) = = CPF_Parm )
{
Result . Parms . Add ( Field ) ;
}
else if ( It - > PropertyFlags & CPF_ReturnParm )
{
Result . Return = Field ;
}
}
return Result ;
}
/**
* Determines whether the glue version of the specified native function
* should be exported
*
* @ param Function the function to check
* @ return true if the glue version of the function should be exported .
*/
bool FNativeClassHeaderGenerator : : ShouldExportFunction ( UFunction * Function )
{
// export any script stubs for native functions declared in interface classes
bool bIsBlueprintNativeEvent = ( Function - > FunctionFlags & FUNC_BlueprintEvent ) & & ( Function - > FunctionFlags & FUNC_Native ) ;
if ( Function - > GetOwnerClass ( ) - > HasAnyClassFlags ( CLASS_Interface ) & & ! bIsBlueprintNativeEvent )
return true ;
// always export if the function is static
if ( Function - > FunctionFlags & FUNC_Static )
return true ;
// don't export the function if this is not the original declaration and there is
// at least one parent version of the function that is declared native
for ( UFunction * ParentFunction = Function - > GetSuperFunction ( ) ; ParentFunction ; ParentFunction = ParentFunction - > GetSuperFunction ( ) )
{
if ( ParentFunction - > FunctionFlags & FUNC_Native )
return false ;
}
return true ;
}
FString CreateLiteralString ( const FString & Str )
{
FString Result = TEXT ( " TEXT( \" " ) ;
// Have a reasonable guess at reserving the right size
Result . Reserve ( Str . Len ( ) + Result . Len ( ) ) ;
bool bPreviousCharacterWasHex = false ;
const TCHAR * Ptr = * Str ;
while ( TCHAR Ch = * Ptr + + )
{
switch ( Ch )
{
case TEXT ( ' \r ' ) : continue ;
case TEXT ( ' \n ' ) : Result + = TEXT ( " \\ n " ) ; bPreviousCharacterWasHex = false ; break ;
case TEXT ( ' \\ ' ) : Result + = TEXT ( " \\ \\ " ) ; bPreviousCharacterWasHex = false ; break ;
case TEXT ( ' \" ' ) : Result + = TEXT ( " \\ \" " ) ; bPreviousCharacterWasHex = false ; break ;
default :
if ( Ch < 31 | | Ch > = 128 )
{
Result + = FString : : Printf ( TEXT ( " \\ x%04x " ) , Ch ) ;
bPreviousCharacterWasHex = true ;
}
else
{
// We close and open the literal (with TEXT) here in order to ensure that successive hex characters aren't appended to the hex sequence, causing a different number
if ( bPreviousCharacterWasHex & & FCharWide : : IsHexDigit ( Ch ) )
{
Result + = " \" )TEXT( \" " ;
}
bPreviousCharacterWasHex = false ;
Result + = Ch ;
}
break ;
}
}
Result + = TEXT ( " \" ) " ) ;
return Result ;
}
static FString GetMetaDataCodeForObject ( UObject * Object , const TCHAR * SymbolName , const TCHAR * Spaces )
{
TMap < FName , FString > * MetaData = UMetaData : : GetMapForObject ( Object ) ;
FString Result ;
if ( MetaData & & MetaData - > Num ( ) )
{
typedef TKeyValuePair < FName , FString > KVPType ;
TArray < KVPType > KVPs ;
for ( auto & KVP : * MetaData )
{
KVPs . Add ( KVPType ( KVP . Key , KVP . Value ) ) ;
}
// We sort the metadata here so that we can get consistent output across multiple runs
// even when metadata is added in a different order
KVPs . Sort ( [ ] ( const KVPType & Lhs , const KVPType & Rhs ) { return Lhs . Key < Rhs . Key ; } ) ;
for ( const auto & KVP : KVPs )
{
Result + = FString : : Printf ( TEXT ( " %sMetaData->SetValue(%s, TEXT( \" %s \" ), %s); \r \n " ) , Spaces , SymbolName , * KVP . Key . ToString ( ) , * CreateLiteralString ( KVP . Value ) ) ;
}
}
return Result ;
}
/**
* Exports the struct ' s C + + properties to the specified output device and adds special
* compiler directives for GCC to pack as we expect .
*
* @ param Struct UStruct to export properties
* @ param TextIndent Current text indentation
* @ param ImportsDefaults whether this struct will be serialized with a default value
*/
2015-03-27 18:10:52 -04:00
void FNativeClassHeaderGenerator : : ExportProperties ( UStruct * Struct , int32 TextIndent , bool bAccessSpecifiers , FUHTStringBuilder * Output )
2014-03-14 14:13:41 -04:00
{
UProperty * Previous = NULL ;
UProperty * PreviousNonEditorOnly = NULL ;
UProperty * LastInSuper = NULL ;
UStruct * InheritanceSuper = Struct - > GetInheritanceSuper ( ) ;
bool bEmittedHasEditorOnlyMacro = false ;
bool bEmittedHasScriptAlign = false ;
2015-03-27 18:10:52 -04:00
check ( Output ! = NULL ) ;
FUHTStringBuilder & HeaderOutput = * Output ;
2014-03-14 14:13:41 -04:00
// Find last property in the lowest base class that has any properties
UStruct * CurrentSuper = InheritanceSuper ;
while ( LastInSuper = = NULL & & CurrentSuper )
{
for ( TFieldIterator < UProperty > It ( CurrentSuper , EFieldIteratorFlags : : ExcludeSuper ) ; It ; + + It )
{
UProperty * Current = * It ;
// Disregard properties with 0 size like functions.
if ( It . GetStruct ( ) = = CurrentSuper & & Current - > ElementSize )
{
LastInSuper = Current ;
}
}
// go up a layer in the hierarchy
CurrentSuper = CurrentSuper - > GetSuperStruct ( ) ;
}
EPropertyHeaderExportFlags CurrentExportType = PROPEXPORT_Public ;
// find structs that are nothing but bytes, account for editor only properties being
// removed on consoles
int32 NumProperties = 0 ;
int32 NumByteProperties = 0 ;
int32 NumNonEditorOnlyProperties = 0 ;
int32 NumNonEditorOnlyByteProperties = 0 ;
for ( TFieldIterator < UProperty > It ( Struct , EFieldIteratorFlags : : ExcludeSuper ) ; It ; + + It )
{
// treat bitfield and bytes the same
bool bIsByteProperty = It - > IsA ( UByteProperty : : StaticClass ( ) ) ; // || It->IsA(UBoolProperty::StaticClass());
bool bIsEditorOnlyProperty = It - > IsEditorOnlyProperty ( ) ;
// count our propertie
NumProperties + + ;
if ( bIsByteProperty )
{
2014-04-02 18:09:23 -04:00
NumByteProperties + + ;
2014-03-14 14:13:41 -04:00
}
if ( ! bIsEditorOnlyProperty )
{
NumNonEditorOnlyProperties + + ;
}
if ( ! bIsEditorOnlyProperty & & bIsByteProperty )
{
NumNonEditorOnlyByteProperties + + ;
}
}
bool bCurrentlyInNotCPPBlock = false ;
// Iterate over all properties in this struct.
for ( TFieldIterator < UProperty > It ( Struct , EFieldIteratorFlags : : ExcludeSuper ) ; It ; + + It )
{
UProperty * Current = * It ;
2015-03-27 18:10:52 -04:00
FUHTStringBuilder PropertyText ;
2014-03-14 14:13:41 -04:00
// Disregard properties with 0 size like functions.
if ( It . GetStruct ( ) = = Struct )
{
FString AccessSpecifier = TEXT ( " public " ) ;
if ( bAccessSpecifiers )
{
// find the class info for this class
2015-01-20 09:33:54 -05:00
FClassMetaData * ClassData = GScriptHelper . FindClassData ( Struct ) ;
2014-03-14 14:13:41 -04:00
// find the compiler token for this property
FTokenData * PropData = ClassData - > FindTokenData ( Current ) ;
if ( PropData ! = NULL )
{
// if this property has a different access specifier, then export that now
if ( ( PropData - > Token . PropertyExportFlags & CurrentExportType ) = = 0 )
{
if ( ( PropData - > Token . PropertyExportFlags & PROPEXPORT_Private ) ! = 0 )
{
CurrentExportType = PROPEXPORT_Private ;
AccessSpecifier = TEXT ( " private " ) ;
}
else if ( ( PropData - > Token . PropertyExportFlags & PROPEXPORT_Protected ) ! = 0 )
{
CurrentExportType = PROPEXPORT_Protected ;
AccessSpecifier = TEXT ( " protected " ) ;
}
else
{
CurrentExportType = PROPEXPORT_Public ;
AccessSpecifier = TEXT ( " public " ) ;
}
if ( AccessSpecifier . Len ( ) )
{
// If we are changing the access specifier we need to emit the #endif for the WITH_EDITORONLY_DATA macro first otherwise the access specifier may
// only be conditionally compiled in.
if ( bEmittedHasEditorOnlyMacro )
{
PropertyText . Logf ( TEXT ( " #endif // WITH_EDITORONLY_DATA \r \n " ) ) ;
bEmittedHasEditorOnlyMacro = false ;
}
2015-03-27 18:10:52 -04:00
PropertyText . Logf ( TEXT ( " %s: " ) LINE_TERMINATOR , * AccessSpecifier ) ;
2014-03-14 14:13:41 -04:00
}
}
}
}
// If we are switching from editor to non-editor or vice versa and the state of the WITH_EDITORONLY_DATA macro emission doesn't match, generate the
// #if or #endif appropriately.
bool RequiresHasEditorOnlyMacro = Current - > IsEditorOnlyProperty ( ) ;
if ( ! bEmittedHasEditorOnlyMacro & & RequiresHasEditorOnlyMacro )
{
// Indent code and export CPP text.
PropertyText . Logf ( TEXT ( " #if WITH_EDITORONLY_DATA \r \n " ) ) ;
bEmittedHasEditorOnlyMacro = true ;
}
else if ( bEmittedHasEditorOnlyMacro & & ! RequiresHasEditorOnlyMacro )
{
PropertyText . Logf ( TEXT ( " #endif // WITH_EDITORONLY_DATA \r \n " ) ) ;
bEmittedHasEditorOnlyMacro = false ;
}
// Export property specifiers
// Indent code and export CPP text.
{
2015-03-27 18:10:52 -04:00
FUHTStringBuilder JustPropertyDecl ;
2014-03-14 14:13:41 -04:00
const FString * Dim = GArrayDimensions . Find ( Current ) ;
Current - > ExportCppDeclaration ( JustPropertyDecl , EExportedDeclaration : : Member , Dim ? * * Dim : NULL ) ;
ApplyAlternatePropertyExportText ( * It , JustPropertyDecl ) ;
// Finish up line.
2015-03-27 18:10:52 -04:00
PropertyText . Logf ( TEXT ( " %s%s; \r \n " ) , GetTabs ( TextIndent + 1 ) , * JustPropertyDecl ) ;
2014-03-14 14:13:41 -04:00
}
LastInSuper = NULL ;
2015-03-27 18:10:52 -04:00
Previous = Current ;
2014-03-14 14:13:41 -04:00
if ( ! Current - > IsEditorOnlyProperty ( ) )
{
PreviousNonEditorOnly = Current ;
}
HeaderOutput . Log ( PropertyText ) ;
}
}
if ( bCurrentlyInNotCPPBlock )
{
2015-03-27 18:10:52 -04:00
HeaderOutput + = TEXT ( " #endif \r \n " ) ;
2014-03-14 14:13:41 -04:00
bCurrentlyInNotCPPBlock = false ;
}
// End of property list. If we haven't generated the WITH_EDITORONLY_DATA #endif, do so now.
if ( bEmittedHasEditorOnlyMacro )
{
2015-03-27 18:10:52 -04:00
HeaderOutput + = TEXT ( " #endif // WITH_EDITORONLY_DATA \r \n " ) ;
2014-03-14 14:13:41 -04:00
}
// if the last property that was exported wasn't public, emit a line to reset the access to "public" so that we don't interfere with cpptext
2015-03-27 18:10:52 -04:00
if ( CurrentExportType ! = PROPEXPORT_Public )
2014-03-14 14:13:41 -04:00
{
2015-03-27 18:10:52 -04:00
HeaderOutput + = TEXT ( " public: " ) LINE_TERMINATOR ;
2014-03-14 14:13:41 -04:00
}
}
/** This table maps a singleton name to an extern declaration for it. For cross-module access, we add these to GeneratedFunctionDeclarations **/
static TMap < FString , FString > SingletonNameToExternDecl ;
FString FNativeClassHeaderGenerator : : GetSingletonName ( UField * Item , bool bRequiresValidObject )
{
FString Suffix ;
2014-06-02 07:02:29 -04:00
if ( UClass * ItemClass = Cast < UClass > ( Item ) )
2014-03-14 14:13:41 -04:00
{
2014-06-02 07:02:29 -04:00
if ( ItemClass - > HasAllClassFlags ( CLASS_Intrinsic ) )
{
return FString : : Printf ( TEXT ( " %s::StaticClass() " ) , NameLookupCPP . GetNameCPP ( ItemClass ) ) ;
}
if ( ! bRequiresValidObject & & ItemClass - > HasAllClassFlags ( CLASS_Native ) )
{
Suffix = TEXT ( " _NoRegister " ) ;
}
2014-03-14 14:13:41 -04:00
}
FString Result ;
UObject * Outer = Item ;
while ( Outer )
{
if ( Cast < UClass > ( Outer ) | | Cast < UScriptStruct > ( Outer ) )
{
2014-06-02 07:02:29 -04:00
FString OuterName = NameLookupCPP . GetNameCPP ( Cast < UStruct > ( Outer ) ) ;
2014-03-14 14:13:41 -04:00
if ( Result . Len ( ) )
{
Result = OuterName + TEXT ( " _ " ) + Result ;
}
else
{
Result = OuterName ;
}
// Structs can also have UPackage outer.
if ( Cast < UClass > ( Outer ) | | Cast < UPackage > ( Outer - > GetOuter ( ) ) )
{
break ;
}
}
else if ( Result . Len ( ) )
{
// Handle UEnums with UPackage outer.
Result = Outer - > GetName ( ) + TEXT ( " _ " ) + Result ;
}
else
{
Result = Outer - > GetName ( ) ;
}
Outer = Outer - > GetOuter ( ) ;
}
2015-01-20 09:33:54 -05:00
2014-06-02 07:02:29 -04:00
FString ClassString = NameLookupCPP . GetNameCPP ( Item - > GetClass ( ) ) ;
2014-03-14 14:13:41 -04:00
// Can't use long package names in function names.
2015-03-27 18:10:52 -04:00
if ( Result . StartsWith ( TEXT ( " /Script/ " ) , ESearchCase : : CaseSensitive ) )
2014-03-14 14:13:41 -04:00
{
Result = FPackageName : : GetShortName ( Result ) ;
}
Result = FString ( TEXT ( " Z_Construct_ " ) ) + ClassString + TEXT ( " _ " ) + Result + Suffix + TEXT ( " () " ) ;
if ( CastChecked < UPackage > ( Item - > GetOutermost ( ) ) ! = Package )
{
// this is a cross module reference, we need to include the right extern decl
FString * Extern = SingletonNameToExternDecl . Find ( Result ) ;
if ( ! Extern )
{
UE_LOG ( LogCompile , Warning , TEXT ( " Could not find extern declaration for cross module reference %s \n " ) , * Result ) ;
}
else
{
bool bAlreadyInSet = false ;
UniqueCrossModuleReferences . Add ( * Extern , & bAlreadyInSet ) ;
if ( ! bAlreadyInSet )
{
CrossModuleGeneratedFunctionDeclarations . Log ( * Extern ) ;
}
}
}
return Result ;
}
2014-06-02 07:02:29 -04:00
FString FNativeClassHeaderGenerator : : GetSingletonName ( FClass * Item , bool bRequiresValidObject )
{
return GetSingletonName ( ( UClass * ) Item , bRequiresValidObject ) ;
}
2014-03-14 14:13:41 -04:00
FString FNativeClassHeaderGenerator : : PropertyNew ( FString & Meta , UProperty * Prop , const FString & OuterString , const FString & PropMacro , const TCHAR * NameSuffix , const TCHAR * Spaces , const TCHAR * SourceStruct )
{
FString ExtraArgs ;
2014-07-29 02:43:48 -04:00
FString GeneratedCrc ;
2014-03-14 14:13:41 -04:00
FString PropNameDep = Prop - > GetName ( ) ;
if ( Prop - > HasAllPropertyFlags ( CPF_Deprecated ) )
{
PropNameDep + = TEXT ( " _DEPRECATED " ) ;
}
if ( UObjectPropertyBase * ObjectProperty = Cast < UObjectPropertyBase > ( Prop ) )
{
UClass * TargetClass = ObjectProperty - > PropertyClass ;
if ( UClassProperty * ClassProperty = Cast < UClassProperty > ( Prop ) )
{
TargetClass = ClassProperty - > MetaClass ;
}
if ( UAssetClassProperty * SubclassOfProperty = Cast < UAssetClassProperty > ( Prop ) )
{
TargetClass = SubclassOfProperty - > MetaClass ;
}
ExtraArgs = FString : : Printf ( TEXT ( " , %s " ) , * GetSingletonName ( TargetClass , false ) ) ;
}
else if ( UInterfaceProperty * InterfaceProperty = Cast < UInterfaceProperty > ( Prop ) )
{
UClass * TargetClass = InterfaceProperty - > InterfaceClass ;
ExtraArgs = FString : : Printf ( TEXT ( " , %s " ) , * GetSingletonName ( TargetClass , false ) ) ;
}
else if ( UStructProperty * StructProperty = Cast < UStructProperty > ( Prop ) )
{
UScriptStruct * Struct = StructProperty - > Struct ;
check ( Struct ) ;
ExtraArgs = FString : : Printf ( TEXT ( " , %s " ) , * GetSingletonName ( Struct ) ) ;
}
else if ( UByteProperty * ByteProperty = Cast < UByteProperty > ( Prop ) )
{
if ( ByteProperty - > Enum )
{
ExtraArgs = FString : : Printf ( TEXT ( " , %s " ) , * GetSingletonName ( ByteProperty - > Enum ) ) ;
}
}
else if ( UBoolProperty * BoolProperty = Cast < UBoolProperty > ( Prop ) )
{
if ( Cast < UArrayProperty > ( BoolProperty - > GetOuter ( ) ) )
{
ExtraArgs = FString ( TEXT ( " , 0 " ) ) ; // this is an array of C++ bools so the mask is irrelevant.
}
else
{
check ( SourceStruct ) ;
ExtraArgs = FString : : Printf ( TEXT ( " , CPP_BOOL_PROPERTY_BITMASK(%s, %s) " ) , * PropNameDep , SourceStruct ) ;
}
ExtraArgs + = FString : : Printf ( TEXT ( " , sizeof(%s), %s " ) , * BoolProperty - > GetCPPType ( NULL , 0 ) , BoolProperty - > IsNativeBool ( ) ? TEXT ( " true " ) : TEXT ( " false " ) ) ;
}
else if ( UDelegateProperty * DelegateProperty = Cast < UDelegateProperty > ( Prop ) )
{
UFunction * TargetFunction = DelegateProperty - > SignatureFunction ;
ExtraArgs = FString : : Printf ( TEXT ( " , %s " ) , * GetSingletonName ( TargetFunction ) ) ;
}
else if ( UMulticastDelegateProperty * MulticastDelegateProperty = Cast < UMulticastDelegateProperty > ( Prop ) )
{
UFunction * TargetFunction = MulticastDelegateProperty - > SignatureFunction ;
ExtraArgs = FString : : Printf ( TEXT ( " , %s " ) , * GetSingletonName ( TargetFunction ) ) ;
}
2015-01-30 08:30:03 -05:00
FString Constructor = FString : : Printf ( TEXT ( " new(EC_InternalUseOnlyConstructor, %s, TEXT( \" %s \" ), RF_Public|RF_Transient|RF_Native) U%s(%s, 0x%016llx%s); " ) ,
2014-03-14 14:13:41 -04:00
* OuterString ,
* Prop - > GetName ( ) ,
* Prop - > GetClass ( ) - > GetName ( ) ,
* PropMacro ,
Prop - > PropertyFlags & ~ CPF_ComputedFlags ,
* ExtraArgs ) ;
TheFlagAudit . Add ( Prop , TEXT ( " PropertyFlags " ) , Prop - > PropertyFlags ) ;
FString Symbol = FString : : Printf ( TEXT ( " NewProp_%s%s " ) , * Prop - > GetName ( ) , NameSuffix ) ;
2014-07-29 02:43:48 -04:00
FString Lines = FString : : Printf ( TEXT ( " %sUProperty* %s = %s%s \r \n " ) ,
2014-03-14 14:13:41 -04:00
Spaces ,
* Symbol ,
2014-07-29 02:43:48 -04:00
* Constructor ,
2014-10-30 09:53:47 -04:00
* GetGeneratedCodeCRCTag ( Prop ) ) ;
2014-03-14 14:13:41 -04:00
if ( Prop - > ArrayDim ! = 1 )
{
Lines + = FString : : Printf ( TEXT ( " %s%s->ArrayDim = CPP_ARRAY_DIM(%s, %s); \r \n " ) , Spaces , * Symbol , * PropNameDep , SourceStruct ) ;
}
if ( Prop - > RepNotifyFunc ! = NAME_None )
{
Lines + = FString : : Printf ( TEXT ( " %s%s->RepNotifyFunc = FName(TEXT( \" %s \" )); \r \n " ) , Spaces , * Symbol , * Prop - > RepNotifyFunc . ToString ( ) ) ;
}
Meta + = GetMetaDataCodeForObject ( Prop , * Symbol , Spaces ) ;
return Lines ;
}
void FNativeClassHeaderGenerator : : OutputProperties ( FString & Meta , FOutputDevice & OutputDevice , const FString & OuterString , TArray < UProperty * > & Properties , const TCHAR * Spaces )
{
bool bEmittedHasEditorOnlyMacro = false ;
for ( int32 Index = Properties . Num ( ) - 1 ; Index > = 0 ; Index - - )
{
bool RequiresHasEditorOnlyMacro = Properties [ Index ] - > IsEditorOnlyProperty ( ) ;
if ( ! bEmittedHasEditorOnlyMacro & & RequiresHasEditorOnlyMacro )
{
// Indent code and export CPP text.
OutputDevice . Logf ( TEXT ( " #if WITH_EDITORONLY_DATA \r \n " ) ) ;
bEmittedHasEditorOnlyMacro = true ;
}
else if ( bEmittedHasEditorOnlyMacro & & ! RequiresHasEditorOnlyMacro )
{
OutputDevice . Logf ( TEXT ( " #endif // WITH_EDITORONLY_DATA \r \n " ) ) ;
bEmittedHasEditorOnlyMacro = false ;
}
2014-11-06 15:16:05 -05:00
OutputProperty ( Meta , OutputDevice , OuterString , Properties [ Index ] , Spaces ) ;
2014-03-14 14:13:41 -04:00
}
if ( bEmittedHasEditorOnlyMacro )
{
OutputDevice . Logf ( TEXT ( " #endif // WITH_EDITORONLY_DATA \r \n " ) ) ;
}
}
2015-01-20 09:33:54 -05:00
inline FString GetEventStructParamsName ( UObject * Outer , const TCHAR * FunctionName )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
FString OuterName ;
if ( Outer - > IsA < UClass > ( ) )
{
OuterName = ( ( UClass * ) Outer ) - > GetName ( ) ;
}
else if ( Outer - > IsA < UPackage > ( ) )
{
2015-03-27 18:10:52 -04:00
OuterName = ( ( UPackage * ) Outer ) - > GetName ( ) ;
OuterName . ReplaceInline ( TEXT ( " / " ) , TEXT ( " _ " ) , ESearchCase : : CaseSensitive ) ;
2015-01-20 09:33:54 -05:00
}
else
{
FError : : Throwf ( TEXT ( " Unrecognized outer type " ) ) ;
}
FString Result = FString : : Printf ( TEXT ( " %s_event%s_Parms " ) , * OuterName , FunctionName ) ;
2014-03-14 14:13:41 -04:00
return Result ;
}
void FNativeClassHeaderGenerator : : OutputProperty ( FString & Meta , FOutputDevice & OutputDevice , const FString & OuterString , UProperty * Prop , const TCHAR * Spaces )
{
{
FString SourceStruct ;
UFunction * Function = Cast < UFunction > ( Prop - > GetOuter ( ) ) ;
if ( Function )
{
while ( Function - > GetSuperFunction ( ) )
{
Function = Function - > GetSuperFunction ( ) ;
}
FString FunctionName = Function - > GetName ( ) ;
if ( Function - > HasAnyFunctionFlags ( FUNC_Delegate ) )
{
FunctionName = FunctionName . LeftChop ( FString ( HEADER_GENERATED_DELEGATE_SIGNATURE_SUFFIX ) . Len ( ) ) ;
}
2015-01-20 09:33:54 -05:00
SourceStruct = GetEventStructParamsName ( Function - > GetOuter ( ) , * FunctionName ) ;
2014-03-14 14:13:41 -04:00
}
else
{
2014-06-02 07:02:29 -04:00
SourceStruct = NameLookupCPP . GetNameCPP ( CastChecked < UStruct > ( Prop - > GetOuter ( ) ) ) ;
2014-03-14 14:13:41 -04:00
}
FString PropMacroOuterClass ;
FString PropNameDep = Prop - > GetName ( ) ;
if ( Prop - > HasAllPropertyFlags ( CPF_Deprecated ) )
{
PropNameDep + = TEXT ( " _DEPRECATED " ) ;
}
UBoolProperty * BoolProperty = Cast < UBoolProperty > ( Prop ) ;
if ( BoolProperty )
{
OutputDevice . Logf ( TEXT ( " %sCPP_BOOL_PROPERTY_BITMASK_STRUCT(%s, %s, %s); \r \n " ) ,
Spaces ,
* PropNameDep ,
* SourceStruct ,
* BoolProperty - > GetCPPType ( NULL , 0 ) ) ;
2014-10-14 10:29:11 -04:00
PropMacroOuterClass = FString : : Printf ( TEXT ( " FObjectInitializer(), EC_CppProperty, CPP_BOOL_PROPERTY_OFFSET(%s, %s) " ) ,
2014-03-14 14:13:41 -04:00
* PropNameDep , * SourceStruct ) ;
}
else
{
PropMacroOuterClass = FString : : Printf ( TEXT ( " CPP_PROPERTY_BASE(%s, %s) " ) , * PropNameDep , * SourceStruct ) ;
}
OutputDevice . Log ( * PropertyNew ( Meta , Prop , OuterString , PropMacroOuterClass , TEXT ( " " ) , Spaces , * SourceStruct ) ) ;
}
2015-04-21 10:25:59 -04:00
if ( UArrayProperty * ArrayProperty = Cast < UArrayProperty > ( Prop ) )
2014-03-14 14:13:41 -04:00
{
FString InnerOuterString = FString : : Printf ( TEXT ( " NewProp_%s " ) , * Prop - > GetName ( ) ) ;
2014-10-14 10:29:11 -04:00
FString PropMacroOuterArray = TEXT ( " FObjectInitializer(), EC_CppProperty, 0 " ) ;
2014-03-14 14:13:41 -04:00
OutputDevice . Log ( * PropertyNew ( Meta , ArrayProperty - > Inner , InnerOuterString , PropMacroOuterArray , TEXT ( " _Inner " ) , Spaces ) ) ;
}
2015-04-21 10:25:59 -04:00
if ( UMapProperty * MapProperty = Cast < UMapProperty > ( Prop ) )
{
FString InnerOuterString = FString : : Printf ( TEXT ( " NewProp_%s " ) , * Prop - > GetName ( ) ) ;
FString PropMacroOuterMap = TEXT ( " FObjectInitializer(), EC_CppProperty, " ) ;
OutputDevice . Log ( * PropertyNew ( Meta , MapProperty - > KeyProp , InnerOuterString , PropMacroOuterMap + TEXT ( " 0 " ) , TEXT ( " _KeyProp " ) , Spaces ) ) ;
OutputDevice . Log ( * PropertyNew ( Meta , MapProperty - > ValueProp , InnerOuterString , PropMacroOuterMap + TEXT ( " 1 " ) , TEXT ( " _ValueProp " ) , Spaces ) ) ;
}
2014-03-14 14:13:41 -04:00
}
static FString BackSlashAndIndent ( const FString & Text )
{
FString Trailer ( TEXT ( " \\ \r \n " ) ) ;
2015-03-27 18:10:52 -04:00
FString Result = FString ( TEXT ( " " ) ) + Text . Replace ( TEXT ( " \r \n " ) , * Trailer , ESearchCase : : CaseSensitive ) ;
2014-03-14 14:13:41 -04:00
return Result . LeftChop ( Trailer . Len ( ) ) + TEXT ( " \r \n " ) ;
}
static bool IsAlwaysAccessible ( UScriptStruct * Script )
{
FName ToTest = Script - > GetFName ( ) ;
if ( ToTest = = NAME_Matrix )
{
return false ; // special case, the C++ FMatrix does not have the same members.
}
bool Result = Script - > HasDefaults ( ) ; // if we have cpp struct ops in it for UHT, then we can assume it is always accessible
if ( ToTest = = NAME_Plane
| | ToTest = = NAME_Vector
| | ToTest = = NAME_Vector4
| | ToTest = = NAME_Quat
| | ToTest = = NAME_Color
)
{
check ( Result ) ;
}
return Result ;
}
static void FindNoExportStructs ( TArray < UScriptStruct * > & Structs , UStruct * Start )
{
while ( Start )
{
if ( UScriptStruct * StartScript = Cast < UScriptStruct > ( Start ) )
{
if ( StartScript - > StructFlags & STRUCT_Native )
{
break ;
}
if ( ! IsAlwaysAccessible ( StartScript ) ) // these are a special cases that already exists and if wrong if exported nievely
{
// this will topologically sort them in reverse order
Structs . Remove ( StartScript ) ;
Structs . Add ( StartScript ) ;
}
}
2015-04-21 10:25:59 -04:00
for ( UProperty * Prop : TFieldRange < UProperty > ( Start , EFieldIteratorFlags : : ExcludeSuper ) )
2014-03-14 14:13:41 -04:00
{
2015-04-21 10:25:59 -04:00
if ( UStructProperty * StructProp = Cast < UStructProperty > ( Prop ) )
2014-03-14 14:13:41 -04:00
{
2015-04-21 10:25:59 -04:00
FindNoExportStructs ( Structs , StructProp - > Struct ) ;
2014-03-14 14:13:41 -04:00
}
2015-04-21 10:25:59 -04:00
else if ( UArrayProperty * ArrayProp = Cast < UArrayProperty > ( Prop ) )
2014-03-14 14:13:41 -04:00
{
2015-04-21 10:25:59 -04:00
if ( UStructProperty * InnerStructProp = Cast < UStructProperty > ( ArrayProp - > Inner ) )
{
FindNoExportStructs ( Structs , InnerStructProp - > Struct ) ;
}
}
else if ( UMapProperty * MapProp = Cast < UMapProperty > ( Prop ) )
{
if ( UStructProperty * KeyStructProp = Cast < UStructProperty > ( MapProp - > KeyProp ) )
{
FindNoExportStructs ( Structs , KeyStructProp - > Struct ) ;
}
if ( UStructProperty * ValueStructProp = Cast < UStructProperty > ( MapProp - > ValueProp ) )
{
FindNoExportStructs ( Structs , ValueStructProp - > Struct ) ;
}
2014-03-14 14:13:41 -04:00
}
}
Start = Start - > GetSuperStruct ( ) ;
}
}
FString GetPackageSingletonName ( UPackage * Package )
{
2014-06-02 07:02:29 -04:00
static FString ClassString = NameLookupCPP . GetNameCPP ( UPackage : : StaticClass ( ) ) ;
2014-03-14 14:13:41 -04:00
return FString ( TEXT ( " Z_Construct_ " ) ) + ClassString + TEXT ( " _ " ) + FPackageName : : GetShortName ( Package ) + TEXT ( " () " ) ;
}
2015-04-22 14:15:56 -04:00
void FNativeClassHeaderGenerator : : ExportGeneratedPackageInitCode ( UPackage * InPackage )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
FString ApiString = GetAPIString ( ) ;
2015-04-22 14:15:56 -04:00
FString SingletonName ( GetPackageSingletonName ( InPackage ) ) ;
2014-03-14 14:13:41 -04:00
2015-03-27 18:10:52 -04:00
FUHTStringBuilder & GeneratedFunctionText = GetGeneratedFunctionTextDevice ( ) ;
2014-03-14 14:13:41 -04:00
GeneratedFunctionDeclarations . Logf ( TEXT ( " %sclass UPackage* %s; \r \n " ) , * ApiString , * SingletonName ) ;
GeneratedFunctionText . Logf ( TEXT ( " UPackage* %s \r \n " ) , * SingletonName ) ;
GeneratedFunctionText . Logf ( TEXT ( " { \r \n " ) ) ;
GeneratedFunctionText . Logf ( TEXT ( " static UPackage* ReturnPackage = NULL; \r \n " ) ) ;
GeneratedFunctionText . Logf ( TEXT ( " if (!ReturnPackage) \r \n " ) ) ;
GeneratedFunctionText . Logf ( TEXT ( " { \r \n " ) ) ;
2015-04-22 14:15:56 -04:00
GeneratedFunctionText . Logf ( TEXT ( " ReturnPackage = CastChecked<UPackage>(StaticFindObjectFast(UPackage::StaticClass(), NULL, FName(TEXT( \" %s \" )), false, false)); \r \n " ) , * InPackage - > GetName ( ) ) ;
2014-03-14 14:13:41 -04:00
2015-04-22 14:15:56 -04:00
FString Meta = GetMetaDataCodeForObject ( InPackage , TEXT ( " ReturnPackage " ) , TEXT ( " " ) ) ;
2014-03-14 14:13:41 -04:00
if ( Meta . Len ( ) )
{
GeneratedFunctionText . Logf ( TEXT ( " #if WITH_METADATA \r \n " ) ) ;
GeneratedFunctionText . Logf ( TEXT ( " UMetaData* MetaData = ReturnPackage->GetMetaData(); \r \n " ) ) ;
GeneratedFunctionText . Log ( * Meta ) ;
GeneratedFunctionText . Logf ( TEXT ( " #endif \r \n " ) ) ;
}
2015-04-22 14:15:56 -04:00
GeneratedFunctionText . Logf ( TEXT ( " ReturnPackage->PackageFlags |= PKG_CompiledIn | 0x%08X; \r \n " ) , InPackage - > PackageFlags & ( PKG_ClientOptional | PKG_ServerSideOnly ) ) ;
TheFlagAudit . Add ( InPackage , TEXT ( " PackageFlags " ) , InPackage - > PackageFlags ) ;
2014-03-14 14:13:41 -04:00
{
FGuid Guid ;
2015-01-13 12:24:06 -05:00
uint32 CombinedCRC = 0 ;
for ( auto & Split : GeneratedFunctionBodyTextSplit )
{
2015-04-14 08:03:34 -04:00
uint32 SplitCRC = GenerateTextCRC ( * Split - > ToUpper ( ) ) ;
2015-01-13 12:24:06 -05:00
if ( CombinedCRC = = 0 )
{
// Don't combine in the first case because it keeps GUID backwards compatibility
CombinedCRC = SplitCRC ;
}
else
{
CombinedCRC = HashCombine ( SplitCRC , CombinedCRC ) ;
}
}
Guid . A = CombinedCRC ;
2014-12-11 04:58:57 -05:00
Guid . B = GenerateTextCRC ( * GeneratedFunctionDeclarations . ToUpper ( ) ) ;
2014-03-14 14:13:41 -04:00
GeneratedFunctionText . Logf ( TEXT ( " FGuid Guid; \r \n " ) ) ;
GeneratedFunctionText . Logf ( TEXT ( " Guid.A = 0x%08X; \r \n " ) , Guid . A ) ;
GeneratedFunctionText . Logf ( TEXT ( " Guid.B = 0x%08X; \r \n " ) , Guid . B ) ;
GeneratedFunctionText . Logf ( TEXT ( " Guid.C = 0x%08X; \r \n " ) , Guid . C ) ;
GeneratedFunctionText . Logf ( TEXT ( " Guid.D = 0x%08X; \r \n " ) , Guid . D ) ;
GeneratedFunctionText . Logf ( TEXT ( " ReturnPackage->SetGuid(Guid); \r \n " ) , Guid . D ) ;
2015-01-20 09:33:54 -05:00
GeneratedFunctionText . Log ( TEXT ( " \r \n " ) ) ;
for ( UField * ScriptType : TObjectRange < UField > ( ) )
{
2015-04-22 14:15:56 -04:00
if ( ScriptType - > GetOutermost ( ) ! = InPackage )
2015-01-20 09:33:54 -05:00
{
continue ;
}
if (
( ScriptType - > IsA < UScriptStruct > ( ) & & ( ( ( UScriptStruct * ) ScriptType ) - > StructFlags & STRUCT_NoExport ) ! = 0 ) | |
ScriptType - > IsA < UDelegateFunction > ( )
)
{
GeneratedFunctionText . Logf ( TEXT ( " %s; \r \n " ) , * GetSingletonName ( ScriptType ) ) ;
}
}
2014-03-14 14:13:41 -04:00
}
GeneratedFunctionText . Logf ( TEXT ( " } \r \n " ) ) ;
GeneratedFunctionText . Logf ( TEXT ( " return ReturnPackage; \r \n " ) ) ;
GeneratedFunctionText . Logf ( TEXT ( " } \r \n " ) ) ;
}
2015-03-27 18:10:52 -04:00
void FNativeClassHeaderGenerator : : ExportNativeGeneratedInitCode ( FClass * Class , FUHTStringBuilder & OutFriendText )
2014-03-14 14:13:41 -04:00
{
2015-03-27 18:10:52 -04:00
FUHTStringBuilder & GeneratedFunctionText = GetGeneratedFunctionTextDevice ( ) ;
2015-01-20 09:33:54 -05:00
check ( ! OutFriendText . Len ( ) ) ;
2014-03-14 14:13:41 -04:00
// Emit code to build the UObjects that used to be in .u files
2015-01-20 09:33:54 -05:00
bool bIsNoExport = Class - > HasAnyClassFlags ( CLASS_NoExport ) ;
2015-03-27 18:10:52 -04:00
FUHTStringBuilder BodyText ;
FUHTStringBuilder CallSingletons ;
2015-01-20 09:33:54 -05:00
FString ApiString = GetAPIString ( ) ;
2014-03-14 14:13:41 -04:00
TArray < UFunction * > FunctionsToExport ;
for ( TFieldIterator < UFunction > Function ( Class , EFieldIteratorFlags : : ExcludeSuper ) ; Function ; + + Function )
{
FunctionsToExport . Add ( * Function ) ;
}
// Sort the list of functions
FunctionsToExport . Sort ( ) ;
// find the class info for this class
2014-06-02 07:02:29 -04:00
FClassMetaData * ClassData = GScriptHelper . FindClassData ( Class ) ;
2014-03-14 14:13:41 -04:00
// Export the init code for each function
for ( int32 FuncIndex = 0 ; FuncIndex < FunctionsToExport . Num ( ) ; FuncIndex + + )
{
UFunction * Function = FunctionsToExport [ FuncIndex ] ;
2015-03-12 14:06:13 -04:00
if ( ! Function - > IsA < UDelegateFunction > ( ) )
{
ExportFunction ( Function , & FScope : : GetTypeScope ( Class ) . Get ( ) , bIsNoExport ) ;
}
2015-01-20 09:33:54 -05:00
CallSingletons . Logf ( TEXT ( " OuterClass->LinkChild(%s); \r \n " ) , * GetSingletonName ( Function ) ) ;
2014-03-14 14:13:41 -04:00
}
2015-03-27 18:10:52 -04:00
FUHTStringBuilder GeneratedClassRegisterFunctionText ;
2014-07-29 02:43:48 -04:00
2015-01-20 09:33:54 -05:00
// The class itself.
2014-03-14 14:13:41 -04:00
{
// simple ::StaticClass wrapper to avoid header, link and DLL hell
{
FString SingletonNameNoRegister ( GetSingletonName ( Class , false ) ) ;
FString Extern = FString : : Printf ( TEXT ( " %sclass UClass* %s; \r \n " ) , * ApiString , * SingletonNameNoRegister ) ;
SingletonNameToExternDecl . Add ( SingletonNameNoRegister , Extern ) ;
GeneratedFunctionDeclarations . Log ( * Extern ) ;
2014-07-29 02:43:48 -04:00
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " UClass* %s \r \n " ) , * SingletonNameNoRegister ) ;
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " { \r \n " ) ) ;
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " return %s::StaticClass(); \r \n " ) , NameLookupCPP . GetNameCPP ( Class ) ) ;
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " } \r \n " ) ) ;
2014-03-14 14:13:41 -04:00
}
FString SingletonName ( GetSingletonName ( Class ) ) ;
2015-01-20 09:33:54 -05:00
OutFriendText . Logf ( TEXT ( " friend %sclass UClass* %s; \r \n " ) , * ApiString , * SingletonName ) ;
2014-03-14 14:13:41 -04:00
FString Extern = FString : : Printf ( TEXT ( " %sclass UClass* %s; \r \n " ) , * ApiString , * SingletonName ) ;
SingletonNameToExternDecl . Add ( SingletonName , Extern ) ;
GeneratedFunctionDeclarations . Log ( * Extern ) ;
2014-07-29 02:43:48 -04:00
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " UClass* %s \r \n " ) , * SingletonName ) ;
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " { \r \n " ) ) ;
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " static UClass* OuterClass = NULL; \r \n " ) ) ;
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " if (!OuterClass) \r \n " ) ) ;
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " { \r \n " ) ) ;
2014-03-14 14:13:41 -04:00
if ( Class - > GetSuperClass ( ) & & Class - > GetSuperClass ( ) ! = Class )
{
2014-07-29 02:43:48 -04:00
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " %s; \r \n " ) , * GetSingletonName ( Class - > GetSuperClass ( ) ) ) ;
2014-03-14 14:13:41 -04:00
}
2014-07-29 02:43:48 -04:00
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " %s; \r \n " ) , * GetPackageSingletonName ( CastChecked < UPackage > ( Class - > GetOutermost ( ) ) ) ) ;
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " OuterClass = %s::StaticClass(); \r \n " ) , NameLookupCPP . GetNameCPP ( Class ) ) ;
2014-11-06 15:16:05 -05:00
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " if (!(OuterClass->ClassFlags & CLASS_Constructed)) \r \n " ) , NameLookupCPP . GetNameCPP ( Class ) ) ;
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " { \r \n " ) , NameLookupCPP . GetNameCPP ( Class ) ) ;
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " UObjectForceRegistration(OuterClass); \r \n " ) ) ;
uint32 Flags = ( Class - > ClassFlags & CLASS_SaveInCompiledInClasses ) | CLASS_Constructed ;
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " OuterClass->ClassFlags |= 0x%08X; \r \n " ) , Flags ) ;
2014-03-14 14:13:41 -04:00
TheFlagAudit . Add ( Class , TEXT ( " ClassFlags " ) , Flags ) ;
2014-07-29 02:43:48 -04:00
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " \r \n " ) ) ;
GeneratedClassRegisterFunctionText . Log ( CallSingletons ) ;
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " \r \n " ) ) ;
2014-03-14 14:13:41 -04:00
FString OuterString = FString ( TEXT ( " OuterClass " ) ) ;
2014-11-06 15:16:05 -05:00
FString Meta = GetMetaDataCodeForObject ( Class , * OuterString , TEXT ( " " ) ) ;
2014-03-14 14:13:41 -04:00
// properties
{
TArray < UProperty * > Props ;
for ( TFieldIterator < UProperty > ItInner ( Class , EFieldIteratorFlags : : ExcludeSuper ) ; ItInner ; + + ItInner )
{
Props . Add ( * ItInner ) ;
}
2015-02-05 13:10:48 -05:00
if ( Props . Num ( ) > 0 )
{
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " PRAGMA_DISABLE_DEPRECATION_WARNINGS \r \n " ) ) ;
OutputProperties ( Meta , GeneratedClassRegisterFunctionText , OuterString , Props , TEXT ( " " ) ) ;
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " PRAGMA_POP \r \n " ) ) ;
}
2014-03-14 14:13:41 -04:00
}
// function table
{
// Grab and sort the list of functions in the function map
TArray < UFunction * > FunctionsInMap ;
for ( auto Function : TFieldRange < UFunction > ( Class , EFieldIteratorFlags : : ExcludeSuper ) )
{
FunctionsInMap . Add ( Function ) ;
}
FunctionsInMap . Sort ( ) ;
// Emit code to construct each UFunction and rebuild the function map at runtime
for ( UFunction * Function : FunctionsInMap )
{
2014-11-06 15:16:05 -05:00
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " OuterClass->AddFunctionToFunctionMap(%s);%s \r \n " ) , * GetSingletonName ( Function ) , * GetGeneratedCodeCRCTag ( Function ) ) ;
2014-03-14 14:13:41 -04:00
}
}
// class flags are handled by the intrinsic bootstrap code
2014-07-29 02:43:48 -04:00
//GeneratedClassRegisterFunctionText.Logf(TEXT(" OuterClass->ClassFlags = 0x%08X;\r\n"), Class->ClassFlags);
2014-03-14 14:13:41 -04:00
if ( Class - > ClassConfigName ! = NAME_None )
{
2014-11-06 15:16:05 -05:00
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " OuterClass->ClassConfigName = FName(TEXT( \" %s \" )); \r \n " ) , * Class - > ClassConfigName . ToString ( ) ) ;
2014-03-14 14:13:41 -04:00
}
for ( auto & Inter : Class - > Interfaces )
{
check ( Inter . Class ) ;
FString OffsetString ( TEXT ( " 0 " ) ) ;
if ( Inter . PointerOffset )
{
2014-06-02 07:02:29 -04:00
OffsetString = FString : : Printf ( TEXT ( " VTABLE_OFFSET(%s, %s) " ) , NameLookupCPP . GetNameCPP ( Class ) , NameLookupCPP . GetNameCPP ( Inter . Class , true ) ) ;
2014-03-14 14:13:41 -04:00
}
2014-11-06 15:16:05 -05:00
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " OuterClass->Interfaces.Add(FImplementedInterface(%s, %s, %s )); \r \n " ) ,
2014-03-14 14:13:41 -04:00
* GetSingletonName ( Inter . Class , false ) ,
* OffsetString ,
Inter . bImplementedByK2 ? TEXT ( " true " ) : TEXT ( " false " )
) ;
}
if ( Class - > ClassGeneratedBy )
{
UE_LOG ( LogCompile , Fatal , TEXT ( " For intrinsic and compiled-in classes, ClassGeneratedBy should always be NULL " ) ) ;
2014-11-06 15:16:05 -05:00
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " OuterClass->ClassGeneratedBy = %s; \r \n " ) , * GetSingletonName ( CastChecked < UClass > ( Class - > ClassGeneratedBy ) , false ) ) ;
2014-03-14 14:13:41 -04:00
}
2014-11-06 15:16:05 -05:00
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " OuterClass->StaticLink(); \r \n " ) ) ;
2014-03-14 14:13:41 -04:00
if ( Meta . Len ( ) )
{
2014-07-29 02:43:48 -04:00
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " #if WITH_METADATA \r \n " ) ) ;
2014-11-06 15:16:05 -05:00
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " UMetaData* MetaData = OuterClass->GetOutermost()->GetMetaData(); \r \n " ) ) ;
2014-07-29 02:43:48 -04:00
GeneratedClassRegisterFunctionText . Log ( * Meta ) ;
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " #endif \r \n " ) ) ;
2014-03-14 14:13:41 -04:00
}
2014-11-06 15:16:05 -05:00
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " } \r \n " ) ) ;
2014-07-29 02:43:48 -04:00
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " } \r \n " ) ) ;
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " check(OuterClass->GetClass()); \r \n " ) ) ;
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " return OuterClass; \r \n " ) ) ;
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " } \r \n " ) ) ;
GeneratedFunctionText + = GeneratedClassRegisterFunctionText ;
2014-03-14 14:13:41 -04:00
}
2015-01-20 09:33:54 -05:00
if ( OutFriendText . Len ( ) & & bIsNoExport )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
GeneratedFunctionText . Logf ( TEXT ( " /* friend declarations for pasting into noexport class %s \r \n " ) , NameLookupCPP . GetNameCPP ( Class ) ) ;
GeneratedFunctionText . Log ( OutFriendText ) ;
GeneratedFunctionText . Logf ( TEXT ( " */ \r \n " ) ) ;
2015-03-27 18:10:52 -04:00
OutFriendText . Reset ( ) ;
2014-03-14 14:13:41 -04:00
}
FString SingletonName ( GetSingletonName ( Class ) ) ;
2015-03-27 18:10:52 -04:00
SingletonName . ReplaceInline ( TEXT ( " () " ) , TEXT ( " " ) , ESearchCase : : CaseSensitive ) ; // function address
2014-03-14 14:13:41 -04:00
2014-07-29 02:43:48 -04:00
{
2015-01-20 09:33:54 -05:00
auto ClassNameCPP = NameLookupCPP . GetNameCPP ( Class ) ;
2014-07-29 02:43:48 -04:00
GeneratedFunctionText . Logf ( TEXT ( " static FCompiledInDefer Z_CompiledInDefer_UClass_%s(%s, TEXT( \" %s \" )); \r \n " ) ,
ClassNameCPP , * SingletonName , ClassNameCPP ) ;
// Calculate generated class initialization code CRC so that we know when it changes after hot-reload
2014-12-11 04:58:57 -05:00
uint32 ClassCrc = GenerateTextCRC ( * GeneratedClassRegisterFunctionText ) ;
2014-07-29 02:43:48 -04:00
// Emit the IMPLEMENT_CLASS macro to go in the generated cpp file.
GeneratedPackageCPP . Logf ( TEXT ( " IMPLEMENT_CLASS(%s, %u); \r \n " ) , ClassNameCPP , ClassCrc ) ;
2014-03-14 14:13:41 -04:00
}
}
2015-01-20 09:33:54 -05:00
void FNativeClassHeaderGenerator : : ExportFunction ( UFunction * Function , FScope * Scope , bool bIsNoExport )
{
UFunction * SuperFunction = Function - > GetSuperFunction ( ) ;
auto * CompilerInfo = FFunctionData : : FindForFunction ( Function ) ;
bool bIsDelegate = Function - > HasAnyFunctionFlags ( FUNC_Delegate ) ;
const FFuncInfo & FunctionData = CompilerInfo - > GetFunctionData ( ) ;
const FString SingletonName ( GetSingletonName ( Function ) ) ;
FString Extern = FString : : Printf ( TEXT ( " %sclass UFunction* %s; \r \n " ) , * GetAPIString ( ) , * SingletonName ) ;
SingletonNameToExternDecl . Add ( SingletonName , Extern ) ;
GeneratedFunctionDeclarations . Log ( * Extern ) ;
2015-03-27 18:10:52 -04:00
FUHTStringBuilder CurrentFunctionText ;
2015-01-20 09:33:54 -05:00
CurrentFunctionText . Logf ( TEXT ( " UFunction* %s \r \n " ) , * SingletonName ) ;
CurrentFunctionText . Logf ( TEXT ( " { \r \n " ) ) ;
if ( bIsNoExport | | ! ( Function - > FunctionFlags & FUNC_Event ) ) // non-events do not export a params struct, so lets do that locally for offset determination
{
TGuardValue < bool > Guard ( bIsExportingForOffsetDeterminationOnly , true ) ;
TArray < UScriptStruct * > Structs ;
FindNoExportStructs ( Structs , Function ) ;
if ( Structs . Num ( ) )
{
2015-03-27 18:10:52 -04:00
ExportMirrorsForNoexportStructs ( Structs , /*Indent=*/ 2 , CurrentFunctionText ) ;
2015-01-20 09:33:54 -05:00
}
TArray < UFunction * > CallbackFunctions ;
CallbackFunctions . Add ( Function ) ;
2015-03-27 18:10:52 -04:00
ExportEventParms ( * Scope , CallbackFunctions , CurrentFunctionText , /*Indent=*/ 2 , /*bOutputConstructor=*/ false ) ;
2015-01-20 09:33:54 -05:00
}
if ( UObject * Outer = Function - > GetOuter ( ) )
{
CurrentFunctionText . Logf ( TEXT ( " UObject* Outer=%s; \r \n " ) , Outer - > IsA < UPackage > ( ) ? * GetPackageSingletonName ( ( UPackage * ) Outer ) : * GetSingletonName ( Function - > GetOwnerClass ( ) ) ) ;
}
else
{
CurrentFunctionText . Logf ( TEXT ( " UObject* Outer=nullptr; \r \n " ) ) ;
}
CurrentFunctionText . Logf ( TEXT ( " static UFunction* ReturnFunction = NULL; \r \n " ) ) ;
CurrentFunctionText . Logf ( TEXT ( " if (!ReturnFunction) \r \n " ) ) ;
CurrentFunctionText . Logf ( TEXT ( " { \r \n " ) ) ;
FString SuperFunctionString ( TEXT ( " NULL " ) ) ;
if ( SuperFunction )
{
SuperFunctionString = GetSingletonName ( SuperFunction ) ;
}
TArray < UProperty * > Props ;
for ( TFieldIterator < UProperty > ItInner ( Function , EFieldIteratorFlags : : ExcludeSuper ) ; ItInner ; + + ItInner )
{
Props . Add ( * ItInner ) ;
}
FString StructureSize ;
if ( Props . Num ( ) )
{
UFunction * TempFunction = Function ;
while ( TempFunction - > GetSuperFunction ( ) )
{
TempFunction = TempFunction - > GetSuperFunction ( ) ;
}
FString FunctionName = TempFunction - > GetName ( ) ;
if ( TempFunction - > HasAnyFunctionFlags ( FUNC_Delegate ) )
{
FunctionName = FunctionName . LeftChop ( FString ( HEADER_GENERATED_DELEGATE_SIGNATURE_SUFFIX ) . Len ( ) ) ;
}
StructureSize = FString : : Printf ( TEXT ( " , sizeof(%s) " ) , * GetEventStructParamsName ( TempFunction - > GetOuter ( ) , * FunctionName ) ) ;
}
FString UFunctionType = bIsDelegate ? TEXT ( " UDelegateFunction " ) : TEXT ( " UFunction " ) ;
2015-01-30 08:30:03 -05:00
CurrentFunctionText . Logf ( TEXT ( " ReturnFunction = new(EC_InternalUseOnlyConstructor, Outer, TEXT( \" %s \" ), RF_Public|RF_Transient|RF_Native) %s(FObjectInitializer(), %s, 0x%08X, %d%s); \r \n " ) ,
2015-01-20 09:33:54 -05:00
* Function - > GetName ( ) ,
* UFunctionType ,
* SuperFunctionString ,
Function - > FunctionFlags ,
( uint32 ) Function - > RepOffset ,
* StructureSize
) ;
TheFlagAudit . Add ( Function , TEXT ( " FunctionFlags " ) , Function - > FunctionFlags ) ;
FString OuterString = FString ( TEXT ( " ReturnFunction " ) ) ;
FString Meta = GetMetaDataCodeForObject ( Function , * OuterString , TEXT ( " " ) ) ;
for ( int32 Index = Props . Num ( ) - 1 ; Index > = 0 ; Index - - )
{
OutputProperty ( Meta , CurrentFunctionText , OuterString , Props [ Index ] , TEXT ( " " ) ) ;
}
if ( FunctionData . FunctionFlags & ( FUNC_NetRequest | FUNC_NetResponse ) )
{
CurrentFunctionText . Logf ( TEXT ( " ReturnFunction->RPCId=%d; \r \n " ) , FunctionData . RPCId ) ;
CurrentFunctionText . Logf ( TEXT ( " ReturnFunction->RPCResponseId=%d; \r \n " ) , FunctionData . RPCResponseId ) ;
}
CurrentFunctionText . Logf ( TEXT ( " ReturnFunction->Bind(); \r \n " ) ) ;
CurrentFunctionText . Logf ( TEXT ( " ReturnFunction->StaticLink(); \r \n " ) ) ;
if ( Meta . Len ( ) )
{
CurrentFunctionText . Logf ( TEXT ( " #if WITH_METADATA \r \n " ) ) ;
CurrentFunctionText . Logf ( TEXT ( " UMetaData* MetaData = ReturnFunction->GetOutermost()->GetMetaData(); \r \n " ) ) ;
CurrentFunctionText . Log ( * Meta ) ;
CurrentFunctionText . Logf ( TEXT ( " #endif \r \n " ) ) ;
}
CurrentFunctionText . Logf ( TEXT ( " } \r \n " ) ) ;
CurrentFunctionText . Logf ( TEXT ( " return ReturnFunction; \r \n " ) ) ;
CurrentFunctionText . Logf ( TEXT ( " } \r \n " ) ) ;
uint32 FunctionCrc = GenerateTextCRC ( * CurrentFunctionText ) ;
GGeneratedCodeCRCs . Add ( Function , FunctionCrc ) ;
GetGeneratedFunctionTextDevice ( ) + = CurrentFunctionText ;
}
2014-06-02 07:02:29 -04:00
void FNativeClassHeaderGenerator : : ExportNatives ( FClass * Class )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
// Skip no export classes.
if ( Class - > HasAnyClassFlags ( CLASS_NoExport ) )
{
2014-03-14 14:13:41 -04:00
return ;
2015-01-20 09:33:54 -05:00
}
2014-03-14 14:13:41 -04:00
2014-06-02 07:02:29 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " void %s::StaticRegisterNatives%s() \r \n " ) , NameLookupCPP . GetNameCPP ( Class ) , NameLookupCPP . GetNameCPP ( Class ) ) ;
2014-03-14 14:13:41 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " { \r \n " ) ) ;
{
TArray < UFunction * > FunctionsToExport ;
for ( auto * Function : TFieldRange < UFunction > ( Class , EFieldIteratorFlags : : ExcludeSuper ) )
{
if ( ( Function - > FunctionFlags & ( FUNC_Native | FUNC_NetRequest ) ) = = FUNC_Native )
{
FunctionsToExport . Add ( Function ) ;
}
}
FunctionsToExport . Sort ( ) ;
for ( auto Func : FunctionsToExport )
{
GeneratedPackageCPP . Logf ( TEXT ( " FNativeFunctionRegistrar::RegisterFunction(%s::StaticClass(), \" %s \" ,(Native)&%s::exec%s); \r \n " ) ,
2014-06-02 07:02:29 -04:00
NameLookupCPP . GetNameCPP ( Class ) ,
2014-03-14 14:13:41 -04:00
* Func - > GetName ( ) ,
2014-06-02 07:02:29 -04:00
Class - > HasAnyClassFlags ( CLASS_Interface ) ? * FString : : Printf ( TEXT ( " I%s " ) , * Class - > GetName ( ) ) : NameLookupCPP . GetNameCPP ( Class ) ,
2014-03-14 14:13:41 -04:00
* Func - > GetName ( )
) ;
}
}
for ( auto * Struct : TFieldRange < UScriptStruct > ( Class , EFieldIteratorFlags : : ExcludeSuper ) )
{
if ( Struct - > StructFlags & STRUCT_Native )
{
GeneratedPackageCPP . Logf ( TEXT ( " UScriptStruct::DeferCppStructOps(FName(TEXT( \" %s \" )),new UScriptStruct::TCppStructOps<%s%s>); \r \n " ) , * Struct - > GetName ( ) , Struct - > GetPrefixCPP ( ) , * Struct - > GetName ( ) ) ;
}
}
GeneratedPackageCPP . Logf ( TEXT ( " } \r \n " ) ) ;
}
2015-03-27 18:10:52 -04:00
void FNativeClassHeaderGenerator : : ExportInterfaceCallFunctions ( const TArray < UFunction * > & InCallbackFunctions , UClass * Class , FClassMetaData * ClassData , FUHTStringBuilder & HeaderOutput )
2014-03-14 14:13:41 -04:00
{
TArray < UFunction * > CallbackFunctions = InCallbackFunctions ;
CallbackFunctions . Sort ( ) ;
for ( auto FuncIt = CallbackFunctions . CreateConstIterator ( ) ; FuncIt ; + + FuncIt )
{
UFunction * Function = * FuncIt ;
FString FunctionName = Function - > GetName ( ) ;
2015-01-20 09:33:54 -05:00
FString ClassName = Class - > GetName ( ) ;
2014-03-14 14:13:41 -04:00
2015-01-20 09:33:54 -05:00
auto * CompilerInfo = FFunctionData : : FindForFunction ( Function ) ;
2014-03-14 14:13:41 -04:00
const FFuncInfo & FunctionData = CompilerInfo - > GetFunctionData ( ) ;
const TCHAR * ConstQualifier = FunctionData . FunctionReference - > HasAllFunctionFlags ( FUNC_Const ) ? TEXT ( " const " ) : TEXT ( " " ) ;
FString ExtraParam = FString : : Printf ( TEXT ( " %sUObject* O " ) , ConstQualifier ) ;
ExportNativeFunctionHeader ( FunctionData , HeaderOutput , EExportFunctionType : : Interface , EExportFunctionHeaderStyle : : Declaration , * ExtraParam ) ;
2015-03-27 18:10:52 -04:00
HeaderOutput . Logf ( TEXT ( " ; " ) LINE_TERMINATOR ) ;
2014-03-14 14:13:41 -04:00
ExportNativeFunctionHeader ( FunctionData , GeneratedPackageCPP , EExportFunctionType : : Interface , EExportFunctionHeaderStyle : : Definition , * ExtraParam ) ;
2015-03-27 18:10:52 -04:00
GeneratedPackageCPP . Logf ( LINE_TERMINATOR TEXT ( " \t { " ) LINE_TERMINATOR ) ;
2014-03-14 14:13:41 -04:00
2015-03-27 18:10:52 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " \t \t check(O != NULL); " ) LINE_TERMINATOR ) ;
GeneratedPackageCPP . Logf ( TEXT ( " \t \t check(O->GetClass()->ImplementsInterface(U%s::StaticClass())); " ) LINE_TERMINATOR , * ClassName ) ;
2014-03-14 14:13:41 -04:00
auto Parameters = GetFunctionParmsAndReturn ( FunctionData . FunctionReference ) ;
// See if we need to create Parms struct
2015-03-27 18:10:52 -04:00
const bool bHasParms = Parameters . HasParms ( ) ;
2014-03-14 14:13:41 -04:00
if ( bHasParms )
{
2015-01-20 09:33:54 -05:00
FString EventParmStructName = GetEventStructParamsName ( Function - > GetOuter ( ) , * FunctionName ) ;
2015-03-27 18:10:52 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " \t \t %s Parms; " ) LINE_TERMINATOR , * EventParmStructName ) ;
2014-03-14 14:13:41 -04:00
}
2015-03-27 18:10:52 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " \t \t UFunction* const Func = O->FindFunction(%s_%s); " ) LINE_TERMINATOR , * API , * FunctionName ) ;
GeneratedPackageCPP . Logf ( TEXT ( " \t \t if (Func) " ) LINE_TERMINATOR ) ;
GeneratedPackageCPP . Logf ( TEXT ( " \t \t { " ) LINE_TERMINATOR ) ;
2014-03-14 14:13:41 -04:00
// code to populate Parms struct
for ( auto It = Parameters . Parms . CreateConstIterator ( ) ; It ; + + It )
{
UProperty * Param = * It ;
2015-03-27 18:10:52 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " \t \t \t Parms.%s=%s; " ) LINE_TERMINATOR , * Param - > GetName ( ) , * Param - > GetName ( ) ) ;
2014-03-14 14:13:41 -04:00
}
[UE-2345] BP - enforce const-correctness in native const class method overrides
this change introduces enforcement of 'const-correctness' into implemented function graphs.
summary:
if you have a function declared in C++ like this:
UFUNCTION(BlueprintImplementableEvent)
int32 MyFunctionThatReturnsSomeValue() const;
if you implement that (BPIE) function in a Blueprint that's parented to that native class, it will now be flagged as 'const'. this makes any properties of 'self' read-only within the context of that graph, which means the compiler will emit an error if you try to set a property or otherwise call a non-const, non-static function with 'self' as the target.
if there happens to already be an implemented const function in a Blueprint that was in place prior to this change, the compiler will emit a warning instead of an error, in order to allow existing Blueprints that may currently be "violating" const within the context of a const BPIE function to still compile, while still alerting to issues that should probably be addressed.
notes:
1) this also applies to BlueprintNativeEvent (BPNE) implementations, and also when implementing BPIE/BPNE interface methods that are also declared as const
2) a const BPIE/BPNE function with no return value and no output parameters will be implemented as a "normal" impure function, and not as an event as in the non-const case
3) a const BPIE/BPNE function with a return value and/or output parameters will currently be implemented as a pure function, regardless of whether or not BlueprintCallable is specified
4) this CL also retains some consolidation of static function validation code that i had previously done, mostly to allow static functions to more easily be whitelisted for const function graphs
#codereview Nick.Whiting, Michael.Noland
[CL 2368059 by Phillip Kavan in Main branch]
2014-11-21 17:47:17 -05:00
const FString ObjectRef = FunctionData . FunctionReference - > HasAllFunctionFlags ( FUNC_Const ) ? FString : : Printf ( TEXT ( " const_cast<UObject*>(O) " ) , * ClassName ) : TEXT ( " O " ) ;
2015-03-27 18:10:52 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " \t \t \t %s->ProcessEvent(Func, %s); " ) LINE_TERMINATOR , * ObjectRef , bHasParms ? TEXT ( " &Parms " ) : TEXT ( " NULL " ) ) ;
2014-03-14 14:13:41 -04:00
for ( auto It = Parameters . Parms . CreateConstIterator ( ) ; It ; + + It )
{
UProperty * Param = * It ;
if ( Param - > HasAllPropertyFlags ( CPF_OutParm ) & & ! Param - > HasAnyPropertyFlags ( CPF_ConstParm | CPF_ReturnParm ) )
{
2015-03-27 18:10:52 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " \t \t \t %s=Parms.%s; " ) LINE_TERMINATOR , * Param - > GetName ( ) , * Param - > GetName ( ) ) ;
2014-03-14 14:13:41 -04:00
}
}
2015-03-27 18:10:52 -04:00
GeneratedPackageCPP + = TEXT ( " \t \t } " ) LINE_TERMINATOR ;
2014-03-14 14:13:41 -04:00
// else clause to call back into native if it's a BlueprintNativeEvent
if ( Function - > FunctionFlags & FUNC_Native )
{
2015-03-27 18:10:52 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " \t \t else if (auto I = (%sI%s*)(O->GetNativeInterfaceAddress(U%s::StaticClass()))) " ) LINE_TERMINATOR , ConstQualifier , * ClassName , * ClassName ) ;
GeneratedPackageCPP + = TEXT ( " \t \t { " ) LINE_TERMINATOR ;
2014-03-14 14:13:41 -04:00
2015-03-27 18:10:52 -04:00
GeneratedPackageCPP + = TEXT ( " \t \t \t " ) ;
2014-03-14 14:13:41 -04:00
if ( Parameters . Return )
{
2015-03-27 18:10:52 -04:00
GeneratedPackageCPP + = TEXT ( " Parms.ReturnValue = " ) ;
2014-03-14 14:13:41 -04:00
}
GeneratedPackageCPP . Logf ( TEXT ( " I->%s_Implementation( " ) , * FunctionName ) ;
bool First = true ;
for ( auto It = Parameters . Parms . CreateConstIterator ( ) ; It ; + + It )
{
UProperty * Param = * It ;
if ( ! First )
{
GeneratedPackageCPP . Logf ( TEXT ( " , " ) ) ;
}
First = false ;
GeneratedPackageCPP . Logf ( TEXT ( " %s " ) , * Param - > GetName ( ) ) ;
}
2015-03-27 18:10:52 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " ); " ) LINE_TERMINATOR ) ;
2014-03-14 14:13:41 -04:00
2015-03-27 18:10:52 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " \t \t } " ) LINE_TERMINATOR ) ;
2014-03-14 14:13:41 -04:00
}
if ( Parameters . Return )
{
2015-03-27 18:10:52 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " \t \t return Parms.ReturnValue; " ) LINE_TERMINATOR ) ;
2014-03-14 14:13:41 -04:00
}
2015-03-27 18:10:52 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " \t } " ) LINE_TERMINATOR ) ;
2014-03-14 14:13:41 -04:00
}
}
2014-10-10 04:34:56 -04:00
/**
* Gets preprocessor string to emit GENERATED_U * _BODY ( ) macro is deprecated .
*
* @ param MacroName Name of the macro to be deprecated .
*
* @ returns Preprocessor string to emit the message .
*/
FString GetGeneratedMacroDeprecationWarning ( const TCHAR * MacroName )
{
// Deprecation warning is disabled right now. After people get familiar with the new macro it should be re-enabled.
//return FString() + TEXT("EMIT_DEPRECATED_WARNING_MESSAGE(\"") + MacroName + TEXT("() macro is deprecated. Please use GENERATED_BODY() macro instead.\")") LINE_TERMINATOR;
return TEXT ( " " ) ;
}
2014-10-13 10:31:50 -04:00
/**
* Returns a string with access specifier that was met before parsing GENERATED_BODY ( ) macro to preserve it .
*
* @ param Class Class for which to return the access specifier .
*
* @ returns Access specifier string .
*/
FString GetPreservedAccessSpecifierString ( FClass * Class )
{
2014-11-07 13:17:32 -05:00
FString PreservedAccessSpecifier ( FString : : Printf ( TEXT ( " static_assert(false, \" Unknown access specifier for GENERATED_BODY() macro in class % s . \ " ) ; " ), *GetNameSafe(Class)));
FClassMetaData * Data = GScriptHelper . FindClassData ( Class ) ;
if ( Data )
2014-10-13 10:31:50 -04:00
{
2014-11-07 13:17:32 -05:00
switch ( Data - > GeneratedBodyMacroAccessSpecifier )
{
case EAccessSpecifier : : ACCESS_Private :
PreservedAccessSpecifier = " private: " ;
break ;
case EAccessSpecifier : : ACCESS_Protected :
PreservedAccessSpecifier = " protected: " ;
break ;
case EAccessSpecifier : : ACCESS_Public :
PreservedAccessSpecifier = " public: " ;
break ;
2015-04-02 16:31:18 -04:00
case EAccessSpecifier : : ACCESS_NotAnAccessSpecifier :
break ;
2014-11-07 13:17:32 -05:00
}
2014-10-13 10:31:50 -04:00
}
return PreservedAccessSpecifier + LINE_TERMINATOR ;
}
2014-03-14 14:13:41 -04:00
/**
2015-01-20 09:33:54 -05:00
* Exports interface body macros .
2014-03-14 14:13:41 -04:00
*/
2015-03-27 18:10:52 -04:00
void ExportInterfaceBodyMacros ( FUHTStringBuilder & Out , FUnrealSourceFile & SourceFile , int32 ClassGeneratedBodyLine , FClass * Class , const FString & StdCtorCall , const FString & EnhCtorCall , const FString & UInterfaceBoilerplate )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
Out . Log ( TEXT ( " #undef GENERATED_UINTERFACE_BODY_COMMON \r \n " ) ) ;
Out . Log ( Macroize ( TEXT ( " GENERATED_UINTERFACE_BODY_COMMON() " ) , * UInterfaceBoilerplate ) ) ;
2014-03-14 14:13:41 -04:00
2015-01-20 09:33:54 -05:00
auto DeprecationWarning = GetGeneratedMacroDeprecationWarning ( TEXT ( " GENERATED_UINTERFACE_BODY " ) ) ;
auto DeprecationPushString = TEXT ( " PRAGMA_DISABLE_DEPRECATION_WARNINGS " ) LINE_TERMINATOR ;
auto DeprecationPopString = TEXT ( " PRAGMA_POP " ) LINE_TERMINATOR ;
2015-03-27 18:10:52 -04:00
auto Offset = TEXT ( " \t " ) ;
2015-01-20 09:33:54 -05:00
Out . Log ( Macroize ( * SourceFile . GetGeneratedBodyMacroName ( ClassGeneratedBodyLine , true ) , * ( FString ( ) +
Offset + DeprecationWarning +
Offset + DeprecationPushString +
Offset + TEXT ( " GENERATED_UINTERFACE_BODY_COMMON() " ) LINE_TERMINATOR +
StdCtorCall +
Offset + DeprecationPopString ) ) ) ;
Out . Log ( Macroize ( * SourceFile . GetGeneratedBodyMacroName ( ClassGeneratedBodyLine ) , * ( FString ( ) +
Offset + DeprecationPushString +
Offset + TEXT ( " GENERATED_UINTERFACE_BODY_COMMON() " ) LINE_TERMINATOR +
EnhCtorCall +
GetPreservedAccessSpecifierString ( Class ) +
Offset + DeprecationPopString ) ) ) ;
}
void FNativeClassHeaderGenerator : : ExportSourceFileHeader ( FClasses & AllClasses , FUnrealSourceFile * SourceFile )
{
TSet < const FUnrealSourceFile * > VisitedSet ;
ExportSourceFileHeaderRecursive ( AllClasses , SourceFile , VisitedSet , false ) ;
}
2015-03-27 18:10:52 -04:00
void WriteMacro ( FUHTStringBuilder & Output , const FString & MacroName , const FString & MacroContent )
2015-01-20 09:33:54 -05:00
{
Output . Log ( * Macroize ( * MacroName , * MacroContent ) ) ;
}
2015-03-17 09:34:18 -04:00
/**
* Writes to output device auto - includes for the given source file .
*
* @ param Out Output device .
* @ param SourceFile Source file .
*/
void ExportAutoIncludes ( FStringOutputDevice & Out , const FUnrealSourceFile & SourceFile )
{
for ( const auto & Include : SourceFile . GetIncludes ( ) )
{
if ( ! Include . IsAutoInclude ( ) )
{
continue ;
}
const auto * AutoIncludedSourceFile = Include . GetResolved ( ) ;
if ( AutoIncludedSourceFile = = nullptr )
{
continue ;
}
Out . Logf (
TEXT ( " #ifndef %s " ) LINE_TERMINATOR
TEXT ( " #include \" %s \" " ) LINE_TERMINATOR
TEXT ( " #endif " ) LINE_TERMINATOR
LINE_TERMINATOR ,
* AutoIncludedSourceFile - > GetFileDefineName ( ) , * AutoIncludedSourceFile - > GetIncludePath ( ) ) ;
}
}
2015-01-20 09:33:54 -05:00
void FNativeClassHeaderGenerator : : ExportClassesFromSourceFileInner ( FUnrealSourceFile & SourceFile )
{
TArray < UEnum * > Enums ;
TArray < UScriptStruct * > Structs ;
TArray < UDelegateFunction * > DelegateFunctions ;
GeneratedHeaderText . Logf (
2015-03-17 09:34:18 -04:00
TEXT ( " #ifdef %s " ) LINE_TERMINATOR
2015-01-20 09:33:54 -05:00
TEXT ( " #error \" %s.generated.h already included, missing '#pragma once' in %s.h \" " ) LINE_TERMINATOR
TEXT ( " #endif " ) LINE_TERMINATOR
2015-03-17 09:34:18 -04:00
TEXT ( " #define %s " ) LINE_TERMINATOR
2015-01-20 09:33:54 -05:00
LINE_TERMINATOR ,
2015-03-17 09:34:18 -04:00
* SourceFile . GetFileDefineName ( ) , * SourceFile . GetStrippedFilename ( ) , * SourceFile . GetStrippedFilename ( ) , * SourceFile . GetFileDefineName ( ) ) ;
ExportAutoIncludes ( GeneratedHeaderText , SourceFile ) ;
2014-03-14 14:13:41 -04:00
// get the lists of fields that belong to this class that should be exported
2015-01-20 09:33:54 -05:00
SourceFile . GetScope ( ) - > SplitTypesIntoArrays ( Enums , Structs , DelegateFunctions ) ;
2014-03-14 14:13:41 -04:00
// export enum declarations
ExportEnums ( Enums ) ;
// export delegate definitions
2015-01-20 09:33:54 -05:00
ExportDelegateDefinitions ( SourceFile , DelegateFunctions , false ) ;
2014-03-14 14:13:41 -04:00
// Export enums declared in non-UClass headers.
ExportGeneratedEnumsInitCode ( Enums ) ;
2015-01-20 09:33:54 -05:00
// export boilerplate macros for structs
ExportGeneratedStructBodyMacros ( SourceFile , Structs ) ;
2014-03-14 14:13:41 -04:00
// export delegate wrapper function implementations
2015-01-20 09:33:54 -05:00
ExportDelegateDefinitions ( SourceFile , DelegateFunctions , true ) ;
2014-03-14 14:13:41 -04:00
2015-01-20 09:33:54 -05:00
for ( auto * RawUClass : SourceFile . GetDefinedClasses ( ) )
2014-03-14 14:13:41 -04:00
{
2015-03-27 18:10:52 -04:00
PrologMacroCalls . Reset ( ) ;
InClassMacroCalls . Reset ( ) ;
InClassNoPureDeclsMacroCalls . Reset ( ) ;
StandardUObjectConstructorsMacroCall . Reset ( ) ;
EnhancedUObjectConstructorsMacroCall . Reset ( ) ;
2014-03-14 14:13:41 -04:00
2015-01-20 09:33:54 -05:00
auto * Class = ( FClass * ) RawUClass ;
auto * ClassData = GScriptHelper . FindClassData ( Class ) ;
2014-03-14 14:13:41 -04:00
2015-01-20 09:33:54 -05:00
if ( Class - > ClassFlags & CLASS_Intrinsic )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
continue ;
2014-03-14 14:13:41 -04:00
}
2015-01-20 09:33:54 -05:00
// C++ -> VM stubs (native function execs)
ExportNativeFunctions ( SourceFile , Class , ClassData ) ;
2014-03-14 14:13:41 -04:00
2015-01-20 09:33:54 -05:00
// VM -> C++ proxies (events and delegates).
TArray < UFunction * > CallbackFunctions = ExportCallbackFunctions ( SourceFile , Class , ClassData ) ;
// Class definition.
ExportNatives ( Class ) ;
2015-03-27 18:10:52 -04:00
FUHTStringBuilder FriendText ;
2015-01-20 09:33:54 -05:00
ExportNativeGeneratedInitCode ( Class , FriendText ) ;
FClass * SuperClass = Class - > GetSuperClass ( ) ;
// the name for the C++ version of the UClass
const TCHAR * ClassCPPName = NameLookupCPP . GetNameCPP ( Class ) ;
const TCHAR * SuperClassCPPName = ( SuperClass ! = nullptr ) ? NameLookupCPP . GetNameCPP ( SuperClass ) : nullptr ;
if ( Class - > HasAnyClassFlags ( CLASS_Interface ) )
2014-03-14 14:13:41 -04:00
{
{
2015-03-27 18:10:52 -04:00
FUHTStringBuilder UInterfaceBoilerplate ;
2015-01-20 09:33:54 -05:00
// Export the class's native function registration.
UInterfaceBoilerplate . Logf ( TEXT ( " private: \r \n " ) ) ;
UInterfaceBoilerplate . Logf ( TEXT ( " static void StaticRegisterNatives%s(); \r \n " ) , NameLookupCPP . GetNameCPP ( Class ) ) ;
UInterfaceBoilerplate . Log ( * FriendText ) ;
2015-03-27 18:10:52 -04:00
FriendText . Reset ( ) ;
2015-01-20 09:33:54 -05:00
UInterfaceBoilerplate . Logf ( TEXT ( " public: \r \n " ) ) ;
// Build the DECLARE_CLASS line
FString APIArg ( API ) ;
if ( ! Class - > HasAnyClassFlags ( CLASS_MinimalAPI ) )
{
APIArg = TEXT ( " NO " ) ;
}
const bool bCastedClass = Class - > HasAnyCastFlag ( CASTCLASS_AllFlags ) & & SuperClass & & Class - > ClassCastFlags ! = SuperClass - > ClassCastFlags ;
UInterfaceBoilerplate . Logf ( TEXT ( " DECLARE_CLASS(%s, %s, COMPILED_IN_FLAGS(CLASS_Abstract%s), %s, %s, %s_API) \r \n " ) ,
ClassCPPName ,
SuperClassCPPName ,
* GetClassFlagExportText ( Class ) ,
bCastedClass ? * FString : : Printf ( TEXT ( " CASTCLASS_%s " ) , ClassCPPName ) : TEXT ( " 0 " ) ,
* FPackageName : : GetShortName ( Class - > GetOuter ( ) - > GetName ( ) ) ,
* APIArg ) ;
UInterfaceBoilerplate . Logf ( TEXT ( " DECLARE_SERIALIZER(%s) \r \n " ) , ClassCPPName ) ;
UInterfaceBoilerplate . Log ( TEXT ( " enum {IsIntrinsic=COMPILED_IN_INTRINSIC}; \r \n " ) ) ;
if ( Class - > ClassWithin ! = Class - > GetSuperClass ( ) - > ClassWithin )
{
UInterfaceBoilerplate . Logf ( TEXT ( " DECLARE_WITHIN(%s) \r \n " ) , NameLookupCPP . GetNameCPP ( Class - > GetClassWithin ( ) ) ) ;
}
ExportConstructorsMacros ( SourceFile . GetGeneratedMacroName ( ClassData ) , Class ) ;
ExportInterfaceBodyMacros ( GeneratedHeaderText , SourceFile , ClassData - > GetGeneratedBodyLine ( ) , Class , StandardUObjectConstructorsMacroCall , EnhancedUObjectConstructorsMacroCall , UInterfaceBoilerplate ) ;
2014-03-14 14:13:41 -04:00
}
2015-01-20 09:33:54 -05:00
// =============================================
// Export the pure interface version of the class
// the name of the pure interface class
FString InterfaceCPPName = FString : : Printf ( TEXT ( " I%s " ) , * Class - > GetName ( ) ) ;
FString SuperInterfaceCPPName ;
if ( SuperClass ! = NULL )
{
SuperInterfaceCPPName = FString : : Printf ( TEXT ( " I%s " ) , * SuperClass - > GetName ( ) ) ;
}
// Thunk functions
2015-03-27 18:10:52 -04:00
FUHTStringBuilder InterfaceBoilerplate ;
2015-01-20 09:33:54 -05:00
InterfaceBoilerplate . Logf ( TEXT ( " protected: \r \n \t virtual ~%s() {} \r \n public: \r \n " ) , * InterfaceCPPName ) ;
InterfaceBoilerplate . Logf ( TEXT ( " \t typedef %s UClassType; \r \n " ) , ClassCPPName ) ;
ExportInterfaceCallFunctions ( CallbackFunctions , Class , ClassData , InterfaceBoilerplate ) ;
// we'll need a way to get to the UObject portion of a native interface, so that we can safely pass native interfaces
// to script VM functions
if ( SuperClass - > IsChildOf ( UInterface : : StaticClass ( ) ) )
{
InterfaceBoilerplate . Logf ( TEXT ( " \t virtual UObject* _getUObject() const = 0; \r \n " ) ) ;
}
// Replication, add in the declaration for GetLifetimeReplicatedProps() automatically if there are any net flagged properties
bool bNeedsRep = false ;
auto ClassName = FString ( NameLookupCPP . GetNameCPP ( Class ) ) ;
for ( TFieldIterator < UProperty > It ( Class , EFieldIteratorFlags : : ExcludeSuper ) ; It ; + + It )
{
if ( ( It - > PropertyFlags & CPF_Net ) ! = 0 )
{
bNeedsRep = true ;
break ;
}
}
auto ClassRange = ClassDefinitionRange ( ) ;
if ( ClassDefinitionRanges . Contains ( Class ) )
{
ClassRange = ClassDefinitionRanges [ Class ] ;
}
auto ClassStart = ClassRange . Start ;
auto ClassEnd = ClassRange . End ;
auto ClassDefinition = FString ( ClassEnd - ClassStart , ClassStart ) ;
2015-04-10 06:02:22 -04:00
bool bHasGetLifetimeReplicatedProps = HasIdentifierExactMatch ( ClassDefinition , TEXT ( " GetLifetimeReplicatedProps " ) ) ;
2015-01-20 09:33:54 -05:00
if ( bNeedsRep & & ! bHasGetLifetimeReplicatedProps )
{
2015-04-10 06:02:22 -04:00
if ( SourceFile . GetGeneratedCodeVersionForStruct ( Class ) = = EGeneratedCodeVersion : : V1 )
{
InterfaceBoilerplate . Logf ( TEXT ( " \v oid GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const; \r \n " ) ) ;
}
else
{
FError : : Throwf ( TEXT ( " Class %s has Net flagged properties and should declare member function: void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override " ) , ClassCPPName ) ;
}
2015-01-20 09:33:54 -05:00
}
auto NoPureDeclsMacroName = SourceFile . GetGeneratedMacroName ( ClassData , TEXT ( " _INCLASS_IINTERFACE_NO_PURE_DECLS " ) ) ;
WriteMacro ( GeneratedHeaderText , NoPureDeclsMacroName , InterfaceBoilerplate ) ;
2015-03-27 18:10:52 -04:00
InClassNoPureDeclsMacroCalls . Logf ( TEXT ( " \t %s \r \n " ) , * NoPureDeclsMacroName ) ;
2015-01-20 09:33:54 -05:00
auto MacroName = SourceFile . GetGeneratedMacroName ( ClassData , TEXT ( " _INCLASS_IINTERFACE " ) ) ;
2015-04-10 06:02:22 -04:00
WriteMacro ( GeneratedHeaderText , MacroName , InterfaceBoilerplate ) ;
2015-03-27 18:10:52 -04:00
InClassMacroCalls . Logf ( TEXT ( " \t %s \r \n " ) , * MacroName ) ;
2014-03-14 14:13:41 -04:00
}
2015-01-20 09:33:54 -05:00
else
2014-12-11 11:49:41 -05:00
{
2015-04-22 14:15:56 -04:00
FUHTStringBuilder ClassBoilerplate ;
2014-03-14 14:13:41 -04:00
2015-04-22 14:15:56 -04:00
// Export the class's native function registration.
ClassBoilerplate . Logf ( TEXT ( " private: \r \n " ) ) ;
ClassBoilerplate . Logf ( TEXT ( " static void StaticRegisterNatives%s(); \r \n " ) , NameLookupCPP . GetNameCPP ( Class ) ) ;
ClassBoilerplate . Log ( * FriendText ) ;
ClassBoilerplate . Logf ( TEXT ( " public: \r \n " ) ) ;
2014-03-14 14:13:41 -04:00
2015-04-22 14:15:56 -04:00
// Build the DECLARE_CLASS line
FString APIArg ( API ) ;
if ( ! Class - > HasAnyClassFlags ( CLASS_MinimalAPI ) )
2014-03-14 14:13:41 -04:00
{
2015-04-22 14:15:56 -04:00
APIArg = TEXT ( " NO " ) ;
}
const bool bCastedClass = Class - > HasAnyCastFlag ( CASTCLASS_AllFlags ) & & SuperClass & & Class - > ClassCastFlags ! = SuperClass - > ClassCastFlags ;
ClassBoilerplate . Logf ( TEXT ( " DECLARE_CLASS(%s, %s, COMPILED_IN_FLAGS(%s%s), %s, %s, %s_API) \r \n " ) ,
ClassCPPName ,
SuperClassCPPName ? SuperClassCPPName : TEXT ( " None " ) ,
Class - > HasAnyClassFlags ( CLASS_Abstract ) ? TEXT ( " CLASS_Abstract " ) : TEXT ( " 0 " ) ,
* GetClassFlagExportText ( Class ) ,
bCastedClass ? * FString : : Printf ( TEXT ( " CASTCLASS_%s " ) , ClassCPPName ) : TEXT ( " 0 " ) ,
* FPackageName : : GetShortName ( * Class - > GetOuter ( ) - > GetName ( ) ) ,
* APIArg ) ;
2014-03-14 14:13:41 -04:00
2015-04-22 14:15:56 -04:00
ClassBoilerplate . Logf ( TEXT ( " DECLARE_SERIALIZER(%s) \r \n " ) , ClassCPPName ) ;
ClassBoilerplate . Log ( TEXT ( " /** Indicates whether the class is compiled into the engine */ " ) ) ;
ClassBoilerplate . Log ( TEXT ( " enum {IsIntrinsic=COMPILED_IN_INTRINSIC}; \r \n " ) ) ;
2014-03-14 14:13:41 -04:00
2015-04-22 14:15:56 -04:00
if ( SuperClass & & Class - > ClassWithin ! = SuperClass - > ClassWithin )
{
ClassBoilerplate . Logf ( TEXT ( " DECLARE_WITHIN(%s) \r \n " ) , NameLookupCPP . GetNameCPP ( Class - > GetClassWithin ( ) ) ) ;
}
// export the class's config name
if ( SuperClass & & Class - > ClassConfigName ! = NAME_None & & Class - > ClassConfigName ! = SuperClass - > ClassConfigName )
{
ClassBoilerplate . Logf ( TEXT ( " static const TCHAR* StaticConfigName() {return TEXT( \" %s \" );} \r \n \r \n " ) , * Class - > ClassConfigName . ToString ( ) ) ;
}
// @todo srobb: clean up _getUObject() code generation
if ( ( ( SuperClass = = UClass : : StaticClass ( ) ) | | ( SuperClass = = UObject : : StaticClass ( ) ) | | ( SuperClass & & ( SuperClass - > ClassFlags & CLASS_Intrinsic ) ) ) & & ! Class - > IsChildOf ( UInterface : : StaticClass ( ) ) )
{
ClassBoilerplate . Logf ( TEXT ( " \t virtual UObject* _getUObject() const { return const_cast<%s*>(this); } \r \n " ) , ClassCPPName ) ;
}
else
{
ClassBoilerplate . Logf ( TEXT ( " \t virtual UObject* _getUObject() const override { return const_cast<%s*>(this); } \r \n " ) , ClassCPPName ) ;
}
// Replication, add in the declaration for GetLifetimeReplicatedProps() automatically if there are any net flagged properties
bool bHasNetFlaggedProperties = false ;
for ( TFieldIterator < UProperty > It ( Class , EFieldIteratorFlags : : ExcludeSuper ) ; It ; + + It )
{
if ( ( It - > PropertyFlags & CPF_Net ) ! = 0 )
2014-03-14 14:13:41 -04:00
{
2015-04-22 14:15:56 -04:00
bHasNetFlaggedProperties = true ;
break ;
2014-03-14 14:13:41 -04:00
}
2015-04-22 14:15:56 -04:00
}
2014-10-10 04:34:56 -04:00
2015-04-22 14:15:56 -04:00
auto ClassRange = ClassDefinitionRange ( ) ;
if ( ClassDefinitionRanges . Contains ( Class ) )
{
ClassRange = ClassDefinitionRanges [ Class ] ;
}
2014-03-14 14:13:41 -04:00
2015-04-22 14:15:56 -04:00
auto ClassStart = ClassRange . Start ;
auto ClassEnd = ClassRange . End ;
auto ClassDefinition = FString ( ClassEnd - ClassStart , ClassStart ) ;
bool bHasGetLifetimeReplicatedProps = HasIdentifierExactMatch ( ClassDefinition , TEXT ( " GetLifetimeReplicatedProps " ) ) ;
if ( bHasNetFlaggedProperties & & ! bHasGetLifetimeReplicatedProps )
{
// Default version autogenerates declarations.
if ( SourceFile . GetGeneratedCodeVersionForStruct ( Class ) = = EGeneratedCodeVersion : : V1 )
2014-03-14 14:13:41 -04:00
{
2015-04-22 14:15:56 -04:00
ClassBoilerplate . Logf ( TEXT ( " \t void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override; \r \n " ) ) ;
2015-03-26 18:31:15 -04:00
}
else
{
2015-04-22 14:15:56 -04:00
FError : : Throwf ( TEXT ( " Class %s has Net flagged properties and should declare member function: void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override " ) , ClassCPPName ) ;
2015-03-26 18:31:15 -04:00
}
2014-03-14 14:13:41 -04:00
}
2015-04-22 14:15:56 -04:00
auto NoPureDeclsMacroName = SourceFile . GetGeneratedMacroName ( ClassData , TEXT ( " _INCLASS_NO_PURE_DECLS " ) ) ;
WriteMacro ( GeneratedHeaderText , NoPureDeclsMacroName , ClassBoilerplate ) ;
InClassNoPureDeclsMacroCalls . Logf ( TEXT ( " \t %s \r \n " ) , * NoPureDeclsMacroName ) ;
FString MacroName = SourceFile . GetGeneratedMacroName ( ClassData , TEXT ( " _INCLASS " ) ) ;
WriteMacro ( GeneratedHeaderText , MacroName , ClassBoilerplate ) ;
InClassMacroCalls . Logf ( TEXT ( " \t %s \r \n " ) , * MacroName ) ;
ExportConstructorsMacros ( SourceFile . GetGeneratedMacroName ( ClassData ) , Class ) ;
2014-03-14 14:13:41 -04:00
}
2015-01-20 09:33:54 -05:00
{
FString MacroName = SourceFile . GetGeneratedMacroName ( ClassData - > GetPrologLine ( ) , TEXT ( " _PROLOG " ) ) ;
WriteMacro ( GeneratedHeaderText , MacroName , PrologMacroCalls ) ;
}
{
bool bIsIInterface = Class - > HasAnyClassFlags ( CLASS_Interface ) ;
2015-03-17 05:19:11 -04:00
auto MacroName = FString : : Printf ( TEXT ( " GENERATED_%s_BODY() " ) , bIsIInterface ? TEXT ( " IINTERFACE " ) : TEXT ( " UCLASS " ) ) ;
2015-01-20 09:33:54 -05:00
auto DeprecationWarning = bIsIInterface ? FString ( TEXT ( " " ) ) : GetGeneratedMacroDeprecationWarning ( * MacroName ) ;
auto DeprecationPushString = TEXT ( " PRAGMA_DISABLE_DEPRECATION_WARNINGS " ) LINE_TERMINATOR ;
auto DeprecationPopString = TEXT ( " PRAGMA_POP " ) LINE_TERMINATOR ;
auto Public = TEXT ( " public: " LINE_TERMINATOR ) ;
2015-03-17 05:19:11 -04:00
auto GeneratedBodyLine = bIsIInterface ? ClassData - > GetInterfaceGeneratedBodyLine ( ) : ClassData - > GetGeneratedBodyLine ( ) ;
auto LegacyGeneratedBody = InClassMacroCalls + ( bIsIInterface ? TEXT ( " " ) : StandardUObjectConstructorsMacroCall ) ;
auto GeneratedBody = InClassNoPureDeclsMacroCalls + ( bIsIInterface ? TEXT ( " " ) : EnhancedUObjectConstructorsMacroCall ) ;
2015-01-20 09:33:54 -05:00
2015-03-17 05:19:11 -04:00
auto WrappedLegacyGeneratedBody = DeprecationWarning + DeprecationPushString + Public + LegacyGeneratedBody + Public + DeprecationPopString ;
auto WrappedGeneratedBody = FString ( DeprecationPushString ) + Public + GeneratedBody + GetPreservedAccessSpecifierString ( Class ) + DeprecationPopString ;
2015-01-20 09:33:54 -05:00
2015-03-17 05:19:11 -04:00
auto BodyMacros = Macroize ( * SourceFile . GetGeneratedBodyMacroName ( GeneratedBodyLine , true ) , * WrappedLegacyGeneratedBody ) +
Macroize ( * SourceFile . GetGeneratedBodyMacroName ( GeneratedBodyLine , false ) , * WrappedGeneratedBody ) ;
2015-01-20 09:33:54 -05:00
GeneratedHeaderText . Log ( * BodyMacros ) ;
}
2014-03-14 14:13:41 -04:00
}
2015-01-20 09:33:54 -05:00
if ( GPublicSourceFileSet . Contains ( & SourceFile ) & & ! ListOfPublicHeaderGroupIncludes . Contains ( & SourceFile ) )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
ListOfPublicHeaderGroupIncludes . Add ( & SourceFile ) ;
2014-03-14 14:13:41 -04:00
}
}
2014-10-31 04:01:12 -04:00
/**
* Generates private copy - constructor declaration .
*
* @ param Out Output device to generate to .
* @ param Class Class to generate constructor for .
* @ param API API string for this constructor .
*/
2015-03-27 18:10:52 -04:00
void ExportCopyConstructorDefinition ( FUHTStringBuilder & Out , FClass * Class , const FString & API )
2014-10-31 04:01:12 -04:00
{
auto ClassNameCPP = NameLookupCPP . GetNameCPP ( Class ) ;
Out . Logf ( TEXT ( " private: \r \n " ) ) ;
2015-03-27 18:10:52 -04:00
Out . Logf ( TEXT ( " \t /** Private copy-constructor, should never be used */ \r \n " ) ) ;
Out . Logf ( TEXT ( " \t %s_API %s(const %s& InCopy); \r \n " ) , * API , ClassNameCPP , ClassNameCPP ) ;
2014-10-31 04:01:12 -04:00
Out . Logf ( TEXT ( " public: \r \n " ) ) ;
}
2015-03-02 06:44:04 -05:00
# if WITH_HOT_RELOAD_CTORS
/**
* Generates vtable helper constructor declaration .
*
* @ param Out Output device to generate to .
* @ param Class Class to generate constructor for .
* @ param API API string for this constructor .
*/
void ExportVTableHelperConstructorDecl ( FStringOutputDevice & Out , FClass * Class , const FString & API )
{
auto * ClassData = GScriptHelper . FindClassData ( Class ) ;
if ( ! ClassData - > bCustomVTableHelperConstructorDeclared )
{
Out . Logf ( TEXT ( " %sDECLARE_VTABLE_PTR_HELPER_CTOR(%s_API, %s); " LINE_TERMINATOR ) , FCString : : Spc ( 4 ) , * API , NameLookupCPP . GetNameCPP ( Class ) ) ;
}
}
/**
* Generates vtable helper ctor caller .
*
* @ param Out Output device to generate to .
* @ param Class Class to generate for .
*/
void ExportVTableHelperCtorCaller ( FStringOutputDevice & Out , FClass * Class )
{
Out . Logf ( TEXT ( " DEFINE_VTABLE_PTR_HELPER_CTOR_CALLER(%s); " LINE_TERMINATOR ) , NameLookupCPP . GetNameCPP ( Class ) ) ;
}
/**
* Generates vtable helper ctor caller dummy .
*
* @ param Out Output device to generate to .
*/
void ExportVTableHelperCtorCallerDummy ( FStringOutputDevice & Out )
{
Out . Logf ( TEXT ( " DEFINE_VTABLE_PTR_HELPER_CTOR_CALLER_DUMMY(); " LINE_TERMINATOR ) ) ;
}
/**
* Generates vtable helper constructor body .
*
* @ param Out Output device to generate to .
* @ param Class Class to generate constructor for .
* @ param API API string for this constructor .
*/
void ExportVTableHelperConstructorBody ( FStringOutputDevice & Out , FClass * Class )
{
auto * ClassData = GScriptHelper . FindClassData ( Class ) ;
if ( ! ClassData - > bCustomVTableHelperConstructorDeclared )
{
Out . Logf ( TEXT ( " %sDEFINE_VTABLE_PTR_HELPER_CTOR(%s); " LINE_TERMINATOR ) , FCString : : Spc ( 4 ) , NameLookupCPP . GetNameCPP ( Class ) ) ;
}
}
/**
* Generates vtable helper caller and eventual constructor body .
*
* @ param Out Output device to generate to .
* @ param Class Class to generate for .
* @ param API API string .
* @ param bExportVTableConstructors Tells if we are going to export constructors as well .
*/
void ExportVTableHelperCtorAndCaller ( FStringOutputDevice & Out , FClass * Class , const FString & API , bool bExportVTableConstructors )
{
if ( bExportVTableConstructors )
{
ExportVTableHelperConstructorDecl ( Out , Class , API ) ;
ExportVTableHelperCtorCaller ( Out , Class ) ;
}
else
{
ExportVTableHelperCtorCallerDummy ( Out ) ;
}
}
# endif // WITH_HOT_RELOAD_CTORS
2014-10-10 04:34:56 -04:00
/**
* Generates standard constructor declaration .
*
* @ param Out Output device to generate to .
* @ param Class Class to generate constructor for .
* @ param API API string for this constructor .
2015-03-02 06:44:04 -05:00
* @ param bExportVTableConstructors Export VTable constructors .
2014-10-10 04:34:56 -04:00
*/
2015-03-27 18:10:52 -04:00
void ExportStandardConstructorsMacro ( FUHTStringBuilder & Out , FClass * Class , const FString & API
2015-03-02 06:44:04 -05:00
# if WITH_HOT_RELOAD_CTORS
, bool bExportVTableConstructors
# endif // WITH_HOT_RELOAD_CTORS
)
2014-10-10 04:34:56 -04:00
{
if ( ! Class - > HasAnyClassFlags ( CLASS_CustomConstructor ) )
{
2015-03-27 18:10:52 -04:00
Out . Logf ( TEXT ( " \t /** Standard constructor, called after all reflected properties have been initialized */ \r \n " ) ) ;
2015-04-21 04:37:32 -04:00
auto * ClassData = GScriptHelper . FindClassData ( Class ) ;
Out . Logf ( TEXT ( " \t %s_API %s(const FObjectInitializer& ObjectInitializer%s); \r \n " ) , * API , NameLookupCPP . GetNameCPP ( Class ) ,
ClassData - > bDefaultConstructorDeclared ? TEXT ( " " ) : TEXT ( " = FObjectInitializer::Get() " ) ) ;
2014-10-10 04:34:56 -04:00
}
2015-03-27 18:10:52 -04:00
Out . Logf ( TEXT ( " \t DEFINE_DEFAULT_OBJECT_INITIALIZER_CONSTRUCTOR_CALL(%s) \r \n " ) , NameLookupCPP . GetNameCPP ( Class ) ) ;
2015-03-02 06:44:04 -05:00
# if WITH_HOT_RELOAD_CTORS
ExportVTableHelperCtorAndCaller ( Out , Class , API , bExportVTableConstructors ) ;
# endif // WITH_HOT_RELOAD_CTORS
2014-10-31 04:01:12 -04:00
ExportCopyConstructorDefinition ( Out , Class , API ) ;
2014-10-10 04:34:56 -04:00
}
/**
* Generates constructor definition .
*
* @ param Out Output device to generate to .
* @ param Class Class to generate constructor for .
* @ param API API string for this constructor .
*/
2015-03-27 18:10:52 -04:00
void ExportConstructorDefinition ( FUHTStringBuilder & Out , FClass * Class , const FString & API )
2014-10-10 04:34:56 -04:00
{
auto * ClassData = GScriptHelper . FindClassData ( Class ) ;
if ( ! ClassData - > bConstructorDeclared )
{
2015-03-27 18:10:52 -04:00
Out . Logf ( TEXT ( " \t /** Standard constructor, called after all reflected properties have been initialized */ \r \n " ) ) ;
2015-02-14 17:40:09 -05:00
// Assume super class has OI constructor, this may not always be true but we should always be able to check this.
// In any case, it will default to old behaviour before we even checked this.
bool bSuperClassObjectInitializerConstructorDeclared = true ;
auto * SuperClass = Class - > GetSuperClass ( ) ;
if ( SuperClass ! = nullptr )
{
auto * SuperClassData = GScriptHelper . FindClassData ( SuperClass ) ;
if ( SuperClassData )
{
bSuperClassObjectInitializerConstructorDeclared = SuperClassData - > bObjectInitializerConstructorDeclared ;
}
}
if ( bSuperClassObjectInitializerConstructorDeclared )
{
2015-04-21 04:37:32 -04:00
Out . Logf ( TEXT ( " \t %s_API %s(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get()) : Super(ObjectInitializer) { }; \r \n " ) , * API , NameLookupCPP . GetNameCPP ( Class ) ) ;
2015-02-14 17:40:09 -05:00
ClassData - > bObjectInitializerConstructorDeclared = true ;
}
else
{
2015-03-27 18:10:52 -04:00
Out . Logf ( TEXT ( " \t %s_API %s() { }; \r \n " ) , * API , NameLookupCPP . GetNameCPP ( Class ) ) ;
2015-02-14 17:40:09 -05:00
ClassData - > bDefaultConstructorDeclared = true ;
}
2014-10-10 04:34:56 -04:00
ClassData - > bConstructorDeclared = true ;
}
2014-10-31 04:01:12 -04:00
ExportCopyConstructorDefinition ( Out , Class , API ) ;
2014-10-10 04:34:56 -04:00
}
/**
* Generates constructor call definition .
*
* @ param Out Output device to generate to .
* @ param Class Class to generate constructor call definition for .
*/
2015-03-27 18:10:52 -04:00
void ExportDefaultConstructorCallDefinition ( FUHTStringBuilder & Out , FClass * Class )
2014-10-10 04:34:56 -04:00
{
auto * ClassData = GScriptHelper . FindClassData ( Class ) ;
2014-10-14 10:29:11 -04:00
if ( ClassData - > bObjectInitializerConstructorDeclared )
2014-10-10 04:34:56 -04:00
{
2015-03-27 18:10:52 -04:00
Out . Logf ( TEXT ( " \t DEFINE_DEFAULT_OBJECT_INITIALIZER_CONSTRUCTOR_CALL(%s) \r \n " ) , NameLookupCPP . GetNameCPP ( Class ) ) ;
2014-10-10 04:34:56 -04:00
}
else if ( ClassData - > bDefaultConstructorDeclared )
{
2015-03-27 18:10:52 -04:00
Out . Logf ( TEXT ( " \t DEFINE_DEFAULT_CONSTRUCTOR_CALL(%s) \r \n " ) , NameLookupCPP . GetNameCPP ( Class ) ) ;
2014-10-10 04:34:56 -04:00
}
else
{
2015-03-27 18:10:52 -04:00
Out . Logf ( TEXT ( " \t DEFINE_FORBIDDEN_DEFAULT_CONSTRUCTOR_CALL(%s) \r \n " ) , NameLookupCPP . GetNameCPP ( Class ) ) ;
2014-10-10 04:34:56 -04:00
}
}
/**
* Generates enhanced constructor declaration .
*
* @ param Out Output device to generate to .
* @ param Class Class to generate constructor for .
* @ param API API string for this constructor .
2015-03-02 06:44:04 -05:00
* @ param bExportVTableConstructors Export VTable constructors .
2014-10-10 04:34:56 -04:00
*/
2015-03-27 18:10:52 -04:00
void ExportEnhancedConstructorsMacro ( FUHTStringBuilder & Out , FClass * Class , const FString & API
2015-03-02 06:44:04 -05:00
# if WITH_HOT_RELOAD_CTORS
, bool bExportVTableConstructors
# endif // WITH_HOT_RELOAD_CTORS
)
2014-10-10 04:34:56 -04:00
{
ExportConstructorDefinition ( Out , Class , API ) ;
2015-03-02 06:44:04 -05:00
# if WITH_HOT_RELOAD_CTORS
ExportVTableHelperCtorAndCaller ( Out , Class , API , bExportVTableConstructors ) ;
# endif // WITH_HOT_RELOAD_CTORS
2014-10-10 04:34:56 -04:00
ExportDefaultConstructorCallDefinition ( Out , Class ) ;
}
2015-01-21 12:32:28 -05:00
/**
* Gets a package relative inclusion path of the given source file for build .
*
* @ param SourceFile Given source file .
*
* @ returns Inclusion path .
*/
FString GetBuildPath ( FUnrealSourceFile & SourceFile )
{
FString Out = SourceFile . GetFilename ( ) ;
ConvertToBuildIncludePath ( SourceFile . GetPackage ( ) , Out ) ;
return Out ;
}
2015-04-22 14:15:56 -04:00
FString FNativeClassHeaderGenerator : : GetListOfPublicHeaderGroupIncludesString ( UPackage * InPackage )
2015-01-20 09:33:54 -05:00
{
2015-03-27 18:10:52 -04:00
FUHTStringBuilder Out ;
2015-01-20 09:33:54 -05:00
// Fill with the rest source files from this package.
for ( auto * SourceFile : GPublicSourceFileSet )
{
2015-04-22 14:15:56 -04:00
if ( SourceFile - > GetPackage ( ) = = InPackage & & ! ListOfPublicHeaderGroupIncludes . Contains ( SourceFile ) )
2015-01-20 09:33:54 -05:00
{
ListOfPublicHeaderGroupIncludes . Add ( SourceFile ) ;
}
}
for ( auto * SourceFile : ListOfPublicHeaderGroupIncludes )
{
2015-01-21 12:32:28 -05:00
Out . Logf ( TEXT ( " #include \" %s \" " ) LINE_TERMINATOR , * GetBuildPath ( * SourceFile ) ) ;
2015-01-20 09:33:54 -05:00
}
Out . Log ( LINE_TERMINATOR ) ;
return Out ;
}
void FNativeClassHeaderGenerator : : ExportConstructorsMacros ( const FString & ConstructorsMacroPrefix , FClass * Class )
2014-10-10 04:34:56 -04:00
{
FString APIArg ( API ) ;
if ( ! Class - > HasAnyClassFlags ( CLASS_MinimalAPI ) )
{
APIArg = TEXT ( " NO " ) ;
}
2015-03-27 18:10:52 -04:00
FUHTStringBuilder StdMacro ;
FUHTStringBuilder EnhMacro ;
2015-01-20 09:33:54 -05:00
FString StdMacroName = ConstructorsMacroPrefix + TEXT ( " _STANDARD_CONSTRUCTORS " ) ;
FString EnhMacroName = ConstructorsMacroPrefix + TEXT ( " _ENHANCED_CONSTRUCTORS " ) ;
2014-10-10 04:34:56 -04:00
2015-03-02 06:44:04 -05:00
# if WITH_HOT_RELOAD_CTORS
ExportStandardConstructorsMacro ( StdMacro , Class , APIArg , bExportVTableConstructors ) ;
ExportEnhancedConstructorsMacro ( EnhMacro , Class , APIArg , bExportVTableConstructors ) ;
if ( bExportVTableConstructors )
{
ExportVTableHelperConstructorBody ( GetGeneratedFunctionTextDevice ( ) , Class ) ;
}
# else // WITH_HOT_RELOAD_CTORS
2014-10-10 04:34:56 -04:00
ExportStandardConstructorsMacro ( StdMacro , Class , APIArg ) ;
ExportEnhancedConstructorsMacro ( EnhMacro , Class , APIArg ) ;
2015-03-02 06:44:04 -05:00
# endif // WITH_HOT_RELOAD_CTORS
2014-10-10 04:34:56 -04:00
GeneratedHeaderText . Log ( * Macroize ( * StdMacroName , * StdMacro ) ) ;
GeneratedHeaderText . Log ( * Macroize ( * EnhMacroName , * EnhMacro ) ) ;
2015-03-27 18:10:52 -04:00
StandardUObjectConstructorsMacroCall . Logf ( TEXT ( " \t %s \r \n " ) , * StdMacroName ) ;
EnhancedUObjectConstructorsMacroCall . Logf ( TEXT ( " \t %s \r \n " ) , * EnhMacroName ) ;
2014-10-10 04:34:56 -04:00
}
2015-01-20 09:33:54 -05:00
void FNativeClassHeaderGenerator : : ExportClassesFromSourceFileWrapper ( FUnrealSourceFile & SourceFile )
2014-03-14 14:13:41 -04:00
{
check ( ! GeneratedHeaderText . Len ( ) ) ;
2015-01-20 09:33:54 -05:00
ExportClassesFromSourceFileInner ( SourceFile ) ;
2014-03-14 14:13:41 -04:00
if ( ! GeneratedHeaderText . Len ( ) & & ! EnumForeachText . Len ( ) )
{
// Nothing to export
return ;
}
2015-01-20 09:33:54 -05:00
GeneratedHeaderText . Logf ( TEXT ( " #undef CURRENT_FILE_ID \r \n " ) ) ;
GeneratedHeaderText . Logf ( TEXT ( " #define CURRENT_FILE_ID %s \r \n \r \n \r \n " ) , * SourceFile . GetFileId ( ) ) ;
2014-03-14 14:13:41 -04:00
2015-01-20 09:33:54 -05:00
const FString SourceFilename = SourceFile . GetFilename ( ) ;
const FString PkgName = FPackageName : : GetShortName ( Package ) ;
2014-03-14 14:13:41 -04:00
FString NewFileName = SourceFilename . EndsWith ( TEXT ( " .h " ) ) ? SourceFilename : ( SourceFilename + TEXT ( " .h " ) ) ;
FString PkgDir ;
FString GeneratedIncludeDirectory ;
2014-09-18 04:05:01 -04:00
if ( FindPackageLocation ( * PkgName , PkgDir , GeneratedIncludeDirectory ) = = false )
2014-03-14 14:13:41 -04:00
{
UE_LOG ( LogCompile , Error , TEXT ( " Failed to find path for package %s " ) , * PkgName ) ;
}
2015-01-20 09:33:54 -05:00
const FString ClassHeaderPath ( GeneratedIncludeDirectory / FPaths : : GetBaseFilename ( SourceFile . GetFilename ( ) ) + TEXT ( " .generated.h " ) ) ;
GeneratedHeaderText + = EnumForeachText ;
2015-03-27 18:10:52 -04:00
FUHTStringBuilder GeneratedHeaderTextWithCopyright ;
2015-01-20 09:33:54 -05:00
GeneratedHeaderTextWithCopyright . Log (
TEXT ( " // Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. \r \n " )
TEXT ( " /*=========================================================================== \r \n " )
TEXT ( " C++ class header boilerplate exported from UnrealHeaderTool. \r \n " )
TEXT ( " This is automatically generated by the tools. \r \n " )
TEXT ( " DO NOT modify this manually! Edit the corresponding .h files instead! \r \n " )
TEXT ( " ===========================================================================*/ \r \n " ) ) ;
GeneratedHeaderTextWithCopyright . Log (
LINE_TERMINATOR
TEXT ( " #include \" ObjectBase.h \" " ) LINE_TERMINATOR
LINE_TERMINATOR ) ;
2015-03-10 08:24:59 -04:00
GeneratedHeaderTextWithCopyright . Logf ( TEXT ( " PRAGMA_DISABLE_DEPRECATION_WARNINGS " ) LINE_TERMINATOR ) ;
2015-01-20 09:33:54 -05:00
GeneratedHeaderTextWithCopyright . Log ( * GeneratedHeaderTextBeforeForwardDeclarations ) ;
TSet < FString > ForwardDeclarationStrings ;
for ( auto Property : ForwardDeclarations )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
auto FWDecl = Property - > GetCPPTypeForwardDeclaration ( ) ;
if ( FWDecl . Len ( ) > 0 )
2014-12-11 11:49:41 -05:00
{
2015-01-20 09:33:54 -05:00
ForwardDeclarationStrings . Add ( FWDecl ) ;
2014-03-14 14:13:41 -04:00
}
}
2015-01-20 09:33:54 -05:00
for ( auto FWDeclString : ForwardDeclarationStrings )
{
GeneratedForwardDeclarations . Logf ( TEXT ( " %s \r \n " ) , * FWDeclString ) ;
}
GeneratedHeaderTextWithCopyright . Log ( * GeneratedForwardDeclarations ) ;
GeneratedHeaderTextWithCopyright . Log ( * GeneratedHeaderText ) ;
2015-03-10 08:24:59 -04:00
GeneratedHeaderTextWithCopyright . Logf ( TEXT ( " PRAGMA_ENABLE_DEPRECATION_WARNINGS " ) LINE_TERMINATOR ) ;
2015-01-20 09:33:54 -05:00
SourceFile . SetGeneratedFilename ( ClassHeaderPath ) ;
SourceFile . SetHasChanged ( SaveHeaderIfChanged ( * ClassHeaderPath , * GeneratedHeaderTextWithCopyright ) ) ;
check ( SourceFilename . EndsWith ( TEXT ( " .h " ) ) ) ;
ConvertToBuildIncludePath ( Package , NewFileName ) ;
auto IncludeStr = FString : : Printf (
2015-03-17 09:34:18 -04:00
TEXT ( " #ifndef %s " ) LINE_TERMINATOR
TEXT ( " #include \" %s \" " ) LINE_TERMINATOR
TEXT ( " #endif " ) LINE_TERMINATOR ,
* SourceFile . GetFileDefineName ( ) , * NewFileName ) ;
2015-01-20 09:33:54 -05:00
// Keep track of all of the UObject headers for this module, in the same order that we digest them in
// @todo uht: We're wrapping these includes in checks for header guards, ONLY because most existing UObject headers are missing '#pragma once'
ListOfAllUObjectHeaderIncludes . Logf ( TEXT ( " %s " ) , * IncludeStr ) ;
ListOfPublicClassesUObjectHeaderModuleIncludes . Logf ( TEXT ( " %s " ) , * IncludeStr ) ;
2015-03-27 18:10:52 -04:00
ForwardDeclarations . Reset ( ) ;
GeneratedHeaderTextBeforeForwardDeclarations . Reset ( ) ;
GeneratedForwardDeclarations . Reset ( ) ;
GeneratedHeaderText . Reset ( ) ;
EnumForeachText . Reset ( ) ;
2014-03-14 14:13:41 -04:00
}
2015-01-20 09:33:54 -05:00
void FNativeClassHeaderGenerator : : ExportSourceFileHeaderRecursive ( FClasses & AllClasses , FUnrealSourceFile * SourceFile , TSet < const FUnrealSourceFile * > & VisitedSet , bool bCheckDependenciesOnly )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
bool bIsCorrectHeader = SourceFile - > GetPackage ( ) = = Package ;
2014-03-14 14:13:41 -04:00
// Check for circular header dependencies between export classes.
2015-01-20 09:33:54 -05:00
if ( ! bIsCorrectHeader )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
if ( VisitedSet . Num ( ) = = 0 )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
// The first export class we found doesn't belong in this header: No need to keep exporting along this dependency path.
return ;
2014-03-14 14:13:41 -04:00
}
2015-01-20 09:33:54 -05:00
// From now on, we're not going to export anything. Instead, we're going to check that no deeper dependency tries to export to this header file.
bCheckDependenciesOnly = true ;
2014-03-14 14:13:41 -04:00
}
// Check if the Class has already been exported, after we've checked for circular header dependencies.
2015-01-20 09:33:54 -05:00
if ( GExportedSourceFiles . Contains ( SourceFile ) )
2014-03-14 14:13:41 -04:00
{
return ;
}
// Check for circular dependencies.
2015-01-20 09:33:54 -05:00
if ( VisitedSet . Contains ( SourceFile ) )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
UE_LOG ( LogCompile , Error , TEXT ( " Circular dependency detected for filename %s! " ) , * SourceFile - > GetFilename ( ) ) ;
2014-03-14 14:13:41 -04:00
return ;
}
2014-04-23 20:18:55 -04:00
2014-03-14 14:13:41 -04:00
// Temporarily mark the Class as VISITED. Make sure to clear this flag before returning!
2015-01-20 09:33:54 -05:00
VisitedSet . Add ( SourceFile ) ;
2014-03-14 14:13:41 -04:00
2015-01-20 09:33:54 -05:00
TArray < FUnrealSourceFile * > DependOnList ;
for ( auto & Include : SourceFile - > GetIncludes ( ) )
2014-03-14 14:13:41 -04:00
{
2015-04-22 14:15:56 -04:00
auto * OtherSourceFile = Include . Resolve ( ) ;
if ( OtherSourceFile & & ! DependOnList . Contains ( OtherSourceFile ) )
2014-03-14 14:13:41 -04:00
{
2015-04-22 14:15:56 -04:00
DependOnList . Add ( OtherSourceFile ) ;
2014-03-14 14:13:41 -04:00
}
2015-01-20 09:33:54 -05:00
}
2014-03-14 14:13:41 -04:00
2015-01-20 09:33:54 -05:00
for ( auto * DependOn : DependOnList )
{
ExportSourceFileHeaderRecursive ( AllClasses , DependOn , VisitedSet , bCheckDependenciesOnly ) ;
2014-03-14 14:13:41 -04:00
}
// Export class header.
2015-01-20 09:33:54 -05:00
if ( bIsCorrectHeader & & ! bCheckDependenciesOnly )
2014-03-14 14:13:41 -04:00
{
// Mark class as exported.
2015-01-20 09:33:54 -05:00
GExportedSourceFiles . Add ( SourceFile ) ;
2014-03-14 14:13:41 -04:00
2015-01-20 09:33:54 -05:00
ExportClassesFromSourceFileWrapper ( * SourceFile ) ;
2014-03-14 14:13:41 -04:00
}
// We're done visiting this Class.
2015-01-20 09:33:54 -05:00
VisitedSet . Remove ( SourceFile ) ;
2014-03-14 14:13:41 -04:00
}
/**
* Returns a string in the format CLASS_Something | CLASS_Something which represents all class flags that are set for the specified
* class which need to be exported as part of the DECLARE_CLASS macro
*/
FString FNativeClassHeaderGenerator : : GetClassFlagExportText ( UClass * Class )
{
FString StaticClassFlagText ;
check ( Class ) ;
if ( Class - > HasAnyClassFlags ( CLASS_Transient ) )
{
StaticClassFlagText + = TEXT ( " | CLASS_Transient " ) ;
}
if ( Class - > HasAnyClassFlags ( CLASS_DefaultConfig ) )
{
StaticClassFlagText + = TEXT ( " | CLASS_DefaultConfig " ) ;
}
- Generate AndroidManifest.xml from ProjectSettings
- Moved some Android settings to ProjectSettings, re-enabled SDK settings
- Removed SigningConfig.xml, and moved those settings into project settings
- Added concept of NotForLicensees and NoRedist engine and project config settings
- Removed BaseInternalGame.ini, replaced with NotForLicensees/BaseGame.ini
- Moved User*.ini to end of .ini hierarchy
- Added support for CLASS_GlobalUserConfig, so their settings will be saved to <AppData>/.../User*.ini (useful for SDK paths, etc)
- Enabled AndroidPlatformEditor module on Mac
- Changed Mac Build.sh to allow for Android on the commandline (just pass through if it's not an Xcode platform name)
- Iterative Android packaging now looks at just the important .ini sections, NOT entire .ini files
#codereview jamie.dale,james.moran,michael.trepka,robert.jones,chris.babcock
[CL 2413870 by Josh Adams in Main branch]
2015-01-21 11:17:55 -05:00
if ( Class - > HasAnyClassFlags ( CLASS_GlobalUserConfig ) )
{
StaticClassFlagText + = TEXT ( " | CLASS_GlobalUserConfig " ) ;
}
2014-03-14 14:13:41 -04:00
if ( Class - > HasAnyClassFlags ( CLASS_Config ) )
{
StaticClassFlagText + = TEXT ( " | CLASS_Config " ) ;
}
if ( Class - > HasAnyClassFlags ( CLASS_Interface ) )
{
StaticClassFlagText + = TEXT ( " | CLASS_Interface " ) ;
}
if ( Class - > HasAnyClassFlags ( CLASS_Deprecated ) )
{
StaticClassFlagText + = TEXT ( " | CLASS_Deprecated " ) ;
}
return StaticClassFlagText ;
}
/**
* Exports the header text for the list of enums specified
*
* @ param Enums the enums to export
*/
void FNativeClassHeaderGenerator : : ExportEnums ( const TArray < UEnum * > & Enums )
{
// Enum definitions.
for ( int32 EnumIdx = Enums . Num ( ) - 1 ; EnumIdx > = 0 ; EnumIdx - - )
{
UEnum * Enum = Enums [ EnumIdx ] ;
// Export FOREACH macro
EnumForeachText . Logf ( TEXT ( " #define FOREACH_ENUM_%s(op) " ) , * Enum - > GetName ( ) . ToUpper ( ) ) ;
for ( int32 i = 0 ; i < Enum - > NumEnums ( ) - 1 ; i + + )
{
const FString QualifiedEnumValue = Enum - > GetEnum ( i ) . ToString ( ) ;
EnumForeachText . Logf ( TEXT ( " \\ \r \n op(%s) " ) , * QualifiedEnumValue ) ;
}
EnumForeachText . Logf ( TEXT ( " \r \n " ) ) ;
}
}
2015-03-17 05:19:11 -04:00
// Exports the header text for the list of structs specified (GENERATED_BODY impls)
2015-01-20 09:33:54 -05:00
void FNativeClassHeaderGenerator : : ExportGeneratedStructBodyMacros ( FUnrealSourceFile & SourceFile , const TArray < UScriptStruct * > & NativeStructs )
2014-03-14 14:13:41 -04:00
{
// reverse the order.
for ( int32 i = NativeStructs . Num ( ) - 1 ; i > = 0 ; - - i )
{
UScriptStruct * Struct = NativeStructs [ i ] ;
// Export struct.
if ( Struct - > StructFlags & STRUCT_Native )
{
check ( Struct - > StructMacroDeclaredLineNumber ! = INDEX_NONE ) ;
2015-01-20 09:33:54 -05:00
const FString FriendApiString = GetAPIString ( ) ;
2014-03-14 14:13:41 -04:00
const FString StaticConstructionString = GetSingletonName ( Struct ) ;
FString RequiredAPI ;
if ( ! ( Struct - > StructFlags & STRUCT_RequiredAPI ) )
{
RequiredAPI = FriendApiString ;
}
const FString FriendLine = FString : : Printf ( TEXT ( " friend %sclass UScriptStruct* %s; \r \n " ) , * FriendApiString , * StaticConstructionString ) ;
const FString StaticClassLine = FString : : Printf ( TEXT ( " %sstatic class UScriptStruct* StaticStruct(); \r \n " ) , * RequiredAPI ) ;
const FString CombinedLine = FriendLine + StaticClassLine ;
2015-01-20 09:33:54 -05:00
const FString MacroName = SourceFile . GetGeneratedBodyMacroName ( Struct - > StructMacroDeclaredLineNumber ) ;
2014-03-14 14:13:41 -04:00
const FString Macroized = Macroize ( * MacroName , * CombinedLine ) ;
GeneratedHeaderText . Log ( * Macroized ) ;
2014-07-29 02:43:48 -04:00
const TCHAR * StructNameCPP = NameLookupCPP . GetNameCPP ( Struct ) ;
2015-03-27 18:10:52 -04:00
FString SingletonName = StaticConstructionString . Replace ( TEXT ( " () " ) , TEXT ( " " ) , ESearchCase : : CaseSensitive ) ; // function address
2014-07-29 02:43:48 -04:00
FString GetCRCName = FString : : Printf ( TEXT ( " Get_%s_CRC " ) , * SingletonName ) ;
2014-03-14 14:13:41 -04:00
2014-07-29 02:43:48 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " class UScriptStruct* %s::StaticStruct() \r \n " ) , StructNameCPP ) ;
2014-03-14 14:13:41 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " { \r \n " ) ) ;
GeneratedPackageCPP . Logf ( TEXT ( " static class UScriptStruct* Singleton = NULL; \r \n " ) ) ;
GeneratedPackageCPP . Logf ( TEXT ( " if (!Singleton) \r \n " ) ) ;
GeneratedPackageCPP . Logf ( TEXT ( " { \r \n " ) ) ;
GeneratedPackageCPP . Logf ( TEXT ( " extern %sclass UScriptStruct* %s; \r \n " ) , * FriendApiString , * StaticConstructionString ) ;
2014-07-29 02:43:48 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " extern %suint32 %s(); \r \n " ) , * FriendApiString , * GetCRCName ) ;
2015-01-20 09:33:54 -05:00
2014-03-14 14:13:41 -04:00
// UStructs can have UClass or UPackage outer (if declared in non-UClass headers).
if ( Struct - > GetOuter ( ) - > IsA ( UStruct : : StaticClass ( ) ) )
{
2015-01-20 09:33:54 -05:00
GeneratedPackageCPP . Logf ( TEXT ( " Singleton = GetStaticStruct(%s, %s::StaticClass(), TEXT( \" %s \" ), sizeof(%s), %s()); \r \n " ) ,
2014-07-29 02:43:48 -04:00
* SingletonName , NameLookupCPP . GetNameCPP ( CastChecked < UStruct > ( Struct - > GetOuter ( ) ) ) , * Struct - > GetName ( ) , StructNameCPP , * GetCRCName ) ;
2014-03-14 14:13:41 -04:00
}
else
{
FString PackageSingletonName = GetPackageSingletonName ( CastChecked < UPackage > ( Struct - > GetOuter ( ) ) ) ;
GeneratedPackageCPP . Logf ( TEXT ( " extern %sclass UPackage* %s; \r \n " ) , * FriendApiString , * PackageSingletonName ) ;
2015-01-20 09:33:54 -05:00
GeneratedPackageCPP . Logf ( TEXT ( " Singleton = GetStaticStruct(%s, %s, TEXT( \" %s \" ), sizeof(%s), %s()); \r \n " ) ,
2014-07-29 02:43:48 -04:00
* SingletonName , * PackageSingletonName , * Struct - > GetName ( ) , StructNameCPP , * GetCRCName ) ;
2014-03-14 14:13:41 -04:00
}
2015-01-20 09:33:54 -05:00
2014-03-14 14:13:41 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " } \r \n " ) ) ;
GeneratedPackageCPP . Logf ( TEXT ( " return Singleton; \r \n " ) ) ;
GeneratedPackageCPP . Logf ( TEXT ( " } \r \n " ) ) ;
2015-01-20 09:33:54 -05:00
GeneratedPackageCPP . Logf ( TEXT ( " static FCompiledInDeferStruct Z_CompiledInDeferStruct_UScriptStruct_%s(%s::StaticStruct, TEXT( \" %s \" )); \r \n " ) ,
2014-09-23 05:12:53 -04:00
StructNameCPP , StructNameCPP , * Struct - > GetOutermost ( ) - > GetName ( ) ) ;
2014-03-14 14:13:41 -04:00
// Generate StaticRegisterNatives equivalent for structs without classes.
if ( ! Struct - > GetOuter ( ) - > IsA ( UStruct : : StaticClass ( ) ) )
{
const FString ShortPackageName = FPackageName : : GetShortName ( Struct - > GetOuter ( ) - > GetName ( ) ) ;
2014-07-29 02:43:48 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " static struct FScriptStruct_%s_StaticRegisterNatives%s \r \n " ) , * ShortPackageName , StructNameCPP ) ;
2014-03-14 14:13:41 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " { \r \n " ) ) ;
2014-07-29 02:43:48 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " \t FScriptStruct_%s_StaticRegisterNatives%s() \r \n " ) , * ShortPackageName , StructNameCPP ) ;
2014-03-14 14:13:41 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " \t { \r \n " ) ) ;
2015-01-20 09:33:54 -05:00
GeneratedPackageCPP . Logf ( TEXT ( " \t \t UScriptStruct::DeferCppStructOps(FName(TEXT( \" %s \" )),new UScriptStruct::TCppStructOps<%s%s>); \r \n " ) , * Struct - > GetName ( ) , Struct - > GetPrefixCPP ( ) , * Struct - > GetName ( ) ) ;
2014-03-14 14:13:41 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " \t } \r \n " ) ) ;
2014-07-29 02:43:48 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " } ScriptStruct_%s_StaticRegisterNatives%s; \r \n " ) , * ShortPackageName , StructNameCPP ) ;
2014-03-14 14:13:41 -04:00
}
}
2015-01-20 09:33:54 -05:00
{
UScriptStruct * ScriptStruct = Struct ;
UStruct * BaseStruct = ScriptStruct - > GetSuperStruct ( ) ;
const FString SingletonName ( GetSingletonName ( ScriptStruct ) ) ;
FString ApiString = GetAPIString ( ) ;
FString Extern = FString : : Printf ( TEXT ( " %sclass UScriptStruct* %s; \r \n " ) , * ApiString , * SingletonName ) ;
SingletonNameToExternDecl . Add ( SingletonName , Extern ) ;
GeneratedFunctionDeclarations . Log ( * Extern ) ;
2015-03-27 18:10:52 -04:00
FUHTStringBuilder GeneratedStructRegisterFunctionText ;
2015-01-20 09:33:54 -05:00
GeneratedStructRegisterFunctionText . Logf ( TEXT ( " UScriptStruct* %s \r \n " ) , * SingletonName ) ;
GeneratedStructRegisterFunctionText . Logf ( TEXT ( " { \r \n " ) ) ;
// if this is a no export struct, we will put a local struct here for offset determination
TArray < UScriptStruct * > Structs ;
FindNoExportStructs ( Structs , ScriptStruct ) ;
if ( Structs . Num ( ) )
{
TGuardValue < bool > Guard ( bIsExportingForOffsetDeterminationOnly , true ) ;
2015-03-27 18:10:52 -04:00
ExportMirrorsForNoexportStructs ( Structs , /*Indent=*/ 2 , GeneratedStructRegisterFunctionText ) ;
2015-01-20 09:33:54 -05:00
}
// Structs can either have a UClass or UPackage as outer (if delcared in non-UClass header).
if ( ScriptStruct - > GetOuter ( ) - > IsA ( UStruct : : StaticClass ( ) ) )
{
GeneratedStructRegisterFunctionText . Logf ( TEXT ( " UStruct* Outer=%s; \r \n " ) , * GetSingletonName ( CastChecked < UStruct > ( ScriptStruct - > GetOuter ( ) ) ) ) ;
}
else
{
GeneratedStructRegisterFunctionText . Logf ( TEXT ( " UPackage* Outer=%s; \r \n " ) , * GetPackageSingletonName ( CastChecked < UPackage > ( ScriptStruct - > GetOuter ( ) ) ) ) ;
}
GeneratedStructRegisterFunctionText . Logf ( TEXT ( " static UScriptStruct* ReturnStruct = NULL; \r \n " ) ) ;
GeneratedStructRegisterFunctionText . Logf ( TEXT ( " if (!ReturnStruct) \r \n " ) ) ;
GeneratedStructRegisterFunctionText . Logf ( TEXT ( " { \r \n " ) ) ;
FString BaseStructString ( TEXT ( " NULL " ) ) ;
if ( BaseStruct )
{
CastChecked < UScriptStruct > ( BaseStruct ) ; // this better actually be a script struct
BaseStructString = GetSingletonName ( BaseStruct ) ;
}
FString CppStructOpsString ( TEXT ( " NULL " ) ) ;
FString ExplicitSizeString ;
FString ExplicitAlignmentString ;
if ( ( ScriptStruct - > StructFlags & STRUCT_Native ) ! = 0 )
{
//@todo .u we don't need the auto register versions of these (except for hotreload, which should be fixed)
CppStructOpsString = FString : : Printf ( TEXT ( " new UScriptStruct::TCppStructOps<%s> " ) , NameLookupCPP . GetNameCPP ( ScriptStruct ) ) ;
}
else
{
ExplicitSizeString = FString : : Printf ( TEXT ( " , sizeof(%s), ALIGNOF(%s) " ) , NameLookupCPP . GetNameCPP ( ScriptStruct ) , NameLookupCPP . GetNameCPP ( ScriptStruct ) ) ;
}
2015-01-30 08:30:03 -05:00
GeneratedStructRegisterFunctionText . Logf ( TEXT ( " ReturnStruct = new(EC_InternalUseOnlyConstructor, Outer, TEXT( \" %s \" ), RF_Public|RF_Transient|RF_Native) UScriptStruct(FObjectInitializer(), %s, %s, EStructFlags(0x%08X)%s); \r \n " ) ,
2015-01-20 09:33:54 -05:00
* ScriptStruct - > GetName ( ) ,
* BaseStructString ,
* CppStructOpsString ,
( uint32 ) ( ScriptStruct - > StructFlags & ~ STRUCT_ComputedFlags ) ,
* ExplicitSizeString
) ;
TheFlagAudit . Add ( ScriptStruct , TEXT ( " StructFlags " ) , ( uint64 ) ( ScriptStruct - > StructFlags & ~ STRUCT_ComputedFlags ) ) ;
TArray < UProperty * > Props ;
for ( TFieldIterator < UProperty > ItInner ( ScriptStruct , EFieldIteratorFlags : : ExcludeSuper ) ; ItInner ; + + ItInner )
{
Props . Add ( * ItInner ) ;
}
FString OuterString = FString ( TEXT ( " ReturnStruct " ) ) ;
FString Meta = GetMetaDataCodeForObject ( ScriptStruct , * OuterString , TEXT ( " " ) ) ;
OutputProperties ( Meta , GeneratedStructRegisterFunctionText , OuterString , Props , TEXT ( " " ) ) ;
GeneratedStructRegisterFunctionText . Logf ( TEXT ( " ReturnStruct->StaticLink(); \r \n " ) ) ;
if ( Meta . Len ( ) )
{
GeneratedStructRegisterFunctionText . Logf ( TEXT ( " #if WITH_METADATA \r \n " ) ) ;
GeneratedStructRegisterFunctionText . Logf ( TEXT ( " UMetaData* MetaData = ReturnStruct->GetOutermost()->GetMetaData(); \r \n " ) ) ;
GeneratedStructRegisterFunctionText . Log ( * Meta ) ;
GeneratedStructRegisterFunctionText . Logf ( TEXT ( " #endif \r \n " ) ) ;
}
GeneratedStructRegisterFunctionText . Logf ( TEXT ( " } \r \n " ) ) ;
GeneratedStructRegisterFunctionText . Logf ( TEXT ( " return ReturnStruct; \r \n " ) ) ;
GeneratedStructRegisterFunctionText . Logf ( TEXT ( " } \r \n " ) ) ;
uint32 StructCrc = GenerateTextCRC ( * GeneratedStructRegisterFunctionText ) ;
GGeneratedCodeCRCs . Add ( ScriptStruct , StructCrc ) ;
auto & GeneratedFunctionText = GetGeneratedFunctionTextDevice ( ) ;
GeneratedFunctionText + = GeneratedStructRegisterFunctionText ;
2015-03-27 18:10:52 -04:00
GeneratedFunctionText . Logf ( TEXT ( " uint32 Get_%s_CRC() { return %uU; } \r \n " ) , * SingletonName . Replace ( TEXT ( " () " ) , TEXT ( " " ) , ESearchCase : : CaseSensitive ) , StructCrc ) ;
2015-01-20 09:33:54 -05:00
//CallSingletons.Logf(TEXT(" OuterClass->LinkChild(%s); // %u\r\n"), *SingletonName, StructCrc);
}
2014-03-14 14:13:41 -04:00
}
}
void FNativeClassHeaderGenerator : : ExportGeneratedEnumsInitCode ( const TArray < UEnum * > & Enums )
{
// reverse the order.
for ( int32 i = Enums . Num ( ) - 1 ; i > = 0 ; - - i )
{
UEnum * Enum = Enums [ i ] ;
// Export Enum.
2015-01-20 09:33:54 -05:00
if ( ! Enum - > GetOuter ( ) - > IsA ( UPackage : : StaticClass ( ) ) )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
continue ;
}
2014-03-14 14:13:41 -04:00
2015-01-20 09:33:54 -05:00
const FString FriendApiString = GetAPIString ( ) ;
const FString StaticConstructionString = GetSingletonName ( Enum ) ;
2014-03-14 14:13:41 -04:00
2015-03-27 18:10:52 -04:00
FString SingletonName = StaticConstructionString . Replace ( TEXT ( " () " ) , TEXT ( " " ) , ESearchCase : : CaseSensitive ) ; // function address
2014-03-14 14:13:41 -04:00
2015-01-20 09:33:54 -05:00
GeneratedPackageCPP . Logf ( TEXT ( " static class UEnum* %s_StaticEnum() \r \n " ) , * Enum - > GetName ( ) ) ;
GeneratedPackageCPP . Logf ( TEXT ( " { \r \n " ) ) ;
GeneratedPackageCPP . Logf ( TEXT ( " static class UEnum* Singleton = NULL; \r \n " ) ) ;
GeneratedPackageCPP . Logf ( TEXT ( " if (!Singleton) \r \n " ) ) ;
GeneratedPackageCPP . Logf ( TEXT ( " { \r \n " ) ) ;
GeneratedPackageCPP . Logf ( TEXT ( " extern %sclass UEnum* %s; \r \n " ) , * FriendApiString , * StaticConstructionString ) ;
FString PackageSingletonName = GetPackageSingletonName ( CastChecked < UPackage > ( Enum - > GetOuter ( ) ) ) ;
GeneratedPackageCPP . Logf ( TEXT ( " extern %sclass UPackage* %s; \r \n " ) , * FriendApiString , * PackageSingletonName ) ;
GeneratedPackageCPP . Logf ( TEXT ( " Singleton = GetStaticEnum(%s, %s, TEXT( \" %s \" )); \r \n " ) , * SingletonName , * PackageSingletonName , * Enum - > GetName ( ) ) ;
2014-03-14 14:13:41 -04:00
2015-01-20 09:33:54 -05:00
GeneratedPackageCPP . Logf ( TEXT ( " } \r \n " ) ) ;
GeneratedPackageCPP . Logf ( TEXT ( " return Singleton; \r \n " ) ) ;
GeneratedPackageCPP . Logf ( TEXT ( " } \r \n " ) ) ;
GeneratedPackageCPP . Logf ( TEXT ( " static FCompiledInDeferEnum Z_CompiledInDeferEnum_UEnum_%s(%s_StaticEnum, TEXT( \" %s \" )); \r \n " ) , * Enum - > GetName ( ) , * Enum - > GetName ( ) , * Enum - > GetOutermost ( ) - > GetName ( ) ) ;
{
2015-04-22 14:15:56 -04:00
const FString EnumSingletonName = GetSingletonName ( Enum ) ;
2015-01-20 09:33:54 -05:00
2015-04-22 14:15:56 -04:00
FString Extern = FString : : Printf ( TEXT ( " %s_API class UEnum* %s; \r \n " ) , * API , * EnumSingletonName ) ;
SingletonNameToExternDecl . Add ( EnumSingletonName , Extern ) ;
2015-01-20 09:33:54 -05:00
GeneratedFunctionDeclarations . Log ( * Extern ) ;
2015-03-27 18:10:52 -04:00
FUHTStringBuilder GeneratedEnumRegisterFunctionText ;
2015-01-20 09:33:54 -05:00
2015-04-22 14:15:56 -04:00
GeneratedEnumRegisterFunctionText . Logf ( TEXT ( " UEnum* %s \r \n " ) , * EnumSingletonName ) ;
2015-01-20 09:33:54 -05:00
GeneratedEnumRegisterFunctionText . Logf ( TEXT ( " { \r \n " ) ) ;
// Enums can either have a UClass or UPackage as outer (if declared in non-UClass header).
if ( Enum - > GetOuter ( ) - > IsA ( UStruct : : StaticClass ( ) ) )
{
GeneratedEnumRegisterFunctionText . Logf ( TEXT ( " UClass* Outer=%s; \r \n " ) , * GetSingletonName ( CastChecked < UStruct > ( Enum - > GetOuter ( ) ) ) ) ;
}
else
{
GeneratedEnumRegisterFunctionText . Logf ( TEXT ( " UPackage* Outer=%s; \r \n " ) , * GetPackageSingletonName ( CastChecked < UPackage > ( Enum - > GetOuter ( ) ) ) ) ;
}
GeneratedEnumRegisterFunctionText . Logf ( TEXT ( " static UEnum* ReturnEnum = NULL; \r \n " ) ) ;
GeneratedEnumRegisterFunctionText . Logf ( TEXT ( " if (!ReturnEnum) \r \n " ) ) ;
GeneratedEnumRegisterFunctionText . Logf ( TEXT ( " { \r \n " ) ) ;
2015-01-30 08:30:03 -05:00
GeneratedEnumRegisterFunctionText . Logf ( TEXT ( " ReturnEnum = new(EC_InternalUseOnlyConstructor, Outer, TEXT( \" %s \" ), RF_Public|RF_Transient|RF_Native) UEnum(FObjectInitializer()); \r \n " ) , * Enum - > GetName ( ) ) ;
2015-01-20 09:33:54 -05:00
GeneratedEnumRegisterFunctionText . Logf ( TEXT ( " TArray<FName> EnumNames; \r \n " ) ) ;
for ( int32 Index = 0 ; Index < Enum - > NumEnums ( ) ; Index + + )
{
GeneratedEnumRegisterFunctionText . Logf ( TEXT ( " EnumNames.Add(FName(TEXT( \" %s \" ))); \r \n " ) , * Enum - > GetEnum ( Index ) . ToString ( ) ) ;
}
FString EnumTypeStr ;
switch ( Enum - > GetCppForm ( ) )
{
case UEnum : : ECppForm : : Regular : EnumTypeStr = TEXT ( " UEnum::ECppForm::Regular " ) ; break ;
case UEnum : : ECppForm : : Namespaced : EnumTypeStr = TEXT ( " UEnum::ECppForm::Namespaced " ) ; break ;
case UEnum : : ECppForm : : EnumClass : EnumTypeStr = TEXT ( " UEnum::ECppForm::EnumClass " ) ; break ;
}
GeneratedEnumRegisterFunctionText . Logf ( TEXT ( " ReturnEnum->SetEnums(EnumNames, %s); \r \n " ) , * EnumTypeStr ) ;
FString Meta = GetMetaDataCodeForObject ( Enum , TEXT ( " ReturnEnum " ) , TEXT ( " " ) ) ;
if ( Meta . Len ( ) )
{
GeneratedEnumRegisterFunctionText . Logf ( TEXT ( " #if WITH_METADATA \r \n " ) ) ;
GeneratedEnumRegisterFunctionText . Logf ( TEXT ( " UMetaData* MetaData = ReturnEnum->GetOutermost()->GetMetaData(); \r \n " ) ) ;
GeneratedEnumRegisterFunctionText . Log ( * Meta ) ;
GeneratedEnumRegisterFunctionText . Logf ( TEXT ( " #endif \r \n " ) ) ;
}
GeneratedEnumRegisterFunctionText . Logf ( TEXT ( " } \r \n " ) ) ;
GeneratedEnumRegisterFunctionText . Logf ( TEXT ( " return ReturnEnum; \r \n " ) ) ;
GeneratedEnumRegisterFunctionText . Logf ( TEXT ( " } \r \n " ) ) ;
auto & GeneratedFunctionText = GetGeneratedFunctionTextDevice ( ) ;
GeneratedFunctionText + = GeneratedEnumRegisterFunctionText ;
uint32 EnumCrc = GenerateTextCRC ( * GeneratedEnumRegisterFunctionText ) ;
GGeneratedCodeCRCs . Add ( Enum , EnumCrc ) ;
2015-04-22 14:15:56 -04:00
// CallSingletons.Logf(TEXT(" OuterClass->LinkChild(%s); // %u\r\n"), *EnumSingletonName, EnumCrc);
2014-03-14 14:13:41 -04:00
}
}
}
2015-03-27 18:10:52 -04:00
void FNativeClassHeaderGenerator : : ExportMirrorsForNoexportStructs ( const TArray < UScriptStruct * > & NativeStructs , int32 TextIndent , FUHTStringBuilder & HeaderOutput )
2014-03-14 14:13:41 -04:00
{
// reverse the order.
for ( int32 i = NativeStructs . Num ( ) - 1 ; i > = 0 ; - - i )
{
UScriptStruct * Struct = NativeStructs [ i ] ;
// Export struct.
2015-03-27 18:10:52 -04:00
HeaderOutput . Logf ( TEXT ( " %sstruct %s " ) , GetTabs ( TextIndent ) , NameLookupCPP . GetNameCPP ( Struct ) ) ;
2014-03-14 14:13:41 -04:00
if ( Struct - > GetSuperStruct ( ) ! = NULL )
{
2014-06-02 07:02:29 -04:00
HeaderOutput . Logf ( TEXT ( " : public %s " ) , NameLookupCPP . GetNameCPP ( Struct - > GetSuperStruct ( ) ) ) ;
2014-03-14 14:13:41 -04:00
}
2015-03-27 18:10:52 -04:00
HeaderOutput . Logf ( TEXT ( " \r \n %s{ \r \n " ) , GetTabs ( TextIndent ) ) ;
2014-03-14 14:13:41 -04:00
// Export the struct's CPP properties.
ExportProperties ( Struct , TextIndent , /*bAccessSpecifiers=*/ false , & HeaderOutput ) ;
2015-03-27 18:10:52 -04:00
HeaderOutput . Logf ( TEXT ( " %s}; \r \n \r \n " ) , GetTabs ( TextIndent ) ) ;
2014-03-14 14:13:41 -04:00
}
}
bool FNativeClassHeaderGenerator : : WillExportEventParms ( UFunction * Function )
{
2015-04-02 16:31:18 -04:00
TFieldIterator < UProperty > It ( Function ) ;
return It & & ( It - > PropertyFlags & CPF_Parm ) ;
2014-03-14 14:13:41 -04:00
}
2015-03-27 18:10:52 -04:00
void WriteEventFunctionPrologue ( FUHTStringBuilder & Output , int32 Indent , const FParmsAndReturnProperties & Parameters , UObject * FunctionOuter , const TCHAR * FunctionName )
2014-03-14 14:13:41 -04:00
{
// now the body - first we need to declare a struct which will hold the parameters for the event/delegate call
2015-03-27 18:10:52 -04:00
Output . Logf ( TEXT ( " \r \n %s{ \r \n " ) , GetTabs ( Indent ) ) ;
2014-03-14 14:13:41 -04:00
// declare and zero-initialize the parameters and return value, if applicable
if ( ! Parameters . HasParms ( ) )
return ;
2015-01-20 09:33:54 -05:00
FString EventStructName = GetEventStructParamsName ( FunctionOuter , FunctionName ) ;
2014-03-14 14:13:41 -04:00
2015-03-27 18:10:52 -04:00
Output . Logf ( TEXT ( " %s%s Parms; \r \n " ) , GetTabs ( Indent + 1 ) , * EventStructName ) ;
2014-03-14 14:13:41 -04:00
// Declare a parameter struct for this event/delegate and assign the struct members using the values passed into the event/delegate call.
for ( auto It = Parameters . Parms . CreateConstIterator ( ) ; It ; + + It )
{
UProperty * Prop = * It ;
const FString PropertyName = Prop - > GetName ( ) ;
2015-03-27 18:10:52 -04:00
if ( Prop - > ArrayDim > 1 )
2014-03-14 14:13:41 -04:00
{
2015-03-27 18:10:52 -04:00
Output . Logf ( TEXT ( " %sFMemory::Memcpy(Parms.%s,%s,sizeof(Parms.%s)); \r \n " ) , GetTabs ( Indent + 1 ) , * PropertyName , * PropertyName , * PropertyName ) ;
2014-03-14 14:13:41 -04:00
}
else
{
FString ValueAssignmentText = PropertyName ;
if ( Prop - > IsA < UBoolProperty > ( ) )
{
ValueAssignmentText + = TEXT ( " ? true : false " ) ;
}
2015-03-27 18:10:52 -04:00
Output . Logf ( TEXT ( " %sParms.%s=%s; \r \n " ) , GetTabs ( Indent + 1 ) , * PropertyName , * ValueAssignmentText ) ;
2014-03-14 14:13:41 -04:00
}
}
}
2015-03-27 18:10:52 -04:00
void WriteEventFunctionEpilogue ( FUHTStringBuilder & Output , int32 Indent , const FParmsAndReturnProperties & Parameters , const TCHAR * FunctionName )
2014-03-14 14:13:41 -04:00
{
// Out parm copying.
for ( auto It = Parameters . Parms . CreateConstIterator ( ) ; It ; + + It )
{
UProperty * Prop = * It ;
if ( Prop - > HasAnyPropertyFlags ( CPF_OutParm ) & & ( ! Prop - > HasAnyPropertyFlags ( CPF_ConstParm ) | | Prop - > IsA < UObjectPropertyBase > ( ) ) )
{
const FString PropertyName = Prop - > GetName ( ) ;
if ( Prop - > ArrayDim > 1 )
{
2015-03-27 18:10:52 -04:00
Output . Logf ( TEXT ( " %sFMemory::Memcpy(&%s,&Parms.%s,sizeof(%s)); \r \n " ) , GetTabs ( Indent + 1 ) , * PropertyName , * PropertyName , * PropertyName ) ;
2014-03-14 14:13:41 -04:00
}
else
{
2015-03-27 18:10:52 -04:00
Output . Logf ( TEXT ( " %s%s=Parms.%s; \r \n " ) , GetTabs ( Indent + 1 ) , * PropertyName , * PropertyName ) ;
2014-03-14 14:13:41 -04:00
}
}
}
// Return value.
if ( Parameters . Return )
{
// Make sure uint32 -> bool is supported
bool bBoolProperty = Parameters . Return - > IsA ( UBoolProperty : : StaticClass ( ) ) ;
2015-03-27 18:10:52 -04:00
Output . Logf ( TEXT ( " %sreturn %sParms.%s; \r \n " ) , GetTabs ( Indent + 1 ) , bBoolProperty ? TEXT ( " !! " ) : TEXT ( " " ) , * Parameters . Return - > GetName ( ) ) ;
2014-03-14 14:13:41 -04:00
}
2015-03-27 18:10:52 -04:00
Output . Logf ( TEXT ( " %s} \r \n " ) , GetTabs ( Indent ) ) ;
2014-03-14 14:13:41 -04:00
}
2015-01-20 09:33:54 -05:00
void FNativeClassHeaderGenerator : : ExportDelegateDefinitions ( FUnrealSourceFile & SourceFile , const TArray < UDelegateFunction * > & DelegateFunctions , const bool bWrapperImplementationsOnly )
2014-03-14 14:13:41 -04:00
{
2015-03-27 18:10:52 -04:00
FUHTStringBuilder HeaderOutput ;
2014-03-14 14:13:41 -04:00
for ( int32 i = DelegateFunctions . Num ( ) - 1 ; i > = 0 ; i - - )
{
UFunction * Function = DelegateFunctions [ i ] ;
2015-03-27 18:10:52 -04:00
FUHTStringBuilder DelegateOutput ;
2014-03-14 14:13:41 -04:00
check ( Function - > HasAnyFunctionFlags ( FUNC_Delegate ) ) ;
2015-01-20 09:33:54 -05:00
if ( bWrapperImplementationsOnly )
{
// Export parameters structs for all delegates. We'll need these to declare our delegate execution function.
ExportEventParm ( Function , DelegateOutput ) ;
}
2014-03-14 14:13:41 -04:00
const bool bIsMulticastDelegate = Function - > HasAnyFunctionFlags ( FUNC_MulticastDelegate ) ;
// Unmangle the function name
const FString DelegateName = Function - > GetName ( ) . LeftChop ( FString ( HEADER_GENERATED_DELEGATE_SIGNATURE_SUFFIX ) . Len ( ) ) ;
2015-01-20 09:33:54 -05:00
auto * CompilerInfo = FFunctionData : : FindForFunction ( Function ) ;
2014-03-14 14:13:41 -04:00
FFuncInfo FunctionData = CompilerInfo - > GetFunctionData ( ) ;
if ( bWrapperImplementationsOnly )
{
// Always export delegate wrapper functions as inline
FunctionData . FunctionExportFlags | = FUNCEXPORT_Inline ;
}
// Add class name to beginning of function, to avoid collisions with other classes with the same delegate name in this scope
FString Delegate ( TEXT ( " delegate " ) ) ;
check ( FunctionData . MarshallAndCallName . StartsWith ( Delegate ) ) ;
FString ShortName = * FunctionData . MarshallAndCallName + Delegate . Len ( ) ;
FunctionData . MarshallAndCallName = FString : : Printf ( TEXT ( " F%s_DelegateWrapper " ) , * ShortName ) ;
// Setup delegate parameter
const FString ExtraParam ( FString : : Printf ( TEXT ( " const %s& %s " ) ,
bIsMulticastDelegate ? TEXT ( " FMulticastScriptDelegate " ) : TEXT ( " FScriptDelegate " ) ,
* DelegateName ) ) ;
2015-01-20 09:33:54 -05:00
DelegateOutput . Log ( TEXT ( " static " ) ) ;
2014-03-14 14:13:41 -04:00
// export the line that looks like: int32 Main(const FString& Parms)
2015-01-20 09:33:54 -05:00
ExportNativeFunctionHeader ( FunctionData , DelegateOutput , EExportFunctionType : : Event , EExportFunctionHeaderStyle : : Declaration , * ExtraParam ) ;
2014-03-14 14:13:41 -04:00
if ( ! bWrapperImplementationsOnly )
{
// Only exporting function prototype
2015-01-20 09:33:54 -05:00
DelegateOutput . Logf ( TEXT ( " ; \r \n " ) ) ;
ExportFunction ( Function , & SourceFile . GetScope ( ) . Get ( ) , false ) ;
2014-03-14 14:13:41 -04:00
}
else
{
auto Parameters = GetFunctionParmsAndReturn ( FunctionData . FunctionReference ) ;
2015-01-20 09:33:54 -05:00
WriteEventFunctionPrologue ( DelegateOutput , 0 , Parameters , Function - > GetOuter ( ) , * DelegateName ) ;
2014-03-14 14:13:41 -04:00
{
const TCHAR * DelegateType = bIsMulticastDelegate ? TEXT ( " ProcessMulticastDelegate " ) : TEXT ( " ProcessDelegate " ) ;
const TCHAR * DelegateArg = Parameters . HasParms ( ) ? TEXT ( " &Parms " ) : TEXT ( " NULL " ) ;
2015-03-27 18:10:52 -04:00
DelegateOutput . Logf ( TEXT ( " \t %s.%s<UObject>(%s); \r \n " ) , * DelegateName , DelegateType , DelegateArg ) ;
2014-03-14 14:13:41 -04:00
}
2015-01-20 09:33:54 -05:00
WriteEventFunctionEpilogue ( DelegateOutput , 0 , Parameters , * DelegateName ) ;
}
if ( ! bWrapperImplementationsOnly )
{
HeaderOutput . Log ( DelegateOutput ) ;
}
else
{
2015-03-17 05:19:11 -04:00
FString MacroName = SourceFile . GetGeneratedMacroName ( FunctionData . MacroLine , TEXT ( " _DELEGATE " ) ) ;
2015-01-20 09:33:54 -05:00
WriteMacro ( HeaderOutput , MacroName , DelegateOutput ) ;
2014-03-14 14:13:41 -04:00
}
}
if ( HeaderOutput . Len ( ) )
{
2015-01-20 09:33:54 -05:00
GeneratedHeaderText . Log ( * HeaderOutput ) ;
GeneratedHeaderText . Log ( TEXT ( " \r \n \r \n " ) ) ;
2014-03-14 14:13:41 -04:00
}
}
/**
* Export a single . proto declaration , recursing as necessary for sub declarations
*
* @ param Out output device
* @ param MessageName name of the message in the declaration
* @ param Properties array of parameters in the function definition
* @ param PropertyFlags flags to filter property array against
* @ param Ident starting indentation level
*/
void ExportProtoDeclaration ( FOutputDevice & Out , const FString & MessageName , TFieldIterator < UProperty > & Properties , uint64 PropertyFlags , int32 Indent )
{
2015-03-27 18:10:52 -04:00
Out . Logf ( TEXT ( " %smessage CMsg%sMessage \r \n " ) , GetTabs ( Indent ) , * MessageName ) ;
Out . Logf ( TEXT ( " %s{ \r \n " ) , GetTabs ( Indent ) ) ;
2014-03-14 14:13:41 -04:00
static TMap < FString , FString > ToProtoTypeMappings ;
static bool bInitMapping = false ;
if ( ! bInitMapping )
{
// Explicit type mappings
ToProtoTypeMappings . Add ( TEXT ( " FString " ) , TEXT ( " string " ) ) ;
ToProtoTypeMappings . Add ( TEXT ( " int32 " ) , TEXT ( " int32 " ) ) ;
ToProtoTypeMappings . Add ( TEXT ( " int64 " ) , TEXT ( " int64 " ) ) ;
ToProtoTypeMappings . Add ( TEXT ( " uint8 " ) , TEXT ( " bytes " ) ) ;
ToProtoTypeMappings . Add ( TEXT ( " bool " ) , TEXT ( " bool " ) ) ;
ToProtoTypeMappings . Add ( TEXT ( " double " ) , TEXT ( " double " ) ) ;
ToProtoTypeMappings . Add ( TEXT ( " float " ) , TEXT ( " float " ) ) ;
bInitMapping = true ;
}
int32 FieldIdx = 1 ;
for ( ; Properties & & ( Properties - > PropertyFlags & PropertyFlags ) ; + + Properties )
{
UProperty * Property = * Properties ;
UClass * PropClass = Property - > GetClass ( ) ;
// Skip out and return paramaters
if ( ( Property - > PropertyFlags & CPF_RepSkip ) | | ( Property - > PropertyFlags & CPF_ReturnParm ) )
{
continue ;
}
// export the property type text (e.g. FString; int32; TArray, etc.)
FString TypeText , ExtendedTypeText ;
TypeText = Property - > GetCPPType ( & ExtendedTypeText , CPPF_None ) ;
if ( PropClass ! = UInterfaceProperty : : StaticClass ( ) & & PropClass ! = UObjectProperty : : StaticClass ( ) )
{
bool bIsRepeated = false ;
2015-04-21 10:25:59 -04:00
if ( UArrayProperty * ArrayProperty = Cast < UArrayProperty > ( Property ) )
2014-03-14 14:13:41 -04:00
{
2014-06-02 14:20:58 -04:00
UClass * InnerPropClass = ArrayProperty - > Inner - > GetClass ( ) ;
2014-03-14 14:13:41 -04:00
if ( InnerPropClass ! = UInterfaceProperty : : StaticClass ( ) & & InnerPropClass ! = UObjectProperty : : StaticClass ( ) )
{
FString InnerExtendedTypeText ;
2014-06-02 14:20:58 -04:00
FString InnerTypeText = ArrayProperty - > Inner - > GetCPPType ( & InnerExtendedTypeText , CPPF_None ) ;
2014-03-14 14:13:41 -04:00
TypeText = InnerTypeText ;
ExtendedTypeText = InnerExtendedTypeText ;
2014-06-02 14:20:58 -04:00
Property = ArrayProperty - > Inner ;
2014-03-14 14:13:41 -04:00
bIsRepeated = true ;
}
else
{
FError : : Throwf ( TEXT ( " ExportProtoDeclaration - Unhandled property type '%s': %s " ) , * PropClass - > GetName ( ) , * Property - > GetPathName ( ) ) ;
}
}
2015-04-21 10:25:59 -04:00
else if ( UMapProperty * MapProperty = Cast < UMapProperty > ( Property ) )
{
FError : : Throwf ( TEXT ( " ExportProtoDeclaration - Map properties not yet supported '%s': %s " ) , * PropClass - > GetName ( ) , * Property - > GetPathName ( ) ) ;
}
2014-03-14 14:13:41 -04:00
else if ( Property - > ArrayDim ! = 1 )
{
bIsRepeated = true ;
}
FString VariableTypeName = FString : : Printf ( TEXT ( " %s%s " ) , * TypeText , * ExtendedTypeText ) ;
FString * ProtoTypeName = NULL ;
UStructProperty * StructProperty = Cast < UStructProperty > ( Property ) ;
if ( StructProperty ! = NULL )
{
TFieldIterator < UProperty > StructIt ( StructProperty - > Struct ) ;
2015-03-27 18:10:52 -04:00
ExportProtoDeclaration ( Out , VariableTypeName , StructIt , CPF_AllFlags , Indent + 1 ) ;
2014-03-14 14:13:41 -04:00
VariableTypeName = FString : : Printf ( TEXT ( " CMsg%sMessage " ) , * VariableTypeName ) ;
ProtoTypeName = & VariableTypeName ;
}
else
{
ProtoTypeName = ToProtoTypeMappings . Find ( VariableTypeName ) ;
}
2015-03-27 18:10:52 -04:00
Out . Log ( GetTabs ( Indent + 1 ) ) ;
Out . Log ( bIsRepeated ? TEXT ( " repeated " ) : TEXT ( " optional " ) ) ;
2014-03-14 14:13:41 -04:00
if ( ProtoTypeName ! = NULL )
{
Out . Logf ( TEXT ( " %s %s = %d; \r \n " ) , * * ProtoTypeName , * Property - > GetNameCPP ( ) , FieldIdx ) ;
FieldIdx + + ;
}
else
{
FError : : Throwf ( TEXT ( " ExportProtoDeclaration - Unhandled property mapping '%s': %s " ) , * PropClass - > GetName ( ) , * Property - > GetPathName ( ) ) ;
}
}
else
{
FError : : Throwf ( TEXT ( " ExportProtoDeclaration - Unhandled property type '%s': %s " ) , * PropClass - > GetName ( ) , * Property - > GetPathName ( ) ) ;
}
}
2015-03-27 18:10:52 -04:00
Out . Logf ( TEXT ( " %s} \r \n " ) , GetTabs ( Indent ) ) ;
2014-03-14 14:13:41 -04:00
}
/**
* Generate a . proto message declaration for any functions marked as requiring one
*
* @ param InCallbackFunctions array of functions for consideration to generate . proto definitions
* @ param Indent starting indentation level
* @ param Output optional output redirect
*/
2015-03-27 18:10:52 -04:00
void FNativeClassHeaderGenerator : : ExportProtoMessage ( const TArray < UFunction * > & InCallbackFunctions , FClassMetaData * ClassData , int32 Indent , FUHTStringBuilder * Output )
2014-03-14 14:13:41 -04:00
{
// Parms struct definitions.
2015-03-27 18:10:52 -04:00
FUHTStringBuilder HeaderOutput ;
2014-03-14 14:13:41 -04:00
TArray < UFunction * > CallbackFunctions = InCallbackFunctions ;
CallbackFunctions . Sort ( ) ;
for ( int32 Index = 0 ; Index < CallbackFunctions . Num ( ) ; Index + + )
{
UFunction * Function = CallbackFunctions [ Index ] ;
2015-01-20 09:33:54 -05:00
auto * CompilerInfo = FFunctionData : : FindForFunction ( Function ) ;
2014-03-14 14:13:41 -04:00
const FFuncInfo & FunctionData = CompilerInfo - > GetFunctionData ( ) ;
if ( FunctionData . FunctionExportFlags & FUNCEXPORT_NeedsProto )
{
if ( WillExportEventParms ( Function ) & & ! Function - > HasAnyFunctionFlags ( FUNC_Delegate ) )
{
FString FunctionName = Function - > GetName ( ) ;
TFieldIterator < UProperty > CommentIt ( Function ) ;
FString ParameterList ;
for ( ; CommentIt & & ( CommentIt - > PropertyFlags & CPF_Parm ) ; + + CommentIt )
{
UProperty * Param = * CommentIt ;
2014-12-11 11:49:41 -05:00
ForwardDeclarations . Add ( Param ) ;
2014-03-14 14:13:41 -04:00
FString TypeText , ExtendedTypeText ;
TypeText = Param - > GetCPPType ( & ExtendedTypeText , CPPF_None ) ;
FString ParamName = FString : : Printf ( TEXT ( " %s%s %s " ) , * TypeText , * ExtendedTypeText , * Param - > GetName ( ) ) ;
// add this property to the parameter list string
if ( ParameterList . Len ( ) )
{
ParameterList + = TCHAR ( ' , ' ) ;
}
ParameterList + = ParamName ;
}
2015-03-27 18:10:52 -04:00
HeaderOutput . Logf ( TEXT ( " // %s%s(%s) \r \n " ) , GetTabs ( Indent ) , * FunctionName , * ParameterList ) ;
2014-03-14 14:13:41 -04:00
TFieldIterator < UProperty > ParamIt ( Function ) ;
ExportProtoDeclaration ( HeaderOutput , FunctionName , ParamIt , CPF_Parm , Indent ) ;
}
}
}
if ( ! Output )
{
GeneratedProtoText . Log ( * HeaderOutput ) ;
}
else
{
Output - > Log ( HeaderOutput ) ;
}
}
// Java uses different coding standards for capitalization
static FString FixJavaName ( const FString & StringIn )
{
FString FixedString = StringIn ;
FixedString [ 0 ] = FChar : : ToLower ( FixedString [ 0 ] ) ; // java classes/variable start lower case
FixedString . ReplaceInline ( TEXT ( " ID " ) , TEXT ( " Id " ) , ESearchCase : : CaseSensitive ) ; // Id is standard instead of ID, some of our fnames use ID
return FixedString ;
}
/**
* Export a single . java declaration , recursing as necessary for sub declarations
*
* @ param Out output device
* @ param MessageName name of the message in the declaration
* @ param Properties array of parameters in the function definition
* @ param PropertyFlags flags to filter property array against
* @ param Ident starting indentation level
*/
void ExportMCPDeclaration ( FOutputDevice & Out , const FString & MessageName , TFieldIterator < UProperty > & Properties , uint64 PropertyFlags , int32 Indent )
{
2015-03-27 18:10:52 -04:00
Out . Logf ( TEXT ( " %spublic class %sCommand extends ProfileCommand \r \n " ) , GetTabs ( Indent ) , * MessageName ) ;
Out . Logf ( TEXT ( " %s{ \r \n " ) , GetTabs ( Indent ) ) ;
2014-03-14 14:13:41 -04:00
static TMap < FString , FString > ToMCPTypeMappings ;
static TMap < FString , FString > ToAnnotationMappings ;
static bool bInitMapping = false ;
if ( ! bInitMapping )
{
// Explicit type mappings
ToMCPTypeMappings . Add ( TEXT ( " FString " ) , TEXT ( " String " ) ) ;
ToMCPTypeMappings . Add ( TEXT ( " int32 " ) , TEXT ( " int " ) ) ;
ToMCPTypeMappings . Add ( TEXT ( " int64 " ) , TEXT ( " int " ) ) ;
ToMCPTypeMappings . Add ( TEXT ( " uint8 " ) , TEXT ( " byte " ) ) ;
ToMCPTypeMappings . Add ( TEXT ( " bool " ) , TEXT ( " boolean " ) ) ;
ToMCPTypeMappings . Add ( TEXT ( " double " ) , TEXT ( " double " ) ) ;
ToMCPTypeMappings . Add ( TEXT ( " float " ) , TEXT ( " float " ) ) ;
2014-04-23 19:29:53 -04:00
ToMCPTypeMappings . Add ( TEXT ( " byte " ) , TEXT ( " byte " ) ) ;
2014-03-14 14:13:41 -04:00
ToAnnotationMappings . Add ( TEXT ( " FString " ) , TEXT ( " @NotBlankOrNull " ) ) ;
bInitMapping = true ;
}
FString ConstructorParams ;
FString ConstructorText ;
for ( ; Properties & & ( Properties - > PropertyFlags & PropertyFlags ) ; + + Properties )
{
UProperty * Property = * Properties ;
UClass * PropClass = Property - > GetClass ( ) ;
// Skip out and return paramaters
if ( ( Property - > PropertyFlags & CPF_RepSkip ) | | ( Property - > PropertyFlags & CPF_ReturnParm ) )
{
continue ;
}
// export the property type text (e.g. FString; int32; TArray, etc.)
FString TypeText , ExtendedTypeText ;
TypeText = Property - > GetCPPType ( & ExtendedTypeText , CPPF_None ) ;
if ( PropClass ! = UInterfaceProperty : : StaticClass ( ) & & PropClass ! = UObjectProperty : : StaticClass ( ) )
{
// TODO Implement arrays
UArrayProperty * ArrayProperty = Cast < UArrayProperty > ( Property ) ;
if ( ArrayProperty ! = NULL )
{
// skip array generation for Java, this should result in a List<TYPE> declaration, but we can do this by hand for now.
continue ;
}
2015-04-21 10:25:59 -04:00
// TODO Implement maps
UMapProperty * MapProperty = Cast < UMapProperty > ( Property ) ;
if ( MapProperty ! = NULL )
{
continue ;
}
2014-03-14 14:13:41 -04:00
/*bool bIsRepeated = false;
UArrayProperty * ArrayProperty = Cast < UArrayProperty > ( Property ) ;
if ( ArrayProperty ! = NULL )
{
UClass * InnerPropClass = ArrayProperty - > Inner - > GetClass ( ) ;
if ( InnerPropClass ! = UInterfaceProperty : : StaticClass ( ) & & InnerPropClass ! = UObjectProperty : : StaticClass ( ) )
{
FString InnerExtendedTypeText ;
FString InnerTypeText = ArrayProperty - > Inner - > GetCPPType ( & InnerExtendedTypeText , CPPF_None ) ;
TypeText = InnerTypeText ;
ExtendedTypeText = InnerExtendedTypeText ;
Property = ArrayProperty - > Inner ;
bIsRepeated = true ;
}
else
{
FError : : Throwf ( TEXT ( " ExportMCPDeclaration - Unhandled property type '%s': %s " ) , * PropClass - > GetName ( ) , * Property - > GetPathName ( ) ) ;
}
}
else if ( Property - > ArrayDim ! = 1 )
{
bIsRepeated = true ;
} */
FString VariableTypeName = FString : : Printf ( TEXT ( " %s%s " ) , * TypeText , * ExtendedTypeText ) ;
FString PropertyName = FixJavaName ( Property - > GetNameCPP ( ) ) ;
FString * MCPTypeName = NULL ;
FString * AnnotationName = NULL ;
UStructProperty * StructProperty = Cast < UStructProperty > ( Property ) ;
if ( StructProperty ! = NULL )
{
// TODO Implement structs
/* TFieldIterator<UProperty> StructIt(StructProperty->Struct);
2015-03-27 18:10:52 -04:00
ExportMCPDeclaration ( Out , VariableTypeName , StructIt , CPF_AllFlags , Indent + 1 ) ;
2014-03-14 14:13:41 -04:00
VariableTypeName = FString : : Printf ( TEXT ( " CMsg%sMessage " ) , * VariableTypeName ) ;
MCPTypeName = & VariableTypeName ; */
2014-08-21 20:30:51 -04:00
continue ;
2014-03-14 14:13:41 -04:00
}
else
{
2014-04-23 19:29:53 -04:00
UByteProperty * ByteProperty = Cast < UByteProperty > ( Property ) ;
if ( ByteProperty ! = NULL & & ByteProperty - > Enum ! = NULL )
{
// treat enums like strings because that's how they'll be exported in JSON
MCPTypeName = ToMCPTypeMappings . Find ( TEXT ( " FString " ) ) ;
AnnotationName = ToAnnotationMappings . Find ( TEXT ( " FString " ) ) ;
}
else
{
MCPTypeName = ToMCPTypeMappings . Find ( VariableTypeName ) ;
AnnotationName = ToAnnotationMappings . Find ( VariableTypeName ) ;
}
2014-03-14 14:13:41 -04:00
}
if ( AnnotationName ! = NULL & & ! AnnotationName - > IsEmpty ( ) )
{
2015-03-27 18:10:52 -04:00
Out . Log ( GetTabs ( Indent + 1 ) ) ;
2014-03-14 14:13:41 -04:00
Out . Logf ( TEXT ( " %s \r \n " ) , * * AnnotationName ) ;
}
if ( MCPTypeName ! = NULL )
{
2015-03-27 18:10:52 -04:00
Out . Log ( GetTabs ( Indent + 1 ) ) ;
2014-03-14 14:13:41 -04:00
Out . Logf ( TEXT ( " private %s %s; \r \n " ) , * * MCPTypeName , * PropertyName ) ;
ConstructorParams + = FString : : Printf ( TEXT ( " , %s %s " ) , * * MCPTypeName , * PropertyName ) ;
2015-03-27 18:10:52 -04:00
ConstructorText + = FString : : Printf ( TEXT ( " %sthis.%s = %s; \r \n " ) , GetTabs ( Indent + 2 ) , * PropertyName , * PropertyName ) ;
2014-03-14 14:13:41 -04:00
}
else
{
2014-04-23 19:29:53 -04:00
FError : : Throwf ( TEXT ( " ExportMCPDeclaration - Unhandled property mapping '%s' (%s): %s " ) , * PropClass - > GetName ( ) , * VariableTypeName , * Property - > GetPathName ( ) ) ;
2014-03-14 14:13:41 -04:00
}
}
else
{
FError : : Throwf ( TEXT ( " ExportMCPDeclaration - Unhandled property type '%s': %s " ) , * PropClass - > GetName ( ) , * Property - > GetPathName ( ) ) ;
}
}
2015-03-27 18:10:52 -04:00
Out . Logf ( TEXT ( " \r \n %spublic %sCommand(String epicId, String profileId%s) \r \n " ) , GetTabs ( Indent + 1 ) , * MessageName , * ConstructorParams ) ;
Out . Logf ( TEXT ( " %s{ \r \n " ) , GetTabs ( Indent + 1 ) ) ;
Out . Logf ( TEXT ( " %ssuper(epicId, profileId); \r \n " ) , GetTabs ( Indent + 2 ) ) ;
2014-03-14 14:13:41 -04:00
Out . Logf ( TEXT ( " %s " ) , * ConstructorText ) ;
2015-03-27 18:10:52 -04:00
Out . Logf ( TEXT ( " %s} \r \n " ) , GetTabs ( Indent + 1 ) ) ;
2014-03-14 14:13:41 -04:00
2015-03-27 18:10:52 -04:00
Out . Logf ( TEXT ( " \r \n %s@Override \r \n " ) , GetTabs ( Indent + 1 ) ) ;
Out . Logf ( TEXT ( " %sprotected void execute(@Name( \" profile \" ) @NotNull ProfileEx profile) \r \n " ) , GetTabs ( Indent + 1 ) ) ;
Out . Logf ( TEXT ( " %s{ \r \n " ) , GetTabs ( Indent + 1 ) ) ;
Out . Logf ( TEXT ( " %s} \r \n " ) , GetTabs ( Indent + 1 ) ) ;
2014-03-14 14:13:41 -04:00
2015-03-27 18:10:52 -04:00
Out . Logf ( TEXT ( " %s} \r \n " ) , GetTabs ( Indent ) ) ;
2014-03-14 14:13:41 -04:00
}
/**
* Generate a . MCP message declaration for any functions marked as requiring one
*
* @ param InCallbackFunctions array of functions for consideration to generate . proto definitions
* @ param Indent starting indentation level
* @ param Output optional output redirect
*/
2015-03-27 18:10:52 -04:00
void FNativeClassHeaderGenerator : : ExportMCPMessage ( const TArray < UFunction * > & InCallbackFunctions , FClassMetaData * ClassData , int32 Indent , FUHTStringBuilder * Output )
2014-03-14 14:13:41 -04:00
{
// Parms struct definitions.
2015-03-27 18:10:52 -04:00
FUHTStringBuilder HeaderOutput ;
2014-03-14 14:13:41 -04:00
TArray < UFunction * > CallbackFunctions = InCallbackFunctions ;
CallbackFunctions . Sort ( ) ;
for ( int32 Index = 0 ; Index < CallbackFunctions . Num ( ) ; Index + + )
{
UFunction * Function = CallbackFunctions [ Index ] ;
2015-01-20 09:33:54 -05:00
auto * CompilerInfo = FFunctionData : : FindForFunction ( Function ) ;
2014-03-14 14:13:41 -04:00
const FFuncInfo & FunctionData = CompilerInfo - > GetFunctionData ( ) ;
if ( FunctionData . FunctionExportFlags & FUNCEXPORT_NeedsMCP )
{
if ( WillExportEventParms ( Function ) & & ! Function - > HasAnyFunctionFlags ( FUNC_Delegate ) )
{
FString FunctionName = Function - > GetName ( ) ;
TFieldIterator < UProperty > CommentIt ( Function ) ;
FString ParameterList ;
for ( ; CommentIt & & ( CommentIt - > PropertyFlags & CPF_Parm ) ; + + CommentIt )
{
UProperty * Param = * CommentIt ;
2014-12-11 11:49:41 -05:00
ForwardDeclarations . Add ( Param ) ;
2014-03-14 14:13:41 -04:00
FString TypeText , ExtendedTypeText ;
TypeText = Param - > GetCPPType ( & ExtendedTypeText , CPPF_None ) ;
FString ParamName = FString : : Printf ( TEXT ( " %s%s %s " ) , * TypeText , * ExtendedTypeText , * Param - > GetName ( ) ) ;
// add this property to the parameter list string
if ( ParameterList . Len ( ) )
{
ParameterList + = TCHAR ( ' , ' ) ;
}
ParameterList + = ParamName ;
}
2015-03-27 18:10:52 -04:00
HeaderOutput . Logf ( TEXT ( " // %s%s(%s) \r \n " ) , GetTabs ( Indent ) , * FunctionName , * ParameterList ) ;
2014-03-14 14:13:41 -04:00
TFieldIterator < UProperty > ParamIt ( Function ) ;
ExportMCPDeclaration ( HeaderOutput , FunctionName , ParamIt , CPF_Parm , Indent ) ;
}
}
}
if ( ! Output )
{
GeneratedMCPText . Log ( * HeaderOutput ) ;
}
else
{
Output - > Log ( HeaderOutput ) ;
}
}
2015-03-27 18:10:52 -04:00
void FNativeClassHeaderGenerator : : ExportEventParm ( UFunction * Function , FUHTStringBuilder & HeaderOutput , int32 Indent , bool bOutputConstructor )
2015-01-20 09:33:54 -05:00
{
if ( ! WillExportEventParms ( Function ) )
{
return ;
}
FString FunctionName = Function - > GetName ( ) ;
if ( Function - > HasAnyFunctionFlags ( FUNC_Delegate ) )
{
FunctionName = FunctionName . LeftChop ( FString ( HEADER_GENERATED_DELEGATE_SIGNATURE_SUFFIX ) . Len ( ) ) ;
}
FString EventParmStructName = GetEventStructParamsName ( Function - > GetOuter ( ) , * FunctionName ) ;
2015-03-27 18:10:52 -04:00
HeaderOutput . Logf ( TEXT ( " %sstruct %s \r \n " ) , GetTabs ( Indent ) , * EventParmStructName ) ;
HeaderOutput . Logf ( TEXT ( " %s{ \r \n " ) , GetTabs ( Indent ) ) ;
2015-01-20 09:33:54 -05:00
for ( TFieldIterator < UProperty > It ( Function ) ; It & & ( It - > PropertyFlags & CPF_Parm ) ; + + It )
{
UProperty * Prop = * It ;
ForwardDeclarations . Add ( Prop ) ;
2015-03-27 18:10:52 -04:00
FUHTStringBuilder PropertyText ;
PropertyText . Log ( GetTabs ( Indent + 1 ) ) ;
2015-01-20 09:33:54 -05:00
bool bEmitConst = Prop - > HasAnyPropertyFlags ( CPF_ConstParm ) & & Prop - > IsA < UObjectProperty > ( ) ;
//@TODO: UCREMOVAL: This is awful code duplication to avoid a double-const
{
// export 'const' for parameters
const bool bIsConstParam = ( Prop - > IsA ( UInterfaceProperty : : StaticClass ( ) ) & & ! Prop - > HasAllPropertyFlags ( CPF_OutParm ) ) ; //@TODO: This should be const once that flag exists
const bool bIsOnConstClass = ( Prop - > IsA ( UObjectProperty : : StaticClass ( ) ) & & ( ( UObjectProperty * ) Prop ) - > PropertyClass ! = NULL & & ( ( UObjectProperty * ) Prop ) - > PropertyClass - > HasAnyClassFlags ( CLASS_Const ) ) ;
if ( bIsConstParam | | bIsOnConstClass )
{
bEmitConst = false ; // ExportCppDeclaration will do it for us
}
}
if ( bEmitConst )
{
PropertyText . Logf ( TEXT ( " const " ) ) ;
}
const FString * Dim = GArrayDimensions . Find ( Prop ) ;
Prop - > ExportCppDeclaration ( PropertyText , EExportedDeclaration : : Local , Dim ? * * Dim : NULL ) ;
ApplyAlternatePropertyExportText ( Prop , PropertyText ) ;
PropertyText . Log ( TEXT ( " ; \r \n " ) ) ;
HeaderOutput + = * PropertyText ;
}
// constructor must initialize the return property if it needs it
UProperty * Prop = Function - > GetReturnProperty ( ) ;
if ( Prop & & bOutputConstructor )
{
2015-03-27 18:10:52 -04:00
FUHTStringBuilder InitializationAr ;
2015-01-20 09:33:54 -05:00
UStructProperty * InnerStruct = Cast < UStructProperty > ( Prop ) ;
bool bNeedsOutput = true ;
if ( InnerStruct )
{
bNeedsOutput = InnerStruct - > HasNoOpConstructor ( ) ;
}
else if (
Cast < UNameProperty > ( Prop ) | |
Cast < UDelegateProperty > ( Prop ) | |
Cast < UMulticastDelegateProperty > ( Prop ) | |
Cast < UStrProperty > ( Prop ) | |
Cast < UTextProperty > ( Prop ) | |
Cast < UArrayProperty > ( Prop ) | |
2015-04-21 10:25:59 -04:00
Cast < UMapProperty > ( Prop ) | |
2015-01-20 09:33:54 -05:00
Cast < UInterfaceProperty > ( Prop )
)
{
bNeedsOutput = false ;
}
if ( bNeedsOutput )
{
check ( Prop - > ArrayDim = = 1 ) ; // can't return arrays
2015-03-27 18:10:52 -04:00
HeaderOutput . Logf ( TEXT ( " \r \n %s/** Constructor, intializes return property only **/ \r \n " ) , GetTabs ( Indent + 1 ) ) ;
HeaderOutput . Logf ( TEXT ( " %s%s() \r \n " ) , GetTabs ( Indent + 1 ) , * EventParmStructName ) ;
HeaderOutput . Logf ( TEXT ( " %s%s %s(%s) \r \n " ) , GetTabs ( Indent + 2 ) , TEXT ( " : " ) , * Prop - > GetName ( ) , * GetNullParameterValue ( Prop , false , true ) ) ;
HeaderOutput . Logf ( TEXT ( " %s{ \r \n " ) , GetTabs ( Indent + 1 ) ) ;
HeaderOutput . Logf ( TEXT ( " %s} \r \n " ) , GetTabs ( Indent + 1 ) ) ;
2015-01-20 09:33:54 -05:00
}
}
2015-03-27 18:10:52 -04:00
HeaderOutput . Logf ( TEXT ( " %s}; \r \n " ) , GetTabs ( Indent ) ) ;
2015-01-20 09:33:54 -05:00
}
2015-03-27 18:10:52 -04:00
void FNativeClassHeaderGenerator : : ExportEventParms ( FScope & Scope , const TArray < UFunction * > & InCallbackFunctions , FUHTStringBuilder & Output , int32 Indent , bool bOutputConstructor )
2014-03-14 14:13:41 -04:00
{
// Parms struct definitions.
2015-03-27 18:10:52 -04:00
FUHTStringBuilder HeaderOutput ;
2014-03-14 14:13:41 -04:00
TArray < UFunction * > CallbackFunctions = InCallbackFunctions ;
CallbackFunctions . Sort ( ) ;
for ( int32 Index = 0 ; Index < CallbackFunctions . Num ( ) ; Index + + )
{
UFunction * Function = CallbackFunctions [ Index ] ;
2015-01-20 09:33:54 -05:00
ExportEventParm ( Function , HeaderOutput , Indent , bOutputConstructor ) ;
2014-03-14 14:13:41 -04:00
}
2015-01-20 09:33:54 -05:00
Output . Log ( HeaderOutput ) ;
2014-03-14 14:13:41 -04:00
}
/**
* Get the intrinsic null value for this property
*
* @ param Prop the property to get the null value for
* @ param bMacroContext true when exporting the P_GET * macro , false when exporting the friendly C + + function header
*
* @ return the intrinsic null value for the property ( 0 for ints , TEXT ( " " ) for strings , etc . )
*/
FString FNativeClassHeaderGenerator : : GetNullParameterValue ( UProperty * Prop , bool bMacroContext , bool bInitializer /*=false*/ )
{
UClass * PropClass = Prop - > GetClass ( ) ;
UObjectPropertyBase * ObjectProperty = Cast < UObjectPropertyBase > ( Prop ) ;
if ( PropClass = = UByteProperty : : StaticClass ( )
| | PropClass = = UIntProperty : : StaticClass ( )
| | PropClass = = UBoolProperty : : StaticClass ( )
| | PropClass = = UFloatProperty : : StaticClass ( )
| | PropClass = = UDoubleProperty : : StaticClass ( ) )
{
// if we have a BoolProperty then set it to be false instead of 0
if ( PropClass = = UBoolProperty : : StaticClass ( ) )
{
return TEXT ( " false " ) ;
}
return TEXT ( " 0 " ) ;
}
else if ( PropClass = = UNameProperty : : StaticClass ( ) )
{
return TEXT ( " NAME_None " ) ;
}
else if ( PropClass = = UStrProperty : : StaticClass ( ) )
{
return TEXT ( " TEXT( \" \" ) " ) ;
}
else if ( PropClass = = UTextProperty : : StaticClass ( ) )
{
return TEXT ( " FText::GetEmpty() " ) ;
}
else if ( PropClass = = UArrayProperty : : StaticClass ( )
2015-04-21 10:25:59 -04:00
| | PropClass = = UMapProperty : : StaticClass ( )
2014-03-14 14:13:41 -04:00
| | PropClass = = UDelegateProperty : : StaticClass ( )
2014-06-02 14:20:58 -04:00
| | PropClass = = UMulticastDelegateProperty : : StaticClass ( ) )
2014-03-14 14:13:41 -04:00
{
FString Type , ExtendedType ;
Type = Prop - > GetCPPType ( & ExtendedType , CPPF_OptionalValue ) ;
return Type + ExtendedType + TEXT ( " () " ) ;
}
else if ( PropClass = = UStructProperty : : StaticClass ( ) )
{
bool bHasNoOpConstuctor = CastChecked < UStructProperty > ( Prop ) - > HasNoOpConstructor ( ) ;
if ( bInitializer & & bHasNoOpConstuctor )
{
return TEXT ( " ForceInit " ) ;
}
FString Type , ExtendedType ;
Type = Prop - > GetCPPType ( & ExtendedType , CPPF_OptionalValue ) ;
return Type + ExtendedType + ( bHasNoOpConstuctor ? TEXT ( " (ForceInit) " ) : TEXT ( " () " ) ) ;
}
else if ( ObjectProperty )
{
return TEXT ( " NULL " ) ;
}
else if ( PropClass = = UInterfaceProperty : : StaticClass ( ) )
{
return TEXT ( " NULL " ) ;
}
UE_LOG ( LogCompile , Fatal , TEXT ( " GetNullParameterValue - Unhandled property type '%s': %s " ) , * PropClass - > GetName ( ) , * Prop - > GetPathName ( ) ) ;
return TEXT ( " " ) ;
}
2014-12-08 07:30:42 -05:00
FString FNativeClassHeaderGenerator : : GetFunctionReturnString ( UFunction * Function )
{
if ( auto Return = Function - > GetReturnProperty ( ) )
{
FString ExtendedReturnType ;
2014-12-11 11:49:41 -05:00
ForwardDeclarations . Add ( Return ) ;
2014-12-08 07:30:42 -05:00
FString ReturnType = Return - > GetCPPType ( & ExtendedReturnType , CPPF_ArgumentOrReturnValue ) ;
2015-03-27 18:10:52 -04:00
FUHTStringBuilder ReplacementText ;
ReplacementText + = ReturnType ;
2014-12-08 07:30:42 -05:00
ApplyAlternatePropertyExportText ( Return , ReplacementText ) ;
return ReplacementText + ExtendedReturnType ;
}
return TEXT ( " void " ) ;
}
/**
* Gets string with function const modifier type .
*
* @ param Function Function to get const modifier of .
* @ return Empty FString if function is non - const , FString ( " const " ) if function is const .
*/
FString GetFunctionConstModifierString ( UFunction * Function )
{
if ( Function - > HasAllFunctionFlags ( FUNC_Const ) )
{
return TEXT ( " const " ) ;
}
return FString ( ) ;
}
2015-04-20 06:19:21 -04:00
/**
* Converts Position within File to Line and Column .
*
* @ param File File contents .
* @ param Position Position in string to convert .
* @ param OutLine Result line .
* @ param OutColumn Result column .
*/
void GetLineAndColumnFromPositionInFile ( const FString & File , int32 Position , int32 & OutLine , int32 & OutColumn )
2014-12-08 07:30:42 -05:00
{
2015-04-20 06:19:21 -04:00
OutLine = 1 ;
OutColumn = 1 ;
int32 i ;
for ( i = 1 ; i < = Position ; + + i )
{
if ( File [ i ] = = ' \n ' )
{
+ + OutLine ;
OutColumn = 0 ;
}
else
{
+ + OutColumn ;
}
}
}
bool FNativeClassHeaderGenerator : : IsMissingVirtualSpecifier ( const FString & SourceFile , int32 FunctionNamePosition ) const
{
auto IsEndOfSearchChar = [ ] ( TCHAR C ) { return ( C = = TEXT ( ' } ' ) ) | | ( C = = TEXT ( ' { ' ) ) | | ( C = = TEXT ( ' ; ' ) ) ; } ;
// Find first occurrence of "}", ";", "{" going backwards from ImplementationPosition.
int32 EndOfSearchCharIndex = SourceFile . FindLastCharByPredicate ( IsEndOfSearchChar , FunctionNamePosition ) ;
check ( EndOfSearchCharIndex ! = INDEX_NONE ) ;
// Then find if there is "virtual" keyword starting from position of found character to ImplementationPosition
return ! HasIdentifierExactMatch ( & SourceFile [ EndOfSearchCharIndex ] , & SourceFile [ FunctionNamePosition ] , TEXT ( " virtual " ) ) ;
}
FString CreateClickableErrorMessage ( const FString & Filename , int32 Line , int32 Column )
{
return FString : : Printf ( TEXT ( " %s(%d,%d): error: " ) , * Filename , Line , Column ) ;
}
void FNativeClassHeaderGenerator : : CheckRPCFunctions ( const FFuncInfo & FunctionData , const FString & ClassName , int32 ImplementationPosition , int32 ValidatePosition , const FUnrealSourceFile & SourceFile )
{
bool bHasImplementation = ImplementationPosition ! = INDEX_NONE ;
bool bHasValidate = ValidatePosition ! = INDEX_NONE ;
2014-12-08 07:30:42 -05:00
auto Function = FunctionData . FunctionReference ;
auto FunctionReturnType = GetFunctionReturnString ( Function ) ;
2015-04-10 06:02:22 -04:00
auto ConstModifier = GetFunctionConstModifierString ( Function ) + TEXT ( " " ) ;
2014-12-08 07:30:42 -05:00
auto bIsNative = Function - > HasAllFunctionFlags ( FUNC_Native ) ;
auto bIsNet = Function - > HasAllFunctionFlags ( FUNC_Net ) ;
auto bIsNetValidate = Function - > HasAllFunctionFlags ( FUNC_NetValidate ) ;
auto bIsNetResponse = Function - > HasAllFunctionFlags ( FUNC_NetResponse ) ;
auto bIsBlueprintEvent = Function - > HasAllFunctionFlags ( FUNC_BlueprintEvent ) ;
bool bNeedsImplementation = ( bIsNet & & ! bIsNetResponse ) | | bIsBlueprintEvent | | bIsNative ;
bool bNeedsValidate = ( bIsNative | | bIsNet ) & & ! bIsNetResponse & & bIsNetValidate ;
check ( bNeedsImplementation | | bNeedsValidate ) ;
auto ParameterString = GetFunctionParameterString ( Function ) ;
2015-04-20 06:19:21 -04:00
const auto & Filename = SourceFile . GetFilename ( ) ;
const auto & FileContent = SourceFile . GetContent ( ) ;
2014-12-08 07:30:42 -05:00
//
// Get string with function specifiers, listing why we need _Implementation or _Validate functions.
//
TArray < FString > FunctionSpecifiers ;
FunctionSpecifiers . Reserve ( 4 ) ;
if ( bIsNative ) { FunctionSpecifiers . Add ( TEXT ( " Native " ) ) ; }
if ( bIsNet ) { FunctionSpecifiers . Add ( TEXT ( " Net " ) ) ; }
if ( bIsBlueprintEvent ) { FunctionSpecifiers . Add ( TEXT ( " BlueprintEvent " ) ) ; }
if ( bIsNetValidate ) { FunctionSpecifiers . Add ( TEXT ( " NetValidate " ) ) ; }
check ( FunctionSpecifiers . Num ( ) > 0 ) ;
//
// Coin static_assert message
//
2015-03-27 18:10:52 -04:00
FUHTStringBuilder AssertMessage ;
2014-12-08 07:30:42 -05:00
AssertMessage . Logf ( TEXT ( " Function %s was marked as %s " ) , * ( Function - > GetName ( ) ) , * FunctionSpecifiers [ 0 ] ) ;
for ( int32 i = 1 ; i < FunctionSpecifiers . Num ( ) ; + + i )
{
AssertMessage . Logf ( TEXT ( " , %s " ) , * FunctionSpecifiers [ i ] ) ;
}
AssertMessage . Logf ( TEXT ( " . " ) ) ;
//
2015-04-20 06:19:21 -04:00
// Check if functions are missing.
2014-12-08 07:30:42 -05:00
//
2015-04-20 06:19:21 -04:00
int32 Line ;
int32 Column ;
GetLineAndColumnFromPositionInFile ( FileContent , FunctionData . InputPos , Line , Column ) ;
2015-04-10 06:02:22 -04:00
if ( bNeedsImplementation & & ! bHasImplementation )
2014-12-08 07:30:42 -05:00
{
2015-04-20 06:19:21 -04:00
FString ErrorPosition = CreateClickableErrorMessage ( Filename , Line , Column ) ;
FString FunctionDecl = FString : : Printf ( TEXT ( " virtual %s %s::%s(%s) %s " ) , * FunctionReturnType , * ClassName , * FunctionData . CppImplName , * ParameterString , * ConstModifier ) ;
FError : : Throwf ( TEXT ( " %s%s Declare function %s " ) , * ErrorPosition , * AssertMessage , * FunctionDecl ) ;
2014-12-08 07:30:42 -05:00
}
2015-04-10 06:02:22 -04:00
if ( bNeedsValidate & & ! bHasValidate )
2014-12-08 07:30:42 -05:00
{
2015-04-20 06:19:21 -04:00
FString ErrorPosition = CreateClickableErrorMessage ( Filename , Line , Column ) ;
FString FunctionDecl = FString : : Printf ( TEXT ( " virtual bool %s::%s(%s) %s " ) , * ClassName , * FunctionData . CppValidationImplName , * ParameterString , * ConstModifier ) ;
FError : : Throwf ( TEXT ( " %s%s Declare function %s " ) , * ErrorPosition , * AssertMessage , * FunctionDecl ) ;
}
//
// If all needed functions are declared, check if they have virtual specifiers.
//
if ( bNeedsImplementation & & bHasImplementation & & IsMissingVirtualSpecifier ( FileContent , ImplementationPosition ) )
{
GetLineAndColumnFromPositionInFile ( FileContent , ImplementationPosition , Line , Column ) ;
FString ErrorPosition = CreateClickableErrorMessage ( Filename , Line , Column ) ;
FString FunctionDecl = FString : : Printf ( TEXT ( " %s %s::%s(%s) %s " ) , * FunctionReturnType , * ClassName , * FunctionData . CppImplName , * ParameterString , * ConstModifier ) ;
FError : : Throwf ( TEXT ( " %sDeclared function %sis not marked as virtual. " ) , * ErrorPosition , * FunctionDecl ) ;
}
if ( bNeedsValidate & & bHasValidate & & IsMissingVirtualSpecifier ( FileContent , ValidatePosition ) )
{
GetLineAndColumnFromPositionInFile ( FileContent , ValidatePosition , Line , Column ) ;
FString ErrorPosition = CreateClickableErrorMessage ( Filename , Line , Column ) ;
FString FunctionDecl = FString : : Printf ( TEXT ( " bool %s::%s(%s) %s " ) , * ClassName , * FunctionData . CppValidationImplName , * ParameterString , * ConstModifier ) ;
FError : : Throwf ( TEXT ( " %sDeclared function %sis not marked as virtual. " ) , * ErrorPosition , * FunctionDecl ) ;
2014-12-08 07:30:42 -05:00
}
}
2015-03-27 18:10:52 -04:00
void FNativeClassHeaderGenerator : : ExportNativeFunctionHeader ( const FFuncInfo & FunctionData , FUHTStringBuilder & HeaderOutput , EExportFunctionType : : Type FunctionType , EExportFunctionHeaderStyle : : Type FunctionHeaderStyle , const TCHAR * ExtraParam )
2014-03-14 14:13:41 -04:00
{
UFunction * Function = FunctionData . FunctionReference ;
const bool bIsDelegate = Function - > HasAnyFunctionFlags ( FUNC_Delegate ) ;
const bool bIsInterface = ! bIsDelegate & & Function - > GetOwnerClass ( ) - > HasAnyClassFlags ( CLASS_Interface ) ;
const bool bIsK2Override = Function - > HasAnyFunctionFlags ( FUNC_BlueprintEvent ) ;
2015-03-27 18:10:52 -04:00
if ( ! bIsDelegate )
{
HeaderOutput + = TEXT ( " \t " ) ;
}
2014-03-14 14:13:41 -04:00
if ( FunctionHeaderStyle = = EExportFunctionHeaderStyle : : Declaration )
{
// cpp implementation of functions never have these appendages
// If the function was marked as 'RequiredAPI', then add the *_API macro prefix. Note that if the class itself
// was marked 'RequiredAPI', this is not needed as C++ will exports all methods automatically.
2015-01-20 09:33:54 -05:00
if ( FunctionType ! = EExportFunctionType : : Event & &
! Function - > GetOwnerClass ( ) - > HasAnyClassFlags ( CLASS_RequiredAPI ) & &
( FunctionData . FunctionExportFlags & FUNCEXPORT_RequiredAPI ) )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
HeaderOutput . Log ( GetAPIString ( ) ) ;
2014-03-14 14:13:41 -04:00
}
if ( FunctionType = = EExportFunctionType : : Interface )
{
HeaderOutput . Log ( TEXT ( " static " ) ) ;
}
else if ( bIsK2Override )
{
HeaderOutput . Log ( TEXT ( " virtual " ) ) ;
}
// if the owning class is an interface class
else if ( bIsInterface )
{
HeaderOutput . Log ( TEXT ( " virtual " ) ) ;
}
// this is not an event, the function is not a static function and the function is not marked final
else if ( FunctionType ! = EExportFunctionType : : Event & & ! Function - > HasAnyFunctionFlags ( FUNC_Static ) & & ! ( FunctionData . FunctionExportFlags & FUNCEXPORT_Final ) )
{
HeaderOutput . Log ( TEXT ( " virtual " ) ) ;
}
else if ( FunctionData . FunctionExportFlags & FUNCEXPORT_Inline )
{
HeaderOutput . Log ( TEXT ( " inline " ) ) ;
}
}
if ( auto Return = Function - > GetReturnProperty ( ) )
{
FString ExtendedReturnType ;
FString ReturnType = Return - > GetCPPType ( & ExtendedReturnType , ( FunctionHeaderStyle = = EExportFunctionHeaderStyle : : Definition & & ( FunctionType ! = EExportFunctionType : : Interface ) ? CPPF_Implementation : 0 ) | CPPF_ArgumentOrReturnValue ) ;
2014-12-11 11:49:41 -05:00
ForwardDeclarations . Add ( Return ) ;
2015-03-27 18:10:52 -04:00
FUHTStringBuilder ReplacementText ;
ReplacementText + = ReturnType ;
2014-03-14 14:13:41 -04:00
ApplyAlternatePropertyExportText ( Return , ReplacementText ) ;
HeaderOutput . Logf ( TEXT ( " %s%s " ) , * ReplacementText , * ExtendedReturnType ) ;
}
else
{
HeaderOutput . Log ( TEXT ( " void " ) ) ;
}
FString FunctionName ;
if ( FunctionHeaderStyle = = EExportFunctionHeaderStyle : : Definition )
{
2014-06-02 07:02:29 -04:00
FunctionName = FString ( NameLookupCPP . GetNameCPP ( CastChecked < UClass > ( Function - > GetOuter ( ) ) , bIsInterface | | FunctionType = = EExportFunctionType : : Interface ) ) + TEXT ( " :: " ) ;
2014-03-14 14:13:41 -04:00
}
if ( FunctionType = = EExportFunctionType : : Interface )
{
FunctionName + = FString : : Printf ( TEXT ( " Execute_%s " ) , * Function - > GetName ( ) ) ;
}
else if ( FunctionType = = EExportFunctionType : : Event )
{
FunctionName + = FunctionData . MarshallAndCallName ;
}
else
{
FunctionName + = FunctionData . CppImplName ;
}
HeaderOutput . Logf ( TEXT ( " %s( " ) , * FunctionName ) ;
int32 ParmCount = 0 ;
// Emit extra parameter if we have one
if ( ExtraParam )
{
HeaderOutput + = ExtraParam ;
+ + ParmCount ;
}
for ( TFieldIterator < UProperty > It ( Function ) ; It & & ( It - > PropertyFlags & ( CPF_Parm | CPF_ReturnParm ) ) = = CPF_Parm ; + + It )
{
UProperty * Property = * It ;
2014-12-11 11:49:41 -05:00
ForwardDeclarations . Add ( Property ) ;
2015-01-20 09:33:54 -05:00
2014-03-14 14:13:41 -04:00
if ( ParmCount + + )
{
HeaderOutput . Log ( TEXT ( " , " ) ) ;
}
2015-03-27 18:10:52 -04:00
FUHTStringBuilder PropertyText ;
2014-03-14 14:13:41 -04:00
const FString * Dim = GArrayDimensions . Find ( Property ) ;
Property - > ExportCppDeclaration ( PropertyText , EExportedDeclaration : : Parameter , Dim ? * * Dim : NULL ) ;
ApplyAlternatePropertyExportText ( Property , PropertyText ) ;
HeaderOutput + = PropertyText ;
}
HeaderOutput . Log ( TEXT ( " ) " ) ) ;
if ( FunctionType ! = EExportFunctionType : : Interface )
{
if ( ! bIsDelegate & & Function - > HasAllFunctionFlags ( FUNC_Const ) )
{
HeaderOutput . Log ( TEXT ( " const " ) ) ;
}
if ( bIsInterface & & FunctionHeaderStyle = = EExportFunctionHeaderStyle : : Declaration )
{
// all methods in interface classes are pure virtuals
HeaderOutput . Log ( TEXT ( " =0 " ) ) ;
}
}
}
/**
* Export the actual internals to a standard thunk function
*
* @ param RPCWrappers output device for writing
* @ param FunctionData function data for the current function
* @ param Parameters list of parameters in the function
* @ param Return return parameter for the function
2015-03-17 05:19:11 -04:00
* @ param DeprecationWarningOutputDevice Device to output deprecation warnings for _Validate and _Implementation functions .
2014-03-14 14:13:41 -04:00
*/
2015-03-27 18:10:52 -04:00
void FNativeClassHeaderGenerator : : ExportFunctionThunk ( FUHTStringBuilder & RPCWrappers , UFunction * Function , const FFuncInfo & FunctionData , const TArray < UProperty * > & Parameters , UProperty * Return , FUHTStringBuilder & DeprecationWarningOutputDevice )
2014-03-14 14:13:41 -04:00
{
// export the GET macro for this parameter
FString ParameterList ;
2014-12-08 07:30:42 -05:00
for ( int32 ParameterIndex = 0 ; ParameterIndex < Parameters . Num ( ) ; ParameterIndex + + )
2014-03-14 14:13:41 -04:00
{
UProperty * Param = Parameters [ ParameterIndex ] ;
2014-12-11 11:49:41 -05:00
ForwardDeclarations . Add ( Param ) ;
2015-01-20 09:33:54 -05:00
2014-03-14 14:13:41 -04:00
FString EvalBaseText = TEXT ( " P_GET_ " ) ; // e.g. P_GET_STR
FString EvalModifierText ; // e.g. _REF
FString EvalParameterText ; // e.g. (UObject*,NULL)
FString TypeText ;
2014-12-08 07:30:42 -05:00
if ( Param - > ArrayDim > 1 )
2014-03-14 14:13:41 -04:00
{
EvalBaseText + = TEXT ( " ARRAY " ) ;
TypeText = Param - > GetCPPType ( ) ;
}
else
{
EvalBaseText + = Param - > GetCPPMacroType ( TypeText ) ;
}
2015-03-27 18:10:52 -04:00
FUHTStringBuilder ReplacementText ;
ReplacementText + = TypeText ;
2014-03-14 14:13:41 -04:00
ApplyAlternatePropertyExportText ( Param , ReplacementText ) ;
TypeText = ReplacementText ;
FString DefaultValueText ;
2015-04-13 13:43:58 -04:00
FString ParamPrefix = TEXT ( " Z_Param_ " ) ;
2014-03-14 14:13:41 -04:00
// if this property is an out parm, add the REF tag
if ( Param - > PropertyFlags & CPF_OutParm )
{
EvalModifierText + = TEXT ( " _REF " ) ;
2015-04-13 13:43:58 -04:00
ParamPrefix + = TEXT ( " Out_ " ) ;
2014-03-14 14:13:41 -04:00
}
// if this property requires a specialization, add a comma to the type name so we can print it out easily
2014-12-08 07:30:42 -05:00
if ( TypeText ! = TEXT ( " " ) )
2014-03-14 14:13:41 -04:00
{
TypeText + = TCHAR ( ' , ' ) ;
}
FString ParamName = ParamPrefix + Param - > GetName ( ) ;
EvalParameterText = FString : : Printf ( TEXT ( " (%s%s%s) " ) , * TypeText , * ParamName , * DefaultValueText ) ;
2015-03-27 18:10:52 -04:00
RPCWrappers . Logf ( TEXT ( " \t \t %s%s%s; " ) LINE_TERMINATOR , * EvalBaseText , * EvalModifierText , * EvalParameterText ) ;
2014-03-14 14:13:41 -04:00
// add this property to the parameter list string
2014-12-08 07:30:42 -05:00
if ( ParameterList . Len ( ) )
2014-03-14 14:13:41 -04:00
{
ParameterList + = TCHAR ( ' , ' ) ;
}
{
2014-12-08 07:30:42 -05:00
UDelegateProperty * DelegateProp = Cast < UDelegateProperty > ( Param ) ;
if ( DelegateProp ! = NULL )
2014-03-14 14:13:41 -04:00
{
// For delegates, add an explicit conversion to the specific type of delegate before passing it along
2014-12-08 07:30:42 -05:00
const FString FunctionName = DelegateProp - > SignatureFunction - > GetName ( ) . LeftChop ( FString ( HEADER_GENERATED_DELEGATE_SIGNATURE_SUFFIX ) . Len ( ) ) ;
const FString CPPDelegateName = FString ( TEXT ( " F " ) ) + FunctionName ;
ParamName = FString : : Printf ( TEXT ( " %s(%s) " ) , * CPPDelegateName , * ParamName ) ;
2014-03-14 14:13:41 -04:00
}
}
{
2014-12-08 07:30:42 -05:00
UMulticastDelegateProperty * MulticastDelegateProp = Cast < UMulticastDelegateProperty > ( Param ) ;
if ( MulticastDelegateProp ! = NULL )
2014-03-14 14:13:41 -04:00
{
// For delegates, add an explicit conversion to the specific type of delegate before passing it along
2014-12-08 07:30:42 -05:00
const FString FunctionName = MulticastDelegateProp - > SignatureFunction - > GetName ( ) . LeftChop ( FString ( HEADER_GENERATED_DELEGATE_SIGNATURE_SUFFIX ) . Len ( ) ) ;
const FString CPPDelegateName = FString ( TEXT ( " F " ) ) + FunctionName ;
ParamName = FString : : Printf ( TEXT ( " %s(%s) " ) , * CPPDelegateName , * ParamName ) ;
2014-03-14 14:13:41 -04:00
}
}
2014-08-12 08:51:25 -04:00
UByteProperty * ByteProp = Cast < UByteProperty > ( Param ) ;
if ( ByteProp & & ByteProp - > Enum )
2014-03-14 14:13:41 -04:00
{
// For enums, add an explicit conversion
if ( ! ( ByteProp - > PropertyFlags & CPF_OutParm ) )
{
2014-12-08 07:30:42 -05:00
ParamName = FString : : Printf ( TEXT ( " %s(%s) " ) , * ByteProp - > Enum - > CppType , * ParamName ) ;
2014-03-14 14:13:41 -04:00
}
else
{
2014-12-15 15:29:48 -05:00
if ( ByteProp - > Enum - > GetCppForm ( ) = = UEnum : : ECppForm : : EnumClass )
{
// If we're an enum class don't require the wrapper
ParamName = FString : : Printf ( TEXT ( " (%s&)(%s) " ) , * ByteProp - > Enum - > CppType , * ParamName ) ;
}
else
{
ParamName = FString : : Printf ( TEXT ( " (TEnumAsByte<%s>&)(%s) " ) , * ByteProp - > Enum - > CppType , * ParamName ) ;
}
2014-03-14 14:13:41 -04:00
}
}
ParameterList + = ParamName ;
}
2015-03-27 18:10:52 -04:00
RPCWrappers + = TEXT ( " \t \t P_FINISH; " ) LINE_TERMINATOR ;
2014-03-14 14:13:41 -04:00
2014-12-11 11:49:41 -05:00
const auto DeprecationPushString = TEXT ( " PRAGMA_ENABLE_DEPRECATION_WARNINGS " ) LINE_TERMINATOR ;
const auto DeprecationPopString = TEXT ( " PRAGMA_POP " ) LINE_TERMINATOR ;
auto ClassRange = ClassDefinitionRange ( ) ;
2015-01-20 09:33:54 -05:00
if ( ClassDefinitionRanges . Contains ( Function - > GetOwnerClass ( ) ) )
2014-12-11 11:49:41 -05:00
{
2015-01-20 09:33:54 -05:00
ClassRange = ClassDefinitionRanges [ Function - > GetOwnerClass ( ) ] ;
2014-12-11 11:49:41 -05:00
}
auto ClassStart = ClassRange . Start ;
auto ClassEnd = ClassRange . End ;
auto ClassDefinition = FString ( ClassEnd - ClassStart , ClassStart ) ;
2015-01-20 09:33:54 -05:00
auto ClassName = Function - > GetOwnerClass ( ) - > GetName ( ) ;
2014-12-11 11:49:41 -05:00
auto FunctionName = Function - > GetName ( ) ;
2015-04-10 06:02:22 -04:00
bool bHasImplementation = HasIdentifierExactMatch ( ClassDefinition , FunctionData . CppImplName ) ;
bool bHasValidate = HasIdentifierExactMatch ( ClassDefinition , FunctionData . CppValidationImplName ) ;
2014-12-11 11:49:41 -05:00
auto bShouldEnableImplementationDeprecation =
// Enable deprecation warnings only if GENERATED_BODY is used inside class or interface (not GENERATED_UCLASS_BODY etc.)
ClassRange . bHasGeneratedBody
2015-02-06 09:54:41 -05:00
// and implementation function is called, but not the one declared by user
& & ( FunctionData . CppImplName ! = FunctionName & & ! bHasImplementation ) ;
2014-12-11 11:49:41 -05:00
auto bShouldEnableValidateDeprecation =
// Enable deprecation warnings only if GENERATED_BODY is used inside class or interface (not GENERATED_UCLASS_BODY etc.)
ClassRange . bHasGeneratedBody
2015-02-06 09:54:41 -05:00
// and validation function is called
& & ( FunctionData . FunctionFlags & FUNC_NetValidate ) & & ! bHasValidate ;
2014-12-11 11:49:41 -05:00
//Emit warning here if necessary
2015-03-27 18:10:52 -04:00
FUHTStringBuilder FunctionDeclaration ;
2014-12-11 11:49:41 -05:00
ExportNativeFunctionHeader ( FunctionData , FunctionDeclaration , EExportFunctionType : : Function , EExportFunctionHeaderStyle : : Declaration ) ;
FunctionDeclaration . Trim ( ) ;
2014-03-14 14:13:41 -04:00
// Call the validate function if there is one
2014-12-08 07:30:42 -05:00
if ( ! ( FunctionData . FunctionExportFlags & FUNCEXPORT_CppStatic ) & & ( FunctionData . FunctionFlags & FUNC_NetValidate ) )
2014-03-14 14:13:41 -04:00
{
2015-03-27 18:10:52 -04:00
RPCWrappers . Logf ( TEXT ( " \t \t if (!this->%s(%s)) " ) LINE_TERMINATOR , * FunctionData . CppValidationImplName , * ParameterList ) ;
RPCWrappers . Logf ( TEXT ( " \t \t { " ) LINE_TERMINATOR ) ;
RPCWrappers . Logf ( TEXT ( " \t \t \t RPC_ValidateFailed(TEXT( \" %s \" )); " ) LINE_TERMINATOR , * FunctionData . CppValidationImplName ) ;
RPCWrappers . Logf ( TEXT ( " \t \t \t return; " ) LINE_TERMINATOR ) ; // If we got here, the validation function check failed
RPCWrappers . Logf ( TEXT ( " \t \t } " ) LINE_TERMINATOR ) ;
2014-03-14 14:13:41 -04:00
}
// write out the return value
2015-03-27 18:10:52 -04:00
RPCWrappers . Log ( TEXT ( " \t \t " ) ) ;
2014-12-08 07:30:42 -05:00
if ( Return ! = NULL )
2014-03-14 14:13:41 -04:00
{
FString ReturnType , ReturnExtendedType ;
2014-12-11 11:49:41 -05:00
ForwardDeclarations . Add ( Return ) ;
2014-03-14 14:13:41 -04:00
ReturnType = Return - > GetCPPType ( & ReturnExtendedType ) ;
2015-03-27 18:10:52 -04:00
FUHTStringBuilder ReplacementText ;
ReplacementText + = ReturnType ;
2014-03-14 14:13:41 -04:00
ApplyAlternatePropertyExportText ( Return , ReplacementText ) ;
ReturnType = ReplacementText ;
2015-04-13 13:43:58 -04:00
RPCWrappers . Logf ( TEXT ( " *(%s%s*) " ) TEXT ( PREPROCESSOR_TO_STRING ( RESULT_PARAM ) ) TEXT ( " = " ) , * ReturnType , * ReturnExtendedType ) ;
2014-03-14 14:13:41 -04:00
}
// export the call to the C++ version
if ( FunctionData . FunctionExportFlags & FUNCEXPORT_CppStatic )
{
2015-03-27 18:10:52 -04:00
RPCWrappers . Logf ( TEXT ( " %s::%s(%s); " ) LINE_TERMINATOR , NameLookupCPP . GetNameCPP ( Function - > GetOwnerClass ( ) ) , * FunctionData . CppImplName , * ParameterList ) ;
2014-03-14 14:13:41 -04:00
}
else
{
2015-03-27 18:10:52 -04:00
RPCWrappers . Logf ( TEXT ( " this->%s(%s); " ) LINE_TERMINATOR , * FunctionData . CppImplName , * ParameterList ) ;
2014-03-14 14:13:41 -04:00
}
}
2014-12-08 07:30:42 -05:00
FString FNativeClassHeaderGenerator : : GetFunctionParameterString ( UFunction * Function )
{
FString ParameterList ;
2015-03-27 18:10:52 -04:00
FUHTStringBuilder PropertyText ;
2014-12-08 07:30:42 -05:00
for ( auto Property : TFieldRange < UProperty > ( Function ) )
{
2014-12-11 11:49:41 -05:00
ForwardDeclarations . Add ( Property ) ;
2014-12-08 07:30:42 -05:00
if ( ( Property - > PropertyFlags & ( CPF_Parm | CPF_ReturnParm ) ) ! = CPF_Parm )
{
break ;
}
if ( ParameterList . Len ( ) )
{
ParameterList + = TEXT ( " , " ) ;
}
auto Dim = GArrayDimensions . Find ( Property ) ;
2014-12-11 16:29:40 -05:00
Property - > ExportCppDeclaration ( PropertyText , EExportedDeclaration : : Parameter , Dim ? * * Dim : NULL , 0 , true ) ;
2014-12-08 07:30:42 -05:00
ApplyAlternatePropertyExportText ( Property , PropertyText ) ;
ParameterList + = PropertyText ;
2015-03-27 18:10:52 -04:00
PropertyText . Reset ( ) ;
2014-12-08 07:30:42 -05:00
}
return ParameterList ;
}
2015-01-20 09:33:54 -05:00
void FNativeClassHeaderGenerator : : ExportNativeFunctions ( FUnrealSourceFile & SourceFile , UClass * Class , FClassMetaData * ClassData )
2014-03-14 14:13:41 -04:00
{
2015-03-27 18:10:52 -04:00
FUHTStringBuilder RPCWrappers ;
2015-04-10 06:02:22 -04:00
FUHTStringBuilder AutogeneratedBlueprintFunctionDeclarations ;
FUHTStringBuilder AutogeneratedBlueprintFunctionDeclarationsOnlyNotDeclared ;
auto ClassName = Class - > GetName ( ) ;
2014-03-14 14:13:41 -04:00
2014-12-11 11:49:41 -05:00
auto ClassRange = ClassDefinitionRange ( ) ;
2015-01-20 09:33:54 -05:00
if ( ClassDefinitionRanges . Contains ( Class ) )
2014-12-11 11:49:41 -05:00
{
2015-01-20 09:33:54 -05:00
ClassRange = ClassDefinitionRanges [ Class ] ;
2014-12-11 11:49:41 -05:00
}
2014-03-14 14:13:41 -04:00
// export the C++ stubs
2015-01-20 09:33:54 -05:00
for ( TFieldIterator < UFunction > FunctionIt ( Class , EFieldIteratorFlags : : ExcludeSuper ) ; FunctionIt ; + + FunctionIt )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
UFunction * Function = * FunctionIt ;
if ( ! ( Function - > FunctionFlags & FUNC_Native ) )
{
continue ;
}
auto * CompilerInfo = FFunctionData : : FindForFunction ( Function ) ;
2014-12-08 07:30:42 -05:00
const FFuncInfo & FunctionData = CompilerInfo - > GetFunctionData ( ) ;
// Custom thunks don't get any C++ stub function generated
if ( FunctionData . FunctionExportFlags & FUNCEXPORT_CustomThunk )
2015-01-20 09:33:54 -05:00
{
2014-12-08 07:30:42 -05:00
continue ;
2015-01-20 09:33:54 -05:00
}
2014-12-08 07:30:42 -05:00
2015-03-27 18:10:52 -04:00
FUHTStringBuilder & DestinationForDecl = RPCWrappers ;
2014-12-08 07:30:42 -05:00
// Should we emit these to RPC wrappers or just ignore them?
const bool bWillBeProgrammerTyped = FunctionData . CppImplName = = Function - > GetName ( ) ;
if ( ! bWillBeProgrammerTyped )
2014-03-14 14:13:41 -04:00
{
2014-12-11 11:49:41 -05:00
auto ClassStart = ClassRange . Start ;
auto ClassEnd = ClassRange . End ;
auto ClassDefinition = FString ( ClassEnd - ClassStart , ClassStart ) ;
auto FunctionName = Function - > GetName ( ) ;
2015-04-20 06:19:21 -04:00
int32 ClassDefinitionStartPosition = ClassStart - * SourceFile . GetContent ( ) ;
2014-12-11 11:49:41 -05:00
2015-04-20 06:19:21 -04:00
int32 ImplementationPosition = FindIdentifierExactMatch ( ClassDefinition , FunctionData . CppImplName ) ;
if ( ImplementationPosition ! = INDEX_NONE )
{
ImplementationPosition + = ClassDefinitionStartPosition ;
}
int32 ValidatePosition = FindIdentifierExactMatch ( ClassDefinition , FunctionData . CppValidationImplName ) ;
if ( ValidatePosition ! = INDEX_NONE )
{
ValidatePosition + = ClassDefinitionStartPosition ;
}
bool bHasImplementation = ImplementationPosition ! = INDEX_NONE ;
bool bHasValidate = ValidatePosition ! = INDEX_NONE ;
2014-12-11 11:49:41 -05:00
//Emit warning here if necessary
2015-03-27 18:10:52 -04:00
FUHTStringBuilder FunctionDeclaration ;
2014-12-11 11:49:41 -05:00
ExportNativeFunctionHeader ( FunctionData , FunctionDeclaration , EExportFunctionType : : Function , EExportFunctionHeaderStyle : : Declaration ) ;
FunctionDeclaration . Log ( TEXT ( " ; \r \n " ) ) ;
2014-03-14 14:13:41 -04:00
// Declare validation function if needed
2014-12-08 07:30:42 -05:00
if ( FunctionData . FunctionFlags & FUNC_NetValidate )
2014-03-14 14:13:41 -04:00
{
2014-12-08 07:30:42 -05:00
FString ParameterList = GetFunctionParameterString ( Function ) ;
2014-08-19 09:44:20 -04:00
2014-12-08 07:30:42 -05:00
auto Virtual = ( ! FunctionData . FunctionReference - > HasAnyFunctionFlags ( FUNC_Static ) & & ! ( FunctionData . FunctionExportFlags & FUNCEXPORT_Final ) ) ? TEXT ( " virtual " ) : TEXT ( " " ) ;
2015-03-17 05:19:11 -04:00
FStringOutputDevice ValidDecl ;
ValidDecl . Logf ( TEXT ( " \t %s bool %s(%s); \r \n " ) , Virtual , * FunctionData . CppValidationImplName , * ParameterList ) ;
AutogeneratedBlueprintFunctionDeclarations . Log ( * ValidDecl ) ;
2014-12-11 11:49:41 -05:00
if ( ! bHasValidate )
{
2015-03-17 05:19:11 -04:00
AutogeneratedBlueprintFunctionDeclarationsOnlyNotDeclared . Logf ( * ValidDecl ) ;
2014-12-11 11:49:41 -05:00
}
2014-03-14 14:13:41 -04:00
}
2014-12-11 11:49:41 -05:00
AutogeneratedBlueprintFunctionDeclarations . Log ( * FunctionDeclaration ) ;
2015-02-06 09:54:41 -05:00
if ( ( FunctionData . CppImplName ! = FunctionName & & ! bHasImplementation ) )
2014-03-14 14:13:41 -04:00
{
2014-12-11 11:49:41 -05:00
AutogeneratedBlueprintFunctionDeclarationsOnlyNotDeclared . Log ( * FunctionDeclaration ) ;
2014-03-14 14:13:41 -04:00
}
2014-12-11 11:49:41 -05:00
2015-04-10 06:02:22 -04:00
// Versions that skip function autodeclaration throw an error when a function is missing.
if ( ( SourceFile . GetGeneratedCodeVersionForStruct ( Class ) > EGeneratedCodeVersion : : V1 ) & & ClassRange . bHasGeneratedBody )
{
2015-04-20 06:19:21 -04:00
auto Name = Class - > HasAnyClassFlags ( CLASS_Interface ) ? * ( FString ( TEXT ( " I " ) ) + ClassName ) : NameLookupCPP . GetNameCPP ( Class ) ;
CheckRPCFunctions ( FunctionData , Name , ImplementationPosition , ValidatePosition , SourceFile ) ;
2015-04-10 06:02:22 -04:00
}
2014-03-14 14:13:41 -04:00
}
2014-12-08 07:30:42 -05:00
if ( bMultiLineUFUNCTION )
{
RPCWrappers . Log ( TEXT ( " \r \n " ) ) ;
}
// if this function was originally declared in a base class, and it isn't a static function,
// only the C++ function header will be exported
if ( ! ShouldExportFunction ( Function ) )
{
continue ;
}
// export the script wrappers
2015-03-27 18:10:52 -04:00
RPCWrappers . Logf ( TEXT ( " \t DECLARE_FUNCTION(%s) " ) , * FunctionData . UnMarshallAndCallName ) ;
RPCWrappers + = LINE_TERMINATOR TEXT ( " \t { " ) LINE_TERMINATOR ;
2014-12-08 07:30:42 -05:00
auto Parameters = GetFunctionParmsAndReturn ( FunctionData . FunctionReference ) ;
2015-03-17 05:19:11 -04:00
ExportFunctionThunk ( RPCWrappers , Function , FunctionData , Parameters . Parms , Parameters . Return , AutogeneratedBlueprintFunctionDeclarationsOnlyNotDeclared ) ;
2014-12-08 07:30:42 -05:00
2015-03-27 18:10:52 -04:00
RPCWrappers + = TEXT ( " \t } " ) LINE_TERMINATOR ;
2014-03-14 14:13:41 -04:00
}
2015-01-20 09:33:54 -05:00
FString MacroName = SourceFile . GetGeneratedMacroName ( ClassData , TEXT ( " _RPC_WRAPPERS " ) ) ;
WriteMacro ( GeneratedHeaderText , MacroName , AutogeneratedBlueprintFunctionDeclarations + RPCWrappers ) ;
2015-03-27 18:10:52 -04:00
InClassMacroCalls . Logf ( TEXT ( " \t %s \r \n " ) , * MacroName ) ;
2014-12-08 07:30:42 -05:00
// Put static checks before RPCWrappers to get proper messages from static asserts before compiler errors.
2015-01-20 09:33:54 -05:00
FString NoPureDeclsMacroName = SourceFile . GetGeneratedMacroName ( ClassData , TEXT ( " _RPC_WRAPPERS_NO_PURE_DECLS " ) ) ;
2015-04-10 06:02:22 -04:00
if ( SourceFile . GetGeneratedCodeVersionForStruct ( Class ) > EGeneratedCodeVersion : : V1 )
{
WriteMacro ( GeneratedHeaderText , NoPureDeclsMacroName , RPCWrappers ) ;
}
else
{
WriteMacro ( GeneratedHeaderText , NoPureDeclsMacroName , AutogeneratedBlueprintFunctionDeclarationsOnlyNotDeclared + RPCWrappers ) ;
}
2015-03-27 18:10:52 -04:00
InClassNoPureDeclsMacroCalls . Logf ( TEXT ( " \t %s \r \n " ) , * NoPureDeclsMacroName ) ;
2014-03-14 14:13:41 -04:00
}
/**
* Exports the methods which trigger UnrealScript events and delegates .
*
* @ param CallbackFunctions the functions to export
*/
2015-01-20 09:33:54 -05:00
TArray < UFunction * > FNativeClassHeaderGenerator : : ExportCallbackFunctions ( FUnrealSourceFile & SourceFile , UClass * Class , FClassMetaData * ClassData )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
TArray < UFunction * > CallbackFunctions ;
2014-03-14 14:13:41 -04:00
2015-01-20 09:33:54 -05:00
for ( TFieldIterator < UFunction > FunctionIt ( Class , EFieldIteratorFlags : : ExcludeSuper ) ; FunctionIt ; + + FunctionIt )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
UFunction * Function = * FunctionIt ;
if ( ( Function - > FunctionFlags & FUNC_Event ) & & Function - > GetSuperFunction ( ) = = nullptr )
{
CallbackFunctions . Add ( Function ) ;
}
}
2015-03-27 18:10:52 -04:00
FUHTStringBuilder RPCWrappers ;
FUHTStringBuilder RPCWrappersCPP ;
2015-01-20 09:33:54 -05:00
if ( CallbackFunctions . Num ( ) = = 0 )
{
// Early out.
return CallbackFunctions ;
2014-03-14 14:13:41 -04:00
}
CallbackFunctions . Sort ( ) ;
2015-03-27 18:10:52 -04:00
FUHTStringBuilder UClassMacroContent ;
2015-01-20 09:33:54 -05:00
// export parameters structs for all events and delegates
2015-03-27 18:10:52 -04:00
ExportEventParms ( SourceFile . GetScope ( ) . Get ( ) , CallbackFunctions , UClassMacroContent , /*Indent=*/ 1 , /*bOutputConstructor=*/ true ) ;
2015-01-20 09:33:54 -05:00
FString MacroName = SourceFile . GetGeneratedMacroName ( ClassData , TEXT ( " _EVENT_PARMS " ) ) ;
WriteMacro ( GeneratedHeaderText , MacroName , UClassMacroContent ) ;
2015-03-27 18:10:52 -04:00
PrologMacroCalls . Logf ( TEXT ( " \t %s \r \n " ) , * MacroName ) ;
2015-01-20 09:33:54 -05:00
// export .proto files for any net service functions
ExportProtoMessage ( CallbackFunctions , ClassData ) ;
// export .java files for any net service functions
ExportMCPMessage ( CallbackFunctions , ClassData ) ;
for ( int32 CallbackIndex = 0 ; CallbackIndex < CallbackFunctions . Num ( ) ; CallbackIndex + + )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
UFunction * Function = CallbackFunctions [ CallbackIndex ] ;
2014-03-14 14:13:41 -04:00
// Never expecting to export delegate functions this way
2015-01-20 09:33:54 -05:00
check ( ! Function - > HasAnyFunctionFlags ( FUNC_Delegate ) ) ;
2014-03-14 14:13:41 -04:00
2015-01-20 09:33:54 -05:00
auto * CompilerInfo = FFunctionData : : FindForFunction ( Function ) ;
2014-03-14 14:13:41 -04:00
// cache the TCHAR* for a few strings we'll use a lot here
FString FunctionName = Function - > GetName ( ) ;
2015-01-20 09:33:54 -05:00
GeneratedHeaderText . Logf ( TEXT ( " extern %s FName %s_%s; " ) LINE_TERMINATOR , * GetAPIString ( ) , * API , * FunctionName ) ;
ReferencedNames . Add ( Function - > GetFName ( ) ) ;
2014-03-14 14:13:41 -04:00
const FFuncInfo & FunctionData = CompilerInfo - > GetFunctionData ( ) ;
if ( FunctionData . FunctionFlags & FUNC_NetResponse )
{
// Net response functions don't go into the VM
continue ;
}
const bool bWillBeProgrammerTyped = Function - > GetName ( ) = = FunctionData . MarshallAndCallName ;
// Emit the declaration if the programmer isn't responsible for declaring this wrapper
if ( ! bWillBeProgrammerTyped )
{
// export the line that looks like: int32 Main(const FString& Parms)
ExportNativeFunctionHeader ( FunctionData , RPCWrappers , EExportFunctionType : : Event , EExportFunctionHeaderStyle : : Declaration ) ;
RPCWrappers . Log ( TEXT ( " ; \r \n " ) ) ;
if ( bMultiLineUFUNCTION )
{
RPCWrappers . Log ( TEXT ( " \r \n " ) ) ;
}
}
// Emit the thunk implementation
ExportNativeFunctionHeader ( FunctionData , RPCWrappersCPP , EExportFunctionType : : Event , EExportFunctionHeaderStyle : : Definition ) ;
auto Parameters = GetFunctionParmsAndReturn ( FunctionData . FunctionReference ) ;
2015-01-20 09:33:54 -05:00
if ( ! ( Class - > ClassFlags & CLASS_Interface ) )
2014-03-14 14:13:41 -04:00
{
2015-03-27 18:10:52 -04:00
WriteEventFunctionPrologue ( RPCWrappersCPP , /*Indent=*/ 1 , Parameters , Function - > GetOuter ( ) , * FunctionName ) ;
2015-01-20 09:33:54 -05:00
{
// Cast away const just in case, because ProcessEvent isn't const
RPCWrappersCPP . Logf (
2015-03-27 18:10:52 -04:00
TEXT ( " \t \t %sProcessEvent(FindFunctionChecked(%s_%s),%s); \r \n " ) ,
2015-01-20 09:33:54 -05:00
( Function - > HasAllFunctionFlags ( FUNC_Const ) ) ? * FString : : Printf ( TEXT ( " const_cast<%s*>(this)-> " ) , NameLookupCPP . GetNameCPP ( Cast < UClass > ( Function - > GetOuter ( ) ) ) ) : TEXT ( " " ) ,
* API ,
* FunctionName ,
Parameters . HasParms ( ) ? TEXT ( " &Parms " ) : TEXT ( " NULL " )
) ;
}
2015-03-27 18:10:52 -04:00
WriteEventFunctionEpilogue ( RPCWrappersCPP , /*Indent=*/ 1 , Parameters , * FunctionName ) ;
2015-01-20 09:33:54 -05:00
}
else
{
2015-03-27 18:10:52 -04:00
RPCWrappersCPP + = LINE_TERMINATOR ;
RPCWrappersCPP + = TEXT ( " \t { " ) LINE_TERMINATOR ;
2015-01-20 09:33:54 -05:00
// assert if this is ever called directly
2015-03-27 18:10:52 -04:00
RPCWrappersCPP . Logf ( TEXT ( " \t \t check(0 && \" Do not directly call Event functions in Interfaces. Call Execute_%s instead. \" ); " ) LINE_TERMINATOR , * FunctionName ) ;
2015-01-20 09:33:54 -05:00
// satisfy compiler if it's expecting a return value
if ( Parameters . Return )
{
FString EventParmStructName = GetEventStructParamsName ( Function - > GetOuter ( ) , * FunctionName ) ;
2015-03-27 18:10:52 -04:00
RPCWrappersCPP . Logf ( TEXT ( " \t \t %s Parms; " ) LINE_TERMINATOR , * EventParmStructName ) ;
RPCWrappersCPP . Logf ( TEXT ( " \t \t return Parms.ReturnValue; " ) LINE_TERMINATOR ) ;
2015-01-20 09:33:54 -05:00
}
2015-03-27 18:10:52 -04:00
RPCWrappersCPP + = TEXT ( " \t } " ) LINE_TERMINATOR ;
2014-03-14 14:13:41 -04:00
}
}
2015-01-20 09:33:54 -05:00
if ( ! Class - > HasAnyClassFlags ( CLASS_NoExport ) )
2014-03-14 14:13:41 -04:00
{
GeneratedPackageCPP . Log ( * RPCWrappersCPP ) ;
}
// else drop the implementation on the floor
2015-01-20 09:33:54 -05:00
FString CallbackWrappersMacroName = SourceFile . GetGeneratedMacroName ( ClassData , TEXT ( " _CALLBACK_WRAPPERS " ) ) ;
WriteMacro ( GeneratedHeaderText , CallbackWrappersMacroName , RPCWrappers ) ;
2015-03-27 18:10:52 -04:00
InClassMacroCalls . Logf ( TEXT ( " \t %s \r \n " ) , * CallbackWrappersMacroName ) ;
InClassNoPureDeclsMacroCalls . Logf ( TEXT ( " \t %s \r \n " ) , * CallbackWrappersMacroName ) ;
2015-01-20 09:33:54 -05:00
return CallbackFunctions ;
2014-03-14 14:13:41 -04:00
}
/**
* Determines if the property has alternate export text associated with it and if so replaces the text in PropertyText with the
* alternate version . ( for example , structs or properties that specify a native type using export - text ) . Should be called immediately
* after ExportCppDeclaration ( )
*
* @ param Prop the property that is being exported
* @ param PropertyText the string containing the text exported from ExportCppDeclaration
*/
2015-03-27 18:10:52 -04:00
void FNativeClassHeaderGenerator : : ApplyAlternatePropertyExportText ( UProperty * Prop , FUHTStringBuilder & PropertyText )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
if ( ! bIsExportingForOffsetDeterminationOnly )
2014-03-14 14:13:41 -04:00
{
return ;
}
2015-01-20 09:33:54 -05:00
UDelegateProperty * DelegateProperty = Cast < UDelegateProperty > ( Prop ) ;
UMulticastDelegateProperty * MulticastDelegateProperty = Cast < UMulticastDelegateProperty > ( Prop ) ;
if ( DelegateProperty | | MulticastDelegateProperty )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
FString Original = Prop - > GetCPPType ( ) ;
FString PlaceholderOfSameSizeAndAlignemnt ;
if ( DelegateProperty )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
PlaceholderOfSameSizeAndAlignemnt = TEXT ( " FScriptDelegate " ) ;
2014-03-14 14:13:41 -04:00
}
2015-01-20 09:33:54 -05:00
else
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
PlaceholderOfSameSizeAndAlignemnt = TEXT ( " FMulticastScriptDelegate " ) ;
2014-03-14 14:13:41 -04:00
}
2015-01-20 09:33:54 -05:00
PropertyText . ReplaceInline ( * Original , * PlaceholderOfSameSizeAndAlignemnt , ESearchCase : : CaseSensitive ) ;
2014-03-14 14:13:41 -04:00
}
}
2014-04-23 20:18:11 -04:00
/**
* Sorts the list of header files being exported from a package according to their dependency on each other .
*
* @ param HeaderDependencyMap a mapping of header filenames to a list of header filenames that must be processed before that one .
* @ param SortedHeaderFilenames [ out ] receives the sorted list of header filenames .
*/
bool FNativeClassHeaderGenerator : : SortHeaderDependencyMap ( const TMap < const FString * , HeaderDependents > & HeaderDependencyMap , TArray < const FString * > & SortedHeaderFilenames ) const
{
SortedHeaderFilenames . Empty ( HeaderDependencyMap . Num ( ) ) ;
while ( SortedHeaderFilenames . Num ( ) < HeaderDependencyMap . Num ( ) )
{
bool bAddedSomething = false ;
// Find headers with no dependencies and add those to the list.
for ( auto It = HeaderDependencyMap . CreateConstIterator ( ) ; It ; + + It )
{
auto Header = It - > Key ;
if ( SortedHeaderFilenames . Contains ( Header ) )
continue ;
bool bHasRemainingDependencies = false ;
for ( auto It2 = It - > Value . CreateConstIterator ( ) ; It2 ; + + It2 )
{
if ( ! SortedHeaderFilenames . Contains ( * It2 ) )
{
bHasRemainingDependencies = true ;
break ;
}
}
if ( ! bHasRemainingDependencies )
{
// Add it to the list.
SortedHeaderFilenames . AddUnique ( Header ) ;
bAddedSomething = true ;
}
}
// Circular dependency error?
if ( ! bAddedSomething )
return false ;
}
return true ;
}
2014-03-14 14:13:41 -04:00
bool FNativeClassHeaderGenerator : : FindInterDependency ( TMap < const FString * , HeaderDependents > & HeaderDependencyMap , const FString * Header , const FString * & OutHeader1 , const FString * & OutHeader2 )
{
TSet < const FString * > VisitedHeaders ;
return FindInterDependencyRecursive ( HeaderDependencyMap , Header , VisitedHeaders , OutHeader1 , OutHeader2 ) ;
}
/**
* Finds to headers that are dependent on each other .
*
* @ param HeaderDependencyMap A map of headers and their dependencies . Each header is represented as an index into a TArray of the actual filename strings .
* @ param HeaderIndex A header to scan for any inter - dependency .
* @ param VisitedHeaders Must be filled with false values before the first call ( must be large enough to be indexed by all headers ) .
* @ param OutHeader1 [ out ] Receives the first inter - dependent header index .
* @ param OutHeader2 [ out ] Receives the second inter - dependent header index .
* @ return true if an inter - dependency was found .
*/
bool FNativeClassHeaderGenerator : : FindInterDependencyRecursive ( TMap < const FString * , HeaderDependents > & HeaderDependencyMap , const FString * Header , TSet < const FString * > & VisitedHeaders , const FString * & OutHeader1 , const FString * & OutHeader2 )
{
VisitedHeaders . Add ( Header ) ;
for ( auto It = HeaderDependencyMap [ Header ] . CreateConstIterator ( ) ; It ; + + It )
{
auto DependentHeader = * It ;
if ( VisitedHeaders . Contains ( DependentHeader ) )
{
OutHeader1 = Header ;
OutHeader2 = DependentHeader ;
return true ;
}
if ( FindInterDependencyRecursive ( HeaderDependencyMap , DependentHeader , VisitedHeaders , OutHeader1 , OutHeader2 ) )
{
return true ;
}
}
return false ;
}
2015-01-20 09:33:54 -05:00
bool IsExportClass ( FClass * Class )
2014-04-23 20:18:11 -04:00
{
2015-01-20 09:33:54 -05:00
return Class - > HasAnyClassFlags ( CLASS_Native ) & & ! Class - > HasAnyClassFlags ( CLASS_NoExport | CLASS_Intrinsic ) ;
2014-04-23 20:18:11 -04:00
}
2015-03-27 18:10:52 -04:00
FUHTStringBuilder & FNativeClassHeaderGenerator : : GetGeneratedFunctionTextDevice ( )
2015-01-16 05:02:48 -05:00
{
int32 MaxLinesPerCpp = 30000 ;
2015-04-14 08:03:34 -04:00
if ( ( GeneratedFunctionBodyTextSplit . Num ( ) = = 0 ) | | ( GeneratedFunctionBodyTextSplit [ GeneratedFunctionBodyTextSplit . Num ( ) - 1 ] - > GetLineCount ( ) > MaxLinesPerCpp ) )
2015-01-16 05:02:48 -05:00
{
2015-04-14 08:03:34 -04:00
GeneratedFunctionBodyTextSplit . Add ( TUniqueObj < FUHTStringBuilderLineCounter > ( ) ) ;
2015-01-16 05:02:48 -05:00
}
2015-04-14 08:03:34 -04:00
return GeneratedFunctionBodyTextSplit [ GeneratedFunctionBodyTextSplit . Num ( ) - 1 ] . Get ( ) ;
2015-01-16 05:02:48 -05:00
}
2014-03-14 14:13:41 -04:00
// Constructor.
2015-03-02 06:44:04 -05:00
FNativeClassHeaderGenerator : : FNativeClassHeaderGenerator (
UPackage * InPackage ,
const TArray < FUnrealSourceFile * > & SourceFiles ,
FClasses & AllClasses ,
bool InAllowSaveExportedHeaders
# if WITH_HOT_RELOAD_CTORS
2015-04-22 14:15:56 -04:00
, bool bInExportVTableConstructors
2015-03-02 06:44:04 -05:00
# endif // WITH_HOT_RELOAD_CTORS
)
2015-01-20 09:33:54 -05:00
: API ( FPackageName : : GetShortName ( InPackage ) . ToUpper ( ) )
2014-03-14 14:13:41 -04:00
, Package ( InPackage )
, bIsExportingForOffsetDeterminationOnly ( false )
, bAllowSaveExportedHeaders ( InAllowSaveExportedHeaders )
, bFailIfGeneratedCodeChanges ( false )
2015-03-02 06:44:04 -05:00
# if WITH_HOT_RELOAD_CTORS
2015-04-22 14:15:56 -04:00
, bExportVTableConstructors ( bInExportVTableConstructors )
2015-03-02 06:44:04 -05:00
# endif // WITH_HOT_RELOAD_CTORS
2014-03-14 14:13:41 -04:00
{
const FString PackageName = FPackageName : : GetShortName ( Package ) ;
2014-04-23 20:18:11 -04:00
2014-03-14 14:13:41 -04:00
GeneratedCPPFilenameBase = PackageName + TEXT ( " .generated " ) ;
GeneratedProtoFilenameBase = PackageName + TEXT ( " .generated " ) ;
GeneratedMCPFilenameBase = PackageName + TEXT ( " .generated " ) ;
bFailIfGeneratedCodeChanges = FParse : : Param ( FCommandLine : : Get ( ) , TEXT ( " FailIfGeneratedCodeChanges " ) ) ;
2015-01-20 09:33:54 -05:00
bool bPackageHasAnyExportClasses = AllClasses . GetClassesInPackage ( Package ) . ContainsByPredicate ( IsExportClass ) ;
2014-03-14 14:13:41 -04:00
bool bHasNamesForExport = false ;
2015-03-27 18:10:52 -04:00
TempHeaderPaths . Reset ( ) ;
PackageHeaderPaths . Reset ( ) ;
2014-04-23 20:18:55 -04:00
2014-03-14 14:13:41 -04:00
// Reset header generation output strings
2015-03-27 18:10:52 -04:00
GeneratedPackageCPP . Reset ( ) ;
GeneratedProtoText . Reset ( ) ;
GeneratedMCPText . Reset ( ) ;
CrossModuleGeneratedFunctionDeclarations . Reset ( ) ;
UniqueCrossModuleReferences . Empty ( UniqueCrossModuleReferences . Num ( ) ) ;
GeneratedFunctionDeclarations . Reset ( ) ;
GeneratedFunctionBodyTextSplit . Reset ( ) ;
ListOfPublicClassesUObjectHeaderModuleIncludes . Reset ( ) ;
2014-04-23 20:18:55 -04:00
2015-01-20 09:33:54 -05:00
if ( bPackageHasAnyExportClasses )
2014-03-14 14:13:41 -04:00
{
FString PkgDir ;
FString GeneratedIncludeDirectory ;
2014-09-18 04:05:01 -04:00
if ( FindPackageLocation ( * PackageName , PkgDir , GeneratedIncludeDirectory ) = = false )
2014-03-14 14:13:41 -04:00
{
UE_LOG ( LogCompile , Error , TEXT ( " Failed to find path for package %s " ) , * PackageName ) ;
}
2014-04-28 05:03:10 -04:00
FString ClassesHeaderName = PackageName + TEXT ( " Classes.h " ) ;
2014-04-23 20:18:55 -04:00
ClassesHeaderPath = GeneratedIncludeDirectory / ClassesHeaderName ;
2014-03-14 14:13:41 -04:00
int32 ClassCount = 0 ;
2015-01-20 09:33:54 -05:00
for ( auto * SourceFile : SourceFiles )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
for ( auto * Class : SourceFile - > GetDefinedClasses ( ) )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
if ( Class - > HasAnyClassFlags ( CLASS_Native ) )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
if ( GTypeDefinitionInfoMap . Contains ( Class ) & & ! Class - > HasAnyClassFlags ( CLASS_NoExport ) )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
ClassCount + + ;
2014-03-14 14:13:41 -04:00
Class - > UnMark ( OBJECTMARK_TagImp ) ;
Class - > Mark ( OBJECTMARK_TagExp ) ;
}
}
2015-01-20 09:33:54 -05:00
else
{
Class - > UnMark ( EObjectMark ( OBJECTMARK_TagImp | OBJECTMARK_TagExp ) ) ;
}
2014-03-14 14:13:41 -04:00
}
}
2014-04-28 05:03:10 -04:00
if ( ClassCount ! = 0 )
2014-03-14 14:13:41 -04:00
{
2014-04-28 05:03:10 -04:00
ClassesHeaders . Add ( ClassesHeaderName ) ;
2014-04-23 20:18:11 -04:00
2015-03-27 18:10:52 -04:00
ListOfPublicHeaderGroupIncludes . Reset ( ) ;
ListOfAllUObjectHeaderIncludes . Reset ( ) ;
OriginalHeader . Reset ( ) ;
PreHeaderText . Reset ( ) ;
2014-04-23 20:18:55 -04:00
2014-04-28 05:03:10 -04:00
// Load the original header file into memory
FFileHelper : : LoadFileToString ( OriginalHeader , * ClassesHeaderPath ) ;
2014-04-23 20:18:11 -04:00
2014-04-28 05:03:10 -04:00
// Write the classes and enums header prefixes.
2014-04-23 20:18:11 -04:00
2014-04-28 05:03:10 -04:00
PreHeaderText . Logf (
2014-12-07 19:09:38 -05:00
TEXT ( " // Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. \r \n " )
2014-04-28 05:03:10 -04:00
TEXT ( " /*=========================================================================== \r \n " )
TEXT ( " C++ class boilerplate exported from UnrealHeaderTool. \r \n " )
TEXT ( " This is automatically generated by the tools. \r \n " )
TEXT ( " DO NOT modify this manually! Edit the corresponding .h files instead! \r \n " )
TEXT ( " ===========================================================================*/ \r \n " )
TEXT ( " #pragma once \r \n " )
TEXT ( " \r \n " )
) ;
2014-04-23 20:18:11 -04:00
2014-04-28 05:03:10 -04:00
// if a global auto-include file exists, generate a line to have that file included
FString GlobalAutoIncludeFilename = PackageName + TEXT ( " GlobalIncludes.h " ) ;
const FString StandardHeaderFileLocation = PkgDir / TEXT ( " Public " ) ;
if ( IFileManager : : Get ( ) . FileSize ( * ( StandardHeaderFileLocation / GlobalAutoIncludeFilename ) ) > 0 )
2014-04-23 20:18:11 -04:00
{
2014-04-28 05:03:10 -04:00
PreHeaderText . Logf ( TEXT ( " #include \" %s \" \r \n \r \n " ) , * GlobalAutoIncludeFilename ) ;
2014-04-23 20:18:11 -04:00
}
2014-04-28 05:03:10 -04:00
// Export an include line for each header
2015-01-20 09:33:54 -05:00
for ( auto * SourceFile : SourceFiles )
2014-04-28 05:03:10 -04:00
{
2015-01-20 09:33:54 -05:00
ExportSourceFileHeader ( AllClasses , SourceFile ) ;
2014-04-28 05:03:10 -04:00
}
// build the full header file out of its pieces
const FString FullClassesHeader = FString : : Printf (
TEXT ( " %s \r \n %s " ) ,
* PreHeaderText ,
2015-01-20 09:33:54 -05:00
* GetListOfPublicHeaderGroupIncludesString ( InPackage )
2014-04-28 05:03:10 -04:00
) ;
// Save the classes header if it has changed.
SaveHeaderIfChanged ( * ClassesHeaderPath , * FullClassesHeader ) ;
}
2014-03-14 14:13:41 -04:00
}
2015-01-20 09:33:54 -05:00
if ( ! bPackageHasAnyExportClasses )
2014-03-14 14:13:41 -04:00
{
// If no headers are generated, check if there's any no export classes that need to have the inl file generated.
2015-01-20 09:33:54 -05:00
for ( auto * SourceFile : SourceFiles )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
ExportSourceFileHeader ( AllClasses , SourceFile ) ;
2014-03-14 14:13:41 -04:00
}
}
// now export the names for the functions in this package
// notice we always export this file (as opposed to only exporting if we have any marked names)
// because there would be no way to know when the file was created otherwise
2014-04-28 05:03:10 -04:00
// Export .generated.cpp
ExportGeneratedCPP ( ) ;
2014-03-14 14:13:41 -04:00
ExportGeneratedProto ( ) ;
ExportGeneratedMCP ( ) ;
// Export all changed headers from their temp files to the .h files
ExportUpdatedHeaders ( PackageName ) ;
// Delete stale *.generated.h files
DeleteUnusedGeneratedHeaders ( ) ;
}
void FNativeClassHeaderGenerator : : DeleteUnusedGeneratedHeaders ( )
{
TArray < FString > AllIntermediateFolders ;
2014-04-23 20:18:55 -04:00
for ( const auto & PackageHeader : PackageHeaderPaths )
2014-03-14 14:13:41 -04:00
{
2014-04-23 20:18:55 -04:00
const FString IntermediatePath = FPaths : : GetPath ( PackageHeader ) ;
2014-03-14 14:13:41 -04:00
if ( AllIntermediateFolders . Contains ( IntermediatePath ) )
continue ;
AllIntermediateFolders . Add ( IntermediatePath ) ;
TArray < FString > AllHeaders ;
IFileManager : : Get ( ) . FindFiles ( AllHeaders , * ( IntermediatePath / TEXT ( " *.generated.h " ) ) , true , false ) ;
2014-04-23 20:18:55 -04:00
for ( const auto & Header : AllHeaders )
2014-03-14 14:13:41 -04:00
{
2014-04-23 20:18:55 -04:00
const FString HeaderPath = IntermediatePath / Header ;
2014-03-14 14:13:41 -04:00
if ( PackageHeaderPaths . Contains ( HeaderPath ) )
continue ;
// Check intrinsic classes. Get the class name from file name by removing .generated.h.
const FString HeaderFilename = FPaths : : GetBaseFilename ( HeaderPath ) ;
const int32 GeneratedIndex = HeaderFilename . Find ( TEXT ( " .generated " ) , ESearchCase : : IgnoreCase , ESearchDir : : FromEnd ) ;
const FString ClassName = HeaderFilename . Mid ( 0 , GeneratedIndex ) ;
UClass * IntrinsicClass = FindObject < UClass > ( ANY_PACKAGE , * ClassName ) ;
if ( ! IntrinsicClass | | ! IntrinsicClass - > HasAnyClassFlags ( CLASS_Intrinsic ) )
{
IFileManager : : Get ( ) . Delete ( * HeaderPath ) ;
}
}
}
}
2014-04-23 18:36:17 -04:00
/**
* Dirty hack global variable to allow different result codes passed through
* exceptions . Needs to be fixed in future versions of UHT .
*/
ECompilationResult : : Type GCompilationResult = ECompilationResult : : OtherCompilationError ;
2014-03-14 14:13:41 -04:00
bool FNativeClassHeaderGenerator : : SaveHeaderIfChanged ( const TCHAR * HeaderPath , const TCHAR * InNewHeaderContents )
{
if ( ! bAllowSaveExportedHeaders )
{
// Return false indicating that the header did not need updating
return false ;
}
FString Tabified = Tabify ( InNewHeaderContents ) ;
const TCHAR * NewHeaderContents = * Tabified ;
static bool bTestedCmdLine = false ;
if ( ! bTestedCmdLine )
{
bTestedCmdLine = true ;
2015-03-27 17:16:51 -04:00
const FString ReferenceGeneratedCodePath = FString ( FPaths : : GameSavedDir ( ) ) / TEXT ( " ReferenceGeneratedCode/ " ) ;
const FString VerifyGeneratedCodePath = FString ( FPaths : : GameSavedDir ( ) ) / TEXT ( " VerifyGeneratedCode/ " ) ;
if ( FParse : : Param ( FCommandLine : : Get ( ) , TEXT ( " WRITEREF " ) ) )
2014-03-14 14:13:41 -04:00
{
bWriteContents = true ;
2015-03-27 17:16:51 -04:00
UE_LOG ( LogCompile , Log , TEXT ( " ********************************* Writing reference generated code to %s. " ) , * ReferenceGeneratedCodePath ) ;
2014-03-14 14:13:41 -04:00
UE_LOG ( LogCompile , Log , TEXT ( " ********************************* Deleting all files in ReferenceGeneratedCode. " ) ) ;
2015-03-27 17:16:51 -04:00
IFileManager : : Get ( ) . DeleteDirectory ( * ReferenceGeneratedCodePath , false , true ) ;
IFileManager : : Get ( ) . MakeDirectory ( * ReferenceGeneratedCodePath ) ;
2014-03-14 14:13:41 -04:00
}
2015-03-27 17:16:51 -04:00
else if ( FParse : : Param ( FCommandLine : : Get ( ) , TEXT ( " VERIFYREF " ) ) )
2014-03-14 14:13:41 -04:00
{
bVerifyContents = true ;
2015-03-27 17:16:51 -04:00
UE_LOG ( LogCompile , Log , TEXT ( " ********************************* Writing generated code to %s and comparing to %s " ) , * VerifyGeneratedCodePath , * ReferenceGeneratedCodePath ) ;
2014-03-14 14:13:41 -04:00
UE_LOG ( LogCompile , Log , TEXT ( " ********************************* Deleting all files in VerifyGeneratedCode. " ) ) ;
2015-03-27 17:16:51 -04:00
IFileManager : : Get ( ) . DeleteDirectory ( * VerifyGeneratedCodePath , false , true ) ;
IFileManager : : Get ( ) . MakeDirectory ( * VerifyGeneratedCodePath ) ;
2014-03-14 14:13:41 -04:00
}
}
if ( bWriteContents | | bVerifyContents )
{
2014-04-23 20:18:55 -04:00
FString Ref = FString ( FPaths : : GameSavedDir ( ) ) / TEXT ( " ReferenceGeneratedCode " ) / FPaths : : GetCleanFilename ( HeaderPath ) ;
2014-03-14 14:13:41 -04:00
FString Verify = FString ( FPaths : : GameSavedDir ( ) ) / TEXT ( " VerifyGeneratedCode " ) / FPaths : : GetCleanFilename ( HeaderPath ) ;
if ( bWriteContents )
{
int32 i ;
for ( i = 0 ; i < 10 ; i + + )
{
if ( FFileHelper : : SaveStringToFile ( NewHeaderContents , * Ref ) )
{
break ;
}
FPlatformProcess : : Sleep ( 1.0f ) ; // I don't know why this fails after we delete the directory
}
check ( i < 10 ) ;
}
else
{
int32 i ;
for ( i = 0 ; i < 10 ; i + + )
{
if ( FFileHelper : : SaveStringToFile ( NewHeaderContents , * Verify ) )
{
break ;
}
FPlatformProcess : : Sleep ( 1.0f ) ; // I don't know why this fails after we delete the directory
}
check ( i < 10 ) ;
FString RefHeader ;
FString Message ;
if ( ! FFileHelper : : LoadFileToString ( RefHeader , * Ref ) )
{
Message = FString : : Printf ( TEXT ( " ********************************* %s appears to be a new generated file. " ) , * FPaths : : GetCleanFilename ( HeaderPath ) ) ;
}
else
{
if ( FCString : : Strcmp ( NewHeaderContents , * RefHeader ) ! = 0 )
{
Message = FString : : Printf ( TEXT ( " ********************************* %s has changed. " ) , * FPaths : : GetCleanFilename ( HeaderPath ) ) ;
}
}
if ( Message . Len ( ) )
{
UE_LOG ( LogCompile , Log , TEXT ( " %s " ) , * Message ) ;
ChangeMessages . AddUnique ( Message ) ;
}
}
}
FString OriginalHeaderLocal ;
FFileHelper : : LoadFileToString ( OriginalHeaderLocal , HeaderPath ) ;
const bool bHasChanged = OriginalHeaderLocal . Len ( ) = = 0 | | FCString : : Strcmp ( * OriginalHeaderLocal , NewHeaderContents ) ;
if ( bHasChanged )
{
if ( bFailIfGeneratedCodeChanges )
{
FString ConflictPath = FString ( HeaderPath ) + TEXT ( " .conflict " ) ;
FFileHelper : : SaveStringToFile ( NewHeaderContents , * ConflictPath ) ;
2014-04-23 18:36:17 -04:00
GCompilationResult = ECompilationResult : : FailedDueToHeaderChange ;
2014-03-14 14:13:41 -04:00
FError : : Throwf ( TEXT ( " ERROR: '%s': Changes to generated code are not allowed - conflicts written to '%s' " ) , HeaderPath , * ConflictPath ) ;
}
// save the updated version to a tmp file so that the user can see what will be changing
const FString TmpHeaderFilename = GenerateTempHeaderName ( HeaderPath , false ) ;
// delete any existing temp file
IFileManager : : Get ( ) . Delete ( * TmpHeaderFilename , false , true ) ;
if ( ! FFileHelper : : SaveStringToFile ( NewHeaderContents , * TmpHeaderFilename ) )
{
UE_LOG ( LogCompile , Warning , TEXT ( " Failed to save header export preview: '%s' " ) , * TmpHeaderFilename ) ;
}
TempHeaderPaths . Add ( TmpHeaderFilename ) ;
}
// Remember this header filename to be able to check for any old (unused) headers later.
2015-03-27 18:10:52 -04:00
PackageHeaderPaths . Add ( FString ( HeaderPath ) . Replace ( TEXT ( " \\ " ) , TEXT ( " / " ) , ESearchCase : : CaseSensitive ) ) ;
2014-03-14 14:13:41 -04:00
return bHasChanged ;
}
/**
* Create a temp header file name from the header name
*
* @ param CurrentFilename The filename off of which the current filename will be generated
* @ param bReverseOperation Get the header from the temp file name instead
*
* @ return The generated string
*/
FString FNativeClassHeaderGenerator : : GenerateTempHeaderName ( FString CurrentFilename , bool bReverseOperation )
{
return bReverseOperation
? CurrentFilename . Replace ( TEXT ( " .tmp " ) , TEXT ( " " ) )
: CurrentFilename + TEXT ( " .tmp " ) ;
}
/**
* Exports the temp header files into the . h files , then deletes the temp files .
*
* @ param PackageName Name of the package being saved
*/
void FNativeClassHeaderGenerator : : ExportUpdatedHeaders ( FString PackageName )
{
for ( auto It = TempHeaderPaths . CreateConstIterator ( ) ; It ; + + It )
{
const FString & TmpFilename = * It ;
FString Filename = GenerateTempHeaderName ( TmpFilename , true ) ;
if ( ! IFileManager : : Get ( ) . Move ( * Filename , * TmpFilename , true , true ) )
{
UE_LOG ( LogCompile , Error , TEXT ( " %s " ) , * FString : : Printf ( TEXT ( " Error exporting %s: couldn't write file '%s' " ) , * PackageName , * Filename ) ) ;
}
else
{
UE_LOG ( LogCompile , Log , TEXT ( " Exported updated C++ header: %s " ) , * Filename ) ;
}
}
}
/**
* Exports protobuffer definitions from boilerplate that was generated for a package .
* They are exported to a file using the name < PackageName > . generated . proto
*/
void FNativeClassHeaderGenerator : : ExportGeneratedProto ( )
{
if ( GeneratedProtoText . Len ( ) )
{
UE_LOG ( LogCompile , Log , TEXT ( " Autogenerating boilerplate proto: %s.proto " ) , * GeneratedProtoFilenameBase ) ;
2015-03-27 18:10:52 -04:00
FUHTStringBuilder ProtoPreamble ;
2014-03-14 14:13:41 -04:00
ProtoPreamble . Logf (
2014-12-07 19:09:38 -05:00
TEXT ( " // Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. " ) LINE_TERMINATOR
2014-03-14 14:13:41 -04:00
TEXT ( " /*=========================================================================== " ) LINE_TERMINATOR
TEXT ( " Purpose: The file defines our Google Protocol Buffers which are used in over " ) LINE_TERMINATOR
TEXT ( " the wire messages between servers as well as between clients and servers. " ) LINE_TERMINATOR
TEXT ( " This is automatically generated by UnrealHeaderTool. " ) LINE_TERMINATOR
TEXT ( " DO NOT modify this manually! Edit the corresponding .h files instead! " ) LINE_TERMINATOR
TEXT ( " ===========================================================================*/ " ) LINE_TERMINATOR
LINE_TERMINATOR
TEXT ( " // We care more about speed than code size " ) LINE_TERMINATOR
TEXT ( " option optimize_for = SPEED; " ) LINE_TERMINATOR
TEXT ( " // We don't use the service generation functionality " ) LINE_TERMINATOR
TEXT ( " option cc_generic_services = false; " ) LINE_TERMINATOR
LINE_TERMINATOR
) ;
FString PkgName = FPackageName : : GetShortName ( Package ) ;
FString PkgDir ;
FString GeneratedIncludeDirectory ;
2014-09-18 04:05:01 -04:00
if ( FindPackageLocation ( * PkgName , PkgDir , GeneratedIncludeDirectory ) = = false )
2014-03-14 14:13:41 -04:00
{
UE_LOG ( LogCompile , Error , TEXT ( " Failed to find path for package %s " ) , * PkgName ) ;
}
FString HeaderPath = GeneratedIncludeDirectory / GeneratedProtoFilenameBase + TEXT ( " .proto " ) ;
SaveHeaderIfChanged ( * HeaderPath , * ( ProtoPreamble + GeneratedProtoText ) ) ;
}
}
/**
* Exports MCPbuffer definitions from boilerplate that was generated for a package .
* They are exported to a file using the name < PackageName > . generated . MCP
*/
void FNativeClassHeaderGenerator : : ExportGeneratedMCP ( )
{
if ( GeneratedMCPText . Len ( ) )
{
UE_LOG ( LogCompile , Log , TEXT ( " Autogenerating boilerplate MCP: %s.java " ) , * GeneratedMCPFilenameBase ) ;
2015-03-27 18:10:52 -04:00
FUHTStringBuilder MCPPreamble ;
2014-03-14 14:13:41 -04:00
MCPPreamble . Logf (
2014-12-07 19:09:38 -05:00
TEXT ( " // Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. " ) LINE_TERMINATOR
2014-03-14 14:13:41 -04:00
TEXT ( " /*=========================================================================== " ) LINE_TERMINATOR
TEXT ( " Purpose: The file defines java heaers for MCP rpc messages. " ) LINE_TERMINATOR
TEXT ( " DO NOT modify this manually! Edit the corresponding .h files instead! " ) LINE_TERMINATOR
TEXT ( " ===========================================================================*/ " ) LINE_TERMINATOR
) ;
FString PkgName = FPackageName : : GetShortName ( Package ) ;
FString PkgDir ;
FString GeneratedIncludeDirectory ;
2014-09-18 04:05:01 -04:00
if ( FindPackageLocation ( * PkgName , PkgDir , GeneratedIncludeDirectory ) = = false )
2014-03-14 14:13:41 -04:00
{
UE_LOG ( LogCompile , Error , TEXT ( " Failed to find path for package %s " ) , * PkgName ) ;
}
FString HeaderPath = GeneratedIncludeDirectory / GeneratedMCPFilenameBase + TEXT ( " .java " ) ;
SaveHeaderIfChanged ( * HeaderPath , * ( MCPPreamble + GeneratedMCPText ) ) ;
}
}
/**
* Exports C + + definitions for boilerplate that was generated for a package .
2014-04-23 20:18:55 -04:00
* They are exported to a file using the name < PackageName > . generated . cpp
2014-03-14 14:13:41 -04:00
* @ param ReferencedNames list of function names to export .
*/
void FNativeClassHeaderGenerator : : ExportGeneratedCPP ( )
{
2015-03-27 18:10:52 -04:00
FUHTStringBuilder GeneratedCPPPreamble ;
FUHTStringBuilder GeneratedCPPClassesIncludes ;
FUHTStringBuilder GeneratedCPPEpilogue ;
FUHTStringBuilder GeneratedCPPText ;
FUHTStringBuilder GeneratedLinkerFixupFunction ;
2014-03-14 14:13:41 -04:00
2015-03-27 18:10:52 -04:00
TArray < FUHTStringBuilder > GeneratedCPPFiles ;
2014-03-14 14:13:41 -04:00
UE_LOG ( LogCompile , Log , TEXT ( " Autogenerating boilerplate cpp: %s.cpp " ) , * GeneratedCPPFilenameBase ) ;
GeneratedCPPPreamble . Logf (
2014-12-07 19:09:38 -05:00
TEXT ( " // Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. " ) LINE_TERMINATOR
2014-03-14 14:13:41 -04:00
TEXT ( " /*=========================================================================== " ) LINE_TERMINATOR
TEXT ( " Boilerplate C++ definitions for a single module. " ) LINE_TERMINATOR
TEXT ( " This is automatically generated by UnrealHeaderTool. " ) LINE_TERMINATOR
TEXT ( " DO NOT modify this manually! Edit the corresponding .h files instead! " ) LINE_TERMINATOR
TEXT ( " ===========================================================================*/ " ) LINE_TERMINATOR
LINE_TERMINATOR
) ;
2014-04-24 15:04:34 -04:00
FString ModulePCHInclude ;
2014-04-23 20:18:55 -04:00
const auto * ModuleInfo = GPackageToManifestModuleMap . FindChecked ( Package ) ;
if ( ModuleInfo - > PCH . Len ( ) )
{
2014-04-28 04:53:09 -04:00
FString PCH = ModuleInfo - > PCH ;
2014-05-19 06:57:00 -04:00
ConvertToBuildIncludePath ( Package , PCH ) ;
2014-04-28 04:53:09 -04:00
ModulePCHInclude = FString : : Printf ( TEXT ( " #include \" %s \" " ) LINE_TERMINATOR , * PCH ) ;
2014-04-23 20:18:55 -04:00
}
// Write out the ordered class dependencies into a single header that we can easily include
FString DepHeaderPathname = ModuleInfo - > GeneratedCPPFilenameBase + TEXT ( " .dep.h " ) ;
SaveHeaderIfChanged ( * DepHeaderPathname , * ( GeneratedCPPPreamble + ListOfPublicClassesUObjectHeaderModuleIncludes ) ) ;
// Write out our include to the .dep.h file
GeneratedCPPClassesIncludes . Logf ( TEXT ( " #include \" %s \" " ) LINE_TERMINATOR , * FPaths : : GetCleanFilename ( DepHeaderPathname ) ) ;
2014-03-14 14:13:41 -04:00
2014-06-12 08:08:47 -04:00
GeneratedLinkerFixupFunction . Logf ( TEXT ( " void EmptyLinkFunctionForGeneratedCode%s() {} " ) LINE_TERMINATOR , * ModuleInfo - > Name ) ;
2014-03-14 14:13:41 -04:00
GeneratedCPPText . Log ( * GeneratedPackageCPP ) ;
2015-04-10 06:02:22 -04:00
2014-03-14 14:13:41 -04:00
// Add all names marked for export to a list (for sorting)
TArray < FString > Names ;
for ( TSet < FName > : : TIterator It ( ReferencedNames ) ; It ; + + It )
{
Names . Add ( It - > ToString ( ) ) ;
}
// Autogenerate names (alphabetically sorted).
Names . Sort ( ) ;
for ( int32 NameIndex = 0 ; NameIndex < Names . Num ( ) ; NameIndex + + )
{
GeneratedCPPText . Logf ( TEXT ( " FName %s_%s = FName(TEXT( \" %s \" )); " ) LINE_TERMINATOR , * API , * Names [ NameIndex ] , * Names [ NameIndex ] ) ;
}
GeneratedCPPEpilogue . Logf (
LINE_TERMINATOR
) ;
2015-03-10 08:24:59 -04:00
FString EnableDeprecationWarnings = FString ( TEXT ( " PRAGMA_ENABLE_DEPRECATION_WARNINGS " ) LINE_TERMINATOR ) ;
FString DisableDeprecationWarnings = FString ( TEXT ( " PRAGMA_DISABLE_DEPRECATION_WARNINGS " ) LINE_TERMINATOR ) ;
2014-03-14 14:13:41 -04:00
FString PkgName = FPackageName : : GetShortName ( Package ) ;
FString PkgDir ;
if ( GeneratedFunctionDeclarations . Len ( ) | | CrossModuleGeneratedFunctionDeclarations . Len ( ) )
{
ExportGeneratedPackageInitCode ( Package ) ;
}
TArray < FString > NumberedHeaderNames ;
2014-04-23 20:18:55 -04:00
// Generate each of the .generated.cpp files
2014-03-14 14:13:41 -04:00
for ( int32 FileIdx = 0 ; FileIdx < GeneratedFunctionBodyTextSplit . Num ( ) ; FileIdx + + )
{
2015-03-27 18:10:52 -04:00
FUHTStringBuilder FileText ;
2014-03-14 14:13:41 -04:00
// The first file has all of the GeneratedCPPText, only the functions are split.
if ( FileIdx = = 0 )
{
FileText = GeneratedCPPText ;
}
if ( GeneratedFunctionDeclarations . Len ( ) | | CrossModuleGeneratedFunctionDeclarations . Len ( ) )
{
FileText . Logf ( TEXT ( " #if USE_COMPILED_IN_NATIVES \r \n " ) ) ;
if ( CrossModuleGeneratedFunctionDeclarations . Len ( ) )
{
FileText . Logf ( TEXT ( " // Cross Module References \r \n " ) ) ;
FileText . Log ( CrossModuleGeneratedFunctionDeclarations ) ;
FileText . Logf ( TEXT ( " \r \n " ) ) ;
}
FileText . Log ( GeneratedFunctionDeclarations ) ;
2015-04-14 08:03:34 -04:00
FileText . Log ( GeneratedFunctionBodyTextSplit [ FileIdx ] . Get ( ) ) ;
2014-03-14 14:13:41 -04:00
FileText . Logf ( TEXT ( " #endif \r \n " ) ) ;
}
2014-05-02 14:40:02 -04:00
FString CppPath = ModuleInfo - > GeneratedCPPFilenameBase + ( GeneratedFunctionBodyTextSplit . Num ( ) > 1 ? * FString : : Printf ( TEXT ( " .%d.cpp " ) , FileIdx + 1 ) : TEXT ( " .cpp " ) ) ;
2015-03-10 08:24:59 -04:00
SaveHeaderIfChanged ( * CppPath , * ( GeneratedCPPPreamble + ModulePCHInclude + GeneratedCPPClassesIncludes + DisableDeprecationWarnings + ( ( FileIdx > 0 ) ? FString ( ) : GeneratedLinkerFixupFunction ) + FileText + GeneratedCPPEpilogue + EnableDeprecationWarnings ) ) ;
2014-03-14 14:13:41 -04:00
if ( GeneratedFunctionBodyTextSplit . Num ( ) > 1 )
{
2014-05-02 14:40:02 -04:00
NumberedHeaderNames . Add ( FPaths : : GetCleanFilename ( CppPath ) ) ;
2014-03-14 14:13:41 -04:00
}
}
2014-09-22 09:46:58 -04:00
// delete the old .cpp file that will cause link errors if it's left around (Engine.generated.cpp and Engine.generated.1.cpp will
// conflict now that we no longer use Engine.generated.cpp to #include Engine.generated.1.cpp, and UBT would compile all 3)
// @todo: This is a temp measure so we don't force everyone to require a Clean
2015-03-31 09:33:11 -04:00
if ( GeneratedFunctionBodyTextSplit . Num ( ) > 1 )
{
FString CppPath = ModuleInfo - > GeneratedCPPFilenameBase + TEXT ( " .cpp " ) ;
2014-09-22 09:46:58 -04:00
IFileManager : : Get ( ) . Delete ( * CppPath ) ;
2015-03-31 09:33:11 -04:00
}
// Delete old generated .cpp files which we don't need because we generated less code than last time.
{
TArray < FString > FoundFiles ;
IFileManager : : Get ( ) . FindFiles ( FoundFiles , * ( ModuleInfo - > GeneratedCPPFilenameBase + TEXT ( " .*.cpp " ) ) , true , false ) ;
FString BaseDir = FPaths : : GetPath ( ModuleInfo - > GeneratedCPPFilenameBase ) ;
for ( FString & File : FoundFiles )
{
if ( ! NumberedHeaderNames . Contains ( File ) )
{
IFileManager : : Get ( ) . Delete ( * FPaths : : Combine ( * BaseDir , * File ) ) ;
}
}
}
2014-03-14 14:13:41 -04:00
}
2015-03-27 18:10:52 -04:00
2014-04-29 06:45:18 -04:00
/** Get all script plugins based on ini setting */
void GetScriptPlugins ( TArray < IScriptGeneratorPluginInterface * > & ScriptPlugins )
{
2015-03-27 17:16:51 -04:00
FScopedDurationTimer PluginTimeTracker ( GPluginOverheadTime ) ;
2014-06-30 06:19:02 -04:00
const FString CodeGeneratorPluginCategory ( TEXT ( " UnrealHeaderTool.Code Generator " ) ) ;
const TArray < FPluginStatus > Plugins = IPluginManager : : Get ( ) . QueryStatusForAllPlugins ( ) ;
for ( auto PluginIt ( Plugins . CreateConstIterator ( ) ) ; PluginIt ; + + PluginIt )
2014-04-29 06:45:18 -04:00
{
2014-06-30 06:19:02 -04:00
const auto & PluginStatus = * PluginIt ;
2015-04-22 16:41:13 -04:00
if ( PluginStatus . bIsEnabled & & PluginStatus . Descriptor . Category . StartsWith ( CodeGeneratorPluginCategory ) )
2014-04-29 06:45:18 -04:00
{
2014-06-30 06:19:02 -04:00
auto GeneratorInterface = FModuleManager : : LoadModulePtr < IScriptGeneratorPluginInterface > ( * PluginStatus . Name ) ;
if ( GeneratorInterface )
{
2015-03-27 03:51:19 -04:00
UE_LOG ( LogCompile , Log , TEXT ( " Detected script generator plugin (%d): %s " ) , ScriptPlugins . Num ( ) , * PluginStatus . Name ) ;
2014-06-30 06:19:02 -04:00
ScriptPlugins . Add ( GeneratorInterface ) ;
}
2014-04-29 06:45:18 -04:00
}
}
2014-04-30 07:58:33 -04:00
// Check if we can use these plugins and initialize them
for ( int32 PluginIndex = ScriptPlugins . Num ( ) - 1 ; PluginIndex > = 0 ; - - PluginIndex )
{
auto ScriptGenerator = ScriptPlugins [ PluginIndex ] ;
bool bSupportedPlugin = ScriptGenerator - > SupportsTarget ( GManifest . TargetName ) ;
if ( bSupportedPlugin )
{
// Find the right output direcotry for this plugin base on its target (Engine-side) plugin name.
2014-06-23 06:27:04 -04:00
FString GeneratedCodeModuleName = ScriptGenerator - > GetGeneratedCodeModuleName ( ) ;
const FManifestModule * GeneratedCodeModule = NULL ;
2014-04-30 07:58:33 -04:00
FString OutputDirectory ;
2014-06-23 06:27:04 -04:00
FString IncludeBase ;
2014-04-30 07:58:33 -04:00
for ( const auto & Module : GManifest . Modules )
{
2014-06-23 06:27:04 -04:00
if ( Module . Name = = GeneratedCodeModuleName )
2014-04-30 07:58:33 -04:00
{
2014-06-23 06:27:04 -04:00
GeneratedCodeModule = & Module ;
2014-04-30 07:58:33 -04:00
}
}
2014-06-23 06:27:04 -04:00
if ( GeneratedCodeModule )
2014-04-30 07:58:33 -04:00
{
2014-06-23 06:27:04 -04:00
ScriptGenerator - > Initialize ( GManifest . RootLocalPath , GManifest . RootBuildPath , GeneratedCodeModule - > GeneratedIncludeDirectory , GeneratedCodeModule - > IncludeBase ) ;
2014-04-30 07:58:33 -04:00
}
else
{
// Can't use this plugin
2014-06-23 06:27:04 -04:00
UE_LOG ( LogCompile , Log , TEXT ( " Unable to determine output directory for %s. Cannot export script glue. " ) , * GeneratedCodeModuleName ) ;
2014-04-30 07:58:33 -04:00
bSupportedPlugin = false ;
}
}
if ( ! bSupportedPlugin )
{
2015-03-27 03:51:19 -04:00
UE_LOG ( LogCompile , Log , TEXT ( " Script generator plugin %d not supported for target: %s " ) , PluginIndex , * GManifest . TargetName ) ;
2014-04-30 07:58:33 -04:00
ScriptPlugins . RemoveAt ( PluginIndex ) ;
}
}
2014-04-29 06:45:18 -04:00
}
2014-03-14 14:13:41 -04:00
2014-04-23 18:36:17 -04:00
ECompilationResult : : Type UnrealHeaderTool_Main ( const FString & ModuleInfoFilename )
2014-03-14 14:13:41 -04:00
{
check ( GIsUCCMakeStandaloneHeaderGenerator ) ;
2014-04-23 18:36:17 -04:00
ECompilationResult : : Type Result = ECompilationResult : : Succeeded ;
2014-03-14 14:13:41 -04:00
if ( ! FParse : : Param ( FCommandLine : : Get ( ) , TEXT ( " IgnoreWarnings " ) ) )
{
GWarn - > TreatWarningsAsErrors = true ;
}
FString ModuleInfoPath = FPaths : : GetPath ( ModuleInfoFilename ) ;
// Load the manifest file, giving a list of all modules to be processed, pre-sorted by dependency ordering
2014-08-18 08:53:57 -04:00
# if !PLATFORM_EXCEPTIONS_DISABLED
2014-03-14 14:13:41 -04:00
try
2014-08-18 08:53:57 -04:00
# endif
2014-03-14 14:13:41 -04:00
{
2014-04-02 18:09:23 -04:00
GManifest = FManifest : : LoadFromFile ( ModuleInfoFilename ) ;
2014-03-14 14:13:41 -04:00
}
2014-08-18 08:53:57 -04:00
# if !PLATFORM_EXCEPTIONS_DISABLED
2014-03-14 14:13:41 -04:00
catch ( const TCHAR * Ex )
{
UE_LOG ( LogCompile , Error , TEXT ( " Failed to load manifest file '%s': %s " ) , * ModuleInfoFilename , Ex ) ;
2014-04-23 18:36:17 -04:00
return GCompilationResult ;
2014-03-14 14:13:41 -04:00
}
2014-08-18 08:53:57 -04:00
# endif
2014-03-14 14:13:41 -04:00
// Load classes for editing.
int32 NumFailures = 0 ;
// Three passes. 1) Public 'Classes' headers (legacy) 2) Public headers 3) Private headers
2014-04-25 16:05:52 -04:00
enum EHeaderFolderTypes
2014-03-14 14:13:41 -04:00
{
2014-04-25 16:05:52 -04:00
PublicClassesHeaders = 0 ,
PublicHeaders = 1 ,
PrivateHeaders ,
2014-03-14 14:13:41 -04:00
2014-04-25 16:05:52 -04:00
FolderType_Count
} ;
2014-03-14 14:13:41 -04:00
2015-03-27 17:16:51 -04:00
double TotalModulePreparseTime = 0.0 ;
double TotalParseAndCodegenTime = 0.0 ;
2014-04-25 16:05:52 -04:00
for ( const auto & Module : GManifest . Modules )
{
if ( Result ! = ECompilationResult : : Succeeded )
{
break ;
2014-03-14 14:13:41 -04:00
}
2015-03-27 17:16:51 -04:00
double ThisModulePreparseTime = 0.0 ;
int32 NumHeadersPreparsed = 0 ;
FDurationTimer ThisModuleTimer ( ThisModulePreparseTime ) ;
ThisModuleTimer . Start ( ) ;
2014-04-25 16:05:52 -04:00
UPackage * Package = Cast < UPackage > ( StaticFindObjectFast ( UPackage : : StaticClass ( ) , NULL , FName ( * Module . LongPackageName ) , false , false ) ) ;
if ( Package = = NULL )
2014-03-14 14:13:41 -04:00
{
2014-04-25 16:05:52 -04:00
Package = CreatePackage ( NULL , * Module . LongPackageName ) ;
}
// Set some package flags for indicating that this package contains script
// NOTE: We do this even if we didn't have to create the package, because CoreUObject is compiled into UnrealHeaderTool and we still
// want to make sure our flags get set
Package - > PackageFlags | = PKG_ContainsScript ;
Package - > PackageFlags & = ~ ( PKG_ClientOptional | PKG_ServerSideOnly ) ;
Package - > PackageFlags | = PKG_Compiling ;
GPackageToManifestModuleMap . Add ( Package , & Module ) ;
2015-03-27 17:16:51 -04:00
// Pre-parse the headers
2014-04-25 16:05:52 -04:00
for ( int32 PassIndex = 0 ; PassIndex < FolderType_Count & & Result = = ECompilationResult : : Succeeded ; + + PassIndex )
{
EHeaderFolderTypes CurrentlyProcessing = ( EHeaderFolderTypes ) PassIndex ;
2014-03-14 14:13:41 -04:00
// We'll make an ordered list of all UObject headers we care about.
// @todo uht: Ideally 'dependson' would not be allowed from public -> private, or NOT at all for new style headers
2014-04-23 20:18:55 -04:00
const TArray < FString > & UObjectHeaders =
( CurrentlyProcessing = = PublicClassesHeaders ) ? Module . PublicUObjectClassesHeaders :
( CurrentlyProcessing = = PublicHeaders ) ? Module . PublicUObjectHeaders :
Module . PrivateUObjectHeaders ;
if ( ! UObjectHeaders . Num ( ) )
2015-03-10 06:14:19 -04:00
{
2014-04-23 20:18:55 -04:00
continue ;
2015-03-10 06:14:19 -04:00
}
2014-04-23 20:18:55 -04:00
2015-03-27 17:16:51 -04:00
NumHeadersPreparsed + = UObjectHeaders . Num ( ) ;
for ( const FString & RawFilename : UObjectHeaders )
2014-03-14 14:13:41 -04:00
{
2014-04-23 20:18:55 -04:00
# if !PLATFORM_EXCEPTIONS_DISABLED
try
# endif
2014-03-14 14:13:41 -04:00
{
2014-04-23 20:18:55 -04:00
// Import class.
2015-03-27 17:16:51 -04:00
const FString FullFilename = FPaths : : ConvertRelativePathToFull ( ModuleInfoPath , RawFilename ) ;
2014-03-14 14:13:41 -04:00
2014-04-23 20:18:55 -04:00
FString HeaderFile ;
2015-03-27 17:16:51 -04:00
if ( ! FFileHelper : : LoadFileToString ( HeaderFile , * FullFilename ) )
2014-04-29 06:45:18 -04:00
{
2015-03-27 17:16:51 -04:00
FError : : Throwf ( TEXT ( " UnrealHeaderTool was unable to load source file '%s' " ) , * FullFilename ) ;
2014-04-29 06:45:18 -04:00
}
2014-03-14 14:13:41 -04:00
2015-03-27 17:16:51 -04:00
TSharedRef < FUnrealSourceFile > UnrealSourceFile = PerformInitialParseOnHeader ( Package , RawFilename , RF_Public | RF_Standalone , * HeaderFile ) ;
2014-03-14 14:13:41 -04:00
2015-03-27 17:16:51 -04:00
GUnrealSourceFilesMap . Add ( RawFilename , UnrealSourceFile ) ;
2015-01-20 09:33:54 -05:00
if ( CurrentlyProcessing = = PublicClassesHeaders )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
for ( auto * Class : UnrealSourceFile - > GetDefinedClasses ( ) )
{
GPublicClassSet . Add ( Class ) ;
}
GPublicSourceFileSet . Add ( & UnrealSourceFile . Get ( ) ) ;
2014-04-23 20:18:55 -04:00
}
2014-03-14 14:13:41 -04:00
2014-04-23 20:18:55 -04:00
// Save metadata for the class path, both for it's include path and relative to the module base directory
2015-03-27 17:16:51 -04:00
if ( FullFilename . StartsWith ( Module . BaseDirectory ) )
2014-04-23 20:18:55 -04:00
{
// Get the path relative to the module directory
2015-03-27 17:16:51 -04:00
const TCHAR * ModuleRelativePath = * FullFilename + Module . BaseDirectory . Len ( ) ;
2015-01-20 09:33:54 -05:00
UnrealSourceFile - > SetModuleRelativePath ( ModuleRelativePath ) ;
2014-03-14 14:13:41 -04:00
2014-05-07 05:38:15 -04:00
// Calculate the include path
2015-03-27 17:16:51 -04:00
const TCHAR * IncludePath = ModuleRelativePath ;
2014-05-07 05:38:15 -04:00
// Walk over the first potential slash
2015-03-27 17:16:51 -04:00
if ( * IncludePath = = TEXT ( ' / ' ) )
2014-03-14 14:13:41 -04:00
{
2014-04-23 20:18:55 -04:00
IncludePath + + ;
2014-03-14 14:13:41 -04:00
}
2014-05-07 05:38:15 -04:00
// Does this module path start with a known include path location? If so, we can cut that part out of the include path
static const TCHAR PublicFolderName [ ] = TEXT ( " Public/ " ) ;
static const TCHAR PrivateFolderName [ ] = TEXT ( " Private/ " ) ;
static const TCHAR ClassesFolderName [ ] = TEXT ( " Classes/ " ) ;
2015-03-27 17:16:51 -04:00
if ( FCString : : Strnicmp ( IncludePath , PublicFolderName , ARRAY_COUNT ( PublicFolderName ) - 1 ) = = 0 )
2014-03-14 14:13:41 -04:00
{
2014-05-07 06:23:29 -04:00
IncludePath + = ( ARRAY_COUNT ( PublicFolderName ) - 1 ) ;
2014-04-23 20:18:55 -04:00
}
2015-03-27 17:16:51 -04:00
else if ( FCString : : Strnicmp ( IncludePath , PrivateFolderName , ARRAY_COUNT ( PrivateFolderName ) - 1 ) = = 0 )
2014-04-23 20:18:55 -04:00
{
2014-05-07 06:23:29 -04:00
IncludePath + = ( ARRAY_COUNT ( PrivateFolderName ) - 1 ) ;
2014-05-07 05:38:15 -04:00
}
2015-03-27 17:16:51 -04:00
else if ( FCString : : Strnicmp ( IncludePath , ClassesFolderName , ARRAY_COUNT ( ClassesFolderName ) - 1 ) = = 0 )
2014-05-07 05:38:15 -04:00
{
2014-05-07 06:23:29 -04:00
IncludePath + = ( ARRAY_COUNT ( ClassesFolderName ) - 1 ) ;
2014-05-07 05:38:15 -04:00
}
// Add the include path
2015-03-27 17:16:51 -04:00
if ( * IncludePath ! = 0 )
2014-05-07 05:38:15 -04:00
{
2015-01-20 09:33:54 -05:00
UnrealSourceFile - > SetIncludePath ( MoveTemp ( IncludePath ) ) ;
2014-03-14 14:13:41 -04:00
}
}
}
2014-04-23 20:18:55 -04:00
# if !PLATFORM_EXCEPTIONS_DISABLED
2015-03-27 17:16:51 -04:00
catch ( TCHAR * ErrorMsg )
2014-04-23 18:36:17 -04:00
{
2014-04-23 20:18:55 -04:00
TGuardValue < ELogTimes : : Type > DisableLogTimes ( GPrintLogTimes , ELogTimes : : None ) ;
FString Prefix ;
2015-01-20 09:33:54 -05:00
2015-03-27 17:16:51 -04:00
const FString AbsFilename = IFileManager : : Get ( ) . ConvertToAbsolutePathForExternalAppForRead ( * RawFilename ) ;
2015-01-20 09:33:54 -05:00
Prefix = FString : : Printf ( TEXT ( " %s(1): " ) , * AbsFilename ) ;
2014-04-23 20:18:55 -04:00
FString FormattedErrorMessage = FString : : Printf ( TEXT ( " %sError: %s \r \n " ) , * Prefix , ErrorMsg ) ;
Result = GCompilationResult ;
UE_LOG ( LogCompile , Log , TEXT ( " %s " ) , * FormattedErrorMessage ) ;
GWarn - > Log ( ELogVerbosity : : Error , FormattedErrorMessage ) ;
+ + NumFailures ;
2014-04-23 18:36:17 -04:00
}
2014-04-23 20:18:55 -04:00
# endif
}
2014-04-25 16:05:52 -04:00
if ( Result = = ECompilationResult : : Succeeded & & NumFailures ! = 0 )
2014-04-23 20:18:55 -04:00
{
Result = ECompilationResult : : OtherCompilationError ;
2014-03-14 14:13:41 -04:00
}
}
2015-03-27 17:16:51 -04:00
ThisModuleTimer . Stop ( ) ;
TotalModulePreparseTime + = ThisModulePreparseTime ;
UE_LOG ( LogCompile , Log , TEXT ( " Preparsed module %s containing %i files(s) in %.2f secs. " ) , * Module . LongPackageName , NumHeadersPreparsed , ThisModulePreparseTime ) ;
2014-03-14 14:13:41 -04:00
}
2015-03-27 17:16:51 -04:00
// Do the actual parse of the headers and generate for them
if ( Result = = ECompilationResult : : Succeeded )
2014-03-14 14:13:41 -04:00
{
2015-03-27 17:16:51 -04:00
FScopedDurationTimer ParseAndCodeGenTimer ( TotalParseAndCodegenTime ) ;
2014-03-14 14:13:41 -04:00
// Verify that all script declared superclasses exist.
2014-04-23 20:18:55 -04:00
for ( const UClass * ScriptClass : TObjectRange < UClass > ( ) )
2014-03-14 14:13:41 -04:00
{
const UClass * ScriptSuperClass = ScriptClass - > GetSuperClass ( ) ;
2015-01-20 09:33:54 -05:00
if ( ScriptSuperClass & & ! ScriptSuperClass - > HasAnyClassFlags ( CLASS_Intrinsic ) & & GTypeDefinitionInfoMap . Contains ( ScriptClass ) & & ! GTypeDefinitionInfoMap . Contains ( ScriptSuperClass ) )
2014-03-14 14:13:41 -04:00
{
2014-05-19 03:21:12 -04:00
class FSuperClassContextSupplier : public FContextSupplier
{
public :
2015-01-20 09:33:54 -05:00
FSuperClassContextSupplier ( const UClass * Class )
: DefinitionInfo ( GTypeDefinitionInfoMap [ Class ] )
2014-05-19 03:21:12 -04:00
{ }
2014-06-13 06:14:46 -04:00
virtual FString GetContext ( ) override
2014-05-19 03:21:12 -04:00
{
2015-01-20 09:33:54 -05:00
FString Filename = IFileManager : : Get ( ) . ConvertToAbsolutePathForExternalAppForRead ( * DefinitionInfo - > GetUnrealSourceFile ( ) . GetFilename ( ) ) ;
int32 LineNumber = DefinitionInfo - > GetLineNumber ( ) ;
2014-05-19 03:21:12 -04:00
return FString : : Printf ( TEXT ( " %s(%i) " ) , * Filename , LineNumber ) ;
}
private :
2015-01-20 09:33:54 -05:00
TSharedRef < FUnrealTypeDefinitionInfo > DefinitionInfo ;
2014-05-19 03:21:12 -04:00
} ContextSupplier ( ScriptClass ) ;
auto OldContext = GWarn - > GetContext ( ) ;
TGuardValue < ELogTimes : : Type > DisableLogTimes ( GPrintLogTimes , ELogTimes : : None ) ;
GWarn - > SetContext ( & ContextSupplier ) ;
GWarn - > Log ( ELogVerbosity : : Error , FString : : Printf ( TEXT ( " Error: Superclass %s of class %s not found " ) , * ScriptSuperClass - > GetName ( ) , * ScriptClass - > GetName ( ) ) ) ;
GWarn - > SetContext ( OldContext ) ;
2014-04-23 18:36:17 -04:00
Result = ECompilationResult : : OtherCompilationError ;
2014-03-14 14:13:41 -04:00
+ + NumFailures ;
}
}
2014-04-23 18:36:17 -04:00
if ( Result = = ECompilationResult : : Succeeded )
2014-03-14 14:13:41 -04:00
{
2014-04-29 06:45:18 -04:00
TArray < IScriptGeneratorPluginInterface * > ScriptPlugins ;
2014-04-30 07:58:33 -04:00
// Can only export scripts for game targets
if ( GManifest . IsGameTarget )
{
GetScriptPlugins ( ScriptPlugins ) ;
2014-04-29 09:36:01 -04:00
}
for ( const auto & Module : GManifest . Modules )
{
if ( UPackage * Package = Cast < UPackage > ( StaticFindObjectFast ( UPackage : : StaticClass ( ) , NULL , FName ( * Module . LongPackageName ) , false , false ) ) )
{
2014-06-02 07:02:29 -04:00
// Object which represents all parsed classes
FClasses AllClasses ( Package ) ;
AllClasses . Validate ( ) ;
2015-03-02 06:44:04 -05:00
# if WITH_HOT_RELOAD_CTORS
static struct FUseVTableConstructorsCache
{
FUseVTableConstructorsCache ( )
{
bUseVTableConstructors = false ;
GConfig - > GetBool ( TEXT ( " Core.System " ) , TEXT ( " UseVTableConstructors " ) , bUseVTableConstructors , GEngineIni ) ;
}
bool bUseVTableConstructors ;
} UseVTableConstructorsCache ;
Result = FHeaderParser : : ParseAllHeadersInside ( AllClasses , GWarn , Package , Module , ScriptPlugins ,
Module . ModuleType ! = EBuildModuleType : : Game | | UseVTableConstructorsCache . bUseVTableConstructors ) ;
# else // WITH_HOT_RELOAD_CTORS
2014-06-02 07:02:29 -04:00
Result = FHeaderParser : : ParseAllHeadersInside ( AllClasses , GWarn , Package , Module , ScriptPlugins ) ;
2015-03-02 06:44:04 -05:00
# endif // WITH_HOT_RELOAD_CTORS
2014-04-29 09:36:01 -04:00
if ( Result ! = ECompilationResult : : Succeeded )
{
+ + NumFailures ;
break ;
}
}
}
2014-04-29 06:45:18 -04:00
{
2015-03-27 17:16:51 -04:00
FScopedDurationTimer PluginTimeTracker ( GPluginOverheadTime ) ;
for ( auto ScriptGenerator : ScriptPlugins )
{
ScriptGenerator - > FinishExport ( ) ;
}
2014-03-14 14:13:41 -04:00
}
}
}
// Avoid TArray slack for meta data.
2014-06-02 07:02:29 -04:00
GScriptHelper . Shrink ( ) ;
2014-03-14 14:13:41 -04:00
2015-03-27 17:16:51 -04:00
UE_LOG ( LogCompile , Log , TEXT ( " Preparsing %i modules took %f seconds " ) , GManifest . Modules . Num ( ) , TotalModulePreparseTime ) ;
UE_LOG ( LogCompile , Log , TEXT ( " Parsing took %f seconds " ) , TotalParseAndCodegenTime - GHeaderCodeGenTime ) ;
UE_LOG ( LogCompile , Log , TEXT ( " Code generation took %f seconds " ) , GHeaderCodeGenTime ) ;
UE_LOG ( LogCompile , Log , TEXT ( " ScriptPlugin overhead was %f seconds " ) , GPluginOverheadTime ) ;
UE_LOG ( LogCompile , Log , TEXT ( " Macroize time was %f seconds " ) , GMacroizeTime ) ;
UE_LOG ( LogCompile , Log , TEXT ( " Tabify time was was %f seconds " ) , GTabifyTime ) ;
if ( bWriteContents )
2014-03-14 14:13:41 -04:00
{
UE_LOG ( LogCompile , Log , TEXT ( " ********************************* Wrote reference generated code to ReferenceGeneratedCode. " ) ) ;
}
2015-03-27 17:16:51 -04:00
else if ( bVerifyContents )
2014-03-14 14:13:41 -04:00
{
UE_LOG ( LogCompile , Log , TEXT ( " ********************************* Wrote generated code to VerifyGeneratedCode and compared to ReferenceGeneratedCode " ) ) ;
for ( FString & Msg : ChangeMessages )
{
UE_LOG ( LogCompile , Error , TEXT ( " %s " ) , * Msg ) ;
}
TArray < FString > RefFileNames ;
IFileManager : : Get ( ) . FindFiles ( RefFileNames , * ( FString ( FPaths : : GameSavedDir ( ) ) / TEXT ( " ReferenceGeneratedCode/*.* " ) ) , true , false ) ;
TArray < FString > VerFileNames ;
IFileManager : : Get ( ) . FindFiles ( VerFileNames , * ( FString ( FPaths : : GameSavedDir ( ) ) / TEXT ( " VerifyGeneratedCode/*.* " ) ) , true , false ) ;
if ( RefFileNames . Num ( ) ! = VerFileNames . Num ( ) )
{
UE_LOG ( LogCompile , Error , TEXT ( " Number of generated files mismatch ref=%d, ver=%d " ) , RefFileNames . Num ( ) , VerFileNames . Num ( ) ) ;
}
}
TheFlagAudit . WriteResults ( ) ;
GIsRequestingExit = true ;
2014-04-23 18:36:17 -04:00
2015-03-27 17:16:51 -04:00
if ( ( Result = = ECompilationResult : : Succeeded ) & & ( NumFailures > 0 ) )
2014-04-23 18:36:17 -04:00
{
return ECompilationResult : : OtherCompilationError ;
}
2014-03-14 14:13:41 -04:00
2014-04-23 18:36:17 -04:00
return Result ;
2014-03-14 14:13:41 -04:00
}
2015-01-20 09:33:54 -05:00
UClass * ProcessParsedClass ( bool bClassIsAnInterface , TArray < FHeaderProvider > & DependentOn , const FString & ClassName , const FString & BaseClassName , UObject * InParent , EObjectFlags Flags )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
FString ClassNameStripped = GetClassNameWithPrefixRemoved ( * ClassName ) ;
2014-03-14 14:13:41 -04:00
2015-01-20 13:06:35 -05:00
// All classes must start with a valid unreal prefix
if ( ! FHeaderParser : : ClassNameHasValidPrefix ( ClassName , ClassNameStripped ) )
{
FError : : Throwf ( TEXT ( " Invalid class name '%s'. The class name must have an appropriate prefix added (A for Actors, U for other classes). " ) , * ClassName ) ;
}
2014-03-14 14:13:41 -04:00
// Ensure the base class has any valid prefix and exists as a valid class. Checking for the 'correct' prefix will occur during compilation
FString BaseClassNameStripped ;
if ( ! BaseClassName . IsEmpty ( ) )
{
2014-04-23 18:42:01 -04:00
BaseClassNameStripped = GetClassNameWithPrefixRemoved ( BaseClassName ) ;
2015-01-20 09:33:54 -05:00
if ( ! FHeaderParser : : ClassNameHasValidPrefix ( BaseClassName , BaseClassNameStripped ) )
FError : : Throwf ( TEXT ( " No prefix or invalid identifier for base class %s. \n Class names must match Unreal prefix specifications (e.g., \" UObject \" or \" AActor \" ) " ) , * BaseClassName ) ;
2014-03-14 14:13:41 -04:00
2015-01-20 09:33:54 -05:00
if ( DependentOn . ContainsByPredicate ( [ & ] ( const FHeaderProvider & Dependency ) { FString DependencyStr = Dependency . GetId ( ) ; return ! DependencyStr . Contains ( TEXT ( " .generated.h " ) ) & & FPaths : : GetBaseFilename ( DependencyStr ) = = ClassNameStripped ; } ) )
2014-03-14 14:13:41 -04:00
FError : : Throwf ( TEXT ( " Class '%s' contains a dependency (#include or DependsOn) to itself " ) , * ClassName ) ;
}
//UE_LOG(LogCompile, Log, TEXT("Class: %s extends %s"),*ClassName,*BaseClassName);
// Handle failure and non-class headers.
if ( BaseClassName . IsEmpty ( ) & & ( ClassName ! = TEXT ( " UObject " ) ) )
{
2015-01-20 09:33:54 -05:00
FError : : Throwf ( TEXT ( " Class '%s' must inherit UObject or a UObject-derived class " ) , * ClassName ) ;
2014-03-14 14:13:41 -04:00
}
if ( ClassName = = BaseClassName )
{
2015-01-20 09:33:54 -05:00
FError : : Throwf ( TEXT ( " Class '%s' cannot inherit from itself " ) , * ClassName ) ;
2014-03-14 14:13:41 -04:00
}
// In case the file system and the class disagree on the case of the
// class name replace the fname with the one from the script class file
// This is needed because not all source control systems respect the
// original filename's case
2015-01-20 09:33:54 -05:00
FName ClassNameReplace ( * ClassName , FNAME_Replace_Not_Safe_For_Threading ) ;
2014-03-14 14:13:41 -04:00
// Use stripped class name for processing and replace as we did above
FName ClassNameStrippedReplace ( * ClassNameStripped , FNAME_Replace_Not_Safe_For_Threading ) ;
UClass * ResultClass = FindObject < UClass > ( InParent , * ClassNameStripped ) ;
// if we aren't generating headers, then we shouldn't set misaligned object, since it won't get cleared
const static bool bVerboseOutput = FParse : : Param ( FCommandLine : : Get ( ) , TEXT ( " VERBOSE " ) ) ;
2015-01-20 09:33:54 -05:00
if ( ResultClass = = nullptr | | ! ResultClass - > HasAnyFlags ( RF_Native ) )
2014-03-14 14:13:41 -04:00
{
// detect if the same class name is used in multiple packages
2015-01-20 09:33:54 -05:00
if ( ResultClass = = nullptr )
2014-03-14 14:13:41 -04:00
{
UClass * ConflictingClass = FindObject < UClass > ( ANY_PACKAGE , * ClassNameStripped , true ) ;
2015-01-20 09:33:54 -05:00
if ( ConflictingClass ! = nullptr )
2014-03-14 14:13:41 -04:00
{
UE_LOG ( LogCompile , Warning , TEXT ( " Duplicate class name: %s also exists in file %s " ) , * ClassName , * ConflictingClass - > GetOutermost ( ) - > GetName ( ) ) ;
}
}
// Create new class.
2015-01-30 08:30:03 -05:00
ResultClass = new ( EC_InternalUseOnlyConstructor , InParent , * ClassNameStripped , Flags ) UClass ( FObjectInitializer ( ) , nullptr ) ;
2014-03-14 14:13:41 -04:00
GClassHeaderNameWithNoPathMap . Add ( ResultClass , ClassNameStripped ) ;
// add CLASS_Interface flag if the class is an interface
// NOTE: at this pre-parsing/importing stage, we cannot know if our super class is an interface or not,
// we leave the validation to the main header parser
if ( bClassIsAnInterface )
{
ResultClass - > ClassFlags | = CLASS_Interface ;
}
2015-01-20 09:33:54 -05:00
if ( bVerboseOutput )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
UE_LOG ( LogCompile , Log , TEXT ( " Imported: %s " ) , * ResultClass - > GetFullName ( ) ) ;
}
}
2014-03-14 14:13:41 -04:00
2015-01-20 09:33:54 -05:00
if ( ResultClass ! = nullptr )
{
if ( ! BaseClassNameStripped . IsEmpty ( ) & & ! ResultClass - > GetSuperClass ( ) )
{
// Find or forward-declare base class.
ResultClass - > SetSuperStruct ( FindObject < UClass > ( InParent , * BaseClassNameStripped ) ) ;
if ( ResultClass - > GetSuperStruct ( ) = = nullptr )
{
ResultClass - > SetSuperStruct ( FindObject < UClass > ( ANY_PACKAGE , * BaseClassNameStripped ) ) ;
}
if ( ResultClass - > GetSuperStruct ( ) = = nullptr )
{
// don't know its parent class yet
2015-01-30 08:30:03 -05:00
ResultClass - > SetSuperStruct ( new ( EC_InternalUseOnlyConstructor , InParent , * BaseClassNameStripped ) UClass ( FObjectInitializer ( ) , nullptr ) ) ;
2015-01-20 09:33:54 -05:00
}
if ( ResultClass - > GetSuperStruct ( ) ! = nullptr )
{
ResultClass - > ClassCastFlags | = ResultClass - > GetSuperClass ( ) - > ClassCastFlags ;
}
2014-03-14 14:13:41 -04:00
}
}
if ( bVerboseOutput )
{
for ( const auto & Dependency : DependentOn )
{
UE_LOG ( LogCompile , Log , TEXT ( " \t Adding %s as a dependency " ) , * Dependency . ToString ( ) ) ;
}
}
return ResultClass ;
}
2015-01-20 09:33:54 -05:00
2015-03-27 17:16:51 -04:00
TSharedRef < FUnrealSourceFile > PerformInitialParseOnHeader ( UPackage * InParent , const FString & FileName , EObjectFlags Flags , const TCHAR * Buffer )
2015-01-20 09:33:54 -05:00
{
const TCHAR * InBuffer = Buffer ;
// is the parsed class name an interface?
bool bClassIsAnInterface = false ;
TArray < FHeaderProvider > DependsOn ;
// Parse the header to extract the information needed
2015-03-27 18:10:52 -04:00
FUHTStringBuilder ClassHeaderTextStrippedOfCppText ;
2015-01-20 09:33:54 -05:00
TArray < FSimplifiedParsingClassInfo > ParsedClassArray ;
FHeaderParser : : SimplifiedClassParse ( Buffer , /*out*/ ParsedClassArray , /*out*/ DependsOn , ClassHeaderTextStrippedOfCppText ) ;
TSharedRef < FUnrealSourceFile > UnrealSourceFile = MakeShareable ( new FUnrealSourceFile ( InParent , FileName , ClassHeaderTextStrippedOfCppText ) ) ;
for ( auto & ParsedClassInfo : ParsedClassArray )
{
UClass * ResultClass = ProcessParsedClass ( ParsedClassInfo . IsInterface ( ) , DependsOn , ParsedClassInfo . GetClassName ( ) , ParsedClassInfo . GetBaseClassName ( ) , InParent , Flags ) ;
FScope : : AddTypeScope ( ResultClass , & UnrealSourceFile - > GetScope ( ) . Get ( ) ) ;
AddTypeDefinition ( * UnrealSourceFile , ResultClass , ParsedClassInfo . GetClassDefLine ( ) ) ;
UnrealSourceFile - > AddDefinedClass ( ResultClass ) ;
}
for ( const auto & DependsOnElement : DependsOn )
{
UnrealSourceFile - > GetIncludes ( ) . Add ( DependsOnElement ) ;
}
return UnrealSourceFile ;
}