File: Symbols\Source\ExpressionBodiedMethodTests.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 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.Source
{
    public sealed class ExpressionBodiedMethodTests : CSharpTestBase
    {
        [ClrOnlyFact]
        public void PartialMethods()
        {
            var comp = CompileAndVerify(@"
public partial class C
{
    static partial void goo() => System.Console.WriteLine(""test"");
}
 
public partial class C
{
    public static void Main(string[] args)
    {
        goo();
    }
    static partial void goo();
}
", sourceSymbolValidator: m =>
            {
                var gooDef = m.GlobalNamespace
                    .GetMember<NamedTypeSymbol>("C")
                    .GetMember<SourceOrdinaryMethodSymbol>("goo");
                Assert.True(gooDef.IsPartial);
                Assert.True(gooDef.IsPartialDefinition);
                Assert.False(gooDef.IsPartialImplementation);
                Assert.Null(gooDef.PartialDefinitionPart);
 
                var gooImpl = gooDef.PartialImplementationPart
                    as SourceOrdinaryMethodSymbol;
                Assert.NotNull(gooImpl);
                Assert.True(gooImpl.IsPartial);
                Assert.True(gooImpl.IsPartialImplementation);
                Assert.False(gooImpl.IsPartialDefinition);
                Assert.True(gooImpl.IsExpressionBodied);
            },
expectedOutput: "test");
        }
 
        [Fact(Skip = "973907")]
        public void Syntax01()
        {
            // Feature is enabled by default
            var comp = CreateCompilation(@"
class C
{
    public int M() => 1;
}");
            comp.VerifyDiagnostics();
        }
 
        [Fact]
        public void Syntax02()
        {
            var comp = CreateCompilationWithMscorlib461(@"
class C
{
    public int M() {} => 1;
}");
            comp.VerifyDiagnostics(
    // (4,5): error CS8057: Block bodies and expression bodies cannot both be provided.
    //     public int M() {} => 1;
    Diagnostic(ErrorCode.ERR_BlockBodyAndExpressionBody, "public int M() {} => 1;").WithLocation(4, 5),
    // (4,16): error CS0161: 'C.M()': not all code paths return a value
    //     public int M() {} => 1;
    Diagnostic(ErrorCode.ERR_ReturnExpected, "M").WithArguments("C.M()").WithLocation(4, 16));
        }
 
        [Fact]
        public void Syntax03()
        {
            var comp = CreateCompilation(@"
interface C
{
    int M() => 1;
}", parseOptions: TestOptions.Regular7, targetFramework: TargetFramework.NetCoreApp);
            comp.VerifyDiagnostics(
                // (4,9): error CS8652: The feature 'default interface implementation' is not available in C# 7.0. Please use language version 8.0 or greater.
                //     int M() => 1;
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "M").WithArguments("default interface implementation", "8.0").WithLocation(4, 9)
                );
        }
 
        [Fact]
        public void Syntax04()
        {
            var comp = CreateCompilationWithMscorlib461(@"
abstract class C
{
  public abstract int M() => 1;
}");
            comp.VerifyDiagnostics(
    // (4,23): error CS0500: 'C.M()' cannot declare a body because it is marked abstract
    //   public abstract int M() => 1;
    Diagnostic(ErrorCode.ERR_AbstractHasBody, "M").WithArguments("C.M()").WithLocation(4, 23));
        }
 
        [Fact]
        public void Syntax05()
        {
            var comp = CreateCompilationWithMscorlib461(@"
class C
{
   public abstract int M() => 1;
}");
            comp.VerifyDiagnostics(
    // (4,24): error CS0500: 'C.M()' cannot declare a body because it is marked abstract
    //    public abstract int M() => 1;
    Diagnostic(ErrorCode.ERR_AbstractHasBody, "M").WithArguments("C.M()").WithLocation(4, 24),
    // (4,24): error CS0513: 'C.M()' is abstract but it is contained in non-abstract type 'C'
    //    public abstract int M() => 1;
    Diagnostic(ErrorCode.ERR_AbstractInConcreteClass, "M").WithArguments("C.M()", "C").WithLocation(4, 24));
        }
 
        [Fact]
        public void Syntax06()
        {
            var comp = CreateCompilationWithMscorlib461(@"
abstract class C
{
   abstract int M() => 1;
}");
            comp.VerifyDiagnostics(
    // (4,17): error CS0500: 'C.M()' cannot declare a body because it is marked abstract
    //    abstract int M() => 1;
    Diagnostic(ErrorCode.ERR_AbstractHasBody, "M").WithArguments("C.M()").WithLocation(4, 17),
    // (4,17): error CS0621: 'C.M()': virtual or abstract members cannot be private
    //    abstract int M() => 1;
    Diagnostic(ErrorCode.ERR_VirtualPrivate, "M").WithArguments("C.M()").WithLocation(4, 17));
        }
 
        [Fact]
        [WorkItem(1009638, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1009638")]
        public void Syntax07()
        {
            var comp = CreateCompilationWithMscorlib461(@"
public class C {
    public bool IsNull<T>(T t) where T : class => t != null;
}");
            comp.VerifyDiagnostics();
        }
 
        [Fact]
        [WorkItem(1029117, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1029117")]
        public void Syntax08()
        {
            var comp = CreateCompilationWithMscorlib461(@"
namespace MyNamespace
{
    public partial struct Goo
    {
        public double Bar => 0;
    }
    public partial struct Goo
    {
    }
}");
            comp.VerifyDiagnostics();
        }
 
        [Fact]
        public void LambdaTest01()
        {
            var comp = CreateCompilationWithMscorlib461(@"
using System;
class C
{
    public Func<int, Func<int, int>> M() => x => y => x + y;
}");
            comp.VerifyDiagnostics();
        }
 
        [Fact]
        public void SimpleTest()
        {
            var text = @"
class C
{
    public int P => 2;
    public int M() => P;
    public static explicit operator C(int i) => new C();
    public static C operator++(C c) => (C)c.M();
}";
            var comp = CreateCompilationWithMscorlib461(text);
            comp.VerifyDiagnostics();
            var global = comp.GlobalNamespace;
            var c = global.GetTypeMember("C");
 
            var m = c.GetMember<SourceMemberMethodSymbol>("M");
            Assert.False(m.IsImplicitlyDeclared);
            Assert.True(m.IsExpressionBodied);
 
            var pp = c.GetMember<SourceUserDefinedOperatorSymbol>("op_Increment");
            Assert.False(pp.IsImplicitlyDeclared);
            Assert.True(pp.IsExpressionBodied);
 
            var conv = c.GetMember<SourceUserDefinedConversionSymbol>("op_Explicit");
            Assert.False(conv.IsImplicitlyDeclared);
            Assert.True(conv.IsExpressionBodied);
        }
 
        [Fact]
        public void Override01()
        {
            var comp = CreateCompilationWithMscorlib461(@"
class B
{
    public virtual int M() { return 0; }
}
class C : B
{
    public override int M() => 1;
}").VerifyDiagnostics();
        }
 
        [Fact]
        public void VoidExpression()
        {
            var comp = CreateCompilationWithMscorlib461(@"
class C
{
    public void M() => System.Console.WriteLine(""goo"");
}").VerifyDiagnostics();
        }
 
        [Fact]
        public void VoidExpression2()
        {
            var comp = CreateCompilationWithMscorlib461(@"
class C
{
    public int M() => System.Console.WriteLine(""goo"");
}").VerifyDiagnostics(
    // (4,23): error CS0029: Cannot implicitly convert type 'void' to 'int'
    //     public int M() => System.Console.WriteLine("goo");
    Diagnostic(ErrorCode.ERR_NoImplicitConv, @"System.Console.WriteLine(""goo"")").WithArguments("void", "int").WithLocation(4, 23));
        }
 
        [Fact]
        public void InterfaceImplementation01()
        {
            var comp = CreateCompilationWithMscorlib461(@"
interface I 
{
    int M();
    string N();
}
internal interface J
{
    string N();
}
internal interface K
{
    decimal O();
}
class C : I, J, K
{
    public int M() => 10;
    string I.N() => ""goo"";
    string J.N() => ""bar"";
    public decimal O() => M();
}");
            comp.VerifyDiagnostics();
            var global = comp.GlobalNamespace;
            var i = global.GetTypeMember("I");
            var j = global.GetTypeMember("J");
            var k = global.GetTypeMember("K");
            var c = global.GetTypeMember("C");
 
            var iM = i.GetMember<SourceMemberMethodSymbol>("M");
            var iN = i.GetMember<SourceMemberMethodSymbol>("N");
            var jN = j.GetMember<SourceMemberMethodSymbol>("N");
 
            var method = c.GetMember<SourceMemberMethodSymbol>("M");
            var implements = method.ContainingType.FindImplementationForInterfaceMember(iM);
            Assert.Equal(implements, method);
 
            method = (SourceMemberMethodSymbol)c.GetMethod("I.N");
            implements = c.FindImplementationForInterfaceMember(iN);
            Assert.True(method.IsExplicitInterfaceImplementation);
            Assert.Equal(implements, method);
 
            method = (SourceMemberMethodSymbol)c.GetMethod("J.N");
            implements = c.FindImplementationForInterfaceMember(jN);
            Assert.True(method.IsExplicitInterfaceImplementation);
            Assert.Equal(implements, method);
 
            method = c.GetMember<SourceMemberMethodSymbol>("O");
            Assert.False(method.IsExplicitInterfaceImplementation);
        }
 
        [ClrOnlyFact]
        public void Emit01()
        {
            var comp = CreateCompilationWithMscorlib461(@"
abstract class A
{
    protected abstract string Z();
}
abstract class B : A
{
    protected sealed override string Z() => ""goo"";
    protected abstract string Y();
}    
class C : B
{
    public const int X = 2;
    public static int M(int x) => x * x;
    
    public int N() => X;
    private int O() => M(N()) * N();
    protected sealed override string Y() => Z() + O();
 
    public static void Main()
    {
        System.Console.WriteLine(C.X);
        System.Console.WriteLine(C.M(C.X));
        var c = new C();
        
        System.Console.WriteLine(c.N());
        System.Console.WriteLine(c.O());
        System.Console.WriteLine(c.Z());
        System.Console.WriteLine(c.Y());
    }
}", options: TestOptions.ReleaseExe.WithMetadataImportOptions(MetadataImportOptions.Internal));
            var verifier = CompileAndVerify(comp, expectedOutput:
@"2
4
2
8
goo
goo8");
        }
 
        [ClrOnlyFact]
        public void Emit02()
        {
            var comp = CreateCompilationWithMscorlib461(@"
class C
{
    public void M() { System.Console.WriteLine(""Hello""); }
    public void M(int i) { System.Console.WriteLine(i); }
 
    public string N(string s) { return s; }
 
    public static void Main()
    {
        var c = new C();
        c.M();
        c.M(2);
 
        System.Console.WriteLine(c.N(""World""));
    }
}", options: TestOptions.ReleaseExe.WithMetadataImportOptions(MetadataImportOptions.Internal));
            var verifier = CompileAndVerify(comp, expectedOutput:
@"Hello
2
World");
        }
 
        [Fact]
        public void RefReturningExpressionBodiedMethod()
        {
            var comp = CreateCompilationWithMscorlib461(@"
class C
{
    int field = 0;
    public ref int M() => ref field;
}");
            comp.VerifyDiagnostics();
        }
 
        [Fact]
        [CompilerTrait(CompilerFeature.ReadOnlyReferences)]
        public void RefReadonlyReturningExpressionBodiedMethod()
        {
            var comp = CreateCompilationWithMscorlib461(@"
class C
{
    int field = 0;
    public ref readonly int M() => ref field;
}");
            comp.VerifyDiagnostics();
        }
    }
}