Generic methods evaluation implemented
authorOleg Lekarev <o.lekarev@samsung.com>
Wed, 21 Dec 2022 15:12:26 +0000 (18:12 +0300)
committerAlexander Soldatov/Advanced System SW Lab /SRR/Staff Engineer/Samsung Electronics <soldatov.a@samsung.com>
Tue, 7 Mar 2023 17:18:28 +0000 (20:18 +0300)
14 files changed:
src/debugger/evalhelpers.cpp
src/debugger/evalhelpers.h
src/debugger/evalstackmachine.cpp
src/debugger/evalstackmachine.h
src/debugger/evaluator.cpp
src/debugger/evaluator.h
src/debugger/evalutils.cpp
src/debugger/evalutils.h
src/debugger/hotreloadhelpers.cpp
src/managed/StackMachine.cs
test-suite/MITestEvaluate/Program.cs
test-suite/MITestGeneric/Program.cs
test-suite/VSCodeTestEvaluate/Program.cs
test-suite/VSCodeTestGeneric/Program.cs

index 45848c3be5be221191a64c472ff7b2b0207ed986..7e93b1cd6c8d3ae39f4bf145ae50fad5b4edff02 100644 (file)
@@ -100,6 +100,39 @@ HRESULT EvalHelpers::EvalFunction(
         });
 }
 
+HRESULT EvalHelpers::EvalGenericFunction(
+    ICorDebugThread *pThread,
+    ICorDebugFunction *pFunc,
+    ICorDebugType **ppTypes,
+    ULONG32 typeCount,
+    ICorDebugValue **ppValues,
+    ULONG32 valueCount,
+    ICorDebugValue **ppResult,
+    int flags)
+{
+    assert((!ppTypes && typeCount == 0) || (ppTypes && typeCount > 0));
+    assert((!ppValues && valueCount == 0) || (ppValues && valueCount > 0));
+
+    if (flags & EVAL_NOFUNCEVAL)
+        return S_OK;
+
+    return m_sharedEvalWaiter->WaitEvalResult(pThread, ppResult,
+        [&](ICorDebugEval *pEval) -> HRESULT
+        {
+            // Note, this code execution protected by EvalWaiter mutex.
+            HRESULT Status;
+            ToRelease<ICorDebugEval2> pEval2;
+            IfFailRet(pEval->QueryInterface(IID_ICorDebugEval2, (LPVOID*) &pEval2));
+            IfFailRet(pEval2->CallParameterizedFunction(
+                pFunc,
+                typeCount,
+                ppTypes,
+                valueCount,
+                ppValues));
+            return S_OK;
+        });
+}
+
 static HRESULT GetMethodToken(IMetaDataImport *pMD, mdTypeDef cl, const WCHAR *methodName)
 {
     ULONG numMethods = 0;
index 9b9dadd4ba0d0a8eb05ed41d3c3e25a6fcdc92ea..2d702aed436f5c2353a1a7c6e960fff8b631e231 100644 (file)
@@ -47,6 +47,16 @@ public:
         ICorDebugValue **ppEvalResult,
         int evalFlags);
 
