File: Symbols\Source\ModifierTests.cs
Web Access
Project: src\src\Compilers\CSharp\Test\Symbol\Microsoft.CodeAnalysis.CSharp.Symbol.UnitTests.csproj (Microsoft.CodeAnalysis.CSharp.Symbol.UnitTests)
// 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.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
 
namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
    public class ModifierTests : CSharpTestBase
    {
        [Fact]
        public void Simple1()
        {
            var text =
@"abstract class A : Base
{
    void M1() { }
    public void M2() { }
    protected void M3() { }
    internal void M4() { }
    protected internal void M5() { }
    internal abstract protected void M5_1() { }
    abstract protected internal void M5_2() { }
    private void M6() { }
    extern void M7();
    override sealed internal void M8() { }
    override internal sealed void M8_1() { }
    internal override sealed void M8_2() { }
    abstract internal void M9();
    override internal void M10() { }
    virtual internal void M11() { }
    static void M12() { }
}
abstract class Base
{
    virtual internal void M8() { }
    abstract internal void M10();
}";
            var comp = CreateCompilation(text);
            var global = comp.GlobalNamespace;
            var a = global.GetTypeMembers("A", 0).Single();
            var m1 = a.GetMembers("M1").Single() as MethodSymbol;
            Assert.Equal(Accessibility.Private, m1.DeclaredAccessibility);
            Assert.True(m1.ReturnsVoid);
            var m2 = a.GetMembers("M2").Single() as MethodSymbol;
            Assert.Equal(Accessibility.Public, m2.DeclaredAccessibility);
            var m3 = a.GetMembers("M3").Single() as MethodSymbol;
            Assert.Equal(Accessibility.Protected, m3.DeclaredAccessibility);
            var m4 = a.GetMembers("M4").Single() as MethodSymbol;
            Assert.Equal(Accessibility.Internal, m4.DeclaredAccessibility);
            var m5 = a.GetMembers("M5").Single() as MethodSymbol;
            Assert.Equal(Accessibility.ProtectedOrInternal, m5.DeclaredAccessibility);
            var m5_1 = a.GetMembers("M5_1").Single() as MethodSymbol;
            Assert.Equal(Accessibility.ProtectedOrInternal, m5_1.DeclaredAccessibility);
            Assert.True(m5_1.IsAbstract);
            var m5_2 = a.GetMembers("M5_2").Single() as MethodSymbol;
            Assert.Equal(Accessibility.ProtectedOrInternal, m5_2.DeclaredAccessibility);
            Assert.True(m5_2.IsAbstract);
            var m6 = a.GetMembers("M6").Single() as MethodSymbol;
            Assert.Equal(Accessibility.Private, m6.DeclaredAccessibility);
            var m7 = a.GetMembers("M7").Single() as MethodSymbol;
            Assert.True(m7.IsExtern);
            var m8 = a.GetMembers("M8").Single() as MethodSymbol;
            Assert.True(m8.IsOverride);
            Assert.True(m8.IsSealed);
            Assert.Equal(Accessibility.Internal, m8.DeclaredAccessibility);
            var m8_1 = a.GetMembers("M8_1").Single() as MethodSymbol;
            Assert.True(m8_1.IsOverride);
            Assert.True(m8_1.IsSealed);
            Assert.Equal(Accessibility.Internal, m8_1.DeclaredAccessibility);
            var m8_2 = a.GetMembers("M8_2").Single() as MethodSymbol;
            Assert.True(m8_2.IsOverride);
            Assert.True(m8_2.IsSealed);
            Assert.Equal(Accessibility.Internal, m8_2.DeclaredAccessibility);
            var m9 = a.GetMembers("M9").Single() as MethodSymbol;
            Assert.True(m9.IsAbstract);
            Assert.Equal(Accessibility.Internal, m9.DeclaredAccessibility);
            var m10 = a.GetMembers("M10").Single() as MethodSymbol;
            Assert.True(m10.IsOverride);
            Assert.Equal(Accessibility.Internal, m10.DeclaredAccessibility);
            var m11 = a.GetMembers("M11").Single() as MethodSymbol;
            Assert.True(m11.IsVirtual);
            Assert.Equal(Accessibility.Internal, m11.DeclaredAccessibility);
            var m12 = a.GetMembers("M12").Single() as MethodSymbol;
            Assert.True(m12.IsStatic);
        }
 
        [Fact]
        public void InScript()
        {
            var text =
@"
void M1() { }
public void M2() { }
protected void M3() { }
internal void M4() { }
protected internal void M5() { }
private void M6() { }
extern void M7();
static void M12() { }
";
 
            var comp = CreateCompilationWithMscorlib461(text, parseOptions: TestOptions.Script);
            var script = comp.ScriptClass;
            var m1 = script.GetMembers("M1").Single() as MethodSymbol;
            Assert.Equal(Accessibility.Private, m1.DeclaredAccessibility);
            var m2 = script.GetMembers("M2").Single() as MethodSymbol;
            Assert.Equal(Accessibility.Public, m2.DeclaredAccessibility);
            var m3 = script.GetMembers("M3").Single() as MethodSymbol;
            Assert.Equal(Accessibility.Protected, m3.DeclaredAccessibility);
            var m4 = script.GetMembers("M4").Single() as MethodSymbol;
            Assert.Equal(Accessibility.Internal, m4.DeclaredAccessibility);
            var m5 = script.GetMembers("M5").Single() as MethodSymbol;
            Assert.Equal(Accessibility.ProtectedOrInternal, m5.DeclaredAccessibility);
            var m6 = script.GetMembers("M6").Single() as MethodSymbol;
            Assert.Equal(Accessibility.Private, m6.DeclaredAccessibility);
            var m7 = script.GetMembers("M7").Single() as MethodSymbol;
            Assert.True(m7.IsExtern);
            var m12 = script.GetMembers("M12").Single() as MethodSymbol;
            Assert.True(m12.IsStatic);
 
            comp.VerifyDiagnostics(
                // (4,16): warning CS0628: 'M3()': new protected member declared in sealed type
                Diagnostic(ErrorCode.WRN_ProtectedInSealed, "M3").WithArguments("M3()"),
                // (6,25): warning CS0628: 'M5()': new protected member declared in sealed type
                Diagnostic(ErrorCode.WRN_ProtectedInSealed, "M5").WithArguments("M5()"),
                // (8,13): warning CS0626: Method, operator, or accessor 'M7()' is marked external and has no attributes on it. Consider adding a DllImport attribute to specify the external implementation.
                Diagnostic(ErrorCode.WRN_ExternMethodNoImplementation, "M7").WithArguments("M7()")
            );
        }
 
        [Fact]
        public void TypeMap()
        {
            var source = @"
struct S<T> where T : struct
{
}
";
 
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics();
 
            var intType = comp.GetSpecialType(SpecialType.System_Int32);
            var customModifiers = ImmutableArray.Create(CSharpCustomModifier.CreateOptional(intType));
 
            var structType = comp.GlobalNamespace.GetMember<NamedTypeSymbol>("S");
            var typeParamType = structType.TypeParameters.Single();
 
            var pointerType = new PointerTypeSymbol(TypeWithAnnotations.Create(typeParamType, customModifiers: customModifiers)); // NOTE: We're constructing this manually, since it's illegal.
            var arrayType = ArrayTypeSymbol.CreateCSharpArray(comp.Assembly, TypeWithAnnotations.Create(typeParamType, customModifiers: customModifiers)); // This is legal, but we're already manually constructing types.
 
            var typeMap = new TypeMap(ImmutableArray.Create(typeParamType), ImmutableArray.Create(TypeWithAnnotations.Create(intType)));
 
            var substitutedPointerType = (PointerTypeSymbol)typeMap.SubstituteType(pointerType).AsTypeSymbolOnly();
            var substitutedArrayType = (ArrayTypeSymbol)typeMap.SubstituteType(arrayType).AsTypeSymbolOnly();
 
            // The map changed the types.
            Assert.Equal(intType, substitutedPointerType.PointedAtType);
            Assert.Equal(intType, substitutedArrayType.ElementType);
 
            // The map preserved the custom modifiers.
            Assert.Equal(customModifiers, substitutedPointerType.PointedAtTypeWithAnnotations.CustomModifiers);
            Assert.Equal(customModifiers, substitutedArrayType.ElementTypeWithAnnotations.CustomModifiers);
        }
 
        [Fact, WorkItem(63758, "https://github.com/dotnet/roslyn/issues/63758")]
        public void ReadonlyParameter1()
        {
            CreateCompilation(@"
public class Base {
    public void M(ref readonly int X) {
    }
}").VerifyDiagnostics();
        }
 
        [Fact, WorkItem(63758, "https://github.com/dotnet/roslyn/issues/63758")]
        public void ReadonlyParameter2()
        {
            CreateCompilation(@"
public class Base {
    public void M(readonly ref int X) {
    }
}").VerifyDiagnostics(
            // (3,19): error CS9190: 'readonly' modifier must be specified after 'ref'.
            //     public void M(readonly ref int X) {
            Diagnostic(ErrorCode.ERR_RefReadOnlyWrongOrdering, "readonly").WithLocation(3, 19));
        }
 
        [Fact, WorkItem(63758, "https://github.com/dotnet/roslyn/issues/63758")]
        public void ReadonlyParameter3()
        {
            CreateCompilation(@"
public class Base {
    public void M(readonly int X) {
    }
}").VerifyDiagnostics(
                // (3,19): error CS9190: 'readonly' modifier must be specified after 'ref'.
                //     public void M(readonly int X) {
                Diagnostic(ErrorCode.ERR_RefReadOnlyWrongOrdering, "readonly").WithLocation(3, 19));
        }
 
        [Fact, WorkItem(63758, "https://github.com/dotnet/roslyn/issues/63758")]
        public void ReadonlyParameter4()
        {
            CreateCompilation(@"
public class Base {
    void M()
    {
        var v = (readonly int i) => { };
    }
}").VerifyDiagnostics(
                // (5,18): error CS9190: 'readonly' modifier must be specified after 'ref'.
                //         var v = (readonly int i) => { };
                Diagnostic(ErrorCode.ERR_RefReadOnlyWrongOrdering, "readonly").WithLocation(5, 18));
        }
 
        [Fact, WorkItem(63758, "https://github.com/dotnet/roslyn/issues/63758")]
        public void ReadonlyParameter5()
        {
            CreateCompilation(@"
public class Base {
    void M()
    {
        var v = (ref readonly int i) => { };
    }
}").VerifyDiagnostics();
        }
 
        [Fact, WorkItem(63758, "https://github.com/dotnet/roslyn/issues/63758")]
        public void ReadonlyParameter6()
        {
            CreateCompilation(@"
public class Base {
    void M()
    {
        var v = (readonly ref int i) => { };
    }
}").VerifyDiagnostics(
                // (5,18): error CS9190: 'readonly' modifier must be specified after 'ref'.
                //         var v = (readonly ref int i) => { };
                Diagnostic(ErrorCode.ERR_RefReadOnlyWrongOrdering, "readonly").WithLocation(5, 18));
        }
 
        [Fact]
        public void RefExtensionMethodsNotSupportedBefore7_2_InSyntax()
        {
            var code = @"
public static class Extensions
{
    public static void Print(in this int p)
    {
        System.Console.WriteLine(p);
    }
}
public static class Program
{
    public static void Main()
    {
        int p = 5;
        p.Print();
    }
}";
 
            CreateCompilation(code, parseOptions: CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp7_1)).VerifyDiagnostics(
                // (4,30): error CS8302: Feature 'readonly references' is not available in C# 7.1. Please use language version 7.2 or greater.
                //     public static void Print(in this int p)
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_1, "in").WithArguments("readonly references", "7.2").WithLocation(4, 30),
                // (4,33): error CS8302: Feature 'ref extension methods' is not available in C# 7.1. Please use language version 7.2 or greater.
                //     public static void Print(in this int p)
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_1, "this").WithArguments("ref extension methods", "7.2").WithLocation(4, 33),
                // (14,9): error CS8302: Feature 'ref extension methods' is not available in C# 7.1. Please use language version 7.2 or greater.
                //         p.Print();
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_1, "p").WithArguments("ref extension methods", "7.2").WithLocation(14, 9));
 
            CompileAndVerify(code, expectedOutput: "5");
        }
 
        [Fact]
        public void RefExtensionMethodsNotSupportedBefore7_2_RefSyntax()
        {
            var code = @"
public static class Extensions
{
    public static void Print(ref this int p)
    {
        System.Console.WriteLine(p);
    }
}
public static class Program
{
    public static void Main()
    {
        int p = 5;
        p.Print();
    }
}";
 
            CreateCompilation(code, parseOptions: CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp7_1)).VerifyDiagnostics(
                // (4,34): error CS8302: Feature 'ref extension methods' is not available in C# 7.1. Please use language version 7.2 or greater.
                //     public static void Print(ref this int p)
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_1, "this").WithArguments("ref extension methods", "7.2").WithLocation(4, 34),
                // (14,9): error CS8302: Feature 'ref extension methods' is not available in C# 7.1. Please use language version 7.2 or greater.
                //         p.Print();
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_1, "p").WithArguments("ref extension methods", "7.2").WithLocation(14, 9));
 
            CompileAndVerify(code, expectedOutput: "5");
        }
 
        [Fact]
        [CompilerTrait(CompilerFeature.ReadOnlyReferences)]
        public void InParametersWouldErrorOutInEarlierCSharpVersions()
        {
            var code = @"
public class Test
{
    public void DoSomething(in int x) { }
}";
 
            CreateCompilation(code, parseOptions: new CSharpParseOptions(LanguageVersion.CSharp7)).VerifyDiagnostics(
                // (4,29): error CS8107: Feature 'readonly references' is not available in C# 7.0. Please use language version 7.2 or greater.
                //     public void DoSomething(in int x) { }
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "in").WithArguments("readonly references", "7.2").WithLocation(4, 29));
        }
    }
}