/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/CSharp/Test/Symbol/Symbols/Source/MethodTests.cs
2 629 строк
93 KB
Copilot
Update documentation for DeclaringSyntaxReferences and Locations to clarify partial members behavior (#80704)
21 окт 2025, 20:56
Не верифицирован
21 окт 2025, 20:56
53766eb
Код
Авторство
О чём код?
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. #nullable disable using System; using System.Collections.Generic; using System.Linq; using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.CSharp.Emit; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Emit; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Roslyn.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.CSharp.UnitTests { public class MethodTests : CSharpTestBase { [Fact] public void Simple1() { var text = @" class A { void M(int x) {} } "; var comp = CreateCompilation(text); var global = comp.GlobalNamespace; var a = global.GetTypeMembers("A", 0).Single(); var m = a.GetMembers("M").Single() as MethodSymbol; Assert.NotNull(m); Assert.True(m.ReturnsVoid); var x = m.Parameters[0]; Assert.Equal("x", x.Name); Assert.Equal(SymbolKind.NamedType, x.Type.Kind); Assert.Equal("Int32", x.Type.Name); // fully qualified to work around a metadata reader bug Assert.Equal(SymbolKind.Parameter, x.Kind); Assert.Equal(Accessibility.Private, m.DeclaredAccessibility); } [Fact] public void NoParameterlessCtorForStruct() { var text = "struct A { A() {} }"; var comp = CreateCompilation(text, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics( // (1,12): error CS8773: Feature 'parameterless struct constructors' is not available in C# 9.0. Please use language version 10.0 or greater. // struct A { A() {} } Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "A").WithArguments("parameterless struct constructors", "10.0").WithLocation(1, 12), // (1,12): error CS8938: The parameterless struct constructor must be 'public'. // struct A { A() {} } Diagnostic(ErrorCode.ERR_NonPublicParameterlessStructConstructor, "A").WithLocation(1, 12)); } [WorkItem(537194, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537194")] [Fact] public void DefaultCtor1() { Action<string, string, int, Accessibility?> check = (source, className, ctorCount, accessibility) => { var comp = CreateCompilation(source); var global = comp.GlobalNamespace; var a = global.GetTypeMembers(className, 0).Single(); var ctors = a.InstanceConstructors; // Note, this only returns *instance* constructors. Assert.Equal(ctorCount, ctors.Length); foreach (var ct in ctors) { Assert.Equal( ct.IsStatic ? WellKnownMemberNames.StaticConstructorName : WellKnownMemberNames.InstanceConstructorName, ct.Name ); if (accessibility != null) Assert.Equal(accessibility, ct.DeclaredAccessibility); } }; Accessibility? doNotCheckAccessibility = null; // A class without any defined constructors should generator a public constructor. check(@"internal class A { }", "A", 1, Accessibility.Public); // An abstract class without any defined constructors should generator a protected constructor. check(@"abstract internal class A { }", "A", 1, Accessibility.Protected); // A static class should not generate a default constructor check(@"static internal class A { }", "A", 0, doNotCheckAccessibility); // A class with a defined instance constructor should not generate a default constructor. check(@"internal class A { A(int x) {} }", "A", 1, doNotCheckAccessibility); // A class with only a static constructor defined should still generate a default instance constructor. check(@"internal class A { static A(int x) {} }", "A", 1, doNotCheckAccessibility); } [WorkItem(537345, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537345")] [Fact] public void Ctor1() { var text = @" class A { A(int x) {} } "; var comp = CreateCompilation(text); var global = comp.GlobalNamespace; var a = global.GetTypeMembers("A", 0).Single(); var m = a.InstanceConstructors.Single(); Assert.NotNull(m); Assert.Equal(WellKnownMemberNames.InstanceConstructorName, m.Name); Assert.True(m.ReturnsVoid); Assert.Equal(MethodKind.Constructor, m.MethodKind); var x = m.Parameters[0]; Assert.Equal("x", x.Name); Assert.Equal(SymbolKind.NamedType, x.Type.Kind); Assert.Equal("Int32", x.Type.Name); // fully qualified to work around a metadata reader bug Assert.Equal(SymbolKind.Parameter, x.Kind); Assert.Equal(Accessibility.Private, m.DeclaredAccessibility); } [Fact] public void Simple2() { var text = @" class A { void M<T>(int x) {} } "; var comp = CreateCompilation(text); var global = comp.GlobalNamespace; var a = global.GetTypeMembers("A", 0).Single(); var m = a.GetMembers("M").Single() as MethodSymbol; Assert.NotNull(m); Assert.True(m.ReturnsVoid); Assert.Equal(MethodKind.Ordinary, m.MethodKind); var x = m.Parameters[0]; Assert.Equal("x", x.Name); Assert.Equal(SymbolKind.NamedType, x.Type.Kind); Assert.Equal("Int32", x.Type.Name); // fully qualified to work around a metadata reader bug Assert.Equal(SymbolKind.Parameter, x.Kind); Assert.Equal(Accessibility.Private, m.DeclaredAccessibility); } [Fact] public void Access1() { var text = @" class A { void M1() {} } interface B { void M2() {} } "; var comp = CreateCompilation(text); var global = comp.GlobalNamespace; var a = global.GetTypeMembers("A", 0).Single(); var m1 = a.GetMembers("M1").Single() as MethodSymbol; var b = global.GetTypeMembers("B", 0).Single(); var m2 = b.GetMembers("M2").Single() as MethodSymbol; Assert.Equal(Accessibility.Private, m1.DeclaredAccessibility); Assert.Equal(Accessibility.Public, m2.DeclaredAccessibility); } [Fact] public void GenericParameter() { var text = @" public class MyList<T> { public void Add(T element) { } } "; var comp = CreateCompilation(text); var global = comp.GlobalNamespace; var mylist = global.GetTypeMembers("MyList", 1).Single(); var t1 = mylist.TypeParameters[0]; var add = mylist.GetMembers("Add").Single() as MethodSymbol; var element = add.Parameters[0]; var t2 = element.Type; Assert.Equal(t1, t2); } [Fact] public void PartialLocation() { var text = @" public partial class A { partial void M(); } public partial class A { partial void M() {} } "; var comp = CreateCompilation(text); var global = comp.GlobalNamespace; var a = global.GetTypeMembers("A", 0).Single(); var m = a.GetMembers("M"); Assert.Equal(1, m.Length); Assert.Equal(1, m.First().Locations.Length); } [Fact] public void PartialExtractSyntaxLocation_DeclBeforeDef() { var text = @"public partial class A { partial void M(); } public partial class A { partial void M() {} } "; var comp = CreateCompilation(text); var global = comp.GlobalNamespace; var a = global.GetTypeMembers("A", 0).Single(); var m = (MethodSymbol)a.GetMembers("M").Single(); Assert.True(m.IsPartialDefinition()); var returnSyntax = m.ExtractReturnTypeSyntax(); var tree = comp.SyntaxTrees.Single(); var node = tree.GetRoot().DescendantNodes().OfType<PredefinedTypeSyntax>().Where(n => n.Keyword.Kind() == SyntaxKind.VoidKeyword).First(); var otherSymbol = m.PartialImplementationPart; Assert.True(otherSymbol.IsPartialImplementation()); Assert.Equal(node, returnSyntax); Assert.Equal(node, otherSymbol.ExtractReturnTypeSyntax()); } [Fact] public void PartialExtractSyntaxLocation_DefBeforeDecl() { var text = @"public partial class A { partial void M() {} } public partial class A { partial void M(); } "; var comp = CreateCompilation(text); var global = comp.GlobalNamespace; var a = global.GetTypeMembers("A", 0).Single(); var m = (MethodSymbol)a.GetMembers("M").Single(); Assert.True(m.IsPartialDefinition()); var returnSyntax = m.ExtractReturnTypeSyntax(); var tree = comp.SyntaxTrees.Single(); var node = tree.GetRoot().DescendantNodes().OfType<PredefinedTypeSyntax>().Where(n => n.Keyword.Kind() == SyntaxKind.VoidKeyword).Last(); var otherSymbol = m.PartialImplementationPart; Assert.True(otherSymbol.IsPartialImplementation()); Assert.Equal(node, returnSyntax); Assert.Equal(node, otherSymbol.ExtractReturnTypeSyntax()); } [Fact] public void PartialExtractSyntaxLocation_OnlyDef() { var text = @"public partial class A { partial void M() {} } "; var comp = CreateCompilation(text); var global = comp.GlobalNamespace; var a = global.GetTypeMembers("A", 0).Single(); var m = (MethodSymbol)a.GetMembers("M").Single(); Assert.True(m.IsPartialImplementation()); var returnSyntax = m.ExtractReturnTypeSyntax(); var tree = comp.SyntaxTrees.Single().GetRoot(); var node = tree.DescendantNodes().OfType<PredefinedTypeSyntax>().Where(n => n.Keyword.Kind() == SyntaxKind.VoidKeyword).Single(); Assert.Equal(node, returnSyntax); } [Fact] public void PartialExtractSyntaxLocation_OnlyDecl() { var text = @"public partial class A { partial void M(); } "; var comp = CreateCompilation(text); var global = comp.GlobalNamespace; var a = global.GetTypeMembers("A", 0).Single(); var m = (MethodSymbol)a.GetMembers("M").Single(); Assert.True(m.IsPartialDefinition()); var returnSyntax = m.ExtractReturnTypeSyntax(); var tree = comp.SyntaxTrees.Single().GetRoot(); var node = tree.DescendantNodes().OfType<PredefinedTypeSyntax>().Where(n => n.Keyword.Kind() == SyntaxKind.VoidKeyword).Single(); Assert.Equal(node, returnSyntax); } [Fact] public void FullName() { var text = @" public class A { public string M(int x); } "; var comp = CreateCompilation(text); var global = comp.GlobalNamespace; var a = global.GetTypeMembers("A", 0).Single(); var m = a.GetMembers("M").Single() as MethodSymbol; Assert.Equal("System.String A.M(System.Int32 x)", m.ToTestDisplayString()); } [Fact] public void TypeParameterScope() { var text = @" public interface A { T M<T>(T t); } "; var comp = CreateCompilation(text); var global = comp.GlobalNamespace; var a = global.GetTypeMembers("A", 0).Single(); var m = a.GetMembers("M").Single() as MethodSymbol; var t = m.TypeParameters[0]; Assert.Equal(t, m.Parameters[0].Type); Assert.Equal(t, m.ReturnType); } [WorkItem(931142, "DevDiv/Personal")] [Fact] public void RefOutParameterType() { var text = @"public class A { void M(ref A refp, out long outp) { } } "; var comp = CreateCompilation(text); var global = comp.GlobalNamespace; var a = global.GetTypeMembers("A", 0).Single(); var m = a.GetMembers("M").Single() as MethodSymbol; var p1 = m.Parameters[0]; var p2 = m.Parameters[1]; Assert.Equal(RefKind.Ref, p1.RefKind); Assert.Equal(RefKind.Out, p2.RefKind); var refP = p1.Type; Assert.Equal(TypeKind.Class, refP.TypeKind); Assert.True(refP.IsReferenceType); Assert.False(refP.IsValueType); Assert.Equal("Object", refP.BaseType().Name); Assert.Equal(2, refP.GetMembers().Length); // M + generated constructor. Assert.Equal(1, refP.GetMembers("M").Length); var outP = p2.Type; Assert.Equal(TypeKind.Struct, outP.TypeKind); Assert.False(outP.IsReferenceType); Assert.True(outP.IsValueType); Assert.False(outP.IsStatic); Assert.False(outP.IsAbstract); Assert.True(outP.IsSealed); Assert.Equal(Accessibility.Public, outP.DeclaredAccessibility); Assert.Equal(5, outP.Interfaces().Length); Assert.Equal(0, outP.GetTypeMembers().Length); // Enumerable.Empty<NamedTypeSymbol>() Assert.Equal(0, outP.GetTypeMembers(String.Empty).Length); Assert.Equal(0, outP.GetTypeMembers(String.Empty, 0).Length); } [Fact] public void RefReturn() { var text = @"public class A { ref int M(ref int i) { return ref i; } } "; var comp = CreateCompilationWithMscorlib461(text); var global = comp.GlobalNamespace; var a = global.GetTypeMembers("A", 0).Single(); var m = a.GetMembers("M").Single() as MethodSymbol; Assert.Equal(RefKind.Ref, m.RefKind); Assert.Equal(TypeKind.Struct, m.ReturnType.TypeKind); Assert.False(m.ReturnType.IsReferenceType); Assert.True(m.ReturnType.IsValueType); var p1 = m.Parameters[0]; Assert.Equal(RefKind.Ref, p1.RefKind); Assert.Equal("ref System.Int32 A.M(ref System.Int32 i)", m.ToTestDisplayString()); } [Fact] public void BothKindsOfCtors() { var text = @"public class Test { public Test() {} public static Test() {} }"; var comp = CreateCompilation(text); var classTest = comp.GlobalNamespace.GetTypeMembers("Test", 0).Single(); var members = classTest.GetMembers(); Assert.Equal(2, members.Length); } [WorkItem(931663, "DevDiv/Personal")] [Fact] public void RefOutArrayParameter() { var text = @"public class Test { public void MethodWithRefOutArray(ref int[] ary1, out string[] ary2) { ary2 = null; } }"; var comp = CreateCompilation(text); var classTest = comp.GlobalNamespace.GetTypeMembers("Test", 0).Single(); var method = classTest.GetMembers("MethodWithRefOutArray").Single() as MethodSymbol; Assert.Equal(classTest, method.ContainingSymbol); Assert.Equal(SymbolKind.Method, method.Kind); Assert.True(method.IsDefinition); // var paramList = (method as MethodSymbol).Parameters; var p1 = method.Parameters[0]; var p2 = method.Parameters[1]; Assert.Equal(RefKind.Ref, p1.RefKind); Assert.Equal(RefKind.Out, p2.RefKind); } [Theory, MemberData(nameof(FileScopedOrBracedNamespace))] public void InterfaceImplementsCrossTrees(string ob, string cb) { var text1 = @"using System; using System.Collections.Generic; namespace NS " + ob + @" public class Abc {} public interface IGoo<T> { void M(ref T t); } public interface I1 { void M(ref string p); int M1(short p1, params object[] ary); } public interface I2 : I1 { void M21(); Abc M22(ref Abc p); } " + cb; var text2 = @"using System; using System.Collections.Generic; namespace NS.NS1 " + ob + @" public class Impl : I2, IGoo<string>, I1 { void IGoo<string>.M(ref string p) { } void I1.M(ref string p) { } public int M1(short p1, params object[] ary) { return p1; } public void M21() {} public Abc M22(ref Abc p) { return p; } } struct S<T>: IGoo<T> { void IGoo<T>.M(ref T t) {} } " + cb; var comp = CreateCompilation(new[] { text1, text2 }); Assert.Equal(0, comp.GetDeclarationDiagnostics().Count()); var ns = comp.GlobalNamespace.GetMembers("NS").Single() as NamespaceSymbol; var ns1 = ns.GetMembers("NS1").Single() as NamespaceSymbol; var classImpl = ns1.GetTypeMembers("Impl", 0).Single() as NamedTypeSymbol; Assert.Equal(3, classImpl.Interfaces().Length); // var itfc = classImpl.Interfaces().First() as NamedTypeSymbol; Assert.Equal(1, itfc.Interfaces().Length); itfc = itfc.Interfaces().First() as NamedTypeSymbol; Assert.Equal("I1", itfc.Name); // explicit interface member names include the explicit interface var mems = classImpl.GetMembers("M"); Assert.Equal(0, mems.Length); //var mem1 = mems.First() as MethodSymbol; // not impl // Assert.Equal(MethodKind.ExplicitInterfaceImplementation, mem1.MethodKind); // Assert.Equal(1, mem1.ExplicitInterfaceImplementation.Count()); var mem1 = classImpl.GetMembers("M22").Single() as MethodSymbol; // not impl // Assert.Equal(0, mem1.ExplicitInterfaceImplementation.Count()); var param = mem1.Parameters.First() as ParameterSymbol; Assert.Equal(RefKind.Ref, param.RefKind); Assert.Equal("ref NS.Abc p", param.ToTestDisplayString()); var structImpl = ns1.GetTypeMembers("S").Single() as NamedTypeSymbol; Assert.Equal(1, structImpl.Interfaces().Length); itfc = structImpl.Interfaces().First() as NamedTypeSymbol; Assert.Equal("NS.IGoo<T>", itfc.ToTestDisplayString()); //var mem2 = structImpl.GetMembers("M").Single() as MethodSymbol; // not impl // Assert.Equal(1, mem2.ExplicitInterfaceImplementation.Count()); } [Fact] public void AbstractVirtualMethodsCrossTrees() { var text = @" namespace MT { public interface IGoo { void M0(); } } "; var text1 = @" namespace N1 { using MT; public abstract class Abc : IGoo { public abstract void M0(); public char M1; public abstract object M2(ref object p1); public virtual void M3(ulong p1, out ulong p2) { p2 = p1; } public virtual object M4(params object[] ary) { return null; } public static void M5<T>(T t) { } public abstract ref int M6(ref int i); } } "; var text2 = @" namespace N1.N2 { public class Bbc : Abc { public override void M0() { } public override object M2(ref object p1) { M1 = 'a'; return p1; } public sealed override void M3(ulong p1, out ulong p2) { p2 = p1; } public override object M4(params object[] ary) { return null; } public static new void M5<T>(T t) { } public override ref int M6(ref int i) { return ref i; } } } "; var comp = CreateCompilationWithMscorlib461(new[] { text, text1, text2 }); Assert.Equal(0, comp.GetDiagnostics().Count()); var ns = comp.GlobalNamespace.GetMembers("N1").Single() as NamespaceSymbol; var ns1 = ns.GetMembers("N2").Single() as NamespaceSymbol; #region "Bbc" var type1 = ns1.GetTypeMembers("Bbc", 0).Single() as NamedTypeSymbol; var mems = type1.GetMembers(); Assert.Equal(7, mems.Length); // var sorted = mems.Orderby(m => m.Name).ToArray(); var sorted = (from m in mems orderby m.Name select m).ToArray(); var m0 = sorted[0] as MethodSymbol; Assert.Equal(WellKnownMemberNames.InstanceConstructorName, m0.Name); Assert.False(m0.IsAbstract); Assert.False(m0.IsOverride); Assert.False(m0.IsSealed); Assert.False(m0.IsVirtual); var m1 = sorted[1] as MethodSymbol; Assert.Equal("M0", m1.Name); Assert.False(m1.IsAbstract); Assert.True(m1.IsOverride); Assert.False(m1.IsSealed); Assert.False(m1.IsVirtual); var m2 = sorted[2] as MethodSymbol; Assert.Equal("M2", m2.Name); Assert.False(m2.IsAbstract); Assert.True(m2.IsOverride); Assert.False(m2.IsSealed); Assert.False(m2.IsVirtual); var m3 = sorted[3] as MethodSymbol; Assert.Equal("M3", m3.Name); Assert.False(m3.IsAbstract); Assert.True(m3.IsOverride); Assert.True(m3.IsSealed); Assert.False(m3.IsVirtual); var m4 = sorted[4] as MethodSymbol; Assert.Equal("M4", m4.Name); Assert.False(m4.IsAbstract); Assert.True(m4.IsOverride); Assert.False(m4.IsSealed); Assert.False(m4.IsVirtual); var m5 = sorted[5] as MethodSymbol; Assert.Equal("M5", m5.Name); Assert.False(m5.IsAbstract); Assert.False(m5.IsOverride); Assert.False(m5.IsSealed); Assert.False(m5.IsVirtual); Assert.True(m5.IsStatic); var m6 = sorted[6] as MethodSymbol; Assert.Equal("M6", m6.Name); Assert.False(m6.IsAbstract); Assert.True(m6.IsOverride); Assert.False(m6.IsSealed); Assert.False(m6.IsVirtual); #endregion #region "Abc" var type2 = type1.BaseType(); Assert.Equal("Abc", type2.Name); mems = type2.GetMembers(); Assert.Equal(8, mems.Length); sorted = (from m in mems orderby m.Name select m).ToArray(); var mm = sorted[2] as FieldSymbol; Assert.Equal("M1", mm.Name); Assert.False(mm.IsAbstract); Assert.False(mm.IsOverride); Assert.False(mm.IsSealed); Assert.False(mm.IsVirtual); m0 = sorted[0] as MethodSymbol; Assert.Equal(WellKnownMemberNames.InstanceConstructorName, m0.Name); Assert.Equal(Accessibility.Protected, m0.DeclaredAccessibility); m1 = sorted[1] as MethodSymbol; Assert.Equal("M0", m1.Name); Assert.True(m1.IsAbstract); Assert.False(m1.IsOverride); Assert.False(m1.IsSealed); Assert.False(m1.IsVirtual); m2 = sorted[3] as MethodSymbol; Assert.Equal("M2", m2.Name); Assert.True(m2.IsAbstract); Assert.False(m2.IsOverride); Assert.False(m2.IsSealed); Assert.False(m2.IsVirtual); m3 = sorted[4] as MethodSymbol; Assert.Equal("M3", m3.Name); Assert.False(m3.IsAbstract); Assert.False(m3.IsOverride); Assert.False(m3.IsSealed); Assert.True(m3.IsVirtual); m4 = sorted[5] as MethodSymbol; Assert.Equal("M4", m4.Name); Assert.False(m4.IsAbstract); Assert.False(m4.IsOverride); Assert.False(m4.IsSealed); Assert.True(m4.IsVirtual); m5 = sorted[6] as MethodSymbol; Assert.Equal("M5", m5.Name); Assert.False(m5.IsAbstract); Assert.False(m5.IsOverride); Assert.False(m5.IsSealed); Assert.False(m5.IsVirtual); Assert.True(m5.IsStatic); m6 = sorted[7] as MethodSymbol; Assert.Equal("M6", m6.Name); Assert.True(m6.IsAbstract); Assert.False(m6.IsOverride); Assert.False(m6.IsSealed); Assert.False(m6.IsVirtual); #endregion } [WorkItem(537752, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537752")] [Fact] public void AbstractVirtualMethodsCrossComps() { var text = @" namespace MT { public interface IGoo { void M0(); } } "; var text1 = @" namespace N1 { using MT; public abstract class Abc : IGoo { public abstract void M0(); public char M1; public abstract object M2(ref object p1); public virtual void M3(ulong p1, out ulong p2) { p2 = p1; } public virtual object M4(params object[] ary) { return null; } public static void M5<T>(T t) { } public abstract ref int M6(ref int i); } } "; var text2 = @" namespace N1.N2 { public class Bbc : Abc { public override void M0() { } public override object M2(ref object p1) { M1 = 'a'; return p1; } public sealed override void M3(ulong p1, out ulong p2) { p2 = p1; } public override object M4(params object[] ary) { return null; } public static new void M5<T>(T t) { } public override ref int M6(ref int i) { return ref i; } } } "; var comp1 = CreateCompilationWithMscorlib461(text); var compRef1 = new CSharpCompilationReference(comp1); var comp2 = CreateCompilationWithMscorlib461(new string[] { text1 }, new List<MetadataReference>() { compRef1 }, assemblyName: "Test2"); //Compilation.Create(outputName: "Test2", options: CompilationOptions.Default, // syntaxTrees: new SyntaxTree[] { SyntaxTree.ParseCompilationUnit(text1) }, // references: new MetadataReference[] { compRef1, GetCorlibReference() }); var compRef2 = new CSharpCompilationReference(comp2); var comp = CreateCompilationWithMscorlib461(new string[] { text2 }, new List<MetadataReference>() { compRef1, compRef2 }, assemblyName: "Test3"); //Compilation.Create(outputName: "Test3", options: CompilationOptions.Default, // syntaxTrees: new SyntaxTree[] { SyntaxTree.ParseCompilationUnit(text2) }, // references: new MetadataReference[] { compRef1, compRef2, GetCorlibReference() }); Assert.Equal(0, comp1.GetDiagnostics().Count()); Assert.Equal(0, comp2.GetDiagnostics().Count()); Assert.Equal(0, comp.GetDiagnostics().Count()); //string errs = String.Empty; //foreach (var e in comp.GetDiagnostics()) //{ // errs += e.Info.ToString() + "\r\n"; //} //Assert.Equal("Errs", errs); var ns = comp.GlobalNamespace.GetMembers("N1").Single() as NamespaceSymbol; var ns1 = ns.GetMembers("N2").Single() as NamespaceSymbol; #region "Bbc" var type1 = ns1.GetTypeMembers("Bbc", 0).Single() as NamedTypeSymbol; var mems = type1.GetMembers(); Assert.Equal(7, mems.Length); // var sorted = mems.Orderby(m => m.Name).ToArray(); var sorted = (from m in mems orderby m.Name select m).ToArray(); var m0 = sorted[0] as MethodSymbol; Assert.Equal(WellKnownMemberNames.InstanceConstructorName, m0.Name); Assert.False(m0.IsAbstract); Assert.False(m0.IsOverride); Assert.False(m0.IsSealed); Assert.False(m0.IsVirtual); var m1 = sorted[1] as MethodSymbol; Assert.Equal("M0", m1.Name); Assert.False(m1.IsAbstract); Assert.True(m1.IsOverride); Assert.False(m1.IsSealed); Assert.False(m1.IsVirtual); var m2 = sorted[2] as MethodSymbol; Assert.Equal("M2", m2.Name); Assert.False(m2.IsAbstract); Assert.True(m2.IsOverride); Assert.False(m2.IsSealed); Assert.False(m2.IsVirtual); var m3 = sorted[3] as MethodSymbol; Assert.Equal("M3", m3.Name); Assert.False(m3.IsAbstract); Assert.True(m3.IsOverride); Assert.True(m3.IsSealed); Assert.False(m3.IsVirtual); var m4 = sorted[4] as MethodSymbol; Assert.Equal("M4", m4.Name); Assert.False(m4.IsAbstract); Assert.True(m4.IsOverride); Assert.False(m4.IsSealed); Assert.False(m4.IsVirtual); var m5 = sorted[5] as MethodSymbol; Assert.Equal("M5", m5.Name); Assert.False(m5.IsAbstract); Assert.False(m5.IsOverride); Assert.False(m5.IsSealed); Assert.False(m5.IsVirtual); Assert.True(m5.IsStatic); var m6 = sorted[6] as MethodSymbol; Assert.Equal("M6", m6.Name); Assert.False(m6.IsAbstract); Assert.True(m6.IsOverride); Assert.False(m6.IsSealed); Assert.False(m6.IsVirtual); #endregion #region "Abc" var type2 = type1.BaseType(); Assert.Equal("Abc", type2.Name); mems = type2.GetMembers(); Assert.Equal(8, mems.Length); sorted = (from m in mems orderby m.Name select m).ToArray(); var mm = sorted[2] as FieldSymbol; Assert.Equal("M1", mm.Name); Assert.False(mm.IsAbstract); Assert.False(mm.IsOverride); Assert.False(mm.IsSealed); Assert.False(mm.IsVirtual); m0 = sorted[0] as MethodSymbol; Assert.Equal(WellKnownMemberNames.InstanceConstructorName, m0.Name); Assert.False(m0.IsAbstract); Assert.False(m0.IsOverride); Assert.False(m0.IsSealed); Assert.False(m0.IsVirtual); m1 = sorted[1] as MethodSymbol; Assert.Equal("M0", m1.Name); Assert.True(m1.IsAbstract); Assert.False(m1.IsOverride); Assert.False(m1.IsSealed); Assert.False(m1.IsVirtual); m2 = sorted[3] as MethodSymbol; Assert.Equal("M2", m2.Name); Assert.True(m2.IsAbstract); Assert.False(m2.IsOverride); Assert.False(m2.IsSealed); Assert.False(m2.IsVirtual); m3 = sorted[4] as MethodSymbol; Assert.Equal("M3", m3.Name); Assert.False(m3.IsAbstract); Assert.False(m3.IsOverride); Assert.False(m3.IsSealed); Assert.True(m3.IsVirtual); m4 = sorted[5] as MethodSymbol; Assert.Equal("M4", m4.Name); Assert.False(m4.IsAbstract); Assert.False(m4.IsOverride); Assert.False(m4.IsSealed); Assert.True(m4.IsVirtual); m5 = sorted[6] as MethodSymbol; Assert.Equal("M5", m5.Name); Assert.False(m5.IsAbstract); Assert.False(m5.IsOverride); Assert.False(m5.IsSealed); Assert.False(m5.IsVirtual); Assert.True(m5.IsStatic); m6 = sorted[7] as MethodSymbol; Assert.Equal("M6", m6.Name); Assert.True(m6.IsAbstract); Assert.False(m6.IsOverride); Assert.False(m6.IsSealed); Assert.False(m6.IsVirtual); #endregion } [Fact] public void OverloadMethodsCrossTrees() { var text = @" using System; namespace NS { public class A { public void Overloads(ushort p) { } public void Overloads(A p) { } } } "; var text1 = @" namespace NS { using System; public class B : A { public void Overloads(ref A p) { } public string Overloads(B p) { return null; } protected long Overloads(A p, long p2) { return p2; } } } "; var text2 = @" namespace NS { public class Test { public class C : B { protected long Overloads(A p, B p2) { return 1; } } public static void Main() { var obj = new C(); A a = obj; obj.Overloads(ref a); obj.Overloads(obj); } } } "; var comp = CreateCompilation(new[] { text, text1, text2 }); // Not impl errors // Assert.Equal(0, comp.GetDiagnostics().Count()); var ns = comp.GlobalNamespace.GetMembers("NS").Single() as NamespaceSymbol; var type1 = (ns.GetTypeMembers("Test").Single() as NamedTypeSymbol).GetTypeMembers("C", 0).Single() as NamedTypeSymbol; Assert.Equal(Accessibility.Public, type1.DeclaredAccessibility); var mems = type1.GetMembers(); Assert.Equal(2, mems.Length); var mems1 = type1.BaseType().GetMembers(); Assert.Equal(4, mems1.Length); var mems2 = type1.BaseType().BaseType().GetMembers(); Assert.Equal(3, mems2.Length); var list = new List<Symbol>(); list.AddRange(mems); list.AddRange(mems1); list.AddRange(mems2); var sorted = (from m in list orderby m.Name select m).ToArray(); var m0 = sorted[0] as MethodSymbol; Assert.Equal(WellKnownMemberNames.InstanceConstructorName, m0.Name); m0 = sorted[1] as MethodSymbol; Assert.Equal(WellKnownMemberNames.InstanceConstructorName, m0.Name); m0 = sorted[2] as MethodSymbol; Assert.Equal(WellKnownMemberNames.InstanceConstructorName, m0.Name); var m1 = sorted[3] as MethodSymbol; Assert.Equal("System.Int64 NS.Test.C.Overloads(NS.A p, NS.B p2)", m1.ToTestDisplayString()); m1 = sorted[4] as MethodSymbol; Assert.Equal("void NS.B.Overloads(ref NS.A p)", m1.ToTestDisplayString()); m1 = sorted[5] as MethodSymbol; Assert.Equal("System.String NS.B.Overloads(NS.B p)", m1.ToTestDisplayString()); m1 = sorted[6] as MethodSymbol; Assert.Equal("System.Int64 NS.B.Overloads(NS.A p, System.Int64 p2)", m1.ToTestDisplayString()); m1 = sorted[7] as MethodSymbol; Assert.Equal("void NS.A.Overloads(System.UInt16 p)", m1.ToTestDisplayString()); m1 = sorted[8] as MethodSymbol; Assert.Equal("void NS.A.Overloads(NS.A p)", m1.ToTestDisplayString()); } [WorkItem(537752, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537752")] [Fact] public void OverloadMethodsCrossComps() { var text = @" namespace NS { public class A { public void Overloads(ushort p) { } public void Overloads(A p) { } } } "; var text1 = @" namespace NS { public class B : A { public void Overloads(ref A p) { } public string Overloads(B p) { return null; } protected long Overloads(A p, long p2) { return p2; } } } "; var text2 = @" namespace NS { public class Test { public class C : B { protected long Overloads(A p, B p2) { return 1; } } public static void Main() { C obj = new C(); // var NotImpl ??? A a = obj; obj.Overloads(ref a); obj.Overloads(obj); } } } "; var comp1 = CreateCompilation(text); var compRef1 = new CSharpCompilationReference(comp1); var comp2 = CreateCompilation(new string[] { text1 }, new List<MetadataReference>() { compRef1 }, assemblyName: "Test2"); //Compilation.Create(outputName: "Test2", options: CompilationOptions.Default, // syntaxTrees: new SyntaxTree[] { SyntaxTree.ParseCompilationUnit(text1) }, // references: new MetadataReference[] { compRef1, GetCorlibReference() }); var compRef2 = new CSharpCompilationReference(comp2); var comp = CreateCompilation(new string[] { text2 }, new List<MetadataReference>() { compRef1, compRef2 }, assemblyName: "Test3"); //Compilation.Create(outputName: "Test3", options: CompilationOptions.Default, // syntaxTrees: new SyntaxTree[] { SyntaxTree.ParseCompilationUnit(text2) }, // references: new MetadataReference[] { compRef1, compRef2, GetCorlibReference() }); Assert.Equal(0, comp1.GetDiagnostics().Count()); Assert.Equal(0, comp2.GetDiagnostics().Count()); Assert.Equal(0, comp.GetDiagnostics().Count()); //string errs = String.Empty; //foreach (var e in comp.GetDiagnostics()) //{ // errs += e.Info.ToString() + "\r\n"; //} //Assert.Equal(String.Empty, errs); var ns = comp.GlobalNamespace.GetMembers("NS").Single() as NamespaceSymbol; var type1 = (ns.GetTypeMembers("Test").Single() as NamedTypeSymbol).GetTypeMembers("C", 0).Single() as NamedTypeSymbol; Assert.Equal(Accessibility.Public, type1.DeclaredAccessibility); var mems = type1.GetMembers(); Assert.Equal(2, mems.Length); var mems1 = type1.BaseType().GetMembers(); Assert.Equal(4, mems1.Length); var mems2 = type1.BaseType().BaseType().GetMembers(); Assert.Equal(3, mems2.Length); var list = new List<Symbol>(); list.AddRange(mems); list.AddRange(mems1); list.AddRange(mems2); var sorted = (from m in list orderby m.Name select m).ToArray(); var m0 = sorted[0] as MethodSymbol; Assert.Equal(WellKnownMemberNames.InstanceConstructorName, m0.Name); m0 = sorted[1] as MethodSymbol; Assert.Equal(WellKnownMemberNames.InstanceConstructorName, m0.Name); m0 = sorted[2] as MethodSymbol; Assert.Equal(WellKnownMemberNames.InstanceConstructorName, m0.Name); var m1 = sorted[3] as MethodSymbol; Assert.Equal("System.Int64 NS.Test.C.Overloads(NS.A p, NS.B p2)", m1.ToTestDisplayString()); m1 = sorted[4] as MethodSymbol; Assert.Equal("void NS.B.Overloads(ref NS.A p)", m1.ToTestDisplayString()); m1 = sorted[5] as MethodSymbol; Assert.Equal("System.String NS.B.Overloads(NS.B p)", m1.ToTestDisplayString()); m1 = sorted[6] as MethodSymbol; Assert.Equal("System.Int64 NS.B.Overloads(NS.A p, System.Int64 p2)", m1.ToTestDisplayString()); m1 = sorted[7] as MethodSymbol; Assert.Equal("void NS.A.Overloads(System.UInt16 p)", m1.ToTestDisplayString()); m1 = sorted[8] as MethodSymbol; Assert.Equal("void NS.A.Overloads(NS.A p)", m1.ToTestDisplayString()); } [WorkItem(537754, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537754")] [Fact] public void PartialMethodsCrossTrees() { var text = @" namespace NS { public partial struct PS { partial void M0(string p); partial class GPC<T> { partial void GM0(T p1, short p2); } } } "; var text1 = @" namespace NS { partial struct PS { partial void M0(string p) { } partial void M1(params ulong[] ary); public partial class GPC<T> { partial void GM0(T p1, short p2) { } partial void GM1<V>(T p1, V p2); } } } "; var text2 = @" namespace NS { partial struct PS { partial void M1(params ulong[] ary) {} partial void M2(sbyte p); partial class GPC<T> { partial void GM1<V>(T p1, V p2) { } } } } "; var comp = CreateCompilation(new[] { text, text1, text2 }); Assert.Equal(0, comp.GetDiagnostics().Count()); var ns = comp.GlobalNamespace.GetMembers("NS").Single() as NamespaceSymbol; var type1 = ns.GetTypeMembers("PS", 0).Single() as NamedTypeSymbol; // Bug // Assert.Equal(Accessibility.Public, type1.DeclaredAccessibility); Assert.Equal(3, type1.Locations.Length); Assert.False(type1.IsReferenceType); Assert.True(type1.IsValueType); var mems = type1.GetMembers(); Assert.Equal(5, mems.Length); var sorted = (from m in mems orderby m.Name select m).ToArray(); var m0 = sorted[0] as MethodSymbol; Assert.Equal(WellKnownMemberNames.InstanceConstructorName, m0.Name); Assert.Equal(Accessibility.Public, m0.DeclaredAccessibility); Assert.Equal(3, m0.Locations.Length); var m2 = sorted[2] as MethodSymbol; Assert.Equal("M0", m2.Name); Assert.Equal(Accessibility.Private, m2.DeclaredAccessibility); Assert.Equal(1, m2.Locations.Length); Assert.True(m2.ReturnsVoid); var m3 = sorted[3] as MethodSymbol; Assert.Equal("M1", m3.Name); Assert.Equal(Accessibility.Private, m3.DeclaredAccessibility); Assert.Equal(1, m3.Locations.Length); var m4 = sorted[4] as MethodSymbol; Assert.Equal("M2", m4.Name); Assert.Equal(Accessibility.Private, m4.DeclaredAccessibility); Assert.Equal(1, m4.Locations.Length); #region "GPC" var type2 = sorted[1] as NamedTypeSymbol; Assert.Equal("NS.PS.GPC<T>", type2.ToTestDisplayString()); Assert.True(type2.IsNestedType()); // Bug Assert.Equal(Accessibility.Public, type2.DeclaredAccessibility); Assert.Equal(3, type2.Locations.Length); Assert.False(type2.IsValueType); Assert.True(type2.IsReferenceType); mems = type2.GetMembers(); // Assert.Equal(3, mems.Count()); sorted = (from m in mems orderby m.Name select m).ToArray(); m0 = sorted[0] as MethodSymbol; Assert.Equal(WellKnownMemberNames.InstanceConstructorName, m0.Name); Assert.Equal(Accessibility.Public, m0.DeclaredAccessibility); Assert.Equal(3, m0.Locations.Length); var mm = sorted[1] as MethodSymbol; Assert.Equal("GM0", mm.Name); Assert.Equal(Accessibility.Private, mm.DeclaredAccessibility); Assert.Equal(1, mm.Locations.Length); m2 = sorted[2] as MethodSymbol; Assert.Equal("GM1", m2.Name); Assert.Equal(Accessibility.Private, m2.DeclaredAccessibility); Assert.Equal(1, m2.Locations.Length); Assert.True(m2.ReturnsVoid); #endregion } [WorkItem(537755, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537755")] [Fact] public void PartialMethodsWithRefParams() { var text = @" namespace NS { public partial class PC { partial void M0(ref long p); partial void M1(ref string p); } partial class PC { partial void M0(ref long p) {} partial void M1(ref string p) {} } } "; var comp = CreateCompilation(text); Assert.Equal(0, comp.GetDiagnostics().Count()); var ns = comp.GlobalNamespace.GetMembers("NS").Single() as NamespaceSymbol; var type1 = ns.GetTypeMembers("PC", 0).Single() as NamedTypeSymbol; Assert.Equal(Accessibility.Public, type1.DeclaredAccessibility); Assert.Equal(2, type1.Locations.Length); Assert.True(type1.IsReferenceType); Assert.False(type1.IsValueType); var mems = type1.GetMembers(); // Bug: actual 5 Assert.Equal(3, mems.Length); var sorted = (from m in mems orderby m.Name select m).ToArray(); var m1 = sorted[0] as MethodSymbol; Assert.Equal(WellKnownMemberNames.InstanceConstructorName, m1.Name); Assert.Equal(Accessibility.Public, m1.DeclaredAccessibility); Assert.Equal(2, m1.Locations.Length); var m2 = sorted[1] as MethodSymbol; Assert.Equal("M0", m2.Name); Assert.Equal(Accessibility.Private, m2.DeclaredAccessibility); Assert.Equal(1, m2.Locations.Length); Assert.True(m2.ReturnsVoid); var m3 = sorted[2] as MethodSymbol; Assert.Equal("M1", m3.Name); Assert.Equal(Accessibility.Private, m3.DeclaredAccessibility); Assert.Equal(1, m3.Locations.Length); Assert.True(m3.ReturnsVoid); } [WorkItem(2358, "DevDiv_Projects/Roslyn")] [Fact] public void ExplicitInterfaceImplementation() { var text = @" interface ISubFuncProp { } interface Interface3 { System.Collections.Generic.List<ISubFuncProp> Goo(); } interface Interface3Derived : Interface3 { } public class DerivedClass : Interface3Derived { System.Collections.Generic.List<ISubFuncProp> Interface3.Goo() { return null; } System.Collections.Generic.List<ISubFuncProp> Goo() { return null; } }"; var comp = CreateCompilation(text); var derivedClass = (NamedTypeSymbol)comp.SourceModule.GlobalNamespace.GetMembers("DerivedClass")[0]; var members = derivedClass.GetMembers(); Assert.Equal(3, members.Length); } [Fact] public void SubstitutedExplicitInterfaceImplementation() { var text = @" public class A<T> { public interface I<U> { void M<V>(T t, U u, V v); } } public class B<Q, R> : A<Q>.I<R> { void A<Q>.I<R>.M<S>(Q q, R r, S s) { } } public class C : B<int, long> { }"; var comp = CreateCompilation(text); var classB = (NamedTypeSymbol)comp.GlobalNamespace.GetMembers("B").Single(); var classBTypeArguments = classB.TypeArguments(); Assert.Equal(2, classBTypeArguments.Length); Assert.Equal("Q", classBTypeArguments[0].Name); Assert.Equal("R", classBTypeArguments[1].Name); var classBMethodM = (MethodSymbol)classB.GetMembers().Single(sym => sym.Name.EndsWith("M", StringComparison.Ordinal)); var classBMethodMTypeParameters = classBMethodM.TypeParameters; Assert.Equal(1, classBMethodMTypeParameters.Length); Assert.Equal("S", classBMethodMTypeParameters[0].Name); var classBMethodMParameters = classBMethodM.Parameters; Assert.Equal(3, classBMethodMParameters.Length); Assert.Equal(classBTypeArguments[0], classBMethodMParameters[0].Type); Assert.Equal(classBTypeArguments[1], classBMethodMParameters[1].Type); Assert.Equal(classBMethodMTypeParameters[0], classBMethodMParameters[2].Type); var classC = (NamedTypeSymbol)comp.GlobalNamespace.GetMembers("C").Single(); var classCBase = classC.BaseType(); Assert.Equal(classB, classCBase.ConstructedFrom); var classCBaseTypeArguments = classCBase.TypeArguments(); Assert.Equal(2, classCBaseTypeArguments.Length); Assert.Equal(SpecialType.System_Int32, classCBaseTypeArguments[0].SpecialType); Assert.Equal(SpecialType.System_Int64, classCBaseTypeArguments[1].SpecialType); var classCBaseMethodM = (MethodSymbol)classCBase.GetMembers().Single(sym => sym.Name.EndsWith("M", StringComparison.Ordinal)); Assert.NotEqual(classBMethodM, classCBaseMethodM); var classCBaseMethodMTypeParameters = classCBaseMethodM.TypeParameters; Assert.Equal(1, classCBaseMethodMTypeParameters.Length); Assert.Equal("S", classCBaseMethodMTypeParameters[0].Name); var classCBaseMethodMParameters = classCBaseMethodM.Parameters; Assert.Equal(3, classCBaseMethodMParameters.Length); Assert.Equal(classCBaseTypeArguments[0], classCBaseMethodMParameters[0].Type); Assert.Equal(classCBaseTypeArguments[1], classCBaseMethodMParameters[1].Type); Assert.Equal(classCBaseMethodMTypeParameters[0], classCBaseMethodMParameters[2].Type); } #region Regressions [WorkItem(527149, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/527149")] [Fact] public void MethodWithParamsInParameters() { var text = @"class C { void F1(params int[] a) { } } "; var comp = CreateEmptyCompilation(text); var c = comp.GlobalNamespace.GetTypeMembers("C").Single(); var f1 = c.GetMembers("F1").Single() as MethodSymbol; Assert.Equal("void C.F1(params System.Int32[missing][] a)", f1.ToTestDisplayString()); } [WorkItem(537352, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537352")] [Fact] public void Arglist() { string code = @" class AA { public static int Method1(__arglist) { } }"; var comp = CreateCompilation(code); NamedTypeSymbol nts = comp.Assembly.GlobalNamespace.GetTypeMembers()[0]; Assert.Equal("AA", nts.ToTestDisplayString()); Assert.Empty(comp.GetDeclarationDiagnostics()); Assert.Equal("System.Int32 AA.Method1(__arglist)", nts.GetMembers("Method1").Single().ToTestDisplayString()); } [WorkItem(537877, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537877")] [Fact] public void ExpImpInterfaceWithGlobal() { var text = @" using System; namespace N1 { interface I1 { int Method(); } } namespace N2 { class ExpImpl : N1.I1 { int global::N1.I1.Method() { return 42; } ExpImpl(){} } } "; var comp = CreateCompilation(text); Assert.Equal(0, comp.GetDeclarationDiagnostics().Count()); var ns = comp.GlobalNamespace.GetMembers("N2").Single() as NamespaceSymbol; var type1 = ns.GetTypeMembers("ExpImpl", 0).Single() as NamedTypeSymbol; var m1 = type1.GetMembers().FirstOrDefault() as MethodSymbol; Assert.Equal("System.Int32 N2.ExpImpl.N1.I1.Method()", m1.ToTestDisplayString()); var em1 = m1.ExplicitInterfaceImplementations.First() as MethodSymbol; Assert.Equal("System.Int32 N1.I1.Method()", em1.ToTestDisplayString()); } [WorkItem(537877, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537877")] [Fact] public void BaseInterfaceNameWithAlias() { var text = @" using N1Alias = N1; namespace N1 { interface I1 {} } namespace N2 { class N1Alias {} class Test : N1Alias::I1 { static int Main() { Test t = new Test(); return 0; } } } "; var comp = CreateCompilation(text); Assert.Equal(0, comp.GetDeclarationDiagnostics().Count()); var n2 = comp.GlobalNamespace.GetMembers("N2").Single() as NamespaceSymbol; var test = n2.GetTypeMembers("Test").Single() as NamedTypeSymbol; var bt = test.Interfaces().Single() as NamedTypeSymbol; Assert.Equal("N1.I1", bt.ToTestDisplayString()); } [WorkItem(538209, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538209")] [Fact] public void ParameterAccessibility01() { var text = @" using System; class MyClass { private class MyInner { public int MyMeth(MyInner2 arg) { return arg.intI; } } protected class MyInner2 { public int intI = 2; } public static int Main() { MyInner MI = new MyInner(); if (MI.MyMeth(new MyInner2()) == 2) { return 0; } else { return 1; } } } "; var comp = CreateCompilation(text); Assert.Equal(0, comp.GetDeclarationDiagnostics().Count()); } [WorkItem(537877, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537877")] [Fact] public void MethodsWithSameSigDiffReturnType() { var text = @" class Test { public int M1() { } float M1() { } } "; var comp = CreateCompilation(text); var test = comp.GlobalNamespace.GetTypeMembers("Test").Single() as NamedTypeSymbol; var members = test.GetMembers("M1"); Assert.Equal(2, members.Length); Assert.Equal("System.Int32 Test.M1()", members[0].ToTestDisplayString()); Assert.Equal("System.Single Test.M1()", members[1].ToTestDisplayString()); } [Fact] public void OverriddenMethod01() { var text = @" class A { public virtual void F(object[] args) {} } class B : A { public override void F(params object[] args) {} public static void Main(B b) { b.F(// yes, there is a parse error here } } "; var comp = CreateCompilation(text); var a = comp.GlobalNamespace.GetTypeMembers("A").Single() as NamedTypeSymbol; var b = comp.GlobalNamespace.GetTypeMembers("B").Single() as NamedTypeSymbol; var f = b.GetMembers("F").Single() as MethodSymbol; Assert.True(f.IsOverride); var f2 = f.OverriddenMethod; Assert.NotNull(f2); Assert.Equal("A", f2.ContainingSymbol.Name); } #endregion [WorkItem(537401, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537401")] [Fact] public void MethodEscapedIdentifier() { var text = @" interface @void { @void @return(@void @in); }; class @int { virtual @int @float(@int @in); }; class C1 : @int, @void { @void @void.@return(@void @in) { return null; } override @int @float(@int @in) { return null; } } "; var comp = CreateCompilation(Parse(text)); NamedTypeSymbol c1 = (NamedTypeSymbol)comp.SourceModule.GlobalNamespace.GetMembers("C1").Single(); // Per explanation from NGafter: // // We intentionally escape keywords that appear in the type qualification of the interface name // on interface implementation members. That is necessary to distinguish I<int>.F from I<@int>.F, // for example, which might both be members in a class. An alternative would be to stop using the // abbreviated names for the built-in types, but since we may want to use these names in // diagnostics the @-escaped version is preferred. // MethodSymbol mreturn = (MethodSymbol)c1.GetMembers("@void.return").Single(); Assert.Equal("@void.return", mreturn.Name); Assert.Equal("C1.@void.@return(@void)", mreturn.ToString()); NamedTypeSymbol rvoid = (NamedTypeSymbol)mreturn.ReturnType; Assert.Equal("void", rvoid.Name); Assert.Equal("@void", rvoid.ToString()); MethodSymbol mvoidreturn = (MethodSymbol)mreturn.ExplicitInterfaceImplementations.Single(); Assert.Equal("return", mvoidreturn.Name); Assert.Equal("@void.@return(@void)", mvoidreturn.ToString()); ParameterSymbol pin = mreturn.Parameters.Single(); Assert.Equal("in", pin.Name); Assert.Equal("@in", pin.ToDisplayString( new SymbolDisplayFormat( parameterOptions: SymbolDisplayParameterOptions.IncludeName, miscellaneousOptions: SymbolDisplayMiscellaneousOptions.EscapeKeywordIdentifiers))); MethodSymbol mfloat = (MethodSymbol)c1.GetMembers("float").Single(); Assert.Equal("float", mfloat.Name); Assert.Empty(c1.GetMembers("@float")); } [Fact] public void ExplicitInterfaceImplementationSimple() { string text = @" interface I { void Method(); } class C : I { void I.Method() { } } "; var comp = CreateCompilation(Parse(text)); var globalNamespace = comp.GlobalNamespace; var @interface = (NamedTypeSymbol)globalNamespace.GetTypeMembers("I").Single(); Assert.Equal(TypeKind.Interface, @interface.TypeKind); var interfaceMethod = (MethodSymbol)@interface.GetMembers("Method").Single(); var @class = (NamedTypeSymbol)globalNamespace.GetTypeMembers("C").Single(); Assert.Equal(TypeKind.Class, @class.TypeKind); Assert.True(@class.Interfaces().Contains(@interface)); var classMethod = (MethodSymbol)@class.GetMembers("I.Method").Single(); Assert.Equal(MethodKind.ExplicitInterfaceImplementation, classMethod.MethodKind); var explicitImpl = classMethod.ExplicitInterfaceImplementations.Single(); Assert.Equal(interfaceMethod, explicitImpl); var typeDef = (Cci.ITypeDefinition)@class.GetCciAdapter(); var module = new PEAssemblyBuilder((SourceAssemblySymbol)@class.ContainingAssembly, EmitOptions.Default, OutputKind.DynamicallyLinkedLibrary, GetDefaultModulePropertiesForSerialization(), SpecializedCollections.EmptyEnumerable<ResourceDescription>()); var context = new EmitContext(module, null, new DiagnosticBag(), metadataOnly: false, includePrivateMembers: true); var explicitOverride = typeDef.GetExplicitImplementationOverrides(context).Single(); Assert.Equal(@class, explicitOverride.ContainingType.GetInternalSymbol()); Assert.Equal(classMethod, explicitOverride.ImplementingMethod.GetInternalSymbol()); Assert.Equal(interfaceMethod, explicitOverride.ImplementedMethod.GetInternalSymbol()); context.Diagnostics.Verify(); } [Fact] public void ExplicitInterfaceImplementationCorLib() { string text = @" class F : System.IFormattable { string System.IFormattable.ToString(string format, System.IFormatProvider formatProvider) { return null; } } "; var comp = CreateCompilation(Parse(text)); var globalNamespace = comp.GlobalNamespace; var systemNamespace = (NamespaceSymbol)globalNamespace.GetMembers("System").Single(); var @interface = (NamedTypeSymbol)systemNamespace.GetTypeMembers("IFormattable").Single(); Assert.Equal(TypeKind.Interface, @interface.TypeKind); var interfaceMethod = (MethodSymbol)@interface.GetMembers("ToString").Single(); var @class = (NamedTypeSymbol)globalNamespace.GetTypeMembers("F").Single(); Assert.Equal(TypeKind.Class, @class.TypeKind); Assert.True(@class.Interfaces().Contains(@interface)); var classMethod = (MethodSymbol)@class.GetMembers("System.IFormattable.ToString").Single(); Assert.Equal(MethodKind.ExplicitInterfaceImplementation, classMethod.MethodKind); var explicitImpl = classMethod.ExplicitInterfaceImplementations.Single(); Assert.Equal(interfaceMethod, explicitImpl); var typeDef = (Cci.ITypeDefinition)@class.GetCciAdapter(); var module = new PEAssemblyBuilder((SourceAssemblySymbol)@class.ContainingAssembly, EmitOptions.Default, OutputKind.DynamicallyLinkedLibrary, GetDefaultModulePropertiesForSerialization(), SpecializedCollections.EmptyEnumerable<ResourceDescription>()); var context = new EmitContext(module, null, new DiagnosticBag(), metadataOnly: false, includePrivateMembers: true); var explicitOverride = typeDef.GetExplicitImplementationOverrides(context).Single(); Assert.Equal(@class, explicitOverride.ContainingType.GetInternalSymbol()); Assert.Equal(classMethod, explicitOverride.ImplementingMethod.GetInternalSymbol()); Assert.Equal(interfaceMethod, explicitOverride.ImplementedMethod.GetInternalSymbol()); context.Diagnostics.Verify(); } [Fact] public void ExplicitInterfaceImplementationRef() { string text = @" interface I { ref int Method(ref int i); } class C : I { ref int I.Method(ref int i) { return ref i; } } "; var comp = CreateCompilationWithMscorlib461(text); var globalNamespace = comp.GlobalNamespace; var @interface = (NamedTypeSymbol)globalNamespace.GetTypeMembers("I").Single(); Assert.Equal(TypeKind.Interface, @interface.TypeKind); var interfaceMethod = (MethodSymbol)@interface.GetMembers("Method").Single(); Assert.Equal(RefKind.Ref, interfaceMethod.RefKind); var @class = (NamedTypeSymbol)globalNamespace.GetTypeMembers("C").Single(); Assert.Equal(TypeKind.Class, @class.TypeKind); Assert.True(@class.Interfaces().Contains(@interface)); var classMethod = (MethodSymbol)@class.GetMembers("I.Method").Single(); Assert.Equal(MethodKind.ExplicitInterfaceImplementation, classMethod.MethodKind); Assert.Equal(RefKind.Ref, classMethod.RefKind); var explicitImpl = classMethod.ExplicitInterfaceImplementations.Single(); Assert.Equal(interfaceMethod, explicitImpl); var typeDef = (Cci.ITypeDefinition)@class.GetCciAdapter(); var module = new PEAssemblyBuilder((SourceAssemblySymbol)@class.ContainingAssembly, EmitOptions.Default, OutputKind.DynamicallyLinkedLibrary, GetDefaultModulePropertiesForSerialization(), SpecializedCollections.EmptyEnumerable<ResourceDescription>()); var context = new EmitContext(module, null, new DiagnosticBag(), metadataOnly: false, includePrivateMembers: true); var explicitOverride = typeDef.GetExplicitImplementationOverrides(context).Single(); Assert.Equal(@class, explicitOverride.ContainingType.GetInternalSymbol()); Assert.Equal(classMethod, explicitOverride.ImplementingMethod.GetInternalSymbol()); Assert.Equal(interfaceMethod, explicitOverride.ImplementedMethod.GetInternalSymbol()); context.Diagnostics.Verify(); } [Fact] public void ExplicitInterfaceImplementationGeneric() { string text = @" namespace Namespace { interface I<T> { void Method(T t); } } class IC : Namespace.I<int> { void Namespace.I<int>.Method(int i) { } } "; var comp = CreateCompilation(Parse(text)); var globalNamespace = comp.GlobalNamespace; var systemNamespace = (NamespaceSymbol)globalNamespace.GetMembers("Namespace").Single(); var @interface = (NamedTypeSymbol)systemNamespace.GetTypeMembers("I", 1).Single(); Assert.Equal(TypeKind.Interface, @interface.TypeKind); var interfaceMethod = (MethodSymbol)@interface.GetMembers("Method").Single(); var @class = (NamedTypeSymbol)globalNamespace.GetTypeMembers("IC").Single(); Assert.Equal(TypeKind.Class, @class.TypeKind); var substitutedInterface = @class.Interfaces().Single(); Assert.Equal(@interface, substitutedInterface.ConstructedFrom); var substitutedInterfaceMethod = (MethodSymbol)substitutedInterface.GetMembers("Method").Single(); var classMethod = (MethodSymbol)@class.GetMembers("Namespace.I<System.Int32>.Method").Single(); Assert.Equal(MethodKind.ExplicitInterfaceImplementation, classMethod.MethodKind); var explicitImpl = classMethod.ExplicitInterfaceImplementations.Single(); Assert.Equal(substitutedInterface, explicitImpl.ContainingType); Assert.Equal(substitutedInterfaceMethod.OriginalDefinition, explicitImpl.OriginalDefinition); var typeDef = (Cci.ITypeDefinition)@class.GetCciAdapter(); var module = new PEAssemblyBuilder((SourceAssemblySymbol)@class.ContainingAssembly, EmitOptions.Default, OutputKind.DynamicallyLinkedLibrary, GetDefaultModulePropertiesForSerialization(), SpecializedCollections.EmptyEnumerable<ResourceDescription>()); var context = new EmitContext(module, null, new DiagnosticBag(), metadataOnly: false, includePrivateMembers: true); var explicitOverride = typeDef.GetExplicitImplementationOverrides(context).Single(); Assert.Equal(@class, explicitOverride.ContainingType.GetInternalSymbol()); Assert.Equal(classMethod, explicitOverride.ImplementingMethod.GetInternalSymbol()); var explicitOverrideImplementedMethod = explicitOverride.ImplementedMethod; Assert.Equal(substitutedInterface, explicitOverrideImplementedMethod.GetContainingType(context).GetInternalSymbol()); Assert.Equal(substitutedInterfaceMethod.Name, explicitOverrideImplementedMethod.Name); Assert.Equal(substitutedInterfaceMethod.Arity, explicitOverrideImplementedMethod.GenericParameterCount); context.Diagnostics.Verify(); } [Fact()] public void TestMetadataVirtual() { string text = @" class C { virtual void Method1() { } virtual void Method2() { } void Method3() { } void Method4() { } } "; var comp = CreateCompilation(Parse(text)); var @class = (NamedTypeSymbol)comp.GlobalNamespace.GetTypeMembers("C").Single(); var method1 = (SourceMemberMethodSymbol)@class.GetMembers("Method1").Single(); var method2 = (SourceMemberMethodSymbol)@class.GetMembers("Method2").Single(); var method3 = (SourceMemberMethodSymbol)@class.GetMembers("Method3").Single(); var method4 = (SourceMemberMethodSymbol)@class.GetMembers("Method4").Single(); Assert.True(method1.IsVirtual); Assert.True(method2.IsVirtual); Assert.False(method3.IsVirtual); Assert.False(method4.IsVirtual); //1 and 3 - read before set Assert.True(((Cci.IMethodDefinition)method1.GetCciAdapter()).IsVirtual); Assert.False(((Cci.IMethodDefinition)method3.GetCciAdapter()).IsVirtual); //2 and 4 - set before read method2.EnsureMetadataVirtual(); method4.EnsureMetadataVirtual(); //can set twice (e.g. if the method implicitly implements more than one interface method) method2.EnsureMetadataVirtual(); method4.EnsureMetadataVirtual(); Assert.True(((Cci.IMethodDefinition)method2.GetCciAdapter()).IsVirtual); Assert.True(((Cci.IMethodDefinition)method4.GetCciAdapter()).IsVirtual); //API view unchanged Assert.True(method1.IsVirtual); Assert.True(method2.IsVirtual); Assert.False(method3.IsVirtual); Assert.False(method4.IsVirtual); } [Fact] public void ExplicitStaticConstructor() { string text = @" class C { static C() { } } "; var comp = CreateCompilation(text); comp.VerifyDiagnostics(); var staticConstructor = comp.GlobalNamespace.GetMember<NamedTypeSymbol>("C").GetMember<MethodSymbol>(WellKnownMemberNames.StaticConstructorName); Assert.Equal(MethodKind.StaticConstructor, staticConstructor.MethodKind); Assert.Equal(Accessibility.Private, staticConstructor.DeclaredAccessibility); Assert.True(staticConstructor.IsStatic, "Static constructor should be static"); Assert.Equal(SpecialType.System_Void, staticConstructor.ReturnType.SpecialType); } [Fact] public void ImplicitStaticConstructor() { string text = @" class C { static int f = 1; //initialized in implicit static constructor } "; var comp = CreateCompilation(text); comp.VerifyDiagnostics( // (4,16): warning CS0414: The field 'C.f' is assigned but its value is never used // static int f = 1; //initialized in implicit static constructor Diagnostic(ErrorCode.WRN_UnreferencedFieldAssg, "f").WithArguments("C.f") ); var staticConstructor = comp.GlobalNamespace.GetMember<NamedTypeSymbol>("C").GetMember<MethodSymbol>(WellKnownMemberNames.StaticConstructorName); Assert.Equal(MethodKind.StaticConstructor, staticConstructor.MethodKind); Assert.Equal(Accessibility.Private, staticConstructor.DeclaredAccessibility); Assert.True(staticConstructor.IsStatic, "Static constructor should be static"); Assert.Equal(SpecialType.System_Void, staticConstructor.ReturnType.SpecialType); } [WorkItem(541834, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/541834")] [Fact] public void AccessorMethodAccessorOverriding() { var text = @" public class A { public virtual int P { get; set; } } public class B : A { public virtual int get_P() { return 0; } } public class C : B { public override int P { get; set; } } "; var comp = CreateCompilation(text); comp.VerifyDiagnostics(); var globalNamespace = comp.GlobalNamespace; var classA = globalNamespace.GetMember<NamedTypeSymbol>("A"); var classB = globalNamespace.GetMember<NamedTypeSymbol>("B"); var classC = globalNamespace.GetMember<NamedTypeSymbol>("C"); var methodA = classA.GetMember<PropertySymbol>("P").GetMethod; var methodB = classB.GetMember<MethodSymbol>("get_P"); var methodC = classC.GetMember<PropertySymbol>("P").GetMethod; var typeDefC = (Cci.ITypeDefinition)classC.GetCciAdapter(); var module = new PEAssemblyBuilder((SourceAssemblySymbol)classC.ContainingAssembly, EmitOptions.Default, OutputKind.DynamicallyLinkedLibrary, GetDefaultModulePropertiesForSerialization(), SpecializedCollections.EmptyEnumerable<ResourceDescription>()); var context = new EmitContext(module, null, new DiagnosticBag(), metadataOnly: false, includePrivateMembers: true); var explicitOverride = typeDefC.GetExplicitImplementationOverrides(context).Single(); Assert.Equal(classC, explicitOverride.ContainingType.GetInternalSymbol()); Assert.Equal(methodC, explicitOverride.ImplementingMethod.GetInternalSymbol()); Assert.Equal(methodA, explicitOverride.ImplementedMethod.GetInternalSymbol()); context.Diagnostics.Verify(); } [WorkItem(541834, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/541834")] [Fact] public void MethodAccessorMethodOverriding() { var text = @" public class A { public virtual int get_P() { return 0; } } public class B : A { public virtual int P { get; set; } } public class C : B { public override int get_P() { return 0; } } "; var comp = CreateCompilation(text); comp.VerifyDiagnostics(); var globalNamespace = comp.GlobalNamespace; var classA = globalNamespace.GetMember<NamedTypeSymbol>("A"); var classB = globalNamespace.GetMember<NamedTypeSymbol>("B"); var classC = globalNamespace.GetMember<NamedTypeSymbol>("C"); var methodA = classA.GetMember<MethodSymbol>("get_P"); var methodB = classB.GetMember<PropertySymbol>("P").GetMethod; var methodC = classC.GetMember<MethodSymbol>("get_P"); var typeDefC = (Cci.ITypeDefinition)classC.GetCciAdapter(); var module = new PEAssemblyBuilder((SourceAssemblySymbol)classC.ContainingAssembly, EmitOptions.Default, OutputKind.DynamicallyLinkedLibrary, GetDefaultModulePropertiesForSerialization(), SpecializedCollections.EmptyEnumerable<ResourceDescription>()); var context = new EmitContext(module, null, new DiagnosticBag(), metadataOnly: false, includePrivateMembers: true); var explicitOverride = typeDefC.GetExplicitImplementationOverrides(context).Single(); Assert.Equal(classC, explicitOverride.ContainingType.GetInternalSymbol()); Assert.Equal(methodC, explicitOverride.ImplementingMethod.GetInternalSymbol()); Assert.Equal(methodA, explicitOverride.ImplementedMethod.GetInternalSymbol()); context.Diagnostics.Verify(); } [WorkItem(543444, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543444")] [Fact] public void BadArityInOperatorDeclaration() { var text = @"class A { public static bool operator true(A x, A y) { return false; } } class B { public static B operator *(B x) { return null; } } "; var comp = CreateCompilation(text); comp.VerifyDiagnostics( // (3,33): error CS1020: Overloadable binary operator expected // public static bool operator true(A x, A y) { return false; } Diagnostic(ErrorCode.ERR_OvlBinaryOperatorExpected, "true"), // (8,30): error CS1019: Overloadable unary operator expected // public static B operator *(B x) { return null; } Diagnostic(ErrorCode.ERR_OvlUnaryOperatorExpected, "*"), // (3,33): error CS0216: The operator 'A.operator true(A, A)' requires a matching operator 'false' to also be defined // public static bool operator true(A x, A y) { return false; } Diagnostic(ErrorCode.ERR_OperatorNeedsMatch, "true").WithArguments("A.operator true(A, A)", "false") ); } [WorkItem(779441, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/779441")] [Fact] public void UserDefinedOperatorLocation() { var source = @" public class C { public static C operator +(C c) { return null; } } "; var keywordPos = source.IndexOf('+'); var parenPos = source.IndexOf('('); var comp = CreateCompilation(source); var symbol = comp.GlobalNamespace.GetMember<NamedTypeSymbol>("C").GetMembers(WellKnownMemberNames.UnaryPlusOperatorName).Single(); var span = symbol.Locations.Single().SourceSpan; Assert.Equal(keywordPos, span.Start); Assert.Equal(parenPos, span.End); } [WorkItem(779441, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/779441")] [Fact] public void UserDefinedConversionLocation() { var source = @" public class C { public static explicit operator string(C c) { return null; } } "; var keywordPos = source.IndexOf("string", StringComparison.Ordinal); var parenPos = source.IndexOf('('); var comp = CreateCompilation(source); var symbol = comp.GlobalNamespace.GetMember<NamedTypeSymbol>("C").GetMembers(WellKnownMemberNames.ExplicitConversionName).Single(); var span = symbol.Locations.Single().SourceSpan; Assert.Equal(keywordPos, span.Start); Assert.Equal(parenPos, span.End); } [WorkItem(787708, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/787708")] [Fact] public void PartialAsyncMethodInTypeWithAttributes() { var source = @" using System; class Attr : Attribute { public int P { get; set; } } [Attr(P = F)] partial class C { const int F = 1; partial void M(); async partial void M() { } } "; CreateCompilation(source).VerifyDiagnostics(); } [WorkItem(910100, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/910100")] [Fact] public void SubstitutedParameterEquality() { var source = @" class C { void M<T>(T t) { } } "; var comp = CreateCompilation(source); var type = comp.GlobalNamespace.GetMember<NamedTypeSymbol>("C"); var method = type.GetMember<MethodSymbol>("M"); var constructedMethod1 = method.Construct(type); var constructedMethod2 = method.Construct(type); Assert.Equal(constructedMethod1, constructedMethod2); Assert.NotSame(constructedMethod1, constructedMethod2); var substitutedParameter1 = constructedMethod1.Parameters.Single(); var substitutedParameter2 = constructedMethod2.Parameters.Single(); Assert.Equal(substitutedParameter1, substitutedParameter2); Assert.NotSame(substitutedParameter1, substitutedParameter2); } [WorkItem(910100, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/910100")] [Fact] public void ReducedExtensionMethodParameterEquality() { var source = @" static class C { static void M(this int i, string s) { } } "; var comp = CreateCompilation(source); var type = comp.GlobalNamespace.GetMember<NamedTypeSymbol>("C"); var method = type.GetMember<MethodSymbol>("M"); var reducedMethod1 = method.ReduceExtensionMethod(); var reducedMethod2 = method.ReduceExtensionMethod(); Assert.Equal(reducedMethod1, reducedMethod2); Assert.NotSame(reducedMethod1, reducedMethod2); var extensionParameter1 = reducedMethod1.Parameters.Single(); var extensionParameter2 = reducedMethod2.Parameters.Single(); Assert.Equal(extensionParameter1, extensionParameter2); Assert.NotSame(extensionParameter1, extensionParameter2); } [Fact] public void RefReturningVoidMethod() { var source = @" static class C { static ref void M() { } } "; CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (4,16): error CS1547: Keyword 'void' cannot be used in this context // static ref void M() { } Diagnostic(ErrorCode.ERR_NoVoidHere, "void").WithLocation(4, 16) ); } [Fact] [CompilerTrait(CompilerFeature.ReadOnlyReferences)] public void RefReadonlyReturningVoidMethod() { var source = @" static class C { static ref readonly void M() { } } "; CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (4,25): error CS1547: Keyword 'void' cannot be used in this context // static ref readonly void M() { } Diagnostic(ErrorCode.ERR_NoVoidHere, "void").WithLocation(4, 25) ); } [Fact] public void RefReturningVoidMethodNested() { var source = @" static class C { static void Main() { ref void M() { } } } "; CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (6,13): error CS1547: Keyword 'void' cannot be used in this context // ref void M() { } Diagnostic(ErrorCode.ERR_NoVoidHere, "void").WithLocation(6, 13), // (6,18): warning CS8321: The local function 'M' is declared but never used // ref void M() { } Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "M").WithArguments("M").WithLocation(6, 18) ); } [Fact] [CompilerTrait(CompilerFeature.ReadOnlyReferences)] public void RefReadonlyReturningVoidMethodNested() { var source = @" static class C { static void Main() { // valid ref readonly int M1() {throw null;} // not valid ref readonly void M2() {M1(); throw null;} M2(); } } "; var parseOptions = TestOptions.Regular; CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (10,22): error CS1547: Keyword 'void' cannot be used in this context // ref readonly void M2() {M1(); throw null;} Diagnostic(ErrorCode.ERR_NoVoidHere, "void").WithLocation(10, 22) ); } [Fact] public void RefReturningAsyncMethod() { var source = @" static class C { static async ref int M() { } } "; CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (4,18): error CS1073: Unexpected token 'ref' // static async ref int M() { } Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(4, 18), // (4,26): error CS0161: 'C.M()': not all code paths return a value // static async ref int M() { } Diagnostic(ErrorCode.ERR_ReturnExpected, "M").WithArguments("C.M()").WithLocation(4, 26) ); } [Fact] [CompilerTrait(CompilerFeature.ReadOnlyReferences)] public void RefReadonlyReturningAsyncMethod() { var source = @" static class C { static async ref readonly int M() { } } "; CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (4,18): error CS1073: Unexpected token 'ref' // static async ref readonly int M() { } Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(4, 18), // (4,35): error CS0161: 'C.M()': not all code paths return a value // static async ref readonly int M() { } Diagnostic(ErrorCode.ERR_ReturnExpected, "M").WithArguments("C.M()").WithLocation(4, 35) ); } [Fact] public void StaticMethodDoesNotRequireInstanceReceiver() { var source = @" class C { public static int M() => 42; }"; var compilation = CreateCompilation(source).VerifyDiagnostics(); var method = compilation.GetMember<MethodSymbol>("C.M"); Assert.False(method.RequiresInstanceReceiver); } [Fact] public void InstanceMethodRequiresInstanceReceiver() { var source = @" class C { public int M() => 42; }"; var compilation = CreateCompilation(source).VerifyDiagnostics(); var method = compilation.GetMember<MethodSymbol>("C.M"); Assert.True(method.RequiresInstanceReceiver); } [Fact] public void OrdinaryMethodIsNotConditional() { var source = @" class C { public void M() {} }"; var compilation = CreateCompilation(source).VerifyDiagnostics(); var method = compilation.GetMember<MethodSymbol>("C.M"); Assert.False(method.IsConditional); } [Fact] public void ConditionalMethodIsConditional() { var source = @" using System.Diagnostics; class C { [Conditional(""Debug"")] public void M() {} }"; var compilation = CreateCompilation(source).VerifyDiagnostics(); var method = compilation.GetMember<MethodSymbol>("C.M"); Assert.True(method.IsConditional); } [Fact] public void ConditionalMethodOverrideIsConditional() { var source = @" using System.Diagnostics; class Base { [Conditional(""Debug"")] public virtual void M() {} } class Derived : Base { public override void M() {} }"; var compilation = CreateCompilation(source).VerifyDiagnostics(); var method = compilation.GetMember<MethodSymbol>("Derived.M"); Assert.True(method.IsConditional); } [Fact] public void InvalidConditionalMethodIsConditional() { var source = @" using System.Diagnostics; class C { [Conditional(""Debug"")] public int M() => 42; }"; var compilation = CreateCompilation(source).VerifyDiagnostics( // (5,6): error CS0578: The Conditional attribute is not valid on 'C.M()' because its return type is not void // [Conditional("Debug")] Diagnostic(ErrorCode.ERR_ConditionalMustReturnVoid, @"Conditional(""Debug"")").WithArguments("C.M()").WithLocation(5, 6)); var method = compilation.GetMember<MethodSymbol>("C.M"); Assert.True(method.IsConditional); } [Fact, WorkItem(51082, "https://github.com/dotnet/roslyn/issues/51082")] public void IsPartialDefinitionOnNonPartial() { var source = @" class C { void M() {} } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics(); var m = comp.GetMember<MethodSymbol>("C.M").GetPublicSymbol(); Assert.False(m.IsPartialDefinition); } [Fact, WorkItem(51082, "https://github.com/dotnet/roslyn/issues/51082")] public void IsPartialDefinitionOnPartialDefinitionOnly() { var source = @" partial class C { partial void M(); } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics(); var m = comp.GetMember<MethodSymbol>("C.M").GetPublicSymbol(); Assert.True(m.IsPartialDefinition); Assert.Null(m.PartialDefinitionPart); Assert.Null(m.PartialImplementationPart); } [Fact, WorkItem(51082, "https://github.com/dotnet/roslyn/issues/51082")] public void IsPartialDefinitionWithPartialImplementation() { var source = @" partial class C { partial void M(); partial void M() {} } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics(); var m = comp.GetMember<MethodSymbol>("C.M").GetPublicSymbol(); Assert.True(m.IsPartialDefinition); Assert.Null(m.PartialDefinitionPart); Assert.False(m.PartialImplementationPart.IsPartialDefinition); } [Fact, WorkItem(51082, "https://github.com/dotnet/roslyn/issues/51082")] public void IsPartialDefinitionOnPartialImplementation_NonPartialClass() { var source = @" class C { partial void M(); partial void M() {} } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (4,18): error CS0751: A partial member must be declared within a partial type // partial void M(); Diagnostic(ErrorCode.ERR_PartialMemberOnlyInPartialClass, "M").WithLocation(4, 18), // (5,18): error CS0751: A partial member must be declared within a partial type // partial void M() {} Diagnostic(ErrorCode.ERR_PartialMemberOnlyInPartialClass, "M").WithLocation(5, 18) ); var m = comp.GetMember<MethodSymbol>("C.M").GetPublicSymbol(); Assert.True(m.IsPartialDefinition); Assert.Null(m.PartialDefinitionPart); Assert.False(m.PartialImplementationPart.IsPartialDefinition); } [Fact, WorkItem(51082, "https://github.com/dotnet/roslyn/issues/51082")] public void IsPartialDefinitionOnPartialImplementationOnly() { var source = @" partial class C { partial void M() {} } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (4,18): error CS0759: No defining declaration found for implementing declaration of partial method 'C.M()' // partial void M() {} Diagnostic(ErrorCode.ERR_PartialMethodMustHaveLatent, "M").WithArguments("C.M()").WithLocation(4, 18) ); var m = comp.GetMember<MethodSymbol>("C.M").GetPublicSymbol(); Assert.False(m.IsPartialDefinition); Assert.Null(m.PartialDefinitionPart); Assert.Null(m.PartialImplementationPart); } [Fact, WorkItem(51082, "https://github.com/dotnet/roslyn/issues/51082")] public void IsPartialDefinition_ReturnsFalseFromMetadata() { var source = @" public partial class C { public partial void M(); public partial void M() {} } "; CompileAndVerify(source, sourceSymbolValidator: module => { var m = module.GlobalNamespace.GetTypeMember("C").GetMethod("M").GetPublicSymbol(); Assert.True(m.IsPartialDefinition); Assert.Null(m.PartialDefinitionPart); Assert.False(m.PartialImplementationPart.IsPartialDefinition); }, symbolValidator: module => { var m = module.GlobalNamespace.GetTypeMember("C").GetMethod("M").GetPublicSymbol(); Assert.False(m.IsPartialDefinition); Assert.Null(m.PartialDefinitionPart); Assert.Null(m.PartialImplementationPart); }); } [Fact] public void IsPartialDefinition_OnPartialExtern() { var source = @" public partial class C { private partial void M(); private extern partial void M(); } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics(); var syntax = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(syntax); var methods = syntax.GetRoot().DescendantNodes().OfType<MethodDeclarationSyntax>().ToArray(); var partialDef = model.GetDeclaredSymbol(methods[0]); Assert.True(partialDef.IsPartialDefinition); var partialImpl = model.GetDeclaredSymbol(methods[1]); Assert.False(partialImpl.IsPartialDefinition); Assert.Same(partialDef.PartialImplementationPart, partialImpl); Assert.Same(partialImpl.PartialDefinitionPart, partialDef); Assert.Null(partialDef.PartialDefinitionPart); Assert.Null(partialImpl.PartialImplementationPart); } [Fact] public void IsPartialDefinition_Constructed() { var source = @" public partial class C { public partial void M<T>(); public partial void M<T>() { } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics(); var syntax = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(syntax); var type = syntax.GetRoot().DescendantNodes().OfType<ClassDeclarationSyntax>().Single(); var methods = syntax.GetRoot().DescendantNodes().OfType<MethodDeclarationSyntax>().ToArray(); var classC = model.GetDeclaredSymbol(type); var partialDef = model.GetDeclaredSymbol(methods[0]); var partialDefConstructed = partialDef.Construct(classC); // M<C>() Assert.True(partialDef.IsPartialDefinition); Assert.False(partialDefConstructed.IsPartialDefinition); var partialImpl = model.GetDeclaredSymbol(methods[1]); var partialImplConstructed = partialImpl.Construct(classC); // M<C>() Assert.False(partialImpl.IsPartialDefinition); Assert.False(partialImplConstructed.IsPartialDefinition); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/22598")] public void PartialMethodsLocationsAndSyntaxReferences() { var source1 = """ namespace N1 { partial class C1 { partial void PartialM(); } } """; var source2 = """ namespace N1 { partial class C1 { partial void PartialM() { } } } """; var comp = CreateCompilation([(source1, "source1"), (source2, "source2")]); comp.VerifyDiagnostics(); var method = (IMethodSymbol)comp.GetSymbolsWithName("PartialM").Single(); // For partial methods, Locations and DeclaringSyntaxReferences contain only one location Assert.Equal(1, method.Locations.Length); Assert.Equal(1, method.DeclaringSyntaxReferences.Length); // The single location is the definition part Assert.True(method.IsPartialDefinition); Assert.Null(method.PartialDefinitionPart); Assert.NotNull(method.PartialImplementationPart); // To get all locations, you need to use PartialImplementationPart var implementationPart = method.PartialImplementationPart; Assert.Equal(1, implementationPart.Locations.Length); Assert.Equal(1, implementationPart.DeclaringSyntaxReferences.Length); // Verify the locations are different Assert.NotEqual(method.Locations[0], implementationPart.Locations[0]); Assert.Equal("source1", method.Locations[0].SourceTree.FilePath); Assert.Equal("source2", implementationPart.Locations[0].SourceTree.FilePath); } } }