/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/CSharp/Test/Symbol/Symbols/InterfaceImplementationTests.cs
2 762 строки
96 KB
Jared Parsons
Do not use nint / nuint in IL baselines (#78246)
28 апр 2025, 22:12
Не верифицирован
28 апр 2025, 22:12
afb3565
Код
Авторство
О чём код?
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. #nullable disable using System; using System.Linq; using System.Threading; 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 { public class InterfaceImplementationTests : CSharpTestBase { /// <summary> /// Test the pre-checks performed by TypeSymbol.FindImplementationForInterfaceMember to /// short-circuit interface mapping. Should be the same for methods, properties, and /// events since it never gets to the interface mapping code. /// </summary> [Fact] public void TestObviousNulls() { var text = @" class Base { public void Method() { } public int Property { get { return 0; } } public int this[int x] { get { return 0; } } public event Delegate Event; public int Field; public interface Interface { } public class Class { } public struct Struct { } public enum Enum { Element } public delegate void Delegate(); } interface Interface { void Method(); } "; var comp = CreateCompilation(text); var global = comp.GlobalNamespace; var @base = (NamedTypeSymbol)global.GetMembers("Base").Single(); var baseMethod = @base.GetMembers("Method").Single(); Assert.Null(@base.FindImplementationForInterfaceMember(baseMethod)); //containing type is not an interface var baseProperty = @base.GetMember<PropertySymbol>("Property"); Assert.Null(@base.FindImplementationForInterfaceMember(baseProperty)); //containing type is not an interface var baseIndexer = @base.Indexers.Single(); Assert.Null(@base.FindImplementationForInterfaceMember(baseIndexer)); //containing type is not an interface var baseEvent = @base.GetMember<EventSymbol>("Event"); Assert.Null(@base.FindImplementationForInterfaceMember(baseEvent)); //containing type is not an interface var baseField = @base.GetMembers("Field").Single(); Assert.Null(@base.FindImplementationForInterfaceMember(baseField)); //not a method/property/event var baseNestedInterface = @base.GetMembers("Interface").Single(); Assert.Null(@base.FindImplementationForInterfaceMember(baseNestedInterface)); //not a method/property/event var baseNestedClass = @base.GetMembers("Class").Single(); Assert.Null(@base.FindImplementationForInterfaceMember(baseNestedClass)); //not a method/property/event var baseNestedStruct = @base.GetMembers("Struct").Single(); Assert.Null(@base.FindImplementationForInterfaceMember(baseNestedStruct)); //not a method/property/event var baseNestedEnum = @base.GetMembers("Enum").Single(); Assert.Null(@base.FindImplementationForInterfaceMember(baseNestedEnum)); //not a method/property/event var baseNestedDelegate = @base.GetMembers("Delegate").Single(); Assert.Null(@base.FindImplementationForInterfaceMember(baseNestedDelegate)); //not a method/property/event Assert.Throws<ArgumentNullException>(() => @base.FindImplementationForInterfaceMember(null)); //not a method/property/event var @interface = (NamedTypeSymbol)global.GetMembers("Interface").Single(); var interfaceMethod = @base.GetMembers("Method").Single(); Assert.Null(@interface.FindImplementationForInterfaceMember(interfaceMethod)); //type is not a class or struct Assert.Null(@interface.FindImplementationForInterfaceMember(@interface)); //symbol containing type is null } /// <summary> /// 1) Explicit implementation beats implicit implementation. /// 2) Explicit implementation of a declared interface's base interface. /// 3) Explicit implementation of a hidden interface method. /// </summary> [Fact] public void TestExplicitMethodImplementation() { var text = @" interface BaseInterface { void Method(); } interface Interface : BaseInterface { new void Method(); } class Class : Interface { void BaseInterface.Method() { } void Interface.Method() { } public void Method() { } } "; var comp = CreateCompilation(text); var global = comp.GlobalNamespace; var baseInterface = (NamedTypeSymbol)global.GetMembers("BaseInterface").Single(); var baseInterfaceMethod = baseInterface.GetMembers("Method").Single(); var @interface = (NamedTypeSymbol)global.GetMembers("Interface").Single(); var interfaceMethod = @interface.GetMembers("Method").Single(); var @class = (NamedTypeSymbol)global.GetMembers("Class").Single(); var classExplicitImplementationBase = (MethodSymbol)@class.GetMembers("BaseInterface.Method").Single(); Assert.Equal(MethodKind.ExplicitInterfaceImplementation, classExplicitImplementationBase.MethodKind); var classExplicitImplementation = (MethodSymbol)@class.GetMembers("Interface.Method").Single(); Assert.Equal(MethodKind.ExplicitInterfaceImplementation, classExplicitImplementation.MethodKind); var classImplicitImplementation = (MethodSymbol)@class.GetMembers("Method").Single(); Assert.Equal(MethodKind.Ordinary, classImplicitImplementation.MethodKind); Assert.NotSame(classImplicitImplementation, classExplicitImplementation); Assert.NotSame(classImplicitImplementation, classExplicitImplementationBase); var implementingMethodBase = @class.FindImplementationForInterfaceMember(baseInterfaceMethod); Assert.Same(classExplicitImplementationBase, implementingMethodBase); var implementingMethod = @class.FindImplementationForInterfaceMember(interfaceMethod); Assert.Same(classExplicitImplementation, implementingMethod); } /// <summary> /// 1) Explicit implementation beats implicit implementation. /// 2) Explicit implementation of a declared interface's base interface. /// 3) Explicit implementation of a hidden interface method. /// </summary> [Fact] public void TestExplicitIndexerImplementation() { var text = @" interface BaseInterface { int this[int x] { get; } } interface Interface : BaseInterface { new int this[int x] { get; } } class Class : Interface { int BaseInterface.this[int x] { get { return 0; } } int Interface.this[int x] { get { return 0; } } public int this[int x] { get { return 0; } } } "; var comp = CreateCompilation(text); var global = comp.GlobalNamespace; var baseInterface = (NamedTypeSymbol)global.GetMembers("BaseInterface").Single(); var baseInterfaceIndexer = baseInterface.Indexers.Single(); var @interface = (NamedTypeSymbol)global.GetMembers("Interface").Single(); var interfaceIndexer = @interface.Indexers.Single(); var @class = (NamedTypeSymbol)global.GetMembers("Class").Single(); var classExplicitImplementationBase = @class.GetProperty("BaseInterface.this[]"); var classExplicitImplementation = @class.GetProperty("Interface.this[]"); var classImplicitImplementation = @class.GetProperty("this[]"); Assert.NotSame(classImplicitImplementation, classExplicitImplementation); Assert.NotSame(classImplicitImplementation, classExplicitImplementationBase); var implementingMethodBase = @class.FindImplementationForInterfaceMember(baseInterfaceIndexer); Assert.Same(classExplicitImplementationBase, implementingMethodBase); var implementingMethod = @class.FindImplementationForInterfaceMember(interfaceIndexer); Assert.Same(classExplicitImplementation, implementingMethod); } /// <summary> /// 1) Implicit implementation of a declared interface. /// 2) Implicit implementation of a declared interface's base interface. /// 3) Implicit implementation of more than one interface method. /// </summary> [Fact] public void TestImplicitMethodImplementation() { var text1 = @" public interface BaseInterface1 { void BaseMethod(); } public interface BaseInterface2 { void BaseMethod(); } "; var text2 = @" public interface Interface : BaseInterface1, BaseInterface2 { void Method(); } "; var text3 = @" class Class : Interface { public void Method() { } public void BaseMethod() { } } "; 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 baseInterface1 = (NamedTypeSymbol)global.GetMembers("BaseInterface1").Single(); var baseInterface1Method = baseInterface1.GetMembers("BaseMethod").Single(); var baseInterface2 = (NamedTypeSymbol)global.GetMembers("BaseInterface2").Single(); var baseInterface2Method = baseInterface2.GetMembers("BaseMethod").Single(); var @interface = (NamedTypeSymbol)global.GetMembers("Interface").Single(); var interfaceMethod = @interface.GetMembers("Method").Single(); var @class = (NamedTypeSymbol)global.GetMembers("Class").Single(); var classImplicitImplementation = (MethodSymbol)@class.GetMembers("Method").Single(); Assert.Equal(MethodKind.Ordinary, classImplicitImplementation.MethodKind); var classImplicitImplementationBase = (MethodSymbol)@class.GetMembers("BaseMethod").Single(); Assert.Equal(MethodKind.Ordinary, classImplicitImplementationBase.MethodKind); var implementingMethod = @class.FindImplementationForInterfaceMember(interfaceMethod); Assert.Same(classImplicitImplementation, implementingMethod); var implementingMethodBase1 = @class.FindImplementationForInterfaceMember(baseInterface1Method); Assert.Same(classImplicitImplementationBase, implementingMethodBase1); var implementingMethodBase2 = @class.FindImplementationForInterfaceMember(baseInterface2Method); Assert.Same(classImplicitImplementationBase, implementingMethodBase2); } /// <summary> /// 1) Implicit implementation of a declared interface. /// 2) Implicit implementation of a declared interface's base interface. /// 3) Implicit implementation of more than one interface indexer. /// </summary> [Fact] public void TestImplicitIndexerImplementation() { var text1 = @" public interface BaseInterface1 { int this[int x] { get; } } public interface BaseInterface2 { int this[int x] { get; } } "; var text2 = @" public interface Interface : BaseInterface1, BaseInterface2 { int this[int x, int y] { get; } } "; var text3 = @" class Class : Interface { public int this[int x] { get { return 0; } } public int this[int x, int y] { get { return 0; } } } "; 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 baseInterface1 = (NamedTypeSymbol)global.GetMembers("BaseInterface1").Single(); var baseInterface1Indexer = baseInterface1.Indexers.Single(); var baseInterface2 = (NamedTypeSymbol)global.GetMembers("BaseInterface2").Single(); var baseInterface2Indexer = baseInterface2.Indexers.Single(); var @interface = (NamedTypeSymbol)global.GetMembers("Interface").Single(); var interfaceIndexer = @interface.Indexers.Single(); var @class = (NamedTypeSymbol)global.GetMembers("Class").Single(); var classImplicitImplementation = @class.Indexers.Single(p => p.Parameters.Length == 2); var classImplicitImplementationBase = @class.Indexers.Single(p => p.Parameters.Length == 1); var implementingIndexer = @class.FindImplementationForInterfaceMember(interfaceIndexer); Assert.Same(classImplicitImplementation, implementingIndexer); var implementingIndexerBase1 = @class.FindImplementationForInterfaceMember(baseInterface1Indexer); Assert.Same(classImplicitImplementationBase, implementingIndexerBase1); var implementingIndexerBase2 = @class.FindImplementationForInterfaceMember(baseInterface2Indexer); Assert.Same(classImplicitImplementationBase, implementingIndexerBase2); } /// <summary> /// Tests classes that nearly, but do not actually implement interface methods. /// </summary> [Fact] public void TestImplicitMethodImplementationMismatches() { //UNDONE: type constraint mismatch var text = @" interface Interface { void Method<T>(long l, int i); } class Class1 : Interface { private void Method<T>(long l, int i) { } //non-public methods don't participate public void Method<T, U>(long l, int i) { } //wrong arity public void Method(long l, int i) { } //wrong arity public int Method<T>(long l, int i) { } //wrong return type public void Method1<T>(long l, int i) { } //wrong name public void Method<T>(long l) { } //wrong parameter count public void Method<T>(int i, long l) { } //wrong parameter types public void Method<T>(long l, ref int i) { } //wrong parameter ref kind } class Class2 : Interface { public static void Method<T>(T t, int i) { } //static methods don't participate } "; var comp = CreateCompilation(text); var global = comp.GlobalNamespace; var @interface = (NamedTypeSymbol)global.GetMembers("Interface").Single(); var interfaceMethod = @interface.GetMembers("Method").Single(); var class1 = (NamedTypeSymbol)global.GetMembers("Class1").Single(); Assert.Null(class1.FindImplementationForInterfaceMember(interfaceMethod)); var class2 = (NamedTypeSymbol)global.GetMembers("Class2").Single(); Assert.Null(class2.FindImplementationForInterfaceMember(interfaceMethod)); } /// <summary> /// Class implements interface method via explicit implementation in base class. /// </summary> [Fact] public void TestExplicitMethodImplementationInBase() { var text1 = @" public interface BaseInterface { void Method(); } public interface Interface : BaseInterface { new void Method(); } "; var text2 = @" public class BaseClass : Interface { void BaseInterface.Method() { } void Interface.Method() { } public void Method() { } } "; var text3 = @" class Class1 : BaseClass, Interface //declares Interface { } class Class2 : BaseClass //does not declare interface { } "; 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 baseInterface = (NamedTypeSymbol)global.GetMembers("BaseInterface").Single(); var baseInterfaceMethod = baseInterface.GetMembers("Method").Single(); var @interface = (NamedTypeSymbol)global.GetMembers("Interface").Single(); var interfaceMethod = @interface.GetMembers("Method").Single(); var baseClass = (NamedTypeSymbol)global.GetMembers("BaseClass").Single(); var baseClassExplicitImplementationBase = (MethodSymbol)baseClass.GetMembers("BaseInterface.Method").Single(); Assert.Equal(MethodKind.ExplicitInterfaceImplementation, baseClassExplicitImplementationBase.MethodKind); var baseClassExplicitImplementation = (MethodSymbol)baseClass.GetMembers("Interface.Method").Single(); Assert.Equal(MethodKind.ExplicitInterfaceImplementation, baseClassExplicitImplementation.MethodKind); var baseClassImplicitImplementation = (MethodSymbol)baseClass.GetMembers("Method").Single(); Assert.Equal(MethodKind.Ordinary, baseClassImplicitImplementation.MethodKind); Assert.NotSame(baseClassImplicitImplementation, baseClassExplicitImplementation); Assert.NotSame(baseClassImplicitImplementation, baseClassExplicitImplementationBase); var class1 = (NamedTypeSymbol)global.GetMembers("Class1").Single(); var class1ImplementingMethodBase = class1.FindImplementationForInterfaceMember(baseInterfaceMethod); Assert.Same(baseClassExplicitImplementationBase, class1ImplementingMethodBase); var class1ImplementingMethod = class1.FindImplementationForInterfaceMember(interfaceMethod); Assert.Same(baseClassExplicitImplementation, class1ImplementingMethod); var class2 = (NamedTypeSymbol)global.GetMembers("Class2").Single(); var class2ImplementingMethodBase = class2.FindImplementationForInterfaceMember(baseInterfaceMethod); Assert.Same(baseClassExplicitImplementationBase, class2ImplementingMethodBase); var class2ImplementingMethod = class2.FindImplementationForInterfaceMember(interfaceMethod); Assert.Same(baseClassExplicitImplementation, class2ImplementingMethod); } /// <summary> /// Class implements interface method via implicit implementation in base class. /// </summary> [Fact] public void TestImplicitMethodImplementationInBase() { var text = @" interface BaseInterface1 { void BaseMethod(); } interface BaseInterface2 { void BaseMethod(); } interface Interface : BaseInterface1, BaseInterface2 { void Method(); } class BaseClass : Interface { public void Method() { } public void BaseMethod() { } } class Class1 : BaseClass, Interface //declares Interface { } class Class2 : BaseClass //does not declare interface { } "; var comp = CreateCompilation(text); var global = comp.GlobalNamespace; var baseInterface1 = (NamedTypeSymbol)global.GetMembers("BaseInterface1").Single(); var baseInterface1Method = baseInterface1.GetMembers("BaseMethod").Single(); var baseInterface2 = (NamedTypeSymbol)global.GetMembers("BaseInterface2").Single(); var baseInterface2Method = baseInterface2.GetMembers("BaseMethod").Single(); var @interface = (NamedTypeSymbol)global.GetMembers("Interface").Single(); var interfaceMethod = @interface.GetMembers("Method").Single(); var baseClass = (NamedTypeSymbol)global.GetMembers("BaseClass").Single(); var baseClassImplicitImplementation = (MethodSymbol)baseClass.GetMembers("Method").Single(); Assert.Equal(MethodKind.Ordinary, baseClassImplicitImplementation.MethodKind); var baseClassImplicitImplementationBase = (MethodSymbol)baseClass.GetMembers("BaseMethod").Single(); Assert.Equal(MethodKind.Ordinary, baseClassImplicitImplementationBase.MethodKind); var class1 = (NamedTypeSymbol)global.GetMembers("Class1").Single(); var class1ImplementingMethod = class1.FindImplementationForInterfaceMember(interfaceMethod); Assert.Same(baseClassImplicitImplementation, class1ImplementingMethod); var class1ImplementingMethodBase1 = class1.FindImplementationForInterfaceMember(baseInterface1Method); Assert.Same(baseClassImplicitImplementationBase, class1ImplementingMethodBase1); var class1ImplementingMethodBase2 = class1.FindImplementationForInterfaceMember(baseInterface2Method); Assert.Same(baseClassImplicitImplementationBase, class1ImplementingMethodBase2); var class2 = (NamedTypeSymbol)global.GetMembers("Class2").Single(); var class2ImplementingMethod = class2.FindImplementationForInterfaceMember(interfaceMethod); Assert.Same(baseClassImplicitImplementation, class2ImplementingMethod); var class2ImplementingMethodBase1 = class2.FindImplementationForInterfaceMember(baseInterface1Method); Assert.Same(baseClassImplicitImplementationBase, class2ImplementingMethodBase1); var class2ImplementingMethodBase2 = class2.FindImplementationForInterfaceMember(baseInterface2Method); Assert.Same(baseClassImplicitImplementationBase, class2ImplementingMethodBase2); } /// <summary> /// Class implements interface method via implicit implementation in base class (which does not implement the interface). /// </summary> [Fact] public void TestImplicitMethodImplementationViaBase() { var text = @" interface Interface { void Method(); } class BaseClass { public void Method() { } } class Class1 : BaseClass, Interface //declares Interface { } class Class2 : BaseClass //does not declare interface { } "; var comp = CreateCompilation(text); var global = comp.GlobalNamespace; var @interface = (NamedTypeSymbol)global.GetMembers("Interface").Single(); var interfaceMethod = @interface.GetMembers("Method").Single(); var baseClass = (NamedTypeSymbol)global.GetMembers("BaseClass").Single(); Assert.False(baseClass.AllInterfaces().Contains(@interface)); var baseClassMethod = (MethodSymbol)baseClass.GetMembers("Method").Single(); Assert.Equal(MethodKind.Ordinary, baseClassMethod.MethodKind); var class1 = (NamedTypeSymbol)global.GetMembers("Class1").Single(); Assert.Same(baseClass, class1.BaseType()); Assert.True(class1.Interfaces().Contains(@interface)); var class2 = (NamedTypeSymbol)global.GetMembers("Class2").Single(); Assert.Same(baseClass, class2.BaseType()); Assert.False(class2.AllInterfaces().Contains(@interface)); Assert.Null(baseClass.FindImplementationForInterfaceMember(interfaceMethod)); Assert.Same(baseClassMethod, class1.FindImplementationForInterfaceMember(interfaceMethod)); Assert.Null(class2.FindImplementationForInterfaceMember(interfaceMethod)); } /// <summary> /// Class implements interface indexer via implicit implementation in base class (which does not implement the interface). /// </summary> [Fact] public void TestImplicitIndexerImplementationViaBase() { var text = @" interface Interface { int this[int x] { get; } } class BaseClass { public int this[int x] { get { return 0; } } } class Class1 : BaseClass, Interface //declares Interface { } class Class2 : BaseClass //does not declare interface { } "; var comp = CreateCompilation(text); var global = comp.GlobalNamespace; var @interface = (NamedTypeSymbol)global.GetMembers("Interface").Single(); var interfaceIndexer = @interface.Indexers.Single(); var baseClass = (NamedTypeSymbol)global.GetMembers("BaseClass").Single(); Assert.False(baseClass.AllInterfaces().Contains(@interface)); var baseClassIndexer = baseClass.Indexers.Single(); var class1 = (NamedTypeSymbol)global.GetMembers("Class1").Single(); Assert.Same(baseClass, class1.BaseType()); Assert.True(class1.Interfaces().Contains(@interface)); var class2 = (NamedTypeSymbol)global.GetMembers("Class2").Single(); Assert.Same(baseClass, class2.BaseType()); Assert.False(class2.AllInterfaces().Contains(@interface)); Assert.Null(baseClass.FindImplementationForInterfaceMember(interfaceIndexer)); Assert.Same(baseClassIndexer, class1.FindImplementationForInterfaceMember(interfaceIndexer)); Assert.Null(class2.FindImplementationForInterfaceMember(interfaceIndexer)); } /// <summary> /// Test remapping of an explicitly implemented interface. /// </summary> [Fact] public void TestExplicitMethodImplementationRemapping() { var text = @" interface Interface { void Method(); } class BaseClass : Interface { void Interface.Method() { } } class Class1 : BaseClass, Interface //declares Interface { public void Method() { } } class Class2 : BaseClass //does not declare interface { public void Method() { } } "; var comp = CreateCompilation(text); var global = comp.GlobalNamespace; var @interface = (NamedTypeSymbol)global.GetMembers("Interface").Single(); var interfaceMethod = @interface.GetMembers("Method").Single(); var baseClass = (NamedTypeSymbol)global.GetMembers("BaseClass").Single(); var baseClassMethod = (MethodSymbol)baseClass.GetMembers("Interface.Method").Single(); Assert.Equal(MethodKind.ExplicitInterfaceImplementation, baseClassMethod.MethodKind); var baseClassImplementingMethod = baseClass.FindImplementationForInterfaceMember(interfaceMethod); Assert.Same(baseClassMethod, baseClassImplementingMethod); var class1 = (NamedTypeSymbol)global.GetMembers("Class1").Single(); var class1Method = (MethodSymbol)class1.GetMembers("Method").Single(); Assert.Equal(MethodKind.Ordinary, class1Method.MethodKind); var class1ImplementingMethod = class1.FindImplementationForInterfaceMember(interfaceMethod); Assert.Same(class1Method, class1ImplementingMethod); Assert.NotSame(baseClassMethod, class1ImplementingMethod); var class2 = (NamedTypeSymbol)global.GetMembers("Class2").Single(); var class2Method = (MethodSymbol)class2.GetMembers("Method").Single(); Assert.Equal(MethodKind.Ordinary, class2Method.MethodKind); var class2ImplementingMethod = class2.FindImplementationForInterfaceMember(interfaceMethod); Assert.Same(baseClassMethod, class2ImplementingMethod); Assert.NotSame(class2Method, class1ImplementingMethod); } /// <summary> /// Test remapping of an implicitly implemented interface. /// </summary> [Fact] public void TestImplicitMethodImplementationRemapping() { var text = @" interface Interface { void Virtual(); void NonVirtual(); } class BaseClass : Interface { public virtual void Virtual() { } public void NonVirtual() { } } class Class1 : BaseClass, Interface //declares Interface { public override void Virtual() { } public new void NonVirtual() { } } class Class2 : BaseClass //does not declare interface { public override void Virtual() { } public new void NonVirtual() { } } "; var comp = CreateCompilation(text); var global = comp.GlobalNamespace; var @interface = (NamedTypeSymbol)global.GetMembers("Interface").Single(); var interfaceMethodVirtual = @interface.GetMembers("Virtual").Single(); var interfaceMethodNonVirtual = @interface.GetMembers("NonVirtual").Single(); var baseClass = (NamedTypeSymbol)global.GetMembers("BaseClass").Single(); var baseClassMethodVirtual = (MethodSymbol)baseClass.GetMembers("Virtual").Single(); Assert.Equal(MethodKind.Ordinary, baseClassMethodVirtual.MethodKind); Assert.True(baseClassMethodVirtual.IsVirtual); var baseClassMethodNonVirtual = (MethodSymbol)baseClass.GetMembers("NonVirtual").Single(); Assert.Equal(MethodKind.Ordinary, baseClassMethodNonVirtual.MethodKind); Assert.False(baseClassMethodNonVirtual.IsVirtual); var baseClassImplementingMethodVirtual = baseClass.FindImplementationForInterfaceMember(interfaceMethodVirtual); Assert.Same(baseClassMethodVirtual, baseClassImplementingMethodVirtual); var baseClassImplementingMethodNonVirtual = baseClass.FindImplementationForInterfaceMember(interfaceMethodNonVirtual); Assert.Same(baseClassMethodNonVirtual, baseClassImplementingMethodNonVirtual); var class1 = (NamedTypeSymbol)global.GetMembers("Class1").Single(); var class1MethodVirtual = (MethodSymbol)class1.GetMembers("Virtual").Single(); Assert.Equal(MethodKind.Ordinary, class1MethodVirtual.MethodKind); Assert.True(class1MethodVirtual.IsOverride); var class1MethodNonVirtual = (MethodSymbol)class1.GetMembers("NonVirtual").Single(); Assert.Equal(MethodKind.Ordinary, class1MethodNonVirtual.MethodKind); Assert.False(class1MethodNonVirtual.IsOverride); var class1ImplementingMethodVirtual = class1.FindImplementationForInterfaceMember(interfaceMethodVirtual); Assert.Same(class1MethodVirtual, class1ImplementingMethodVirtual); Assert.NotSame(baseClassMethodVirtual, class1ImplementingMethodVirtual); var class1ImplementingMethodNonVirtual = class1.FindImplementationForInterfaceMember(interfaceMethodNonVirtual); Assert.Same(class1MethodNonVirtual, class1ImplementingMethodNonVirtual); Assert.NotSame(baseClassMethodNonVirtual, class1ImplementingMethodNonVirtual); var class2 = (NamedTypeSymbol)global.GetMembers("Class2").Single(); var class2MethodVirtual = (MethodSymbol)class2.GetMembers("Virtual").Single(); Assert.Equal(MethodKind.Ordinary, class2MethodVirtual.MethodKind); Assert.True(class2MethodVirtual.IsOverride); var class2MethodNonVirtual = (MethodSymbol)class2.GetMembers("NonVirtual").Single(); Assert.Equal(MethodKind.Ordinary, class2MethodNonVirtual.MethodKind); Assert.False(class2MethodNonVirtual.IsOverride); var class2ImplementingMethodVirtual = class2.FindImplementationForInterfaceMember(interfaceMethodVirtual); Assert.Same(baseClassMethodVirtual, class2ImplementingMethodVirtual); Assert.NotSame(class2MethodVirtual, class2ImplementingMethodVirtual); var class2ImplementingMethodNonVirtual = class2.FindImplementationForInterfaceMember(interfaceMethodNonVirtual); Assert.Same(baseClassMethodNonVirtual, class2ImplementingMethodNonVirtual); Assert.NotSame(class2MethodNonVirtual, class2ImplementingMethodNonVirtual); } /// <summary> /// Test remapping of an implicitly implemented interface in a longer chain of types. /// </summary> [Fact] public void TestImplicitMethodImplementationRemapping2() { var text = @" interface Interface { void Method(); } class NonDeclaringClass1 { public void Method() { } } class DeclaringClass1 : NonDeclaringClass1, Interface { } class NonDeclaringClass2 : DeclaringClass1 { public new void Method() { } } class DeclaringClass2 : NonDeclaringClass2, Interface { } "; var comp = CreateCompilation(text); var global = comp.GlobalNamespace; var @interface = (NamedTypeSymbol)global.GetMembers("Interface").Single(); var interfaceMethod = @interface.GetMembers("Method").Single(); var nonDeclaring1 = (NamedTypeSymbol)global.GetMembers("NonDeclaringClass1").Single(); Assert.False(nonDeclaring1.InterfacesAndTheirBaseInterfacesNoUseSiteDiagnostics.ContainsKey(@interface)); var nonDeclaring1Method = nonDeclaring1.GetMembers("Method").Single(); var declaring1 = (NamedTypeSymbol)global.GetMembers("DeclaringClass1").Single(); Assert.True(declaring1.InterfacesAndTheirBaseInterfacesNoUseSiteDiagnostics.ContainsKey(@interface)); Assert.Equal(nonDeclaring1, declaring1.BaseType()); var nonDeclaring2 = (NamedTypeSymbol)global.GetMembers("NonDeclaringClass2").Single(); Assert.False(nonDeclaring2.InterfacesAndTheirBaseInterfacesNoUseSiteDiagnostics.ContainsKey(@interface)); Assert.Equal(declaring1, nonDeclaring2.BaseType()); var nonDeclaring2Method = nonDeclaring2.GetMembers("Method").Single(); var declaring2 = (NamedTypeSymbol)global.GetMembers("DeclaringClass2").Single(); Assert.True(declaring2.InterfacesAndTheirBaseInterfacesNoUseSiteDiagnostics.ContainsKey(@interface)); Assert.Equal(nonDeclaring2, declaring2.BaseType()); Assert.Null(nonDeclaring1.FindImplementationForInterfaceMember(interfaceMethod)); Assert.Equal(nonDeclaring1Method, declaring1.FindImplementationForInterfaceMember(interfaceMethod)); Assert.Equal(nonDeclaring1Method, nonDeclaring2.FindImplementationForInterfaceMember(interfaceMethod)); Assert.Equal(nonDeclaring2Method, declaring2.FindImplementationForInterfaceMember(interfaceMethod)); } /// <summary> /// In metadata, it is possible for a type to explicitly implement a method of an interface /// declared by its base type (even if it does not declare the interface itself). /// </summary> [Fact] public void TestExplicitMethodImplementationOnNonDeclaringType() { var assemblies = MetadataTestHelpers.GetSymbolsForReferences( new[] { NetFramework.mscorlib, TestReferences.SymbolsTests.ExplicitInterfaceImplementation.Methods.IL, }); var global = assemblies.ElementAt(1).GlobalNamespace; var @interface = (NamedTypeSymbol)global.GetMembers("I1").Single(); var interfaceMethod = @interface.GetMembers("Method1").Single(); var baseClass = (NamedTypeSymbol)global.GetMembers("BaseDeclaresInterface").Single(); Assert.True(baseClass.Interfaces().Contains(@interface)); Assert.Null(baseClass.FindImplementationForInterfaceMember(interfaceMethod)); var derivedClass = (NamedTypeSymbol)global.GetMembers("DerivedExplicitlyImplementsInterface").Single(); Assert.False(derivedClass.InterfacesAndTheirBaseInterfacesNoUseSiteDiagnostics.ContainsKey(@interface)); Assert.True(derivedClass.AllInterfaces().Contains(@interface)); var derivedClassMethod = derivedClass.GetMembers("I1.Method1").Single(); Assert.Same(derivedClassMethod, derivedClass.FindImplementationForInterfaceMember(interfaceMethod)); } [Fact] public void TestNonVirtualImplicitImplementationSameAssembly() { var text = @" public interface Interface { void Method(); int Property { get; set; } } public class Base { public void Method() { } public int Property { get; set; } } public class Derived : Base, Interface { } "; var comp = CreateCompilation(text); var global = comp.GlobalNamespace; Assert.False(comp.GetDiagnostics().Any(), string.Join("\n", comp.GetDiagnostics())); var @interface = (NamedTypeSymbol)global.GetMembers("Interface").Single(); var interfaceMethod = (MethodSymbol)@interface.GetMembers("Method").Single(); var interfaceProperty = (PropertySymbol)@interface.GetMembers("Property").Single(); var interfacePropertyGetter = interfaceProperty.GetMethod; var interfacePropertySetter = interfaceProperty.SetMethod; var baseClass = (NamedTypeSymbol)global.GetMembers("Base").Single(); Assert.False(baseClass.AllInterfaces().Contains(@interface)); var baseClassMethod = (MethodSymbol)baseClass.GetMembers("Method").Single(); var baseClassProperty = (PropertySymbol)baseClass.GetMembers("Property").Single(); var baseClassPropertyGetter = baseClassProperty.GetMethod; var baseClassPropertySetter = baseClassProperty.SetMethod; Assert.False(baseClassMethod.IsVirtual); Assert.False(baseClassProperty.IsVirtual); Assert.False(baseClassPropertyGetter.IsVirtual); Assert.False(baseClassPropertySetter.IsVirtual); var derivedClass = (SourceNamedTypeSymbol)global.GetMembers("Derived").Single(); Assert.True(derivedClass.Interfaces().Contains(@interface)); Assert.Same(baseClassMethod, derivedClass.FindImplementationForInterfaceMember(interfaceMethod)); Assert.Same(baseClassProperty, derivedClass.FindImplementationForInterfaceMember(interfaceProperty)); Assert.Same(baseClassPropertyGetter, derivedClass.FindImplementationForInterfaceMember(interfacePropertyGetter)); Assert.Same(baseClassPropertySetter, derivedClass.FindImplementationForInterfaceMember(interfacePropertySetter)); Assert.True(((Cci.IMethodDefinition)baseClassMethod.GetCciAdapter()).IsVirtual); Assert.True(((Cci.IMethodDefinition)baseClassPropertyGetter.GetCciAdapter()).IsVirtual); Assert.True(((Cci.IMethodDefinition)baseClassPropertySetter.GetCciAdapter()).IsVirtual); Assert.False(derivedClass.GetSynthesizedExplicitImplementations(CancellationToken.None).ForwardingMethods.Any()); } [Fact] public void TestNonVirtualImplicitImplementationOtherAssembly() { var text1 = @" public interface Interface { void Method(); int Property { get; set; } } public class Base { public void Method() { } public int Property { get; set; } } "; var text2 = @" public class Derived : Base, Interface { } "; var comp1 = CreateCompilation(text1, assemblyName: "OtherAssembly", options: TestOptions.ReleaseDll); Assert.False(comp1.GetDiagnostics().Any(), string.Join("\n", comp1.GetDiagnostics())); var comp2 = CreateCompilation(text2, references: new MetadataReference[] { new CSharpCompilationReference(comp1) }, assemblyName: "SourceAssembly", options: TestOptions.ReleaseDll); Assert.False(comp2.GetDiagnostics().Any(), string.Join("\n", comp2.GetDiagnostics())); var global = comp2.GlobalNamespace; var @interface = (NamedTypeSymbol)global.GetMembers("Interface").Single(); var interfaceMethod = (MethodSymbol)@interface.GetMembers("Method").Single(); var interfaceProperty = (PropertySymbol)@interface.GetMembers("Property").Single(); var interfacePropertyGetter = interfaceProperty.GetMethod; var interfacePropertySetter = interfaceProperty.SetMethod; var baseClass = (NamedTypeSymbol)global.GetMembers("Base").Single(); Assert.False(baseClass.AllInterfaces().Contains(@interface)); var baseClassMethod = (MethodSymbol)baseClass.GetMembers("Method").Single(); var baseClassProperty = (PropertySymbol)baseClass.GetMembers("Property").Single(); var baseClassPropertyGetter = baseClassProperty.GetMethod; var baseClassPropertySetter = baseClassProperty.SetMethod; Assert.False(baseClassMethod.IsVirtual); Assert.False(baseClassProperty.IsVirtual); Assert.False(baseClassPropertyGetter.IsVirtual); Assert.False(baseClassPropertySetter.IsVirtual); var derivedClass = (SourceNamedTypeSymbol)global.GetMembers("Derived").Single(); Assert.True(derivedClass.Interfaces().Contains(@interface)); Assert.Same(baseClassMethod, derivedClass.FindImplementationForInterfaceMember(interfaceMethod)); Assert.Same(baseClassProperty, derivedClass.FindImplementationForInterfaceMember(interfaceProperty)); Assert.Same(baseClassPropertyGetter, derivedClass.FindImplementationForInterfaceMember(interfacePropertyGetter)); Assert.Same(baseClassPropertySetter, derivedClass.FindImplementationForInterfaceMember(interfacePropertySetter)); Assert.False(((Cci.IMethodDefinition)baseClassMethod.GetCciAdapter()).IsVirtual); Assert.False(((Cci.IMethodDefinition)baseClassPropertyGetter.GetCciAdapter()).IsVirtual); Assert.False(((Cci.IMethodDefinition)baseClassPropertySetter.GetCciAdapter()).IsVirtual); // GetSynthesizedExplicitImplementations doesn't guarantee order, so sort to make the asserts easier to write. var synthesizedExplicitImpls = (from m in derivedClass.GetSynthesizedExplicitImplementations(CancellationToken.None).ForwardingMethods orderby m.MethodKind select m).ToArray(); Assert.Equal(3, synthesizedExplicitImpls.Length); Assert.True(synthesizedExplicitImpls.All(s => ReferenceEquals(derivedClass, s.ContainingType))); Assert.Same(interfaceMethod, synthesizedExplicitImpls[0].ExplicitInterfaceImplementations.Single()); Assert.Same(baseClassMethod, synthesizedExplicitImpls[0].ImplementingMethod); Assert.Same(interfacePropertyGetter, synthesizedExplicitImpls[1].ExplicitInterfaceImplementations.Single()); Assert.Same(baseClassPropertyGetter, synthesizedExplicitImpls[1].ImplementingMethod); Assert.Equal(MethodKind.PropertyGet, synthesizedExplicitImpls[1].MethodKind); Assert.Same(interfacePropertySetter, synthesizedExplicitImpls[2].ExplicitInterfaceImplementations.Single()); Assert.Same(baseClassPropertySetter, synthesizedExplicitImpls[2].ImplementingMethod); Assert.Equal(MethodKind.PropertySet, synthesizedExplicitImpls[2].MethodKind); } /// <summary> /// Layout: /// D : C : B : A /// All have virtual Method1 and Method2 with the same signatures (modulo 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> [Fact] public void TestCustomModifierImplicitImplementation() { var text = @" interface Interface { void Method1(int[] x); void Method2(int[] x); } class Class : CustomModifierOverridingD, Interface { } "; 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 classD = global.GetTypeMembers("CustomModifierOverridingD").Single(); var classDMethod1 = (MethodSymbol)classD.GetMembers("Method1").Single(); var classDMethod2 = (MethodSymbol)classD.GetMembers("Method2").Single(); //Source var @interface = global.GetTypeMembers("Interface").Single(); var interfaceMethod1 = (MethodSymbol)@interface.GetMembers("Method1").Single(); var interfaceMethod2 = (MethodSymbol)@interface.GetMembers("Method2").Single(); var @class = (SourceNamedTypeSymbol)global.GetTypeMembers("Class").Single(); //ignore custom modifiers (chooses most derived, even though less derived has fewer) var classMethod1Impl = @class.FindImplementationForInterfaceMember(interfaceMethod1); Assert.Same(classDMethod1, classMethod1Impl); //ignore custom modifiers (chooses most derived, even though less derived is exact) var classMethod2Impl = @class.FindImplementationForInterfaceMember(interfaceMethod2); Assert.Same(classDMethod2, classMethod2Impl); // GetSynthesizedExplicitImplementations doesn't guarantee order, so sort to make the asserts easier to write. var synthesizedExplicitImpls = (from m in @class.GetSynthesizedExplicitImplementations(CancellationToken.None).ForwardingMethods orderby m.Name select m).ToArray(); Assert.Equal(2, synthesizedExplicitImpls.Length); var synthesizedExplicitMethod1Impl = synthesizedExplicitImpls[0]; Assert.Same(interfaceMethod1, synthesizedExplicitMethod1Impl.ExplicitInterfaceImplementations.Single()); Assert.Same(classDMethod1, synthesizedExplicitMethod1Impl.ImplementingMethod); Assert.Same(@class, synthesizedExplicitMethod1Impl.ContainingType); var synthesizedExplicitMethod2Impl = synthesizedExplicitImpls[1]; Assert.Same(interfaceMethod2, synthesizedExplicitMethod2Impl.ExplicitInterfaceImplementations.Single()); Assert.Same(classDMethod2, synthesizedExplicitMethod2Impl.ImplementingMethod); Assert.Same(@class, synthesizedExplicitMethod2Impl.ContainingType); } [Fact] public void TestExplicitImplementationOfStaticMethod() { var text = @" class Class : ContainsStatic { void ContainsStatic.Bar() { } void ContainsStatic.StaticMethod() { } //CS0539 } "; var ilAssemblyReference = TestReferences.SymbolsTests.Interface.StaticMethodInInterface; var comp = CreateCompilation(text, new[] { ilAssemblyReference }); comp.VerifyDiagnostics( // (5,25): error CS0539: 'Class.StaticMethod()' in explicit interface declaration is not a member of interface Diagnostic(ErrorCode.ERR_InterfaceMemberNotFound, "StaticMethod").WithArguments("Class.StaticMethod()")); } [Fact] public void TestNoImplementationOfStaticMethod() { var text = @" class Class : ContainsStatic { void ContainsStatic.Bar() { } } "; var ilAssemblyReference = TestReferences.SymbolsTests.Interface.StaticMethodInInterface; var comp = CreateCompilation(text, new[] { ilAssemblyReference }); comp.VerifyDiagnostics(); } [Fact] public void MultiLevelPropertyImplementation() { var text = @" interface I1 { int bar { get; set; } } public class c1 { public virtual int bar { get { return 1; } set { } } } public class c2 : c1, I1 { public override int bar { get { return 2; } } } "; var comp = CreateCompilation(text); var global = comp.GlobalNamespace; var type = comp.GlobalNamespace.GetTypeMembers("c2").Single(); Assert.NotEmpty(type.Interfaces()); Assert.True(type.Interfaces().Any(@interface => @interface.Name == "I1")); } [Fact] public void TestImplementInterfaceInpartialClass() { var text = @" interface Interface { void Method1(); } partial class Base : Interface { public void Method2() { } } partial class Base { public void Method1() { } } "; CreateCompilation(text).VerifyDiagnostics(); } /// <summary> /// I -> M(ref int) /// B -> M(out int) /// D : B, I /// /// I source, B source, D source /// </summary> [Fact] [WorkItem(540451, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540451")] public void TestSourceMetadataImplicitImplementation1() { var csharp = @" interface Interface { void M(ref int x); } class Base { void M(out int x) { x = 1; } } class Derived : Base, Interface { } class Program { static void Main() { Interface id = new Derived(); int x = 2; id.M(ref x); } } "; var comp = CreateCompilation(csharp); comp.VerifyDiagnostics( // (15,7): error CS0535: 'Derived' does not implement interface member 'Interface.M(ref int)' Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "Interface").WithArguments("Derived", "Interface.M(ref int)")); var global = comp.GlobalNamespace; Assert.Null(global.GetMember<NamedTypeSymbol>("Derived").FindImplementationForInterfaceMember( global.GetMember<NamedTypeSymbol>("Interface").GetMember<MethodSymbol>("M"))); } // I source, B source, D metadata - skip: metadata implementing source // public void TestSourceMetadataImplicitImplementation2() /// <summary> /// I -> M(ref int) /// B -> M(out int) /// D : B, I /// /// I source, B metadata, D source /// </summary> [Fact] [WorkItem(540451, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540451")] public void TestSourceMetadataImplicitImplementation3() { var csharp = @" interface Interface { void M(ref int x); } class Derived : Base, Interface { } class Program { static void Main() { Interface id = new Derived(); int x = 2; id.M(ref x); } } "; var il = @" .class public auto ansi beforefieldinit Base extends [mscorlib]System.Object { .method public hidebysig virtual instance void M([out] int32& x) cil managed { // Code size 5 (0x5) .maxstack 8 IL_0000: nop IL_0001: ldarg.1 IL_0002: ldc.i4.1 IL_0003: stind.i4 IL_0004: ret } // end of method Base::M .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { // Code size 7 (0x7) .maxstack 8 IL_0000: ldarg.0 IL_0001: call instance void [mscorlib]System.Object::.ctor() IL_0006: ret } // end of method Base::.ctor } // end of class Base"; var comp = CreateCompilationWithILAndMscorlib40(csharp, il); comp.VerifyDiagnostics( // (7,7): error CS0535: 'Derived' does not implement interface member 'Interface.M(ref int)' Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "Interface").WithArguments("Derived", "Interface.M(ref int)")); var global = comp.GlobalNamespace; Assert.Null(global.GetMember<NamedTypeSymbol>("Derived").FindImplementationForInterfaceMember( global.GetMember<NamedTypeSymbol>("Interface").GetMember<MethodSymbol>("M"))); } // I source, B metadata, D metadata - skip: metadata implementing source // public void TestSourceMetadataImplicitImplementation4() /// <summary> /// I -> M(ref int) /// B -> M(out int) /// D : B, I /// /// I metadata, B source, D source /// </summary> [Fact] [WorkItem(540451, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540451")] public void TestSourceMetadataImplicitImplementation5() { var csharp = @" class Base { void M(out int x) { x = 1; } } class Derived : Base, Interface { } class Program { static void Main() { Interface id = new Derived(); int x = 2; id.M(ref x); } } "; var il = @" .class interface public abstract auto ansi Interface { .method public hidebysig newslot abstract virtual instance void M(int32& x) cil managed { } // end of method Interface::M } // end of class Interface"; var comp = CreateCompilationWithILAndMscorlib40(csharp, il); comp.VerifyDiagnostics( // (10,7): error CS0535: 'Derived' does not implement interface member 'Interface.M(ref int)' Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "Interface").WithArguments("Derived", "Interface.M(ref int)")); var global = comp.GlobalNamespace; Assert.Null(global.GetMember<NamedTypeSymbol>("Derived").FindImplementationForInterfaceMember( global.GetMember<NamedTypeSymbol>("Interface").GetMember<MethodSymbol>("M"))); } // I metadata, B source, D metadata - skip: metadata extending source // public void TestSourceMetadataImplicitImplementation6() /// <summary> /// I -> M(ref int) /// B -> M(out int) /// D : B, I /// /// I metadata, B metadata, D source /// </summary> [Fact] [WorkItem(540451, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540451")] public void TestSourceMetadataImplicitImplementation7() { var csharp = @" class Derived : Base, Interface { } class Program { static void Main() { Interface id = new Derived(); int x = 2; id.M(ref x); } } "; var il = @" .class interface public abstract auto ansi Interface { .method public hidebysig newslot abstract virtual instance void M(int32& x) cil managed { } // end of method Interface::M } // end of class Interface .class public auto ansi beforefieldinit Base extends [mscorlib]System.Object { .method public hidebysig virtual instance void M([out] int32& x) cil managed { // Code size 5 (0x5) .maxstack 8 IL_0000: nop IL_0001: ldarg.1 IL_0002: ldc.i4.1 IL_0003: stind.i4 IL_0004: ret } // end of method Base::M .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { // Code size 7 (0x7) .maxstack 8 IL_0000: ldarg.0 IL_0001: call instance void [mscorlib]System.Object::.ctor() IL_0006: ret } // end of method Base::.ctor } // end of class Base"; var comp = CreateCompilationWithILAndMscorlib40(csharp, il); comp.VerifyDiagnostics( // (2,7): error CS0535: 'Derived' does not implement interface member 'Interface.M(ref int)' Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "Interface").WithArguments("Derived", "Interface.M(ref int)")); var global = comp.GlobalNamespace; Assert.Null(global.GetMember<NamedTypeSymbol>("Derived").FindImplementationForInterfaceMember( global.GetMember<NamedTypeSymbol>("Interface").GetMember<MethodSymbol>("M"))); } [WorkItem(528858, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/528858")] [Fact(Skip = "528858")] public void InconsistentTypeParameters() { var il = @" .class interface public abstract I<T> { .class interface abstract auto ansi nested public I2 { } } "; var csharp = @" class C : I<int>.I2 { } "; var comp = CreateCompilationWithILAndMscorlib40(csharp, il); comp.VerifyDiagnostics( Diagnostic(ErrorCode.ERR_BogusType)); } [WorkItem(528901, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/528901")] [Fact(Skip = "528901")] public void BaseInterfacesWithWeirdNamesCanBeImplementedThroughInterfaceInheritance() { var il = @" .class interface public abstract 'N..A' { } .class interface public abstract B implements 'N..A' { } "; var csharp = @" class C : B { } "; CompileWithCustomILSource(csharp, il); } /// <summary> /// I -> M(ref int) /// B -> M(out int) /// D : B, I /// /// I source, B source, D source /// </summary> [Fact] [WorkItem(540451, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540451")] public void TestSourceMetadataImplicitImplementation8() { var csharp = @" class Program { static void Main() { Interface id = new Derived(); int x = 2; id.M(ref x); } } "; var il = @" .class interface public abstract auto ansi Interface { .method public hidebysig newslot abstract virtual instance void M(int32& x) cil managed { } // end of method Interface::M } // end of class Interface .class public auto ansi beforefieldinit Base extends [mscorlib]System.Object { .method public hidebysig virtual instance void M([out] int32& x) cil managed { // Code size 5 (0x5) .maxstack 8 IL_0000: nop IL_0001: ldarg.1 IL_0002: ldc.i4.1 IL_0003: stind.i4 IL_0004: ret } // end of method Base::M .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { // Code size 7 (0x7) .maxstack 8 IL_0000: ldarg.0 IL_0001: call instance void [mscorlib]System.Object::.ctor() IL_0006: ret } // end of method Base::.ctor } // end of class Base .class public auto ansi beforefieldinit Derived extends Base implements Interface { .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { // Code size 7 (0x7) .maxstack 8 IL_0000: ldarg.0 IL_0001: call instance void Base::.ctor() IL_0006: ret } // end of method Derived::.ctor } // end of class Derived"; var comp = CreateCompilationWithILAndMscorlib40(csharp, il); comp.VerifyDiagnostics(); // CONSIDER: dev10 probably regards the interface method as unimplemented, // but it also doesn't give diagnostics for such cases and this is the behavior at runtime. var global = comp.GlobalNamespace; Assert.Equal( global.GetMember<NamedTypeSymbol>("Base").GetMember<MethodSymbol>("M"), global.GetMember<NamedTypeSymbol>("Derived").FindImplementationForInterfaceMember( global.GetMember<NamedTypeSymbol>("Interface").GetMember<MethodSymbol>("M"))); } [WorkItem(540451, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540451")] [Fact] public void TestImplementRefParamWithOutParam() { var text = @" interface I1 { void Goo(out int x); } class C1 : I1 { public void Goo(ref int x) { } } "; CreateCompilation(text).VerifyDiagnostics( Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "I1").WithArguments("C1", "I1.Goo(out int)")); } [Fact] public void TestSameInterfaceOverloadUsingGenericArgument() { var text = @" interface I1<T> { void Goo(int x); void Goo(T x); } class C1 : I1<int> { public void Goo(int x) { } } static class Program { static void Main() { I1<int> i = new C1(); i.Goo(0); } } "; var comp = CreateCompilation(text); comp.VerifyDiagnostics(); var typeSymbol = comp.GlobalNamespace.GetTypeMembers("C1").Single(); var interfaceSymbol = typeSymbol.Interfaces().First(); var gooMethod = typeSymbol.GetMember<MethodSymbol>("Goo"); var interfaceMembers = interfaceSymbol.GetMembers().OfType<MethodSymbol>(); var firstInterfaceMethod = interfaceMembers.First(); var secondInterfaceMethod = interfaceMembers.Last(); Assert.Equal(gooMethod, typeSymbol.FindImplementationForInterfaceMember(firstInterfaceMethod)); Assert.Equal(gooMethod, typeSymbol.FindImplementationForInterfaceMember(secondInterfaceMethod)); } /// <summary> /// In this case, C# thinks B.M implements I.M for C, but the CLR thinks A.M does. To make sure that we get the /// desired behavior, we have to insert an explicit bridge method. /// (See SourceNamedTypeSymbol.IsOverrideOfPossibleImplementationUnderRuntimeRules.) /// </summary> [Fact] [WorkItem(540558, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540558")] public void TestCSharpClrDisagreement_NonOverride() { var text = @" interface I { void M(); } class A : I { public virtual void M() { } } class B : A { public new virtual void M() { } } class C : B, I { } "; var comp = CreateCompilation(text); var global = comp.GlobalNamespace; var @interface = global.GetMember<NamedTypeSymbol>("I"); var interfaceMethod = @interface.GetMember<MethodSymbol>("M"); var classA = global.GetMember<NamedTypeSymbol>("A"); var classAMethod = classA.GetMember<MethodSymbol>("M"); var classB = global.GetMember<NamedTypeSymbol>("B"); var classBMethod = classB.GetMember<MethodSymbol>("M"); var classC = global.GetMember<SourceNamedTypeSymbol>("C"); Assert.Equal(@interface, classA.AllInterfaces().Single()); Assert.Equal(@interface, classB.AllInterfaces().Single()); Assert.Equal(@interface, classC.AllInterfaces().Single()); Assert.Equal(0, classB.Interfaces().Length); Assert.Equal(classB, classC.BaseType()); Assert.Equal(classA, classB.BaseType()); Assert.Equal(classAMethod, classA.FindImplementationForInterfaceMember(interfaceMethod)); Assert.Equal(classBMethod, classC.FindImplementationForInterfaceMember(interfaceMethod)); var synthesizedExplicitImpl = classC.GetSynthesizedExplicitImplementations(CancellationToken.None).ForwardingMethods.Single(); Assert.Equal(classC, synthesizedExplicitImpl.ContainingType); Assert.Equal(interfaceMethod, synthesizedExplicitImpl.ExplicitInterfaceImplementations.Single()); Assert.Equal(classBMethod, synthesizedExplicitImpl.ImplementingMethod); } /// <summary> /// In this case, C# thinks B.M implements I.M for C, but the CLR thinks A.M does. However, /// B.M overrides A.M, so there's no problem (distinguish from TestCSharpClrDisagreement_NonOverride). /// (See SourceNamedTypeSymbol.IsOverrideOfPossibleImplementationUnderRuntimeRules.) /// </summary> [Fact] [WorkItem(540558, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540558")] public void TestCSharpClrDisagreement_Override() { var text = @" interface I { void M(); } class A : I { public virtual void M() { } } class B : A { public override void M() { } } class C : B, I { } "; var comp = CreateCompilation(text); var global = comp.GlobalNamespace; var @interface = global.GetMember<NamedTypeSymbol>("I"); var interfaceMethod = @interface.GetMember<MethodSymbol>("M"); var classA = global.GetMember<NamedTypeSymbol>("A"); var classAMethod = classA.GetMember<MethodSymbol>("M"); var classB = global.GetMember<NamedTypeSymbol>("B"); var classBMethod = classB.GetMember<MethodSymbol>("M"); var classC = global.GetMember<SourceNamedTypeSymbol>("C"); Assert.Equal(@interface, classA.AllInterfaces().Single()); Assert.Equal(@interface, classB.AllInterfaces().Single()); Assert.Equal(@interface, classC.AllInterfaces().Single()); Assert.Equal(0, classB.Interfaces().Length); Assert.Equal(classB, classC.BaseType()); Assert.Equal(classA, classB.BaseType()); Assert.Equal(classAMethod, classA.FindImplementationForInterfaceMember(interfaceMethod)); Assert.Equal(classBMethod, classC.FindImplementationForInterfaceMember(interfaceMethod)); Assert.Equal(0, classC.GetSynthesizedExplicitImplementations(CancellationToken.None).ForwardingMethods.Length); } [Fact] public void ExplicitlyImplementParameterizedProperty() { var il = @" .class interface public abstract auto ansi I { .method public hidebysig newslot specialname abstract virtual instance int32 get_Item(int32 x) cil managed { } // end of method I::get_Item .method public hidebysig newslot specialname abstract virtual instance void set_Item(int32 x, int32 'value') cil managed { } // end of method I::set_Item .property instance int32 Item(int32) { .get instance int32 I::get_Item(int32) .set instance void I::set_Item(int32, int32) } // end of property I::Item } // end of class I "; var csharp = @" class C : I { int I.get_Item(int x) { return 0; } void I.set_Item(int x, int value) { } } class D : I { public int get_Item(int x) { return 0; } public void set_Item(int x, int value) { } } "; var compilation = CreateCompilationWithILAndMscorlib40(csharp, il); compilation.VerifyDiagnostics(); var globalNamespace = compilation.GlobalNamespace; var @interface = globalNamespace.GetMember<NamedTypeSymbol>("I"); var classC = globalNamespace.GetMember<NamedTypeSymbol>("C"); var classD = globalNamespace.GetMember<NamedTypeSymbol>("D"); var interfaceProperty = @interface.GetMember<PropertySymbol>("Item"); Assert.False(interfaceProperty.IsIndexer); Assert.True(interfaceProperty.MustCallMethodsDirectly); var interfaceGetter = interfaceProperty.GetMethod; var interfaceSetter = interfaceProperty.SetMethod; Assert.Null(classC.FindImplementationForInterfaceMember(interfaceProperty)); Assert.Equal("System.Int32 C.I.get_Item(System.Int32 x)", classC.FindImplementationForInterfaceMember(interfaceGetter).ToTestDisplayString()); Assert.Equal("void C.I.set_Item(System.Int32 x, System.Int32 value)", classC.FindImplementationForInterfaceMember(interfaceSetter).ToTestDisplayString()); Assert.Null(classD.FindImplementationForInterfaceMember(interfaceProperty)); Assert.Equal("System.Int32 D.get_Item(System.Int32 x)", classD.FindImplementationForInterfaceMember(interfaceGetter).ToTestDisplayString()); Assert.Equal("void D.set_Item(System.Int32 x, System.Int32 value)", classD.FindImplementationForInterfaceMember(interfaceSetter).ToTestDisplayString()); } [WorkItem(528898, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/528898")] [ClrOnlyFact] public void GenericTypeWithObsoleteBangAritySuffixIsNotAvailable() { var ilSource = @" .class public A { .class interface nested public abstract I`1<T> { } } .class public B extends A { .class nested public 'I!1'<T> { } } "; var csharpSource = @" class C : object, B.I<string> { } "; CompileWithCustomILSource(csharpSource, ilSource); } [WorkItem(528913, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/528913")] [Fact(Skip = "528913")] public void StaticTypesCannotBeUsedAsTypeArgumentsInInterfacesImplementedThroughInterfaceInheritance() { var ilSource = @" .class public interface abstract A`1<T> { } .class public abstract sealed B { } .class public interface abstract C implements class A`1<class B> { } "; var csharpSource = @" class D : C { } "; CreateCompilationWithILAndMscorlib40(csharpSource, ilSource).VerifyDiagnostics( Diagnostic(ErrorCode.ERR_GenericArgIsStaticClass, "B")); } [WorkItem(530224, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/530224")] [Fact] public void IsMetadataVirtualBeforeForceComplete() { var source = @" interface I { void Finalize(); } class Derived : Base, I { ~Derived() { } static void Main() { } } class Base { public void Finalize() { } } "; var comp = CreateCompilation(source); var global = comp.GlobalNamespace; var @interface = global.GetMember<NamedTypeSymbol>("I"); var @base = global.GetMember<NamedTypeSymbol>("Base"); var derived = global.GetMember<NamedTypeSymbol>("Derived"); // Force completion of destructor symbol. Calls IsMetadataVirtual on Base.Finalize. var returnType = derived.GetMember<MethodSymbol>(WellKnownMemberNames.DestructorName).ReturnTypeWithAnnotations; Assert.Equal(SpecialType.System_Void, returnType.SpecialType); // Force completion of entire symbol. Calls EnsureMetadataVirtual on Base.Finalize. derived.ForceComplete(locationOpt: null, filter: null, cancellationToken: CancellationToken.None); } [Fact] public void NoBridgeMethodForVirtualImplementation() { var source1 = @" public interface I { void Virtual(); void NonVirtual(); } public class B { public virtual void Virtual() { } public void NonVirtual() { } } "; var source2 = @" class D : B, I { } "; var comp1 = CreateCompilation(source1, options: TestOptions.ReleaseDll, assemblyName: "asm1"); comp1.VerifyDiagnostics(); var ref1 = new CSharpCompilationReference(comp1); var comp2 = CreateCompilation(source2, new[] { ref1 }, options: TestOptions.ReleaseDll, assemblyName: "asm2"); comp2.VerifyDiagnostics(); var derivedType = comp2.GlobalNamespace.GetMember<SourceNamedTypeSymbol>("D"); var bridgeMethod = derivedType.GetSynthesizedExplicitImplementations(CancellationToken.None).ForwardingMethods.Single(); Assert.Equal("NonVirtual", bridgeMethod.ImplementingMethod.Name); } [WorkItem(530358, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/530358")] [Fact] public void ExplicitImplementationWithoutInterfaceInName() { var il = @" .class interface public abstract auto ansi I1 { .method public hidebysig newslot abstract virtual instance void M() cil managed { } } // end of class I1 .class interface public abstract auto ansi I2 { .method public hidebysig newslot abstract virtual instance void M() cil managed { } } // end of class I2 .class public auto ansi beforefieldinit Base extends [mscorlib]System.Object implements I1, I2 { .method public hidebysig newslot virtual final instance void M() cil managed { .override I1::M ret } // end of method Base::I1.M .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { ldarg.0 call instance void [mscorlib]System.Object::.ctor() ret } // end of method Base::.ctor } // end of class Base "; var source = @" class Derived : Base, I2 { } "; var comp = CreateCompilationWithILAndMscorlib40(source, il); comp.VerifyDiagnostics(); var global = comp.GlobalNamespace; var interface1 = global.GetMember<NamedTypeSymbol>("I1"); var interface1Method = interface1.GetMember<MethodSymbol>("M"); var interface2 = global.GetMember<NamedTypeSymbol>("I2"); var interface2Method = interface2.GetMember<MethodSymbol>("M"); var baseType = global.GetMember<NamedTypeSymbol>("Base"); var baseTypeMethod = baseType.GetMember<MethodSymbol>("M"); var derivedType = global.GetMember<NamedTypeSymbol>("Derived"); // Both interface methods are implemented by a single base type method - one implicitly and // the other explicitly. Assert.Equal(baseTypeMethod, derivedType.FindImplementationForInterfaceMember(interface1Method)); Assert.Equal(baseTypeMethod, derivedType.FindImplementationForInterfaceMember(interface2Method)); } [Fact] [WorkItem(530164, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/530164"), WorkItem(531642, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/531642"), WorkItem(531643, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/531643")] public void ImplicitImplementationOfByRefReturn() { var il = @" .class interface public abstract auto ansi I { .method public hidebysig newslot abstract virtual instance int32& M() cil managed { } } // end of class I .class public auto ansi beforefieldinit B extends [mscorlib]System.Object { .method public hidebysig instance int32& M() cil managed { ldnull throw } .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { ldarg.0 call instance void [mscorlib]System.Object::.ctor() ret } } // end of class B "; var source = @" public class D : B, I { } "; var comp = CreateCompilationWithILAndMscorlib40(source, il); comp.VerifyDiagnostics(); var global = comp.GlobalNamespace; var interfaceType = global.GetMember<NamedTypeSymbol>("I"); var interfaceMethod = interfaceType.GetMember<MethodSymbol>("M"); var baseType = global.GetMember<NamedTypeSymbol>("B"); var baseMethod = baseType.GetMember<MethodSymbol>("M"); var derivedType = global.GetMember<SourceNamedTypeSymbol>("D"); // Interface implementation: Assert.Equal(RefKind.Ref, interfaceMethod.RefKind); Assert.Equal(RefKind.Ref, baseMethod.RefKind); Assert.Equal(baseMethod, derivedType.FindImplementationForInterfaceMember(interfaceMethod)); var synthesized = derivedType.GetSynthesizedExplicitImplementations(CancellationToken.None).ForwardingMethods.Single(); Assert.Equal(baseMethod, synthesized.ImplementingMethod); Assert.Equal(interfaceMethod, synthesized.ExplicitInterfaceImplementations.Single()); // Still get a use site error if you actually call the method. var source2 = @" public class D : B, I { static void Main() { I i = new D(); var x = i.M(); } } "; CreateCompilationWithILAndMscorlib40(source2, il).VerifyDiagnostics(); } [WorkItem(547149, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/547149")] [Fact] public void BaseTypeDoesNotActuallyImplementInterface() { var il = @" .class interface public abstract auto ansi Interface { .method public hidebysig newslot abstract virtual instance void M() cil managed { } } // end of class Interface .class public auto ansi beforefieldinit Base1 extends [mscorlib]System.Object implements Interface { .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 ilRef = CompileIL(il); var source = @" class Derived1 : Base1, Interface { } class Base2 : Interface { } class Derived2 : Base2, Interface { } "; // Base1 is in metadata, so we just trust it when it claims to implement Interface. // Base2 is identical, but in source. We produce error for Base2. CreateCompilation(source, new[] { ilRef }).VerifyDiagnostics( // (6,7): error CS0535: 'Base2' does not implement interface member 'Interface.M()' // class Base2 : Interface Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "Interface").WithArguments("Base2", "Interface.M()")); } [WorkItem(718115, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/718115")] [ClrOnlyFact] public void ExplicitlyImplementedAccessorsWithoutEvent() { var il = @" .class interface public abstract auto ansi I { .method public hidebysig newslot specialname abstract virtual instance void add_E(class [mscorlib]System.Action 'value') cil managed { } .method public hidebysig newslot specialname abstract virtual instance void remove_E(class [mscorlib]System.Action 'value') cil managed { } .event [mscorlib]System.Action E { .addon instance void I::add_E(class [mscorlib]System.Action) .removeon instance void I::remove_E(class [mscorlib]System.Action) } } // end of class I .class public auto ansi beforefieldinit Base extends [mscorlib]System.Object implements I { .method private hidebysig newslot specialname virtual final instance void I.add_E(class [mscorlib]System.Action 'value') cil managed { .override I::add_E ldstr ""Explicit implementation"" call void [mscorlib]System.Console::WriteLine(string) ret } .method private hidebysig newslot specialname virtual final instance void I.remove_E(class [mscorlib]System.Action 'value') cil managed { .override I::remove_E ret } .method family hidebysig specialname instance void add_E(class [mscorlib]System.Action 'value') cil managed { ldstr ""Protected event"" call void [mscorlib]System.Console::WriteLine(string) ret } .method family hidebysig specialname instance void remove_E(class [mscorlib]System.Action 'value') cil managed { ret } .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { ldarg.0 call instance void [mscorlib]System.Object::.ctor() ret } // NOTE: No event I.E .event [mscorlib]System.Action E { .addon instance void Base::add_E(class [mscorlib]System.Action) .removeon instance void Base::remove_E(class [mscorlib]System.Action) } } // end of class Base "; var source = @" public class Derived : Base, I { public void Test() { ((I)this).E += null; } } public class Program { static void Main() { Derived d = new Derived(); d.Test(); I id = new Derived(); id.E += null; } } "; var comp = CreateCompilationWithILAndMscorlib40(source, il, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: @" Explicit implementation Explicit implementation "); var global = comp.GlobalNamespace; var @interface = global.GetMember<NamedTypeSymbol>("I"); var baseType = global.GetMember<NamedTypeSymbol>("Base"); var derivedType = global.GetMember<NamedTypeSymbol>("Derived"); var interfaceEvent = @interface.GetMember<EventSymbol>("E"); var interfaceAdder = interfaceEvent.AddMethod; var baseAdder = baseType.GetMembers().OfType<MethodSymbol>(). Where(m => m.MethodKind == MethodKind.ExplicitInterfaceImplementation). Single(m => m.ExplicitInterfaceImplementations.Single().MethodKind == MethodKind.EventAdd); Assert.Equal(baseAdder, derivedType.FindImplementationForInterfaceMember(interfaceAdder)); Assert.Equal(baseAdder, baseType.FindImplementationForInterfaceMember(interfaceAdder)); Assert.Null(derivedType.FindImplementationForInterfaceMember(interfaceEvent)); Assert.Null(baseType.FindImplementationForInterfaceMember(interfaceEvent)); } [WorkItem(718115, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/718115")] [Fact] public void ExplicitlyImplementedParameterizedPropertyAccessor() { var il = @" .class interface public abstract auto ansi I { .method public hidebysig newslot specialname abstract virtual instance int32 get_P(int32 x) cil managed { } .property instance int32 P(int32) { .get instance int32 I::get_P(int32) } } // end of class I .class public auto ansi beforefieldinit Base extends [mscorlib]System.Object implements I { .method public hidebysig newslot specialname virtual final instance int32 get_P(int32 x) cil managed { ldc.i4.0 ret } .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { ldarg.0 call instance void [mscorlib]System.Object::.ctor() ret } .property instance int32 P(int32) { .get instance int32 Base::get_P(int32) } } // end of class Base "; var source = @" public class Derived : Base, I { int I.get_P(int x) { return 0; } } "; var comp = CreateCompilationWithILAndMscorlib40(source, il); comp.VerifyDiagnostics(); var global = comp.GlobalNamespace; var @interface = global.GetMember<NamedTypeSymbol>("I"); var baseType = global.GetMember<NamedTypeSymbol>("Base"); var derivedType = global.GetMember<NamedTypeSymbol>("Derived"); var interfaceProperty = @interface.GetMember<PropertySymbol>("P"); var interfaceGetter = interfaceProperty.GetMethod; var baseProperty = baseType.GetMember<PropertySymbol>("P"); var baseGetter = baseProperty.GetMethod; var derivedGetter = derivedType.GetMembers().OfType<MethodSymbol>(). Single(m => m.MethodKind == MethodKind.ExplicitInterfaceImplementation); Assert.Equal(baseProperty, baseType.FindImplementationForInterfaceMember(interfaceProperty)); Assert.Equal(baseGetter, baseType.FindImplementationForInterfaceMember(interfaceGetter)); Assert.Null(derivedType.FindImplementationForInterfaceMember(interfaceProperty)); // Used to return baseProperty, which seems wrong. Assert.Equal(derivedGetter, derivedType.FindImplementationForInterfaceMember(interfaceGetter)); } [WorkItem(943542, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/943542"), WorkItem(137, "CodePlex")] [ClrOnlyFact] public void Bug943542() { var il = @" .class interface public abstract auto ansi IBase { .method public newslot specialname abstract strict virtual instance object get_P1() cil managed { } // end of method IBase::get_P1 .method public newslot specialname abstract strict virtual instance void set_P1(object Value) cil managed { } // end of method IBase::set_P1 .method public newslot specialname abstract strict virtual instance object get_P2() cil managed { } // end of method IBase::get_P2 .method public newslot specialname abstract strict virtual instance void set_P2(object Value) cil managed { } // end of method IBase::set_P2 .property instance object P1() { .get instance object IBase::get_P1() .set instance void IBase::set_P1(object) } // end of property IBase::P1 .property instance object P2() { .get instance object IBase::get_P2() .set instance void IBase::set_P2(object) } // end of property IBase::P2 } // end of class IBase .class public auto ansi Base extends [mscorlib]System.Object implements IBase { .method public specialname rtspecialname instance void .ctor() cil managed { // Code size 7 (0x7) .maxstack 8 IL_0000: ldarg.0 IL_0001: call instance void [mscorlib]System.Object::.ctor() IL_0006: ret } // end of method Base::.ctor .method public newslot specialname strict virtual instance object g_P1() cil managed { .override IBase::get_P1 // Code size 16 (0x10) .maxstack 1 .locals init (object V_0) IL_0000: ldstr ""g_P1"" IL_0005: call void [mscorlib]System.Console::WriteLine(string) IL_000a: ldnull IL_000b: stloc.0 IL_000c: br.s IL_000e IL_000e: ldloc.0 IL_000f: ret } // end of method Base::get_P1 .method public newslot specialname strict virtual instance void set_P1(object 'value') cil managed { .override IBase::set_P1 // Code size 11 (0xb) .maxstack 8 IL_0000: ldstr ""set_P1"" IL_0005: call void [mscorlib]System.Console::WriteLine(string) IL_000a: ret } // end of method Base::set_P1 .method public newslot specialname strict virtual instance object get_P2() cil managed { .override IBase::get_P2 // Code size 16 (0x10) .maxstack 1 .locals init (object V_0) IL_0000: ldstr ""get_P2"" IL_0005: call void [mscorlib]System.Console::WriteLine(string) IL_000a: ldnull IL_000b: stloc.0 IL_000c: br.s IL_000e IL_000e: ldloc.0 IL_000f: ret } // end of method Base::get_P2 .method public newslot specialname strict virtual instance void s_P2(object 'value') cil managed { .override IBase::set_P2 // Code size 11 (0xb) .maxstack 8 IL_0000: ldstr ""s_P2"" IL_0005: call void [mscorlib]System.Console::WriteLine(string) IL_000a: ret } // end of method Base::set_P2 .property instance object P1() { .get instance object Base::g_P1() .set instance void Base::set_P1(object) } // end of property Base::P1 .property instance object P2() { .get instance object Base::get_P2() .set instance void Base::s_P2(object) } // end of property Base::P2 } // end of class Base "; var source = @" interface IDerived { object P1 {get;set;} object P2 {get;set;} } class Derived : Base, IDerived { static void Main() { object val; IDerived x = new Derived(); x.P1 = null; val = x.P1; x.P2 = null; val = x.P2; } }"; var comp = CreateCompilationWithILAndMscorlib40(source, il, options: TestOptions.DebugExe); CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: @"set_P1 g_P1 s_P2 get_P2"); } [Fact] [WorkItem(42340, "https://github.com/dotnet/roslyn/issues/42340")] public void Issue42340() { var text = @" #nullable enable class StringComparer : System.Collections.Generic.IEqualityComparer<string?> { public bool Equals(string? x, string? y) { throw null; } public int GetHashCode(string obj) { throw null; } } class OneToOneUnicodeComparer : StringComparer { } "; var comp = CreateCompilation(text); comp.VerifyDiagnostics( // (7,15): warning CS8597: Thrown value may be null. // throw null; Diagnostic(ErrorCode.WRN_ThrowPossibleNull, "null").WithLocation(7, 15), // (10,16): warning CS8767: Nullability of reference types in type of parameter 'obj' of 'int StringComparer.GetHashCode(string obj)' doesn't match implicitly implemented member 'int IEqualityComparer<string?>.GetHashCode(string? obj)' (possibly because of nullability attributes). // public int GetHashCode(string obj) Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnImplicitImplementation, "GetHashCode").WithArguments("obj", "int StringComparer.GetHashCode(string obj)", "int IEqualityComparer<string?>.GetHashCode(string? obj)").WithLocation(10, 16), // (12,15): warning CS8597: Thrown value may be null. // throw null; Diagnostic(ErrorCode.WRN_ThrowPossibleNull, "null").WithLocation(12, 15) ); var baseType = comp.GetTypeByMetadataName("StringComparer"); var derivedType = comp.GetTypeByMetadataName("OneToOneUnicodeComparer"); var implementation = derivedType.FindImplementationForInterfaceMember(baseType.Interfaces().Single().GetMember("GetHashCode")); Assert.Equal("System.Int32 StringComparer.GetHashCode(System.String obj)", implementation.ToTestDisplayString()); } [Theory] [CombinatorialData] [WorkItem(46494, "https://github.com/dotnet/roslyn/issues/46494")] public void ExplicitImplementationInBaseType_01(bool useCompilationReference) { var source0 = @"#nullable enable public struct S<T> { } public interface I { S<object?> F(); }"; var source1 = @"#nullable enable public class A<T> : I where T : class { public S<T?> F() => throw null; S<object?> I.F() => default; }"; var source2A = @"#nullable enable class B<T> : A<T>, I where T : class { }"; var source2B = @"#nullable disable class B<T> : A<T>, I where T : class { }"; var source3 = @"class Program { static void Main() { object o = ((I)new B<string>()).F(); System.Console.WriteLine(o); } }"; ExplicitImplementationInBaseType(useCompilationReference, source0, source1, source2A, source3, "B", "I.F", "S`1[System.Object]", "S<System.Object?> A<T>.I.F()"); ExplicitImplementationInBaseType(useCompilationReference, source0, source1, source2B, source3, "B", "I.F", "S`1[System.Object]", "S<System.Object?> A<T>.I.F()"); } [WorkItem(46494, "https://github.com/dotnet/roslyn/issues/46494")] [Theory] [InlineData("dynamic", "dynamic", "dynamic", "System.Object", true)] [InlineData("dynamic", "dynamic", "dynamic", "System.Object", false)] [InlineData("dynamic", "object", "System.Object", "System.Object", true)] [InlineData("dynamic", "object", "System.Object", "System.Object", false)] [InlineData("object", "dynamic", "dynamic", "System.Object", true)] [InlineData("object", "dynamic", "dynamic", "System.Object", false)] [InlineData("(int X, int Y)", "(int X, int Y)", "(System.Int32 X, System.Int32 Y)", "System.ValueTuple`2[System.Int32,System.Int32]", true)] [InlineData("(int X, int Y)", "(int X, int Y)", "(System.Int32 X, System.Int32 Y)", "System.ValueTuple`2[System.Int32,System.Int32]", false)] [InlineData("nint", "nint", "System.IntPtr", "System.IntPtr", true)] [InlineData("nint", "nint", "System.IntPtr", "System.IntPtr", false)] [InlineData("nint", "System.IntPtr", "System.IntPtr", "System.IntPtr", true)] [InlineData("nint", "System.IntPtr", "System.IntPtr", "System.IntPtr", false)] [InlineData("System.IntPtr", "nint", "System.IntPtr", "System.IntPtr", true)] [InlineData("System.IntPtr", "nint", "System.IntPtr", "System.IntPtr", false)] public void ExplicitImplementationInBaseType_02(string interfaceTypeArg, string baseTypeArg, string expectedTypeArg, string expectedOutput, bool useCompilationReference) { var source0 = $@"public struct S<T> {{ }} public interface I {{ S<{interfaceTypeArg}> F(); }}"; var source1 = $@"public class A<T> : I {{ public S<T> F() => throw null; S<{baseTypeArg}> I.F() => default; }}"; var source2 = @"class B<T> : A<T>, I { }"; var source3 = @"class Program { static void Main() { object o = ((I)new B<string>()).F(); System.Console.WriteLine(o); } }"; ExplicitImplementationInBaseType(useCompilationReference, source0, source1, source2, source3, "B", "I.F", $"S`1[{expectedOutput}]", $"S<{expectedTypeArg}> A<T>.I.F()"); } [Theory] [CombinatorialData] [WorkItem(46494, "https://github.com/dotnet/roslyn/issues/46494")] public void ExplicitImplementationInBaseType_03(bool useCompilationReference) { var source0 = @"#nullable enable public struct S<T> { } public interface I { void F(S<object?> s); }"; var source1 = @"#nullable enable public class A<T> : I { public void F(S<T> s) => throw null; void I.F(S<object?> s) { } }"; var source2A = @"#nullable enable class B<T> : A<T>, I { }"; var source2B = @"#nullable disable class B<T> : A<T>, I { }"; var source3 = @"class Program { static void Main() { ((I)new B<string>()).F(default); System.Console.WriteLine(1); } }"; ExplicitImplementationInBaseType(useCompilationReference, source0, source1, source2A, source3, "B", "I.F", "1", "void A<T>.I.F(S<System.Object?> s)"); ExplicitImplementationInBaseType(useCompilationReference, source0, source1, source2B, source3, "B", "I.F", "1", "void A<T>.I.F(S<System.Object?> s)"); } [WorkItem(46494, "https://github.com/dotnet/roslyn/issues/46494")] [Theory] [InlineData("dynamic", "dynamic", "dynamic", true)] [InlineData("dynamic", "dynamic", "dynamic", false)] [InlineData("dynamic", "object", "System.Object", true)] [InlineData("dynamic", "object", "System.Object", false)] [InlineData("object", "dynamic", "dynamic", true)] [InlineData("object", "dynamic", "dynamic", false)] [InlineData("(int X, int Y)", "(int X, int Y)", "(System.Int32 X, System.Int32 Y)", true)] [InlineData("(int X, int Y)", "(int X, int Y)", "(System.Int32 X, System.Int32 Y)", false)] [InlineData("nint", "nint", "System.IntPtr", true)] [InlineData("nint", "nint", "System.IntPtr", false)] [InlineData("nint", "System.IntPtr", "System.IntPtr", true)] [InlineData("nint", "System.IntPtr", "System.IntPtr", false)] [InlineData("System.IntPtr", "nint", "System.IntPtr", true)] [InlineData("System.IntPtr", "nint", "System.IntPtr", false)] public void ExplicitImplementationInBaseType_04(string interfaceTypeArg, string baseTypeArg, string expectedTypeArg, bool useCompilationReference) { var source0 = $@"public struct S<T> {{ }} public interface I {{ void F(S<{interfaceTypeArg}> s); }}"; var source1 = $@"public class A<T> : I {{ public void F(S<T> s) => throw null; void I.F(S<{baseTypeArg}> s) {{ }} }}"; var source2 = @"class B<T> : A<T>, I { }"; var source3 = @"class Program { static void Main() { ((I)new B<string>()).F(default); System.Console.WriteLine(1); } }"; ExplicitImplementationInBaseType(useCompilationReference, source0, source1, source2, source3, "B", "I.F", "1", $"void A<T>.I.F(S<{expectedTypeArg}> s)"); } private void ExplicitImplementationInBaseType( bool useCompilationReference, string source0, string source1, string source2, string source3, string derivedTypeName, string interfaceMemberName, string expectedOutput, string expectedImplementingMember) { var comp = CreateCompilation(source0); var ref0 = AsReference(comp, useCompilationReference); comp = CreateCompilation(source1, references: new[] { ref0 }); var ref1 = AsReference(comp, useCompilationReference); comp = CreateCompilation(new[] { source2, source3 }, references: new[] { ref0, ref1 }, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: expectedOutput); var derivedType = comp.GetMember<SourceNamedTypeSymbol>(derivedTypeName); Assert.True(derivedType.GetSynthesizedExplicitImplementations(cancellationToken: default).ForwardingMethods.IsEmpty); var interfaceMember = comp.GetMember<MethodSymbol>(interfaceMemberName); var implementingMember = derivedType.FindImplementationForInterfaceMember(interfaceMember); Assert.Equal(expectedImplementingMember, implementingMember.ToTestDisplayString()); } [Fact] [WorkItem(50713, "https://github.com/dotnet/roslyn/issues/50713")] public void Issue50713_1() { var text1 = @" public interface I1 { void M(); } public interface I2 : I1 { new void M(); } "; var comp1 = CreateCompilation(text1); comp1.VerifyDiagnostics(); var i1M = comp1.GetMember("I1.M"); var i2 = comp1.GetMember<NamedTypeSymbol>("I2"); Assert.Null(i2.FindImplementationForInterfaceMember(i1M)); } [Fact] [WorkItem(50713, "https://github.com/dotnet/roslyn/issues/50713")] public void Issue50713_2() { var text0 = @" public interface I1 { void M(); } public interface I2 : I1 { new void M(); } "; var comp0 = CreateCompilation(text0); var comp1 = CreateCompilation("", references: new[] { comp0.EmitToImageReference() }); var i1M = comp1.GetMember("I1.M"); var i2 = comp1.GetMember<NamedTypeSymbol>("I2"); Assert.Null(i2.FindImplementationForInterfaceMember(i1M)); } } }