From 78dd56d6c5fb9fd100640f58f28d6b3ebc5150b1 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Mon, 6 Jul 2020 09:09:28 -0700 Subject: [PATCH] Added GetFieldReference, ability to explicitly reference in Variant --- BeefLibs/corlib/src/Reflection/FieldInfo.bf | 24 +++ BeefLibs/corlib/src/Reflection/MethodInfo.bf | 28 +++- BeefLibs/corlib/src/Type.bf | 11 +- BeefLibs/corlib/src/Variant.bf | 155 +++++++++++++++---- IDE/dist/BeefDbgVis.toml | 17 +- IDEHelper/Compiler/BfCompiler.cpp | 2 +- IDEHelper/Compiler/BfModule.cpp | 1 + IDEHelper/DbgExprEvaluator.cpp | 4 +- IDEHelper/DbgModule.cpp | 8 +- IDEHelper/DbgModule.h | 2 +- IDEHelper/Tests/src/Reflection.bf | 81 +++++++++- 11 files changed, 279 insertions(+), 54 deletions(-) diff --git a/BeefLibs/corlib/src/Reflection/FieldInfo.bf b/BeefLibs/corlib/src/Reflection/FieldInfo.bf index b34dfb47..d381a10a 100644 --- a/BeefLibs/corlib/src/Reflection/FieldInfo.bf +++ b/BeefLibs/corlib/src/Reflection/FieldInfo.bf @@ -216,6 +216,30 @@ namespace System.Reflection return value; } + public Result GetValueReference(Object target) + { + Variant value = Variant(); + + Type tTarget; + void* targetDataAddr = GetDataPtrAndType(target, out tTarget); + + if (!tTarget.IsSubtypeOf(mTypeInstance)) + Runtime.FatalError("Invalid type"); + + targetDataAddr = (uint8*)targetDataAddr + mFieldData.mDataOffset; + + Type fieldType = Type.[Friend]GetType(mFieldData.mFieldTypeId); + + TypeCode typeCode = fieldType.[Friend]mTypeCode; + if (typeCode == TypeCode.Enum) + typeCode = fieldType.UnderlyingType.[Friend]mTypeCode; + + value = Variant.CreateReference(fieldType, targetDataAddr); + + return value; + } + + public Result GetValue() { Variant value = Variant(); diff --git a/BeefLibs/corlib/src/Reflection/MethodInfo.bf b/BeefLibs/corlib/src/Reflection/MethodInfo.bf index b5c7e036..b78cc69c 100644 --- a/BeefLibs/corlib/src/Reflection/MethodInfo.bf +++ b/BeefLibs/corlib/src/Reflection/MethodInfo.bf @@ -137,7 +137,16 @@ namespace System.Reflection added = true; } else - isValid = false; + { + if ((Type)argType != refParamType.UnderlyingType) + isValid = false; + + ffiParamList.Add(&FFIType.Pointer); + int* stackDataPtr = scope:mixin int(); + *stackDataPtr = (int)dataPtr; + ffiArgList.Add(stackDataPtr); + added = true; + } } else if (paramType.IsValueType) { @@ -412,7 +421,22 @@ namespace System.Reflection added = true; } else - isValid = false; + { + var elemType = argType.UnderlyingType; + if (elemType != refParamType.UnderlyingType) + { + if (elemType.IsTypedPrimitive) + elemType = elemType.UnderlyingType; + if (elemType != refParamType.UnderlyingType) + isValid = false; + } + + ffiParamList.Add(&FFIType.Pointer); + int* stackDataPtr = scope:mixin int(); + *stackDataPtr = (int)dataPtr; + ffiArgList.Add(stackDataPtr); + added = true; + } } else if (paramType.IsValueType) { diff --git a/BeefLibs/corlib/src/Type.bf b/BeefLibs/corlib/src/Type.bf index 1844371e..efb03908 100644 --- a/BeefLibs/corlib/src/Type.bf +++ b/BeefLibs/corlib/src/Type.bf @@ -757,6 +757,12 @@ namespace System.Reflection } strBuffer.Append(')'); } + else if (mTypeFlags.HasFlag(.Boxed)) + { + strBuffer.Append("boxed "); + let ut = UnderlyingType; + ut.GetFullName(strBuffer); + } else { if (mOuterType != 0) @@ -769,8 +775,9 @@ namespace System.Reflection if (!String.IsNullOrEmpty(mNamespace)) strBuffer.Append(mNamespace, "."); } - - strBuffer.Append(mName); + + if (mName != null) + strBuffer.Append(mName); } } diff --git a/BeefLibs/corlib/src/Variant.bf b/BeefLibs/corlib/src/Variant.bf index 22fcae26..f4459233 100644 --- a/BeefLibs/corlib/src/Variant.bf +++ b/BeefLibs/corlib/src/Variant.bf @@ -4,7 +4,21 @@ namespace System { struct Variant { - int mStructType; // 0 = unowned object, 1 = owned object, 2 = null value (mData is type), otherwise is struct type + enum ObjectType + { + UnownedObject, + OwnedObject, + NullObject + } + + enum StructFlag + { + InternalValue, + OwnedPtr, + ExternalPtr + } + + int mStructType; // 0 = unowned object, 1 = owned object, 2 = null value (mData is type), otherwise is struct type (|0 is internal, |1 is owned ptr, |2 is external ptr) int mData; // This is either an Object reference, struct data, or a pointer to struct data public bool OwnsMemory @@ -13,7 +27,7 @@ namespace System { if (mStructType <= 2) return mStructType == 1; - return VariantType.Size > sizeof(int); + return (mStructType & 1) != 0; } } @@ -21,7 +35,11 @@ namespace System { get { - return mStructType <= 2; + if (mStructType <= 2) + return true; + if ((mStructType & 3) == (int)StructFlag.ExternalPtr) + return VariantType.IsObject; + return false; } } @@ -37,7 +55,7 @@ namespace System { return Internal.UnsafeCastToObject((void*)mData).GetType(); } - return (Type)Internal.UnsafeCastToObject((void*)mStructType); + return (Type)Internal.UnsafeCastToObject((void*)(mStructType & ~3)); } } @@ -53,7 +71,7 @@ namespace System { get mut { - if (IsObject) + if (mStructType <= 3) { if (mStructType == 2) return null; @@ -61,8 +79,7 @@ namespace System return (uint8*)Internal.UnsafeCastToPtr(obj) + obj.GetType().[Friend]mMemberDataOffset; } - var type = VariantType; - if (type.Size <= sizeof(int)) + if ((mStructType & 3) == (int)StructFlag.InternalValue) return (void*)&mData; else return (void*)mData; @@ -71,7 +88,7 @@ namespace System protected override void GCMarkMembers() { - if ((mStructType == 1) || (mStructType == 0)) + if ((mStructType == (int)ObjectType.UnownedObject) || (mStructType == (int)ObjectType.OwnedObject)) { var obj = Internal.UnsafeCastToObject((void*)mData); GC.Mark(obj); @@ -80,7 +97,7 @@ namespace System public void Dispose() mut { - if (mStructType == 1) + if (mStructType == (int)ObjectType.OwnedObject) { delete Internal.UnsafeCastToObject((void*)mData); } @@ -97,12 +114,12 @@ namespace System Variant variant; if (val == null) { - variant.mStructType = 2; + variant.mStructType = (int)ObjectType.NullObject; variant.mData = (int)Internal.UnsafeCastToPtr(typeof(T)); } else { - variant.mStructType = (int)(owns ? 1 : 0); + variant.mStructType = (int)(owns ? (int)ObjectType.OwnedObject : (int)ObjectType.UnownedObject); variant.mData = (int)Internal.UnsafeCastToPtr(val); } return variant; @@ -112,14 +129,15 @@ namespace System { Variant variant; Type type = typeof(T); - variant.mStructType = (int)Internal.UnsafeCastToPtr(type); if (sizeof(T) <= sizeof(int)) { + variant.mStructType = (int)Internal.UnsafeCastToPtr(type); variant.mData = 0; *(T*)&variant.mData = val; } else { + variant.mStructType = (int)Internal.UnsafeCastToPtr(type) | 1; T* newVal = (T*)new uint8[sizeof(T)]*; *newVal = val; variant.mData = (int)(void*)newVal; @@ -131,14 +149,15 @@ namespace System { Variant variant; Type type = typeof(T); - variant.mStructType = (int)Internal.UnsafeCastToPtr(type); if (type.Size <= sizeof(int)) { + variant.mStructType = (int)Internal.UnsafeCastToPtr(type); variant.mData = 0; *(T*)&variant.mData = val; } else { + variant.mStructType = (int)Internal.UnsafeCastToPtr(type) | 1; T* newVal = (T*)new uint8[sizeof(T)]*; *newVal = val; variant.mData = (int)(void*)newVal; @@ -146,18 +165,53 @@ namespace System return variant; } + public static Variant Create(ref T val) where T : struct + { + Variant variant; + Type type = typeof(T); + variant.mStructType = (int)Internal.UnsafeCastToPtr(type) | 2; + variant.mData = 0; + variant.mData = (int)(void*)&val; + return variant; + } + + public static Variant CreateOwned(T val) where T : struct + { + Variant variant; + Type type = typeof(T); + variant.mStructType = (int)Internal.UnsafeCastToPtr(type) | 1; + T* newVal = (T*)new uint8[sizeof(T)]*; + *newVal = val; + variant.mData = (int)(void*)newVal; + return variant; + } + + public void EnsureReference() mut + { + if ((mStructType <= 2) && (mStructType & 3 == (int)StructFlag.InternalValue)) + return; + + var val = mData; + + mStructType |= (int)StructFlag.OwnedPtr; + int* newVal = (int*)new uint8[sizeof(int)]*; + *newVal = val; + mData = (int)(void*)newVal; + } + public static Variant Create(Type type, void* val) { Variant variant; Debug.Assert(!type.IsObject); - variant.mStructType = (int)Internal.UnsafeCastToPtr(type); if (type.Size <= sizeof(int)) { + variant.mStructType = (int)Internal.UnsafeCastToPtr(type); variant.mData = 0; Internal.MemCpy(&variant.mData, val, type.[Friend]mSize); } else { + variant.mStructType = (int)Internal.UnsafeCastToPtr(type) | 1; void* data = new uint8[type.[Friend]mSize]*; Internal.MemCpy(data, val, type.[Friend]mSize); variant.mData = (int)data; @@ -165,6 +219,14 @@ namespace System return variant; } + public static Variant CreateReference(Type type, void* val) + { + Variant variant; + variant.mStructType = (int)Internal.UnsafeCastToPtr(type) | 2; + variant.mData = (int)val; + return variant; + } + public static void* Alloc(Type type, out Variant variant) { variant = .(); @@ -175,14 +237,15 @@ namespace System } else { - variant.mStructType = (int)Internal.UnsafeCastToPtr(type); if (type.Size <= sizeof(int)) { + variant.mStructType = (int)Internal.UnsafeCastToPtr(type); variant.mData = 0; return &variant.mData; } else { + variant.mStructType = (int)Internal.UnsafeCastToPtr(type) | 1; void* data = new uint8[type.[Friend]mSize]*; variant.mData = (int)data; return data; @@ -196,7 +259,11 @@ namespace System if (mStructType == 2) return (T)null; Type type = typeof(T); - T obj = (T)Internal.UnsafeCastToObject((void*)mData); + T obj; + if (mStructType >= 3) + obj = (T)Internal.UnsafeCastToObject(*(void**)(void*)mData); + else + obj = (T)Internal.UnsafeCastToObject((void*)mData); Debug.Assert(obj.GetType().IsSubtypeOf(type)); return obj; } @@ -204,9 +271,9 @@ namespace System public T Get() where T : struct { Debug.Assert(!IsObject); - var type = VariantType; + //var type = VariantType; //Debug.Assert((typeof(T) == type) || (typeof(T) == type.GetUnderlyingType())); - if (type.Size <= sizeof(int)) + if ((mStructType & 3) == (int)StructFlag.InternalValue) { int data = mData; return *(T*)&data; @@ -218,9 +285,9 @@ namespace System public T Get() where T : struct* { Debug.Assert(!IsObject); - var type = VariantType; + //var type = VariantType; //Debug.Assert((typeof(T) == type) || (typeof(T) == type.GetUnderlyingType())); - if (type.Size <= sizeof(int)) + if ((mStructType & 3) == (int)StructFlag.InternalValue) { int data = mData; return *(T*)&data; @@ -248,7 +315,7 @@ namespace System } var type = VariantType; - if (type.Size <= sizeof(int)) + if ((mStructType & 3) == (int)StructFlag.InternalValue) { int data = mData; Internal.MemCpy(dest, &data, type.Size); @@ -262,8 +329,7 @@ namespace System public void* GetValueData() mut { Debug.Assert(!IsObject); - var type = VariantType; - if (type.Size <= sizeof(int)) + if ((mStructType & 3) == (int)StructFlag.InternalValue) { return (void*)&mData; } @@ -284,18 +350,19 @@ namespace System return v1.mData == v2.mData; } - if (v1.mStructType != v2.mStructType) + if (v1.mStructType & 3 != v2.mStructType & 3) return false; - let type = v1.VariantType; - if (type.[Friend]mSize <= sizeof(int)) + if ((v1.mStructType & 3 == 0) && (v2.mStructType & 3 == 0)) return v1.mData == v2.mData; - for (int i < type.[Friend]mSize) - { - if (((uint8*)(void*)v1.mData)[i] != ((uint8*)(void*)v2.mData)[i]) - return false; - } - return true; + + var v1; + var v2; + + let type = v1.VariantType; + let ptr1 = v1.DataPtr; + let ptr2 = v2.DataPtr; + return Internal.MemCmp(ptr1, ptr2, type.[Friend]mSize) == 0; } public static mixin Equals(var v1, var v2) @@ -303,16 +370,19 @@ namespace System v1.Get() == v2.Get() } - public static Result CreateFromVariant(Variant varFrom) + public static Variant CreateFromVariant(Variant varFrom) { Variant varTo = varFrom; if (varTo.mStructType == 1) varTo.mStructType = 0; if (varTo.mStructType > 2) { - let type = (Type)Internal.UnsafeCastToObject((void*)varFrom.mStructType); + varTo.mStructType &= ~3; + + let type = (Type)Internal.UnsafeCastToObject((void*)(varFrom.mStructType & ~3)); if (type.[Friend]mSize > sizeof(int)) { + varTo.mStructType |= (int)StructFlag.OwnedPtr; void* data = new uint8[type.[Friend]mSize]*; Internal.MemCpy(data, (void*)varFrom.mData, type.[Friend]mSize); varTo.mData = (int)data; @@ -322,6 +392,22 @@ namespace System return varTo; } + public static Variant CreateFromVariantRef(ref Variant varFrom) + { + Variant varTo = varFrom; + if (varTo.mStructType == 1) + varTo.mStructType = 0; + if (varTo.mStructType > 2) + { + varTo.mStructType &= ~3; + + varTo.mStructType |= (int)StructFlag.ExternalPtr; + varTo.mData = (int)varFrom.DataPtr; + } + + return varTo; + } + public static Result CreateFromBoxed(Object objectFrom) { if (objectFrom == null) @@ -342,6 +428,7 @@ namespace System } else { + variant.mStructType |= (int)StructFlag.OwnedPtr; void* data = new uint8[underlying.[Friend]mSize]*; Internal.MemCpy(data, srcDataPtr, underlying.[Friend]mSize); variant.mData = (int)data; diff --git a/IDE/dist/BeefDbgVis.toml b/IDE/dist/BeefDbgVis.toml index b0e27d7e..486672e8 100644 --- a/IDE/dist/BeefDbgVis.toml +++ b/IDE/dist/BeefDbgVis.toml @@ -105,10 +105,13 @@ String = "{{ OwnedObj: {(System.Object)mData} }}" Condition = "mStructType == 2" String = "{{ Null: {__cast((System.Type)mData, null)} }}" [[Type.DisplayString]] -Condition = "((System.Type)mStructType).mSize <= sizeof(int)" -String = "{{ InlineValue: {__bitcast((System.Type)mStructType, mData)} }}" +Condition = "mStructType & 3 == 0" +String = "{{ InlineValue: {__bitcast((System.Type)(mStructType & ~3), mData)} }}" [[Type.DisplayString]] -String = "{{ AllocValue: {*__cast((System.Type)mStructType, \"*\", mData)} }}" +Condition = "mStructType & 3 == 1" +String = "{{ AllocValue: {*__cast((System.Type)(mStructType & ~3), \"*\", mData)} }}" +[[Type.DisplayString]] +String = "{{ RefValue: {*__cast((System.Type)(mStructType & ~3), \"*\", mData)} }}" [[Type.Expand.Item]] Condition = "mStructType == 0" Name = "[UnownedObj]" @@ -122,13 +125,13 @@ Condition = "mStructType == 3" Name = "[Null]" Value = "__cast((System.Type)mData, null)" [[Type.Expand.Item]] -Condition = "(mStructType != 0) && ((System.Type)mStructType).mSize <= sizeof(int)" +Condition = "(mStructType != 0) && (mStructType & 3 == 0)" Name = "[InlineValue]" -Value = "__bitcast((System.Type)mStructType, mData)" +Value = "__bitcast((System.Type)(mStructType & ~3), mData)" [[Type.Expand.Item]] -Condition = "(mStructType != 0) && ((System.Type)mStructType).mSize > sizeof(int)" +Condition = "(mStructType != 0) && (mStructType & 3 != 0)" Name = "[AllocValue]" -Value = "*__cast((System.Type)mStructType, \"*\", mData)" +Value = "*__cast((System.Type)(mStructType & ~3), \"*\", mData)" [[Type]] Name = "*?" diff --git a/IDEHelper/Compiler/BfCompiler.cpp b/IDEHelper/Compiler/BfCompiler.cpp index c0e75761..3839de56 100644 --- a/IDEHelper/Compiler/BfCompiler.cpp +++ b/IDEHelper/Compiler/BfCompiler.cpp @@ -1266,7 +1266,7 @@ void BfCompiler::CreateVData(BfVDataModule* bfModule) bool needsTypeList = bfModule->IsMethodImplementedAndReified(typeDefType, "GetType"); bool needsObjectTypeData = needsTypeList || bfModule->IsMethodImplementedAndReified(vdataContext->mBfObjectType, "RawGetType") || bfModule->IsMethodImplementedAndReified(vdataContext->mBfObjectType, "GetType"); - bool needsTypeNames = bfModule->IsMethodImplementedAndReified(typeDefType, "GetName"); + bool needsTypeNames = bfModule->IsMethodImplementedAndReified(typeDefType, "GetName") || bfModule->IsMethodImplementedAndReified(typeDefType, "GetFullName"); bool needsStringLiteralList = (mOptions.mAllowHotSwapping) || (bfModule->IsMethodImplementedAndReified(stringType, "Intern")); Dictionary usedStringIdMap; diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index 7ee4652b..3e45a8d8 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -6312,6 +6312,7 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary& usedStrin { typeDataVar = mBfIRBuilder->CreateGlobalVariable(typeInstanceDataType, true, BfIRLinkageType_External, typeInstanceData, typeDataName); + mBfIRBuilder->GlobalVar_SetAlignment(typeDataVar, mSystem->mPtrSize); if (mBfIRBuilder->DbgHasInfo()) { diff --git a/IDEHelper/DbgExprEvaluator.cpp b/IDEHelper/DbgExprEvaluator.cpp index 2bfcd3cf..814698c3 100644 --- a/IDEHelper/DbgExprEvaluator.cpp +++ b/IDEHelper/DbgExprEvaluator.cpp @@ -7190,12 +7190,12 @@ DbgTypedValue DbgExprEvaluator::MatchMethod(BfAstNode* targetSrc, DbgTypedValue } } - auto castedType = mDbgModule->FindType(typeName, NULL, GetLanguage()); + auto castedType = mDbgModule->FindType(typeName, NULL, GetLanguage(), true); if (castedType == NULL) { if (typeName.EndsWith('*')) { - auto noPtrTypeEntry = mDbgModule->FindType(typeName.Substring(0, typeName.length() - 1), NULL, DbgLanguage_Beef); + auto noPtrTypeEntry = mDbgModule->FindType(typeName.Substring(0, typeName.length() - 1), NULL, DbgLanguage_Beef, true); if (noPtrTypeEntry != NULL) castedType = mDbgModule->GetPointerType(noPtrTypeEntry); } diff --git a/IDEHelper/DbgModule.cpp b/IDEHelper/DbgModule.cpp index 3ef72afb..b2729d97 100644 --- a/IDEHelper/DbgModule.cpp +++ b/IDEHelper/DbgModule.cpp @@ -7382,7 +7382,7 @@ DbgType* DbgModule::FindTypeHelper(const String& typeName, DbgType* checkType) return NULL; } -DbgType* DbgModule::FindType(const String& typeName, DbgType* contextType, DbgLanguage language) +DbgType* DbgModule::FindType(const String& typeName, DbgType* contextType, DbgLanguage language, bool bfObjectPtr) { if ((language == DbgLanguage_Unknown) && (contextType != NULL)) language = contextType->mLanguage; @@ -7391,7 +7391,7 @@ DbgType* DbgModule::FindType(const String& typeName, DbgType* contextType, DbgLa { if (typeName[typeName.length() - 1] == '*') { - DbgType* dbgType = FindType(typeName.Substring(0, typeName.length() - 1), contextType, language); + DbgType* dbgType = FindType(typeName.Substring(0, typeName.length() - 1), contextType, language, bfObjectPtr); if (dbgType == NULL) return NULL; return GetPointerType(dbgType); @@ -7400,7 +7400,11 @@ DbgType* DbgModule::FindType(const String& typeName, DbgType* contextType, DbgLa auto entry = GetLinkedModule()->mTypeMap.Find(typeName.c_str(), language); if (entry != NULL) + { + if ((bfObjectPtr) && (entry->mValue->IsBfObject())) + return GetPointerType(entry->mValue); return entry->mValue; + } if (contextType != NULL) { diff --git a/IDEHelper/DbgModule.h b/IDEHelper/DbgModule.h index 29ab1cdd..1daa59b9 100644 --- a/IDEHelper/DbgModule.h +++ b/IDEHelper/DbgModule.h @@ -1298,7 +1298,7 @@ public: //const uint8* CopyOrigImageData(addr_target address, int length); DbgType* FindTypeHelper(const String& typeName, DbgType* checkType); - DbgType* FindType(const String& typeName, DbgType* contextType = NULL, DbgLanguage language = DbgLanguage_Unknown); + DbgType* FindType(const String& typeName, DbgType* contextType = NULL, DbgLanguage language = DbgLanguage_Unknown, bool bfObjectPtr = false); DbgTypeMap::Entry* FindType(const char* typeName, DbgLanguage language); DbgType* GetPointerType(DbgType* innerType); diff --git a/IDEHelper/Tests/src/Reflection.bf b/IDEHelper/Tests/src/Reflection.bf index 265d3380..07c45f94 100644 --- a/IDEHelper/Tests/src/Reflection.bf +++ b/IDEHelper/Tests/src/Reflection.bf @@ -53,6 +53,9 @@ namespace Tests [Reflect] class ClassA { + int32 mA = 123; + String mStr = "A"; + [AlwaysInclude, AttrC(71, 72)] static float StaticMethodA(int32 a, int32 b, float c, ref int32 d, ref StructA sa) { @@ -62,6 +65,18 @@ namespace Tests return a + b + c; } + [AlwaysInclude] + static StructA StaticMethodB(ref int32 a, ref String b) + { + a += 1000; + b = "B"; + + StructA sa; + sa.mA = 12; + sa.mB = 34; + return sa; + } + [AlwaysInclude] float MemberMethodA(int32 a, int32 b, float c) { @@ -168,6 +183,21 @@ namespace Tests Test.Assert(result.Get() == 123); result.Dispose(); + Object aObj = a; + Object saObj = sa; + Test.Assert(methodInfo.Name == "StaticMethodA"); + result = methodInfo.Invoke(null, 100, (int32)20, 3.0f, aObj, saObj).Get(); + Test.Assert(a == 120); + Test.Assert(sa.mA == 101); + Test.Assert(sa.mB == 22); + int32 a2 = (int32)aObj; + StructA sa2 = (StructA)saObj; + Test.Assert(a2 == 240); + Test.Assert(sa2.mA == 201); + Test.Assert(sa2.mB == 42); + Test.Assert(result.Get() == 123); + result.Dispose(); + result = methodInfo.Invoke(.(), .Create(100), .Create((int32)20), .Create(3.0f), .Create(&a), .Create(&sa)).Get(); Test.Assert(a == 240); Test.Assert(sa.mA == 201); @@ -175,10 +205,55 @@ namespace Tests Test.Assert(result.Get() == 123); result.Dispose(); + Variant aV = .CreateOwned(a); + Variant saV = .CreateOwned(sa); + result = methodInfo.Invoke(.(), .Create(100), .Create((int32)20), .Create(3.0f), aV, saV).Get(); + Test.Assert(a == 240); + Test.Assert(sa.mA == 201); + Test.Assert(sa.mB == 42); + a2 = aV.Get(); + sa2 = saV.Get(); + Test.Assert(a2 == 360); + Test.Assert(sa2.mA == 301); + Test.Assert(sa2.mB == 62); + Test.Assert(result.Get() == 123); + aV.Dispose(); + saV.Dispose(); + result.Dispose(); + let attrC = methodInfo.GetCustomAttribute().Get(); Test.Assert(attrC.mA == 71); Test.Assert(attrC.mB == 72); case 1: + Test.Assert(methodInfo.Name == "StaticMethodB"); + + var fieldA = typeInfo.GetField("mA").Value; + var fieldStr = typeInfo.GetField("mStr").Value; + + var fieldAV = fieldA.GetValueReference(ca).Value; + var fieldStrV = fieldStr.GetValueReference(ca).Value; + + Test.Assert(fieldAV.Get() == 123); + Test.Assert(fieldStrV.Get() == "A"); + + var res = methodInfo.Invoke(.(), fieldAV, fieldStrV).Value; + var sa = res.Get(); + Test.Assert(sa.mA == 12); + Test.Assert(sa.mB == 34); + res.Dispose(); + + Test.Assert(fieldAV.Get() == 1123); + Test.Assert(fieldStrV.Get() == "B"); + fieldAV.Dispose(); + fieldStrV.Dispose(); + + fieldAV = fieldA.GetValue(ca).Value; + fieldStrV = fieldStr.GetValue(ca).Value; + Test.Assert(fieldAV.Get() == 1123); + Test.Assert(fieldStrV.Get() == "B"); + fieldAV.Dispose(); + fieldStrV.Dispose(); + case 2: Test.Assert(methodInfo.Name == "MemberMethodA"); var result = methodInfo.Invoke(ca, 100, (int32)20, 3.0f).Get(); Test.Assert(result.Get() == 123); @@ -187,7 +262,7 @@ namespace Tests result = methodInfo.Invoke(.Create(ca), .Create(100), .Create((int32)20), .Create(3.0f)).Get(); Test.Assert(result.Get() == 123); result.Dispose(); - case 2: + case 3: Test.Assert(methodInfo.Name == "GetA"); var result = methodInfo.Invoke(ca, 123).Get(); Test.Assert(result.Get() == 1123); @@ -198,10 +273,10 @@ namespace Tests result = methodInfo.Invoke(.Create(ca2), .Create(123)).Get(); Test.Assert(result.Get() == 2123); result.Dispose(); - case 3: + case 4: Test.Assert(methodInfo.Name == "__BfCtor"); Test.Assert(methodInfo.IsConstructor); - case 4: + case 5: Test.FatalError(); // Shouldn't have any more }