+    HRESULT EvalGenericFunction(
+        ICorDebugThread *pThread,
+        ICorDebugFunction *pFunc,
+        ICorDebugType **ppArgsType,
+        ULONG32 ArgsTypeCount,
+        ICorDebugValue **ppArgsValue,
+        ULONG32 ArgsValueCount,
+        ICorDebugValue **ppEvalResult,
+        int evalFlags);
+
     HRESULT GetLiteralValue(
         ICorDebugThread *pThread,
         ICorDebugType *pType,
index ab226917ba8e2f5e3a8dd0f0bd394ffad9784483..dc158f710502aaa540b0f6353ebc1bc950e7b4df 100644 (file)
@@ -11,6 +11,7 @@
 #include "debugger/evalhelpers.h"
 #include "debugger/evalwaiter.h"
 #include "debugger/valueprint.h"
+#include "debugger/evalutils.h"
 #include "managed/interop.h"
 #include "metadata/typeprinter.h"
 #include "utils/utf.h"
@@ -1035,15 +1036,45 @@ namespace
 
     HRESULT GenericName(std::list<EvalStackEntry> &evalStack, PVOID pArguments, std::string &output, EvalData &ed)
     {
-        // TODO uint32_t Flags = ((FormatFIS*)pArguments)->Flags;
-        // TODO int32_t Int = ((FormatFIS*)pArguments)->Int;
-        // TODO std::string String = to_utf8(((FormatFIS*)pArguments)->wString);
-        return E_NOTIMPL;
+        HRESULT Status;
+        int32_t Int = ((FormatFIS*)pArguments)->Int;
+        std::string String = to_utf8(((FormatFIS*)pArguments)->wString);
+        std::vector<ToRelease<ICorDebugType>> genericValues;
+        std::string generics = ">";
+        genericValues.reserve(Int);
+        for(int i = 0; i < Int; i++)
+        {
+            ToRelease<ICorDebugValue> icdv;
+            ToRelease<ICorDebugType> icdt;
+            ToRelease<ICorDebugValue2> icdv2;
+            std::string genericType;
+            Status = GetFrontStackEntryValue(&icdv, nullptr, evalStack, ed, output);
+            if(Status == S_OK) {
+                IfFailRet(icdv->QueryInterface(IID_ICorDebugValue2, (LPVOID *) &icdv2));
+                IfFailRet(icdv2->GetExactType(&icdt));
+            }
+            else {
+                IfFailRet(GetFrontStackEntryType(&icdt, evalStack, ed, output));
+            }
+            TypePrinter::GetTypeOfValue(icdt, genericType);
+            generics = "," + genericType + generics;
+            genericValues.emplace_back(icdt.Detach());
+            evalStack.pop_front();
+        }
+        generics.erase(0,1);
+        String += "<" + generics;
+        evalStack.emplace_front();
+        evalStack.front().identifiers.emplace_back(std::move(String));
+        evalStack.front().genericTypeCache = std::move(genericValues);
+        evalStack.front().editable = true;
+        return S_OK;
     }
 
     HRESULT InvocationExpression(std::list<EvalStackEntry> &evalStack, PVOID pArguments, std::string &output, EvalData &ed)
     {
+        // todo:        static const char* extensionAttributeName = "System.Runtime.CompilerServices.ExtensionAttribute..ctor";
         int32_t Int = ((FormatFI*)pArguments)->Int;
+
         if (Int < 0)
             return E_INVALIDARG;
 
@@ -1057,12 +1088,21 @@ namespace
             evalStack.pop_front();
         }
 
+        if (evalStack.front().preventBinding)
+            return S_OK;
+
         assert(evalStack.front().identifiers.size() > 0); // We must have at least method name (identifier).
 
         // TODO local defined function (compiler will create such function with name like `<Calc1>g__Calc2|0_0`)
-        std::string funcName = evalStack.front().identifiers.back();
+        std::string funcNameGenerics = evalStack.front().identifiers.back();
         evalStack.front().identifiers.pop_back();
 
+        std::string funcName;
+        std::vector<std::string> methodGenericStrings = EvalUtils::ParseGenericParams(funcNameGenerics, funcName);
+        size_t pos = funcName.find('`');
+        if (pos != std::string::npos)
+            funcName.resize(pos);
+
         if (!evalStack.front().iCorValue && evalStack.front().identifiers.empty())
         {
             std::string methodClass;
@@ -1134,8 +1174,15 @@ namespace
                 IfFailRet(TypePrinter::GetTypeOfValue(iCorValueArg, funcArgs[i].typeName));
         }
 
+        std::vector<Evaluator::ArgElementType> methodGenerics;
+        methodGenerics.reserve(methodGenericStrings.size());
+        for(ULONG32 i = 0; i < methodGenericStrings.size(); i++)
+        {
+            methodGenerics.emplace_back(ed.pEvaluator->GetElementTypeByTypeName(methodGenericStrings[i]));
+        }
+
         ToRelease<ICorDebugFunction> iCorFunc;
-        ed.pEvaluator->WalkMethods(iCorType, [&](
+        ed.pEvaluator->WalkMethods(iCorType, methodGenerics, [&](
             bool is_static,
             const std::string &methodName,
             Evaluator::ReturnElementType&,
@@ -1148,8 +1195,7 @@ namespace
 
             for (size_t i = 0; i < funcArgs.size(); ++i)
             {
-                if (funcArgs[i].corType != methodArgs[i].corType ||
-                    funcArgs[i].typeName != methodArgs[i].typeName)
+                if (funcArgs[i] != methodArgs[i])
                     return S_OK;
             }
 
@@ -1158,24 +1204,49 @@ namespace
 
             return E_ABORT; // Fast exit from cycle.
         });
+
         if (!iCorFunc)
             return E_FAIL;
 
-        evalStack.front().ResetEntry();
-
+        size_t typeArgsCount = evalStack.front().genericTypeCache.size();
         ULONG32 realArgsCount = Int + (isInstance ? 1 : 0);
+        std::vector<ICorDebugType*> iCorTypeArgs;
         std::vector<ICorDebugValue*> iCorValueArgs;
         iCorValueArgs.reserve(realArgsCount);
+        iCorTypeArgs.reserve(typeArgsCount);
+
+        // Place instance value ("this") if not static
         if (isInstance)
         {
             iCorValueArgs.emplace_back(iCorValue.GetPtr());
         }
+
+        // Add arguments values
         for (int32_t i = 0; i < Int; i++)
         {
             iCorValueArgs.emplace_back(iCorArgs[i].GetPtr());
         }
 
-        Status = ed.pEvalHelpers->EvalFunction(ed.pThread, iCorFunc, nullptr, 0, iCorValueArgs.data(), realArgsCount, &evalStack.front().iCorValue, ed.evalFlags);
+        // Collect type(class)'s generic types if any
+        ToRelease<ICorDebugTypeEnum> pTypeEnum;
+        if (SUCCEEDED(iCorType->EnumerateTypeParameters(&pTypeEnum)))
+        {
+            ICorDebugType *curType;
+            ULONG fetched = 0;
+            while (SUCCEEDED(pTypeEnum->Next(1, &curType, &fetched)) && fetched == 1)
+            {
+                iCorTypeArgs.emplace_back(curType);
+            }
+        }
+
+        // Add method's generic types if any
+        for (size_t i = typeArgsCount; i > 0; i--)
+        {
+            iCorTypeArgs.emplace_back(evalStack.front().genericTypeCache[i-1].GetPtr());
+        }
+
+        evalStack.front().ResetEntry();
+        Status = ed.pEvalHelpers->EvalGenericFunction(ed.pThread, iCorFunc, iCorTypeArgs.data(), (ULONG32)iCorTypeArgs.size(), iCorValueArgs.data(), (ULONG32)iCorValueArgs.size(), &evalStack.front().iCorValue, ed.evalFlags);
 
         // CORDBG_S_FUNC_EVAL_HAS_NO_RESULT: Some Func evals will lack a return value, such as those whose return type is void.
         if (Status == CORDBG_S_FUNC_EVAL_HAS_NO_RESULT)
@@ -1456,7 +1527,7 @@ namespace
             ELEMENT_TYPE_MAX,       // Object
             ELEMENT_TYPE_I1,        // SByte
             ELEMENT_TYPE_I2,        // Short
-            ELEMENT_TYPE_MAX,       // String
+            ELEMENT_TYPE_STRING,    // String
             ELEMENT_TYPE_U2,        // UShort
             ELEMENT_TYPE_U4,        // UInt
             ELEMENT_TYPE_U8         // ULong
@@ -1464,13 +1535,16 @@ namespace
 
         // TODO uint32_t Flags = ((FormatFI*)pArguments)->Flags;
         int32_t Int = ((FormatFI*)pArguments)->Int;
+        std::string String;
 
         evalStack.emplace_front();
 
         if (BasicTypesAlias[Int] == ELEMENT_TYPE_VALUETYPE)
-            return CreateValueType(ed.pEvalWaiter, ed.pThread, ed.iCorDecimalClass, &evalStack.front().iCorValuePredefined, nullptr);
+            return CreateValueType(ed.pEvalWaiter, ed.pThread, ed.iCorDecimalClass, &evalStack.front().iCorValue, nullptr);
+        else if (BasicTypesAlias[Int] == ELEMENT_TYPE_STRING)
+            return ed.pEvalHelpers->CreateString(ed.pThread, String, &evalStack.front().iCorValue);
         else
-            return CreatePrimitiveValue(ed.pThread, &evalStack.front().iCorValuePredefined, BasicTypesAlias[Int], nullptr);
+            return CreatePrimitiveValue(ed.pThread, &evalStack.front().iCorValue, BasicTypesAlias[Int], nullptr);
     }
 
     HRESULT AliasQualifiedName(std::list<EvalStackEntry> &evalStack, PVOID pArguments, std::string &output, EvalData &ed)
@@ -1525,11 +1599,22 @@ namespace
         assert(evalStack.front().identifiers.size() == 1); // Only one unresolved identifier must be here.
 
         std::string identifier = std::move(evalStack.front().identifiers[0]);
+        std::vector<ToRelease<ICorDebugType>> iCorDebugTypes;
+        size_t genericsCount = evalStack.front().genericTypeCache.size();
+        if (genericsCount > 0)
+        {
+            iCorDebugTypes = std::move(evalStack.front().genericTypeCache);
+        }
         evalStack.pop_front();
-
         if (!evalStack.front().preventBinding)
+        {
             evalStack.front().identifiers.emplace_back(std::move(identifier));
-
+            evalStack.front().genericTypeCache.clear(); // We need method's generics only, so remove all previous if exist.
+            if (genericsCount > 0)
+            {
+                evalStack.front().genericTypeCache = std::move(iCorDebugTypes);
+            }
+        }
         return S_OK;
     }
 
@@ -1724,20 +1809,20 @@ namespace
         uint32_t size = 0;
         PVOID szPtr = &size;
 
-        if (evalStack.front().iCorValuePredefined)
+        if (evalStack.front().iCorValue)
         {
             //  predefined type
             CorElementType elType;
-            IfFailRet(evalStack.front().iCorValuePredefined->GetType(&elType));
+            IfFailRet(evalStack.front().iCorValue->GetType(&elType));
             if(elType == ELEMENT_TYPE_CLASS)
             {
                 ToRelease<ICorDebugValue> iCorValue;
-                IfFailRet(DereferenceAndUnboxValue(evalStack.front().iCorValuePredefined, &iCorValue, nullptr));
+                IfFailRet(DereferenceAndUnboxValue(evalStack.front().iCorValue, &iCorValue, nullptr));
                 IfFailRet(iCorValue->GetSize(&size));
             }
             else
             {
-                IfFailRet(evalStack.front().iCorValuePredefined->GetSize(&size));
+                IfFailRet(evalStack.front().iCorValue->GetSize(&size));
             }
         }
         else
index 71d3c44ee0aeff00ae6210194ba0c7697e7343ed..30b5d20ae8d53c517fe896846ee2f2c687aa2981 100644 (file)
@@ -35,8 +35,9 @@ struct EvalStackEntry
     std::vector<std::string> identifiers;\r
     // Resolved to value identifiers.\r
     ToRelease<ICorDebugValue> iCorValue;\r
-    // Predefined types values\r
-    ToRelease<ICorDebugValue> iCorValuePredefined;\r
+    // Generic types cache. Note, finally we need the method's generic types only, i.e. the last element of\r
+    // identifiers vector. The other type(class)'s generics can easily be got from the corresponding iCorDebugType\r
+    std::vector<ToRelease<ICorDebugType>> genericTypeCache;\r
     // Prevent future binding in case of conditional access with nulled object (`a?.b`, `a?[1]`, ...).\r
     // Note, this state could be related to iCorValue only (iCorValue must be checked for null first).\r
     bool preventBinding;\r
@@ -55,7 +56,7 @@ struct EvalStackEntry
     {\r
         identifiers.clear();\r
         iCorValue.Free();\r
-        iCorValuePredefined.Free();\r
+        genericTypeCache.clear();\r
         preventBinding = false;\r
         if (resetLiteral == ResetLiteralStatus::Yes)\r
             literal = false;\r
index ca73874a1b90420c90ea76a9b5a58a0ab7535980..66af3237ac458d54ad2b194fbcc6778f7b5bd5f1 100644 (file)
 #include "utils/utf.h"
 #include "metadata/modules.h"
 #include "metadata/typeprinter.h"
+#include "metadata/attributes.h"
 #include "valueprint.h"
 #include "managed/interop.h"
 
 namespace netcoredbg
 {
 
+bool Evaluator::ArgElementType::isAlias(const CorElementType type1, const CorElementType type2, const std::string& name2)
+{
+    static const std::unordered_map<CorElementType, ArgElementType> aliases = {
+        {ELEMENT_TYPE_BOOLEAN, {ELEMENT_TYPE_VALUETYPE, "System.Boolean"}},
+        {ELEMENT_TYPE_CHAR,    {ELEMENT_TYPE_VALUETYPE, "System.Char"}},
+        {ELEMENT_TYPE_I1,      {ELEMENT_TYPE_VALUETYPE, "System.Byte"}},
+        {ELEMENT_TYPE_U1,      {ELEMENT_TYPE_VALUETYPE, "System.SByte"}},
+        {ELEMENT_TYPE_R8,      {ELEMENT_TYPE_VALUETYPE, "System.Double"}},
+        {ELEMENT_TYPE_R4,      {ELEMENT_TYPE_VALUETYPE, "System.Single"}},
+        {ELEMENT_TYPE_I4,      {ELEMENT_TYPE_VALUETYPE, "System.Int32"}},
+        {ELEMENT_TYPE_U4,      {ELEMENT_TYPE_VALUETYPE, "System.UInt32"}},
+        {ELEMENT_TYPE_I8,      {ELEMENT_TYPE_VALUETYPE, "System.Int64"}},
+        {ELEMENT_TYPE_U8,      {ELEMENT_TYPE_VALUETYPE, "System.UInt64"}},
+        {ELEMENT_TYPE_OBJECT,  {ELEMENT_TYPE_CLASS,     "System.Object"}},
+        {ELEMENT_TYPE_I2,      {ELEMENT_TYPE_VALUETYPE, "System.Int16"}},
+        {ELEMENT_TYPE_U2,      {ELEMENT_TYPE_VALUETYPE, "System.UInt16"}},
+        {ELEMENT_TYPE_STRING,  {ELEMENT_TYPE_CLASS,     "System.String"}}
+    };
+
+    auto found = aliases.find(type1);
+    if (found != aliases.end())
+    {
+        if (found->second.corType == type2 && found->second.typeName == name2)
+            return true;
+    }
+    return false;
+}
+
+bool Evaluator::ArgElementType::areEqual(const ArgElementType& arg)
+{
+    if (corType == arg.corType && typeName == arg.typeName)
+        return true;
+    if (isAlias(corType, arg.corType, arg.typeName))
+        return true;
+    if (isAlias(arg.corType, corType, typeName))
+        return true;
+    return false;
+}
+
+Evaluator::ArgElementType Evaluator::GetElementTypeByTypeName(const std::string typeName)
+{
+    static const std::unordered_map<std::string, Evaluator::ArgElementType> stypes = {
+        {"void",    {ELEMENT_TYPE_VALUETYPE, "System.Void"}},
+        {"bool",    {ELEMENT_TYPE_VALUETYPE, "System.Boolean"}},
+        {"byte",    {ELEMENT_TYPE_VALUETYPE, "System.Byte"}},
+        {"sbyte",   {ELEMENT_TYPE_VALUETYPE, "System.SByte"}},
+        {"char",    {ELEMENT_TYPE_VALUETYPE, "System.Char"}},
+        {"decimal", {ELEMENT_TYPE_VALUETYPE, "System.Decimal"}},
+        {"double",  {ELEMENT_TYPE_VALUETYPE, "System.Double"}},
+        {"float",   {ELEMENT_TYPE_VALUETYPE, "System.Single"}},
+        {"int",     {ELEMENT_TYPE_VALUETYPE, "System.Int32"}},
+        {"uint",    {ELEMENT_TYPE_VALUETYPE, "System.UInt32"}},
+        {"long",    {ELEMENT_TYPE_VALUETYPE, "System.Int64"}},
+        {"ulong",   {ELEMENT_TYPE_VALUETYPE, "System.UInt64"}},
+        {"object",  {ELEMENT_TYPE_CLASS,     "System.Object"}},
+        {"short",   {ELEMENT_TYPE_VALUETYPE, "System.Int16"}},
+        {"ushort",  {ELEMENT_TYPE_VALUETYPE, "System.UInt16"}},
+        {"string",  {ELEMENT_TYPE_CLASS,     "System.String"}},
+        {"IntPtr",  {ELEMENT_TYPE_VALUETYPE, "System.IntPtr"}},
+        {"UIntPtr", {ELEMENT_TYPE_VALUETYPE, "System.UIntPtr"}}
+    };
+
+    Evaluator::ArgElementType userType;
+    auto found = stypes.find(typeName);
+    if (found != stypes.end())
+    {
+        return found->second;
+    }
+    userType.corType = ELEMENT_TYPE_CLASS;
+    userType.typeName = typeName;
+    return userType;
+}
+
 HRESULT Evaluator::GetElement(ICorDebugValue *pInputValue, std::vector<ULONG32> &indexes, ICorDebugValue **ppResultValue)
 {
     HRESULT Status;
@@ -261,7 +335,8 @@ static void GetCorTypeName(ULONG corType, std::string &typeName)
 static HRESULT ParseElementType(IMetaDataImport *pMD,
                                 PCCOR_SIGNATURE *ppSig,
                                 Evaluator::ArgElementType &argElementType,
-                                std::vector<Evaluator::ArgElementType> &genericArgs,
+                                std::vector<Evaluator::ArgElementType> &typeGenerics,
+                                std::vector<Evaluator::ArgElementType> &methodGenerics,
                                 bool addCorTypeName = false)
 {
     HRESULT Status;
@@ -299,14 +374,14 @@ static HRESULT ParseElementType(IMetaDataImport *pMD,
             break;
 
         case ELEMENT_TYPE_SZARRAY:
-            if (FAILED(Status = ParseElementType(pMD, ppSig, argElementType, genericArgs, true)) || Status == S_FALSE)
+            if (FAILED(Status = ParseElementType(pMD, ppSig, argElementType, typeGenerics, methodGenerics, true)) || Status == S_FALSE)
                 return Status;
             argElementType.corType = (CorElementType)corType;
             argElementType.typeName += "[]";
             break;
         case ELEMENT_TYPE_ARRAY:
         {
-            if (FAILED(Status = ParseElementType(pMD, ppSig, argElementType, genericArgs, true)) || Status == S_FALSE)
+            if (FAILED(Status = ParseElementType(pMD, ppSig, argElementType, typeGenerics, methodGenerics, true)) || Status == S_FALSE)
                 return Status;
             argElementType.corType = (CorElementType)corType;
             // Parse for the rank
@@ -337,23 +412,52 @@ static HRESULT ParseElementType(IMetaDataImport *pMD,
 
         case ELEMENT_TYPE_VAR: // Generic parameter in a generic type definition, represented as number
             *ppSig += CorSigUncompressData(*ppSig, &argNum);
-            if (argNum >= genericArgs.size())
+            if (argNum >= typeGenerics.size())
                 return S_FALSE;
             else
             {
-                argElementType = genericArgs[argNum];
+                argElementType = typeGenerics[argNum];
                 if (addCorTypeName && argElementType.typeName.empty())
                     GetCorTypeName(argElementType.corType, argElementType.typeName);
             }
             break;
+
+        case ELEMENT_TYPE_MVAR: // Generic parameter in a generic method definition, represented as number
+            *ppSig += CorSigUncompressData(*ppSig, &argNum);
+            if (argNum >= methodGenerics.size())
+                return S_FALSE;
+            else
+            {
+                argElementType = methodGenerics[argNum];
+                if (addCorTypeName && argElementType.typeName.empty())
+                    GetCorTypeName(argElementType.corType, argElementType.typeName);
+            }
+            break;
+
+        case ELEMENT_TYPE_GENERICINST: // A type modifier for generic types - List<>, Dictionary<>, ...
+            ULONG number;
+            mdToken token;
+            *ppSig += CorSigUncompressData(*ppSig, &corType);
+            if(corType != ELEMENT_TYPE_CLASS && corType != ELEMENT_TYPE_VALUETYPE)
+                return S_FALSE;
+            *ppSig += CorSigUncompressToken(*ppSig, &token);
+            argElementType.corType = (CorElementType)corType;
+            IfFailRet(TypePrinter::NameForTypeByToken(token, pMD, argElementType.typeName, nullptr));
+            *ppSig += CorSigUncompressData(*ppSig, &number);
+            for(ULONG i = 0; i < number; i++)
+            {
+                Evaluator::ArgElementType mycop; // Not needed at the moment
+                if (FAILED(Status = ParseElementType(pMD, ppSig, mycop, typeGenerics, methodGenerics, true)) || Status == S_FALSE)
+                    return Status;
+            }
+            break;
+
 // TODO
         case ELEMENT_TYPE_U: // "nuint" - error CS8652: The feature 'native-sized integers' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
         case ELEMENT_TYPE_I: // "nint" - error CS8652: The feature 'native-sized integers' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
         case ELEMENT_TYPE_TYPEDBYREF:
         case ELEMENT_TYPE_PTR: // int* ptr (unsafe code only)
         case ELEMENT_TYPE_BYREF: // ref, in, out
-        case ELEMENT_TYPE_MVAR: // Generic parameter in a generic method definition, represented as number
-        case ELEMENT_TYPE_GENERICINST: // A type modifier for generic types - List<>, Dictionary<>, ...
         case ELEMENT_TYPE_CMOD_REQD:
         case ELEMENT_TYPE_CMOD_OPT:
             return S_FALSE;
@@ -372,11 +476,12 @@ HRESULT Evaluator::WalkMethods(ICorDebugValue *pInputTypeValue, WalkMethodsCallb
     IfFailRet(pInputTypeValue->QueryInterface(IID_ICorDebugValue2, (LPVOID *) &iCorValue2));
     ToRelease<ICorDebugType> iCorType;
     IfFailRet(iCorValue2->GetExactType(&iCorType));
+    std::vector<Evaluator::ArgElementType> methodGenerics;
 
-    return WalkMethods(iCorType, cb);
+    return WalkMethods(iCorType, methodGenerics, cb);
 }
 
-static HRESULT InternalWalkMethods(ICorDebugType *pInputType, Evaluator::WalkMethodsCallback cb)
+static HRESULT InternalWalkMethods(ICorDebugType *pInputType, std::vector<Evaluator::ArgElementType> &methodGenerics, Evaluator::WalkMethodsCallback cb)
 {
     HRESULT Status;
     ToRelease<ICorDebugClass> pClass;
@@ -390,7 +495,7 @@ static HRESULT InternalWalkMethods(ICorDebugType *pInputType, Evaluator::WalkMet
     ToRelease<IMetaDataImport> pMD;
     IfFailRet(pMDUnknown->QueryInterface(IID_IMetaDataImport, (LPVOID*) &pMD));
 
-    std::vector<Evaluator::ArgElementType> genericArgs;
+    std::vector<Evaluator::ArgElementType> typeGenerics;
     ToRelease<ICorDebugTypeEnum> paramTypes;
 
     if (SUCCEEDED(pInputType->EnumerateTypeParameters(&paramTypes)))
@@ -404,7 +509,7 @@ static HRESULT InternalWalkMethods(ICorDebugType *pInputType, Evaluator::WalkMet
             pCurrentTypeParam->GetType(&argElType.corType);
             if(argElType.corType == ELEMENT_TYPE_VALUETYPE || argElType.corType == ELEMENT_TYPE_CLASS)
                 IfFailRet(TypePrinter::NameForTypeByType(pCurrentTypeParam, argElType.typeName));
-            genericArgs.emplace_back(argElType);
+            typeGenerics.emplace_back(argElType);
             pCurrentTypeParam.Free();
         }
     }
@@ -429,6 +534,7 @@ static HRESULT InternalWalkMethods(ICorDebugType *pInputType, Evaluator::WalkMet
                                      szFunctionName, _countof(szFunctionName), &nameLen,
                                      &methodAttr, &pSig, &cbSig, nullptr,  nullptr)))
             continue;
+        ULONG gParams; // Count of signature generics
         ULONG cParams; // Count of signature parameters.
         ULONG elementSize;
         ULONG convFlags;
@@ -438,26 +544,32 @@ static HRESULT InternalWalkMethods(ICorDebugType *pInputType, Evaluator::WalkMet
         elementSize = CorSigUncompressData(pSig, &convFlags);
         pSig += elementSize;
 
-        // TODO add VARARG and GENERIC methods support.
-        if ((convFlags & SIG_METHOD_VARARG) ||
-            (convFlags & SIG_METHOD_GENERIC))
+        // TODO add VARARG methods support.
+        if (convFlags & SIG_METHOD_VARARG)
             continue;
 
-        // 2. count of params
+        // 2. count of generics if any
+        if (convFlags & SIG_METHOD_GENERIC)
+        {
+            elementSize = CorSigUncompressData(pSig, &gParams);
+            pSig += elementSize;
+        }
+
+        // 3. count of params
         elementSize = CorSigUncompressData(pSig, &cParams);
         pSig += elementSize;
 
-        // 3. return type
+        // 4. return type
         Evaluator::ArgElementType returnElementType;
-        IfFailRet(ParseElementType(pMD, &pSig, returnElementType, genericArgs));
+        IfFailRet(ParseElementType(pMD, &pSig, returnElementType, typeGenerics, methodGenerics));
         if (Status == S_FALSE)
             continue;
 
-        // 4. get next element from method signature
+        // 5. get next element from method signature
         std::vector<Evaluator::ArgElementType> argElementTypes(cParams);
         for (ULONG i = 0; i < cParams; ++i)
         {
-            IfFailRet(ParseElementType(pMD, &pSig, argElementTypes[i], genericArgs));
+            IfFailRet(ParseElementType(pMD, &pSig, argElementTypes[i], typeGenerics, methodGenerics));
             if (Status == S_FALSE)
                 break;
         }
@@ -483,15 +595,15 @@ static HRESULT InternalWalkMethods(ICorDebugType *pInputType, Evaluator::WalkMet
     ToRelease<ICorDebugType> iCorBaseType;
     if(SUCCEEDED(pInputType->GetBase(&iCorBaseType)) && iCorBaseType != NULL)
     {
-        IfFailRet(InternalWalkMethods(iCorBaseType, cb));
+        IfFailRet(InternalWalkMethods(iCorBaseType, methodGenerics, cb));
     }
 
     return S_OK;
 }
 
-HRESULT Evaluator::WalkMethods(ICorDebugType *pInputType, Evaluator::WalkMethodsCallback cb)
+HRESULT Evaluator::WalkMethods(ICorDebugType *pInputType, std::vector<Evaluator::ArgElementType> &methodGenerics, Evaluator::WalkMethodsCallback cb)
 {
-    return InternalWalkMethods(pInputType, cb);
+    return InternalWalkMethods(pInputType, methodGenerics, cb);
 }
 
 static HRESULT InternalSetValue(EvalStackMachine *pEvalStackMachine, EvalHelpers *pEvalHelpers, ICorDebugThread *pThread, FrameLevel frameLevel,
@@ -1640,3 +1752,4 @@ HRESULT Evaluator::ResolveIdentifiers(ICorDebugThread *pThread, FrameLevel frame
 }
 
 } // namespace netcoredbg
+
index a22d3f4926f66111649b54f5b6f49953781c0294..c9dd56b796221c1e5c35c268857dc68d742b840a 100644 (file)
@@ -34,7 +34,19 @@ public:
         ArgElementType() :
             corType(ELEMENT_TYPE_END)
         {}
+
+        ArgElementType(CorElementType t, std::string n)
+        {
+            corType = t;
+            typeName = n;
+        }
+
+        bool isAlias (const CorElementType type1, const CorElementType type2, const std::string& name2);
+        bool areEqual(const ArgElementType& arg);
+        inline bool operator==(const ArgElementType& arg) { return areEqual(arg); }
+        inline bool operator!=(const ArgElementType& arg) { return !areEqual(arg); }
     };
+
     typedef ArgElementType ReturnElementType;
 
     struct SetterData
@@ -120,12 +132,13 @@ public:
         bool &thisParam);
 
     HRESULT GetElement(ICorDebugValue *pInputValue, std::vector<ULONG32> &indexes, ICorDebugValue **ppResultValue);
-    HRESULT WalkMethods(ICorDebugType *pInputType, WalkMethodsCallback cb);
+    HRESULT WalkMethods(ICorDebugType *pInputType, std::vector<Evaluator::ArgElementType> &methodGenerics, WalkMethodsCallback cb);
     HRESULT WalkMethods(ICorDebugValue *pInputTypeValue, WalkMethodsCallback cb);
-
     HRESULT SetValue(ICorDebugThread *pThread, FrameLevel frameLevel, ICorDebugValue *pValue, SetterData *setterData,
                      const std::string &value, int evalFlags, std::string &output);
 
+    ArgElementType GetElementTypeByTypeName(const std::string typeName);
+
 private:
 
     std::shared_ptr<Modules> m_sharedModules;
index 91e2ba32f11c7a8f84e7f6648bf867e0ff730fc6..5260733211d41ede9eb9999ebe21e99442af76fa 100644 (file)
@@ -14,7 +14,7 @@ namespace netcoredbg
 namespace EvalUtils
 {
 
-    static std::vector<std::string> ParseGenericParams(const std::string &identifier, std::string &typeName)
+    std::vector<std::string> ParseGenericParams(const std::string &identifier, std::string &typeName)
     {
         std::vector<std::string> result;
 
index 9b58bfd40ab56c3413ae440a3ab184a27d8f4245..53da52476c87715586adc2f3f8e7a9892425691c 100644 (file)
@@ -21,6 +21,7 @@ namespace EvalUtils
     std::vector<std::string> ParseType(const std::string &expression, std::vector<int> &ranks);
     HRESULT FindType(const std::vector<std::string> &identifiers, int &nextIdentifier, ICorDebugThread *pThread, Modules *pModules,
                      ICorDebugModule *pModule, ICorDebugType **ppType, ICorDebugModule **ppModule = nullptr);
+    std::vector<std::string> ParseGenericParams(const std::string &identifier, std::string &typeName);
 }
 
 } // namespace netcoredbg
index a25e5d074b7d9aa0ca942ea9daea2af04dc5600e..27876e87b5e99ccb7cba957a305bde50061deeda 100644 (file)
@@ -71,9 +71,10 @@ HRESULT UpdateApplication(ICorDebugThread *pThread, Modules *pModules, Evaluator
 
     std::list<ToRelease<ICorDebugFunction>> listClearCache;
     std::list<ToRelease<ICorDebugFunction>> listUpdateApplication;
+    std::vector<Evaluator::ArgElementType> emptyVector;
     for (auto &updateHandlerType : modulesUpdateHandlerTypes)
     {
-        pEvaluator->WalkMethods(updateHandlerType.GetPtr(), [&](
+        pEvaluator->WalkMethods(updateHandlerType.GetPtr(), emptyVector, [&](
             bool is_static,
             const std::string &methodName,
             Evaluator::ReturnElementType &methodRet,
index 4bb451a1dfd06f97e7183593245341c8eeccd856..093bc7efe0a8986d6a734ac2008d4b683023d257 100644 (file)
@@ -564,7 +564,7 @@ namespace NetCoreDbg
                         case SyntaxKind.StringLiteralExpression:
                             stackMachineProgram.Commands.Add(new OneOperandCommand(node.Kind(), CurrentScopeFlags.Peek(), node.GetFirstToken().Value));
                             break;
-/* TODO
+
                         case SyntaxKind.GenericName:
                             // GenericName
                             //     \ TypeArgumentList
@@ -595,7 +595,7 @@ namespace NetCoreDbg
                             }
                             stackMachineProgram.Commands.Add(new TwoOperandCommand(node.Kind(), CurrentScopeFlags.Peek(), node.GetFirstToken().Value, GenericNameArgs));
                             break;
-*/
+
                         case SyntaxKind.InvocationExpression:
 /* TODO
                         case SyntaxKind.ObjectCreationExpression:
@@ -669,8 +669,8 @@ namespace NetCoreDbg
                         case SyntaxKind.ConditionalAccessExpression:
                         case SyntaxKind.ArgumentList:
                         case SyntaxKind.ParenthesizedExpression:
-/* TODO
                         case SyntaxKind.TypeArgumentList:
+/* TODO
                         case SyntaxKind.OmittedTypeArgument:
                         case SyntaxKind.UncheckedExpression:
                         case SyntaxKind.CheckedExpression:
@@ -758,7 +758,6 @@ namespace NetCoreDbg
                 {
                     sb.AppendFormat("    {0}\n", command.ToString());
                 }
-
                 return sb.ToString();
             }
 #endif
index dee834c20a89b521c6bc8128688bfdfc39b364e1..e32cc1c51b91bc742272230cd01b656dc6e971ff 100644 (file)
@@ -540,6 +540,7 @@ namespace MITestEvaluate
     public class MethodCallTest2
     {
         public static MethodCallTest1 member1 = new MethodCallTest1();
+        public MethodCallTest1 nullMember;
     }
 
     public class MethodCallTest3
@@ -1270,6 +1271,9 @@ namespace MITestEvaluate
             }
 
             MethodCallTest1 MethodCallTest = new MethodCallTest1();
+            MethodCallTest1 methodCallTest1Null;
+            MethodCallTest2 methodCallTest2 = new MethodCallTest2();
+            MethodCallTest2 methodCallTest2Null;
             test_child TestCallChild = new test_child();
             test_parent TestCallParentOverride = new test_child();
             test_parent TestCallParent = new test_parent();
@@ -1302,6 +1306,12 @@ namespace MITestEvaluate
                 Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "MethodCallTest?.Calc1()", "Error");
                 Context.GetAndCheckValue(@"__FILE__:__LINE__", "6", "int", "MethodCallTest?.Calc2()");
                 Context.GetAndCheckValue(@"__FILE__:__LINE__", "\\\"MITestEvaluate.MethodCallTest1\\\"", "string", "MethodCallTest?.ToString()");
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "null", "MITestEvaluate.MethodCallTest1", "methodCallTest1Null?.Calc2()");
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "{System.NullReferenceException}", "System.NullReferenceException", "methodCallTest1Null.Calc2()");
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "null", "MITestEvaluate.MethodCallTest2", "methodCallTest2Null?.member.Calc2()");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "methodCallTest2Null.member.Calc2()", "Error");
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "{System.NullReferenceException}", "System.NullReferenceException", "methodCallTest2.nullMember.Calc2()");
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "null", "MITestEvaluate.MethodCallTest1", "methodCallTest2.nullMember?.Calc2()");
 
                 // Call non static method in static member.
                 Context.GetAndCheckValue(@"__FILE__:__LINE__", "6", "int", "MITestEvaluate.MethodCallTest2.member1.Calc2()");
index fc72f8eee689f6a1119db10744dc5dd97a6cd4db..d1c09bbd01f106af6e8c30ee5166a8ec439f5886 100644 (file)
@@ -244,27 +244,151 @@ namespace MITestGeneric
 {\r
     class Program\r
     {\r
+        public class MY\r
+        {\r
+            public int m;\r
+            public static int retme(int arg1)\r
+            {\r
+                return arg1;\r
+            }\r
+        }\r
+\r
+        public class TestNested<X,Y>\r
+        {\r
+            public class Nested<A,B>\r
+            {\r
+                public static MY my;\r
+\r
+                public A test1(A arga)\r
+                {\r
+                    return arga;\r
+                }\r
+\r
+                public B test1(B argb)\r
+                {\r
+                    return argb;\r
+                }\r
+\r
+                public C test3<C>(A arga, B argb, C argc)\r
+                {\r
+                    return argc;\r
+                }\r
+\r
+                public static A static_test1(A arga)\r
+                {\r
+                    return arga;\r
+                }\r
+\r
+                public static B static_test1(B argb)\r
+                {\r
+                    return argb;\r
+                }\r
+\r
+                public static C static_test3<C>(A arga, B argb, C argc)\r
+                {\r
+                    return argc;\r
+                }\r
+            }\r
+\r
+            public static Nested<X,Y> static_nested;\r
+            public Nested<X,Y> nested;\r
+            public Nested<X,Y> uninitialized;\r
+            public TestNested()\r
+            {\r
+                nested = new Nested<X,Y>();\r
+            }\r
+        }\r
+\r
         public class TestGeneric<T,U>\r
         {\r
+            public T test1(T argt)\r
+            {\r
+                return argt;\r
+            }\r
 \r
-            public T test1(T arg1)\r
+            public U test1(U argu)\r
             {\r
-                return arg1;\r
+                return argu;\r
             }\r
 \r
-            public W test2<W>(W arg2)\r
+            public T test12(T argt, U argu)\r
             {\r
-                return arg2;\r
+                return argt;\r
             }\r
 \r
-            static public T static_test1(T arg1)\r
+            public U test21(U argu, T argt)\r
             {\r
-                return arg1;\r
+                return argu;\r
+            }\r
+\r
+            public W test2<W>(W argw)\r
+            {\r
+                return argw;\r
+            }\r
+\r
+            public W test3<W>(T argt, U argu, W argw)\r
+            {\r
+                return argw;\r
             }\r
 \r
-            static public W static_test2<W>(W arg2)\r
+            public W test41<W,Y,Z>(W argw, Y argy, Z argz, T argt)\r
             {\r
-                return arg2;\r
+                return argw;\r
+            }\r
+\r
+            public Y test42<W,Y,Z>(W argw, Y argy, Z argz, T argt)\r
+            {\r
+                return argy;\r
+            }\r
+\r
+            public Z test43<W,Y,Z>(W argw, Y argy, Z argz, T argt)\r
+            {\r
+                return argz;\r
+            }\r
+\r
+            public T test44<W,Y,Z>(W argw, Y argy, Z argz, T argt)\r
+            {\r
+                return argt;\r
+            }\r
+\r
+            static public T static_test1(T argt)\r
+            {\r
+                return argt;\r
+            }\r
+\r
+            static public U static_test1(U argu)\r
+            {\r
+                return argu;\r
+            }\r
+\r
+            static public W static_test2<W>(W argw)\r
+            {\r
+                return argw;\r
+            }\r
+\r
+            static public W static_test3<W>(T argt, U argu, W argw)\r
+            {\r
+                return argw;\r
+            }\r
+\r
+            static public W static_test41<W,Y,Z>(W argw, Y argy, Z argz, T argt)\r
+            {\r
+                return argw;\r
+            }\r
+\r
+            static public Y static_test42<W,Y,Z>(W argw, Y argy, Z argz, T argt)\r
+            {\r
+                return argy;\r
+            }\r
+\r
+            static public Z static_test43<W,Y,Z>(W argw, Y argy, Z argz, T argt)\r
+            {\r
+                return argz;\r
+            }\r
+\r
+            static public T static_test44<W,Y,Z>(W argw, Y argy, Z argz, T argt)\r
+            {\r
+                return argt;\r
             }\r
 \r
             public T i1;\r
@@ -287,6 +411,7 @@ namespace MITestGeneric
 \r
             public void test_func()\r
             {\r
+                MY my = new MY();\r
                 Console.WriteLine("test_func()");                                                            Label.Breakpoint("BREAK2");\r
 \r
                 Label.Checkpoint("test_func", "test_set_value", (Object context) => {\r
@@ -303,11 +428,50 @@ namespace MITestGeneric
                     Context.GetAndCheckValue(@"__FILE__:__LINE__", "456", "int", "static_p_i1");\r
                     Context.GetAndCheckValue(@"__FILE__:__LINE__", "\\\"test_string4\\\"", "string", "static_p_s1");\r
 \r
-                    // FIXME\r
-                    //Context.GetAndCheckValue(@"__FILE__:__LINE__", "5", "int", "test1(5)");\r
-                    //Context.GetAndCheckValue(@"__FILE__:__LINE__", "10", "int", "test2<int>(10)");\r
-                    //Context.GetAndCheckValue(@"__FILE__:__LINE__", "15", "int", "static_test1(15)");\r
-                    //Context.GetAndCheckValue(@"__FILE__:__LINE__", "20", "int", "static_test2<int>(20)");\r
+                    // Instance methods\r
+                    Context.GetAndCheckValue(@"__FILE__:__LINE__", "5", "int", "test1(5)");\r
+                    Context.GetAndCheckValue(@"__FILE__:__LINE__", "\\\"five\\\"", "string", "test1(\\\"five\\\")");\r
+                    Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "test1(false)", "Error");\r
+                    Context.GetAndCheckValue(@"__FILE__:__LINE__", "5", "int", "test12(5,\\\"five\\\")");\r
+                    Context.GetAndCheckValue(@"__FILE__:__LINE__", "\\\"five\\\"", "string", "test21(\\\"five\\\",5)");\r
+                    Context.GetAndCheckValue(@"__FILE__:__LINE__", "10", "int", "test2<int>(10)");\r
+                    Context.GetAndCheckValue(@"__FILE__:__LINE__", "false", "bool", "test2<bool>(false)");\r
+                    Context.GetAndCheckValue(@"__FILE__:__LINE__", "97 'a'", "char", "test2<char>('a')");\r
+                    Context.GetAndCheckValue(@"__FILE__:__LINE__", "\\\"abc\\\"", "string", "test2<string>(\\\"abc\\\")");\r
+                    Context.GetAndCheckValue(@"__FILE__:__LINE__", "{MITestGeneric.Program.MY}", "MITestGeneric.Program.MY", "test2<MY>(my)");\r
+                    Context.GetAndCheckValue(@"__FILE__:__LINE__", "97 'a'", "char", "test3<char>(101,\\\"string\\\",'a')");\r
+                    Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "test3<bool>(101,\\\"string\\\",'a')", "Error");\r
+                    Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "test3<char>(101,'a','a')", "Error");\r
+                    Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "test3<char>('a',\\\"string\\\",'a')", "Error");\r
+                    Context.GetAndCheckValue(@"__FILE__:__LINE__", "97 'a'", "char", "test41<char,bool,string>('a',true,\\\"string\\\", 41)");\r
+                    Context.GetAndCheckValue(@"__FILE__:__LINE__", "true", "bool", "test42<char,bool,string>('a',true,\\\"string\\\", 41)");\r
+                    Context.GetAndCheckValue(@"__FILE__:__LINE__", "\\\"string\\\"", "string", "test43<char,bool,string>('a',true,\\\"string\\\", 41)");\r
+                    Context.GetAndCheckValue(@"__FILE__:__LINE__", "41", "int", "test44<char,bool,string>('a',true,\\\"string\\\", 41)");\r
+                    Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "test44<bool,string,char>('a',true,\\\"string\\\", 41)", "Error");\r
+                    Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "test44<string,char,bool>('a',true,\\\"string\\\", 41)", "Error");\r
+                    Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "test44<bool,char,string>('a',true,\\\"string\\\", 41)", "Error");\r
+\r
+                    // Static methods\r
+\r
+                    Context.GetAndCheckValue(@"__FILE__:__LINE__", "15", "int", "static_test1(15)");\r
+                    Context.GetAndCheckValue(@"__FILE__:__LINE__", "\\\"fifteen\\\"", "string", "static_test1(\\\"fifteen\\\")");\r
+                    Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "static_test1(false)", "Error");\r
+                    Context.GetAndCheckValue(@"__FILE__:__LINE__", "20", "int", "static_test2<int>(20)");\r
+                    Context.GetAndCheckValue(@"__FILE__:__LINE__", "true", "bool", "static_test2<bool>(true)");\r
+                    Context.GetAndCheckValue(@"__FILE__:__LINE__", "120 'x'", "char", "static_test2<char>('x')");\r
+                    Context.GetAndCheckValue(@"__FILE__:__LINE__", "\\\"xyz\\\"", "string", "static_test2<string>(\\\"xyz\\\")");\r
+                    Context.GetAndCheckValue(@"__FILE__:__LINE__", "{MITestGeneric.Program.MY}", "MITestGeneric.Program.MY", "static_test2<MY>(my)");\r
+                    Context.GetAndCheckValue(@"__FILE__:__LINE__", "97 'a'", "char", "static_test3<char>(101,\\\"string\\\",'a')");\r
+                    Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "static_test3<bool>(101,\\\"string\\\",'a')", "Error");\r
+                    Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "static_test3<char>(101,'a','a')", "Error");\r
+                    Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "static_test3<char>('a',\\\"string\\\",'a')", "Error");\r
+                    Context.GetAndCheckValue(@"__FILE__:__LINE__", "97 'a'", "char", "static_test41<char,bool,string>('a',true,\\\"string\\\", 41)");\r
+                    Context.GetAndCheckValue(@"__FILE__:__LINE__", "true", "bool", "static_test42<char,bool,string>('a',true,\\\"string\\\", 41)");\r
+                    Context.GetAndCheckValue(@"__FILE__:__LINE__", "\\\"string\\\"", "string", "static_test43<char,bool,string>('a',true,\\\"string\\\", 41)");\r
+                    Context.GetAndCheckValue(@"__FILE__:__LINE__", "41", "int", "static_test44<char,bool,string>('a',true,\\\"string\\\", 41)");\r
+                    Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "static_test44<bool,string,char>('a',true,\\\"string\\\", 41)", "Error");\r
+                    Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "static_test44<string,char,bool>('a',true,\\\"string\\\", 41)", "Error");\r
+                    Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "static_test44<bool,char,string>('a',true,\\\"string\\\", 41)", "Error");\r
 \r
                     // Test set value.\r
 \r
@@ -353,6 +517,9 @@ namespace MITestGeneric
             TestGeneric<int,string>.static_s1 = "test_string3";\r
             TestGeneric<int,string>.static_p_i1 = 456;\r
             TestGeneric<int,string>.static_p_s1 = "test_string4";\r
+            MY my = new MY();\r
+            TestNested<char,int> testnested = new TestNested<char,int>();\r
+            TestNested<char,int> uninitialized;\r
 \r
             ttt.test_func();                                                                                 Label.Breakpoint("BREAK1");\r
 \r
@@ -370,17 +537,72 @@ namespace MITestGeneric
                 Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "ttt.static_p_i1", "error");\r
                 Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "ttt.static_p_s1", "error");\r
 \r
-                // FIXME debugger must be fixed first\r
-                //Context.GetAndCheckValue(@"__FILE__:__LINE__", "345", "int", "TestGeneric<int, string>.static_i1");\r
-                //Context.GetAndCheckValue(@"__FILE__:__LINE__", "\\\"test_string3\\\"", "string", "TestGeneric<int, string>.static_s1");\r
-                //Context.GetAndCheckValue(@"__FILE__:__LINE__", "456", "int", "TestGeneric<int, string>.static_p_i1");\r
-                //Context.GetAndCheckValue(@"__FILE__:__LINE__", "\\\"test_string4\\\"", "string", "TestGeneric<int, string>.static_p_s1");\r
-\r
-                // FIXME debugger must be fixed first\r
-                //Context.GetAndCheckValue(@"__FILE__:__LINE__", "5", "int", "ttt.test1(5)");\r
-                //Context.GetAndCheckValue(@"__FILE__:__LINE__", "10", "int", "ttt.test2<int>(10)");\r
-                //Context.GetAndCheckValue(@"__FILE__:__LINE__", "15", "int", "TestGeneric<int,string>.static_test1(15)");\r
-                //Context.GetAndCheckValue(@"__FILE__:__LINE__", "20", "int", "TestGeneric<int,string>.static_test2<int>(20)");\r
+                // Static class members\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "345", "int", "TestGeneric<int, string>.static_i1");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "\\\"test_string3\\\"", "string", "TestGeneric<int, string>.static_s1");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "456", "int", "TestGeneric<int, string>.static_p_i1");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "\\\"test_string4\\\"", "string", "TestGeneric<int, string>.static_p_s1");\r
+\r
+                // Instance methods\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "5", "int", "ttt.test1(5)");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "\\\"five\\\"", "string", "ttt.test1(\\\"five\\\")");\r
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "ttt.test1(false)", "Error");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "5", "int", "ttt.test12(5,\\\"five\\\")");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "\\\"five\\\"", "string", "ttt.test21(\\\"five\\\",5)");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "10", "int", "ttt.test2<int>(10)");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "false", "bool", "ttt.test2<bool>(false)");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "97 'a'", "char", "ttt.test2<char>('a')");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "\\\"abc\\\"", "string", "ttt.test2<string>(\\\"abc\\\")");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "{MITestGeneric.Program.MY}", "MITestGeneric.Program.MY", "ttt.test2<MY>(my)");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "97 'a'", "char", "ttt.test3<char>(101,\\\"string\\\",'a')");\r
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "ttt.test3<bool>(101,\\\"string\\\",'a')", "Error");\r
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "ttt.test3<char>(101,'a','a')", "Error");\r
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "ttt.test3<char>('a',\\\"string\\\",'a')", "Error");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "97 'a'", "char", "ttt.test41<char,bool,string>('a',true,\\\"string\\\", 41)");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "true", "bool", "ttt.test42<char,bool,string>('a',true,\\\"string\\\", 41)");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "\\\"string\\\"", "string", "ttt.test43<char,bool,string>('a',true,\\\"string\\\", 41)");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "41", "int", "ttt.test44<char,bool,string>('a',true,\\\"string\\\", 41)");\r
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "ttt.test44<bool,string,char>('a',true,\\\"string\\\", 41)", "Error");\r
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "ttt.test44<string,char,bool>('a',true,\\\"string\\\", 41)", "Error");\r
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "ttt.test44<bool,char,string>('a',true,\\\"string\\\", 41)", "Error");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "97 'a'", "char", "testnested.nested.test1('a')");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "123", "int", "testnested.nested.test1(123)");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "789", "int", "testnested.nested.test3<int>('c',456,789)");\r
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "testnested.nested.test3<int>(false,456,789)", "Error");\r
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "testnested.nested.test3<int>('c',456,\\\"abc\\\")", "Error");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "\\\"cde\\\"", "string", "testnested.nested.test3<string>('c',456,\\\"cde\\\")");\r
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "testnested.nested.test3<string>(false,456,\\\"cde\\\")", "Error");\r
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "testnested.nested.test3<string>('c',456,789)", "Error");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "null", "MITestGeneric.Program.TestNested<char, int>", "uninitialized?.uninitialized?.test3<string>('c',456,\\\"cde\\\")");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "null", "MITestGeneric.Program.TestNested<char, int>.Nested<char, int>", "testnested.uninitialized?.test3<string>('c',456,\\\"cde\\\")");\r
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "uninitialized.uninitialized?.test3<string>('c',456,\\\"cde\\\")", "error:");\r
+\r
+                // Static methods\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "15", "int", "TestGeneric<int,string>.static_test1(15)");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "\\\"fifteen\\\"", "string", "TestGeneric<int,string>.static_test1(\\\"fifteen\\\")");\r
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "TestGeneric<int,string>.static_test1(false)", "Error");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "20", "int", "TestGeneric<int,string>.static_test2<int>(20)");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "true", "bool", "TestGeneric<int,string>.static_test2<bool>(true)");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "120 'x'", "char", "TestGeneric<int,string>.static_test2<char>('x')");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "\\\"xyz\\\"", "string", "TestGeneric<int,string>.static_test2<string>(\\\"xyz\\\")");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "{MITestGeneric.Program.MY}", "MITestGeneric.Program.MY", "TestGeneric<int,string>.static_test2<MY>(my)");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "97 'a'", "char", "TestGeneric<int,string>.static_test3<char>(101,\\\"string\\\",'a')");\r
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "TestGeneric<int,string>.static_test3<bool>(101,\\\"string\\\",'a')", "Error");\r
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "TestGeneric<int,string>.static_test3<char>(101,'a','a')", "Error");\r
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "TestGeneric<int,string>.static_test3<char>('a',\\\"string\\\",'a')", "Error");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "97 'a'", "char", "TestGeneric<int,string>.static_test41<char,bool,string>('a',true,\\\"string\\\", 41)");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "true", "bool", "TestGeneric<int,string>.static_test42<char,bool,string>('a',true,\\\"string\\\", 41)");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "\\\"string\\\"", "string", "TestGeneric<int,string>.static_test43<char,bool,string>('a',true,\\\"string\\\", 41)");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "41", "int", "TestGeneric<int,string>.static_test44<char,bool,string>('a',true,\\\"string\\\", 41)");\r
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "TestGeneric<int,string>.static_test44<bool,string,char>('a',true,\\\"string\\\", 41)", "Error");\r
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "TestGeneric<int,string>.static_test44<string,char,bool>('a',true,\\\"string\\\", 41)", "Error");\r
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "TestGeneric<int,string>.static_test44<bool,char,string>('a',true,\\\"string\\\", 41)", "Error");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "97 'a'", "char", "TestNested<int,string>.Nested<char,bool>.static_test1('a')");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "true", "bool", "TestNested<int,string>.Nested<char,bool>.static_test1(true)");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "\\\"abc\\\"", "string", "TestNested<int,string>.Nested<char,bool>.static_test3<string>('a', true, \\\"abc\\\")");\r
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "TestNested<int,string>.Nested<char,bool>.static_test1(\\\"xyz\\\")", "Error");\r
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "TestNested<int,string>.Nested<char,bool>.static_test3<string>('a', true, 123)", "Error");\r
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "TestNested<int,string>.Nested<char,bool>.static_test3<string>(123, true, \\\"abc\\\")", "Error");\r
 \r
                 Context.Continue(@"__FILE__:__LINE__");\r
             });\r
@@ -400,14 +622,14 @@ namespace MITestGeneric
                 Context.CreateAndCompareVar(@"__FILE__:__LINE__", "ttt.p_s1", "\\\"changed_string2\\\"");\r
 \r
                 // FIXME debugger must be fixed first\r
-                //Context.CreateAndAssignVar(@"__FILE__:__LINE__", "TestGeneric<int,string>.static_i1", "777");\r
-                //Context.CreateAndAssignVar(@"__FILE__:__LINE__", "TestGeneric<int,string>.static_s1", "\"changed_string3\"", true);\r
-                //Context.CreateAndCompareVar(@"__FILE__:__LINE__", "TestGeneric<int,string>.static_s1", "\\\"changed_string3\\\"");\r
+                Context.CreateAndAssignVar(@"__FILE__:__LINE__", "TestGeneric<int,string>.static_i1", "777");\r
+                Context.CreateAndAssignVar(@"__FILE__:__LINE__", "TestGeneric<int,string>.static_s1", "\"changed_string3\"", true);\r
+                Context.CreateAndCompareVar(@"__FILE__:__LINE__", "TestGeneric<int,string>.static_s1", "\\\"changed_string3\\\"");\r
 \r
                 // FIXME debugger must be fixed first\r
-                //Context.CreateAndAssignVar(@"__FILE__:__LINE__", "TestGeneric<int,string>.static_p_i1", "888");\r
-                //Context.CreateAndAssignVar(@"__FILE__:__LINE__", "TestGeneric<int,string>.static_p_s1", "\"changed_string4\"", true);\r
-                //Context.CreateAndCompareVar(@"__FILE__:__LINE__", "TestGeneric<int,string>.static_p_s1", "\\\"changed_string4\\\"");\r
+                Context.CreateAndAssignVar(@"__FILE__:__LINE__", "TestGeneric<int,string>.static_p_i1", "888");\r
+                Context.CreateAndAssignVar(@"__FILE__:__LINE__", "TestGeneric<int,string>.static_p_s1", "\"changed_string4\"", true);\r
+                Context.CreateAndCompareVar(@"__FILE__:__LINE__", "TestGeneric<int,string>.static_p_s1", "\\\"changed_string4\\\"");\r
 \r
                 Context.Continue(@"__FILE__:__LINE__");\r
             });\r
index 6eb8377f9e2fc2c4996635c7ec2663a592348d6f..f98ad0a7a5e79581f4777748f2c971b7613c7ffb 100644 (file)
@@ -657,6 +657,8 @@ namespace VSCodeTestEvaluate
     public class MethodCallTest2
     {
         public static MethodCallTest1 member1 = new MethodCallTest1();
+        public MethodCallTest1 nullMember;
+
     }
 
     public class MethodCallTest3
@@ -1389,6 +1391,9 @@ namespace VSCodeTestEvaluate
             }
 
             MethodCallTest1 MethodCallTest = new MethodCallTest1();
+            MethodCallTest1 methodCallTest1Null;
+            MethodCallTest2 methodCallTest2 = new MethodCallTest2();
+            MethodCallTest2 methodCallTest2Null;
             test_child TestCallChild = new test_child();
             test_parent TestCallParentOverride = new test_child();
             test_parent TestCallParent = new test_parent();
@@ -1422,6 +1427,12 @@ namespace VSCodeTestEvaluate
                 Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "MethodCallTest?.Calc1()", "error:");
                 Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "6", "int", "MethodCallTest?.Calc2()");
                 Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "\"VSCodeTestEvaluate.MethodCallTest1\"", "string", "MethodCallTest?.ToString()");
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "null", "VSCodeTestEvaluate.MethodCallTest1", "methodCallTest1Null?.Calc2()");
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "{System.NullReferenceException}", "System.NullReferenceException", "methodCallTest1Null.Calc2()");
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "null", "VSCodeTestEvaluate.MethodCallTest2", "methodCallTest2Null?.member.Calc2()");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "methodCallTest2Null.member.Calc2()", "error:");
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "{System.NullReferenceException}", "System.NullReferenceException", "methodCallTest2.nullMember.Calc2()");
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "null", "VSCodeTestEvaluate.MethodCallTest1", "methodCallTest2.nullMember?.Calc2()");
 
                 // Call non static method in static member.
                 Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "6", "int", "VSCodeTestEvaluate.MethodCallTest2.member1.Calc2()");
index 169bbebe07bd3a4e1de8607eb6136717173e96cc..c66cf0bb82ce92d7790d65c3d8de0dd7d6ce8c26 100644 (file)
@@ -352,27 +352,151 @@ namespace VSCodeTestGeneric
 {\r
     class Program\r
     {\r
+        public class MY\r
+        {\r
+            public int m;\r
+            public static int retme(int arg1)\r
+            {\r
+                return arg1;\r
+            }\r
+        }\r
+\r
+        public class TestNested<X,Y>\r
+        {\r
+            public class Nested<A,B>\r
+            {\r
+                public static MY my;\r
+\r
+                public A test1(A arga)\r
+                {\r
+                    return arga;\r
+                }\r
+\r
+                public B test1(B argb)\r
+                {\r
+                    return argb;\r
+                }\r
+\r
+                public C test3<C>(A arga, B argb, C argc)\r
+                {\r
+                    return argc;\r
+                }\r
+\r
+                public static A static_test1(A arga)\r
+                {\r
+                    return arga;\r
+                }\r
+\r
+                public static B static_test1(B argb)\r
+                {\r
+                    return argb;\r
+                }\r
+\r
+                public static C static_test3<C>(A arga, B argb, C argc)\r
+                {\r
+                    return argc;\r
+                }\r
+            }\r
+\r
+            public static Nested<X,Y> static_nested;\r
+            public Nested<X,Y> nested;\r
+            public Nested<X,Y> uninitialized;\r
+            public TestNested()\r
+            {\r
+                nested = new Nested<X,Y>();\r
+            }\r
+        }\r
+\r
         public class TestGeneric<T,U>\r
         {\r
+            public T test1(T argt)\r
+            {\r
+                return argt;\r
+            }\r
 \r
-            public T test1(T arg1)\r
+            public U test1(U argu)\r
             {\r
-                return arg1;\r
+                return argu;\r
             }\r
 \r
-            public W test2<W>(W arg2)\r
+            public T test12(T argt, U argu)\r
             {\r
-                return arg2;\r
+                return argt;\r
             }\r
 \r
-            static public T static_test1(T arg1)\r
+            public U test21(U argu, T argt)\r
             {\r
-                return arg1;\r
+                return argu;\r
+            }\r
+\r
+            public W test2<W>(W argw)\r
+            {\r
+                return argw;\r
+            }\r
+\r
+            public W test3<W>(T argt, U argu, W argw)\r
+            {\r
+                return argw;\r
             }\r
 \r
-            static public W static_test2<W>(W arg2)\r
+            public W test41<W,Y,Z>(W argw, Y argy, Z argz, T argt)\r
             {\r
-                return arg2;\r
+                return argw;\r
+            }\r
+\r
+            public Y test42<W,Y,Z>(W argw, Y argy, Z argz, T argt)\r
+            {\r
+                return argy;\r
+            }\r
+\r
+            public Z test43<W,Y,Z>(W argw, Y argy, Z argz, T argt)\r
+            {\r
+                return argz;\r
+            }\r
+\r
+            public T test44<W,Y,Z>(W argw, Y argy, Z argz, T argt)\r
+            {\r
+                return argt;\r
+            }\r
+\r
+            static public T static_test1(T argt)\r
+            {\r
+                return argt;\r
+            }\r
+\r
+            static public U static_test1(U argu)\r
+            {\r
+                return argu;\r
+            }\r
+\r
+            static public W static_test2<W>(W argw)\r
+            {\r
+                return argw;\r
+            }\r
+\r
+            static public W static_test3<W>(T argt, U argu, W argw)\r
+            {\r
+                return argw;\r
+            }\r
+\r
+            static public W static_test41<W,Y,Z>(W argw, Y argy, Z argz, T argt)\r
+            {\r
+                return argw;\r
+            }\r
+\r
+            static public Y static_test42<W,Y,Z>(W argw, Y argy, Z argz, T argt)\r
+            {\r
+                return argy;\r
+            }\r
+\r
+            static public Z static_test43<W,Y,Z>(W argw, Y argy, Z argz, T argt)\r
+            {\r
+                return argz;\r
+            }\r
+\r
+            static public T static_test44<W,Y,Z>(W argw, Y argy, Z argz, T argt)\r
+            {\r
+                return argt;\r
             }\r
 \r
             public T i1;\r
@@ -395,6 +519,7 @@ namespace VSCodeTestGeneric
 \r
             public void test_func()\r
             {\r
+                MY my = new MY();\r
                 Console.WriteLine("test_func()");                                                            Label.Breakpoint("BREAK2");\r
 \r
                 Label.Checkpoint("test_func", "test_set_value", (Object context) => {\r
@@ -412,11 +537,50 @@ namespace VSCodeTestGeneric
                     Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "456", "int", "static_p_i1");\r
                     Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "\"test_string4\"", "string", "static_p_s1");\r
 \r
-                    // FIXME\r
-                    //Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "5", "int", "test1(5)");\r
-                    //Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "10", "int", "test2<int>(10)");\r
-                    //Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "15", "int", "static_test1(15)");\r
-                    //Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "20", "int", "static_test2<int>(20)");\r
+                    // Instance methods\r
+                    Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "5", "int", "test1(5)");\r
+                    Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "\"five\"", "string", "test1(\"five\")");\r
+                    Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "test1(false)", "error");\r
+                    Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "5", "int", "test12(5,\"five\")");\r
+                    Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "\"five\"", "string", "test21(\"five\",5)");\r
+                    Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "10", "int", "test2<int>(10)");\r
+                    Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "false", "bool", "test2<bool>(false)");\r
+                    Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "97 'a'", "char", "test2<char>('a')");\r
+                    Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "\"abc\"", "string", "test2<string>(\"abc\")");\r
+                    Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "{VSCodeTestGeneric.Program.MY}", "VSCodeTestGeneric.Program.MY", "test2<MY>(my)");\r
+                    Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "97 'a'", "char", "test3<char>(101,\"string\",'a')");\r
+                    Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "test3<bool>(101,\"string\",'a')", "error");\r
+                    Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "test3<char>(101,'a','a')", "error");\r
+                    Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "test3<char>('a',\"string\",'a')", "error");\r
+                    Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "97 'a'", "char", "test41<char,bool,string>('a',true,\"string\", 41)");\r
+                    Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "true", "bool", "test42<char,bool,string>('a',true,\"string\", 41)");\r
+                    Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "\"string\"", "string", "test43<char,bool,string>('a',true,\"string\", 41)");\r
+                    Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "41", "int", "test44<char,bool,string>('a',true,\"string\", 41)");\r
+                    Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "test44<bool,string,char>('a',true,\"string\", 41)", "error");\r
+                    Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "test44<string,char,bool>('a',true,\"string\", 41)", "error");\r
+                    Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "test44<bool,char,string>('a',true,\"string\", 41)", "error");\r
+\r
+                    // Static methods\r
+\r
+                    Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "15", "int", "static_test1(15)");\r
+                    Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "\"fifteen\"", "string", "static_test1(\"fifteen\")");\r
+                    Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "static_test1(false)", "error");\r
+                    Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "20", "int", "static_test2<int>(20)");\r
+                    Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "true", "bool", "static_test2<bool>(true)");\r
+                    Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "120 'x'", "char", "static_test2<char>('x')");\r
+                    Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "\"xyz\"", "string", "static_test2<string>(\"xyz\")");\r
+                    Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "{VSCodeTestGeneric.Program.MY}", "VSCodeTestGeneric.Program.MY", "static_test2<MY>(my)");\r
+                    Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "97 'a'", "char", "static_test3<char>(101,\"string\",'a')");\r
+                    Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "static_test3<bool>(101,\"string\",'a')", "error");\r
+                    Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "static_test3<char>(101,'a','a')", "error");\r
+                    Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "static_test3<char>('a',\"string\",'a')", "error");\r
+                    Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "97 'a'", "char", "static_test41<char,bool,string>('a',true,\"string\", 41)");\r
+                    Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "true", "bool", "static_test42<char,bool,string>('a',true,\"string\", 41)");\r
+                    Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "\"string\"", "string", "static_test43<char,bool,string>('a',true,\"string\", 41)");\r
+                    Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "41", "int", "static_test44<char,bool,string>('a',true,\"string\", 41)");\r
+                    Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "static_test44<bool,string,char>('a',true,\"string\", 41)", "error");\r
+                    Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "static_test44<string,char,bool>('a',true,\"string\", 41)", "error");\r
+                    Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "static_test44<bool,char,string>('a',true,\"string\", 41)", "error");\r
 \r
                     // Test set value.\r
 \r
@@ -470,6 +634,9 @@ namespace VSCodeTestGeneric
             TestGeneric<int,string>.static_s1 = "test_string3";\r
             TestGeneric<int,string>.static_p_i1 = 456;\r
             TestGeneric<int,string>.static_p_s1 = "test_string4";\r
+            MY my = new MY();\r
+            TestNested<char,int> testnested = new TestNested<char,int>();\r
+            TestNested<char,int> uninitialized;\r
 \r
             ttt.test_func();                                                                                 Label.Breakpoint("BREAK1");\r
 \r
@@ -488,17 +655,72 @@ namespace VSCodeTestGeneric
                 Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "ttt.static_p_i1", "error");\r
                 Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "ttt.static_p_s1", "error");\r
 \r
-                // FIXME debugger must be fixed first\r
-                //Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "345", "int", "TestGeneric<int, string>.static_i1");\r
-                //Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "\"test_string3\"", "string", "TestGeneric<int, string>.static_s1");\r
-                //Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "456", "int", "TestGeneric<int, string>.static_p_i1");\r
-                //Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "\"test_string4\"", "string", "TestGeneric<int, string>.static_p_s1");\r
-\r
-                // FIXME debugger must be fixed first\r
-                //Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "5", "int", "ttt.test1(5)");\r
-                //Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "10", "int", "ttt.test2<int>(10)");\r
-                //Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "15", "int", "TestGeneric<int,string>.static_test1(15)");\r
-                //Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "20", "int", "TestGeneric<int,string>.static_test2<int>(20)");\r
+                // Static members\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "345", "int", "TestGeneric<int, string>.static_i1");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "\"test_string3\"", "string", "TestGeneric<int, string>.static_s1");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "456", "int", "TestGeneric<int, string>.static_p_i1");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "\"test_string4\"", "string", "TestGeneric<int, string>.static_p_s1");\r
+\r
+                // Instance methods\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "5", "int", "ttt.test1(5)");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "\"five\"", "string", "ttt.test1(\"five\")");\r
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "ttt.test1(false)", "error");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "5", "int", "ttt.test12(5,\"five\")");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "\"five\"", "string", "ttt.test21(\"five\",5)");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "10", "int", "ttt.test2<int>(10)");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "false", "bool", "ttt.test2<bool>(false)");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "97 'a'", "char", "ttt.test2<char>('a')");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "\"abc\"", "string", "ttt.test2<string>(\"abc\")");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "{VSCodeTestGeneric.Program.MY}", "VSCodeTestGeneric.Program.MY", "ttt.test2<MY>(my)");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "97 'a'", "char", "ttt.test3<char>(101,\"string\",'a')");\r
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "ttt.test3<bool>(101,\"string\",'a')", "error");\r
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "ttt.test3<char>(101,'a','a')", "error");\r
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "ttt.test3<char>('a',\"string\",'a')", "error");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "97 'a'", "char", "ttt.test41<char,bool,string>('a',true,\"string\", 41)");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "true", "bool", "ttt.test42<char,bool,string>('a',true,\"string\", 41)");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "\"string\"", "string", "ttt.test43<char,bool,string>('a',true,\"string\", 41)");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "41", "int", "ttt.test44<char,bool,string>('a',true,\"string\", 41)");\r
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "ttt.test44<bool,string,char>('a',true,\"string\", 41)", "error");\r
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "ttt.test44<string,char,bool>('a',true,\"string\", 41)", "error");\r
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "ttt.test44<bool,char,string>('a',true,\"string\", 41)", "error");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "97 'a'", "char", "testnested.nested.test1('a')");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "123", "int", "testnested.nested.test1(123)");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "789", "int", "testnested.nested.test3<int>('c',456,789)");\r
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "testnested.nested.test3<int>(false,456,789)", "error");\r
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "testnested.nested.test3<int>('c',456,\"abc\")", "error");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "\"cde\"", "string", "testnested.nested.test3<string>('c',456,\"cde\")");\r
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "testnested.nested.test3<string>(false,456,\"cde\")", "error");\r
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "testnested.nested.test3<string>('c',456,789)", "error");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "null", "VSCodeTestGeneric.Program.TestNested<char, int>", "uninitialized?.uninitialized?.test3<string>('c',456,\"cde\")");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "null", "VSCodeTestGeneric.Program.TestNested<char, int>.Nested<char, int>", "testnested.uninitialized?.test3<string>('c',456,\"cde\")");\r
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "uninitialized.uninitialized?.test3<string>('c',456,\"cde\")", "error");\r
+\r
+                // Static methods\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "15", "int", "TestGeneric<int,string>.static_test1(15)");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "\"fifteen\"", "string", "TestGeneric<int,string>.static_test1(\"fifteen\")");\r
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "TestGeneric<int,string>.static_test1(false)", "error");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "20", "int", "TestGeneric<int,string>.static_test2<int>(20)");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "true", "bool", "TestGeneric<int,string>.static_test2<bool>(true)");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "120 'x'", "char", "TestGeneric<int,string>.static_test2<char>('x')");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "\"xyz\"", "string", "TestGeneric<int,string>.static_test2<string>(\"xyz\")");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "{VSCodeTestGeneric.Program.MY}", "VSCodeTestGeneric.Program.MY", "TestGeneric<int,string>.static_test2<MY>(my)");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "97 'a'", "char", "TestGeneric<int,string>.static_test3<char>(101,\"string\",'a')");\r
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "TestGeneric<int,string>.static_test3<bool>(101,\"string\",'a')", "error");\r
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "TestGeneric<int,string>.static_test3<char>(101,'a','a')", "error");\r
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "TestGeneric<int,string>.static_test3<char>('a',\"string\",'a')", "error");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "97 'a'", "char", "TestGeneric<int,string>.static_test41<char,bool,string>('a',true,\"string\", 41)");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "true", "bool", "TestGeneric<int,string>.static_test42<char,bool,string>('a',true,\"string\", 41)");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "\"string\"", "string", "TestGeneric<int,string>.static_test43<char,bool,string>('a',true,\"string\", 41)");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "41", "int", "TestGeneric<int,string>.static_test44<char,bool,string>('a',true,\"string\", 41)");\r
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "TestGeneric<int,string>.static_test44<bool,string,char>('a',true,\"string\", 41)", "error");\r
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "TestGeneric<int,string>.static_test44<string,char,bool>('a',true,\"string\", 41)", "error");\r
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "TestGeneric<int,string>.static_test44<bool,char,string>('a',true,\"string\", 41)", "error");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "97 'a'", "char", "TestNested<int,string>.Nested<char,bool>.static_test1('a')");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "true", "bool", "TestNested<int,string>.Nested<char,bool>.static_test1(true)");\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "\"abc\"", "string", "TestNested<int,string>.Nested<char,bool>.static_test3<string>('a', true, \"abc\")");\r
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "TestNested<int,string>.Nested<char,bool>.static_test1(\"xyz\")", "error");\r
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "TestNested<int,string>.Nested<char,bool>.static_test3<string>('a', true, 123)", "error");\r
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "TestNested<int,string>.Nested<char,bool>.static_test3<string>(123, true, \"abc\")", "error");\r
 \r
                 Context.Continue(@"__FILE__:__LINE__");\r
             });\r
@@ -529,12 +751,12 @@ namespace VSCodeTestGeneric
                 Context.SetVariable(@"__FILE__:__LINE__", frameId, setStaticReference, "static_p_s1", "\"changed_string44\"");\r
 \r
                 // FIXME debugger must be fixed first\r
-                //Context.SetExpression(@"__FILE__:__LINE__", frameId, "TestGeneric<int,string>.static_i1", "777");\r
-                //Context.SetExpression(@"__FILE__:__LINE__", frameId, "TestGeneric<int,string>.static_s1", "\"changed_string3\"");\r
+                Context.SetExpression(@"__FILE__:__LINE__", frameId, "TestGeneric<int,string>.static_i1", "777");\r
+                Context.SetExpression(@"__FILE__:__LINE__", frameId, "TestGeneric<int,string>.static_s1", "\"changed_string3\"");\r
 \r
                 // FIXME debugger must be fixed first\r
-                //Context.SetExpression(@"__FILE__:__LINE__", frameId, "TestGeneric<int,string>.static_p_i1", "888");\r
-                //Context.SetExpression(@"__FILE__:__LINE__", frameId, "TestGeneric<int,string>.static_p_s1", "\"changed_string4\"");\r
+                Context.SetExpression(@"__FILE__:__LINE__", frameId, "TestGeneric<int,string>.static_p_i1", "888");\r
+                Context.SetExpression(@"__FILE__:__LINE__", frameId, "TestGeneric<int,string>.static_p_s1", "\"changed_string4\"");\r
 \r
                 Context.Continue(@"__FILE__:__LINE__");\r
             });\r