﻿// Copyright (c) Microsoft.  All Rights Reserved.  Licensed under the Apache License, Version 2.0.  See License.txt in the project root for license information.

using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;

namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Symbols
{
    /// <summary>
    /// Test MethodSymbol.OverriddenOrHiddenMembers and PropertySymbol.OverriddenOrHiddenMembers.
    /// </summary>
    public class OverriddenOrHiddenMembersTests : CSharpTestBase
    {
        [Fact]
        public void TestOverridingGenericMethods()
        {
            // When dealing with one generic method that overrides another, things get a bit
            // complicated. Basically we need to draw a distinction between the method
            // *definition* that is overridden, and the method *reference* that is overridden.
            // We also need to draw a distinction between the *immediately* overridden method
            // and the *original* virtual or abstract method.
            //
            // Consider D.M<V>. What method does it override?  One could make several arguments.
            // First, one could say that *as a definition*, the method D.M<V>(int, V) overrides 
            // the definition B<T>.M<U>(T, U).  That is a bit unsatisfying because the signatures
            // do not match, and it seems implausible that two methods with different signatures
            // can be overrides.
            //
            // Second, one could say that *as a definition*, the method D.M<V>(int, V) overrides
            // the definition B<int>.M<U>(int, U). That is somewhat more satisfying, as now the
            // signatures differ only in terms of generic type substitution of V for U.
            //
            // Third, one could say that *as a reference*, the method D.M<V>(int, V) overrides
            // the method *reference* B<int>.M<V>(int, V). Now we have an exact signature match.
            //
            // Now consider D.M<string>(int, string). What does it override? There are four
            // possibilities: (1) it doesn't override any method because D.M<string> is not a
            // definition, it is a reference, (2) B<T>.M<U>, (3) B<int>.M<U>, (4) B<int>.M<string>.
            //
            // The "OverriddenMethod" property says that D.M<V> overrides B<int>.M<U> and
            // D.M<string> overrides nothing.  The "OriginalOverriddenMethod" property says
            // that D.M<string> overrides B<int>.M<string>.
            //
            // Also, the "OverriddenMethod" property will tell you what abstract, virtual
            // *or overriding* method a given method overrides; that is, it looks up
            // the base class hierarchy until it finds a first match.  By contrast the
            // "OriginalOverriddenMethod" property looks all the way up to find the original
            // virtual or abstract method.

            // Let's see this in action:

            var text = @"
class B<T>
{
  public virtual void M<U>(T t, U u) {}
}
class D : B<D>
{
  public override void M<V>(D d, V v)
  {
  }
}
";

            var tree = Parse(text);
            var comp = CreateCompilation(tree);

            var global = comp.GlobalNamespace;

            // Types
            /* B<T> */
            var BofT = global.GetMember<NamedTypeSymbol>("B");
            /* D    */
            var D = global.GetMember<NamedTypeSymbol>("D");
            /* <D>  */
            var ofD = ImmutableArray.Create<TypeSymbol>(D);
            /* B<D> */
            var BofD = BofT.Construct(ofD);

            // Methods
            /* B<T>.M<U> */
            var BofT_MofU = BofT.GetMember<MethodSymbol>("M");
            /* B<D>.M<U> */
            var BofD_MofU = BofD.GetMember<MethodSymbol>("M");
            /* B<D>.M<D> */
            var BofD_MofD = BofD_MofU.Construct(ofD);
            /* D.M<V>    */
            var D_MofV = D.GetMember<MethodSymbol>("M");
            /* <V>       */
            var ofV = ImmutableArray.Create<TypeSymbol>(D_MofV.TypeParameters[0]);
            /* D.M<D>    */
            var D_MofD = D_MofV.Construct(ofD);
            /* B<D>.M<V> */
            var BofD_MofV = BofD_MofU.Construct(ofV);

            // Nothing is hidden:
            AssertSame(0, BofT_MofU.OverriddenOrHiddenMembers.HiddenMembers.Length);
            AssertSame(0, BofD_MofU.OverriddenOrHiddenMembers.HiddenMembers.Length);
            AssertSame(0, BofD_MofD.OverriddenOrHiddenMembers.HiddenMembers.Length);
            AssertSame(0, D_MofV.OverriddenOrHiddenMembers.HiddenMembers.Length);
            AssertSame(0, D_MofD.OverriddenOrHiddenMembers.HiddenMembers.Length);

            // B<whatever>.M<whatever> overrides nothing.
            AssertSame(0, BofT_MofU.OverriddenOrHiddenMembers.OverriddenMembers.Length);
            AssertSame(0, BofD_MofU.OverriddenOrHiddenMembers.OverriddenMembers.Length);
            AssertSame(0, BofD_MofD.OverriddenOrHiddenMembers.OverriddenMembers.Length);

            // D.M<V> overrides B<D>.M<U>, *not* B<D>.M<V> or B<T>.M<U>...
            AssertSame(1, D_MofV.OverriddenOrHiddenMembers.OverriddenMembers.Length);
            Assert.Equal(D_MofV.OverriddenMethod, BofD_MofU);
            // ... but the "original" overridden method of D.M<V> is B<D>.M<V>
            Assert.Equal(D_MofV.GetConstructedLeastOverriddenMethod(D), BofD_MofV);

            // D.M<D> overrides nothing, since it is constructed...
            Assert.Null(D_MofD.OverriddenMethod);
            // ... and the overridden members count is zero if the overridden method is null...
            AssertSame(0, D_MofD.OverriddenOrHiddenMembers.OverriddenMembers.Length);
            // ... but the original overridden method is B<D>.M<D>
            Assert.Equal(D_MofD.GetConstructedLeastOverriddenMethod(D), BofD_MofD);
        }

        [Fact]
        public void TestBug6156()
        {
            var text = @"
class Ref1
{
    public virtual void M(ref int x) { x = 1; } // SLOT1
}
class Out1 : Ref1
{
    public virtual void M(out int x) { x = 2; } // SLOT2
}
class Ref2 : Out1
{
    public override void M(ref int x) { x = 3; } 
    // CLR says this overrides SLOT2, even though there is a ref/out mismatch with Out1.
    // C# says this overrides SLOT1
}
class Out2 : Ref2
{
    public override void M(out int x) { x = 4; } 
    // CLR says this overrides SLOT2, even though there is a ref/out mismatch with Ref2.M.
    // C# says this overrides SLOT2
}
class Out3 : Out2
{
    public override void M(out int x) { x = 5; } 
}
";

            var tree = Parse(text);
            var comp = CreateCompilation(tree);

            var global = comp.GlobalNamespace;

            var ref1 = global.GetMember<NamedTypeSymbol>("Ref1");
            var out1 = global.GetMember<NamedTypeSymbol>("Out1");
            var ref2 = global.GetMember<NamedTypeSymbol>("Ref2");
            var out2 = global.GetMember<NamedTypeSymbol>("Out2");
            var out3 = global.GetMember<NamedTypeSymbol>("Out3");

            var ref1M = ref1.GetMember<MethodSymbol>("M");
            var out1M = out1.GetMember<MethodSymbol>("M");
            var ref2M = ref2.GetMember<MethodSymbol>("M");
            var out2M = out2.GetMember<MethodSymbol>("M");
            var out3M = out3.GetMember<MethodSymbol>("M");

            // Clearly nothing is hidden or overridden in Ref1.
            AssertSame(0, ref1M.OverriddenOrHiddenMembers.HiddenMembers.Length);
            AssertSame(0, ref1M.OverriddenOrHiddenMembers.OverriddenMembers.Length);

            // Out1.M does not override anything (because it is not declared with "override") and
            // it does not hide anything (because it does not match signatures with Ref1.M).
            AssertSame(0, out1M.OverriddenOrHiddenMembers.HiddenMembers.Length);
            AssertSame(0, out1M.OverriddenOrHiddenMembers.OverriddenMembers.Length);

            // C# thinks that Ref2.M overrides Ref1.M, though at runtime in fact the CLR
            // will set Ref2.M to the second slot, not the first slot.
            AssertSame(0, ref2M.OverriddenOrHiddenMembers.HiddenMembers.Length);
            AssertSame(1, ref2M.OverriddenOrHiddenMembers.OverriddenMembers.Length);
            Assert.Same(ref1M, ref2M.OverriddenMethod);
            Assert.Same(ref1M, ref2M.OverriddenOrHiddenMembers.OverriddenMembers.Single());

            // C# thinks that Out2.M overrides Out1.M. The runtime agrees and will set
            // Out2.M to the first slot.
            AssertSame(0, out2M.OverriddenOrHiddenMembers.HiddenMembers.Length);
            AssertSame(1, out2M.OverriddenOrHiddenMembers.OverriddenMembers.Length);
            Assert.Same(out1M, out2M.OverriddenMethod);
            Assert.Same(out1M, out2M.OverriddenOrHiddenMembers.OverriddenMembers.Single());

            // Note that the "overridden method" is the *immediately* overridden method,
            // not the original method that was declared.
            AssertSame(0, out3M.OverriddenOrHiddenMembers.HiddenMembers.Length);
            AssertSame(1, out3M.OverriddenOrHiddenMembers.OverriddenMembers.Length);
            Assert.Same(out2M, out3M.OverriddenMethod);
            Assert.Same(out2M, out3M.OverriddenOrHiddenMembers.OverriddenMembers.Single());
        }

        private static void AssertSame(int expected, int actual)
        {
            Assert.True(expected == actual, string.Format("expected {0}, actual {1}", expected, actual));
        }

        [Fact]
        public void TestInterfaceHiding()
        {
            var text = @"
interface BaseInterface1
{
    void Method();
    int Property { get; set; }
}
interface BaseInterface2
{
    void Method();
    int Property { get; set; }
}

interface DerivedInterface1 : BaseInterface1, BaseInterface2
{
    void Method();
    void Method(int x);
    int Property { get; set; }
}

interface DerivedInterface2 : BaseInterface2, BaseInterface1
{
    void Method();
    void Method(int x);
    int Property { get; set; }
}
";
            var comp = CreateCompilation(text);
            var global = comp.GlobalNamespace;

            var baseInterface1 = (NamedTypeSymbol)global.GetMembers("BaseInterface1").Single();
            var baseInterface2 = (NamedTypeSymbol)global.GetMembers("BaseInterface2").Single();
            var derivedInterface1 = (NamedTypeSymbol)global.GetMembers("DerivedInterface1").Single();
            var derivedInterface2 = (NamedTypeSymbol)global.GetMembers("DerivedInterface2").Single();

            var baseInterface1Method = (MethodSymbol)baseInterface1.GetMembers("Method").Single();
            var baseInterface1Property = (PropertySymbol)baseInterface1.GetMembers("Property").Single();

            var baseInterface2Method = (MethodSymbol)baseInterface2.GetMembers("Method").Single();
            var baseInterface2Property = (PropertySymbol)baseInterface2.GetMembers("Property").Single();

            var derivedInterface1Method = (MethodSymbol)derivedInterface1.GetMembers("Method").First();
            var derivedInterface1MethodInt = (MethodSymbol)derivedInterface1.GetMembers("Method").Last();
            var derivedInterface1Property = (PropertySymbol)derivedInterface1.GetMembers("Property").Single();

            var derivedInterface2Method = (MethodSymbol)derivedInterface2.GetMembers("Method").First();
            var derivedInterface2MethodInt = (MethodSymbol)derivedInterface2.GetMembers("Method").Last();
            var derivedInterface2Property = (PropertySymbol)derivedInterface2.GetMembers("Property").Single();

            Assert.Same(OverriddenOrHiddenMembersResult.Empty, baseInterface1Method.OverriddenOrHiddenMembers);
            Assert.Same(OverriddenOrHiddenMembersResult.Empty, baseInterface1Property.OverriddenOrHiddenMembers);

            Assert.Same(OverriddenOrHiddenMembersResult.Empty, baseInterface2Method.OverriddenOrHiddenMembers);
            Assert.Same(OverriddenOrHiddenMembersResult.Empty, baseInterface2Property.OverriddenOrHiddenMembers);

            Assert.Same(OverriddenOrHiddenMembersResult.Empty, derivedInterface1MethodInt.OverriddenOrHiddenMembers);

            Assert.Same(OverriddenOrHiddenMembersResult.Empty, derivedInterface2MethodInt.OverriddenOrHiddenMembers);

            var derivedInterface1MethodOverriddenOrHidden = derivedInterface1Method.OverriddenOrHiddenMembers;
            Assert.False(derivedInterface1MethodOverriddenOrHidden.OverriddenMembers.Any());
            Assert.False(derivedInterface1MethodOverriddenOrHidden.RuntimeOverriddenMembers.Any());
            AssertEx.SetEqual(derivedInterface1MethodOverriddenOrHidden.HiddenMembers, baseInterface1Method, baseInterface2Method);

            var derivedInterface1PropertyOverriddenOrHidden = derivedInterface1Property.OverriddenOrHiddenMembers;
            Assert.False(derivedInterface1PropertyOverriddenOrHidden.OverriddenMembers.Any());
            Assert.False(derivedInterface1PropertyOverriddenOrHidden.RuntimeOverriddenMembers.Any());
            AssertEx.SetEqual(derivedInterface1PropertyOverriddenOrHidden.HiddenMembers, baseInterface1Property, baseInterface2Property);

            var derivedInterface2MethodOverriddenOrHidden = derivedInterface2Method.OverriddenOrHiddenMembers;
            Assert.False(derivedInterface2MethodOverriddenOrHidden.OverriddenMembers.Any());
            Assert.False(derivedInterface2MethodOverriddenOrHidden.RuntimeOverriddenMembers.Any());
            AssertEx.SetEqual(derivedInterface2MethodOverriddenOrHidden.HiddenMembers, baseInterface1Method, baseInterface2Method);

            var derivedInterface2PropertyOverriddenOrHidden = derivedInterface2Property.OverriddenOrHiddenMembers;
            Assert.False(derivedInterface2PropertyOverriddenOrHidden.OverriddenMembers.Any());
            Assert.False(derivedInterface2PropertyOverriddenOrHidden.RuntimeOverriddenMembers.Any());
            AssertEx.SetEqual(derivedInterface2PropertyOverriddenOrHidden.HiddenMembers, baseInterface1Property, baseInterface2Property);

            Assert.Null(baseInterface1Method.OverriddenMethod);
            Assert.Null(baseInterface1Property.OverriddenProperty);
            Assert.Null(baseInterface2Method.OverriddenMethod);
            Assert.Null(baseInterface2Property.OverriddenProperty);
            Assert.Null(derivedInterface1Method.OverriddenMethod);
            Assert.Null(derivedInterface1MethodInt.OverriddenMethod);
            Assert.Null(derivedInterface1Property.OverriddenProperty);
            Assert.Null(derivedInterface2Method.OverriddenMethod);
            Assert.Null(derivedInterface2MethodInt.OverriddenMethod);
            Assert.Null(derivedInterface2Property.OverriddenProperty);
        }

        [Fact]
        public void TestGenericInterfaceHiding()
        {
            var text = @"
interface BaseInterface1<T>
{
    void Method(T t);
    void Method(int i);
    int Property { get; set; }
}
interface BaseInterface2<T>
{
    void Method(T t);
    void Method(int i);
    int Property { get; set; }
}

interface DerivedInterface1 : BaseInterface1<int>, BaseInterface2<int>
{
    void Method();
    void Method(int x);
    int Property { get; set; }
}

interface DerivedInterface2 : BaseInterface2<int>, BaseInterface1<int>
{
    void Method();
    void Method(int x);
    int Property { get; set; }
}
";
            var comp = CreateCompilation(text);
            var global = comp.GlobalNamespace;

            var baseInterface1 = (NamedTypeSymbol)global.GetMembers("BaseInterface1").Single();
            var baseInterface2 = (NamedTypeSymbol)global.GetMembers("BaseInterface2").Single();
            var derivedInterface1 = (NamedTypeSymbol)global.GetMembers("DerivedInterface1").Single();
            var derivedInterface2 = (NamedTypeSymbol)global.GetMembers("DerivedInterface2").Single();

            var baseInterface1MethodT = (MethodSymbol)baseInterface1.GetMembers("Method").First();
            var baseInterface1MethodInt = (MethodSymbol)baseInterface1.GetMembers("Method").Last();
            var baseInterface1Property = (PropertySymbol)baseInterface1.GetMembers("Property").Single();

            var baseInterface2MethodT = (MethodSymbol)baseInterface2.GetMembers("Method").First();
            var baseInterface2MethodInt = (MethodSymbol)baseInterface2.GetMembers("Method").Last();
            var baseInterface2Property = (PropertySymbol)baseInterface2.GetMembers("Property").Single();

            var derivedInterface1Method = (MethodSymbol)derivedInterface1.GetMembers("Method").First();
            var derivedInterface1MethodInt = (MethodSymbol)derivedInterface1.GetMembers("Method").Last();
            var derivedInterface1Property = (PropertySymbol)derivedInterface1.GetMembers("Property").Single();

            var derivedInterface2Method = (MethodSymbol)derivedInterface2.GetMembers("Method").First();
            var derivedInterface2MethodInt = (MethodSymbol)derivedInterface2.GetMembers("Method").Last();
            var derivedInterface2Property = (PropertySymbol)derivedInterface2.GetMembers("Property").Single();

            Assert.Same(OverriddenOrHiddenMembersResult.Empty, baseInterface1MethodT.OverriddenOrHiddenMembers);
            Assert.Same(OverriddenOrHiddenMembersResult.Empty, baseInterface1MethodInt.OverriddenOrHiddenMembers);
            Assert.Same(OverriddenOrHiddenMembersResult.Empty, baseInterface1Property.OverriddenOrHiddenMembers);

            Assert.Same(OverriddenOrHiddenMembersResult.Empty, baseInterface2MethodT.OverriddenOrHiddenMembers);
            Assert.Same(OverriddenOrHiddenMembersResult.Empty, baseInterface2MethodInt.OverriddenOrHiddenMembers);
            Assert.Same(OverriddenOrHiddenMembersResult.Empty, baseInterface2Property.OverriddenOrHiddenMembers);

            Assert.Same(OverriddenOrHiddenMembersResult.Empty, derivedInterface1Method.OverriddenOrHiddenMembers);

            Assert.Same(OverriddenOrHiddenMembersResult.Empty, derivedInterface2Method.OverriddenOrHiddenMembers);

            var derivedInterface1MethodIntOverriddenOrHidden = derivedInterface1MethodInt.OverriddenOrHiddenMembers;
            Assert.False(derivedInterface1MethodIntOverriddenOrHidden.OverriddenMembers.Any());
            Assert.False(derivedInterface1MethodIntOverriddenOrHidden.RuntimeOverriddenMembers.Any());
            Assert.Equal(4, derivedInterface1MethodIntOverriddenOrHidden.HiddenMembers.Length);

            var derivedInterface1PropertyOverriddenOrHidden = derivedInterface1Property.OverriddenOrHiddenMembers;
            Assert.False(derivedInterface1PropertyOverriddenOrHidden.OverriddenMembers.Any());
            Assert.False(derivedInterface1PropertyOverriddenOrHidden.RuntimeOverriddenMembers.Any());
            Assert.Equal(2, derivedInterface1PropertyOverriddenOrHidden.HiddenMembers.Length);

            var derivedInterface2MethodIntOverriddenOrHidden = derivedInterface2MethodInt.OverriddenOrHiddenMembers;
            Assert.False(derivedInterface2MethodIntOverriddenOrHidden.OverriddenMembers.Any());
            Assert.False(derivedInterface2MethodIntOverriddenOrHidden.RuntimeOverriddenMembers.Any());
            Assert.Equal(4, derivedInterface2MethodIntOverriddenOrHidden.HiddenMembers.Length);

            var derivedInterface2PropertyOverriddenOrHidden = derivedInterface2Property.OverriddenOrHiddenMembers;
            Assert.False(derivedInterface2PropertyOverriddenOrHidden.OverriddenMembers.Any());
            Assert.False(derivedInterface2PropertyOverriddenOrHidden.RuntimeOverriddenMembers.Any());
            Assert.Equal(2, derivedInterface2PropertyOverriddenOrHidden.HiddenMembers.Length);

            Assert.Null(baseInterface1MethodT.OverriddenMethod);
            Assert.Null(baseInterface1Property.OverriddenProperty);
            Assert.Null(baseInterface2MethodT.OverriddenMethod);
            Assert.Null(baseInterface2Property.OverriddenProperty);
            Assert.Null(derivedInterface1Method.OverriddenMethod);
            Assert.Null(derivedInterface1MethodInt.OverriddenMethod);
            Assert.Null(derivedInterface1Property.OverriddenProperty);
            Assert.Null(derivedInterface2Method.OverriddenMethod);
            Assert.Null(derivedInterface2MethodInt.OverriddenMethod);
            Assert.Null(derivedInterface2Property.OverriddenProperty);
        }

        [Fact]
        public void TestClassHiding()
        {
            var text = @"
class BaseClass
{
    public void Method();
    public int Property { get; set; }
}

class DerivedClass : BaseClass
{
    public void Method();
    public void Method(int x);
    public int Property { get; set; }
}
";
            var comp = CreateCompilation(text);
            var global = comp.GlobalNamespace;

            var baseClass = (NamedTypeSymbol)global.GetMembers("BaseClass").Single();
            var derivedClass = (NamedTypeSymbol)global.GetMembers("DerivedClass").Single();

            var baseClassMethod = (MethodSymbol)baseClass.GetMembers("Method").Single();
            var baseClassProperty = (PropertySymbol)baseClass.GetMembers("Property").Single();

            var derivedClassMethod = (MethodSymbol)derivedClass.GetMembers("Method").First();
            var derivedClassMethodInt = (MethodSymbol)derivedClass.GetMembers("Method").Last();
            var derivedClassProperty = (PropertySymbol)derivedClass.GetMembers("Property").Single();

            Assert.Same(OverriddenOrHiddenMembersResult.Empty, baseClassMethod.OverriddenOrHiddenMembers);
            Assert.Same(OverriddenOrHiddenMembersResult.Empty, baseClassProperty.OverriddenOrHiddenMembers);

            Assert.Same(OverriddenOrHiddenMembersResult.Empty, derivedClassMethodInt.OverriddenOrHiddenMembers);

            var derivedClassMethodOverriddenOrHidden = derivedClassMethod.OverriddenOrHiddenMembers;
            Assert.False(derivedClassMethodOverriddenOrHidden.OverriddenMembers.Any());
            Assert.False(derivedClassMethodOverriddenOrHidden.RuntimeOverriddenMembers.Any());
            Assert.Same(baseClassMethod, derivedClassMethodOverriddenOrHidden.HiddenMembers.Single());

            var derivedClassPropertyOverriddenOrHidden = derivedClassProperty.OverriddenOrHiddenMembers;
            Assert.False(derivedClassPropertyOverriddenOrHidden.OverriddenMembers.Any());
            Assert.False(derivedClassPropertyOverriddenOrHidden.RuntimeOverriddenMembers.Any());
            Assert.Same(baseClassProperty, derivedClassPropertyOverriddenOrHidden.HiddenMembers.Single());

            Assert.Null(baseClassMethod.OverriddenMethod);
            Assert.Null(baseClassProperty.OverriddenProperty);
            Assert.Null(derivedClassMethod.OverriddenMethod);
            Assert.Null(derivedClassMethodInt.OverriddenMethod);
            Assert.Null(derivedClassProperty.OverriddenProperty);
        }

        [Fact]
        public void TestGenericClassHiding()
        {
            var text = @"
class BaseClass<T>
{
    public void Method(T t) { }
    public void Method(int i) { }
    public int Property { get; set; }
}

class DerivedClass : BaseClass<int>
{
    public void Method() { }
    public void Method(int x) { }
    public int Property { get; set; }
}
";
            var comp = CreateCompilation(text);
            var global = comp.GlobalNamespace;

            var baseClass = (NamedTypeSymbol)global.GetMembers("BaseClass").Single();
            var derivedClass = (NamedTypeSymbol)global.GetMembers("DerivedClass").Single();

            var baseClassMethodT = (MethodSymbol)baseClass.GetMembers("Method").First();
            var baseClassMethodInt = (MethodSymbol)baseClass.GetMembers("Method").Last();
            var baseClassProperty = (PropertySymbol)baseClass.GetMembers("Property").Single();

            var derivedClassMethod = (MethodSymbol)derivedClass.GetMembers("Method").First();
            var derivedClassMethodInt = (MethodSymbol)derivedClass.GetMembers("Method").Last();
            var derivedClassProperty = (PropertySymbol)derivedClass.GetMembers("Property").Single();

            Assert.Same(OverriddenOrHiddenMembersResult.Empty, baseClassMethodT.OverriddenOrHiddenMembers);
            Assert.Same(OverriddenOrHiddenMembersResult.Empty, baseClassMethodInt.OverriddenOrHiddenMembers);
            Assert.Same(OverriddenOrHiddenMembersResult.Empty, baseClassProperty.OverriddenOrHiddenMembers);

            Assert.Same(OverriddenOrHiddenMembersResult.Empty, derivedClassMethod.OverriddenOrHiddenMembers);

            var derivedClassMethodIntOverriddenOrHidden = derivedClassMethodInt.OverriddenOrHiddenMembers;
            Assert.False(derivedClassMethodIntOverriddenOrHidden.OverriddenMembers.Any());
            Assert.False(derivedClassMethodIntOverriddenOrHidden.RuntimeOverriddenMembers.Any());
            Assert.Equal(2, derivedClassMethodIntOverriddenOrHidden.HiddenMembers.Length);

            var derivedClassPropertyOverriddenOrHidden = derivedClassProperty.OverriddenOrHiddenMembers;
            Assert.False(derivedClassPropertyOverriddenOrHidden.OverriddenMembers.Any());
            Assert.False(derivedClassPropertyOverriddenOrHidden.RuntimeOverriddenMembers.Any());
            Assert.Equal(1, derivedClassPropertyOverriddenOrHidden.HiddenMembers.Length);

            Assert.Null(baseClassMethodT.OverriddenMethod);
            Assert.Null(baseClassMethodInt.OverriddenMethod);
            Assert.Null(baseClassProperty.OverriddenProperty);
            Assert.Null(derivedClassMethod.OverriddenMethod);
            Assert.Null(derivedClassMethodInt.OverriddenMethod);
            Assert.Null(derivedClassProperty.OverriddenProperty);
        }

        [Fact]
        public void TestClassOverriding()
        {
            var text = @"
class BaseClass
{
    public int field;
    public virtual void Method() { }
    public virtual int Property { get; set; }
    public virtual ref int Method1() { return ref field; }
    public virtual ref int Property1 { get { return ref field; } }
    public virtual ref int this[int i] { get { return ref field; } }
}

class DerivedClass : BaseClass
{
    public override void Method() { }
    public override void Method(int x) { } //this is incorrect, but doesn't break the test
    public override int Property { get; set; }
    public override ref int Method1() { return ref field; }
    public override ref int Property1 { get { return ref field; } }
    public override ref int this[int i] { get { return ref field; } }
}
";
            var comp = CreateCompilationWithMscorlib45(text);
            var global = comp.GlobalNamespace;

            var baseClass = (NamedTypeSymbol)global.GetMembers("BaseClass").Single();
            var derivedClass = (NamedTypeSymbol)global.GetMembers("DerivedClass").Single();

            var baseClassMethod = (MethodSymbol)baseClass.GetMembers("Method").Single();
            var baseClassProperty = (PropertySymbol)baseClass.GetMembers("Property").Single();
            var baseClassRefMethod = (MethodSymbol)baseClass.GetMembers("Method1").Single();
            var baseClassRefProperty = (PropertySymbol)baseClass.GetMembers("Property1").Single();
            var baseClassRefIndexer = (PropertySymbol)baseClass.GetMembers("this[]").Single();

            var derivedClassMethod = (MethodSymbol)derivedClass.GetMembers("Method").First();
            var derivedClassMethodInt = (MethodSymbol)derivedClass.GetMembers("Method").Last();
            var derivedClassProperty = (PropertySymbol)derivedClass.GetMembers("Property").Single();
            var derivedClassRefMethod = (MethodSymbol)derivedClass.GetMembers("Method1").Single();
            var derivedClassRefProperty = (PropertySymbol)derivedClass.GetMembers("Property1").Single();
            var derivedClassRefIndexer = (PropertySymbol)derivedClass.GetMembers("this[]").Single();

            Assert.Same(OverriddenOrHiddenMembersResult.Empty, baseClassMethod.OverriddenOrHiddenMembers);
            Assert.Same(OverriddenOrHiddenMembersResult.Empty, baseClassProperty.OverriddenOrHiddenMembers);

            Assert.Same(OverriddenOrHiddenMembersResult.Empty, derivedClassMethodInt.OverriddenOrHiddenMembers);

            var derivedClassMethodOverriddenOrHidden = derivedClassMethod.OverriddenOrHiddenMembers;
            Assert.False(derivedClassMethodOverriddenOrHidden.HiddenMembers.Any());
            Assert.Same(baseClassMethod, derivedClassMethodOverriddenOrHidden.OverriddenMembers.Single());
            Assert.Same(baseClassMethod, derivedClassMethodOverriddenOrHidden.RuntimeOverriddenMembers.Single());

            var derivedClassPropertyOverriddenOrHidden = derivedClassProperty.OverriddenOrHiddenMembers;
            Assert.False(derivedClassPropertyOverriddenOrHidden.HiddenMembers.Any());
            Assert.Same(baseClassProperty, derivedClassPropertyOverriddenOrHidden.OverriddenMembers.Single());
            Assert.Same(baseClassProperty, derivedClassPropertyOverriddenOrHidden.RuntimeOverriddenMembers.Single());

            var derivedClassRefMethodOverriddenOrHidden = derivedClassRefMethod.OverriddenOrHiddenMembers;
            Assert.False(derivedClassRefMethodOverriddenOrHidden.HiddenMembers.Any());
            Assert.Same(baseClassRefMethod, derivedClassRefMethodOverriddenOrHidden.OverriddenMembers.Single());
            Assert.Same(baseClassRefMethod, derivedClassRefMethodOverriddenOrHidden.RuntimeOverriddenMembers.Single());

            var derivedClassRefPropertyOverriddenOrHidden = derivedClassRefProperty.OverriddenOrHiddenMembers;
            Assert.False(derivedClassRefPropertyOverriddenOrHidden.HiddenMembers.Any());
            Assert.Same(baseClassRefProperty, derivedClassRefPropertyOverriddenOrHidden.OverriddenMembers.Single());
            Assert.Same(baseClassRefProperty, derivedClassRefPropertyOverriddenOrHidden.RuntimeOverriddenMembers.Single());

            var derivedClassRefIndexerOverriddenOrHidden = derivedClassRefIndexer.OverriddenOrHiddenMembers;
            Assert.False(derivedClassRefIndexerOverriddenOrHidden.HiddenMembers.Any());
            Assert.Same(baseClassRefIndexer, derivedClassRefIndexerOverriddenOrHidden.OverriddenMembers.Single());
            Assert.Same(baseClassRefIndexer, derivedClassRefIndexerOverriddenOrHidden.RuntimeOverriddenMembers.Single());

            Assert.Null(baseClassMethod.OverriddenMethod);
            Assert.Null(baseClassProperty.OverriddenProperty);
            Assert.Null(baseClassRefMethod.OverriddenMethod);
            Assert.Null(baseClassRefProperty.OverriddenProperty);
            Assert.Null(baseClassRefIndexer.OverriddenProperty);
            Assert.Null(derivedClassMethodInt.OverriddenMethod);

            Assert.Same(baseClassMethod, derivedClassMethod.OverriddenMethod);
            Assert.Same(baseClassProperty, derivedClassProperty.OverriddenProperty);
            Assert.Same(baseClassRefMethod, derivedClassRefMethod.OverriddenMethod);
            Assert.Same(baseClassRefProperty, derivedClassRefProperty.OverriddenProperty);
            Assert.Same(baseClassRefIndexer, derivedClassRefIndexer.OverriddenProperty);
        }

        [Fact]
        public void TestOverridingMembersOnObject()
        {
            // Tests:
            // Override virtual methods declared on object (ToString, GetHashCode etc.)

            var text = @"
class BaseClass<TInt, TLong>
{
    public override string ToString() { return ""; }
    public override int GetHashCode() { return 0; }
}

abstract class DerivedClass : BaseClass<int, long>
{
    public override int GetHashCode() { return 1; }
    public override bool Equals(object obj) { return true; }
}";
            var comp = CreateCompilation(text);
            var global = comp.GlobalNamespace;
            var system = comp.GlobalNamespace.GetNestedNamespace("System");

            var systemObject = (NamedTypeSymbol)system.GetMembers("Object").Single();
            var baseClass = (NamedTypeSymbol)global.GetMembers("BaseClass").Single();
            var derivedClass = (NamedTypeSymbol)global.GetMembers("DerivedClass").Single();

            var objectToString = (MethodSymbol)systemObject.GetMembers("ToString").Single();
            var objectGetHashCode = (MethodSymbol)systemObject.GetMembers("GetHashCode").Single();
            var objectEquals = (MethodSymbol)systemObject.GetMembers("Equals")[0];

            var baseClassToString = (MethodSymbol)baseClass.GetMembers("ToString").Single();
            var baseClassGetHashCode = (MethodSymbol)baseClass.GetMembers("GetHashCode").Single();
            Assert.Null(baseClass.GetMembers("Equals").SingleOrDefault());

            Assert.Null(derivedClass.GetMembers("ToString").SingleOrDefault());
            var derivedClassGetHashCode = (MethodSymbol)derivedClass.GetMembers("GetHashCode").Single();
            var derivedClassEquals = (MethodSymbol)derivedClass.GetMembers("Equals").Single();

            var baseClassToStringOverriddenOrHidden = baseClassToString.OverriddenOrHiddenMembers;
            Assert.False(baseClassToStringOverriddenOrHidden.HiddenMembers.Any());
            Assert.Equal(1, baseClassToStringOverriddenOrHidden.OverriddenMembers.Length);
            Assert.Equal(1, baseClassToStringOverriddenOrHidden.RuntimeOverriddenMembers.Length);

            var baseClassGetHashCodeOverriddenOrHidden = baseClassGetHashCode.OverriddenOrHiddenMembers;
            Assert.False(baseClassGetHashCodeOverriddenOrHidden.HiddenMembers.Any());
            Assert.Equal(1, baseClassGetHashCodeOverriddenOrHidden.OverriddenMembers.Length);
            Assert.Equal(1, baseClassGetHashCodeOverriddenOrHidden.RuntimeOverriddenMembers.Length);

            var derivedClassEqualsOverriddenOrHidden = derivedClassEquals.OverriddenOrHiddenMembers;
            Assert.False(derivedClassEqualsOverriddenOrHidden.HiddenMembers.Any());
            Assert.Equal(1, derivedClassEqualsOverriddenOrHidden.OverriddenMembers.Length);
            Assert.Equal(1, derivedClassEqualsOverriddenOrHidden.RuntimeOverriddenMembers.Length);

            var derivedClassGetHashCodeOverriddenOrHidden = derivedClassGetHashCode.OverriddenOrHiddenMembers;
            Assert.False(derivedClassGetHashCodeOverriddenOrHidden.HiddenMembers.Any());
            Assert.Equal(1, derivedClassGetHashCodeOverriddenOrHidden.OverriddenMembers.Length);
            Assert.Equal(1, derivedClassGetHashCodeOverriddenOrHidden.RuntimeOverriddenMembers.Length);

            Assert.Same(objectToString, baseClassToString.OverriddenMethod);
            Assert.Same(objectGetHashCode, baseClassGetHashCode.OverriddenMethod);

            Assert.Same(baseClassGetHashCode, derivedClassGetHashCode.OverriddenMethod.OriginalDefinition);
            Assert.Same(objectEquals, derivedClassEquals.OverriddenMethod);
        }

        [Fact]
        public void TestGenericClassOverriding()
        {
            var text = @"
class BaseClass<TInt, TLong>
{
    public virtual void Method(ref TInt i, out long l) { }
    public virtual void Method(ref int i, ref TLong l) { }
    public virtual void Method(ref int i, ref long l) { }
    public virtual int Property { get; set; }
}

class DerivedClass : BaseClass<int, long>
{
    public override void Method() { } //this is incorrect, but doesn't break the test
    public override void Method(ref int i, ref long l) { }
    public override int Property { get; set; }
}
";
            var comp = CreateCompilation(text);
            var global = comp.GlobalNamespace;

            var baseClass = (NamedTypeSymbol)global.GetMembers("BaseClass").Single();
            var derivedClass = (NamedTypeSymbol)global.GetMembers("DerivedClass").Single();

            var baseClassMethod1 = (MethodSymbol)baseClass.GetMembers("Method")[0];
            var baseClassMethod2 = (MethodSymbol)baseClass.GetMembers("Method")[1];
            var baseClassMethod3 = (MethodSymbol)baseClass.GetMembers("Method")[2];
            var baseClassProperty = (PropertySymbol)baseClass.GetMembers("Property").Single();

            var derivedClassMethod = (MethodSymbol)derivedClass.GetMembers("Method")[0];
            var derivedClassMethodParams = (MethodSymbol)derivedClass.GetMembers("Method")[1];
            var derivedClassProperty = (PropertySymbol)derivedClass.GetMembers("Property").Single();

            Assert.Same(OverriddenOrHiddenMembersResult.Empty, baseClassMethod1.OverriddenOrHiddenMembers);
            Assert.Same(OverriddenOrHiddenMembersResult.Empty, baseClassMethod2.OverriddenOrHiddenMembers);
            Assert.Same(OverriddenOrHiddenMembersResult.Empty, baseClassMethod3.OverriddenOrHiddenMembers);
            Assert.Same(OverriddenOrHiddenMembersResult.Empty, baseClassProperty.OverriddenOrHiddenMembers);

            Assert.Same(OverriddenOrHiddenMembersResult.Empty, derivedClassMethod.OverriddenOrHiddenMembers);

            var derivedClassMethodIntOverriddenOrHidden = derivedClassMethodParams.OverriddenOrHiddenMembers;
            Assert.False(derivedClassMethodIntOverriddenOrHidden.HiddenMembers.Any());
            Assert.Equal(2, derivedClassMethodIntOverriddenOrHidden.OverriddenMembers.Length);
            Assert.Equal(3, derivedClassMethodIntOverriddenOrHidden.RuntimeOverriddenMembers.Length);

            var derivedClassPropertyOverriddenOrHidden = derivedClassProperty.OverriddenOrHiddenMembers;
            Assert.False(derivedClassPropertyOverriddenOrHidden.HiddenMembers.Any());
            Assert.Equal(1, derivedClassPropertyOverriddenOrHidden.RuntimeOverriddenMembers.Length);
            Assert.Equal(1, derivedClassPropertyOverriddenOrHidden.OverriddenMembers.Length);

            Assert.Null(baseClassMethod1.OverriddenMethod);
            Assert.Null(baseClassMethod2.OverriddenMethod);
            Assert.Null(baseClassMethod3.OverriddenMethod);
            Assert.Null(baseClassProperty.OverriddenProperty);
            Assert.Null(derivedClassMethod.OverriddenMethod);

            Assert.NotNull(derivedClassMethodParams.OverriddenMethod);
            Assert.NotNull(derivedClassProperty.OverriddenProperty);
        }

        [Fact]
        public void TestClassHiddenOverrides()
        {
            var text1 = @"
public class DefiningClass
{
    public virtual void Method1() { }
    public virtual void Method2() { }
    public virtual int Property1 { get; set; }
    public virtual int Property2 { get; set; }
}
";
            var text2 = @"
public class HidingClass : DefiningClass
{
    public new int Method1;
    public new void Method2() { }
    public new int Property1;
    public new int Property2 { get; set; }
}
";
            var text3 = @"
class OverridingClass : HidingClass
{
    public override void Method1() { } //blocked by non-method
    public override void Method2() { } //blocked by non-virtual method
    public override int Property1 { get; set; } //blocked by non-property
    public override int Property2 { get; set; } //blocked by non-virtual property
}
";

            var comp1 = CreateCompilation(text1);
            var comp1ref = new CSharpCompilationReference(comp1);
            var refs = new System.Collections.Generic.List<MetadataReference>() { comp1ref };

            var comp2 = CreateCompilation(text2, references: refs, assemblyName: "Test2");
            var comp2ref = new CSharpCompilationReference(comp2);

            refs.Add(comp2ref);
            var comp = CreateCompilation(text3, refs, assemblyName: "Test3");

            var global = comp.GlobalNamespace;

            var definingClass = (NamedTypeSymbol)global.GetMembers("DefiningClass").Single();
            var hidingClass = (NamedTypeSymbol)global.GetMembers("HidingClass").Single();
            var overridingClass = (NamedTypeSymbol)global.GetMembers("OverridingClass").Single();

            var definingClassMethod1 = (MethodSymbol)definingClass.GetMembers("Method1").Single();
            var definingClassMethod2 = (MethodSymbol)definingClass.GetMembers("Method2").Single();
            var definingClassProperty1 = (PropertySymbol)definingClass.GetMembers("Property1").Single();
            var definingClassProperty2 = (PropertySymbol)definingClass.GetMembers("Property2").Single();

            var hidingClassMethod1 = (FieldSymbol)hidingClass.GetMembers("Method1").Single();
            var hidingClassMethod2 = (MethodSymbol)hidingClass.GetMembers("Method2").Single();
            var hidingClassProperty1 = (FieldSymbol)hidingClass.GetMembers("Property1").Single();
            var hidingClassProperty2 = (PropertySymbol)hidingClass.GetMembers("Property2").Single();

            var overridingClassMethod1 = (MethodSymbol)overridingClass.GetMembers("Method1").Single();
            var overridingClassMethod2 = (MethodSymbol)overridingClass.GetMembers("Method2").Single();
            var overridingClassProperty1 = (PropertySymbol)overridingClass.GetMembers("Property1").Single();
            var overridingClassProperty2 = (PropertySymbol)overridingClass.GetMembers("Property2").Single();

            var overridingClassMethod1OverriddenOrHidden = overridingClassMethod1.OverriddenOrHiddenMembers;
            Assert.False(overridingClassMethod1OverriddenOrHidden.OverriddenMembers.Any());
            Assert.False(overridingClassMethod1OverriddenOrHidden.RuntimeOverriddenMembers.Any());
            Assert.Same(hidingClassMethod1, overridingClassMethod1OverriddenOrHidden.HiddenMembers.Single());
            Assert.Null(overridingClassMethod1.OverriddenMethod);

            //counts as overriding even though the overridden method isn't virtual - we'll check for that later
            var overridingClassMethod2OverriddenOrHidden = overridingClassMethod2.OverriddenOrHiddenMembers;
            Assert.False(overridingClassMethod2OverriddenOrHidden.HiddenMembers.Any());
            Assert.Same(hidingClassMethod2, overridingClassMethod2OverriddenOrHidden.OverriddenMembers.Single());
            Assert.Same(hidingClassMethod2, overridingClassMethod2OverriddenOrHidden.RuntimeOverriddenMembers.Single());
            Assert.Null(overridingClassMethod2.OverriddenMethod);

            var overridingClassProperty1OverriddenOrHidden = overridingClassProperty1.OverriddenOrHiddenMembers;
            Assert.False(overridingClassProperty1OverriddenOrHidden.OverriddenMembers.Any());
            Assert.False(overridingClassProperty1OverriddenOrHidden.RuntimeOverriddenMembers.Any());
            Assert.Null(overridingClassProperty1.OverriddenProperty);

            //counts as overriding even though the overridden property isn't virtual - we'll check for that later
            var overridingClassProperty2OverriddenOrHidden = overridingClassProperty2.OverriddenOrHiddenMembers;
            Assert.False(overridingClassProperty2OverriddenOrHidden.HiddenMembers.Any());
            Assert.Same(hidingClassProperty2, overridingClassProperty2OverriddenOrHidden.OverriddenMembers.Single());
            Assert.Same(hidingClassProperty2, overridingClassProperty2OverriddenOrHidden.RuntimeOverriddenMembers.Single());
            Assert.Null(overridingClassProperty2.OverriddenProperty);
        }

        [Fact]
        public void TestNonImplementedAbstractMembers()
        {
            // Tests: 
            // Test error when not all abstract members have been overridden in derived type

            var text = @"
abstract class Base<T, U>
{
    public abstract T Property { get; set; }
    public virtual void Method(T x, U y) { }
    public abstract ref T RefProperty { get; }
}

class Base2<A, B> : Base<A, B>
{
    A field = default(A);
    public override A Property { set { } }
    public override ref A RefProperty { get { return ref field; } }
}

abstract class Base3<T, U> : Base2<T, U>
{
    public override abstract T Property { set; }
    public abstract override void Method(T x, U y);
}

class Base4<U, V> : Base3<U, V>
{
    public override U Property { set { } }
}";
            CreateCompilationWithMscorlib45(text).VerifyDiagnostics(
                Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "Base2").WithArguments("Base2<A, B>", "Base<A, B>.Property.get"),
                Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "Base4").WithArguments("Base4<U, V>", "Base3<U, V>.Method(U, V)"));
        }

        [Fact]
        public void TestNonImplementedAbstractMembers2()
        {
            // Tests: 
            // Test error when not all abstract members from grandparent types have been overridden in derived type
            // Use base class where abstract members are declared in different partial parts of the same type

            var text = @"
abstract partial class Base
{
    public abstract int Property { get; set; }
}

abstract partial class Base
{
    public abstract void Method(int x, long y);
}

abstract partial class Base2
{
    public abstract void Method(int x);
}

abstract partial class Base2 : Base
{
    public override int Property { set { } }
}

abstract class Base3 : Base2
{
    public override abstract int Property { set; }
    public abstract override void Method(int x, long y);
}

class Base4 : Base3
{
    public override int Property { set { } }
}";
            CreateCompilation(text).VerifyDiagnostics(
                Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "Base4").WithArguments("Base4", "Base3.Method(int, long)"),
                Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "Base4").WithArguments("Base4", "Base2.Method(int)"),
                Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "Base4").WithArguments("Base4", "Base.Property.get"));
        }

        /// <summary>
        /// Layout:
        /// E : D : C : B : A
        /// All have virtual Method1 and Method2 with the same signatures (modulo custom modifiers)
        /// E, from source, has no custom modifiers
        /// D has 2 custom modifiers
        /// C has 1 custom modifier
        /// B has 2 custom modifiers, but not the same as D
        /// A has 1 custom modifier for Method1, but not the same as C, and 0 custom modifiers for Method2
        /// </summary>
        /// <remarks>
        /// ACASEY: When I initially wrote this test, I had the order of the tie-breakers wrong because I missed
        /// an exit condition in CSemanticChecker::FindSymHiddenByMethPropAgg.  Preferring more-derived types is
        /// a more important tie-breaker than preferring fewer custom modifiers.  Unfortunately, the correct rules
        /// make this test less comprehensive - no tie breaking occurs in practice, since we stop searching after
        /// finding candidates in D.  I updated the test, rather than deleting it, as a record of the correct
        /// behavior in this apparently complicated scenario.
        /// </remarks>
        [Fact]
        public void TestCustomModifierOverride()
        {
            var text = @"
class CustomModifierOverridingE : CustomModifierOverridingD
{
    public override void Method1(int[] x) { }
    public override void Method2(int[] x) { }
}
";
            var ilAssemblyReference = TestReferences.SymbolsTests.CustomModifiers.Modifiers.dll;

            var comp = CreateCompilation(text, new MetadataReference[] { ilAssemblyReference });
            var global = comp.GlobalNamespace;

            Assert.False(comp.GetDiagnostics().Any());

            //IL
            var classA = (NamedTypeSymbol)global.GetTypeMembers("CustomModifierOverridingA").Single();
            var classB = (NamedTypeSymbol)global.GetTypeMembers("CustomModifierOverridingB").Single();
            var classC = (NamedTypeSymbol)global.GetTypeMembers("CustomModifierOverridingC").Single();
            var classD = (NamedTypeSymbol)global.GetTypeMembers("CustomModifierOverridingD").Single();

            var classAMethod1 = (MethodSymbol)classA.GetMembers("Method1").Single();
            var classAMethod2 = (MethodSymbol)classA.GetMembers("Method2").Single();
            var classBMethod1 = (MethodSymbol)classB.GetMembers("Method1").Single();
            var classBMethod2 = (MethodSymbol)classB.GetMembers("Method2").Single();
            var classCMethod1 = (MethodSymbol)classC.GetMembers("Method1").Single();
            var classCMethod2 = (MethodSymbol)classC.GetMembers("Method2").Single();
            var classDMethod1 = (MethodSymbol)classD.GetMembers("Method1").Single();
            var classDMethod2 = (MethodSymbol)classD.GetMembers("Method2").Single();

            Assert.Same(OverriddenOrHiddenMembersResult.Empty, classAMethod1.OverriddenOrHiddenMembers);
            Assert.Same(OverriddenOrHiddenMembersResult.Empty, classAMethod2.OverriddenOrHiddenMembers);
            Assert.Same(OverriddenOrHiddenMembersResult.Empty, classBMethod1.OverriddenOrHiddenMembers);
            Assert.Same(OverriddenOrHiddenMembersResult.Empty, classBMethod2.OverriddenOrHiddenMembers);
            Assert.Same(OverriddenOrHiddenMembersResult.Empty, classCMethod1.OverriddenOrHiddenMembers);
            Assert.Same(OverriddenOrHiddenMembersResult.Empty, classCMethod2.OverriddenOrHiddenMembers);
            Assert.Same(OverriddenOrHiddenMembersResult.Empty, classDMethod1.OverriddenOrHiddenMembers);
            Assert.Same(OverriddenOrHiddenMembersResult.Empty, classDMethod2.OverriddenOrHiddenMembers);

            Assert.Null(classAMethod1.OverriddenMethod);
            Assert.Null(classAMethod2.OverriddenMethod);
            Assert.Null(classBMethod1.OverriddenMethod);
            Assert.Null(classBMethod2.OverriddenMethod);
            Assert.Null(classCMethod1.OverriddenMethod);
            Assert.Null(classCMethod2.OverriddenMethod);
            Assert.Null(classDMethod1.OverriddenMethod);
            Assert.Null(classDMethod2.OverriddenMethod);

            //Source
            var classE = (NamedTypeSymbol)global.GetTypeMembers("CustomModifierOverridingE").Single();

            var classEMethod1 = (MethodSymbol)classE.GetMembers("Method1").Single();
            var classEMethod2 = (MethodSymbol)classE.GetMembers("Method2").Single();

            //no match, so apply tie breakers:
            // 1) prefer more derived (leaves classDMethod1)
            // [2) prefer fewer custom modifiers]
            // [3) prefer first in GetMembers order]
            var classEMethod1OverriddenOrHiddenMembers = classEMethod1.OverriddenOrHiddenMembers;
            Assert.False(classEMethod1OverriddenOrHiddenMembers.HiddenMembers.Any());
            Assert.Same(classDMethod1, classEMethod1OverriddenOrHiddenMembers.OverriddenMembers.Single());
            Assert.Same(classDMethod1, classEMethod1OverriddenOrHiddenMembers.RuntimeOverriddenMembers.Single());

            //no match, so apply tie breakers:
            // 1) prefer more derived (leaves classDMethod2)
            // [2) prefer fewer custom modifiers]
            // [3) prefer first in GetMembers order]
            var classEMethod2OverriddenOrHiddenMembers = classEMethod2.OverriddenOrHiddenMembers;
            Assert.False(classEMethod2OverriddenOrHiddenMembers.HiddenMembers.Any());
            Assert.Same(classDMethod2, classEMethod2OverriddenOrHiddenMembers.OverriddenMembers.Single());
            Assert.Same(classDMethod2, classEMethod2OverriddenOrHiddenMembers.RuntimeOverriddenMembers.Single());
        }

        /// <summary>
        /// Choose candidate with fewer custom modifiers.
        /// </summary>
        [Fact]
        public void TestCustomModifierTieBreak1()
        {
            var il = @"
.class public auto ansi beforefieldinit Base
       extends [mscorlib]System.Object
{
  .method public hidebysig newslot virtual 
          instance void  Method(int32[] modopt([mscorlib]System.Int32) x) cil managed
  {
    ret
  }
  .method public hidebysig newslot virtual 
          instance void  Method(int32[] modopt([mscorlib]System.Int32) modopt([mscorlib]System.Int32) x) cil managed
  {
    ret
  }

  .method public hidebysig specialname rtspecialname 
          instance void  .ctor() cil managed
  {
    ldarg.0
    call       instance void [mscorlib]System.Object::.ctor()
    ret
  }

} // end of class Base
";

            var csharp = @"
class Derived : Base 
{
    public override void Method(int[] x) { }
}
";

            var comp = CreateCompilationWithILAndMscorlib40(csharp, il);
            comp.VerifyDiagnostics();

            var global = comp.GlobalNamespace;
            var baseType = global.GetMember<NamedTypeSymbol>("Base");
            var derivedType = global.GetMember<NamedTypeSymbol>("Derived");

            var baseMethod1 = baseType.GetMembers("Method").OfType<MethodSymbol>().Single(m => m.CustomModifierCount() == 1);
            var baseMethod2 = baseType.GetMembers("Method").OfType<MethodSymbol>().Single(m => m.CustomModifierCount() == 1);

            var derivedMethod = derivedType.GetMember<MethodSymbol>("Method");

            var overriddenOrHidden = derivedMethod.OverriddenOrHiddenMembers;
            Assert.Equal(baseMethod1, overriddenOrHidden.OverriddenMembers.Single());
            Assert.Equal(baseMethod1, overriddenOrHidden.RuntimeOverriddenMembers.Single());
            Assert.Equal(0, overriddenOrHidden.HiddenMembers.Length);
        }

        /// <summary>
        /// Choose "first" candidate if custom modifier counts match.
        /// </summary>
        [Fact]
        public void TestCustomModifierTieBreak2()
        {
            var il = @"
.class public auto ansi beforefieldinit Base
       extends [mscorlib]System.Object
{
  .method public hidebysig newslot virtual 
          instance void  Method1(int32[] modopt([mscorlib]System.Int32) x) cil managed
  {
    ret
  }
  .method public hidebysig newslot virtual 
          instance void  Method1(int32[] modopt([mscorlib]System.Int64) x) cil managed
  {
    ret
  }

  // Same as Method1, but order of overloads is reversed.
  .method public hidebysig newslot virtual 
          instance void  Method2(int32[] modopt([mscorlib]System.Int64) x) cil managed
  {
    ret
  }
  .method public hidebysig newslot virtual 
          instance void  Method2(int32[] modopt([mscorlib]System.Int32) x) cil managed
  {
    ret
  }

  .method public hidebysig specialname rtspecialname 
          instance void  .ctor() cil managed
  {
    ldarg.0
    call       instance void [mscorlib]System.Object::.ctor()
    ret
  }

} // end of class Base
";

            var csharp = @"
class Derived : Base 
{
    public override void Method1(int[] x) { }
    public override void Method2(int[] x) { }
}
";

            var comp = CreateCompilationWithILAndMscorlib40(csharp, il);
            comp.VerifyDiagnostics();

            var global = comp.GlobalNamespace;
            var baseType = global.GetMember<NamedTypeSymbol>("Base");
            var derivedType = global.GetMember<NamedTypeSymbol>("Derived");

            var firstBaseMethod1 = baseType.GetMembers("Method1").OfType<MethodSymbol>().First();
            var firstBaseMethod2 = baseType.GetMembers("Method2").OfType<MethodSymbol>().First();

            var derivedMethod1 = derivedType.GetMember<MethodSymbol>("Method1");
            var derivedMethod2 = derivedType.GetMember<MethodSymbol>("Method2");

            var overriddenOrHidden1 = derivedMethod1.OverriddenOrHiddenMembers;
            Assert.Equal(firstBaseMethod1, overriddenOrHidden1.OverriddenMembers.Single());
            Assert.Equal(firstBaseMethod1, overriddenOrHidden1.RuntimeOverriddenMembers.Single());
            Assert.Equal(0, overriddenOrHidden1.HiddenMembers.Length);

            var overriddenOrHidden2 = derivedMethod2.OverriddenOrHiddenMembers;
            Assert.Equal(firstBaseMethod2, overriddenOrHidden2.OverriddenMembers.Single());
            Assert.Equal(firstBaseMethod2, overriddenOrHidden2.RuntimeOverriddenMembers.Single());
            Assert.Equal(0, overriddenOrHidden2.HiddenMembers.Length);
        }

        [Fact]
        public void HideReadOnlyPropertyWithWriteOnlyProperty()
        {
            var text = @"
public class TestClass1
{
    public int P1 { get { return 0;} }
}
public class TestClass2 : TestClass1
{
    public new int P1 { set { } }
}
class Program
{
    static void Main(string[] args)
    {
        TestClass2 c2 = new TestClass2();
        int i = c2.P1;
        c2.P1 = i;
    }
}
";
            CreateCompilation(text)
                .VerifyDiagnostics(Diagnostic(ErrorCode.ERR_PropertyLacksGet, "c2.P1").WithArguments("TestClass2.P1"));
        }

        [Fact]
        public void HidePublicPropertyWithPrivateProperty()
        {
            var text = @"
public class TestClass1
{
    public int P1 { get; set; }
}
public class TestClass2 : TestClass1
{
    private new int P1 { set { } }
}
class Program
{
    static void Main(string[] args)
    {
        TestClass1 c1 = new TestClass2();
        c1.P1 = 0;
    }
}
";
            var comp = CreateCompilation(text);
            Assert.Empty(comp.GetDiagnostics());
        }

        [Fact]
        public void OverrideAccessorOnly()
        {
            var text = @"
public class Base
{
    public virtual long Property1 { get; set; }
}

public class Derived1 : Base
{
    public override long Property1 { get { return 0; } }
}
";
            var comp = CreateCompilation(text);
            Assert.Empty(comp.GetDiagnostics());
        }

        [Fact]
        public void TestOverrideSealNotVisibleMemberMetadataErr()
        {
            #region "Src"
            var text1 = @"
using Metadata;

public class CSClass : Metadata.VBClass02
{
    // Seal
    public override void Sub01(B p1, A p2)
    {
    }
    // ref
    protected override void Sub01(B p1, B p2)
    {
    }
    // not visible
    internal override void Sub01(params B[] p1)
    {
    }
}
";
            #endregion

            var comp = CreateCompilation(
                text1,
                references: new[] { TestReferences.MetadataTests.InterfaceAndClass.VBClasses02 },
                assemblyName: "OHI_OverrideSealNotVisibleMember001",
                options: TestOptions.ReleaseDll);

            comp.VerifyDiagnostics(
                Diagnostic(ErrorCode.ERR_CantOverrideSealed, "Sub01").WithArguments("CSClass.Sub01(Metadata.B, Metadata.A)", "Metadata.VBClass02.Sub01(Metadata.B, Metadata.A)").WithLocation(7, 26), // CS0239
                Diagnostic(ErrorCode.ERR_OverrideNotExpected, "Sub01").WithArguments("CSClass.Sub01(Metadata.B, Metadata.B)").WithLocation(11, 29), // CS0115
                Diagnostic(ErrorCode.ERR_OverrideNotExpected, "Sub01").WithArguments("CSClass.Sub01(params Metadata.B[])").WithLocation(15, 28) // CS0115
            );
        }

        [Fact]
        public void TestAccessUnqualifiedNestedTypeMetadataErr()
        {
            #region "Src"
            var text1 = @"
class CSClass : VBIMeth02Impl, IMeth02, IMeth03
{
    INested n; // CS0246
    public void M(INested nested)  // CS0246
    {
        nested.NestedSub(128);
    }
}
class CSHide : VBIMeth02Impl, IMeth02, IMeth03
{
    internal enum INested { One, Two, Three }
    INested n; // OK
    internal void M(INested nested) // OK
    {
    }
}
";
            #endregion

            var comp = CreateCompilation(
                text1,
                references: new[]
                {
                    TestReferences.MetadataTests.InterfaceAndClass.VBInterfaces01,
                    TestReferences.MetadataTests.InterfaceAndClass.VBClasses01
                },
                assemblyName: "OHI_AccessUnqualifiedNestedType001",
                options: TestOptions.ReleaseDll);

            comp.VerifyDiagnostics(
                // (5,19): error CS0246: The type or namespace name 'INested' could not be found (are you missing a using directive or an assembly reference?)
                //     public void M(INested nested)  // CS0246
                Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "INested").WithArguments("INested"),
                // (4,5): error CS0246: The type or namespace name 'INested' could not be found (are you missing a using directive or an assembly reference?)
                //     INested n; // CS0246
                Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "INested").WithArguments("INested"),
                // (4,13): warning CS0169: The field 'CSClass.n' is never used
                //     INested n; // CS0246
                Diagnostic(ErrorCode.WRN_UnreferencedField, "n").WithArguments("CSClass.n"),
                // (13,13): warning CS0169: The field 'CSHide.n' is never used
                //     INested n; // OK
                Diagnostic(ErrorCode.WRN_UnreferencedField, "n").WithArguments("CSHide.n"));
        }

        [WorkItem(543263, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543263")]
        [Fact]
        public void TestMixedPropertyAccessorModifiers_EmptyAbstract()
        {
            var text1 = @"
abstract class Derived : AccessorModifierMismatch
{
    // Not overriding anything.
}
";
            var refs = new MetadataReference[] { TestReferences.SymbolsTests.Properties };
            CreateCompilation(text1, references: refs, options: TestOptions.ReleaseDll).VerifyDiagnostics();
        }

        [WorkItem(543263, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543263")]
        [Fact]
        public void TestMixedPropertyAccessorModifiers_EmptyConcrete()
        {
            var text1 = @"
class Derived : AccessorModifierMismatch
{
    // Not overriding anything.
}
";
            var refs = new MetadataReference[] { TestReferences.SymbolsTests.Properties };
            CreateCompilation(text1, references: refs, options: TestOptions.ReleaseDll).VerifyDiagnostics(
                // (2,7): error CS0534: 'Derived' does not implement inherited abstract member 'AccessorModifierMismatch.NoneAbstract.set'
                // class Derived : AccessorModifierMismatch
                Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "Derived").WithArguments("Derived", "AccessorModifierMismatch.NoneAbstract.set"),
                // (2,7): error CS0534: 'Derived' does not implement inherited abstract member 'AccessorModifierMismatch.AbstractNone.get'
                // class Derived : AccessorModifierMismatch
                Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "Derived").WithArguments("Derived", "AccessorModifierMismatch.AbstractNone.get"));
        }

        [WorkItem(543263, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543263")]
        [Fact]
        public void TestMixedPropertyAccessorModifiers_OverrideGetters()
        {
            var text1 = @"
class Derived : AccessorModifierMismatch // CS0534 (didn't implement AbstractAbstract.set)
{
    public override int NoneNone { get { return 0; } } // CS0506 (not virtual)
    public override int NoneAbstract { get { return 0; } } // CS0506 (not virtual)
    public override int NoneVirtual { get { return 0; } } // CS0506 (not virtual)
    public override int NoneOverride { get { return 0; } } // CS1545 (bogus)
    public override int NoneSealed { get { return 0; } } // CS1545 (bogus)

    public override int AbstractNone { get { return 0; } }
    public override int AbstractAbstract { get { return 0; } }
    public override int AbstractVirtual { get { return 0; } }
    public override int AbstractOverride { get { return 0; } } // CS1545 (bogus)
    public override int AbstractSealed { get { return 0; } } // CS1545 (bogus)

    public override int VirtualNone { get { return 0; } }
    public override int VirtualAbstract { get { return 0; } }
    public override int VirtualVirtual { get { return 0; } }
    public override int VirtualOverride { get { return 0; } } // CS1545 (bogus)
    public override int VirtualSealed { get { return 0; } } // CS1545 (bogus)

    public override int OverrideNone { get { return 0; } } // CS1545 (bogus)
    public override int OverrideAbstract { get { return 0; } } // CS1545 (bogus)
    public override int OverrideVirtual { get { return 0; } } // CS1545 (bogus)
    public override int OverrideOverride { get { return 0; } }
    public override int OverrideSealed { get { return 0; } } // CS1545 (bogus)

    public override int SealedNone { get { return 0; } } // CS1545 (bogus)
    public override int SealedAbstract { get { return 0; } } // CS1545 (bogus)
    public override int SealedVirtual { get { return 0; } } // CS1545 (bogus)
    public override int SealedOverride { get { return 0; } } // CS1545 (bogus)
    public override int SealedSealed { get { return 0; } } // CS0239 (sealed)
}
";
            var refs = new MetadataReference[] { TestReferences.SymbolsTests.Properties };
            CreateCompilation(text1, references: refs, options: TestOptions.ReleaseDll).VerifyDiagnostics(
                // (4,25): error CS0506: 'Derived.NoneNone': cannot override inherited member 'AccessorModifierMismatch.NoneNone' because it is not marked virtual, abstract, or override
                //     public override int NoneNone { get { return 0; } } // CS0506 (not virtual)
                Diagnostic(ErrorCode.ERR_CantOverrideNonVirtual, "NoneNone").WithArguments("Derived.NoneNone", "AccessorModifierMismatch.NoneNone"),
                // (5,40): error CS0506: 'Derived.NoneAbstract.get': cannot override inherited member 'AccessorModifierMismatch.NoneNone.get' because it is not marked virtual, abstract, or override
                //     public override int NoneAbstract { get { return 0; } } // CS0506 (not virtual)
                Diagnostic(ErrorCode.ERR_CantOverrideNonVirtual, "get").WithArguments("Derived.NoneAbstract.get", "AccessorModifierMismatch.NoneNone.get"),
                // (6,39): error CS0506: 'Derived.NoneVirtual.get': cannot override inherited member 'AccessorModifierMismatch.NoneNone.get' because it is not marked virtual, abstract, or override
                //     public override int NoneVirtual { get { return 0; } } // CS0506 (not virtual)
                Diagnostic(ErrorCode.ERR_CantOverrideNonVirtual, "get").WithArguments("Derived.NoneVirtual.get", "AccessorModifierMismatch.NoneNone.get"),
                // (7,25): error CS0569: 'Derived.NoneOverride': cannot override 'AccessorModifierMismatch.NoneOverride' because it is not supported by the language
                //     public override int NoneOverride { get { return 0; } } // CS1545 (bogus)
                Diagnostic(ErrorCode.ERR_CantOverrideBogusMethod, "NoneOverride").WithArguments("Derived.NoneOverride", "AccessorModifierMismatch.NoneOverride"),
                // (8,25): error CS0569: 'Derived.NoneSealed': cannot override 'AccessorModifierMismatch.NoneSealed' because it is not supported by the language
                //     public override int NoneSealed { get { return 0; } } // CS1545 (bogus)
                Diagnostic(ErrorCode.ERR_CantOverrideBogusMethod, "NoneSealed").WithArguments("Derived.NoneSealed", "AccessorModifierMismatch.NoneSealed"),
                // (13,25): error CS0569: 'Derived.AbstractOverride': cannot override 'AccessorModifierMismatch.AbstractOverride' because it is not supported by the language
                //     public override int AbstractOverride { get { return 0; } } // CS1545 (bogus)
                Diagnostic(ErrorCode.ERR_CantOverrideBogusMethod, "AbstractOverride").WithArguments("Derived.AbstractOverride", "AccessorModifierMismatch.AbstractOverride"),
                // (14,25): error CS0569: 'Derived.AbstractSealed': cannot override 'AccessorModifierMismatch.AbstractSealed' because it is not supported by the language
                //     public override int AbstractSealed { get { return 0; } } // CS1545 (bogus)
                Diagnostic(ErrorCode.ERR_CantOverrideBogusMethod, "AbstractSealed").WithArguments("Derived.AbstractSealed", "AccessorModifierMismatch.AbstractSealed"),
                // (19,25): error CS0569: 'Derived.VirtualOverride': cannot override 'AccessorModifierMismatch.VirtualOverride' because it is not supported by the language
                //     public override int VirtualOverride { get { return 0; } } // CS1545 (bogus)
                Diagnostic(ErrorCode.ERR_CantOverrideBogusMethod, "VirtualOverride").WithArguments("Derived.VirtualOverride", "AccessorModifierMismatch.VirtualOverride"),
                // (20,25): error CS0569: 'Derived.VirtualSealed': cannot override 'AccessorModifierMismatch.VirtualSealed' because it is not supported by the language
                //     public override int VirtualSealed { get { return 0; } } // CS1545 (bogus)
                Diagnostic(ErrorCode.ERR_CantOverrideBogusMethod, "VirtualSealed").WithArguments("Derived.VirtualSealed", "AccessorModifierMismatch.VirtualSealed"),
                // (22,25): error CS0569: 'Derived.OverrideNone': cannot override 'AccessorModifierMismatch.OverrideNone' because it is not supported by the language
                //     public override int OverrideNone { get { return 0; } } // CS1545 (bogus)
                Diagnostic(ErrorCode.ERR_CantOverrideBogusMethod, "OverrideNone").WithArguments("Derived.OverrideNone", "AccessorModifierMismatch.OverrideNone"),
                // (23,25): error CS0569: 'Derived.OverrideAbstract': cannot override 'AccessorModifierMismatch.OverrideAbstract' because it is not supported by the language
                //     public override int OverrideAbstract { get { return 0; } } // CS1545 (bogus)
                Diagnostic(ErrorCode.ERR_CantOverrideBogusMethod, "OverrideAbstract").WithArguments("Derived.OverrideAbstract", "AccessorModifierMismatch.OverrideAbstract"),
                // (24,25): error CS0569: 'Derived.OverrideVirtual': cannot override 'AccessorModifierMismatch.OverrideVirtual' because it is not supported by the language
                //     public override int OverrideVirtual { get { return 0; } } // CS1545 (bogus)
                Diagnostic(ErrorCode.ERR_CantOverrideBogusMethod, "OverrideVirtual").WithArguments("Derived.OverrideVirtual", "AccessorModifierMismatch.OverrideVirtual"),
                // (26,25): error CS0569: 'Derived.OverrideSealed': cannot override 'AccessorModifierMismatch.OverrideSealed' because it is not supported by the language
                //     public override int OverrideSealed { get { return 0; } } // CS1545 (bogus)
                Diagnostic(ErrorCode.ERR_CantOverrideBogusMethod, "OverrideSealed").WithArguments("Derived.OverrideSealed", "AccessorModifierMismatch.OverrideSealed"),
                // (28,25): error CS0569: 'Derived.SealedNone': cannot override 'AccessorModifierMismatch.SealedNone' because it is not supported by the language
                //     public override int SealedNone { get { return 0; } } // CS1545 (bogus)
                Diagnostic(ErrorCode.ERR_CantOverrideBogusMethod, "SealedNone").WithArguments("Derived.SealedNone", "AccessorModifierMismatch.SealedNone"),
                // (29,25): error CS0569: 'Derived.SealedAbstract': cannot override 'AccessorModifierMismatch.SealedAbstract' because it is not supported by the language
                //     public override int SealedAbstract { get { return 0; } } // CS1545 (bogus)
                Diagnostic(ErrorCode.ERR_CantOverrideBogusMethod, "SealedAbstract").WithArguments("Derived.SealedAbstract", "AccessorModifierMismatch.SealedAbstract"),
                // (30,25): error CS0569: 'Derived.SealedVirtual': cannot override 'AccessorModifierMismatch.SealedVirtual' because it is not supported by the language
                //     public override int SealedVirtual { get { return 0; } } // CS1545 (bogus)
                Diagnostic(ErrorCode.ERR_CantOverrideBogusMethod, "SealedVirtual").WithArguments("Derived.SealedVirtual", "AccessorModifierMismatch.SealedVirtual"),
                // (31,25): error CS0569: 'Derived.SealedOverride': cannot override 'AccessorModifierMismatch.SealedOverride' because it is not supported by the language
                //     public override int SealedOverride { get { return 0; } } // CS1545 (bogus)
                Diagnostic(ErrorCode.ERR_CantOverrideBogusMethod, "SealedOverride").WithArguments("Derived.SealedOverride", "AccessorModifierMismatch.SealedOverride"),
                // (32,25): error CS0239: 'Derived.SealedSealed': cannot override inherited member 'AccessorModifierMismatch.SealedSealed' because it is sealed
                //     public override int SealedSealed { get { return 0; } } // CS0239 (sealed)
                Diagnostic(ErrorCode.ERR_CantOverrideSealed, "SealedSealed").WithArguments("Derived.SealedSealed", "AccessorModifierMismatch.SealedSealed"),
                // (2,7): error CS0534: 'Derived' does not implement inherited abstract member 'AccessorModifierMismatch.NoneAbstract.set'
                // class Derived : AccessorModifierMismatch // CS0534 (didn't implement AbstractAbstract.set)
                Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "Derived").WithArguments("Derived", "AccessorModifierMismatch.NoneAbstract.set"));
        }

        [WorkItem(543263, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543263")]
        [Fact]
        public void TestMixedPropertyAccessorModifiers_OverrideSetters()
        {
            var text1 = @"
class Derived : AccessorModifierMismatch // CS0534 (didn't implement AbstractAbstract.get)
{
    public override int NoneNone { set { } } // CS0506 (not virtual)
    public override int NoneAbstract { set { } }
    public override int NoneVirtual { set { } }
    public override int NoneOverride { set { } } // CS1545 (bogus)
    public override int NoneSealed { set { } } // CS1545 (bogus)

    public override int AbstractNone { set { } } // CS0506 (not virtual)
    public override int AbstractAbstract { set { } }
    public override int AbstractVirtual { set { } }
    public override int AbstractOverride { set { } } // CS1545 (bogus)
    public override int AbstractSealed { set { } } // CS1545 (bogus)

    public override int VirtualNone { set { } }
    public override int VirtualAbstract { set { } }
    public override int VirtualVirtual { set { } }
    public override int VirtualOverride { set { } } // CS1545 (bogus)
    public override int VirtualSealed { set { } } // CS1545 (bogus)

    public override int OverrideNone { set { } } // CS1545 (bogus)
    public override int OverrideAbstract { set { } } // CS1545 (bogus)
    public override int OverrideVirtual { set { } } // CS1545 (bogus)
    public override int OverrideOverride { set { } }
    public override int OverrideSealed { set { } } // CS1545 (bogus)

    public override int SealedNone { set { } } // CS1545 (bogus)
    public override int SealedAbstract { set { } } // CS1545 (bogus)
    public override int SealedVirtual { set { } } // CS1545 (bogus)
    public override int SealedOverride { set { } } // CS1545 (bogus)
    public override int SealedSealed { set { } } // CS0239 (sealed)
}
";
            var refs = new MetadataReference[] { TestReferences.SymbolsTests.Properties };
            CreateCompilation(text1, references: refs, options: TestOptions.ReleaseDll).VerifyDiagnostics(
                // (4,25): error CS0506: 'Derived.NoneNone': cannot override inherited member 'AccessorModifierMismatch.NoneNone' because it is not marked virtual, abstract, or override
                //     public override int NoneNone { set { } } // CS0506 (not virtual)
                Diagnostic(ErrorCode.ERR_CantOverrideNonVirtual, "NoneNone").WithArguments("Derived.NoneNone", "AccessorModifierMismatch.NoneNone"),
                // (7,25): error CS0569: 'Derived.NoneOverride': cannot override 'AccessorModifierMismatch.NoneOverride' because it is not supported by the language
                //     public override int NoneOverride { set { } } // CS1545 (bogus)
                Diagnostic(ErrorCode.ERR_CantOverrideBogusMethod, "NoneOverride").WithArguments("Derived.NoneOverride", "AccessorModifierMismatch.NoneOverride"),
                // (8,25): error CS0569: 'Derived.NoneSealed': cannot override 'AccessorModifierMismatch.NoneSealed' because it is not supported by the language
                //     public override int NoneSealed { set { } } // CS1545 (bogus)
                Diagnostic(ErrorCode.ERR_CantOverrideBogusMethod, "NoneSealed").WithArguments("Derived.NoneSealed", "AccessorModifierMismatch.NoneSealed"),
                // (10,40): error CS0506: 'Derived.AbstractNone.set': cannot override inherited member 'AccessorModifierMismatch.NoneNone.set' because it is not marked virtual, abstract, or override
                //     public override int AbstractNone { set { } } // CS0506 (not virtual)
                Diagnostic(ErrorCode.ERR_CantOverrideNonVirtual, "set").WithArguments("Derived.AbstractNone.set", "AccessorModifierMismatch.NoneNone.set"),
                // (13,25): error CS0569: 'Derived.AbstractOverride': cannot override 'AccessorModifierMismatch.AbstractOverride' because it is not supported by the language
                //     public override int AbstractOverride { set { } } // CS1545 (bogus)
                Diagnostic(ErrorCode.ERR_CantOverrideBogusMethod, "AbstractOverride").WithArguments("Derived.AbstractOverride", "AccessorModifierMismatch.AbstractOverride"),
                // (14,25): error CS0569: 'Derived.AbstractSealed': cannot override 'AccessorModifierMismatch.AbstractSealed' because it is not supported by the language
                //     public override int AbstractSealed { set { } } // CS1545 (bogus)
                Diagnostic(ErrorCode.ERR_CantOverrideBogusMethod, "AbstractSealed").WithArguments("Derived.AbstractSealed", "AccessorModifierMismatch.AbstractSealed"),
                // (16,39): error CS0506: 'Derived.VirtualNone.set': cannot override inherited member 'AccessorModifierMismatch.NoneNone.set' because it is not marked virtual, abstract, or override
                //     public override int VirtualNone { set { } }
                Diagnostic(ErrorCode.ERR_CantOverrideNonVirtual, "set").WithArguments("Derived.VirtualNone.set", "AccessorModifierMismatch.NoneNone.set"),
                // (19,25): error CS0569: 'Derived.VirtualOverride': cannot override 'AccessorModifierMismatch.VirtualOverride' because it is not supported by the language
                //     public override int VirtualOverride { set { } } // CS1545 (bogus)
                Diagnostic(ErrorCode.ERR_CantOverrideBogusMethod, "VirtualOverride").WithArguments("Derived.VirtualOverride", "AccessorModifierMismatch.VirtualOverride"),
                // (20,25): error CS0569: 'Derived.VirtualSealed': cannot override 'AccessorModifierMismatch.VirtualSealed' because it is not supported by the language
                //     public override int VirtualSealed { set { } } // CS1545 (bogus)
                Diagnostic(ErrorCode.ERR_CantOverrideBogusMethod, "VirtualSealed").WithArguments("Derived.VirtualSealed", "AccessorModifierMismatch.VirtualSealed"),
                // (22,25): error CS0569: 'Derived.OverrideNone': cannot override 'AccessorModifierMismatch.OverrideNone' because it is not supported by the language
                //     public override int OverrideNone { set { } } // CS1545 (bogus)
                Diagnostic(ErrorCode.ERR_CantOverrideBogusMethod, "OverrideNone").WithArguments("Derived.OverrideNone", "AccessorModifierMismatch.OverrideNone"),
                // (23,25): error CS0569: 'Derived.OverrideAbstract': cannot override 'AccessorModifierMismatch.OverrideAbstract' because it is not supported by the language
                //     public override int OverrideAbstract { set { } } // CS1545 (bogus)
                Diagnostic(ErrorCode.ERR_CantOverrideBogusMethod, "OverrideAbstract").WithArguments("Derived.OverrideAbstract", "AccessorModifierMismatch.OverrideAbstract"),
                // (24,25): error CS0569: 'Derived.OverrideVirtual': cannot override 'AccessorModifierMismatch.OverrideVirtual' because it is not supported by the language
                //     public override int OverrideVirtual { set { } } // CS1545 (bogus)
                Diagnostic(ErrorCode.ERR_CantOverrideBogusMethod, "OverrideVirtual").WithArguments("Derived.OverrideVirtual", "AccessorModifierMismatch.OverrideVirtual"),
                // (26,25): error CS0569: 'Derived.OverrideSealed': cannot override 'AccessorModifierMismatch.OverrideSealed' because it is not supported by the language
                //     public override int OverrideSealed { set { } } // CS1545 (bogus)
                Diagnostic(ErrorCode.ERR_CantOverrideBogusMethod, "OverrideSealed").WithArguments("Derived.OverrideSealed", "AccessorModifierMismatch.OverrideSealed"),
                // (28,25): error CS0569: 'Derived.SealedNone': cannot override 'AccessorModifierMismatch.SealedNone' because it is not supported by the language
                //     public override int SealedNone { set { } } // CS1545 (bogus)
                Diagnostic(ErrorCode.ERR_CantOverrideBogusMethod, "SealedNone").WithArguments("Derived.SealedNone", "AccessorModifierMismatch.SealedNone"),
                // (29,25): error CS0569: 'Derived.SealedAbstract': cannot override 'AccessorModifierMismatch.SealedAbstract' because it is not supported by the language
                //     public override int SealedAbstract { set { } } // CS1545 (bogus)
                Diagnostic(ErrorCode.ERR_CantOverrideBogusMethod, "SealedAbstract").WithArguments("Derived.SealedAbstract", "AccessorModifierMismatch.SealedAbstract"),
                // (30,25): error CS0569: 'Derived.SealedVirtual': cannot override 'AccessorModifierMismatch.SealedVirtual' because it is not supported by the language
                //     public override int SealedVirtual { set { } } // CS1545 (bogus)
                Diagnostic(ErrorCode.ERR_CantOverrideBogusMethod, "SealedVirtual").WithArguments("Derived.SealedVirtual", "AccessorModifierMismatch.SealedVirtual"),
                // (31,25): error CS0569: 'Derived.SealedOverride': cannot override 'AccessorModifierMismatch.SealedOverride' because it is not supported by the language
                //     public override int SealedOverride { set { } } // CS1545 (bogus)
                Diagnostic(ErrorCode.ERR_CantOverrideBogusMethod, "SealedOverride").WithArguments("Derived.SealedOverride", "AccessorModifierMismatch.SealedOverride"),
                // (32,25): error CS0239: 'Derived.SealedSealed': cannot override inherited member 'AccessorModifierMismatch.SealedSealed' because it is sealed
                //     public override int SealedSealed { set { } } // CS0239 (sealed)
                Diagnostic(ErrorCode.ERR_CantOverrideSealed, "SealedSealed").WithArguments("Derived.SealedSealed", "AccessorModifierMismatch.SealedSealed"),
                // (2,7): error CS0534: 'Derived' does not implement inherited abstract member 'AccessorModifierMismatch.AbstractNone.get'
                // class Derived : AccessorModifierMismatch // CS0534 (didn't implement AbstractAbstract.get)
                Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "Derived").WithArguments("Derived", "AccessorModifierMismatch.AbstractNone.get"));
        }

        [WorkItem(543263, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543263")]
        [Fact]
        public void TestMixedPropertyAccessorModifiers_AbstractSealed()
        {
            var il = @"
.class public auto ansi beforefieldinit AccessorModifierMismatchBase
       extends [mscorlib]System.Object
{
  .method public hidebysig newslot virtual 
          instance void  SetSealed(int32 x) cil managed
  {
    ret
  }

  .method public hidebysig specialname rtspecialname 
          instance void  .ctor() cil managed
  {
    ldarg.0
    call       instance void [mscorlib]System.Object::.ctor()
    ret
  }
} // end of class AccessorModifierMismatchBase

.class public abstract auto ansi beforefieldinit AccessorModifierMismatch
       extends AccessorModifierMismatchBase
{
  .method public hidebysig newslot abstract virtual 
          instance int32  GetAbstract() cil managed
  {
  }

  .method public hidebysig virtual final instance void 
          SetSealed(int32 x) cil managed
  {
    ret
  }

  .property instance int32 AbstractSealed()
  {
    .get instance int32 AccessorModifierMismatch::GetAbstract()
    .set instance void AccessorModifierMismatch::SetSealed(int32)
  }

  .method family hidebysig specialname rtspecialname 
          instance void  .ctor() cil managed
  {
    ldarg.0
    call       instance void AccessorModifierMismatchBase::.ctor()
    ret
  }
} // end of class AccessorModifierMismatch
";

            var csharp = @"
class Derived : AccessorModifierMismatch
{
    // Override accessor as method since property is bogus.
    public override int GetAbstract() { return 0; }
}
";

            CreateCompilationWithILAndMscorlib40(csharp, il).VerifyDiagnostics();
        }

        [WorkItem(543263, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543263")]
        [Fact]
        public void TestMixedEventAccessorModifiers_EmptyAbstract()
        {
            var text1 = @"
abstract class Derived : AccessorModifierMismatch
{
    // Not overriding anything.
}
";
            var refs = new[] { TestReferences.SymbolsTests.Events };
            CreateCompilation(text1, references: refs, options: TestOptions.ReleaseDll).VerifyDiagnostics();
        }

        [WorkItem(543263, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543263")]
        [Fact]
        public void TestMixedEventAccessorModifiers_EmptyConcrete()
        {
            var text1 = @"
class Derived : AccessorModifierMismatch
{
    // Not overriding anything.
}
";
            var refs = new MetadataReference[] { TestReferences.SymbolsTests.Events };
            CreateCompilation(text1, references: refs, options: TestOptions.ReleaseDll).VerifyDiagnostics(
                // (2,7): error CS0534: 'Derived' does not implement inherited abstract member 'AccessorModifierMismatch.NoneAbstract.remove'
                // class Derived : AccessorModifierMismatch
                Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "Derived").WithArguments("Derived", "AccessorModifierMismatch.NoneAbstract.remove"),
                // (2,7): error CS0534: 'Derived' does not implement inherited abstract member 'AccessorModifierMismatch.AbstractNone.add'
                // class Derived : AccessorModifierMismatch
                Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "Derived").WithArguments("Derived", "AccessorModifierMismatch.AbstractNone.add"));
        }

        // NOTE: The behavior is quite different from the analogous property tests.
        [WorkItem(543263, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543263")]
        [Fact]
        public void TestMixedEventAccessorModifiers_OverrideAccessors()
        {
            var text1 = @"
class Derived : AccessorModifierMismatch
{
    public override event System.Action NoneNone { add { } remove { } } // CS0506 (not virtual)
    public override event System.Action NoneAbstract { add { } remove { } } // CS0506 (add not virtual)
    public override event System.Action NoneVirtual { add { } remove { } } // CS0506 (add not virtual)
    public override event System.Action NoneOverride { add { } remove { } } // CS0506 (add not virtual)
    public override event System.Action NoneSealed { add { } remove { } } // CS1545 (bogus)

    public override event System.Action AbstractNone { add { } remove { } } // CS0506 (remove not virtual)
    public override event System.Action AbstractAbstract { add { } remove { } }
    public override event System.Action AbstractVirtual { add { } remove { } }
    public override event System.Action AbstractOverride { add { } remove { } }
    public override event System.Action AbstractSealed { add { } remove { } } // CS1545 (bogus)

    public override event System.Action VirtualNone { add { } remove { } } // CS0506 (remove not virtual)
    public override event System.Action VirtualAbstract { add { } remove { } }
    public override event System.Action VirtualVirtual { add { } remove { } }
    public override event System.Action VirtualOverride { add { } remove { } }
    public override event System.Action VirtualSealed { add { } remove { } } // CS1545 (bogus)

    public override event System.Action OverrideNone { add { } remove { } } // CS0506 (remove not virtual)
    public override event System.Action OverrideAbstract { add { } remove { } }
    public override event System.Action OverrideVirtual { add { } remove { } }
    public override event System.Action OverrideOverride { add { } remove { } }
    public override event System.Action OverrideSealed { add { } remove { } } // CS1545 (bogus)

    public override event System.Action SealedNone { add { } remove { } } // CS1545 (bogus)
    public override event System.Action SealedAbstract { add { } remove { } } // CS1545 (bogus)
    public override event System.Action SealedVirtual { add { } remove { } } // CS1545 (bogus)
    public override event System.Action SealedOverride { add { } remove { } } // CS1545 (bogus)
    public override event System.Action SealedSealed { add { } remove { } } // CS0239 (sealed)
}
";
            // ACASEY: these are not exactly the errors that Dev10 produces, but they seem sensible.
            var refs = new MetadataReference[] { TestReferences.SymbolsTests.Events };
            CreateCompilation(text1, references: refs, options: TestOptions.ReleaseDll).VerifyDiagnostics(
                // (4,41): error CS0506: 'Derived.NoneNone': cannot override inherited member 'AccessorModifierMismatch.NoneNone' because it is not marked virtual, abstract, or override
                //     public override event System.Action NoneNone { add { } remove { } } // CS0506 (not virtual)
                Diagnostic(ErrorCode.ERR_CantOverrideNonVirtual, "NoneNone").WithArguments("Derived.NoneNone", "AccessorModifierMismatch.NoneNone"),
                // (5,56): error CS0506: 'Derived.NoneAbstract.add': cannot override inherited member 'AccessorModifierMismatch.NoneNone.add' because it is not marked virtual, abstract, or override
                //     public override event System.Action NoneAbstract { add { } remove { } } // CS0506 (add not virtual)
                Diagnostic(ErrorCode.ERR_CantOverrideNonVirtual, "add").WithArguments("Derived.NoneAbstract.add", "AccessorModifierMismatch.NoneNone.add"),
                // (6,55): error CS0506: 'Derived.NoneVirtual.add': cannot override inherited member 'AccessorModifierMismatch.NoneNone.add' because it is not marked virtual, abstract, or override
                //     public override event System.Action NoneVirtual { add { } remove { } } // CS0506 (add not virtual)
                Diagnostic(ErrorCode.ERR_CantOverrideNonVirtual, "add").WithArguments("Derived.NoneVirtual.add", "AccessorModifierMismatch.NoneNone.add"),
                // (7,56): error CS0506: 'Derived.NoneOverride.add': cannot override inherited member 'AccessorModifierMismatch.NoneNone.add' because it is not marked virtual, abstract, or override
                //     public override event System.Action NoneOverride { add { } remove { } } // CS0506 (add not virtual)
                Diagnostic(ErrorCode.ERR_CantOverrideNonVirtual, "add").WithArguments("Derived.NoneOverride.add", "AccessorModifierMismatch.NoneNone.add"),
                // (8,41): error CS0239: 'Derived.NoneSealed': cannot override inherited member 'AccessorModifierMismatch.NoneSealed' because it is sealed
                //     public override event System.Action NoneSealed { add { } remove { } } // CS1545 (bogus)
                Diagnostic(ErrorCode.ERR_CantOverrideSealed, "NoneSealed").WithArguments("Derived.NoneSealed", "AccessorModifierMismatch.NoneSealed"),

                // (10,64): error CS0506: 'Derived.AbstractNone.remove': cannot override inherited member 'AccessorModifierMismatch.NoneNone.remove' because it is not marked virtual, abstract, or override
                //     public override event System.Action AbstractNone { add { } remove { } } // CS0506 (remove not virtual)
                Diagnostic(ErrorCode.ERR_CantOverrideNonVirtual, "remove").WithArguments("Derived.AbstractNone.remove", "AccessorModifierMismatch.NoneNone.remove"),
                // (14,41): error CS0239: 'Derived.AbstractSealed': cannot override inherited member 'AccessorModifierMismatch.AbstractSealed' because it is sealed
                //     public override event System.Action AbstractSealed { add { } remove { } } // CS1545 (bogus)
                Diagnostic(ErrorCode.ERR_CantOverrideSealed, "AbstractSealed").WithArguments("Derived.AbstractSealed", "AccessorModifierMismatch.AbstractSealed"),

                // (16,63): error CS0506: 'Derived.VirtualNone.remove': cannot override inherited member 'AccessorModifierMismatch.NoneNone.remove' because it is not marked virtual, abstract, or override
                //     public override event System.Action VirtualNone { add { } remove { } } // CS0506 (remove not virtual)
                Diagnostic(ErrorCode.ERR_CantOverrideNonVirtual, "remove").WithArguments("Derived.VirtualNone.remove", "AccessorModifierMismatch.NoneNone.remove"),
                // (20,41): error CS0239: 'Derived.VirtualSealed': cannot override inherited member 'AccessorModifierMismatch.VirtualSealed' because it is sealed
                //     public override event System.Action VirtualSealed { add { } remove { } } // CS1545 (bogus)
                Diagnostic(ErrorCode.ERR_CantOverrideSealed, "VirtualSealed").WithArguments("Derived.VirtualSealed", "AccessorModifierMismatch.VirtualSealed"),

                // (22,64): error CS0506: 'Derived.OverrideNone.remove': cannot override inherited member 'AccessorModifierMismatch.NoneNone.remove' because it is not marked virtual, abstract, or override
                //     public override event System.Action OverrideNone { add { } remove { } } // CS0506 (remove not virtual)
                Diagnostic(ErrorCode.ERR_CantOverrideNonVirtual, "remove").WithArguments("Derived.OverrideNone.remove", "AccessorModifierMismatch.NoneNone.remove"),
                // (26,41): error CS0239: 'Derived.OverrideSealed': cannot override inherited member 'AccessorModifierMismatch.OverrideSealed' because it is sealed
                //     public override event System.Action OverrideSealed { add { } remove { } } // CS1545 (bogus)
                Diagnostic(ErrorCode.ERR_CantOverrideSealed, "OverrideSealed").WithArguments("Derived.OverrideSealed", "AccessorModifierMismatch.OverrideSealed"),

                // (28,41): error CS0239: 'Derived.SealedNone': cannot override inherited member 'AccessorModifierMismatch.SealedNone' because it is sealed
                //     public override event System.Action SealedNone { add { } remove { } } // CS1545 (bogus)
                Diagnostic(ErrorCode.ERR_CantOverrideSealed, "SealedNone").WithArguments("Derived.SealedNone", "AccessorModifierMismatch.SealedNone"),
                // (29,41): error CS0239: 'Derived.SealedAbstract': cannot override inherited member 'AccessorModifierMismatch.SealedAbstract' because it is sealed
                //     public override event System.Action SealedAbstract { add { } remove { } } // CS1545 (bogus)
                Diagnostic(ErrorCode.ERR_CantOverrideSealed, "SealedAbstract").WithArguments("Derived.SealedAbstract", "AccessorModifierMismatch.SealedAbstract"),
                // (30,41): error CS0239: 'Derived.SealedVirtual': cannot override inherited member 'AccessorModifierMismatch.SealedVirtual' because it is sealed
                //     public override event System.Action SealedVirtual { add { } remove { } } // CS1545 (bogus)
                Diagnostic(ErrorCode.ERR_CantOverrideSealed, "SealedVirtual").WithArguments("Derived.SealedVirtual", "AccessorModifierMismatch.SealedVirtual"),
                // (31,41): error CS0239: 'Derived.SealedOverride': cannot override inherited member 'AccessorModifierMismatch.SealedOverride' because it is sealed
                //     public override event System.Action SealedOverride { add { } remove { } } // CS1545 (bogus)
                Diagnostic(ErrorCode.ERR_CantOverrideSealed, "SealedOverride").WithArguments("Derived.SealedOverride", "AccessorModifierMismatch.SealedOverride"),
                // (32,41): error CS0239: 'Derived.SealedSealed': cannot override inherited member 'AccessorModifierMismatch.SealedSealed' because it is sealed
                //     public override event System.Action SealedSealed { add { } remove { } } // CS0239 (sealed)
                Diagnostic(ErrorCode.ERR_CantOverrideSealed, "SealedSealed").WithArguments("Derived.SealedSealed", "AccessorModifierMismatch.SealedSealed"));
        }

        [WorkItem(543263, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543263")]
        [Fact]
        public void TestMixedEventAccessorModifiers_AbstractSealed()
        {
            var il = @"
.class public auto ansi beforefieldinit AccessorModifierMismatchBase
       extends [mscorlib]System.Object
{
  .method public hidebysig newslot virtual 
          instance void  RemoveSealed(class [mscorlib]System.Action a) cil managed
  {
    ret
  }

  .method public hidebysig specialname rtspecialname 
          instance void  .ctor() cil managed
  {
    ldarg.0
    call       instance void [mscorlib]System.Object::.ctor()
    ret
  }
} // end of class AccessorModifierMismatchBase

.class public abstract auto ansi beforefieldinit AccessorModifierMismatch
       extends AccessorModifierMismatchBase
{
  .method public hidebysig newslot abstract virtual 
          instance void  AddAbstract(class [mscorlib]System.Action a) cil managed
  {
  }

  .method public hidebysig virtual final instance void 
          RemoveSealed(class [mscorlib]System.Action a) cil managed
  {
    ret
  }

  .event [mscorlib]System.Action AbstractSealed
  {
    .addon instance void AccessorModifierMismatch::AddAbstract(class [mscorlib]System.Action)
    .removeon instance void AccessorModifierMismatch::RemoveSealed(class [mscorlib]System.Action)
  }

  .method family hidebysig specialname rtspecialname 
          instance void  .ctor() cil managed
  {
    ldarg.0
    call       instance void AccessorModifierMismatchBase::.ctor()
    ret
  }
} // end of class AccessorModifierMismatch
";

            var csharp = @"
class Derived : AccessorModifierMismatch
{
    // Failed to implement AddAbstract
}
";
            CreateCompilationWithILAndMscorlib40(csharp, il).VerifyDiagnostics(
                // (2,7): error CS0534: 'Derived' does not implement inherited abstract member 'AccessorModifierMismatch.AbstractSealed.add'
                Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "Derived").WithArguments("Derived", "AccessorModifierMismatch.AbstractSealed.add"));

            csharp = @"
class Derived : AccessorModifierMismatch
{
    // Cannot override accessor as method since property is bogus.
    public override void AddAbstract(System.Action a) { }
}
";
            CreateCompilationWithILAndMscorlib40(csharp, il).VerifyDiagnostics(
                // (5,26): error CS0115: 'Derived.AddAbstract(System.Action)': no suitable method found to override
                Diagnostic(ErrorCode.ERR_OverrideNotExpected, "AddAbstract").WithArguments("Derived.AddAbstract(System.Action)"),
                // (2,7): error CS0534: 'Derived' does not implement inherited abstract member 'AccessorModifierMismatch.AbstractSealed.add'
                Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "Derived").WithArguments("Derived", "AccessorModifierMismatch.AbstractSealed.add"));

            csharp = @"
class Derived : AccessorModifierMismatch
{
    // Cannot override just one accessor (C# rule).
    public override event System.Action AbstractSealed { add { } }
}
";
            CreateCompilationWithILAndMscorlib40(csharp, il).VerifyDiagnostics(
                // (5,41): error CS0065: 'Derived.AbstractSealed': event property must have both add and remove accessors
                Diagnostic(ErrorCode.ERR_EventNeedsBothAccessors, "AbstractSealed").WithArguments("Derived.AbstractSealed"),
                // (5,41): error CS0239: 'Derived.AbstractSealed': cannot override inherited member 'AccessorModifierMismatch.AbstractSealed' because it is sealed
                Diagnostic(ErrorCode.ERR_CantOverrideSealed, "AbstractSealed").WithArguments("Derived.AbstractSealed", "AccessorModifierMismatch.AbstractSealed"));

            csharp = @"
class Derived : AccessorModifierMismatch
{
    // Cannot override sealed RemoveSealed.
    public override event System.Action AbstractSealed { add { } remove { } }
}
";
            CreateCompilationWithILAndMscorlib40(csharp, il).VerifyDiagnostics(
                // (5,41): error CS0239: 'Derived.AbstractSealed': cannot override inherited member 'AccessorModifierMismatch.AbstractSealed' because it is sealed
                Diagnostic(ErrorCode.ERR_CantOverrideSealed, "AbstractSealed").WithArguments("Derived.AbstractSealed", "AccessorModifierMismatch.AbstractSealed"));
        }

        #region "Regressions"

        [WorkItem(546834, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546834")]
        [Fact]
        public void PropertyHidingAccessor()
        {
            var text = @"
class Derived : Base
{
    public delegate void BogusDelegate();
    public event BogusDelegate set_Instance;

    public int get_Instance
    {
        get { return 0; }
    }

    public int var1
    { get;set; }

    public int var2
    { get;set; }

public void StartEvent()
    {
        if (set_Instance != null)
            set_Instance();
    }
}
public class Base
{
    public int Instance
    {
        get { return 0; }
        set { }
    }
    public int get_var1()
    {
        return 0;
    }
    public int get_var2
    { get;set; }
}
public class MainClass
{
    public static void Main() { }
}
";
            CreateCompilation(text).VerifyDiagnostics();
        }


        [WorkItem(539623, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539623")]
        [Fact]
        public void GenericTypeWithDiffTypeParamNotHideBase()
        {
            var text = @"namespace NS
{
    public class Base
    {
        public class Nested<T> { }
    }

    public class Derived : Base
    {
        public class Nested<T, U> { } // Roslyn warning CS0108
    }
}
namespace A
{
    public class Base<T>
    {
        public class Goo<U> { }

        public class Nested<U>
        {
            public static Goo<U> sFld = new Goo<U>();
        }
    }

    public class Derived<T> : Base<T>
    {
        public class Goo<U, V> { } // Roslyn warning CS0108

        public class Nested<U, V> // Roslyn warning CS0108
        {
            public static Goo<U, V> sFld = new Goo<U, V>();
        }
    }
}
";
            var comp = CreateCompilation(text);
            Assert.Equal(0, comp.GetDiagnostics().Count());
        }

        [Fact]
        public void HideAbstractReadOnlyPropertyWithAbstractWriteOnly()
        {
            var text = @"
abstract public class TestClass1
{
    public abstract int P2 { get; }
}
abstract public class TestClass2 : TestClass1
{
    public abstract new int P2 { set; }
}
public class TestClass3 : TestClass2
{
    int f1;
    public override int P2
    {
        get { return f1; }
        set { f1 = value; }
    }
}
";
            var comp = CreateCompilation(text);
            comp.VerifyDiagnostics(
                Diagnostic(ErrorCode.ERR_HidingAbstractMethod, "P2").WithArguments("TestClass2.P2", "TestClass1.P2"),
                Diagnostic(ErrorCode.ERR_NoGetToOverride, "get").WithArguments("TestClass3.P2.get", "TestClass2.P2"),
                Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "TestClass3").WithArguments("TestClass3", "TestClass1.P2.get"));
        }

        [WorkItem(540383, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540383")]
        [Fact]
        public void HideBaseImplementationWithPrivateProperty()
        {
            var text = @"
interface I1
{
    int Goo { get; set; }
}
class B1
{
    public int Goo { get { return 1; } set { } }
}
class B2 : B1, I1
{
    private new int Goo { get { return 1; } }
}
";
            var comp = CreateCompilation(text);
            comp.VerifyDiagnostics();

            var global = comp.GlobalNamespace;
            Assert.Equal(
                global.GetMember<NamedTypeSymbol>("B1").GetMember<PropertySymbol>("Goo"),
                global.GetMember<NamedTypeSymbol>("B2").FindImplementationForInterfaceMember(
                    global.GetMember<NamedTypeSymbol>("I1").GetMember<PropertySymbol>("Goo")));
        }

        [WorkItem(540383, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540383")]
        [Fact]
        public void HideBaseImplementationWithStaticProperty()
        {
            var text = @"
interface I1
{
    int Goo { get; set; }
}
class B1
{
    public int Goo { get { return 1; } set { } }
}
class B2 : B1, I1
{
    public static new int Goo { get { return 1; } }
}
";
            var comp = CreateCompilation(text);
            comp.VerifyDiagnostics();

            var global = comp.GlobalNamespace;
            Assert.Equal(
                global.GetMember<NamedTypeSymbol>("B1").GetMember<PropertySymbol>("Goo"),
                global.GetMember<NamedTypeSymbol>("B2").FindImplementationForInterfaceMember(
                    global.GetMember<NamedTypeSymbol>("I1").GetMember<PropertySymbol>("Goo")));
        }

        [WorkItem(540383, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540383")]
        [Fact]
        public void HideBaseImplementationWithWrongTypeProperty()
        {
            var text = @"
interface I1
{
    int Goo { get; set; }
}
class B1
{
    public int Goo { get { return 1; } set { } }
}
class B2 : B1, I1
{
    public new float Goo { get { return 1; } }
}
";
            var comp = CreateCompilation(text);
            comp.VerifyDiagnostics();

            var global = comp.GlobalNamespace;
            Assert.Equal(
                global.GetMember<NamedTypeSymbol>("B1").GetMember<PropertySymbol>("Goo"),
                global.GetMember<NamedTypeSymbol>("B2").FindImplementationForInterfaceMember(
                    global.GetMember<NamedTypeSymbol>("I1").GetMember<PropertySymbol>("Goo")));
        }

        [WorkItem(540383, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540383")]
        [Fact]
        public void HideInvalidBaseImplementationWithPrivateProperty()
        {
            var text = @"
interface I1
{
    int Goo { get; set; }
}
class B1
{
    public float Goo { get { return 1; } set { } }
}
class B2 : B1, I1
{
    private new int Goo { get { return 1; } }
}
";
            var comp = CreateCompilation(text);
            comp.VerifyDiagnostics(
                // (10,16): error CS0737: 'B2' does not implement interface member 'I1.Goo'. 'B2.Goo' cannot implement an interface member because it is not public.
                // class B2 : B1, I1
                Diagnostic(ErrorCode.ERR_CloseUnimplementedInterfaceMemberNotPublic, "I1").WithArguments("B2", "I1.Goo", "B2.Goo").WithLocation(10, 16));

            var global = comp.GlobalNamespace;
            Assert.Null(global.GetMember<NamedTypeSymbol>("B2").FindImplementationForInterfaceMember(
                    global.GetMember<NamedTypeSymbol>("I1").GetMember<PropertySymbol>("Goo")));
        }

        [WorkItem(540383, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540383")]
        [Fact]
        public void HideInvalidBaseImplementationWithStaticProperty()
        {
            var text = @"
interface I1
{
    int Goo { get; set; }
}
class B1
{
    public float Goo { get { return 1; } set { } }
}
class B2 : B1, I1
{
    public static new int Goo { get { return 1; } }
}
";
            var comp = CreateCompilation(text);
            comp.VerifyDiagnostics(
                // (10,16): error CS0736: 'B2' does not implement interface member 'I1.Goo'. 'B2.Goo' cannot implement an interface member because it is static.
                // class B2 : B1, I1
                Diagnostic(ErrorCode.ERR_CloseUnimplementedInterfaceMemberStatic, "I1").WithArguments("B2", "I1.Goo", "B2.Goo").WithLocation(10, 16));

            var global = comp.GlobalNamespace;
            Assert.Null(global.GetMember<NamedTypeSymbol>("B2").FindImplementationForInterfaceMember(
                    global.GetMember<NamedTypeSymbol>("I1").GetMember<PropertySymbol>("Goo")));
        }

        /// <summary>
        /// CS0736ERR_CloseUnimplementedInterfaceMemberStatic should
        /// be reported, even if the close match is defined in metadata.
        /// </summary>
        [Fact]
        public void CS0736ERR_CloseUnimplementedInterfaceMemberStatic_BaseFromMetadata()
        {
            var ilSource =
@".class interface public abstract I
{
  .method public hidebysig newslot abstract virtual instance void M<T>() { }
}
.class public A
{
  .method public hidebysig specialname rtspecialname instance void .ctor() { ret }
  .method public hidebysig static void M<T>() { ret }
}";
            var csharpSource =
@"class B1 : I
{
    public void M<T>() { }
}
class B2 : A, I
{
}
class B3 : I
{
    public static void M<T>() { }
}";
            CreateCompilationWithILAndMscorlib40(csharpSource, ilSource).VerifyDiagnostics(
                // (5,15): error CS0736: 'B2' does not implement interface member 'I.M<T>()'. 'A.M<T>()' cannot implement an interface member because it is static.
                // class B2 : A, I
                Diagnostic(ErrorCode.ERR_CloseUnimplementedInterfaceMemberStatic, "I").WithArguments("B2", "I.M<T>()", "A.M<T>()").WithLocation(5, 15),
                // (8,12): error CS0736: 'B3' does not implement interface member 'I.M<T>()'. 'B3.M<T>()' cannot implement an interface member because it is static.
                // class B3 : I
                Diagnostic(ErrorCode.ERR_CloseUnimplementedInterfaceMemberStatic, "I").WithArguments("B3", "I.M<T>()", "B3.M<T>()").WithLocation(8, 12));
        }

        [WorkItem(540383, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540383")]
        [Fact]
        public void HideInvalidBaseImplementationWithWrongTypeProperty()
        {
            var text = @"
interface I1
{
    int Goo { get; set; }
}
class B1
{
    public float Goo { get { return 1; } set { } }
}
class B2 : B1, I1
{
    public new float Goo { get { return 1; } }
}
";
            var comp = CreateCompilation(text);
            comp.VerifyDiagnostics(
                // (10,16): error CS0738: 'B2' does not implement interface member 'I1.Goo'. 'B2.Goo' cannot implement 'I1.Goo' because it does not have the matching return type of 'int'.
                // class B2 : B1, I1
                Diagnostic(ErrorCode.ERR_CloseUnimplementedInterfaceMemberWrongReturnType, "I1").WithArguments("B2", "I1.Goo", "B2.Goo", "int").WithLocation(10, 16));

            var global = comp.GlobalNamespace;
            Assert.Null(global.GetMember<NamedTypeSymbol>("B2").FindImplementationForInterfaceMember(
                    global.GetMember<NamedTypeSymbol>("I1").GetMember<PropertySymbol>("Goo")));
        }

        [WorkItem(540420, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540420")]
        [Fact]
        public void HidingInEnum()
        {
            var text = @"
enum E
{
    Equals
}
";
            CreateCompilation(text).VerifyDiagnostics();
        }

        [Fact, WorkItem(543448, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543448")]
        public void GenericMethodsHidingFieldsAndEvents()
        {
            CreateCompilation(@"
class Base
{
    public int A = 1;
    public int B { get { return 1; } set { } }
    public event System.EventHandler C;
}

class Derived : Base
{
    public void A<T>() { }
    public void B<T>() { }
    public void C<T>() { }
}").
            VerifyDiagnostics(
                Diagnostic(ErrorCode.WRN_NewRequired, "A").WithArguments("Derived.A<T>()", "Base.A"),
                Diagnostic(ErrorCode.WRN_NewRequired, "B").WithArguments("Derived.B<T>()", "Base.B"),
                Diagnostic(ErrorCode.WRN_NewRequired, "C").WithArguments("Derived.C<T>()", "Base.C"),

                Diagnostic(ErrorCode.WRN_UnreferencedEvent, "C").WithArguments("Base.C"));
        }

        [WorkItem(543448, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543448")]
        [Fact]
        public void GenericMethodHidesArityZero()
        {
            var text = @"
class Base
{
    public int A = 1;
    public int B { get { return 1; } set { } }
    public event System.EventHandler C;
}

class Sub : Base
{
    public void A<T>() { }
    public void B<T>() { }
    public void C<T>() { }
}
";
            CreateCompilation(text).VerifyDiagnostics(
                // (11,17): warning CS0108: 'Sub.A<T>()' hides inherited member 'Base.A'. Use the new keyword if hiding was intended.
                Diagnostic(ErrorCode.WRN_NewRequired, "A").WithArguments("Sub.A<T>()", "Base.A"),
                // (12,17): warning CS0108: 'Sub.B<T>()' hides inherited member 'Base.B'. Use the new keyword if hiding was intended.
                Diagnostic(ErrorCode.WRN_NewRequired, "B").WithArguments("Sub.B<T>()", "Base.B"),
                // (13,17): warning CS0108: 'Sub.C<T>()' hides inherited member 'Base.C'. Use the new keyword if hiding was intended.
                Diagnostic(ErrorCode.WRN_NewRequired, "C").WithArguments("Sub.C<T>()", "Base.C"),
                // (6,38): warning CS0067: The event 'Base.C' is never used
                //     public event System.EventHandler C;
                Diagnostic(ErrorCode.WRN_UnreferencedEvent, "C").WithArguments("Base.C"));
        }

        [WorkItem(543908, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543908")]
        [Fact]
        public void OverrideMemberOfConstructedProtectedInnerClass()
        {
            var c1 = CreateCompilation(@"
public class Outer1<T>
{
    protected abstract class Inner1
    {
        public abstract void Method();
    }

    protected abstract class Inner2 : Inner1
    {
        public override void Method() { }
    }
}
");
            var c2 = CreateCompilation(@"
internal class Outer2 : Outer1<Outer2>
{
        private class Inner3 : Inner2 {}
}
", new MetadataReference[] { new CSharpCompilationReference(c1) });

            //repro requires two separate compilations
            c2.GetDiagnostics().Verify();
        }

        [WorkItem(543908, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543908")]
        [Fact]
        public void Repro11967()
        {
            var c1 = CreateCompilation(@"

using System.Collections.Generic;

public class ExpressionSyntax {}
public class SimpleNameSyntax : ExpressionSyntax {}
public class InvocationExpressionSyntax: ExpressionSyntax {}

public interface ITypeParameterSymbol {}

public abstract partial class AbstractGenerateMethodService<TService, TSimpleNameSyntax, TExpressionSyntax, TInvocationExpressionSyntax>
{
    protected abstract class MethodInfo
    {
        protected abstract IList<ITypeParameterSymbol> DetermineTypeParameters();
    }

    protected abstract class AbstractInvocationInfo : MethodInfo
    {
        protected sealed override IList<ITypeParameterSymbol> DetermineTypeParameters()
        {
            return null;
        }
    }
}
");
            var c2 = CreateCompilation(@"

internal partial class CSharpGenerateMethodService :
        AbstractGenerateMethodService<CSharpGenerateMethodService, SimpleNameSyntax, ExpressionSyntax, InvocationExpressionSyntax>
{
        private class InvocationExpressionInfo : AbstractInvocationInfo {}
}
", new MetadataReference[] { new CSharpCompilationReference(c1) });

            //repro requires two separate compilations
            c2.GetDiagnostics().Verify();
        }

        [Fact]
        public void CS0570ERR_BindToBogus_RefParametersWithCustomModifiers()
        {
            var il = @"
.class public auto ansi beforefieldinit ModA extends [mscorlib]System.Object
{
  .method public specialname rtspecialname instance void  .ctor() cil managed
  {
    ldarg.0
    call       instance void [mscorlib]System.Object::.ctor()
    ret
  }
}

.class public auto ansi beforefieldinit ModB extends [mscorlib]System.Object
{
  .method public specialname rtspecialname instance void .ctor() cil managed
  {
    ldarg.0
    call       instance void [mscorlib]System.Object::.ctor()
    ret
  }
}

.class public auto ansi beforefieldinit C extends [mscorlib]System.Object
{

  .method public newslot virtual instance void  FN(class C c) cil managed
  {
    ldarg.0
    ldarg.1
    call       instance void C::F(class C)
    ret
  }

  .method public newslot virtual instance void  FA(class C modopt(ModA) c) cil managed
  {
    ldarg.0
    ldarg.1
    call       instance void C::F(class C modopt(ModA))
    ret
  }

  .method public newslot virtual instance void  FB(class C modopt(ModB) c) cil managed
  {
    ldarg.0
    ldarg.1
    call       instance void C::F(class C modopt(ModB))
    ret
  }

  .method public newslot virtual instance void  FAB(class C modopt(ModA) modopt(ModB) c) cil managed
  {
    ldarg.0
    ldarg.1
    call       instance void C::F(class C modopt(ModA) modopt(ModB))
    ret
  }


  .method public newslot virtual instance void G(class C& c) cil managed
  {
    ldstr      ""C::G(C &)""
    call       void [mscorlib]System.Console::WriteLine(string)
    ret
  }

  .method public newslot virtual instance void G(class C modopt(ModA) & c) cil managed
  {
    ldstr      ""C::G(C [A] &)""
    call       void [mscorlib]System.Console::WriteLine(string)
    ret
  }

  .method public newslot virtual instance void G(class C & modopt(ModB) c) cil managed
  {
    ldstr      ""C::G(C & [B])""
    call       void [mscorlib]System.Console::WriteLine(string)
    ret
  }

  .method public newslot virtual instance void G(class C modopt(ModA) & modopt(ModB) c) cil managed
  {
    ldstr      ""C::G(C [A] & [B])""
    call       void [mscorlib]System.Console::WriteLine(string)
    ret
  }

  .method public newslot virtual instance void GN(class C& c) cil managed
  {
    ldarg.0
    ldarg.1
    call       instance void C::G(class C&)
    ret
  }

  .method public newslot virtual instance void GA(class C modopt(ModA) & c) cil managed
  {
    ldarg.0
    ldarg.1
    call       instance void C::G(class C modopt(ModA) &)
    ret
  }

  .method public newslot virtual instance void GB(class C & modopt(ModB) c) cil managed
  {
    ldarg.0
    ldarg.1
    call       instance void C::G(class C & modopt(ModB))
    ret
  }

  .method public newslot virtual instance void GAB(class C modopt(ModA) & modopt(ModB) c) cil managed
  {
    ldarg.0
    ldarg.1
    call       instance void C::G(class C modopt(ModA) & modopt(ModB))
    ret
  }

  .method public specialname rtspecialname instance void .ctor() cil managed
  {
    ldarg.0
    call       instance void [mscorlib]System.Object::.ctor()
    ret
  }
}

.class public auto ansi beforefieldinit D extends C
{
  .method public specialname rtspecialname instance void .ctor() cil managed
  {
    ldarg.0
    call       instance void C::.ctor()
    ret
  }
}
";

            var csharp = @"
class Test
{
    void Goo()
    {
        C c = new C();

        c.FN(c); // no modopts
        c.FA(c); // modopt A
        c.FB(c); // modopt B
        c.FAB(c); // modopts A, B

        c.GN(ref c); // no modopts
        c.GA(ref c); // modopt A (inside ref)
        c.GB(ref c); // modopt B (outside ref)
        c.GAB(ref c); // modopts A, B (inside and outside ref, respectively)
    }
}";
            CompileAndVerify(CreateCompilationWithILAndMscorlib40(csharp, il));
        }

        [WorkItem(545653, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545653")]
        [Fact]
        public void Repro14242_Property()
        {
            var source = @"
abstract class A
{
    public abstract int X { get; set; }
}
 
abstract class B : A
{
    public override int X { set { } }
}
 
abstract class C : B
{
    public new virtual string X {  get; set;  }
}
 
class D : C
{
    public override int X
    {
        get { return 0; }
    }
}
";
            var comp = CreateCompilation(source);
            var global = comp.GlobalNamespace;

            var propA = global.GetMember<NamedTypeSymbol>("A").GetMember<PropertySymbol>("X");
            var propB = global.GetMember<NamedTypeSymbol>("B").GetMember<PropertySymbol>("X");
            var propC = global.GetMember<NamedTypeSymbol>("C").GetMember<PropertySymbol>("X");
            var propD = global.GetMember<NamedTypeSymbol>("D").GetMember<PropertySymbol>("X");

            var ohmA = propA.OverriddenOrHiddenMembers;
            var ohmB = propB.OverriddenOrHiddenMembers;
            var ohmC = propC.OverriddenOrHiddenMembers;
            var ohmD = propD.OverriddenOrHiddenMembers;

            Assert.Equal(0, ohmA.OverriddenMembers.Length);
            Assert.Equal(0, ohmA.HiddenMembers.Length);

            Assert.Equal(propA, ohmB.OverriddenMembers.Single());
            Assert.Equal(0, ohmB.HiddenMembers.Length);

            Assert.Equal(0, ohmC.OverriddenMembers.Length);
            Assert.Equal(propB, ohmC.HiddenMembers.Single());

            Assert.Equal(propC, ohmD.OverriddenMembers.Single());
            Assert.Equal(0, ohmD.HiddenMembers.Length);

            comp.VerifyDiagnostics(
                // (19,25): error CS1715: 'D.X': type must be 'string' to match overridden member 'C.X'
                //     public override int X
                Diagnostic(ErrorCode.ERR_CantChangeTypeOnOverride, "X").WithArguments("D.X", "C.X", "string"),
                // (17,7): error CS0534: 'D' does not implement inherited abstract member 'A.X.get'
                // class D : C
                Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "D").WithArguments("D", "A.X.get"));
        }

        [WorkItem(545653, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545653")]
        [Fact]
        public void Repro14242_Event()
        {
            var source = @"
abstract class A
{
    public abstract event System.Action E;
}
 
abstract class B : A
{
    public override event System.Action E;
}
 
abstract class C : B
{
    public new virtual event System.Func<int> E;
}
 
class D : C
{
    public override event System.Action E;
}
";
            var comp = CreateCompilation(source);
            var global = comp.GlobalNamespace;

            var eventA = global.GetMember<NamedTypeSymbol>("A").GetMember<EventSymbol>("E");
            var eventB = global.GetMember<NamedTypeSymbol>("B").GetMember<EventSymbol>("E");
            var eventC = global.GetMember<NamedTypeSymbol>("C").GetMember<EventSymbol>("E");
            var eventD = global.GetMember<NamedTypeSymbol>("D").GetMember<EventSymbol>("E");

            var ohmA = eventA.OverriddenOrHiddenMembers;
            var ohmB = eventB.OverriddenOrHiddenMembers;
            var ohmC = eventC.OverriddenOrHiddenMembers;
            var ohmD = eventD.OverriddenOrHiddenMembers;

            Assert.Equal(0, ohmA.OverriddenMembers.Length);
            Assert.Equal(0, ohmA.HiddenMembers.Length);

            Assert.Equal(eventA, ohmB.OverriddenMembers.Single());
            Assert.Equal(0, ohmB.HiddenMembers.Length);

            Assert.Equal(0, ohmC.OverriddenMembers.Length);
            Assert.Equal(eventB, ohmC.HiddenMembers.Single());

            Assert.Equal(eventC, ohmD.OverriddenMembers.Single());
            Assert.Equal(0, ohmD.HiddenMembers.Length);

            comp.VerifyDiagnostics(
                // (19,41): error CS1715: 'D.E': type must be 'Func<int>' to match overridden member 'C.E'
                //     public override event System.Action E;
                Diagnostic(ErrorCode.ERR_CantChangeTypeOnOverride, "E").WithArguments("D.E", "C.E", "System.Func<int>").WithLocation(19, 41),
                // (19,41): warning CS0067: The event 'D.E' is never used
                //     public override event System.Action E;
                Diagnostic(ErrorCode.WRN_UnreferencedEvent, "E").WithArguments("D.E").WithLocation(19, 41),
                // (9,41): warning CS0067: The event 'B.E' is never used
                //     public override event System.Action E;
                Diagnostic(ErrorCode.WRN_UnreferencedEvent, "E").WithArguments("B.E").WithLocation(9, 41),
                // (14,47): warning CS0067: The event 'C.E' is never used
                //     public new virtual event System.Func<int> E;
                Diagnostic(ErrorCode.WRN_UnreferencedEvent, "E").WithArguments("C.E").WithLocation(14, 47));
        }

        [WorkItem(545653, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545653")]
        [Fact]
        public void Repro14242_Method()
        {
            var source = @"
abstract class A
{
    public abstract int M();
}
 
abstract class B : A
{
    public override int M() { return 0; }
}
 
abstract class C : B
{
    public new virtual string M() { return null; }
}
 
class D : C
{
    public override int M() { return 0; }
}
";
            var comp = CreateCompilation(source);
            var global = comp.GlobalNamespace;

            var methodA = global.GetMember<NamedTypeSymbol>("A").GetMember<MethodSymbol>("M");
            var methodB = global.GetMember<NamedTypeSymbol>("B").GetMember<MethodSymbol>("M");
            var methodC = global.GetMember<NamedTypeSymbol>("C").GetMember<MethodSymbol>("M");
            var methodD = global.GetMember<NamedTypeSymbol>("D").GetMember<MethodSymbol>("M");

            var ohmA = methodA.OverriddenOrHiddenMembers;
            var ohmB = methodB.OverriddenOrHiddenMembers;
            var ohmC = methodC.OverriddenOrHiddenMembers;
            var ohmD = methodD.OverriddenOrHiddenMembers;

            Assert.Equal(0, ohmA.OverriddenMembers.Length);
            Assert.Equal(0, ohmA.HiddenMembers.Length);

            Assert.Equal(methodA, ohmB.OverriddenMembers.Single());
            Assert.Equal(0, ohmB.HiddenMembers.Length);

            Assert.Equal(0, ohmC.OverriddenMembers.Length);
            Assert.Equal(methodB, ohmC.HiddenMembers.Single());

            Assert.Equal(methodC, ohmD.OverriddenMembers.Single());
            Assert.Equal(0, ohmD.HiddenMembers.Length);

            comp.VerifyDiagnostics(
                // (19,25): error CS0508: 'D.M()': return type must be 'string' to match overridden member 'C.M()'
                //     public override int M() { return 0; }
                Diagnostic(ErrorCode.ERR_CantChangeReturnTypeOnOverride, "M").WithArguments("D.M()", "C.M()", "string"));
        }

        [WorkItem(545653, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545653")]
        [Fact]
        public void Repro14242_Indexer()
        {
            var source = @"
abstract class A
{
    public abstract int this[int x] { get; set; }
}
 
abstract class B : A
{
    public override int this[int x] { set { } }
}
 
abstract class C : B
{
    public new virtual string this[int x] {  get { return null; } set { } }
}
 
class D : C
{
    public override int this[int x]
    {
        get { return 0; }
    }
}
";
            var comp = CreateCompilation(source);
            var global = comp.GlobalNamespace;

            var indexerA = global.GetMember<NamedTypeSymbol>("A").GetMember<PropertySymbol>(WellKnownMemberNames.Indexer);
            var indexerB = global.GetMember<NamedTypeSymbol>("B").GetMember<PropertySymbol>(WellKnownMemberNames.Indexer);
            var indexerC = global.GetMember<NamedTypeSymbol>("C").GetMember<PropertySymbol>(WellKnownMemberNames.Indexer);
            var indexerD = global.GetMember<NamedTypeSymbol>("D").GetMember<PropertySymbol>(WellKnownMemberNames.Indexer);

            var ohmA = indexerA.OverriddenOrHiddenMembers;
            var ohmB = indexerB.OverriddenOrHiddenMembers;
            var ohmC = indexerC.OverriddenOrHiddenMembers;
            var ohmD = indexerD.OverriddenOrHiddenMembers;

            Assert.Equal(0, ohmA.OverriddenMembers.Length);
            Assert.Equal(0, ohmA.HiddenMembers.Length);

            Assert.Equal(indexerA, ohmB.OverriddenMembers.Single());
            Assert.Equal(0, ohmB.HiddenMembers.Length);

            Assert.Equal(0, ohmC.OverriddenMembers.Length);
            Assert.Equal(indexerB, ohmC.HiddenMembers.Single());

            Assert.Equal(indexerC, ohmD.OverriddenMembers.Single());
            Assert.Equal(0, ohmD.HiddenMembers.Length);

            comp.VerifyDiagnostics(
                // (19,25): error CS1715: 'D.this[int]': type must be 'string' to match overridden member 'C.this[int]'
                //     public override int this[int x]
                Diagnostic(ErrorCode.ERR_CantChangeTypeOnOverride, "this").WithArguments("D.this[int]", "C.this[int]", "string"),
                // (17,7): error CS0534: 'D' does not implement inherited abstract member 'A.this[int].get'
                // class D : C
                Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "D").WithArguments("D", "A.this[int].get"));
        }

        [ConditionalFact(typeof(DesktopOnly), typeof(ClrOnly))]
        [WorkItem(545658, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545658")]
        [WorkItem(18411, "https://github.com/dotnet/roslyn/issues/18411")]
        public void MethodConstructedFromOverrideWithCustomModifiers()
        {
            var il = @"
.class public auto ansi beforefieldinit G`1<T>
       extends [mscorlib]System.Object
{
  .method public hidebysig specialname rtspecialname 
          instance void  .ctor() cil managed
  {
    ldarg.0
    call       instance void [mscorlib]System.Object::.ctor()
    ret
  }

} // end of class G`1

.class public auto ansi beforefieldinit C
       extends [mscorlib]System.Object
{
  .method public hidebysig specialname rtspecialname 
          instance void  .ctor() cil managed
  {
    ldarg.0
    call       instance void [mscorlib]System.Object::.ctor()
    ret
  }

} // end of class C

.class public auto ansi beforefieldinit Base`1<T>
       extends [mscorlib]System.Object
{
  .method public hidebysig newslot virtual 
          instance !T modopt([mscorlib]System.Runtime.CompilerServices.IsConst) 
          vMeth(!T modopt([mscorlib]System.Runtime.CompilerServices.IsConst) t) cil managed
  {
    ldstr      ""Base[{0}].vMeth({0})""
    ldtoken    !T
    call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
    call       void [mscorlib]System.Console::WriteLine(string, object)
    ldarg.1
    ret
  }

  .method public hidebysig instance !T modopt([mscorlib]System.Runtime.CompilerServices.IsConst) 
          Meth(!T modopt([mscorlib]System.Runtime.CompilerServices.IsConst) t,
               int32 modopt([mscorlib]System.Runtime.CompilerServices.IsConst) i) cil managed
  {
    ldstr      ""Base[{0}].Meth({0},{1})""
    ldtoken    !T
    call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
    ldtoken    [mscorlib]System.Int32
    call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
    call       void [mscorlib]System.Console::WriteLine(string, object, object)
    ldarg.1
    ret
  }

  .method public hidebysig specialname rtspecialname 
          instance void  .ctor() cil managed
  {
    ldarg.0
    call       instance void [mscorlib]System.Object::.ctor()
    ret
  }

} // end of class Base`1

.class public auto ansi beforefieldinit SubT`1<T>
       extends class Base`1<!T>
{
  .method public hidebysig specialname rtspecialname 
          instance void  .ctor() cil managed
  {
    ldarg.0
    call       instance void class Base`1<!T>::.ctor()
    ret
  }

} // end of class SubT`1

.class public auto ansi beforefieldinit SubGT`1<T>
       extends class Base`1<class G`1<!T>>
{
  .method public hidebysig specialname rtspecialname 
          instance void  .ctor() cil managed
  {
    ldarg.0
    call       instance void class Base`1<class G`1<!T>>::.ctor()
    ret
  }

} // end of class SubGT`1

.class public auto ansi beforefieldinit SubC
       extends class Base`1<class C>
{
  .method public hidebysig specialname rtspecialname 
          instance void  .ctor() cil managed
  {
    ldarg.0
    call       instance void class Base`1<class C>::.ctor()
    ret
  }

} // end of class SubC
";

            var csharp = @"
using System;

public interface I<T>
{
	T Meth(T t, int i);
	T vMeth(T t);
}

public class SubSubT<T> : SubT<T> , I<T>
{
	public override T vMeth(T t) 
	{
		Console.WriteLine(""SubSubT[{0}].vMeth({0})"",typeof(T));
		return base.vMeth(t);
	}
}

public class SubSubGT<T> : SubGT<T> , I<G<T>>
{
	public override G<T> vMeth(G<T> t) 
	{
		Console.WriteLine(""SubSubGT[{0}].vMeth({1})"",typeof(T),typeof(G<T>));
		return base.vMeth(t);
	}
}

public class SubSubC : SubC , I<C>
{
	public override C vMeth(C t) 
	{ 
		Console.WriteLine(""SubSubC.vMeth(C)"");
		return base.vMeth(t);
	}
}

class Test
{
	public static int Main()
	{
		new SubSubT<int>().vMeth(1);
		new SubSubGT<int>().vMeth(new G<int>());
		new SubSubC().vMeth(new C());

		Console.WriteLine();
		
		new SubSubT<string>().Meth(""1"",1);
		new SubSubGT<string>().Meth(new G<string>(),1);
		new SubSubC().Meth(new C(),1);

		Console.WriteLine();
		
		((I<string>)new SubSubT<string>()).vMeth(""1"");
		((I<G<string>>)new SubSubGT<string>()).vMeth(new G<string>());
		((I<C>)new SubSubC()).vMeth(new C());

		Console.WriteLine();

		((I<int>)new SubSubT<int>()).Meth(1,1);
		((I<G<int>>)new SubSubGT<int>()).Meth(new G<int>(),1);
		((I<C>)new SubSubC()).Meth(new C(),1);
		
		return 0;
	}
}
";
            var ref1 = CompileIL(il);

            var comp = CreateCompilation(csharp, new[] { ref1 }, options: TestOptions.ReleaseExe);
            CompileAndVerify(comp, expectedOutput: @"
SubSubT[System.Int32].vMeth(System.Int32)
Base[System.Int32].vMeth(System.Int32)
SubSubGT[System.Int32].vMeth(G`1[System.Int32])
Base[G`1[System.Int32]].vMeth(G`1[System.Int32])
SubSubC.vMeth(C)
Base[C].vMeth(C)

Base[System.String].Meth(System.String,System.Int32)
Base[G`1[System.String]].Meth(G`1[System.String],System.Int32)
Base[C].Meth(C,System.Int32)

SubSubT[System.String].vMeth(System.String)
Base[System.String].vMeth(System.String)
SubSubGT[System.String].vMeth(G`1[System.String])
Base[G`1[System.String]].vMeth(G`1[System.String])
SubSubC.vMeth(C)
Base[C].vMeth(C)

Base[System.Int32].Meth(System.Int32,System.Int32)
Base[G`1[System.Int32]].Meth(G`1[System.Int32],System.Int32)
Base[C].Meth(C,System.Int32)");
        }

        [ClrOnlyFact]
        [WorkItem(546816, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546816")]
        public void Bug16887()
        {
            var text = @"
class Test
{
    ~Test()
    {
    }
}
";
            var compilation = CreateEmptyCompilation(text, new MetadataReference[] { MscorlibRef_v20 });

            var obj = compilation.GetSpecialType(SpecialType.System_Object);
            var finalize = (MethodSymbol)obj.GetMembers("Finalize").Single();

            Assert.False(finalize.IsVirtual);
            Assert.False(finalize.IsOverride);

            CompileAndVerify(compilation);
        }

        [Fact, WorkItem(546836, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546836")]
        public void OverriddenPropertyAccessibility1()
        {
            var source1 = @"
public class A
{
	protected internal virtual int P { get; set; }
}
";
            var source2 = @"
[assembly:System.Runtime.CompilerServices.InternalsVisibleTo(""C"")]
public class B : A
{
	protected override int P { get; set; }
}
";
            var source3 = @"
public class C : B
{
	protected override int P { get; set; }
}
";

            var comp1 = CreateCompilation(source1, assemblyName: "A.dll");
            var ref1 = comp1.EmitToImageReference();

            var comp2 = CreateCompilation(source2, new[] { ref1 }, assemblyName: "B.dll");
            var ref2 = comp2.EmitToImageReference();

            var comp3 = CreateCompilation(source3, new[] { ref1, ref2 }, assemblyName: "C.dll");
            comp3.VerifyDiagnostics();

            var properties = new[]
            {
                comp1.GlobalNamespace.GetMember<NamedTypeSymbol>("A").GetMember<PropertySymbol>("P"),

                comp2.GlobalNamespace.GetMember<NamedTypeSymbol>("A").GetMember<PropertySymbol>("P"),
                comp2.GlobalNamespace.GetMember<NamedTypeSymbol>("B").GetMember<PropertySymbol>("P"),

                comp3.GlobalNamespace.GetMember<NamedTypeSymbol>("A").GetMember<PropertySymbol>("P"),
                comp3.GlobalNamespace.GetMember<NamedTypeSymbol>("B").GetMember<PropertySymbol>("P"),
                comp3.GlobalNamespace.GetMember<NamedTypeSymbol>("C").GetMember<PropertySymbol>("P"),
            };

            AssertEx.All(properties, p =>
                p.DeclaredAccessibility == (p.ContainingType.Name == "A" ? Accessibility.ProtectedOrInternal : Accessibility.Protected));
        }

        [Fact, WorkItem(546836, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546836")]
        public void OverriddenPropertyAccessibility2()
        {
            var source1 = @"
public class A
{
	protected internal virtual int P { get; set; }
}
";
            var source2 = @"
[assembly:System.Runtime.CompilerServices.InternalsVisibleTo(""C"")]
public class B : A
{
	protected override int P { set { } }
}
";
            var source3 = @"
public class C : B
{
	protected override int P { get { return 0; } }
}
";

            var comp1 = CreateCompilation(source1, assemblyName: "A.dll");
            var ref1 = comp1.EmitToImageReference();

            var comp2 = CreateCompilation(source2, new[] { ref1 }, assemblyName: "B.dll");
            var ref2 = comp2.EmitToImageReference();

            var comp3 = CreateCompilation(source3, new[] { ref1, ref2 }, assemblyName: "C.dll");
            comp3.VerifyDiagnostics();

            var properties = new[]
            {
                comp1.GlobalNamespace.GetMember<NamedTypeSymbol>("A").GetMember<PropertySymbol>("P"),

                comp2.GlobalNamespace.GetMember<NamedTypeSymbol>("A").GetMember<PropertySymbol>("P"),
                comp2.GlobalNamespace.GetMember<NamedTypeSymbol>("B").GetMember<PropertySymbol>("P"),

                comp3.GlobalNamespace.GetMember<NamedTypeSymbol>("A").GetMember<PropertySymbol>("P"),
                comp3.GlobalNamespace.GetMember<NamedTypeSymbol>("B").GetMember<PropertySymbol>("P"),
                comp3.GlobalNamespace.GetMember<NamedTypeSymbol>("C").GetMember<PropertySymbol>("P"),
            };

            AssertEx.All(properties, p =>
                p.DeclaredAccessibility == (p.ContainingType.Name == "A" ? Accessibility.ProtectedOrInternal : Accessibility.Protected));
        }

        [Fact, WorkItem(546836, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546836")]
        public void OverriddenPropertyAccessibility3()
        {
            var source1 = @"
public class A
{
	public virtual int P { get; protected internal set; }
}
";
            var source2 = @"
[assembly:System.Runtime.CompilerServices.InternalsVisibleTo(""C"")]
public class B : A
{
	public override int P { protected set { } }
}
";
            var source3 = @"
public class C : B
{
	public override int P { get { return 0; } }
}
";

            var comp1 = CreateCompilation(source1, assemblyName: "A.dll");
            var ref1 = comp1.EmitToImageReference();

            var comp2 = CreateCompilation(source2, new[] { ref1 }, assemblyName: "B.dll");
            var ref2 = comp2.EmitToImageReference();

            var comp3 = CreateCompilation(source3, new[] { ref1, ref2 }, assemblyName: "C.dll");
            comp3.VerifyDiagnostics();

            var properties = new[]
            {
                comp1.GlobalNamespace.GetMember<NamedTypeSymbol>("A").GetMember<PropertySymbol>("P"),

                comp2.GlobalNamespace.GetMember<NamedTypeSymbol>("A").GetMember<PropertySymbol>("P"),
                comp2.GlobalNamespace.GetMember<NamedTypeSymbol>("B").GetMember<PropertySymbol>("P"),

                comp3.GlobalNamespace.GetMember<NamedTypeSymbol>("A").GetMember<PropertySymbol>("P"),
                comp3.GlobalNamespace.GetMember<NamedTypeSymbol>("B").GetMember<PropertySymbol>("P"),
                comp3.GlobalNamespace.GetMember<NamedTypeSymbol>("C").GetMember<PropertySymbol>("P"),
            };

            AssertEx.All(properties, p => p.DeclaredAccessibility == Accessibility.Public);
        }

        [Fact, WorkItem(546836, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546836")]
        public void OverriddenPropertyAccessibility4()
        {
            var source1 = @"
[assembly:System.Runtime.CompilerServices.InternalsVisibleTo(""B"")]
public class A
{
	public virtual int P { get; protected internal set; }
}
";
            var source2 = @"
public class B : A
{
	public override int P { protected internal set { } }
}
";
            var source3 = @"
public class C : B
{
	public override int P { get { return 0; } }
}
";

            var comp1 = CreateCompilation(source1, assemblyName: "A");
            var ref1 = comp1.EmitToImageReference();

            var comp2 = CreateCompilation(source2, new[] { ref1 }, assemblyName: "B");
            var ref2 = comp2.EmitToImageReference();

            var comp3 = CreateCompilation(source3, new[] { ref1, ref2 }, assemblyName: "C");
            comp3.VerifyDiagnostics();

            var properties = new[]
            {
                comp1.GlobalNamespace.GetMember<NamedTypeSymbol>("A").GetMember<PropertySymbol>("P"),

                comp2.GlobalNamespace.GetMember<NamedTypeSymbol>("A").GetMember<PropertySymbol>("P"),
                comp2.GlobalNamespace.GetMember<NamedTypeSymbol>("B").GetMember<PropertySymbol>("P"),

                comp3.GlobalNamespace.GetMember<NamedTypeSymbol>("A").GetMember<PropertySymbol>("P"),
                comp3.GlobalNamespace.GetMember<NamedTypeSymbol>("B").GetMember<PropertySymbol>("P"),
                comp3.GlobalNamespace.GetMember<NamedTypeSymbol>("C").GetMember<PropertySymbol>("P"),
            };

            AssertEx.All(properties, p => p.DeclaredAccessibility == Accessibility.Public);
        }

        [Fact, WorkItem(546836, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546836")]
        public void OverriddenPropertyAccessibility5()
        {
            var source1 = @"
public class A
{
	public virtual int P { get; protected set; }
}
";
            var source2 = @"
[assembly:System.Runtime.CompilerServices.InternalsVisibleTo(""C"")]
public class B : A
{
	public override int P { protected set { } }
}
";
            var source3 = @"
public class C : B
{
	public override int P { get { return 0; } }
}
";

            var comp1 = CreateCompilation(source1, assemblyName: "A.dll");
            var ref1 = comp1.EmitToImageReference();

            var comp2 = CreateCompilation(source2, new[] { ref1 }, assemblyName: "B.dll");
            var ref2 = comp2.EmitToImageReference();

            var comp3 = CreateCompilation(source3, new[] { ref1, ref2 }, assemblyName: "C.dll");
            comp3.VerifyDiagnostics();

            var properties = new[]
            {
                comp1.GlobalNamespace.GetMember<NamedTypeSymbol>("A").GetMember<PropertySymbol>("P"),

                comp2.GlobalNamespace.GetMember<NamedTypeSymbol>("A").GetMember<PropertySymbol>("P"),
                comp2.GlobalNamespace.GetMember<NamedTypeSymbol>("B").GetMember<PropertySymbol>("P"),

                comp3.GlobalNamespace.GetMember<NamedTypeSymbol>("A").GetMember<PropertySymbol>("P"),
                comp3.GlobalNamespace.GetMember<NamedTypeSymbol>("B").GetMember<PropertySymbol>("P"),
                comp3.GlobalNamespace.GetMember<NamedTypeSymbol>("C").GetMember<PropertySymbol>("P"),
            };

            AssertEx.All(properties, p => p.DeclaredAccessibility == Accessibility.Public);
        }

        [Fact, WorkItem(546836, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546836")]
        public void OverriddenPropertyAccessibility6()
        {
            var source1 = @"
[assembly:System.Runtime.CompilerServices.InternalsVisibleTo(""B"")]
public class A
{
	public virtual int P { get; protected set; }
}
";
            var source2 = @"
public class B : A
{
	public override int P { protected set { } }
}
";
            var source3 = @"
public class C : B
{
	public override int P { get { return 0; } }
}
";

            var comp1 = CreateCompilation(source1, assemblyName: "A.dll");
            var ref1 = comp1.EmitToImageReference();

            var comp2 = CreateCompilation(source2, new[] { ref1 }, assemblyName: "B.dll");
            var ref2 = comp2.EmitToImageReference();

            var comp3 = CreateCompilation(source3, new[] { ref1, ref2 }, assemblyName: "C.dll");
            comp3.VerifyDiagnostics();

            var properties = new[]
            {
                comp1.GlobalNamespace.GetMember<NamedTypeSymbol>("A").GetMember<PropertySymbol>("P"),

                comp2.GlobalNamespace.GetMember<NamedTypeSymbol>("A").GetMember<PropertySymbol>("P"),
                comp2.GlobalNamespace.GetMember<NamedTypeSymbol>("B").GetMember<PropertySymbol>("P"),

                comp3.GlobalNamespace.GetMember<NamedTypeSymbol>("A").GetMember<PropertySymbol>("P"),
                comp3.GlobalNamespace.GetMember<NamedTypeSymbol>("B").GetMember<PropertySymbol>("P"),
                comp3.GlobalNamespace.GetMember<NamedTypeSymbol>("C").GetMember<PropertySymbol>("P"),
            };

            AssertEx.All(properties, p => p.DeclaredAccessibility == Accessibility.Public);
        }

        [Fact, WorkItem(546836, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546836")]
        public void OverriddenPropertyAccessibility7()
        {
            var source1 = @"
[assembly:System.Runtime.CompilerServices.InternalsVisibleTo(""B"")]
public class A
{
	protected internal virtual int P { get; set; }
}
";
            var source2 = @"
public class B : A
{
	protected internal override int P { set { } }
}
";
            // If this was C#, we would have to change the accessibility from
            // "protected internal" to "protected", so we'll do this in IL.
            var source3 = @"
.assembly extern mscorlib { }
.assembly extern B { }
.assembly C { }

.class public auto ansi beforefieldinit C
       extends [B]B
{
  .method famorassem hidebysig specialname virtual 
          instance int32  get_P() cil managed
  {
    ldc.i4.0
    ret
  }

  .method public hidebysig specialname rtspecialname 
          instance void  .ctor() cil managed
  {
    ldarg.0
    call       instance void [B]B::.ctor()
    ret
  } // end of method C::.ctor

  .property instance int32 P()
  {
    .get instance int32 C::get_P()
  } // end of property C::P
} // end of class C
";

            var comp1 = CreateCompilation(source1, assemblyName: "A");
            var ref1 = comp1.EmitToImageReference();

            var comp2 = CreateCompilation(source2, new[] { ref1 }, assemblyName: "B");
            var ref2 = comp2.EmitToImageReference();

            var ilRef = CompileIL(source3, prependDefaultHeader: false);

            var comp3 = CreateCompilation("", new[] { ref1, ref2, ilRef }, assemblyName: "Test");
            comp3.VerifyDiagnostics();

            var properties = new[]
            {
                comp1.GlobalNamespace.GetMember<NamedTypeSymbol>("A").GetMember<PropertySymbol>("P"),

                comp2.GlobalNamespace.GetMember<NamedTypeSymbol>("A").GetMember<PropertySymbol>("P"),
                comp2.GlobalNamespace.GetMember<NamedTypeSymbol>("B").GetMember<PropertySymbol>("P"),

                comp3.GlobalNamespace.GetMember<NamedTypeSymbol>("A").GetMember<PropertySymbol>("P"),
                comp3.GlobalNamespace.GetMember<NamedTypeSymbol>("B").GetMember<PropertySymbol>("P"),
                comp3.GlobalNamespace.GetMember<NamedTypeSymbol>("C").GetMember<PropertySymbol>("P"),
            };

            AssertEx.All(properties, p => p.DeclaredAccessibility == Accessibility.ProtectedOrInternal);
        }

        [Fact, WorkItem(546836, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546836")]
        public void OverriddenEventAccessibility()
        {
            var source1 = @"
public class A
{
	protected internal virtual event System.Action E;

    void UseEvent() { E(); }
}
";
            var source2 = @"
[assembly:System.Runtime.CompilerServices.InternalsVisibleTo(""C"")]
public class B : A
{
	protected override event System.Action E;

    void UseEvent() { E(); }
}
";
            var source3 = @"
public class C : B
{
	protected override event System.Action E;

    void UseEvent() { E(); }
}
";

            var comp1 = CreateCompilation(source1, assemblyName: "A.dll");
            var ref1 = comp1.EmitToImageReference();

            var comp2 = CreateCompilation(source2, new[] { ref1 }, assemblyName: "B.dll");
            var ref2 = comp2.EmitToImageReference();

            var comp3 = CreateCompilation(source3, new[] { ref1, ref2 }, assemblyName: "C.dll");
            comp3.VerifyDiagnostics();

            var events = new[]
            {
                comp1.GlobalNamespace.GetMember<NamedTypeSymbol>("A").GetMember<EventSymbol>("E"),

                comp2.GlobalNamespace.GetMember<NamedTypeSymbol>("A").GetMember<EventSymbol>("E"),
                comp2.GlobalNamespace.GetMember<NamedTypeSymbol>("B").GetMember<EventSymbol>("E"),

                comp3.GlobalNamespace.GetMember<NamedTypeSymbol>("A").GetMember<EventSymbol>("E"),
                comp3.GlobalNamespace.GetMember<NamedTypeSymbol>("B").GetMember<EventSymbol>("E"),
                comp3.GlobalNamespace.GetMember<NamedTypeSymbol>("C").GetMember<EventSymbol>("E"),
            };

            AssertEx.All(events, e =>
                e.DeclaredAccessibility == (e.ContainingType.Name == "A" ? Accessibility.ProtectedOrInternal : Accessibility.Protected));
        }

        [Fact, WorkItem(546836, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546836")]
        public void HideDestructorOperatorConversion1()
        {
            var source = @"
public class B
{
    public static int operator +(B b)
    {
        return 0;
    }

    public static explicit operator int(B b)
    {
        return 0;
    }

    ~B()
    {
    }
}

public class D1 : B
{
    public class op_UnaryPlus { }
    public class op_Explicit { }
    public class Finalize { }
}

public class D2 : B
{
    public int op_UnaryPlus { get; set; }
    public int op_Explicit { get; set; }
    public int Finalize { get; set; }
}

public class D3 : B
{
    public int op_UnaryPlus = 1; //CS0108
    public int op_Explicit = 1; //CS0108
    public int Finalize = 1;
}

public class D4 : B
{
    public event System.Action op_UnaryPlus; //CS0108
    public event System.Action op_Explicit; //CS0108
    public event System.Action Finalize;
}

public class D5 : B
{
    public event System.Action op_UnaryPlus { add { } remove { } } //CS0108
    public event System.Action op_Explicit { add { } remove { } } //CS0108
    public event System.Action Finalize { add { } remove { } }
}

public class D6 : B
{
    public delegate void op_UnaryPlus();
    public delegate void op_Explicit();
    public delegate void Finalize();
}

public class D7 : B
{
    public void op_UnaryPlus(B b) { }
    public void op_Explicit(B b) { }
    public void Finalize() { }
}

public class D8 : B
{
    public static int op_UnaryPlus(B b) { return 0; }
    public static int op_Explicit(B b) { return 0; }
    public static void Finalize() { }
}
";

            CreateCompilation(source).VerifyDiagnostics(
                // (36,16): warning CS0108: 'D3.op_Explicit' hides inherited member 'B.explicit operator int(B)'. Use the new keyword if hiding was intended.
                //     public int op_Explicit = 1;//
                Diagnostic(ErrorCode.WRN_NewRequired, "op_Explicit").WithArguments("D3.op_Explicit", "B.explicit operator int(B)"),
                // (35,16): warning CS0108: 'D3.op_UnaryPlus' hides inherited member 'B.operator +(B)'. Use the new keyword if hiding was intended.
                //     public int op_UnaryPlus = 1;//
                Diagnostic(ErrorCode.WRN_NewRequired, "op_UnaryPlus").WithArguments("D3.op_UnaryPlus", "B.operator +(B)"),
                // (43,32): warning CS0108: 'D4.op_Explicit' hides inherited member 'B.explicit operator int(B)'. Use the new keyword if hiding was intended.
                //     public event System.Action op_Explicit;//
                Diagnostic(ErrorCode.WRN_NewRequired, "op_Explicit").WithArguments("D4.op_Explicit", "B.explicit operator int(B)"),
                // (42,32): warning CS0108: 'D4.op_UnaryPlus' hides inherited member 'B.operator +(B)'. Use the new keyword if hiding was intended.
                //     public event System.Action op_UnaryPlus;//
                Diagnostic(ErrorCode.WRN_NewRequired, "op_UnaryPlus").WithArguments("D4.op_UnaryPlus", "B.operator +(B)"),
                // (50,32): warning CS0108: 'D5.op_Explicit' hides inherited member 'B.explicit operator int(B)'. Use the new keyword if hiding was intended.
                //     public event System.Action op_Explicit { add { } remove { } }//
                Diagnostic(ErrorCode.WRN_NewRequired, "op_Explicit").WithArguments("D5.op_Explicit", "B.explicit operator int(B)"),
                // (49,32): warning CS0108: 'D5.op_UnaryPlus' hides inherited member 'B.operator +(B)'. Use the new keyword if hiding was intended.
                //     public event System.Action op_UnaryPlus { add { } remove { } }//
                Diagnostic(ErrorCode.WRN_NewRequired, "op_UnaryPlus").WithArguments("D5.op_UnaryPlus", "B.operator +(B)"),

                // (43,32): warning CS0067: The event 'D4.op_Explicit' is never used
                //     public event System.Action op_Explicit;//
                Diagnostic(ErrorCode.WRN_UnreferencedEvent, "op_Explicit").WithArguments("D4.op_Explicit"),
                // (42,32): warning CS0067: The event 'D4.op_UnaryPlus' is never used
                //     public event System.Action op_UnaryPlus;//
                Diagnostic(ErrorCode.WRN_UnreferencedEvent, "op_UnaryPlus").WithArguments("D4.op_UnaryPlus"),
                // (44,32): warning CS0067: The event 'D4.Finalize' is never used
                //     public event System.Action Finalize;
                Diagnostic(ErrorCode.WRN_UnreferencedEvent, "Finalize").WithArguments("D4.Finalize"),

                // (72,24): warning CS0465: Introducing a 'Finalize' method can interfere with destructor invocation. Did you intend to declare a destructor?
                //     public static void Finalize() { }
                Diagnostic(ErrorCode.WRN_FinalizeMethod, "Finalize"),
                // (65,17): warning CS0465: Introducing a 'Finalize' method can interfere with destructor invocation. Did you intend to declare a destructor?
                //     public void Finalize() { }
                Diagnostic(ErrorCode.WRN_FinalizeMethod, "Finalize"));
        }

        [Fact, WorkItem(546836, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546836")]
        public void HideDestructorOperatorConversion2()
        {
            var source = @"
public class B
{
    public static int operator +(B b)
    {
        return 0;
    }

    public static explicit operator int(B b)
    {
        return 0;
    }

    ~B()
    {
    }
}

public class D1 : B
{
    new public class op_UnaryPlus { } //CS0109
    new public class op_Explicit { } //CS0109
    new public class Finalize { } //CS0109
}

public class D2 : B
{
    new public int op_UnaryPlus { get; set; } //CS0109
    new public int op_Explicit { get; set; } //CS0109
    new public int Finalize { get; set; } //CS0109
}

public class D3 : B
{
    new public int op_UnaryPlus = 1;
    new public int op_Explicit = 1;
    new public int Finalize = 1; //CS0109
}

public class D4 : B
{
    new public event System.Action op_UnaryPlus;
    new public event System.Action op_Explicit;
    new public event System.Action Finalize; //CS0109
}

public class D5 : B
{
    new public event System.Action op_UnaryPlus { add { } remove { } }
    new public event System.Action op_Explicit { add { } remove { } }
    new public event System.Action Finalize { add { } remove { } } //CS0109
}

public class D6 : B
{
    new public delegate void op_UnaryPlus(); //CS0109
    new public delegate void op_Explicit(); //CS0109
    new public delegate void Finalize(); //CS0109
}

public class D7 : B
{
    new public void op_UnaryPlus(B b) { } //CS0109
    new public void op_Explicit(B b) { } //CS0109
    new public void Finalize() { } //CS0109
}

public class D8 : B
{
    new public static int op_UnaryPlus(B b) { return 0; } //CS0109
    new public static int op_Explicit(B b) { return 0; } //CS0109
    new public static void Finalize() { } //CS0109
}
";

            CreateCompilation(source).VerifyDiagnostics(
                // (23,22): warning CS0109: The member 'D1.Finalize' does not hide an accessible member. The new keyword is not required.
                //     new public class Finalize { } //CS0109
                Diagnostic(ErrorCode.WRN_NewNotRequired, "Finalize").WithArguments("D1.Finalize"),
                // (21,22): warning CS0109: The member 'D1.op_UnaryPlus' does not hide an accessible member. The new keyword is not required.
                //     new public class op_UnaryPlus { } //CS0109
                Diagnostic(ErrorCode.WRN_NewNotRequired, "op_UnaryPlus").WithArguments("D1.op_UnaryPlus"),
                // (22,22): warning CS0109: The member 'D1.op_Explicit' does not hide an accessible member. The new keyword is not required.
                //     new public class op_Explicit { } //CS0109
                Diagnostic(ErrorCode.WRN_NewNotRequired, "op_Explicit").WithArguments("D1.op_Explicit"),
                // (58,30): warning CS0109: The member 'D6.Finalize' does not hide an accessible member. The new keyword is not required.
                //     new public delegate void Finalize(); //CS0109
                Diagnostic(ErrorCode.WRN_NewNotRequired, "Finalize").WithArguments("D6.Finalize"),
                // (56,30): warning CS0109: The member 'D6.op_UnaryPlus' does not hide an accessible member. The new keyword is not required.
                //     new public delegate void op_UnaryPlus(); //CS0109
                Diagnostic(ErrorCode.WRN_NewNotRequired, "op_UnaryPlus").WithArguments("D6.op_UnaryPlus"),
                // (57,30): warning CS0109: The member 'D6.op_Explicit' does not hide an accessible member. The new keyword is not required.
                //     new public delegate void op_Explicit(); //CS0109
                Diagnostic(ErrorCode.WRN_NewNotRequired, "op_Explicit").WithArguments("D6.op_Explicit"),
                // (37,20): warning CS0109: The member 'D3.Finalize' does not hide an accessible member. The new keyword is not required.
                //     new public int Finalize = 1; //CS0109
                Diagnostic(ErrorCode.WRN_NewNotRequired, "Finalize").WithArguments("D3.Finalize"),
                // (51,36): warning CS0109: The member 'D5.Finalize' does not hide an accessible member. The new keyword is not required.
                //     new public event System.Action Finalize { add { } remove { } } //CS0109
                Diagnostic(ErrorCode.WRN_NewNotRequired, "Finalize").WithArguments("D5.Finalize"),
                // (71,27): warning CS0109: The member 'D8.op_Explicit(B)' does not hide an accessible member. The new keyword is not required.
                //     new public static int op_Explicit(B b) { return 0; } //CS0109
                Diagnostic(ErrorCode.WRN_NewNotRequired, "op_Explicit").WithArguments("D8.op_Explicit(B)"),
                // (72,28): warning CS0109: The member 'D8.Finalize()' does not hide an accessible member. The new keyword is not required.
                //     new public static void Finalize() { } //CS0109
                Diagnostic(ErrorCode.WRN_NewNotRequired, "Finalize").WithArguments("D8.Finalize()"),
                // (70,27): warning CS0109: The member 'D8.op_UnaryPlus(B)' does not hide an accessible member. The new keyword is not required.
                //     new public static int op_UnaryPlus(B b) { return 0; } //CS0109
                Diagnostic(ErrorCode.WRN_NewNotRequired, "op_UnaryPlus").WithArguments("D8.op_UnaryPlus(B)"),
                // (44,36): warning CS0109: The member 'D4.Finalize' does not hide an accessible member. The new keyword is not required.
                //     new public event System.Action Finalize; //CS0109
                Diagnostic(ErrorCode.WRN_NewNotRequired, "Finalize").WithArguments("D4.Finalize"),
                // (64,21): warning CS0109: The member 'D7.op_Explicit(B)' does not hide an accessible member. The new keyword is not required.
                //     new public void op_Explicit(B b) { } //CS0109
                Diagnostic(ErrorCode.WRN_NewNotRequired, "op_Explicit").WithArguments("D7.op_Explicit(B)"),
                // (65,21): warning CS0109: The member 'D7.Finalize()' does not hide an accessible member. The new keyword is not required.
                //     new public void Finalize() { } //CS0109
                Diagnostic(ErrorCode.WRN_NewNotRequired, "Finalize").WithArguments("D7.Finalize()"),
                // (63,21): warning CS0109: The member 'D7.op_UnaryPlus(B)' does not hide an accessible member. The new keyword is not required.
                //     new public void op_UnaryPlus(B b) { } //CS0109
                Diagnostic(ErrorCode.WRN_NewNotRequired, "op_UnaryPlus").WithArguments("D7.op_UnaryPlus(B)"),
                // (29,20): warning CS0109: The member 'D2.op_Explicit' does not hide an accessible member. The new keyword is not required.
                //     new public int op_Explicit { get; set; } //CS0109
                Diagnostic(ErrorCode.WRN_NewNotRequired, "op_Explicit").WithArguments("D2.op_Explicit"),
                // (30,20): warning CS0109: The member 'D2.Finalize' does not hide an accessible member. The new keyword is not required.
                //     new public int Finalize { get; set; } //CS0109
                Diagnostic(ErrorCode.WRN_NewNotRequired, "Finalize").WithArguments("D2.Finalize"),
                // (28,20): warning CS0109: The member 'D2.op_UnaryPlus' does not hide an accessible member. The new keyword is not required.
                //     new public int op_UnaryPlus { get; set; } //CS0109
                Diagnostic(ErrorCode.WRN_NewNotRequired, "op_UnaryPlus").WithArguments("D2.op_UnaryPlus"),

                // (44,36): warning CS0067: The event 'D4.Finalize' is never used
                //     new public event System.Action Finalize; //CS0109
                Diagnostic(ErrorCode.WRN_UnreferencedEvent, "Finalize").WithArguments("D4.Finalize"),
                // (42,36): warning CS0067: The event 'D4.op_UnaryPlus' is never used
                //     new public event System.Action op_UnaryPlus;
                Diagnostic(ErrorCode.WRN_UnreferencedEvent, "op_UnaryPlus").WithArguments("D4.op_UnaryPlus"),
                // (43,36): warning CS0067: The event 'D4.op_Explicit' is never used
                //     new public event System.Action op_Explicit;
                Diagnostic(ErrorCode.WRN_UnreferencedEvent, "op_Explicit").WithArguments("D4.op_Explicit"),

                // (72,28): warning CS0465: Introducing a 'Finalize' method can interfere with destructor invocation. Did you intend to declare a destructor?
                //     new public static void Finalize() { } //CS0109
                Diagnostic(ErrorCode.WRN_FinalizeMethod, "Finalize"),
                // (65,21): warning CS0465: Introducing a 'Finalize' method can interfere with destructor invocation. Did you intend to declare a destructor?
                //     new public void Finalize() { } //CS0109
                Diagnostic(ErrorCode.WRN_FinalizeMethod, "Finalize"));
        }

        [Fact]
        [WorkItem(661370, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/661370")]
        public void HideAndOverride1()
        {
            var source = @"
public class Base
{
    public virtual void M() { }
    public virtual int M { get; set; } // NOTE: illegal, since there's already a method M.
}

public class Derived1 : Base
{
    public override void M() { }
}

public class Derived2 : Base
{
    public override int M { get; set; }
}
";
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics(
                // (5,16): error CS0102: The type 'Base' already contains a definition for 'M'
                //     public int M; // NOTE: illegal, since there's already a method M.
                Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "M").WithArguments("Base", "M"));

            var global = comp.GlobalNamespace;

            var baseClass = global.GetMember<NamedTypeSymbol>("Base");
            var baseMethod = baseClass.GetMembers("M").OfType<MethodSymbol>().Single();
            var baseProperty = baseClass.GetMembers("M").OfType<PropertySymbol>().Single();

            var derivedClass1 = global.GetMember<NamedTypeSymbol>("Derived1");
            var derivedMethod = derivedClass1.GetMember<MethodSymbol>("M");

            var overriddenOrHidden1 = derivedMethod.OverriddenOrHiddenMembers;
            Assert.Equal(baseMethod, overriddenOrHidden1.OverriddenMembers.Single());
            Assert.Equal(baseProperty, overriddenOrHidden1.HiddenMembers.Single());

            var derivedClass2 = global.GetMember<NamedTypeSymbol>("Derived2");
            var derivedProperty = derivedClass2.GetMember<PropertySymbol>("M");

            var overriddenOrHidden2 = derivedProperty.OverriddenOrHiddenMembers;
            Assert.Equal(baseProperty, overriddenOrHidden2.OverriddenMembers.Single());
            Assert.Equal(baseMethod, overriddenOrHidden2.HiddenMembers.Single());
        }

        [Fact]
        [WorkItem(743241, "DevDiv")]
        public void OverrideNonObjectEquals()
        {
            var source = @"
class Base
{
    public new virtual bool Equals(object obj)
    {
        return base.Equals(obj);
    }
}

class Derived : Base
{
    public override bool Equals(object obj)
    {
        return base.Equals(obj);
    }
}";

            // Dev11 spuriously reports WRN_EqualsWithoutGetHashCode.
            CreateCompilation(source).VerifyDiagnostics();
        }

        [Fact]
        [WorkItem(6148, "https://github.com/dotnet/roslyn/issues/6148")]
        public void AbstractGenericBase_01()
        {
            var text = @"
class C
{
    public static void Main()
    {
        var t = new Required();
        t.Test1(null);
        t.Test2(null);
    }
}

public abstract class Validator
{
    public abstract void DoValidate(object objectToValidate);

    public void Test1(object objectToValidate)
    {
         DoValidate(objectToValidate);
    }
}

public abstract class Validator<T> : Validator
{
    public override void DoValidate(object objectToValidate)
    {
        System.Console.WriteLine(""void Validator<T>.DoValidate(object objectToValidate)"");
    }

    protected abstract void DoValidate(T objectToValidate);

    public void Test2(T objectToValidate)
    {
         DoValidate(objectToValidate);
    }
}

public abstract class ValidatorBase<T> : Validator<T>
{
    protected override void DoValidate(T objectToValidate)
    {
        System.Console.WriteLine(""void ValidatorBase<T>.DoValidate(T objectToValidate)"");
    }
}

public class Required : ValidatorBase<object>
{
}
";
            var compilation = CreateCompilation(text, options: TestOptions.ReleaseExe);

            var validatorBaseT = compilation.GetTypeByMetadataName("ValidatorBase`1");
            var doValidateT = validatorBaseT.GetMember<MethodSymbol>("DoValidate");

            Assert.Equal(1, doValidateT.OverriddenOrHiddenMembers.OverriddenMembers.Length);
            Assert.Equal("void Validator<T>.DoValidate(T objectToValidate)", doValidateT.OverriddenMethod.ToTestDisplayString());
            Assert.False(validatorBaseT.AbstractMembers.Any());

            var validatorBaseObject = validatorBaseT.Construct(compilation.ObjectType);
            var doValidateObject = validatorBaseObject.GetMember<MethodSymbol>("DoValidate");

            Assert.Equal(2, doValidateObject.OverriddenOrHiddenMembers.OverriddenMembers.Length);
            Assert.Equal("void Validator<T>.DoValidate(T objectToValidate)", doValidateObject.OverriddenMethod.OriginalDefinition.ToTestDisplayString());
            Assert.False(validatorBaseObject.AbstractMembers.Any());

            CompileAndVerify(compilation, expectedOutput: @"void Validator<T>.DoValidate(object objectToValidate)
void ValidatorBase<T>.DoValidate(T objectToValidate)");
        }

        [Fact]
        [WorkItem(6148, "https://github.com/dotnet/roslyn/issues/6148")]
        public void AbstractGenericBase_02()
        {
            var text = @"
class C
{
    public static void Main()
    {
        var t = new Required();
        t.Test1(null);
        t.Test2(null);
    }
}

public abstract class Validator
{
    public abstract void DoValidate(object objectToValidate);

    public void Test1(object objectToValidate)
    {
         DoValidate(objectToValidate);
    }
}

public abstract class Validator<T> : Validator
{
    public abstract override void DoValidate(object objectToValidate);

    public virtual void DoValidate(T objectToValidate)
    {
        System.Console.WriteLine(""void Validator<T>.DoValidate(T objectToValidate)"");
    }

    public void Test2(T objectToValidate)
    {
         DoValidate(objectToValidate);
    }
}


public abstract class ValidatorBase<T> : Validator<T>
{
    public override void DoValidate(T objectToValidate)
    {
        System.Console.WriteLine(""void ValidatorBase<T>.DoValidate(T objectToValidate)"");
    }
}

public class Required : ValidatorBase<object>
{
}";
            var compilation = CreateCompilation(text, options: TestOptions.ReleaseExe);

            compilation.VerifyDiagnostics(
        // (46,14): error CS0534: 'Required' does not implement inherited abstract member 'Validator<object>.DoValidate(object)'
        // public class Required : ValidatorBase<object>
        Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "Required").WithArguments("Required", "Validator<object>.DoValidate(object)").WithLocation(46, 14)
                );
        }

        [Fact]
        [WorkItem(6148, "https://github.com/dotnet/roslyn/issues/6148")]
        public void AbstractGenericBase_03()
        {
            var text = @"
class C
{
    public static void Main()
    {
        var t = new Required();
        t.Test1(null);
        t.Test2(null);
    }
}

public abstract class Validator0<T>
{
    public abstract void DoValidate(T objectToValidate);

    public void Test2(T objectToValidate)
    {
         DoValidate(objectToValidate);
    }
}

public abstract class Validator<T> : Validator0<T>
{
    public virtual void DoValidate(object objectToValidate)
    {
        System.Console.WriteLine(""void Validator<T>.DoValidate(object objectToValidate)"");
    }

    public void Test1(object objectToValidate)
    {
         DoValidate(objectToValidate);
    }
}


public abstract class ValidatorBase<T> : Validator<T>
{
    public override void DoValidate(T objectToValidate)
    {
        System.Console.WriteLine(""void ValidatorBase<T>.DoValidate(T objectToValidate)"");
    }
}

public class Required : ValidatorBase<object>
{
}
";
            var compilation = CreateCompilation(text, options: TestOptions.ReleaseExe);

            CompileAndVerify(compilation, expectedOutput: @"void Validator<T>.DoValidate(object objectToValidate)
void ValidatorBase<T>.DoValidate(T objectToValidate)");
        }

        [Fact]
        [WorkItem(6148, "https://github.com/dotnet/roslyn/issues/6148")]
        public void AbstractGenericBase_04()
        {
            var text = @"
class C
{
    public static void Main()
    {
        var t = new Required();
        Test1(t);
        Test2(t, null);
    }

    static void Test1(Validator v)
    {
        v.Test1(null);
    }

    static void Test2<T>(Validator<T> v, T o)
    {
        v.Test2(o);
    }
}

public abstract class Validator
{
    public abstract void DoValidate(object objectToValidate);

    public void Test1(object objectToValidate)
    {
         DoValidate(objectToValidate);
    }
}

public abstract class Validator<T> : Validator
{
    public virtual void DoValidate(T objectToValidate)
    {
        System.Console.WriteLine(""void Validator<T>.DoValidate(T objectToValidate)"");
    }

    public void Test2(T objectToValidate)
    {
         DoValidate(objectToValidate);
    }
}

public abstract class ValidatorBase<T> : Validator<T>
{
    public override void DoValidate(object objectToValidate)
    {
        System.Console.WriteLine(""void ValidatorBase<T>.DoValidate(object objectToValidate)"");
    }
}

public class Required : ValidatorBase<object>
{
}
";
            var compilation = CreateCompilation(text, options: TestOptions.ReleaseExe);

            CompileAndVerify(compilation, expectedOutput: @"void ValidatorBase<T>.DoValidate(object objectToValidate)
void Validator<T>.DoValidate(T objectToValidate)");
        }

        [Fact]
        [WorkItem(6148, "https://github.com/dotnet/roslyn/issues/6148")]
        public void AbstractGenericBase_05()
        {
            var text = @"
class C
{
    public static void Main()
    {
        var t = new Required();
        t.Test1(null);
        t.Test2(null);
    }
}

public abstract class Validator0<T>
{
    public abstract void DoValidate(object objectToValidate);

    public void Test1(object objectToValidate)
    {
         DoValidate(objectToValidate);
    }
}

public abstract class Validator<T> : Validator0<int>
{
    public override void DoValidate(object objectToValidate)
    {
        System.Console.WriteLine(""void Validator<T>.DoValidate(object objectToValidate)"");
    }

    protected abstract void DoValidate(T objectToValidate);

    public void Test2(T objectToValidate)
    {
         DoValidate(objectToValidate);
    }
}

public abstract class ValidatorBase<T> : Validator<T>
{
    protected override void DoValidate(T objectToValidate)
    {
        System.Console.WriteLine(""void ValidatorBase<T>.DoValidate(T objectToValidate)"");
    }
}

public class Required : ValidatorBase<object>
{
}
";
            var compilation = CreateCompilation(text, options: TestOptions.ReleaseExe);

            var validatorBaseT = compilation.GetTypeByMetadataName("ValidatorBase`1");
            var doValidateT = validatorBaseT.GetMember<MethodSymbol>("DoValidate");

            Assert.Equal(1, doValidateT.OverriddenOrHiddenMembers.OverriddenMembers.Length);
            Assert.Equal("void Validator<T>.DoValidate(T objectToValidate)", doValidateT.OverriddenMethod.ToTestDisplayString());
            Assert.False(validatorBaseT.AbstractMembers.Any());

            var validatorBaseObject = validatorBaseT.Construct(compilation.ObjectType);
            var doValidateObject = validatorBaseObject.GetMember<MethodSymbol>("DoValidate");

            Assert.Equal(2, doValidateObject.OverriddenOrHiddenMembers.OverriddenMembers.Length);
            Assert.Equal("void Validator<T>.DoValidate(T objectToValidate)", doValidateObject.OverriddenMethod.OriginalDefinition.ToTestDisplayString());
            Assert.False(validatorBaseObject.AbstractMembers.Any());

            CompileAndVerify(compilation, expectedOutput: @"void Validator<T>.DoValidate(object objectToValidate)
void ValidatorBase<T>.DoValidate(T objectToValidate)");
        }

        #endregion

        [Fact]
        [CompilerTrait(CompilerFeature.ReadOnlyReferences)]
        public void HidingMethodWithInParameter()
        {
            var code = @"
class A
{
    public void M(in int x) { }
}
class B : A
{
    public void M(in int x) { }
}";

            var comp = CreateCompilation(code).VerifyDiagnostics(
                // (8,17): warning CS0108: 'B.M(in int)' hides inherited member 'A.M(in int)'. Use the new keyword if hiding was intended.
                //     public void M(in int x) { }
                Diagnostic(ErrorCode.WRN_NewRequired, "M").WithArguments("B.M(in int)", "A.M(in int)").WithLocation(8, 17));

            var aMethod = comp.GetMember<MethodSymbol>("A.M");
            var bMethod = comp.GetMember<MethodSymbol>("B.M");

            Assert.Empty(aMethod.OverriddenOrHiddenMembers.OverriddenMembers);
            Assert.Empty(aMethod.OverriddenOrHiddenMembers.HiddenMembers);

            Assert.Empty(bMethod.OverriddenOrHiddenMembers.OverriddenMembers);
            Assert.Equal(aMethod, bMethod.OverriddenOrHiddenMembers.HiddenMembers.Single());
        }

        [Fact]
        [CompilerTrait(CompilerFeature.ReadOnlyReferences)]
        public void HidingMethodWithRefReadOnlyReturnType_RefReadOnly_RefReadOnly()
        {
            var code = @"
class A
{
    protected int x = 0;
    public ref readonly int M() { return ref x; }
}
class B : A
{
    public ref readonly int M() { return ref x; }
}";

            var comp = CreateCompilation(code).VerifyDiagnostics(
                // (9,29): warning CS0108: 'B.M()' hides inherited member 'A.M()'. Use the new keyword if hiding was intended.
                //     public ref readonly int M() { return ref x; }
                Diagnostic(ErrorCode.WRN_NewRequired, "M").WithArguments("B.M()", "A.M()").WithLocation(9, 29));

            var aMethod = comp.GetMember<MethodSymbol>("A.M");
            var bMethod = comp.GetMember<MethodSymbol>("B.M");

            Assert.Empty(aMethod.OverriddenOrHiddenMembers.OverriddenMembers);
            Assert.Empty(aMethod.OverriddenOrHiddenMembers.HiddenMembers);

            Assert.Empty(bMethod.OverriddenOrHiddenMembers.OverriddenMembers);
            Assert.Equal(aMethod, bMethod.OverriddenOrHiddenMembers.HiddenMembers.Single());
        }

        [Fact]
        [CompilerTrait(CompilerFeature.ReadOnlyReferences)]
        public void HidingMethodWithRefReadOnlyReturnType_Ref_RefReadOnly()
        {
            var code = @"
class A
{
    protected int x = 0;
    public ref int M() { return ref x; }
}
class B : A
{
    public ref readonly int M() { return ref x; }
}";

            var comp = CreateCompilation(code).VerifyDiagnostics(
                // (9,29): warning CS0108: 'B.M()' hides inherited member 'A.M()'. Use the new keyword if hiding was intended.
                //     public ref readonly int M() { return ref x; }
                Diagnostic(ErrorCode.WRN_NewRequired, "M").WithArguments("B.M()", "A.M()").WithLocation(9, 29));

            var aMethod = comp.GetMember<MethodSymbol>("A.M");
            var bMethod = comp.GetMember<MethodSymbol>("B.M");

            Assert.Empty(aMethod.OverriddenOrHiddenMembers.OverriddenMembers);
            Assert.Empty(aMethod.OverriddenOrHiddenMembers.HiddenMembers);

            Assert.Empty(bMethod.OverriddenOrHiddenMembers.OverriddenMembers);
            Assert.Equal(aMethod, bMethod.OverriddenOrHiddenMembers.HiddenMembers.Single());
        }

        [Fact]
        [CompilerTrait(CompilerFeature.ReadOnlyReferences)]
        public void HidingMethodWithRefReadOnlyReturnType_RefReadOnly_Ref()
        {
            var code = @"
class A
{
    protected int x = 0;
    public ref readonly int M() { return ref x; }
}
class B : A
{
    public ref int M() { return ref x; }
}";

            var comp = CreateCompilation(code).VerifyDiagnostics(
                // (9,20): warning CS0108: 'B.M()' hides inherited member 'A.M()'. Use the new keyword if hiding was intended.
                //     public ref int M() { return ref x; }
                Diagnostic(ErrorCode.WRN_NewRequired, "M").WithArguments("B.M()", "A.M()").WithLocation(9, 20));

            var aMethod = comp.GetMember<MethodSymbol>("A.M");
            var bMethod = comp.GetMember<MethodSymbol>("B.M");

            Assert.Empty(aMethod.OverriddenOrHiddenMembers.OverriddenMembers);
            Assert.Empty(aMethod.OverriddenOrHiddenMembers.HiddenMembers);

            Assert.Empty(bMethod.OverriddenOrHiddenMembers.OverriddenMembers);
            Assert.Equal(aMethod, bMethod.OverriddenOrHiddenMembers.HiddenMembers.Single());
        }

        [Fact]
        [CompilerTrait(CompilerFeature.ReadOnlyReferences)]
        public void HidingPropertyWithRefReadOnlyReturnType_RefReadOnly_RefReadOnly()
        {
            var code = @"
class A
{
    protected int x = 0;
    public ref readonly int Property { get { return ref x; } }
}
class B : A
{
    public ref readonly int Property { get { return ref x; } }
}";

            var comp = CreateCompilation(code).VerifyDiagnostics(
                // (9,29): warning CS0108: 'B.Property' hides inherited member 'A.Property'. Use the new keyword if hiding was intended.
                //     public ref readonly int Property { get { return ref x; } }
                Diagnostic(ErrorCode.WRN_NewRequired, "Property").WithArguments("B.Property", "A.Property").WithLocation(9, 29));

            var aProperty = comp.GetMember<PropertySymbol>("A.Property");
            var bProperty = comp.GetMember<PropertySymbol>("B.Property");

            Assert.Empty(aProperty.OverriddenOrHiddenMembers.OverriddenMembers);
            Assert.Empty(aProperty.OverriddenOrHiddenMembers.HiddenMembers);

            Assert.Empty(bProperty.OverriddenOrHiddenMembers.OverriddenMembers);
            Assert.Equal(aProperty, bProperty.OverriddenOrHiddenMembers.HiddenMembers.Single());
        }

        [Fact]
        [CompilerTrait(CompilerFeature.ReadOnlyReferences)]
        public void HidingPropertyWithRefReadOnlyReturnType_RefReadOnly_Ref()
        {
            var code = @"
class A
{
    protected int x = 0;
    public ref readonly int Property { get { return ref x; } }
}
class B : A
{
    public ref int Property { get { return ref x; } }
}";

            var comp = CreateCompilation(code).VerifyDiagnostics(
                // (9,20): warning CS0108: 'B.Property' hides inherited member 'A.Property'. Use the new keyword if hiding was intended.
                //     public ref int Property { get { return ref x; } }
                Diagnostic(ErrorCode.WRN_NewRequired, "Property").WithArguments("B.Property", "A.Property").WithLocation(9, 20));

            var aProperty = comp.GetMember<PropertySymbol>("A.Property");
            var bProperty = comp.GetMember<PropertySymbol>("B.Property");

            Assert.Empty(aProperty.OverriddenOrHiddenMembers.OverriddenMembers);
            Assert.Empty(aProperty.OverriddenOrHiddenMembers.HiddenMembers);

            Assert.Empty(bProperty.OverriddenOrHiddenMembers.OverriddenMembers);
            Assert.Equal(aProperty, bProperty.OverriddenOrHiddenMembers.HiddenMembers.Single());
        }

        [Fact]
        [CompilerTrait(CompilerFeature.ReadOnlyReferences)]
        public void HidingPropertyWithRefReadOnlyReturnType_Ref_RefReadOnly()
        {
            var code = @"
class A
{
    protected int x = 0;
    public ref int Property { get { return ref x; } }
}
class B : A
{
    public ref readonly int Property { get { return ref x; } }
}";

            var comp = CreateCompilation(code).VerifyDiagnostics(
                // (9,29): warning CS0108: 'B.Property' hides inherited member 'A.Property'. Use the new keyword if hiding was intended.
                //     public ref readonly int Property { get { return ref x; } }
                Diagnostic(ErrorCode.WRN_NewRequired, "Property").WithArguments("B.Property", "A.Property").WithLocation(9, 29));

            var aProperty = comp.GetMember<PropertySymbol>("A.Property");
            var bProperty = comp.GetMember<PropertySymbol>("B.Property");

            Assert.Empty(aProperty.OverriddenOrHiddenMembers.OverriddenMembers);
            Assert.Empty(aProperty.OverriddenOrHiddenMembers.HiddenMembers);

            Assert.Empty(bProperty.OverriddenOrHiddenMembers.OverriddenMembers);
            Assert.Equal(aProperty, bProperty.OverriddenOrHiddenMembers.HiddenMembers.Single());
        }

        [Fact]
        [CompilerTrait(CompilerFeature.ReadOnlyReferences)]
        public void HidingMethodWithInParameterAndNewKeyword()
        {
            var code = @"
class A
{
    public void M(in int x) { }
}
class B : A
{
    public new void M(in int x) { }
}";

            var comp = CreateCompilation(code).VerifyDiagnostics();

            var aMethod = comp.GetMember<MethodSymbol>("A.M");
            var bMethod = comp.GetMember<MethodSymbol>("B.M");

            Assert.Empty(aMethod.OverriddenOrHiddenMembers.OverriddenMembers);
            Assert.Empty(aMethod.OverriddenOrHiddenMembers.HiddenMembers);

            Assert.Empty(bMethod.OverriddenOrHiddenMembers.OverriddenMembers);
            Assert.Equal(aMethod, bMethod.OverriddenOrHiddenMembers.HiddenMembers.Single());
        }

        [Fact]
        [CompilerTrait(CompilerFeature.ReadOnlyReferences)]
        public void HidingMethodWithRefReadOnlyReturnTypeAndNewKeyword()
        {
            var code = @"
class A
{
    protected int x = 0;
    public ref readonly int M() { return ref x; }
}
class B : A
{
    public new ref readonly int M() { return ref x; }
}";

            var comp = CreateCompilation(code).VerifyDiagnostics();

            var aMethod = comp.GetMember<MethodSymbol>("A.M");
            var bMethod = comp.GetMember<MethodSymbol>("B.M");

            Assert.Empty(aMethod.OverriddenOrHiddenMembers.OverriddenMembers);
            Assert.Empty(aMethod.OverriddenOrHiddenMembers.HiddenMembers);

            Assert.Empty(bMethod.OverriddenOrHiddenMembers.OverriddenMembers);
            Assert.Equal(aMethod, bMethod.OverriddenOrHiddenMembers.HiddenMembers.Single());
        }

        [Fact]
        [CompilerTrait(CompilerFeature.ReadOnlyReferences)]
        public void HidingPropertyWithRefReadOnlyReturnTypeAndNewKeyword()
        {
            var code = @"
class A
{
    protected int x = 0;
    public ref readonly int Property { get { return ref x; } }
}
class B : A
{
    public new ref readonly int Property { get { return ref x; } }
}";

            var comp = CreateCompilation(code).VerifyDiagnostics();

            var aProperty = comp.GetMember<PropertySymbol>("A.Property");
            var bProperty = comp.GetMember<PropertySymbol>("B.Property");

            Assert.Empty(aProperty.OverriddenOrHiddenMembers.OverriddenMembers);
            Assert.Empty(aProperty.OverriddenOrHiddenMembers.HiddenMembers);

            Assert.Empty(bProperty.OverriddenOrHiddenMembers.OverriddenMembers);
            Assert.Equal(aProperty, bProperty.OverriddenOrHiddenMembers.HiddenMembers.Single());
        }

        [Fact]
        [CompilerTrait(CompilerFeature.ReadOnlyReferences)]
        public void OverridingMethodWithInParameter()
        {
            var code = @"
class A
{
    public virtual void M(in int x) { }
}
class B : A
{
    public override void M(in int x) { }
}";

            var comp = CreateCompilation(code).VerifyDiagnostics();

            var aMethod = comp.GetMember<MethodSymbol>("A.M");
            var bMethod = comp.GetMember<MethodSymbol>("B.M");

            Assert.Empty(aMethod.OverriddenOrHiddenMembers.OverriddenMembers);
            Assert.Empty(aMethod.OverriddenOrHiddenMembers.HiddenMembers);

            Assert.Equal(aMethod, bMethod.OverriddenOrHiddenMembers.OverriddenMembers.Single());
            Assert.Empty(bMethod.OverriddenOrHiddenMembers.HiddenMembers);
        }

        [Fact]
        [CompilerTrait(CompilerFeature.ReadOnlyReferences)]
        public void OverridingMethodWithRefReadOnlyReturnType()
        {
            var code = @"
class A
{
    protected int x = 0;
    public virtual ref readonly int M() { return ref x; }
}
class B : A
{
    public override ref readonly int M() { return ref x; }
}";

            var comp = CreateCompilation(code).VerifyDiagnostics();

            var aMethod = comp.GetMember<MethodSymbol>("A.M");
            var bMethod = comp.GetMember<MethodSymbol>("B.M");

            Assert.Empty(aMethod.OverriddenOrHiddenMembers.OverriddenMembers);
            Assert.Empty(aMethod.OverriddenOrHiddenMembers.HiddenMembers);

            Assert.Equal(aMethod, bMethod.OverriddenOrHiddenMembers.OverriddenMembers.Single());
            Assert.Empty(bMethod.OverriddenOrHiddenMembers.HiddenMembers);
        }

        [Fact]
        [CompilerTrait(CompilerFeature.ReadOnlyReferences)]
        public void OverridingPropertyWithRefReadOnlyReturnType()
        {
            var code = @"
class A
{
    protected int x = 0;
    public virtual ref readonly int Property { get { return ref x; } }
}
class B : A
{
    public override ref readonly int Property { get { return ref x; } }
}";

            var comp = CreateCompilation(code).VerifyDiagnostics();

            var aProperty = comp.GetMember<PropertySymbol>("A.Property");
            var bProperty = comp.GetMember<PropertySymbol>("B.Property");

            Assert.Empty(aProperty.OverriddenOrHiddenMembers.OverriddenMembers);
            Assert.Empty(aProperty.OverriddenOrHiddenMembers.HiddenMembers);

            Assert.Equal(aProperty, bProperty.OverriddenOrHiddenMembers.OverriddenMembers.Single());
            Assert.Empty(bProperty.OverriddenOrHiddenMembers.HiddenMembers);
        }

        [Fact]
        [CompilerTrait(CompilerFeature.ReadOnlyReferences)]
        public void DeclaringMethodWithDifferentParameterRefness()
        {
            var code = @"
class A
{
    public void M(in int x) { }
}
class B : A
{
    public void M(ref int x) { }
}";

            var comp = CreateCompilation(code).VerifyDiagnostics();

            var aMethod = comp.GetMember<MethodSymbol>("A.M");
            var bMethod = comp.GetMember<MethodSymbol>("B.M");

            Assert.NotEqual(aMethod, bMethod);

            Assert.Empty(aMethod.OverriddenOrHiddenMembers.OverriddenMembers);
            Assert.Empty(aMethod.OverriddenOrHiddenMembers.HiddenMembers);

            Assert.Empty(bMethod.OverriddenOrHiddenMembers.OverriddenMembers);
            Assert.Empty(bMethod.OverriddenOrHiddenMembers.HiddenMembers);
        }

        [Fact]
        [CompilerTrait(CompilerFeature.ReadOnlyReferences)]
        public void OverriddingRefReadOnlyMembersWillOverwriteTheCorrectSlot()
        {
            var text = @"
class BaseClass
{
    protected int field;
    public virtual ref readonly int Method1(in BaseClass a) { return ref field; }
    public virtual ref readonly int Property1 { get { return ref field; } }
    public virtual ref readonly int this[int a] { get { return ref field; } }
}

class DerivedClass : BaseClass
{
    public override ref readonly int Method1(in BaseClass a) { return ref field; }
    public override ref readonly int Property1 { get { return ref field; } }
    public override ref readonly int this[int a] { get { return ref field; } }
}";

            var comp = CreateCompilation(text).VerifyDiagnostics();

            var baseMethod = comp.GetMember<MethodSymbol>("BaseClass.Method1");
            var baseProperty = comp.GetMember<PropertySymbol>("BaseClass.Property1");
            var baseIndexer = comp.GetMember<PropertySymbol>("BaseClass.this[]");

            var derivedMethod = comp.GetMember<MethodSymbol>("DerivedClass.Method1");
            var derivedProperty = comp.GetMember<PropertySymbol>("DerivedClass.Property1");
            var derivedIndexer = comp.GetMember<PropertySymbol>("DerivedClass.this[]");

            Assert.Empty(baseMethod.OverriddenOrHiddenMembers.HiddenMembers);
            Assert.Empty(baseMethod.OverriddenOrHiddenMembers.OverriddenMembers);

            Assert.Empty(baseProperty.OverriddenOrHiddenMembers.HiddenMembers);
            Assert.Empty(baseProperty.OverriddenOrHiddenMembers.OverriddenMembers);

            Assert.Empty(baseIndexer.OverriddenOrHiddenMembers.HiddenMembers);
            Assert.Empty(baseIndexer.OverriddenOrHiddenMembers.OverriddenMembers);

            Assert.Empty(derivedMethod.OverriddenOrHiddenMembers.HiddenMembers);
            Assert.Equal(baseMethod, derivedMethod.OverriddenOrHiddenMembers.OverriddenMembers.Single());

            Assert.Empty(derivedProperty.OverriddenOrHiddenMembers.HiddenMembers);
            Assert.Equal(baseProperty, derivedProperty.OverriddenOrHiddenMembers.OverriddenMembers.Single());

            Assert.Empty(derivedIndexer.OverriddenOrHiddenMembers.HiddenMembers);
            Assert.Equal(baseIndexer, derivedIndexer.OverriddenOrHiddenMembers.OverriddenMembers.Single());
        }

        [Fact]
        [CompilerTrait(CompilerFeature.ReadOnlyReferences)]
        public void MethodOverloadsShouldPreserveReadOnlyRefnessInParameters()
        {
            var text = @"
abstract class BaseClass
{
    public virtual void Method1(ref int x) { }
    public virtual void Method2(in int x) { }
}
class ChildClass : BaseClass
{
    public override void Method1(in int x) { }
    public override void Method2(ref int x) { }
}";

            var comp = CreateCompilation(text).VerifyDiagnostics(
                // (10,26): error CS0115: 'ChildClass.Method2(ref int)': no suitable method found to override
                //     public override void Method2(ref int x) { }
                Diagnostic(ErrorCode.ERR_OverrideNotExpected, "Method2").WithArguments("ChildClass.Method2(ref int)").WithLocation(10, 26),
                // (9,26): error CS0115: 'ChildClass.Method1(in int)': no suitable method found to override
                //     public override void Method1(in int x) { }
                Diagnostic(ErrorCode.ERR_OverrideNotExpected, "Method1").WithArguments("ChildClass.Method1(in int)").WithLocation(9, 26));
        }

        [Fact]
        [CompilerTrait(CompilerFeature.ReadOnlyReferences)]
        public void MethodOverloadsShouldPreserveReadOnlyRefnessInReturnTypes()
        {
            var text = @"
abstract class BaseClass
{
    protected int x = 0 ;
    public virtual ref int Method1() { return ref x; }
    public virtual ref readonly int Method2() { return ref x; }
}
class ChildClass : BaseClass
{
    public override ref readonly int Method1() { return ref x; }
    public override ref int Method2() { return ref x; }
}";

            var comp = CreateCompilation(text).VerifyDiagnostics(
                // (11,29): error CS8148: 'ChildClass.Method2()' must match by reference return of overridden member 'BaseClass.Method2()'
                //     public override ref int Method2() { return ref x; }
                Diagnostic(ErrorCode.ERR_CantChangeRefReturnOnOverride, "Method2").WithArguments("ChildClass.Method2()", "BaseClass.Method2()").WithLocation(11, 29),
                // (10,38): error CS8148: 'ChildClass.Method1()' must match by reference return of overridden member 'BaseClass.Method1()'
                //     public override in int Method1() { return ref x; }
                Diagnostic(ErrorCode.ERR_CantChangeRefReturnOnOverride, "Method1").WithArguments("ChildClass.Method1()", "BaseClass.Method1()").WithLocation(10, 38));
        }

        [Fact]
        [CompilerTrait(CompilerFeature.ReadOnlyReferences)]
        public void PropertyOverloadsShouldPreserveReadOnlyRefnessInReturnTypes()
        {
            var code = @"
class A
{
    protected int x = 0;
    public virtual ref int Property1 { get { return ref x; } }
    public virtual ref readonly int Property2 { get { return ref x; } }
}
class B : A
{
    public override ref readonly int Property1 { get { return ref x; } }
    public override ref int Property2 { get { return ref x; } }
}";

            var comp = CreateCompilation(code).VerifyDiagnostics(
                // (11,29): error CS8148: 'B.Property2' must match by reference return of overridden member 'A.Property2'
                //     public override ref int Property2 { get { return ref x; } }
                Diagnostic(ErrorCode.ERR_CantChangeRefReturnOnOverride, "Property2").WithArguments("B.Property2", "A.Property2").WithLocation(11, 29),
                // (10,38): error CS8148: 'B.Property1' must match by reference return of overridden member 'A.Property1'
                //     public override ref readonly int Property1 { get { return ref x; } }
                Diagnostic(ErrorCode.ERR_CantChangeRefReturnOnOverride, "Property1").WithArguments("B.Property1", "A.Property1").WithLocation(10, 38));
        }

        [Fact]
        [CompilerTrait(CompilerFeature.ReadOnlyReferences)]
        public void IndexerOverloadsShouldPreserveReadOnlyRefnessInReturnTypes_Ref_RefReadOnly()
        {
            var code = @"
class A
{
    protected int x = 0;
    public virtual ref int this[int p] { get { return ref x; } }
}
class B : A
{
    public override ref readonly int this[int p] { get { return ref x; } }
}";

            var comp = CreateCompilation(code).VerifyDiagnostics(
                // (9,38): error CS8148: 'B.this[int]' must match by reference return of overridden member 'A.this[int]'
                //     public override ref readonly int this[int p] { get { return ref x; } }
                Diagnostic(ErrorCode.ERR_CantChangeRefReturnOnOverride, "this").WithArguments("B.this[int]", "A.this[int]").WithLocation(9, 38));
        }

        [Fact]
        [CompilerTrait(CompilerFeature.ReadOnlyReferences)]
        public void IndexerOverloadsShouldPreserveReadOnlyRefnessInReturnTypes_RefReadOnly_Ref()
        {
            var code = @"
class A
{
    protected int x = 0;
    public virtual ref readonly int this[int p] { get { return ref x; } }
}
class B : A
{
    public override ref int this[int p] { get { return ref x; } }
}";

            var comp = CreateCompilation(code).VerifyDiagnostics(
                // (9,29): error CS8148: 'B.this[int]' must match by reference return of overridden member 'A.this[int]'
                //     public override ref int this[int p] { get { return ref x; } }
                Diagnostic(ErrorCode.ERR_CantChangeRefReturnOnOverride, "this").WithArguments("B.this[int]", "A.this[int]").WithLocation(9, 29));
        }

        [Fact]
        [CompilerTrait(CompilerFeature.ReadOnlyReferences)]
        public void IndexerOverloadsShouldPreserveReadOnlyRefnessInIndexes_Valid()
        {
            var code = @"
abstract class A
{
    public abstract int this[in int p] { get; }
}
class B : A
{
    public override int this[in int p] { get { return p; } }
}";

            var comp = CreateCompilation(code).VerifyDiagnostics();
        }

        [Fact]
        [CompilerTrait(CompilerFeature.ReadOnlyReferences)]
        public void IndexerOverloadsShouldPreserveReadOnlyRefnessInIndexes_Source()
        {
            var code = @"
abstract class A
{
    public abstract int this[in int p] { get; }
}
class B : A
{
    public override int this[int p] { get { return p; } }
}";

            var comp = CreateCompilation(code).VerifyDiagnostics(
                // (8,25): error CS0115: 'B.this[int]': no suitable method found to override
                //     public override int this[int p] { get { return p; } }
                Diagnostic(ErrorCode.ERR_OverrideNotExpected, "this").WithArguments("B.this[int]").WithLocation(8, 25),
                // (6,7): error CS0534: 'B' does not implement inherited abstract member 'A.this[in int].get'
                // class B : A
                Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "B").WithArguments("B", "A.this[in int].get").WithLocation(6, 7));
        }

        [Fact]
        [CompilerTrait(CompilerFeature.ReadOnlyReferences)]
        public void IndexerOverloadsShouldPreserveReadOnlyRefnessInIndexes_Destination()
        {
            var code = @"
abstract class A
{
    public abstract int this[int p] { get; }
}
class B : A
{
    public override int this[in int p] { get { return p; } }
}";

            var comp = CreateCompilation(code).VerifyDiagnostics(
                // (8,25): error CS0115: 'B.this[in int]': no suitable method found to override
                //     public override int this[in int p] { get { return p; } }
                Diagnostic(ErrorCode.ERR_OverrideNotExpected, "this").WithArguments("B.this[in int]").WithLocation(8, 25),
                // (6,7): error CS0534: 'B' does not implement inherited abstract member 'A.this[int].get'
                // class B : A
                Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "B").WithArguments("B", "A.this[int].get").WithLocation(6, 7));
        }
    }
}
