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

using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Utilities;
using Xunit;

namespace Microsoft.CodeAnalysis.CSharp.UnitTests.CodeGen
{
    [CompilerTrait(CompilerFeature.NullCoalescingAssignment)]
    public class CodeGenNullCoalescingAssignmentTests : CompilingTestBase
    {
        [Fact]
        public void LocalLvalue()
        {
            var source = @"
using System;
public class C
{
    public static void Main()
    {
        TestNullable();
        TestObject();
        TestAsStatement();
    }
    static void TestNullable()
    {
        int? i1 = null;
        Console.WriteLine(i1 ??= GetInt());
    }
    static void TestObject()
    {
        string s1 = null;
        Console.WriteLine(s1 ??= GetString());
    }
    static void TestAsStatement()
    {
        object o = null;
        o ??= ""As Statement"";
        Console.WriteLine(o);
    }
    static int GetInt()
    {
        Console.WriteLine(""In GetInt"");
        return 0;
    }
    static string GetString()
    {
        Console.WriteLine(""In GetString"");
        return ""Test"";
    }
}
";

            CompileAndVerify(@"
using System;
class C
{
    static void TestNullable()
    {
        int? i1 = null;
        Console.WriteLine(i1 ??= GetInt());
    }
    static int GetInt()
    {
        Console.WriteLine(""In GetInt"");
        return 0;
    }
}
").VerifyIL("C.TestNullable()", "");
            /*var verifier = CompileAndVerify(source, expectedOutput: @"
In GetInt
0
In GetString
Test
As Statement
");

            verifier.VerifyIL("C.TestNullable()", @"
{
  // Code size       43 (0x2b)
  .maxstack  1
  .locals init (int? V_0)
  IL_0000:  ldloca.s   V_0
  IL_0002:  initobj    ""int?""
  IL_0008:  ldloc.0
  IL_0009:  stloc.0
  IL_000a:  ldloca.s   V_0
  IL_000c:  call       ""bool int?.HasValue.get""
  IL_0011:  brtrue.s   IL_001f
  IL_0013:  call       ""int C.GetInt()""
  IL_0018:  newobj     ""int?..ctor(int)""
  IL_001d:  br.s       IL_0020
  IL_001f:  ldloc.0
  IL_0020:  box        ""int?""
  IL_0025:  call       ""void System.Console.WriteLine(object)""
  IL_002a:  ret
}
");

            // When the optimizer is on, it turns the local into a stack local, so we don't see assignments.
            verifier.VerifyIL("C.TestObject()", expectedIL: @"
{
  // Code size       16 (0x10)
  .maxstack  2
  IL_0000:  ldnull
  IL_0001:  dup
  IL_0002:  brtrue.s   IL_000a
  IL_0004:  pop
  IL_0005:  call       ""string C.GetString()""
  IL_000a:  call       ""void System.Console.WriteLine(string)""
  IL_000f:  ret
}
");

            verifier.VerifyIL("C.TestAsStatement()", expectedIL: @"
{
  // Code size       18 (0x12)
  .maxstack  1
  .locals init (object V_0) //o
  IL_0000:  ldnull
  IL_0001:  stloc.0
  IL_0002:  ldloc.0
  IL_0003:  brtrue.s   IL_000b
  IL_0005:  ldstr      ""As Statement""
  IL_000a:  stloc.0
  IL_000b:  ldloc.0
  IL_000c:  call       ""void System.Console.WriteLine(object)""
  IL_0011:  ret
}
");

            // With the optimizer off, the local is not elided
            CompileAndVerify(source, options: TestOptions.DebugDll).VerifyIL("C.TestObject()", expectedIL: @"
{
  // Code size       22 (0x16)
  .maxstack  2
  .locals init (string V_0) //s1
  IL_0000:  nop
  IL_0001:  ldnull
  IL_0002:  stloc.0
  IL_0003:  ldloc.0
  IL_0004:  dup
  IL_0005:  brtrue.s   IL_000f
  IL_0007:  pop
  IL_0008:  call       ""string C.GetString()""
  IL_000d:  dup
  IL_000e:  stloc.0
  IL_000f:  call       ""void System.Console.WriteLine(string)""
  IL_0014:  nop
  IL_0015:  ret
}
");*/
        }

        [Fact]
        public void FieldLvalue()
        {
            CompileAndVerify(@"
using System;
public class C
{
    int? f1 = null;

    public static void Main()
    {
        var c = new C();
        Console.WriteLine(c.f1 ??= GetInt());
    }
    static int GetInt()
    {
        Console.WriteLine(""In GetInt"");
        return 0;
    }
}<commit_msg>Fix test setup.<commit_after>﻿// Copyright (c) Microsoft.  All Rights Reserved.  Licensed under the Apache License, Version 2.0.  See License.txt in the project root for license information.

using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Utilities;
using Xunit;

namespace Microsoft.CodeAnalysis.CSharp.UnitTests.CodeGen
{
    [CompilerTrait(CompilerFeature.NullCoalescingAssignment)]
    public class CodeGenNullCoalescingAssignmentTests : CompilingTestBase
    {
        [Fact]
        public void LocalLvalue()
        {
            var source = @"
using System;
public class C
{
    public static void Main()
    {
        TestNullable();
        TestObject();
        TestAsStatement();
    }
    static void TestNullable()
    {
        int? i1 = null;
        Console.WriteLine(i1 ??= GetInt());
    }
    static void TestObject()
    {
        string s1 = null;
        Console.WriteLine(s1 ??= GetString());
    }
    static void TestAsStatement()
    {
        object o = null;
        o ??= ""As Statement"";
        Console.WriteLine(o);
    }
    static int GetInt()
    {
        Console.WriteLine(""In GetInt"");
        return 0;
    }
    static string GetString()
    {
        Console.WriteLine(""In GetString"");
        return ""Test"";
    }
}
";

            var verifier = CompileAndVerify(source, expectedOutput: @"
In GetInt
0
In GetString
Test
As Statement
");

            verifier.VerifyIL("C.TestNullable()", @"
{
  // Code size       43 (0x2b)
  .maxstack  1
  .locals init (int? V_0)
  IL_0000:  ldloca.s   V_0
  IL_0002:  initobj    ""int?""
  IL_0008:  ldloc.0
  IL_0009:  stloc.0
  IL_000a:  ldloca.s   V_0
  IL_000c:  call       ""bool int?.HasValue.get""
  IL_0011:  brtrue.s   IL_001f
  IL_0013:  call       ""int C.GetInt()""
  IL_0018:  newobj     ""int?..ctor(int)""
  IL_001d:  br.s       IL_0020
  IL_001f:  ldloc.0
  IL_0020:  box        ""int?""
  IL_0025:  call       ""void System.Console.WriteLine(object)""
  IL_002a:  ret
}
");

            // When the optimizer is on, it turns the local into a stack local, so we don't see assignments.
            verifier.VerifyIL("C.TestObject()", expectedIL: @"
{
  // Code size       16 (0x10)
  .maxstack  2
  IL_0000:  ldnull
  IL_0001:  dup
  IL_0002:  brtrue.s   IL_000a
  IL_0004:  pop
  IL_0005:  call       ""string C.GetString()""
  IL_000a:  call       ""void System.Console.WriteLine(string)""
  IL_000f:  ret
}
");

            verifier.VerifyIL("C.TestAsStatement()", expectedIL: @"
{
  // Code size       18 (0x12)
  .maxstack  1
  .locals init (object V_0) //o
  IL_0000:  ldnull
  IL_0001:  stloc.0
  IL_0002:  ldloc.0
  IL_0003:  brtrue.s   IL_000b
  IL_0005:  ldstr      ""As Statement""
  IL_000a:  stloc.0
  IL_000b:  ldloc.0
  IL_000c:  call       ""void System.Console.WriteLine(object)""
  IL_0011:  ret
}
");

            // With the optimizer off, the local is not elided
            CompileAndVerify(source, options: TestOptions.DebugDll).VerifyIL("C.TestObject()", expectedIL: @"
{
  // Code size       22 (0x16)
  .maxstack  2
  .locals init (string V_0) //s1
  IL_0000:  nop
  IL_0001:  ldnull
  IL_0002:  stloc.0
  IL_0003:  ldloc.0
  IL_0004:  dup
  IL_0005:  brtrue.s   IL_000f
  IL_0007:  pop
  IL_0008:  call       ""string C.GetString()""
  IL_000d:  dup
  IL_000e:  stloc.0
  IL_000f:  call       ""void System.Console.WriteLine(string)""
  IL_0014:  nop
  IL_0015:  ret
}
");
        }

        [Fact]
        public void FieldLvalue()
        {
            CompileAndVerify(@"
using System;
public class C
{
    int? f1 = null;

    public static void Main()
    {
        var c = new C();
        Console.WriteLine(c.f1 ??= GetInt());
    }
    static int GetInt()
    {
        Console.WriteLine(""In GetInt"");
        return 0;
    }
}
{'fraction_non_alphanumeric': 0.12076806467913087, 'fraction_numerical': 0.05722587165234967, 'mean_word_length': 2.2209113100081366, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1796117', 'n_tokens_mistral': 3106, 'n_tokens_neox': 2796, 'n_words': 671}