// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

#nullable disable

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.ExpressionEvaluator;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.VisualStudio.Debugger.Clr;
using Microsoft.VisualStudio.Debugger.Evaluation;
using Roslyn.Test.Utilities;
using Xunit;
using BindingFlags = System.Reflection.BindingFlags;

namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator.UnitTests
{
    public class ResultsViewTests : CSharpResultProviderTestBase
    {
        // IEnumerable pattern not supported.
        [Fact]
        public void IEnumerablePattern()
        {
            var source =
@"using System.Collections;
class C
{
    private readonly IEnumerable e;
    internal C(IEnumerable e)
    {
        this.e = e;
    }
    public IEnumerator GetEnumerator()
    {
        return this.e.GetEnumerator();
    }
}";
            var assembly = GetAssembly(source);
            var assemblies = ReflectionUtilities.GetMscorlibAndSystemCore(assembly);
            using (ReflectionUtilities.LoadAssemblies(assemblies))
            {
                var runtime = new DkmClrRuntimeInstance(assemblies);
                var type = assembly.GetType("C");
                var value = CreateDkmClrValue(
                    value: type.Instantiate(new[] { 1, 2 }),
                    type: runtime.GetType((TypeImpl)type));
                var evalResult = FormatResult("o", value);
                Verify(evalResult,
                    EvalResult("o", "{C}", "C", "o", DkmEvaluationResultFlags.Expandable));
                var children = GetChildren(evalResult);
                Verify(children,
                    EvalResult("e", "{int[2]}", "System.Collections.IEnumerable {int[]}", "o.e", DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.CanFavorite));
            }
        }

        // IEnumerable<T> pattern not supported.
        [Fact]
        public void IEnumerableOfTPattern()
        {
            var source =
@"using System.Collections.Generic;
class C<T>
{
    private readonly IEnumerable<T> e;
    internal C(IEnumerable<T> e)
    {
        this.e = e;
    }
    public IEnumerator<T> GetEnumerator()
    {
        return this.e.GetEnumerator();
    }
}";
            var assembly = GetAssembly(source);
            var assemblies = ReflectionUtilities.GetMscorlibAndSystemCore(assembly);
            using (ReflectionUtilities.LoadAssemblies(assemblies))
            {
                var runtime = new DkmClrRuntimeInstance(assemblies);
                var type = assembly.GetType("C`1").MakeGenericType(typeof(int));
                var value = CreateDkmClrValue(
                    value: type.Instantiate(new[] { 1, 2 }),
                    type: runtime.GetType((TypeImpl)type));
                var evalResult = FormatResult("o", value);
                Verify(evalResult,
                    EvalResult("o", "{C<int>}", "C<int>", "o", DkmEvaluationResultFlags.Expandable));
                var children = GetChildren(evalResult);
                Verify(children,
                    EvalResult("e", "{int[2]}", "System.Collections.Generic.IEnumerable<int> {int[]}", "o.e", DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.CanFavorite));
            }
        }

        [Fact]
        public void IEnumerableImplicitImplementation()
        {
            var source =
@"using System.Collections;
class C : IEnumerable
{
    private readonly IEnumerable e;
    internal C(IEnumerable e)
    {
        this.e = e;
    }
    public IEnumerator GetEnumerator()
    {
        return this.e.GetEnumerator();
    }
}";
            var assembly = GetAssembly(source);
            var assemblies = ReflectionUtilities.GetMscorlibAndSystemCore(assembly);
            using (ReflectionUtilities.LoadAssemblies(assemblies))
            {
                var runtime = new DkmClrRuntimeInstance(assemblies);
                var type = assembly.GetType("C");
                var value = CreateDkmClrValue(
                    value: type.Instantiate(new[] { 1, 2 }),
                    type: runtime.GetType((TypeImpl)type));
                var evalResult = FormatResult("o", value);
                Verify(evalResult,
                    EvalResult("o", "{C}", "C", "o", DkmEvaluationResultFlags.Expandable));
                var children = GetChildren(evalResult);
                Verify(children,
                    EvalResult(
                        "e",
                        "{int[2]}",
                        "System.Collections.IEnumerable {int[]}",
                        "o.e",
                        DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.CanFavorite),
                    EvalResult(
                        "Results View",
                        "Expanding the Results View will enumerate the IEnumerable",
                        "",
                        "o, results",
                        DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.ExpansionHasSideEffects,
                        DkmEvaluationResultCategory.Method));
                children = GetChildren(children[1]);
                Verify(children,
                    EvalResult("[0]", "1", "object {int}", "new System.Linq.SystemCore_EnumerableDebugView(o).Items[0]"),
                    EvalResult("[1]", "2", "object {int}", "new System.Linq.SystemCore_EnumerableDebugView(o).Items[1]"));
            }
        }

        [Fact]
        public void IEnumerableOfTImplicitImplementation()
        {
            var source =
@"using System.Collections;
using System.Collections.Generic;
struct S<T> : IEnumerable<T>
{
    private readonly IEnumerable<T> e;
    internal S(IEnumerable<T> e)
    {
        this.e = e;
    }
    public IEnumerator<T> GetEnumerator()
    {
        return this.e.GetEnumerator();
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return this.e.GetEnumerator();
    }
}";
            var assembly = GetAssembly(source);
            var assemblies = ReflectionUtilities.GetMscorlibAndSystemCore(assembly);
            using (ReflectionUtilities.LoadAssemblies(assemblies))
            {
                var runtime = new DkmClrRuntimeInstance(assemblies);
                var type = assembly.GetType("S`1").MakeGenericType(typeof(int));
                var value = CreateDkmClrValue(
                    value: type.Instantiate(new[] { 1, 2 }),
                    type: runtime.GetType((TypeImpl)type));
                var evalResult = FormatResult("o", value);
                Verify(evalResult,
                    EvalResult("o", "{S<int>}", "S<int>", "o", DkmEvaluationResultFlags.Expandable));
                var children = GetChildren(evalResult);
                Verify(children,
                    EvalResult(
                        "e",
                        "{int[2]}",
                        "System.Collections.Generic.IEnumerable<int> {int[]}",
                        "o.e",
                        DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.CanFavorite),
                    EvalResult(
                        "Results View",
                        "Expanding the Results View will enumerate the IEnumerable",
                        "",
                        "o, results",
                        DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.ExpansionHasSideEffects,
                        DkmEvaluationResultCategory.Method));
                children = GetChildren(children[1]);
                Verify(children,
                    EvalResult("[0]", "1", "int", "new System.Linq.SystemCore_EnumerableDebugView<int>(o).Items[0]"),
                    EvalResult("[1]", "2", "int", "new System.Linq.SystemCore_EnumerableDebugView<int>(o).Items[1]"));
            }
        }

        [Fact]
        public void IEnumerableExplicitImplementation()
        {
            var source =
@"using System.Collections;
class C : IEnumerable
{
    private readonly IEnumerable e;
    internal C(IEnumerable e)
    {
        this.e = e;
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return this.e.GetEnumerator();
    }
}";
            var assembly = GetAssembly(source);
            var assemblies = ReflectionUtilities.GetMscorlibAndSystemCore(assembly);
            using (ReflectionUtilities.LoadAssemblies(assemblies))
            {
                var runtime = new DkmClrRuntimeInstance(assemblies);
                var type = assembly.GetType("C");
                var value = CreateDkmClrValue(
                    value: type.Instantiate(new[] { 1, 2 }),
                    type: runtime.GetType((TypeImpl)type));
                var evalResult = FormatResult("o", value);
                Verify(evalResult,
                    EvalResult("o", "{C}", "C", "o", DkmEvaluationResultFlags.Expandable));
                var children = GetChildren(evalResult);
                Verify(children,
                    EvalResult(
                        "e",
                        "{int[2]}",
                        "System.Collections.IEnumerable {int[]}",
                        "o.e",
                        DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.CanFavorite),
                    EvalResult(
                        "Results View",
                        "Expanding the Results View will enumerate the IEnumerable",
                        "",
                        "o, results",
                        DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.ExpansionHasSideEffects,
                        DkmEvaluationResultCategory.Method));
                children = GetChildren(children[1]);
                Verify(children,
                    EvalResult("[0]", "1", "object {int}", "new System.Linq.SystemCore_EnumerableDebugView(o).Items[0]"),
                    EvalResult("[1]", "2", "object {int}", "new System.Linq.SystemCore_EnumerableDebugView(o).Items[1]"));
            }
        }

        [Fact]
        public void IEnumerableOfTExplicitImplementation()
        {
            var source =
@"using System.Collections;
using System.Collections.Generic;
class C<T> : IEnumerable<T>
{
    private readonly IEnumerable<T> e;
    internal C(IEnumerable<T> e)
    {
        this.e = e;
    }
    IEnumerator<T> IEnumerable<T>.GetEnumerator()
    {
        return this.e.GetEnumerator();
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return this.e.GetEnumerator();
    }
}";
            var assembly = GetAssembly(source);
            var assemblies = ReflectionUtilities.GetMscorlibAndSystemCore(assembly);
            using (ReflectionUtilities.LoadAssemblies(assemblies))
            {
                var runtime = new DkmClrRuntimeInstance(assemblies);
                var type = assembly.GetType("C`1").MakeGenericType(typeof(int));
                var value = CreateDkmClrValue(
                    value: type.Instantiate(new[] { 1, 2 }),
                    type: runtime.GetType((TypeImpl)type));
                var evalResult = FormatResult("o", value);
                Verify(evalResult,
                    EvalResult("o", "{C<int>}", "C<int>", "o", DkmEvaluationResultFlags.Expandable));
                var children = GetChildren(evalResult);
                Verify(children,
                    EvalResult(
                        "e",
                        "{int[2]}",
                        "System.Collections.Generic.IEnumerable<int> {int[]}",
                        "o.e",
                        DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.CanFavorite),
                    EvalResult(
                        "Results View",
                        "Expanding the Results View will enumerate the IEnumerable",
                        "",
                        "o, results",
                        DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.ExpansionHasSideEffects,
                        DkmEvaluationResultCategory.Method));
                children = GetChildren(children[1]);
                Verify(children,
                    EvalResult("[0]", "1", "int", "new System.Linq.SystemCore_EnumerableDebugView<int>(o).Items[0]"),
                    EvalResult("[1]", "2", "int", "new System.Linq.SystemCore_EnumerableDebugView<int>(o).Items[1]"));
            }
        }

        // Results View not supported for
        // IEnumerator implementation.
        [Fact]
        public void IEnumerator()
        {
            var source =
@"using System;
using System.Collections;
using System.Collections.Generic;
class C : IEnumerator<int>
{
    private int[] c = new[] { 1, 2, 3 };
    private int i = 0;
    object IEnumerator.Current
    {
        get { return this.c[this.i]; }
    }
    int IEnumerator<int>.Current
    {
        get { return this.c[this.i]; }
    }
    bool IEnumerator.MoveNext()
    {
        this.i++;
        return this.i < this.c.Length;
    }
    void IEnumerator.Reset()
    {
        this.i = 0;
    }
    void IDisposable.Dispose()
    {
    }
}";
            var assembly = GetAssembly(source);
            var assemblies = ReflectionUtilities.GetMscorlibAndSystemCore(assembly);
            using (ReflectionUtilities.LoadAssemblies(assemblies))
            {
                var runtime = new DkmClrRuntimeInstance(assemblies);
                var type = assembly.GetType("C");
                var value = CreateDkmClrValue(
                    value: type.Instantiate(),
                    type: runtime.GetType((TypeImpl)type));
                var evalResult = FormatResult("o", value);
                Verify(evalResult,
                    EvalResult("o", "{C}", "C", "o", DkmEvaluationResultFlags.Expandable));
                var children = GetChildren(evalResult);
                Verify(children,
                    EvalResult(
                        "System.Collections.Generic.IEnumerator<int>.Current",
                        "1",
                        "int",
                        "((System.Collections.Generic.IEnumerator<int>)o).Current",
                        DkmEvaluationResultFlags.ReadOnly),
                    EvalResult(
                        "System.Collections.IEnumerator.Current",
                        "1",
                        "object {int}",
                        "((System.Collections.IEnumerator)o).Current",
                        DkmEvaluationResultFlags.ReadOnly),
                    EvalResult("c", "{int[3]}", "int[]", "o.c", DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.CanFavorite),
                    EvalResult("i", "0", "int", "o.i", DkmEvaluationResultFlags.CanFavorite));
            }
        }

        [Fact]
        public void Overrides()
        {
            var source =
@"using System;
using System.Collections;
using System.Collections.Generic;
class A : IEnumerable<object>
{
    public virtual IEnumerator<object> GetEnumerator()
    {
        yield return 0;
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        throw new NotImplementedException();
    }
}
class B1 : A
{
    public override IEnumerator<object> GetEnumerator()
    {
        yield return 1;
    }
}
class B2 : A, IEnumerable<int>
{
    public new IEnumerator<int> GetEnumerator()
    {
        yield return 2;
    }
}
class B3 : A
{
    public new IEnumerable<int> GetEnumerator()
    {
        yield return 3;
    }
}
class B4 : A
{
}
class C
{
    A _1 = new B1();
    A _2 = new B2();
    A _3 = new B3();
    A _4 = new B4();
}";
            var assembly = GetAssembly(source);
            var assemblies = ReflectionUtilities.GetMscorlibAndSystemCore(assembly);
            using (ReflectionUtilities.LoadAssemblies(assemblies))
            {
                var runtime = new DkmClrRuntimeInstance(assemblies);
                var type = assembly.GetType("C");
                var value = CreateDkmClrValue(
                    value: type.Instantiate(),
                    type: runtime.GetType((TypeImpl)type));
                var evalResult = FormatResult("o", value);
                Verify(evalResult,
                    EvalResult("o", "{C}", "C", "o", DkmEvaluationResultFlags.Expandable));
                var children = GetChildren(evalResult);
                Verify(children,
                    EvalResult("_1", "{B1}", "A {B1}", "o._1", DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.CanFavorite),
                    EvalResult("_2", "{B2}", "A {B2}", "o._2", DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.CanFavorite),
                    EvalResult("_3", "{B3}", "A {B3}", "o._3", DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.CanFavorite),
                    EvalResult("_4", "{B4}", "A {B4}", "o._4", DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.CanFavorite));
                // A _1 = new B1();
                var moreChildren = GetChildren(children[0]);
                Verify(moreChildren,
                    EvalResult(
                        "Results View",
                        "Expanding the Results View will enumerate the IEnumerable",
                        "",
                        "o._1, results",
                        DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.ExpansionHasSideEffects,
                        DkmEvaluationResultCategory.Method));
                moreChildren = GetChildren(moreChildren[0]);
                Verify(moreChildren,
                    EvalResult("[0]", "1", "object {int}", "new System.Linq.SystemCore_EnumerableDebugView<object>(o._1).Items[0]"));
                // A _2 = new B2();
                moreChildren = GetChildren(children[1]);
                Verify(moreChildren,
                    EvalResult(
                        "Results View",
                        "Expanding the Results View will enumerate the IEnumerable",
                        "",
                        "o._2, results",
                        DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.ExpansionHasSideEffects,
                        DkmEvaluationResultCategory.Method));
                moreChildren = GetChildren(moreChildren[0]);
                Verify(moreChildren,
                    EvalResult("[0]", "2", "int", "new System.Linq.SystemCore_EnumerableDebugView<int>(o._2).Items[0]"));
                // A _3 = new B3();
                moreChildren = GetChildren(children[2]);
                Verify(moreChildren,
                    EvalResult(
                        "Results View",
                        "Expanding the Results View will enumerate the IEnumerable",
                        "",
                        "o._3, results",
                        DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.ExpansionHasSideEffects,
                        DkmEvaluationResultCategory.Method));
                moreChildren = GetChildren(moreChildren[0]);
                Verify(moreChildren,
                    EvalResult("[0]", "0", "object {int}", "new System.Linq.SystemCore_EnumerableDebugView<object>(o._3).Items[0]"));
                // A _4 = new B4();
                moreChildren = GetChildren(children[3]);
                Verify(moreChildren,
                    EvalResult(
                        "Results View",
                        "Expanding the Results View will enumerate the IEnumerable",
                        "",
                        "o._4, results",
                        DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.ExpansionHasSideEffects,
                        DkmEvaluationResultCategory.Method));
                moreChildren = GetChildren(moreChildren[0]);
                Verify(moreChildren,
                    EvalResult("[0]", "0", "object {int}", "new System.Linq.SystemCore_EnumerableDebugView<object>(o._4).Items[0]"));
            }
        }

        /// <summary>
        /// Include Results View on base types
        /// (matches legacy EE behavior).
        /// </summary>
        [Fact]
        public void BaseTypes()
        {
            var source =
@"using System.Collections;
using System.Collections.Generic;
class A1
{
}
class B1 : A1, IEnumerable
{
    public IEnumerator GetEnumerator()
    {
        yield return 0;
    }
}
class A2
{
    public IEnumerator GetEnumerator()
    {
        yield return 1;
    }
}
class B2 : A2, IEnumerable<object>
{
    IEnumerator<object> IEnumerable<object>.GetEnumerator()
    {
        yield return 2;
    }
}
struct S : IEnumerable
{
    public IEnumerator GetEnumerator()
    {
        yield return 3;
    }
}
class C
{
    A1 _1 = new B1();
    B2 _2 = new B2();
    System.ValueType _3 = new S();
}";
            var assembly = GetAssembly(source);
            var assemblies = ReflectionUtilities.GetMscorlibAndSystemCore(assembly);
            using (ReflectionUtilities.LoadAssemblies(assemblies))
            {
                var runtime = new DkmClrRuntimeInstance(assemblies);
                var type = assembly.GetType("C");
                var value = CreateDkmClrValue(
                    value: type.Instantiate(),
                    type: runtime.GetType((TypeImpl)type));
                var evalResult = FormatResult("o", value);
                Verify(evalResult,
                    EvalResult("o", "{C}", "C", "o", DkmEvaluationResultFlags.Expandable));
                var children = GetChildren(evalResult);
                Verify(children,
                    EvalResult("_1", "{B1}", "A1 {B1}", "o._1", DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.CanFavorite),
                    EvalResult("_2", "{B2}", "B2", "o._2", DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.CanFavorite),
                    EvalResult("_3", "{S}", "System.ValueType {S}", "o._3", DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.CanFavorite));
                // A1 _1 = new B1();
                var moreChildren = GetChildren(children[0]);
                Verify(moreChildren,
                    EvalResult(
                        "Results View",
                        "Expanding the Results View will enumerate the IEnumerable",
                        "",
                        "o._1, results",
                        DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.ExpansionHasSideEffects,
                        DkmEvaluationResultCategory.Method));
                Verify(GetChildren(moreChildren[0]),
                    EvalResult("[0]", "0", "object {int}", "new System.Linq.SystemCore_EnumerableDebugView(o._1).Items[0]"));
                // B2 _2 = new B2();
                moreChildren = GetChildren(children[1]);
                Verify(moreChildren,
                    EvalResult(
                        "Results View",
                        "Expanding the Results View will enumerate the IEnumerable",
                        "",
                        "o._2, results",
                        DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.ExpansionHasSideEffects,
                        DkmEvaluationResultCategory.Method));
                Verify(GetChildren(moreChildren[0]),
                    EvalResult("[0]", "2", "object {int}", "new System.Linq.SystemCore_EnumerableDebugView<object>(o._2).Items[0]"));
                // System.ValueType _3 = new S();
                moreChildren = GetChildren(children[2]);
                Verify(moreChildren,
                    EvalResult(
                        "Results View",
                        "Expanding the Results View will enumerate the IEnumerable",
                        "",
                        "o._3, results",
                        DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.ExpansionHasSideEffects,
                        DkmEvaluationResultCategory.Method));
                Verify(GetChildren(moreChildren[0]),
                    EvalResult("[0]", "3", "object {int}", "new System.Linq.SystemCore_EnumerableDebugView(o._3).Items[0]"));
            }
        }

        [Fact]
        public void Nullable()
        {
            var source =
@"using System;
using System.Collections;
using System.Collections.Generic;
struct S : IEnumerable<object>
{
    internal readonly object[] c;
    internal S(object[] c)
    {
        this.c = c;
    }
    public IEnumerator<object> GetEnumerator()
    {
        foreach (var o in this.c)
        {
            yield return o;
        }
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        throw new NotImplementedException();
    }
}
class C
{
    S? F = new S(new object[] { null });
}";
            var assembly = GetAssembly(source);
            var assemblies = ReflectionUtilities.GetMscorlibAndSystemCore(assembly);
            using (ReflectionUtilities.LoadAssemblies(assemblies))
            {
                var runtime = new DkmClrRuntimeInstance(assemblies);
                var type = assembly.GetType("C");
                var value = CreateDkmClrValue(
                    value: type.Instantiate(),
                    type: runtime.GetType((TypeImpl)type));
                var evalResult = FormatResult("o", value);
                Verify(evalResult,
                    EvalResult("o", "{C}", "C", "o", DkmEvaluationResultFlags.Expandable));
                var children = GetChildren(evalResult);
                Verify(children,
                    EvalResult("F", "{S}", "S?", "o.F", DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.CanFavorite));
                children = GetChildren(children[0]);
                Verify(children,
                    EvalResult("c", "{object[1]}", "object[]", "o.F.c", DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.CanFavorite),
                    EvalResult(
                        "Results View",
                        "Expanding the Results View will enumerate the IEnumerable",
                        "",
                        "o.F, results",
                        DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.ExpansionHasSideEffects,
                        DkmEvaluationResultCategory.Method));
                children = GetChildren(children[1]);
                Verify(children,
                    EvalResult(
                        "[0]",
                        "null",
                        "object",
                        "new System.Linq.SystemCore_EnumerableDebugView<object>(o.F).Items[0]"));
            }
        }

        [Fact]
        public void ConstructedType()
        {
            var source =
@"using System;
using System.Collections;
using System.Collections.Generic;
class A<T> : IEnumerable<T>
{
    private readonly T[] items;
    internal A(T[] items)
    {
        this.items = items;
    }
    public IEnumerator<T> GetEnumerator()
    {
        foreach (var item in items)
        {
            yield return item;
        }
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        throw new NotImplementedException();
    }
}
class B
{
    internal object F;
}
class C : A<B>
{
    internal C() : base(new[] { new B() })
    {
    }
}";
            var assembly = GetAssembly(source);
            var assemblies = ReflectionUtilities.GetMscorlibAndSystemCore(assembly);
            using (ReflectionUtilities.LoadAssemblies(assemblies))
            {
                var runtime = new DkmClrRuntimeInstance(assemblies);
                var type = assembly.GetType("C");
                var value = CreateDkmClrValue(
                    value: type.Instantiate(),
                    type: runtime.GetType((TypeImpl)type));
                var evalResult = FormatResult("o", value);
                Verify(evalResult,
                    EvalResult("o", "{C}", "C", "o", DkmEvaluationResultFlags.Expandable));
                var children = GetChildren(evalResult);
                Verify(children,
                    EvalResult(
                        "items",
                        "{B[1]}",
                        "B[]",
                        "o.items",
                        DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.CanFavorite),
                    EvalResult(
                        "Results View",
                        "Expanding the Results View will enumerate the IEnumerable",
                        "",
                        "o, results",
                        DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.ExpansionHasSideEffects,
                        DkmEvaluationResultCategory.Method));
                var moreChildren = GetChildren(children[1]);
                Verify(moreChildren,
                    // The legacy EE treats the Items elements as readonly, but since
                    // Items is a T[], we treat the elements as read/write. However, Items
                    // is not updated when modifying elements so this is harmless.
                    EvalResult(
                        "[0]",
                        "{B}",
                        "B",
                        "new System.Linq.SystemCore_EnumerableDebugView<B>(o).Items[0]",
                        DkmEvaluationResultFlags.Expandable));
                moreChildren = GetChildren(moreChildren[0]);
                Verify(moreChildren,
                    EvalResult("F", "null", "object", "(new System.Linq.SystemCore_EnumerableDebugView<B>(o).Items[0]).F", DkmEvaluationResultFlags.CanFavorite));
            }
        }

        /// <summary>
        /// System.Array should not have Results View.
        /// </summary>
        [Fact]
        public void Array()
        {
            var source =
@"using System;
using System.Collections;
class C
{
    char[] _1 = new char[] { '1' };
    Array _2 = new char[] { '2' };
    IEnumerable _3 = new char[] { '3' };
}";
            var assembly = GetAssembly(source);
            var assemblies = ReflectionUtilities.GetMscorlibAndSystemCore(assembly);
            using (ReflectionUtilities.LoadAssemblies(assemblies))
            {
                var runtime = new DkmClrRuntimeInstance(assemblies);
                var type = assembly.GetType("C");
                var value = CreateDkmClrValue(
                    value: type.Instantiate(),
                    type: runtime.GetType((TypeImpl)type));
                var evalResult = FormatResult("o", value);
                Verify(evalResult,
                    EvalResult("o", "{C}", "C", "o", DkmEvaluationResultFlags.Expandable));
                var children = GetChildren(evalResult);
                Verify(children,
                    EvalResult("_1", "{char[1]}", "char[]", "o._1", DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.CanFavorite),
                    EvalResult("_2", "{char[1]}", "System.Array {char[]}", "o._2", DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.CanFavorite),
                    EvalResult("_3", "{char[1]}", "System.Collections.IEnumerable {char[]}", "o._3", DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.CanFavorite));
                Verify(GetChildren(children[0]),
                    EvalResult("[0]", "49 '1'", "char", "o._1[0]", editableValue: "'1'"));
                Verify(GetChildren(children[1]),
                    EvalResult("[0]", "50 '2'", "char", "((char[])o._2)[0]", editableValue: "'2'"));
                children = GetChildren(children[2]);
                Verify(children,
                    EvalResult("[0]", "51 '3'", "char", "((char[])o._3)[0]", editableValue: "'3'"));
            }
        }

        /// <summary>
        /// String should not have Results View.
        /// </summary>
        [Fact]
        public void String()
        {
            var source =
@"using System.Collections;
using System.Collections.Generic;
class C
{
    string _1 = ""1"";
    object _2 = ""2"";
    IEnumerable _3 = ""3"";
    IEnumerable<char> _4 = ""4"";
}";
            var assembly = GetAssembly(source);
            var assemblies = ReflectionUtilities.GetMscorlibAndSystemCore(assembly);
            using (ReflectionUtilities.LoadAssemblies(assemblies))
            {
                var runtime = new DkmClrRuntimeInstance(assemblies);
                var type = assembly.GetType("C");
                var value = CreateDkmClrValue(
                    value: type.Instantiate(),
                    type: runtime.GetType((TypeImpl)type));
                var evalResult = FormatResult("o", value);
                Verify(evalResult,
                    EvalResult("o", "{C}", "C", "o", DkmEvaluationResultFlags.Expandable));
                var children = GetChildren(evalResult);
                Verify(children,
                    EvalResult("_1", "\"1\"", "string", "o._1", DkmEvaluationResultFlags.RawString | DkmEvaluationResultFlags.CanFavorite, editableValue: "\"1\""),
                    EvalResult("_2", "\"2\"", "object {string}", "o._2", DkmEvaluationResultFlags.RawString | DkmEvaluationResultFlags.CanFavorite, editableValue: "\"2\""),
                    EvalResult("_3", "\"3\"", "System.Collections.IEnumerable {string}", "o._3", DkmEvaluationResultFlags.RawString | DkmEvaluationResultFlags.CanFavorite, editableValue: "\"3\""),
                    EvalResult("_4", "\"4\"", "System.Collections.Generic.IEnumerable<char> {string}", "o._4", DkmEvaluationResultFlags.RawString | DkmEvaluationResultFlags.CanFavorite, editableValue: "\"4\""));
            }
        }

        [Fact]
        public void AsyncStateMachine()
        {
            var source = @"
using System;
using System.Threading.Tasks;

class C
{
    static void Main() => Async(1).Wait();

    static async Task Async(int parameter)
    {
        int i = 42;
        await Task.FromResult(1);
        Console.WriteLine(i + parameter);
    }
}
";
            var assembly = GetAssembly(source);
            var assemblies = ReflectionUtilities.GetMscorlibAndSystemCore(typeof(Task).Assembly, assembly);
            using (ReflectionUtilities.LoadAssemblies(assemblies))
            {
                var runtime = new DkmClrRuntimeInstance(assemblies);
                var stateMachineType = assembly.GetType("C").GetNestedTypes(BindingFlags.NonPublic).Single();

                var value = CreateDkmClrValue(
                    value: stateMachineType.Instantiate(),
                    type: runtime.GetType((TypeImpl)stateMachineType));

                // Raw view

                var evalResult = FormatResult("sm", value, inspectionContext: CreateDkmInspectionContext(DkmEvaluationFlags.ShowValueRaw));

                Verify(evalResult,
                    EvalResult("sm", "{C.<Async>d__1}", "C.<Async>d__1", "sm, raw", DkmEvaluationResultFlags.Expandable));

                var children = GetChildren(evalResult);
                Verify(children,
                    EvalResult("<>1__state", "0", "int", null, DkmEvaluationResultFlags.CanFavorite),
                    EvalResult("<>t__builder", "{System.Runtime.CompilerServices.AsyncTaskMethodBuilder}", "System.Runtime.CompilerServices.AsyncTaskMethodBuilder", null, DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.CanFavorite),
                    EvalResult("<>u__1", "{System.Runtime.CompilerServices.TaskAwaiter<int>}", "System.Runtime.CompilerServices.TaskAwaiter<int>", null, DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.CanFavorite),
                    EvalResult("<i>5__2", "0", "int", null, DkmEvaluationResultFlags.CanFavorite),
                    EvalResult("parameter", "0", "int", "sm.parameter", DkmEvaluationResultFlags.CanFavorite));

                // Regular view

                evalResult = FormatResult("sm", value, inspectionContext: CreateDkmInspectionContext(DkmEvaluationFlags.None));

                Verify(evalResult,
                    EvalResult("sm", "{C.<Async>d__1}", "C.<Async>d__1", "sm", DkmEvaluationResultFlags.Expandable));

                children = GetChildren(evalResult);
                Verify(children,
                    EvalResult("parameter", "0", "int", "sm.parameter", DkmEvaluationResultFlags.CanFavorite));
            }
        }

        [Fact]
        public void IteratorStateMachine()
        {
            var source = @"
using System;
using System.Linq;
using System.Collections.Generic;
using System.Threading.Tasks;

class C
{
    static void Main() => Iter(1).ToArray();

    static IEnumerable<int> Iter(int parameter)
    {
        int i = 42;
        yield return 1;
        Console.WriteLine(i + parameter);
    }
}
";
            var assembly = GetAssembly(source);
            var assemblies = ReflectionUtilities.GetMscorlibAndSystemCore(typeof(Task).Assembly, assembly);
            using (ReflectionUtilities.LoadAssemblies(assemblies))
            {
                var runtime = new DkmClrRuntimeInstance(assemblies);
                var stateMachineType = assembly.GetType("C").GetNestedTypes(BindingFlags.NonPublic).Single();

                var value = CreateDkmClrValue(
                    value: stateMachineType.Instantiate(1),
                    type: runtime.GetType((TypeImpl)stateMachineType));

                // Raw view

                var evalResult = FormatResult("sm", value, inspectionContext: CreateDkmInspectionContext(DkmEvaluationFlags.ShowValueRaw));

                Verify(evalResult,
                    EvalResult("sm", "{C.<Iter>d__1}", "C.<Iter>d__1", "sm, raw", DkmEvaluationResultFlags.Expandable));

                var children = GetChildren(evalResult);
                Verify(children,
                    EvalResult("<>1__state", "1", "int", null, DkmEvaluationResultFlags.CanFavorite),
                    EvalResult("<>2__current", "0", "int", null, DkmEvaluationResultFlags.CanFavorite),
                    EvalResult("<>3__parameter", "0", "int", null, DkmEvaluationResultFlags.CanFavorite),
                    EvalResult("<>l__initialThreadId", UnspecifiedValue, "int", null, DkmEvaluationResultFlags.CanFavorite),
                    EvalResult("<i>5__2", "0", "int", null, DkmEvaluationResultFlags.CanFavorite),
                    EvalResult("System.Collections.Generic.IEnumerator<int>.Current", "0", "int", "((System.Collections.Generic.IEnumerator<int>)sm).Current", DkmEvaluationResultFlags.ReadOnly),
                    EvalResult("System.Collections.IEnumerator.Current", "0", "object {int}", "((System.Collections.IEnumerator)sm).Current", DkmEvaluationResultFlags.ReadOnly),
                    EvalResult("parameter", "0", "int", "sm.parameter", DkmEvaluationResultFlags.CanFavorite),
                    EvalResult("Results View", "Expanding the Results View will enumerate the IEnumerable", "", "sm, raw, results", DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.ExpansionHasSideEffects));

                // Regular view

                evalResult = FormatResult("sm", value, inspectionContext: CreateDkmInspectionContext(DkmEvaluationFlags.None));

                Verify(evalResult,
                    EvalResult("sm", "{C.<Iter>d__1}", "C.<Iter>d__1", "sm", DkmEvaluationResultFlags.Expandable));

                children = GetChildren(evalResult);
                Verify(children,
                    EvalResult("System.Collections.Generic.IEnumerator<int>.Current", "0", "int", "((System.Collections.Generic.IEnumerator<int>)sm).Current", DkmEvaluationResultFlags.ReadOnly),
                    EvalResult("System.Collections.IEnumerator.Current", "0", "object {int}", "((System.Collections.IEnumerator)sm).Current", DkmEvaluationResultFlags.ReadOnly),
                    EvalResult("parameter", "0", "int", "sm.parameter", DkmEvaluationResultFlags.CanFavorite),
                    EvalResult("Results View", "Expanding the Results View will enumerate the IEnumerable", "", "sm, results", DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.ExpansionHasSideEffects));
            }
        }

        [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1006160")]
        public void MultipleImplementations_DifferentImplementors()
        {
            var source =
@"using System;
using System.Collections;
using System.Collections.Generic;
class A<T> : IEnumerable<T>
{
    IEnumerator<T> IEnumerable<T>.GetEnumerator()
    {
        yield return default(T);
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        throw new NotImplementedException();
    }
}
class B1 : A<object>, IEnumerable<int>
{
    IEnumerator<int> IEnumerable<int>.GetEnumerator()
    {
        yield return 1;
    }
}
class B2 : A<int>, IEnumerable<object>
{
    IEnumerator<object> IEnumerable<object>.GetEnumerator()
    {
        yield return null;
    }
}
class B3 : A<object>, IEnumerable
{
    IEnumerator IEnumerable.GetEnumerator()
    {
        yield return 3;
    }
}";
            var assembly = GetAssembly(source);
            var assemblies = ReflectionUtilities.GetMscorlibAndSystemCore(assembly);
            using (ReflectionUtilities.LoadAssemblies(assemblies))
            {
                var runtime = new DkmClrRuntimeInstance(assemblies);
                // class B1 : A<object>, IEnumerable<int>
                var type = assembly.GetType("B1");
                var value = CreateDkmClrValue(
                    value: type.Instantiate(),
                    type: runtime.GetType((TypeImpl)type));
                var evalResult = FormatResult("o", value);
                Verify(evalResult,
                    EvalResult("o", "{B1}", "B1", "o", DkmEvaluationResultFlags.Expandable));
                var children = GetChildren(evalResult);
                Verify(children,
                    EvalResult(
                        "Results View",
                        "Expanding the Results View will enumerate the IEnumerable",
                        "",
                        "o, results",
                        DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.ExpansionHasSideEffects,
                        DkmEvaluationResultCategory.Method));
                children = GetChildren(children[0]);
                Verify(children,
                    EvalResult(
                        "[0]",
                        "1",
                        "int",
                        "new System.Linq.SystemCore_EnumerableDebugView<int>(o).Items[0]"));
                // class B2 : A<int>, IEnumerable<object>
                type = assembly.GetType("B2");
                value = CreateDkmClrValue(
                    value: type.Instantiate(),
                    type: runtime.GetType((TypeImpl)type));
                evalResult = FormatResult("o", value);
                Verify(evalResult,
                    EvalResult("o", "{B2}", "B2", "o", DkmEvaluationResultFlags.Expandable));
                children = GetChildren(evalResult);
                Verify(children,
                    EvalResult(
                        "Results View",
                        "Expanding the Results View will enumerate the IEnumerable",
                        "",
                        "o, results",
                        DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.ExpansionHasSideEffects,
                        DkmEvaluationResultCategory.Method));
                children = GetChildren(children[0]);
                Verify(children,
                    EvalResult(
                        "[0]",
                        "null",
                        "object",
                        "new System.Linq.SystemCore_EnumerableDebugView<object>(o).Items[0]"));
                // class B3 : A<object>, IEnumerable
                type = assembly.GetType("B3");
                value = CreateDkmClrValue(
                    value: type.Instantiate(),
                    type: runtime.GetType((TypeImpl)type));
                evalResult = FormatResult("o", value);
                Verify(evalResult,
                    EvalResult("o", "{B3}", "B3", "o", DkmEvaluationResultFlags.Expandable));
                children = GetChildren(evalResult);
                Verify(children,
                    EvalResult(
                        "Results View",
                        "Expanding the Results View will enumerate the IEnumerable",
                        "",
                        "o, results",
                        DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.ExpansionHasSideEffects,
                        DkmEvaluationResultCategory.Method));
                children = GetChildren(children[0]);
                Verify(children,
                    EvalResult(
                        "[0]",
                        "null",
                        "object",
                        "new System.Linq.SystemCore_EnumerableDebugView<object>(o).Items[0]"));
            }
        }

        [Fact]
        public void MultipleImplementations_SameImplementor()
        {
            var source =
@"using System;
using System.Collections;
using System.Collections.Generic;
class A : IEnumerable<int>, IEnumerable<string>
{
    IEnumerator<int> IEnumerable<int>.GetEnumerator()
    {
        yield return 1;
    }
    IEnumerator<string> IEnumerable<string>.GetEnumerator()
    {
        yield return null;
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        throw new NotImplementedException();
    }
}
class B : IEnumerable<string>, IEnumerable<int>
{
    IEnumerator<string> IEnumerable<string>.GetEnumerator()
    {
        yield return null;
    }
    IEnumerator<int> IEnumerable<int>.GetEnumerator()
    {
        yield return 1;
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        throw new NotImplementedException();
    }
}";
            var assembly = GetAssembly(source);
            var assemblies = ReflectionUtilities.GetMscorlibAndSystemCore(assembly);
            using (ReflectionUtilities.LoadAssemblies(assemblies))
            {
                var runtime = new DkmClrRuntimeInstance(assemblies);
                // class A : IEnumerable<int>, IEnumerable<string>
                var type = assembly.GetType("A");
                var value = CreateDkmClrValue(
                    value: type.Instantiate(),
                    type: runtime.GetType((TypeImpl)type));
                var evalResult = FormatResult("a", value);
                Verify(evalResult,
                    EvalResult("a", "{A}", "A", "a", DkmEvaluationResultFlags.Expandable));
                var children = GetChildren(evalResult);
                Verify(children,
                    EvalResult(
                        "Results View",
                        "Expanding the Results View will enumerate the IEnumerable",
                        "",
                        "a, results",
                        DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.ExpansionHasSideEffects,
                        DkmEvaluationResultCategory.Method));
                children = GetChildren(children[0]);
                Verify(children,
                    EvalResult(
                        "[0]",
                        "1",
                        "int",
                        "new System.Linq.SystemCore_EnumerableDebugView<int>(a).Items[0]"));
                // class B : IEnumerable<string>, IEnumerable<int>
                type = assembly.GetType("B");
                value = CreateDkmClrValue(
                    value: type.Instantiate(),
                    type: runtime.GetType((TypeImpl)type));
                evalResult = FormatResult("b", value);
                Verify(evalResult,
                    EvalResult("b", "{B}", "B", "b", DkmEvaluationResultFlags.Expandable));
                children = GetChildren(evalResult);
                Verify(children,
                    EvalResult(
                        "Results View",
                        "Expanding the Results View will enumerate the IEnumerable",
                        "",
                        "b, results",
                        DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.ExpansionHasSideEffects,
                        DkmEvaluationResultCategory.Method));
                children = GetChildren(children[0]);
                Verify(children,
                    EvalResult(
                        "[0]",
                        "null",
                        "string",
                        "new System.Linq.SystemCore_EnumerableDebugView<string>(b).Items[0]"));
            }
        }

        /// <summary>
        /// Types with [DebuggerTypeProxy] should not have Results View.
        /// </summary>
        [Fact]
        public void DebuggerTypeProxy()
        {
            var source =
@"using System.Collections;
using System.Diagnostics;
public class P : IEnumerable
{
    private readonly C c;
    public P(C c)
    {
        this.c = c;
    }
    public IEnumerator GetEnumerator()
    {
        return this.c.GetEnumerator();
    }
    public int Length
    {
        get { return this.c.o.Length; }
    }
}
[DebuggerTypeProxy(typeof(P))]
public class C : IEnumerable
{
    internal readonly object[] o;
    public C(object[] o)
    {
        this.o = o;
    }
    public IEnumerator GetEnumerator()
    {
        return this.o.GetEnumerator();
    }
}";
            var assembly = GetAssembly(source);
            var assemblies = ReflectionUtilities.GetMscorlibAndSystemCore(assembly);
            using (ReflectionUtilities.LoadAssemblies(assemblies))
            {
                var runtime = new DkmClrRuntimeInstance(assemblies);
                var type = assembly.GetType("C");
                var value = CreateDkmClrValue(
                    value: type.Instantiate(new object[] { new object[] { string.Empty } }),
                    type: runtime.GetType((TypeImpl)type));
                var evalResult = FormatResult("o", value);
                Verify(evalResult,
                    EvalResult("o", "{C}", "C", "o", DkmEvaluationResultFlags.Expandable));
                var children = GetChildren(evalResult);
                Verify(children,
                    EvalResult("Length", "1", "int", "new P(o).Length", DkmEvaluationResultFlags.ReadOnly),
                    EvalResult("Raw View", null, "", "o, raw", DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly, DkmEvaluationResultCategory.Data));
                children = GetChildren(children[1]);
                Verify(children,
                    EvalResult("o", "{object[1]}", "object[]", "o.o", DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly));
            }
        }

        /// <summary>
        /// Do not expose Results View if the proxy type is missing.
        /// </summary>
        [Fact]
        public void MissingProxyType()
        {
            var source =
@"using System.Collections;
class C : IEnumerable
{
    private readonly IEnumerable e;
    internal C(IEnumerable e)
    {
        this.e = e;
    }
    public IEnumerator GetEnumerator()
    {
        return this.e.GetEnumerator();
    }
}";
            var assembly = GetAssembly(source);
            var assemblies = new[] { assembly };
            using (ReflectionUtilities.LoadAssemblies(assemblies))
            {
                var runtime = new DkmClrRuntimeInstance(assemblies);
                var type = assembly.GetType("C");
                var value = CreateDkmClrValue(
                    value: type.Instantiate(new[] { 1, 2 }),
                    type: runtime.GetType((TypeImpl)type));
                var evalResult = FormatResult("o", value);
                Verify(evalResult,
                    EvalResult("o", "{C}", "C", "o", DkmEvaluationResultFlags.Expandable));
                var children = GetChildren(evalResult);
                Verify(children,
                    EvalResult("e", "{int[2]}", "System.Collections.IEnumerable {int[]}", "o.e", DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.CanFavorite));
            }
        }

        /// <summary>
        /// Proxy type not in System.Core.dll.
        /// </summary>
        [Fact]
        public void MissingProxyType_SystemCore()
        {
            // "System.Core.dll"
            var source0 = "";
            var compilation0 = CSharpTestBase.CreateCompilation(source0, assemblyName: "system.core");
            var assembly0 = ReflectionUtilities.Load(compilation0.EmitToArray());
            var source =
@"using System.Collections;
class C : IEnumerable
{
    private readonly IEnumerable e;
    internal C(IEnumerable e)
    {
        this.e = e;
    }
    public IEnumerator GetEnumerator()
    {
        return this.e.GetEnumerator();
    }
}";
            var assembly = GetAssembly(source);
            var assemblies = new[] { assembly0, assembly };
            using (ReflectionUtilities.LoadAssemblies(assemblies))
            {
                var runtime = new DkmClrRuntimeInstance(assemblies);
                var type = assembly.GetType("C");
                var value = CreateDkmClrValue(
                    value: type.Instantiate(new[] { 1, 2 }),
                    type: runtime.GetType((TypeImpl)type));
                var evalResult = FormatResult("o", value);
                Verify(evalResult,
                    EvalResult("o", "{C}", "C", "o", DkmEvaluationResultFlags.Expandable));
                var children = GetChildren(evalResult);
                Verify(children,
                    EvalResult("e", "{int[2]}", "System.Collections.IEnumerable {int[]}", "o.e", DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.CanFavorite));
                // Verify the module was found but ResolveTypeName failed.
                var module = runtime.Modules.Single(m => m.Assembly == assembly0);
                Assert.Equal(1, module.ResolveTypeNameFailures);
            }
        }

        /// <summary>
        /// Report "Enumeration yielded no results" when
        /// GetEnumerator returns an empty collection or null.
        /// </summary>
        [Fact]
        public void GetEnumeratorEmptyOrNull()
        {
            var source =
@"using System;
using System.Collections;
using System.Collections.Generic;
// IEnumerable returns empty collection.
class C0 : IEnumerable
{
    public IEnumerator GetEnumerator()
    {
        yield break;
    }
}
// IEnumerable<T> returns empty collection.
class C1<T> : IEnumerable<T>
{
    public IEnumerator<T> GetEnumerator()
    {
        yield break;
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        throw new NotImplementedException();
    }
}
// IEnumerable returns null.
class C2 : IEnumerable
{
    public IEnumerator GetEnumerator()
    {
        return null;
    }
}
// IEnumerable<T> returns null.
class C3<T> : IEnumerable<T>
{
    public IEnumerator<T> GetEnumerator()
    {
        return null;
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        throw new NotImplementedException();
    }
}
class C
{
    C0 _0 = new C0();
    C1<object> _1 = new C1<object>();
    C2 _2 = new C2();
    C3<object> _3 = new C3<object>();
}";
            using (new EnsureEnglishUICulture())
            {
                var assembly = GetAssembly(source);
                var assemblies = ReflectionUtilities.GetMscorlibAndSystemCore(assembly);
                using (ReflectionUtilities.LoadAssemblies(assemblies))
                {
                    var runtime = new DkmClrRuntimeInstance(assemblies);
                    var type = assembly.GetType("C");
                    var value = CreateDkmClrValue(
                        value: type.Instantiate(),
                        type: runtime.GetType((TypeImpl)type));
                    var evalResult = FormatResult("o", value);
                    Verify(evalResult,
                        EvalResult("o", "{C}", "C", "o", DkmEvaluationResultFlags.Expandable));
                    var children = GetChildren(evalResult);
                    Verify(children,
                        EvalResult("_0", "{C0}", "C0", "o._0", DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.CanFavorite),
                        EvalResult("_1", "{C1<object>}", "C1<object>", "o._1", DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.CanFavorite),
                        EvalResult("_2", "{C2}", "C2", "o._2", DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.CanFavorite),
                        EvalResult("_3", "{C3<object>}", "C3<object>", "o._3", DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.CanFavorite));
                    //  C0 _0 = new C0();
                    var moreChildren = GetChildren(children[0]);
                    Verify(moreChildren,
                        EvalResult(
                            "Results View",
                            "Expanding the Results View will enumerate the IEnumerable",
                            "",
                            "o._0, results",
                            DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.ExpansionHasSideEffects,
                            DkmEvaluationResultCategory.Method));
                    moreChildren = GetChildren(moreChildren[0]);
                    Verify(moreChildren,
                        EvalResult(
                            "Empty",
                            "\"Enumeration yielded no results\"",
                            "string",
                            null,
                            DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.RawString));
                    // C1<object> _1 = new C1<object>();
                    moreChildren = GetChildren(children[1]);
                    Verify(moreChildren,
                        EvalResult(
                            "Results View",
                            "Expanding the Results View will enumerate the IEnumerable",
                            "",
                            "o._1, results",
                            DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.ExpansionHasSideEffects,
                            DkmEvaluationResultCategory.Method));
                    moreChildren = GetChildren(moreChildren[0]);
                    Verify(moreChildren,
                        EvalResult(
                            "Empty",
                            "\"Enumeration yielded no results\"",
                            "string",
                            null,
                            DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.RawString));
                    // C2 _2 = new C2();
                    moreChildren = GetChildren(children[2]);
                    Verify(moreChildren,
                        EvalResult(
                            "Results View",
                            "Expanding the Results View will enumerate the IEnumerable",
                            "",
                            "o._2, results",
                            DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.ExpansionHasSideEffects,
                            DkmEvaluationResultCategory.Method));
                    moreChildren = GetChildren(moreChildren[0]);
                    Verify(moreChildren,
                        EvalResult(
                            "Empty",
                            "\"Enumeration yielded no results\"",
                            "string",
                            null,
                            DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.RawString));
                    // C3<object> _3 = new C3<object>();
                    moreChildren = GetChildren(children[3]);
                    Verify(moreChildren,
                        EvalResult(
                            "Results View",
                            "Expanding the Results View will enumerate the IEnumerable",
                            "",
                            "o._3, results",
                            DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.ExpansionHasSideEffects,
                            DkmEvaluationResultCategory.Method));
                    moreChildren = GetChildren(moreChildren[0]);
                    Verify(moreChildren,
                        EvalResult(
                            "Empty",
                            "\"Enumeration yielded no results\"",
                            "string",
                            null,
                            DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.RawString));
                }
            }
        }

        /// <summary>
        /// Do not instantiate proxy type for null IEnumerable.
        /// </summary>
        [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1009646")]
        public void IEnumerableNull()
        {
            var source =
@"using System.Collections;
using System.Collections.Generic;
interface I : IEnumerable
{
}
class C
{
    IEnumerable<char> E = null;
    I F = null;
    string S = null;
}";
            var assembly = GetAssembly(source);
            var assemblies = ReflectionUtilities.GetMscorlibAndSystemCore(assembly);
            using (ReflectionUtilities.LoadAssemblies(assemblies))
            {
                var runtime = new DkmClrRuntimeInstance(assemblies);
                var type = assembly.GetType("C");
                var value = CreateDkmClrValue(
                    value: type.Instantiate(),
                    type: runtime.GetType((TypeImpl)type));
                var evalResult = FormatResult("o", value);
                Verify(evalResult,
                    EvalResult("o", "{C}", "C", "o", DkmEvaluationResultFlags.Expandable));
                var children = GetChildren(evalResult);
                Verify(children,
                    EvalResult("E", "null", "System.Collections.Generic.IEnumerable<char>", "o.E", DkmEvaluationResultFlags.CanFavorite),
                    EvalResult("F", "null", "I", "o.F", DkmEvaluationResultFlags.CanFavorite),
                    EvalResult("S", "null", "string", "o.S", DkmEvaluationResultFlags.CanFavorite));
            }
        }

        [Fact]
        public void GetEnumeratorException()
        {
            var source =
@"using System;
using System.Collections;
class C : IEnumerable
{
    public IEnumerator GetEnumerator()
    {
        throw new NotImplementedException();
    }
}";
            using (new EnsureEnglishUICulture())
            {
                var assembly = GetAssembly(source);
                var assemblies = ReflectionUtilities.GetMscorlibAndSystemCore(assembly);
                using (ReflectionUtilities.LoadAssemblies(assemblies))
                {
                    var runtime = new DkmClrRuntimeInstance(assemblies);
                    var type = assembly.GetType("C");
                    var value = CreateDkmClrValue(
                        value: type.Instantiate(),
                        type: runtime.GetType((TypeImpl)type));
                    var evalResult = FormatResult("o", value);
                    Verify(evalResult,
                        EvalResult("o", "{C}", "C", "o", DkmEvaluationResultFlags.Expandable));
                    var children = GetChildren(evalResult);
                    Verify(children,
                        EvalResult(
                            "Results View",
                            "Expanding the Results View will enumerate the IEnumerable",
                            "",
                            "o, results",
                            DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.ExpansionHasSideEffects,
                            DkmEvaluationResultCategory.Method));
                    children = GetChildren(children[0]);
                    Verify(children[6],
                        EvalResult("Message", "\"The method or operation is not implemented.\"", "string", null, DkmEvaluationResultFlags.RawString | DkmEvaluationResultFlags.ReadOnly));
                }
            }
        }

        [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1145125")]
        [WorkItem("https://github.com/dotnet/roslyn/issues/5666")]
        public void GetEnumerableException()
        {
            var source =
@"using System;
using System.Collections;
class E : Exception, IEnumerable
{
    IEnumerator IEnumerable.GetEnumerator()
    {
        yield return 1;
    }
}
class C
{
    internal IEnumerable P
    {
        get { throw new NotImplementedException(); }
    }
    internal IEnumerable Q
    {
        get { throw new E(); }
    }
}";
            using (new EnsureEnglishUICulture())
            {
                var runtime = new DkmClrRuntimeInstance(ReflectionUtilities.GetMscorlibAndSystemCore(GetAssembly(source)));
                using (runtime.Load())
                {
                    var type = runtime.GetType("C");
                    var value = type.Instantiate();
                    var evalResult = FormatResult("o", value);
                    Verify(evalResult,
                        EvalResult("o", "{C}", "C", "o", DkmEvaluationResultFlags.Expandable));
                    var children = GetChildren(evalResult);
                    Verify(children,
                        EvalResult(
                            "P",
                            "'o.P' threw an exception of type 'System.NotImplementedException'",
                            "System.Collections.IEnumerable {System.NotImplementedException}",
                            "o.P",
                            DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.ExceptionThrown | DkmEvaluationResultFlags.CanFavorite),
                        EvalResult(
                            "Q",
                            "'o.Q' threw an exception of type 'E'",
                            "System.Collections.IEnumerable {E}",
                            "o.Q",
                            DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.ExceptionThrown | DkmEvaluationResultFlags.CanFavorite));
                    children = GetChildren(children[1]);
                    Verify(children[6],
                        EvalResult(
                            "Message",
                            "\"Exception of type 'E' was thrown.\"",
                            "string",
                            null,
                            DkmEvaluationResultFlags.RawString | DkmEvaluationResultFlags.ReadOnly));
                }
            }
        }

        [Fact]
        public void GetEnumerableError()
        {
            var source =
@"using System.Collections;
class C
{
    bool f;
    internal ArrayList P
    {
        get { while (!this.f) { } return new ArrayList(); }
    }
}";
            DkmClrRuntimeInstance runtime = null;
            VisualStudio.Debugger.Evaluation.ClrCompilation.DkmClrValue getMemberValue(VisualStudio.Debugger.Evaluation.ClrCompilation.DkmClrValue v, string m) => (m == "P") ? CreateErrorValue(runtime.GetType(typeof(System.Collections.ArrayList)), "Function evaluation timed out") : null;
            runtime = new DkmClrRuntimeInstance(ReflectionUtilities.GetMscorlibAndSystemCore(GetAssembly(source)), getMemberValue: getMemberValue);
            using (runtime.Load())
            {
                var type = runtime.GetType("C");
                var value = type.Instantiate();
                var memberValue = value.GetMemberValue("P", (int)System.Reflection.MemberTypes.Property, "C", DefaultInspectionContext);
                var evalResult = FormatResult("o.P", memberValue);
                Verify(evalResult,
                    EvalFailedResult("o.P", "Function evaluation timed out", "System.Collections.ArrayList", "o.P"));
            }
        }

        /// <summary>
        /// If evaluation of the proxy Items property returns an error
        /// (say, evaluation of the enumerable requires func-eval and
        /// either func-eval is disabled or we're debugging a .dmp),
        /// we should include a row that reports the error rather than
        /// having an empty expansion (since the container Items property
        /// is [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]).
        /// Note, the native EE has an empty expansion when .dmp debugging.
        /// </summary>
        [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1043746")]
        public void GetProxyPropertyValueError()
        {
            var source =
@"using System.Collections;
class C : IEnumerable
{
    public IEnumerator GetEnumerator()
    {
        yield return 1;
    }
}";
            DkmClrRuntimeInstance runtime = null;
            VisualStudio.Debugger.Evaluation.ClrCompilation.DkmClrValue getMemberValue(VisualStudio.Debugger.Evaluation.ClrCompilation.DkmClrValue v, string m) => (m == "Items") ? CreateErrorValue(runtime.GetType(typeof(object)).MakeArrayType(), string.Format("Unable to evaluate '{0}'", m)) : null;
            runtime = new DkmClrRuntimeInstance(ReflectionUtilities.GetMscorlibAndSystemCore(GetAssembly(source)), getMemberValue: getMemberValue);
            using (runtime.Load())
            {
                var type = runtime.GetType("C");
                var value = type.Instantiate();
                var evalResult = FormatResult("o", value);
                Verify(evalResult,
                    EvalResult("o", "{C}", "C", "o", DkmEvaluationResultFlags.Expandable));
                var children = GetChildren(evalResult);
                Verify(children,
                    EvalResult(
                        "Results View",
                        "Expanding the Results View will enumerate the IEnumerable",
                        "",
                        "o, results",
                        DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.ExpansionHasSideEffects,
                        DkmEvaluationResultCategory.Method));
                children = GetChildren(children[0]);
                Verify(children,
                    EvalFailedResult("Error", "Unable to evaluate 'Items'", flags: DkmEvaluationResultFlags.None));
            }
        }

        /// <summary>
        /// Root-level synthetic values declared as IEnumerable or
        /// IEnumerable&lt;T&gt; should be expanded directly
        /// without intermediate "Results View" row.
        /// </summary>
        [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1114276")]
        public void SyntheticIEnumerable()
        {
            var source =
@"using System.Collections;
using System.Collections.Generic;
class C
{
    IEnumerable P { get { yield return 1; yield return 2; } }
    IEnumerable<int> Q { get { yield return 3; } }
    IEnumerable R { get { return null; } }
    IEnumerable S { get { return string.Empty; } }
    IEnumerable<int> T { get { return new int[] { 4, 5 }; } }
    IList<int> U { get { return new List<int>(new int[] { 6 }); } }
}";
            var runtime = new DkmClrRuntimeInstance(ReflectionUtilities.GetMscorlibAndSystemCore(GetAssembly(source)));
            using (runtime.Load())
            {
                var type = runtime.GetType("C");
                var value = type.UnderlyingType.Instantiate();

                // IEnumerable
                var evalResult = FormatPropertyValue(runtime, value, "P");
                Verify(evalResult,
                    EvalResult(
                        "P",
                        "{C.<get_P>d__1}",
                        "System.Collections.IEnumerable {C.<get_P>d__1}",
                        "P",
                        DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly,
                        DkmEvaluationResultCategory.Method));
                var children = GetChildren(evalResult);
                Verify(children,
                    EvalResult("[0]", "1", "object {int}", "new System.Linq.SystemCore_EnumerableDebugView(P).Items[0]"),
                    EvalResult("[1]", "2", "object {int}", "new System.Linq.SystemCore_EnumerableDebugView(P).Items[1]"));

                // IEnumerable<int>
                evalResult = FormatPropertyValue(runtime, value, "Q");
                Verify(evalResult,
                    EvalResult(
                        "Q",
                        "{C.<get_Q>d__3}",
                        "System.Collections.Generic.IEnumerable<int> {C.<get_Q>d__3}",
                        "Q",
                        DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly,
                        DkmEvaluationResultCategory.Method));
                children = GetChildren(evalResult);
                Verify(children,
                    EvalResult("[0]", "3", "int", "new System.Linq.SystemCore_EnumerableDebugView<int>(Q).Items[0]"));

                // null (unchanged)
                evalResult = FormatPropertyValue(runtime, value, "R");
                Verify(evalResult,
                    EvalResult(
                        "R",
                        "null",
                        "System.Collections.IEnumerable",
                        "R",
                        DkmEvaluationResultFlags.None));

                // string (unchanged)
                evalResult = FormatPropertyValue(runtime, value, "S");
                Verify(evalResult,
                    EvalResult(
                        "S",
                        "\"\"",
                        "System.Collections.IEnumerable {string}",
                        "S",
                        DkmEvaluationResultFlags.RawString,
                        DkmEvaluationResultCategory.Other,
                       editableValue: "\"\""));

                // array (unchanged)
                evalResult = FormatPropertyValue(runtime, value, "T");
                Verify(evalResult,
                    EvalResult(
                        "T",
                        "{int[2]}",
                        "System.Collections.Generic.IEnumerable<int> {int[]}",
                        "T",
                        DkmEvaluationResultFlags.Expandable));
                children = GetChildren(evalResult);
                Verify(children,
                    EvalResult("[0]", "4", "int", "((int[])T)[0]"),
                    EvalResult("[1]", "5", "int", "((int[])T)[1]"));

                // IList<int> declared type (unchanged)
                evalResult = FormatPropertyValue(runtime, value, "U");
                Verify(evalResult,
                    EvalResult(
                        "U",
                        "Count = 1",
                        "System.Collections.Generic.IList<int> {System.Collections.Generic.List<int>}",
                        "U",
                        DkmEvaluationResultFlags.Expandable));
                children = GetChildren(evalResult);
                Verify(children,
                    EvalResult("[0]", "6", "int", "new System.Collections.Generic.Mscorlib_CollectionDebugView<int>(U).Items[0]"),
                    EvalResult("Raw View", null, "", "U, raw", DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly, DkmEvaluationResultCategory.Data));
            }
        }

        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/4098")]
        public void IEnumerableOfAnonymousType()
        {
            var code =
@"using System.Collections.Generic;
using System.Linq;

class C
{
    static void M(List<int> list)
    {
        var result = from x in list from y in list where x > 0 select new { x, y };
    }
}";
            var assembly = GetAssembly(code);
            var assemblies = ReflectionUtilities.GetMscorlibAndSystemCore(assembly);
            using (ReflectionUtilities.LoadAssemblies(assemblies))
            {
                var runtime = new DkmClrRuntimeInstance(assemblies);
                var anonymousType = assembly.GetType("<>f__AnonymousType0`2").MakeGenericType(typeof(int), typeof(int));
                var type = typeof(Enumerable).GetNestedType("WhereSelectEnumerableIterator`2", BindingFlags.NonPublic).MakeGenericType(anonymousType, anonymousType);
                var displayClass = assembly.GetType("C+<>c");
                var instance = displayClass.Instantiate();
                var ctor = type.GetConstructors().Single();
                var parameters = ctor.GetParameters();
                var listType = typeof(List<>).MakeGenericType(anonymousType);
                var source = listType.Instantiate();
                listType.GetMethod("Add").Invoke(source, new[] { anonymousType.Instantiate(1, 1) });
                var predicate = Delegate.CreateDelegate(parameters[1].ParameterType, instance, displayClass.GetMethod("<M>b__0_2", BindingFlags.Instance | BindingFlags.NonPublic));
                var selector = Delegate.CreateDelegate(parameters[2].ParameterType, instance, displayClass.GetMethod("<M>b__0_3", BindingFlags.Instance | BindingFlags.NonPublic));
                var value = CreateDkmClrValue(
                    value: type.Instantiate(source, predicate, selector),
                    type: runtime.GetType((TypeImpl)type));
                var expr = "from x in my_list from y in my_list where x > 0 select new { x, y }";
                var typeName = "System.Linq.Enumerable.WhereSelectEnumerableIterator<<>f__AnonymousType0<int, int>, <>f__AnonymousType0<int, int>>";

                var name = expr + ";";
                var evalResult = FormatResult(name, value);
                Verify(evalResult,
                    EvalResult(name, $"{{{typeName}}}", typeName, expr, DkmEvaluationResultFlags.Expandable));
                var resultsViewRow = GetChildren(evalResult).Last();
                Verify(GetChildren(resultsViewRow),
                    EvalResult(
                        "[0]",
                        "{{ x = 1, y = 1 }}",
                        "<>f__AnonymousType0<int, int>",
                        null,
                        DkmEvaluationResultFlags.Expandable));

                name = expr + ", results";
                evalResult = FormatResult(name, value, inspectionContext: CreateDkmInspectionContext(DkmEvaluationFlags.ResultsOnly));
                Verify(evalResult,
                    EvalResult(name, $"{{{typeName}}}", typeName, name, DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly));
                Verify(GetChildren(evalResult),
                    EvalResult(
                        "[0]",
                        "{{ x = 1, y = 1 }}",
                        "<>f__AnonymousType0<int, int>",
                        null,
                        DkmEvaluationResultFlags.Expandable));
            }
        }

        private DkmEvaluationResult FormatPropertyValue(DkmClrRuntimeInstance runtime, object value, string propertyName)
        {
            var propertyInfo = value.GetType().GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
            var propertyValue = propertyInfo.GetValue(value);
            var propertyType = runtime.GetType(propertyInfo.PropertyType);
            var valueType = (propertyValue == null) ? propertyType : runtime.GetType(propertyValue.GetType());
            return FormatResult(
                propertyName,
                CreateDkmClrValue(propertyValue, type: valueType, valueFlags: DkmClrValueFlags.Synthetic),
                declaredType: propertyType);
        }
    }
}
