/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/CSharp/Test/Emit3/FlowAnalysis/RegionAnalysisTests.cs
14 274 строки
499 KB
Rikki Gibson
Call Enter/LeaveRegion APIs for binary expressions (#76412)
18 дек 2024, 01:40
Не верифицирован
18 дек 2024, 01:40
b2b9e32
Код
Авторство
О чём код?
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. #nullable disable using System; using System.Linq; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.CSharp.UnitTests { /// <summary> /// Tests for the region analysis APIs. /// </summary> /// <remarks> /// Please add your tests to other files if possible: /// * FlowDiagnosticTests.cs - all tests on Diagnostics /// * IterationJumpYieldStatementTests.cs - while, do, for, foreach, break, continue, goto, iterator (yield break, yield return) /// * TryLockUsingStatementTests.cs - try-catch-finally, lock, & using statement /// * PatternsVsRegions.cs - region analysis tests for pattern matching /// </remarks> public partial class RegionAnalysisTests : FlowTestBase { #region "Expressions" [WorkItem(545047, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545047")] [Fact] public void DataFlowsInAndNullable_Field() { // WARNING: if this test is edited, the test with the // test with the same name in VB must be modified too var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowStatements(@" struct S { public int F; public S(int f) { this.F = f; } static void Main(string[] args) { int? i = 1; S s = new S(1); /*<bind>*/ Console.WriteLine(i.Value); Console.WriteLine(s.F); /*</bind>*/ } } "); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Equal("i, s", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("args, i, s", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("args, i, s", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Equal("i, s", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("args, i, s", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.Captured)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedOutside)); } [Fact] public void DataFlowsOutAndStructField() { var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowStatements(@" struct S { public int F; public S(int f) { this.F = f; } static void Main(string[] args) { S s = new S(1); /*<bind>*/ s.F = 1; /*</bind>*/ var x = s.F; } } "); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Equal("s", GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Equal("s", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("args, s", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("args, s", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Equal("s", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Equal("s", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("args, s, x", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.Captured)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedOutside)); } [Fact] public void DataFlowsInAndNullable_Property() { var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowStatements(@" struct S { public int F; public S(int f) { this.F = f; } public int P { get; set; } static void Main(string[] args) { int? i = 1; S s = new S(1); /*<bind>*/ Console.WriteLine(i.Value); Console.WriteLine(s.P); /*</bind>*/ } } "); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Equal("i, s", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("args, i, s", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("args, i, s", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Equal("i, s", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("args, i, s", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.Captured)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedOutside)); } [WorkItem(538238, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538238")] [Fact] public void TestDataFlowsIn03() { var analysis = CompileAndAnalyzeDataFlowExpression(@" class Program { static void Main(string[] args) { int x = 1; int y = 2; int z = /*<bind>*/x + y/*</bind>*/; } } "); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Equal("args, x, y", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("args, x, y", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); } [Fact] public void TestDataFlowForValueTypes() { // WARNING: test matches the same test in VB (TestDataFlowForValueTypes) // Keep the two tests in sync! var analysis = CompileAndAnalyzeDataFlowStatements(@" class Tst { public static void Main() { S0 a; S1 b; S2 c; S3 d; E0 e; E1 f; /*<bind>*/ Console.WriteLine(a); Console.WriteLine(b); Console.WriteLine(c); Console.WriteLine(d); Console.WriteLine(e); Console.WriteLine(f); /*</bind>*/ } } struct S0 { } struct S1 { public S0 s0; } struct S2 { public S0 s0; public int s1; } struct S3 { public S2 s; public object s1; } enum E0 { } enum E1 { V1 } "); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Equal("a, b, c, d, e, f", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Null(GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("a, b, c, d, e, f", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenOutside)); } [WorkItem(538997, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538997")] [Fact] public void TestDataFlowsIn04() { var analysis = CompileAndAnalyzeDataFlowExpression(@" using System; class Program { static void Main() { string s = ""; Func<string> f = /*<bind>*/s/*</bind>*/.ToString; } } "); Assert.Equal("s", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Equal("s", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("s", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); } [Fact] public void TestDataFlowsOutExpression01() { var analysis = CompileAndAnalyzeDataFlowExpression(@" class C { public void F(int x) { int a = 1, y; int tmp = x + /*<bind>*/ (y = x = 2) /*</bind>*/ + (a = 2); int c = a + 4 + x + y; } }"); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("this, x, a", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("this, x, a, y", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); } [WorkItem(540171, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540171")] [Fact] public void TestIncrement() { var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowExpression(@" class C { static void M(int i) { /*<bind>*/i++/*</bind>*/; M(i); } } "); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Equal("i", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Equal("i", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("i", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("i", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Equal("i", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Equal("i", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Equal("i", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("i", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [WorkItem(543695, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543695")] [Fact] public void FlowAnalysisOnTypeOrNamespace1() { var results = CompileAndAnalyzeDataFlowExpression(@" class C { static void M(int i) { /*<bind>*/ System.Console /*</bind>*/ .WriteLine(i); } } "); Assert.False(results.Succeeded); } [WorkItem(543695, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543695")] [Fact] public void FlowAnalysisOnTypeOrNamespace3() { var results = CompileAndAnalyzeDataFlowExpression(@" public class A { public class B { public static void M() { } } } class C { static void M(int i) { /*<bind>*/ A.B /*</bind>*/ .M(i); } } "); Assert.False(results.Succeeded); } [WorkItem(543695, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543695")] [Fact] public void FlowAnalysisOnTypeOrNamespace4() { var results = CompileAndAnalyzeDataFlowExpression(@" public class A { public class B { public static void M() { } } } class C { static void M(int i) { /*<bind>*/ A /*</bind>*/ .B.M(i); } } "); Assert.False(results.Succeeded); } [WorkItem(540183, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540183")] [Fact] public void DataFlowsOutIncrement01() { var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowExpression(@" class C { static void M(int i) { /*<bind>*/i++/*</bind>*/; M(i); } } "); Assert.Equal("i", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("i", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("i", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("i", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); } [WorkItem(6359, "DevDiv_Projects/Roslyn")] [Fact] public void DataFlowsOutPreDecrement01() { var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowExpression(@" class Test { string method(string s, int i) { string[] myvar = new string[i]; myvar[0] = s; /*<bind>*/myvar[--i] = s + i.ToString()/*</bind>*/; return myvar[i]; } }"); Assert.Equal("i", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("i", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("this, s, i, myvar", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("this, s, i, myvar", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); } [Fact] public void TestBranchOfTernaryOperator() { var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowExpression(@" class C { static void Main() { bool x = true; bool y = x ? /*<bind>*/ x /*</bind>*/ : true; } } "); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("x, y", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [WorkItem(540832, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540832")] [Fact] public void TestAssignmentExpressionAsBranchOfTernaryOperator() { var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowExpression(@" class C { static void Main() { int x; int y = true ? /*<bind>*/ x = 1 /*</bind>*/ : x; } } "); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("y", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [Fact] public void TestAlwaysAssignedWithTernaryOperator() { var analysis = CompileAndAnalyzeDataFlowStatements(@" class C { public void F(int x) { int a, b, x = 100; /*<bind>*/ int c = true ? a = 1 : b = 2; /*</bind>*/ } }"); Assert.Equal("a, c", GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("this, x, x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("this, x, a, x, c", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); } [Fact] public void TestAlwaysAssigned04() { var analysis = CompileAndAnalyzeDataFlowExpression(@" class C { public static void Main(string[] args) { int i; i = /*<bind>*/ int.Parse(args[0].ToString()) /*</bind>*/ ; } }"); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("args", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("args", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); } [Fact] public void TestAlwaysAssigned05() { var analysis = CompileAndAnalyzeDataFlowExpression(@" class C { public static void Main(string[] args) { bool a = true; bool b; int c = /*<bind>*/ (b = a) && (b = !a) /*</bind>*/ ? 1 : 2; } }"); Assert.Equal("b", GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("args, a", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("args, a, b", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); } [Fact] public void TestAlwaysAssigned06() { var analysis = CompileAndAnalyzeDataFlowExpression(@" class C { public static void Main(string[] args) { bool a = true; bool b; int c = /*<bind>*/ a && (b = !a) /*</bind>*/ ? 1 : 2; } }"); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("args, a", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("args, a", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); } [Fact] public void TestAlwaysAssigned07() { var analysis = CompileAndAnalyzeDataFlowExpression(@" class C { public static void Main(string[] args) { bool a = true; bool b; int c = /*<bind>*/ (b = a) && !a /*</bind>*/ ? 1 : 2; } }"); Assert.Equal("b", GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("args, a", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("args, a, b", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); } [Fact] public void TestAlwaysAssigned08() { var analysis = CompileAndAnalyzeDataFlowExpression(@" class C { public static void Main(string[] args) { bool a = true; bool b; int c = /*<bind>*/ (b = a) || (b = !a) /*</bind>*/ ? 1 : 2; } }"); Assert.Equal("b", GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("args, a", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("args, a, b", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); } [Fact] public void TestAlwaysAssigned09() { var analysis = CompileAndAnalyzeDataFlowExpression(@" class C { public static void Main(string[] args) { bool a = true; bool b; int c = /*<bind>*/ a || (b = !a) /*</bind>*/ ? 1 : 2; } }"); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("args, a", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("args, a", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); } [Fact] public void TestAlwaysAssigned10() { var analysis = CompileAndAnalyzeDataFlowExpression(@" class C { public static void Main(string[] args) { bool a = true; bool b; int c = /*<bind>*/ (b = a) || !a /*</bind>*/ ? 1 : 2; } }"); Assert.Equal("b", GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("args, a", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("args, a, b", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); } [Fact] public void TestAlwaysAssigned11() { var analysis = CompileAndAnalyzeDataFlowExpression(@" class C { public static void Main(string[] args) { object a = new object; object b; object c = /*<bind>*/ (b = a) ?? (b = null) /*</bind>*/ ; } }"); Assert.Equal("b", GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("args, a", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("args, a, b", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); } [Fact] public void TestAlwaysAssigned12() { var analysis = CompileAndAnalyzeDataFlowExpression(@" class C { public static void Main(string[] args) { object a = new object; object b; object c = /*<bind>*/ a ?? (b = null) /*</bind>*/ ; } }"); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("args, a", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("args, a", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); } [Fact] public void TestAlwaysAssigned13() { var analysis = CompileAndAnalyzeDataFlowExpression(@" class C { public static void Main(string[] args) { object a = new object; object b; object c = /*<bind>*/ (b = a) ?? null /*</bind>*/ ; } }"); Assert.Equal("b", GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("args, a", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("args, a, b", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); } [Fact] public void TestAlwaysAssigned14() { var analysis = CompileAndAnalyzeDataFlowExpression(@" class C { public static void Main(string[] args) { bool a = true; bool b, c, d, e, f; bool c = (b = a) ? (c = a) : (d = a) ? (e = a) : /*<bind>*/ (f = a) /*</bind>*/; } }"); Assert.Equal("f", GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("args, a, b, d", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("args, a, b, d, f", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); } [Fact] public void TestAlwaysAssigned15() { var analysis = CompileAndAnalyzeDataFlowExpression(@" class C { public static void Main(string[] args) { bool a = true; bool b, c, d, e, f; bool c = (b = a) ? (c = a) : /*<bind>*/ (d = a) ? (e = a) : (f = a) /*</bind>*/; } }"); Assert.Equal("d", GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("args, a, b", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("args, a, b, d", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); } [Fact] public void TestAlwaysAssigned16() { var analysis = CompileAndAnalyzeDataFlowExpression(@" class C { public static bool B(out bool b) { b = true; return b; } public static void Main(string[] args) { bool a, b; bool c = B(out a) && B(out /*<bind>*/b/*</bind>*/); } }"); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("args, a", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("args, a", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); } [Fact] public void TestAlwaysAssigned17() { var analysis = CompileAndAnalyzeDataFlowExpression(@" class C { public static bool B(out bool b) { b = true; return b; } public static void Main(string[] args) { bool a, b; bool c = /*<bind>*/B(out a) && B(out b)/*</bind>*/; } }"); Assert.Equal("a", GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("args", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("args, a", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); } [Fact] public void TestAlwaysAssigned18() { var analysis = CompileAndAnalyzeDataFlowExpression(@" class C { public static bool B(out bool b) { b = true; return b; } public static void Main(string[] args) { bool a, b; bool c = B(out a) || B(out /*<bind>*/b/*</bind>*/); } }"); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("args, a", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("args, a", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); } [Fact] public void TestAlwaysAssigned19() { var analysis = CompileAndAnalyzeDataFlowExpression(@" class C { public static bool B(out bool b) { b = true; return b; } public static void Main(string[] args) { bool a, b; bool c = /*<bind>*/B(out a) || B(out b)/*</bind>*/; } }"); Assert.Equal("a", GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("args", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("args, a", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); } [Fact] public void TestAlwaysAssigned22() { var analysis = CompileAndAnalyzeDataFlowExpression(@" class C { public static bool B(out bool b) { b = true; return b; } public static void Main(string[] args) { bool a, b; if (/*<bind>*/B(out a)/*</bind>*/) a = true; else b = true; } }"); Assert.Equal("a", GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("args", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("args, a", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); } [Fact] public void TestAlwaysAssignedAndWrittenInside() { var analysis = CompileAndAnalyzeDataFlowExpression(@" class C { public static void Main(string[] args) { int i = /*<bind>*/ int.Parse(args[0].ToString()) /*</bind>*/ ; } }"); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("args", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("args", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); } [Fact] public void TestWrittenInside03() { var analysis = CompileAndAnalyzeDataFlowExpression(@" class C { public static void Main(string[] args) { int i; i = /*<bind>*/ int.Parse(args[0].ToString()) /*</bind>*/ ; } }"); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("args", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("args", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); } [Fact] public void TestReadWrite01() { var analysis = CompileAndAnalyzeDataFlowExpression(@" class C { public static void Main(string[] args) { int x = 3; /*<bind>*/x/*</bind>*/ = 3; } }"); Assert.Null(GetSymbolNamesJoined(analysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Null(GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Equal("args, x", GetSymbolNamesJoined(analysis.WrittenOutside)); Assert.Equal("args, x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("args, x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); } [Fact] public void TestReadWrite02() { var analysis = CompileAndAnalyzeDataFlowExpression(@" class C { public static void Main(string[] args) { int x = 3; /*<bind>*/x/*</bind>*/ += 3; } }"); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Null(GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Equal("args, x", GetSymbolNamesJoined(analysis.WrittenOutside)); Assert.Equal("args, x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("args, x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); } [Fact] public void TestReadWrite03() { var analysis = CompileAndAnalyzeDataFlowExpression(@" class C { public static void M(out int x) { x = 1; } public static void Main(string[] args) { int x = 3; M(out /*<bind>*/x/*</bind>*/); } }"); Assert.Null(GetSymbolNamesJoined(analysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Null(GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Equal("args, x", GetSymbolNamesJoined(analysis.WrittenOutside)); Assert.Equal("args, x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("args, x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); } [Fact] public void TestReadWrite04() { var analysis = CompileAndAnalyzeDataFlowExpression(@" class C { public static void M(ref int x) { x = 1; } public static void Main(string[] args) { int x = 3; M(ref /*<bind>*/x/*</bind>*/); } }"); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Equal("args, x", GetSymbolNamesJoined(analysis.WrittenOutside)); Assert.Equal("args, x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("args, x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); } [Fact] public void TestAssignmentExpressionSelection() { var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowExpression(@" class C { static void Main() { int x = ( /*<bind>*/ x = 1 /*</bind>*/ ) + x; } } "); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [Fact] public void TestSingleVariableSelection() { var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowExpression(@" class C { static void Main() { bool x = true; bool y = x | /*<bind>*/ x /*</bind>*/ ; } } "); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("x, y", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [Fact] public void TestParenthesizedAssignmentExpressionSelection() { var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowExpression(@" class C { static void Main() { bool x = true; bool y = x | /*<bind>*/ (x = x) /*</bind>*/ | x; } } "); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("x, y", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [Fact] public void TestRefArgumentSelection() { var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowExpression(@" class C { static void Main() { int x = 0; Goo(ref /*<bind>*/ x /*</bind>*/ ); System.Console.WriteLine(x); } static void Goo(ref int x) { } } "); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [WorkItem(540066, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540066")] [Fact] public void AnalysisOfBadRef() { var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowExpression(@" class C { static void Main() { /*<bind>*/Main(ref 1)/*</bind>*/; } }"); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); } [Fact] public void TestAlwaysAssigned20NullCoalescing() { var analysis = CompileAndAnalyzeDataFlowExpression(@" class C { public static object B(out object b) { b = null; return b; } public static void Main(string[] args) { object a, b; object c = B(out a) ?? B(out /*<bind>*/b/*</bind>*/); } }"); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("args, a", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("args, a", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); } [WorkItem(528662, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/528662")] [Fact] public void TestNullCoalescingWithConstNullLeft() { var dataFlows = CompileAndAnalyzeDataFlowExpression(@" struct STest { public static string SM() { const string s = null; var ss = ""Q""; var ret = /*<bind>*/( s ?? (ss = ""C""))/*</bind>*/ + ss; return ret; } }"); Assert.Null(GetSymbolNamesJoined(dataFlows.VariablesDeclared)); Assert.Equal("ss", GetSymbolNamesJoined(dataFlows.AlwaysAssigned)); Assert.Equal("s", GetSymbolNamesJoined(dataFlows.DataFlowsIn)); Assert.Equal("ss", GetSymbolNamesJoined(dataFlows.DataFlowsOut)); Assert.Equal("s, ss", GetSymbolNamesJoined(dataFlows.DefinitelyAssignedOnEntry)); Assert.Equal("s, ss", GetSymbolNamesJoined(dataFlows.DefinitelyAssignedOnExit)); } [WorkItem(528662, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/528662")] [Fact] public void TestNullCoalescingWithConstNotNullLeft() { var dataFlows = CompileAndAnalyzeDataFlowExpression(@" class Test { public static string SM() { const string s = ""Not Null""; var ss = ""QC""; var ret = /*<bind>*/ s ?? ss /*</bind>*/ + ""\r\n""; return ret; } } "); Assert.Null(GetSymbolNamesJoined(dataFlows.VariablesDeclared)); Assert.Equal("s", GetSymbolNamesJoined(dataFlows.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlows.DataFlowsOut)); Assert.Equal("s, ss", GetSymbolNamesJoined(dataFlows.DefinitelyAssignedOnEntry)); Assert.Equal("s, ss", GetSymbolNamesJoined(dataFlows.DefinitelyAssignedOnExit)); } [WorkItem(8935, "DevDiv_Projects/Roslyn")] [Fact] public void TestDefaultOperator01() { var dataFlows = CompileAndAnalyzeDataFlowExpression(@" using System; using System.Collections.Generic; class Test<T> { public T GetT() { return /*<bind>*/ default(T) /*</bind>*/; } } "); Assert.Null(GetSymbolNamesJoined(dataFlows.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(dataFlows.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlows.DataFlowsOut)); Assert.Equal("this", GetSymbolNamesJoined(dataFlows.DefinitelyAssignedOnEntry)); Assert.Equal("this", GetSymbolNamesJoined(dataFlows.DefinitelyAssignedOnExit)); } [Fact] public void TestTypeOfOperator01() { var dataFlows = CompileAndAnalyzeDataFlowExpression(@" using System; using System.Collections.Generic; class Test<T> { public short GetT(T t) { if (/*<bind>*/ typeof(T) == typeof(int) /*</bind>*/) return 123; return 456; } } "); Assert.Null(GetSymbolNamesJoined(dataFlows.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(dataFlows.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlows.DataFlowsOut)); Assert.Equal("this, t", GetSymbolNamesJoined(dataFlows.DefinitelyAssignedOnEntry)); Assert.Equal("this, t", GetSymbolNamesJoined(dataFlows.DefinitelyAssignedOnExit)); } [Fact] public void TestIsOperator01() { var dataFlows = CompileAndAnalyzeDataFlowExpression(@" using System; using System.Collections.Generic; struct Test<T> { public string GetT(T t) { if /*<bind>*/(t is string)/*</bind>*/ return ""SSS""; return null; } } "); Assert.Null(GetSymbolNamesJoined(dataFlows.VariablesDeclared)); Assert.Equal("t", GetSymbolNamesJoined(dataFlows.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlows.DataFlowsOut)); Assert.Equal("this, t", GetSymbolNamesJoined(dataFlows.DefinitelyAssignedOnEntry)); Assert.Equal("this, t", GetSymbolNamesJoined(dataFlows.DefinitelyAssignedOnExit)); } [Fact] public void TestAsOperator01() { var dataFlows = CompileAndAnalyzeDataFlowExpression(@" using System; using System.Collections.Generic; struct Test<T> { public string GetT(T t) { string ret = null; if (t is string) ret = /*<bind>*/t as string/*</bind>*/; return ret; } } "); Assert.Null(GetSymbolNamesJoined(dataFlows.VariablesDeclared)); Assert.Equal("t", GetSymbolNamesJoined(dataFlows.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlows.DataFlowsOut)); Assert.Equal("this, t, ret", GetSymbolNamesJoined(dataFlows.DefinitelyAssignedOnEntry)); Assert.Equal("this, t, ret", GetSymbolNamesJoined(dataFlows.DefinitelyAssignedOnExit)); } [WorkItem(4028, "DevDiv_Projects/Roslyn")] [Fact] public void TestArrayInitializer() { var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowExpression(@" class C { static void Main() { int y = 1; int[,] x = { { /*<bind>*/ y /*</bind>*/ } }; } } "); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Equal("y", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("y", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("y", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Equal("y", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("y, x", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [Fact] public void TestImplicitStackAllocArrayInitializer() { var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowExpression(@" class C { static void Main() { int z = 1; int y = 1; var x = stackalloc[] { /*<bind>*/ y /*</bind>*/ , z++ }; } } "); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Equal("y", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("z, y", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("z, y", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Equal("y", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Equal("z", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("z, y, x", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [Fact] public void TestStackAllocArrayInitializer() { var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowExpression(@" class C { static void Main() { int z = 1; int y = 1; var x = stackalloc int[] { /*<bind>*/ y /*</bind>*/ , z++ }; } } "); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Equal("y", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("z, y", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("z, y", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Equal("y", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Equal("z", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("z, y, x", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [WorkItem(539286, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539286")] [Fact] public void TestAnalysisInFieldInitializers() { var results1 = CompileAndAnalyzeDataFlowExpression(@" using System; class C { static void Main() { Func<int, int> f = p => { int x = 1; int y = 1; return /*<bind>*/1 + (x=2) + p + y/*</bind>*/; }; f(1); } } "); var results2 = CompileAndAnalyzeDataFlowExpression(@" using System; class C { static Func<int, int> f = p => { int x = 1; int y = 1; return /*<bind>*/1 + (x=2) + p + y/*</bind>*/; }; static void Main() { int r = f(1); } } "); Assert.Equal(GetSymbolNamesJoined(results1.AlwaysAssigned), GetSymbolNamesJoined(results2.AlwaysAssigned)); Assert.Equal(GetSymbolNamesJoined(results1.Captured), GetSymbolNamesJoined(results2.Captured)); Assert.Equal(GetSymbolNamesJoined(results1.CapturedInside), GetSymbolNamesJoined(results2.CapturedInside)); Assert.Equal(GetSymbolNamesJoined(results1.CapturedOutside), GetSymbolNamesJoined(results2.CapturedOutside)); Assert.Equal(GetSymbolNamesJoined(results1.DataFlowsIn), GetSymbolNamesJoined(results2.DataFlowsIn)); Assert.Equal(GetSymbolNamesJoined(results1.DataFlowsOut), GetSymbolNamesJoined(results2.DataFlowsOut)); Assert.Equal("p, x, y", GetSymbolNamesJoined(results2.DefinitelyAssignedOnEntry)); Assert.Equal("p, x, y", GetSymbolNamesJoined(results2.DefinitelyAssignedOnExit)); Assert.Equal(GetSymbolNamesJoined(results1.ReadInside), GetSymbolNamesJoined(results2.ReadInside)); Assert.Equal(GetSymbolNamesJoined(results1.ReadOutside), string.Join(", ", new string[] { "f" }.Concat((results2.ReadOutside).Select(symbol => symbol.Name)).OrderBy(name => name))); Assert.Equal(GetSymbolNamesJoined(results1.WrittenInside), GetSymbolNamesJoined(results2.WrittenInside)); Assert.Equal(GetSymbolNamesJoined(results1.WrittenOutside), string.Join(", ", new string[] { "f" }.Concat((results2.WrittenOutside).Select(symbol => symbol.Name)).OrderBy(name => name))); } [WorkItem(539286, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539286")] [Fact] public void TestAnalysisInSimpleFieldInitializers() { var results1 = CompileAndAnalyzeDataFlowExpression(@" using System; class C { int x = 1; int y = 1; int z = /*<bind>*/1 + (x=2) + p + y/*</bind>*/; } "); var results2 = CompileAndAnalyzeDataFlowExpression(@" using System; class C { int x = 1; int y = 1; static void Main() { /*<bind>*/1 + (x=2) + p + y/*</bind>*/; } } "); // NOTE: 'f' should not be reported in results1.AlwaysAssigned, this issue will be addressed separately Assert.Equal(GetSymbolNamesJoined(results1.AlwaysAssigned), GetSymbolNamesJoined(results2.AlwaysAssigned)); Assert.Equal(GetSymbolNamesJoined(results1.Captured), GetSymbolNamesJoined(results2.Captured)); Assert.Equal(GetSymbolNamesJoined(results1.CapturedInside), GetSymbolNamesJoined(results2.CapturedInside)); Assert.Equal(GetSymbolNamesJoined(results1.CapturedOutside), GetSymbolNamesJoined(results2.CapturedOutside)); Assert.Equal(GetSymbolNamesJoined(results1.DataFlowsIn), GetSymbolNamesJoined(results2.DataFlowsIn)); Assert.Equal(GetSymbolNamesJoined(results1.DataFlowsOut), GetSymbolNamesJoined(results2.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(results2.DefinitelyAssignedOnEntry)); Assert.Null(GetSymbolNamesJoined(results2.DefinitelyAssignedOnExit)); Assert.Equal(GetSymbolNamesJoined(results1.ReadInside), GetSymbolNamesJoined(results2.ReadInside)); Assert.Equal(GetSymbolNamesJoined(results1.ReadOutside), GetSymbolNamesJoined(results2.ReadOutside)); Assert.Equal(GetSymbolNamesJoined(results1.WrittenInside), GetSymbolNamesJoined(results2.WrittenInside)); Assert.Equal(GetSymbolNamesJoined(results1.WrittenOutside), GetSymbolNamesJoined(results2.WrittenOutside)); } [WorkItem(541968, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/541968")] [Fact] public void ConstantFieldInitializerExpression() { var dataFlows = CompileAndAnalyzeDataFlowExpression(@" using System; public class Aa { const int myLength = /*<bind>*/5/*</bind>*/; } "); Assert.Null(GetSymbolNamesJoined(dataFlows.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(dataFlows.DefinitelyAssignedOnEntry)); Assert.Null(GetSymbolNamesJoined(dataFlows.DefinitelyAssignedOnExit)); } [WorkItem(541968, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/541968")] [Fact] public void ConstantFieldInitializerExpression2() { var dataFlows = CompileAndAnalyzeDataFlowExpression(@" using System; public class Aa { // NOTE: illegal, but still a region we should handle. const bool myLength = true || ((Func<int, int>)(x => { int y = x; return /*<bind>*/y/*</bind>*/; }))(1) == 2; } "); Assert.Null(GetSymbolNamesJoined(dataFlows.VariablesDeclared)); Assert.Equal("x, y", GetSymbolNamesJoined(dataFlows.DefinitelyAssignedOnEntry)); Assert.Equal("x, y", GetSymbolNamesJoined(dataFlows.DefinitelyAssignedOnExit)); Assert.Equal("System.Int32 y", dataFlows.DataFlowsIn.Single().ToTestDisplayString()); Assert.Equal("System.Int32 y", dataFlows.ReadInside.Single().ToTestDisplayString()); } [WorkItem(541968, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/541968")] [Fact] public void FieldInitializerExpression() { var dataFlows = CompileAndAnalyzeDataFlowExpression(@" using System; public class Aa { bool myLength = true || ((Func<int, int>)(x => { int y = x; return /*<bind>*/y/*</bind>*/; }))(1) == 2; } "); Assert.Null(GetSymbolNamesJoined(dataFlows.VariablesDeclared)); Assert.Equal("x, y", GetSymbolNamesJoined(dataFlows.DefinitelyAssignedOnEntry)); Assert.Equal("x, y", GetSymbolNamesJoined(dataFlows.DefinitelyAssignedOnExit)); Assert.Equal("System.Int32 y", dataFlows.DataFlowsIn.Single().ToTestDisplayString()); Assert.Equal("System.Int32 y", dataFlows.ReadInside.Single().ToTestDisplayString()); } [WorkItem(542454, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542454")] [Fact] public void IdentifierNameInObjectCreationExpr() { var dataFlows = CompileAndAnalyzeDataFlowExpression(@" class myClass { static int Main() { myClass oc = new /*<bind>*/myClass/*</bind>*/(); return 0; } } "); Assert.Null(GetSymbolNamesJoined(dataFlows.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(dataFlows.DefinitelyAssignedOnEntry)); Assert.Null(GetSymbolNamesJoined(dataFlows.DefinitelyAssignedOnExit)); } [WorkItem(542463, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542463")] [Fact] public void MethodGroupInDelegateCreation() { var dataFlows = CompileAndAnalyzeDataFlowExpression(@" class C { void Method() { System.Action a = new System.Action(/*<bind>*/Method/*</bind>*/); } } "); Assert.Equal("this", dataFlows.ReadInside.Single().Name); } [WorkItem(542771, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542771")] [Fact] public void BindInCaseLabel() { var dataFlows = CompileAndAnalyzeDataFlowExpression(@" class TestShapes { static void Main() { color s = color.blue; switch (s) { case true ? /*<bind>*/ color.blue /*</bind>*/ : color.blue: break; default: goto default; } } } enum color { blue, green }"); var tmp = dataFlows.VariablesDeclared; // ensure no exception thrown Assert.Empty(dataFlows.VariablesDeclared); } [WorkItem(542915, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542915")] [Fact] public void BindLiteralExprInEnumDecl() { var dataFlows = CompileAndAnalyzeDataFlowExpression(@" enum Number { Zero = /*<bind>*/0/*</bind>*/ } "); Assert.True(dataFlows.Succeeded); Assert.Empty(dataFlows.VariablesDeclared); } [WorkItem(542944, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542944")] [Fact] public void AssignToConst() { var analysis = CompileAndAnalyzeDataFlowStatements(@" class Program { static void Main(string[] args) { const string a = null; /*<bind>*/a = null;/*</bind>*/ } } "); Assert.Equal("a", GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("args, a", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("args, a", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); } [WorkItem(543987, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543987")] [Fact] public void TestAddressOfUnassignedStructLocal() { var analysis = CompileAndAnalyzeDataFlowExpression(@" class Program { static void Main() { int x; int* px = /*<bind>*/&x/*</bind>*/; } } "); Assert.Equal("x", GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Equal("x", GetSymbolNamesJoined(analysis.UnsafeAddressTaken)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(analysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Equal("x", GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("px", GetSymbolNamesJoined(analysis.WrittenOutside)); } [WorkItem(543987, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543987")] [Fact] public void TestAddressOfAssignedStructLocal() { var analysis = CompileAndAnalyzeDataFlowExpression(@" class Program { static void Main() { int x = 1; int* px = /*<bind>*/&x/*</bind>*/; } } "); Assert.Equal("x", GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Equal("x", GetSymbolNamesJoined(analysis.UnsafeAddressTaken)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Equal("x", GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x, px", GetSymbolNamesJoined(analysis.WrittenOutside)); } [WorkItem(543987, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543987")] [Fact] public void TestAddressOfUnassignedStructField() { var analysis = CompileAndAnalyzeDataFlowExpression(@" public struct S { public int x; public int y; } class Program { static void Main() { S s; int* px = /*<bind>*/&s.x/*</bind>*/; } } "); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Equal("s", GetSymbolNamesJoined(analysis.UnsafeAddressTaken)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Null(GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(analysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Equal("s", GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("px", GetSymbolNamesJoined(analysis.WrittenOutside)); } [WorkItem(543987, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543987")] [Fact] public void TestAddressOfAssignedStructField() { var analysis = CompileAndAnalyzeDataFlowExpression(@" public struct S { public int x; public int y; } class Program { static void Main() { S s; s.x = 2; int* px = /*<bind>*/&s.x/*</bind>*/; } } "); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Equal("s", GetSymbolNamesJoined(analysis.UnsafeAddressTaken)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Equal("s", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Equal("s", GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Null(GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("s", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Equal("s", GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("s, px", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Fact] public void TestAddressOfAssignedStructField2() { var analysis = CompileAndAnalyzeDataFlowExpression(@" public struct S { public int x; } class Program { static void Main() { S s; s.x = 2; int* px = /*<bind>*/&s.x/*</bind>*/; } } "); // Really ??? Assert.Equal("s", GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Equal("s", GetSymbolNamesJoined(analysis.UnsafeAddressTaken)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Equal("s", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("s", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("s", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("s", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Equal("s", GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("s, px", GetSymbolNamesJoined(analysis.WrittenOutside)); } // Make sure that assignment is consistent with address-of. [Fact] public void TestAssignToStructField() { var analysis = CompileAndAnalyzeDataFlowExpression(@" public struct S { public int x; public int y; } class Program { static void Main() { S s; int x = /*<bind>*/s.x = 1/*</bind>*/; } } "); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Null(GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(analysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Equal("s", GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Fact, WorkItem(544314, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544314")] public void TestOmittedLambdaPointerTypeParameter() { var analysis = CompileAndAnalyzeDataFlowExpression(@" using System; unsafe public class Test { public delegate int D(int* p); public static void Main() { int i = 10; int* p = &i; D d = /*<bind>*/delegate { return *p;}/*</bind>*/; } } "); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("p", GetSymbolNamesJoined(analysis.Captured)); Assert.Equal("p", GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Equal("i", GetSymbolNamesJoined(analysis.UnsafeAddressTaken)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Equal("p", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("i, p", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("i, p", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("p", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal("i", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("i, p, d", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Fact] public void TestObjectInitializerExpression() { var analysis = CompileAndAnalyzeDataFlowExpression(@" public class MemberInitializerTest { public int x; public int y { get; set; } public static void Main() { var i = /*<bind>*/ new MemberInitializerTest() { x = 1, y = 2 } /*</bind>*/; } } "); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Null(GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(analysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("i", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Fact] public void TestObjectInitializerExpression_LocalAccessed() { var analysis = CompileAndAnalyzeDataFlowExpression(@" public class MemberInitializerTest { public int x; public int y { get; set; } public static void Main() { int x = 0, y = 0; var i = /*<bind>*/ new MemberInitializerTest() { x = x, y = y } /*</bind>*/; } } "); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x, y, i", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Fact] public void TestObjectInitializerExpression_InvalidAccess() { var analysis = CompileAndAnalyzeDataFlowExpression(@" public class MemberInitializerTest { public int x; public int y { get; set; } public static void Main() { var i = /*<bind>*/ new MemberInitializerTest() { x = x, y = y } /*</bind>*/; int x = 0, y = 0; } } "); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Null(GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("i, x, y", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Fact] public void TestObjectInitializerExpression_LocalAccessed_InitializerExpressionSyntax() { var analysis = CompileAndAnalyzeDataFlowExpression(@" public class MemberInitializerTest { public int x; public int y { get; set; } public static void Main() { int x = 0, y = 0; var i = new MemberInitializerTest() /*<bind>*/ { x = x, y = y } /*</bind>*/; } } "); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x, y, i", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Fact] public void TestObjectInitializerExpression_NestedObjectInitializer() { var analysis = CompileAndAnalyzeDataFlowExpression(@" public class Goo { public int z; } public class MemberInitializerTest { public int x; public Goo y { get; set; } public static void Main() { int x = 0, z = 0; var i = new MemberInitializerTest() { x = x, y = /*<bind>*/ { z = z } /*</bind>*/ }; } } "); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Equal("z", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x, z", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x, z", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("z", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x, z, i", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Fact] public void TestObjectInitializerExpression_VariableCaptured() { var analysis = CompileAndAnalyzeDataFlowExpression(@" public class Goo { public delegate int D(); public D z; } public class MemberInitializerTest { public int x; public Goo y { get; set; } public static void Main() { int x = 0, z = 0; var i = new MemberInitializerTest() /*<bind>*/ { x = x, y = { z = () => z } } /*</bind>*/; } } "); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("z", GetSymbolNamesJoined(analysis.Captured)); Assert.Equal("z", GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Equal("x, z", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x, z", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x, z", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("x, z", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x, z, i", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Fact] public void TestWithExpression() { var analysis = CompileAndAnalyzeDataFlowExpression(@" #nullable enable record B(string? X) { static void M1(B b1) { var x = ""hello""; _ = /*<bind>*/b1 with { X = x }/*</bind>*/; } } "); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Equal("b1, x", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("b1, x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("b1, x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("b1, x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("b1, x", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Fact] public void DefinitelyAssignedParameters() { var analysis = CompileAndAnalyzeDataFlowExpression(@" #nullable enable class B { static void M0(B b0) { M1(b0); static void M1(B b1) { _ = /*<bind>*/b1 + b2/*</bind>*/; } } } "); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Equal("b1", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("b0, b1", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("b0, b1", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("b1", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal("b0", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("b0, b1", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Fact] public void TestCollectionInitializerExpression() { var analysis = CompileAndAnalyzeDataFlowExpression(@" using System; using System.Collections.Generic; using System.Collections; class Test { public static int Main() { List<int> list = /*<bind>*/ new List<int>() { 1, 2, 3, 4, 5 } /*</bind>*/; return 0; } } "); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Null(GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(analysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("list", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Fact] public void TestCollectionInitializerExpression_LocalAccessed() { var analysis = CompileAndAnalyzeDataFlowExpression(@" using System; using System.Collections.Generic; using System.Collections; class Test { public static int Main() { int x = 1; List<int> list = new List<int>() /*<bind>*/ { x } /*</bind>*/; return 0; } } "); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x, list", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Fact] public void TestCollectionInitializerExpression_ComplexElementInitializer() { var analysis = CompileAndAnalyzeDataFlowExpression(@" using System; using System.Collections.Generic; using System.Collections; class Test { public static int Main() { int x = 1; List<int> list = new List<int>() { /*<bind>*/ { x } /*</bind>*/ }; return 0; } } "); // Nice to have: "x" flows in, "x" read inside, "list, x" written outside. Assert.False(analysis.Succeeded); } [Fact] public void TestCollectionInitializerExpression_VariableCaptured() { var analysis = CompileAndAnalyzeDataFlowExpression(@" using System; using System.Collections.Generic; using System.Collections; class Test { public delegate int D(); public static int Main() { int x = 1; List<D> list = new List<D>() /*<bind>*/ { () => x } /*</bind>*/; return 0; } } "); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("x", GetSymbolNamesJoined(analysis.Captured)); Assert.Equal("x", GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x, list", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Fact] public void ObjectInitializerInField() { var dataFlows = CompileAndAnalyzeDataFlowExpression(@" using System; using System.Collections.Generic; class C { public Func<int, int, int> dele; } public class Test { C c = /*<bind>*/new C { dele = delegate(int x, int y) { return x + y; } }/*</bind>*/; } "); Assert.Equal("x, y", GetSymbolNamesJoined(dataFlows.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(dataFlows.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(dataFlows.Captured)); Assert.Null(GetSymbolNamesJoined(dataFlows.CapturedInside)); Assert.Null(GetSymbolNamesJoined(dataFlows.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(dataFlows.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlows.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(dataFlows.DefinitelyAssignedOnEntry)); Assert.Null(GetSymbolNamesJoined(dataFlows.DefinitelyAssignedOnExit)); Assert.Equal("x, y", GetSymbolNamesJoined(dataFlows.ReadInside)); Assert.Equal("x, y", GetSymbolNamesJoined(dataFlows.WrittenInside)); Assert.Null(GetSymbolNamesJoined(dataFlows.ReadOutside)); Assert.Null(GetSymbolNamesJoined(dataFlows.WrittenOutside)); } [Fact] public void CollectionInitializerInField() { var dataFlows = CompileAndAnalyzeDataFlowExpression(@" using System; using System.Collections.Generic; class C { public Func<int, int, int> dele; } public class Test { List<Func<int, int, int>> list = /*<bind>*/new List<Func<int, int, int>>() { (x, y) => { return x + y; } }/*</bind>*/; } "); Assert.Equal("x, y", GetSymbolNamesJoined(dataFlows.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(dataFlows.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(dataFlows.Captured)); Assert.Null(GetSymbolNamesJoined(dataFlows.CapturedInside)); Assert.Null(GetSymbolNamesJoined(dataFlows.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(dataFlows.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlows.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(dataFlows.DefinitelyAssignedOnEntry)); Assert.Null(GetSymbolNamesJoined(dataFlows.DefinitelyAssignedOnExit)); Assert.Equal("x, y", GetSymbolNamesJoined(dataFlows.ReadInside)); Assert.Equal("x, y", GetSymbolNamesJoined(dataFlows.WrittenInside)); Assert.Null(GetSymbolNamesJoined(dataFlows.ReadOutside)); Assert.Null(GetSymbolNamesJoined(dataFlows.WrittenOutside)); } [Fact(), WorkItem(529329, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/529329")] public void QueryAsFieldInitializer() { var dataFlows = CompileAndAnalyzeDataFlowExpression(@" using System; using System.Linq; using System.Collections.Generic; using System.Collections; class Test { public IEnumerable e = /*<bind>*/ from x in new[] { 1, 2, 3 } where BadExpression let y = x.ToString() select y /*</bind>*/; } "); Assert.Equal("x, y", GetSymbolNamesJoined(dataFlows.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(dataFlows.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(dataFlows.Captured)); Assert.Null(GetSymbolNamesJoined(dataFlows.CapturedInside)); Assert.Null(GetSymbolNamesJoined(dataFlows.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(dataFlows.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlows.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(dataFlows.DefinitelyAssignedOnEntry)); Assert.Null(GetSymbolNamesJoined(dataFlows.DefinitelyAssignedOnExit)); Assert.Equal("x, y", GetSymbolNamesJoined(dataFlows.ReadInside)); Assert.Equal("x, y", GetSymbolNamesJoined(dataFlows.WrittenInside)); Assert.Null(GetSymbolNamesJoined(dataFlows.ReadOutside)); Assert.Null(GetSymbolNamesJoined(dataFlows.WrittenOutside)); } [WorkItem(544361, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544361")] [Fact] public void FullQueryExpression() { var dataFlows = CompileAndAnalyzeDataFlowExpression( @"using System.Linq; class Program { static void Main(string[] args) { var q = /*<bind>*/from arg in args group arg by arg.Length into final select final/*</bind>*/; } }"); Assert.Equal("args", GetSymbolNamesJoined(dataFlows.DataFlowsIn)); Assert.Equal("args", GetSymbolNamesJoined(dataFlows.DefinitelyAssignedOnEntry)); Assert.Equal("args", GetSymbolNamesJoined(dataFlows.DefinitelyAssignedOnExit)); } [WorkItem(669341, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/669341")] [Fact] public void ReceiverRead() { var dataFlows = CompileAndAnalyzeDataFlowExpression( @"using System; struct X { public Y y; } struct Y { public Z z; } struct Z { public int Value; } class Test { static void Main() { X x = new X(); var value = /*<bind>*/x.y/*</bind>*/.z.Value; } }"); Assert.Equal("x", GetSymbolNamesJoined(dataFlows.ReadInside)); Assert.Null(GetSymbolNamesJoined(dataFlows.WrittenInside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlows.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(dataFlows.DefinitelyAssignedOnExit)); } [WorkItem(669341, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/669341")] [Fact] public void ReceiverWritten() { var dataFlows = CompileAndAnalyzeDataFlowExpression( @"using System; struct X { public Y y; } struct Y { public Z z; } struct Z { public int Value; } class Test { static void Main() { X x = new X(); /*<bind>*/x.y/*</bind>*/.z.Value = 3; } }"); Assert.Null(GetSymbolNamesJoined(dataFlows.ReadInside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlows.WrittenInside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlows.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(dataFlows.DefinitelyAssignedOnExit)); } [WorkItem(669341, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/669341")] [Fact] public void ReceiverReadAndWritten() { var dataFlows = CompileAndAnalyzeDataFlowExpression( @"using System; struct X { public Y y; } struct Y { public Z z; } struct Z { public int Value; } class Test { static void Main() { X x = new X(); /*<bind>*/x.y/*</bind>*/.z.Value += 3; } }"); Assert.Equal("x", GetSymbolNamesJoined(dataFlows.ReadInside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlows.WrittenInside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlows.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(dataFlows.DefinitelyAssignedOnExit)); } [Fact] public void UnaryPlus() { // reported at https://social.msdn.microsoft.com/Forums/vstudio/en-US/f5078027-def2-429d-9fef-ab7f240883d2/writteninside-for-unary-operators?forum=roslyn var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowStatements(@" class Main { static int Main(int a) { /*<bind>*/ return +a; /*</bind>*/ } } "); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Equal("a", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("a", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("a", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Equal("a", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("a", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.Captured)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedOutside)); } [Fact] public void NullCoalescingAssignment() { var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowMultipleExpressions(@" public class C { public static void Main() { C c; c ??= new C(); object x1; object y1; /*<bind0>*/GetC(x1 = 1).Prop ??= (y1 = 2)/*</bind0>*/; x1.ToString(); y1.ToString(); object x2; object y2; /*<bind1>*/GetC(x2 = 1).Field ??= (y2 = 2)/*</bind1>*/; x2.ToString(); y2.ToString(); } static C GetC(object i) => null; object Prop { get; set; } object Field; } "); var propertyDataFlowAnalysis = dataFlowAnalysisResults.First(); var fieldDataFlowAnalysis = dataFlowAnalysisResults.Skip(1).Single(); assertAllInfo(propertyDataFlowAnalysis, "x1", "y1", "x2", "y2"); assertAllInfo(fieldDataFlowAnalysis, "x2", "y2", "x1", "y1"); void assertAllInfo(DataFlowAnalysis dataFlowAnalysis, string currentX, string currentY, string otherX, string otherY) { Assert.Null(GetSymbolNamesJoined(dataFlowAnalysis.VariablesDeclared)); Assert.Equal(currentX, GetSymbolNamesJoined(dataFlowAnalysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysis.DataFlowsIn)); Assert.Equal($"{currentX}, {currentY}", GetSymbolNamesJoined(dataFlowAnalysis.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysis.ReadInside)); Assert.Equal("c, x1, y1, x2, y2", GetSymbolNamesJoined(dataFlowAnalysis.ReadOutside)); Assert.Equal($"{currentX}, {currentY}", GetSymbolNamesJoined(dataFlowAnalysis.WrittenInside)); Assert.Equal($"c, {otherX}, {otherY}", GetSymbolNamesJoined(dataFlowAnalysis.WrittenOutside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysis.Captured)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysis.CapturedOutside)); } } [Fact] public void CondAccess_NullCoalescing_DataFlow() { // This test corresponds to ExtractMethodTests.TestFlowStateNullableParameters3 var dataFlowAnalysis = CompileAndAnalyzeDataFlowExpression(@" #nullable enable class C { public string M() { string? a = null; string? b = null; return /*<bind>*/(a + b + a)?.ToString()/*</bind>*/ ?? string.Empty; } } "); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysis.AlwaysAssigned)); Assert.Equal("a, b", GetSymbolNamesJoined(dataFlowAnalysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysis.DataFlowsOut)); Assert.Equal("a, b", GetSymbolNamesJoined(dataFlowAnalysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysis.WrittenInside)); Assert.Equal("this, a, b", GetSymbolNamesJoined(dataFlowAnalysis.WrittenOutside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysis.Captured)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysis.CapturedOutside)); } [Theory] [InlineData("c?.M0(x = 0)")] [InlineData("c!.M0(x = 0)")] public void CondAccess_Equals_DataFlowsOut_01(string leftOperand) { var dataFlowAnalysis = CompileAndAnalyzeDataFlowExpression(@" #nullable enable class C { bool M0(object? obj) => false; public static void M(C? c) { int x = 0; if (" + leftOperand + @" == /*<bind>*/c!.M0(x = 0)/*</bind>*/) { x.ToString(); } x.ToString(); } } "); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysis.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysis.AlwaysAssigned)); Assert.Equal("c", GetSymbolNamesJoined(dataFlowAnalysis.DataFlowsIn)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysis.DataFlowsOut)); Assert.Equal("c", GetSymbolNamesJoined(dataFlowAnalysis.ReadInside)); Assert.Equal("c, x", GetSymbolNamesJoined(dataFlowAnalysis.ReadOutside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysis.WrittenInside)); Assert.Equal("c, x", GetSymbolNamesJoined(dataFlowAnalysis.WrittenOutside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysis.Captured)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysis.CapturedOutside)); } [Theory] [InlineData("c?.M0(x = 0)")] [InlineData("c!.M0(x = 0)")] public void CondAccess_Equals_DataFlowsOut_02(string leftOperand) { var dataFlowAnalysis = CompileAndAnalyzeDataFlowExpression(@" #nullable enable class C { bool M0(object? obj) => false; public static void M(C? c) { int x = 0; if (" + leftOperand + @" == /*<bind>*/c!.M0(x = 0)/*</bind>*/) { x.ToString(); } } } "); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysis.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysis.AlwaysAssigned)); Assert.Equal("c", GetSymbolNamesJoined(dataFlowAnalysis.DataFlowsIn)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysis.DataFlowsOut)); Assert.Equal("c", GetSymbolNamesJoined(dataFlowAnalysis.ReadInside)); Assert.Equal("c, x", GetSymbolNamesJoined(dataFlowAnalysis.ReadOutside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysis.WrittenInside)); Assert.Equal("c, x", GetSymbolNamesJoined(dataFlowAnalysis.WrittenOutside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysis.Captured)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysis.CapturedOutside)); } #endregion #region "constructor initializer" [Fact] public void TestDataFlowsInCtorInitPublicApi() { var program = @" class C { C(int x) {} C(int x, int y) /*<bind>*/ : this(x + y) /*</bind>*/ {} } "; var analysis = CompileAndGetModelAndConstructorInitializer(program, (model, constructorInitializer) => CSharpExtensions.AnalyzeDataFlow(model, constructorInitializer) ); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.DataFlowsIn)); } [Fact] public void TestDataFlowsInCtorInitPublicApi2() { var program = @" class C { C(int x) {} C(int x, int y) /*<bind>*/ : this(x + y) /*</bind>*/ {} } "; var analysis = CompileAndGetModelAndConstructorInitializer(program, (model, constructorInitializer) => global::Microsoft.CodeAnalysis.ModelExtensions.AnalyzeDataFlow(model, constructorInitializer) ); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.DataFlowsIn)); } [Fact] public void TestDataFlowsInCtorInit() { var analysis = CompileAndAnalyzeDataFlowConstructorInitializer(@" class C { C(int x) {} C(int x, int y) /*<bind>*/ : this(x + y) /*</bind>*/ {} }"); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.DataFlowsIn)); } [Fact] public void TestDataFlowsInCtorInitVariablesDeclared() { var analysis = CompileAndAnalyzeDataFlowConstructorInitializer(@" class C { C(int x) {} C(int x) {} C(int x, int y) /*<bind>*/ : this((x++ + y is var b) switch { _ => b * 2}) /*</bind>*/ {} }"); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Equal("x, b", GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("b", GetSymbolNamesJoined(analysis.VariablesDeclared)); } [Fact] public void TestDataFlowsInCtorInitComplex() { var analysis = CompileAndAnalyzeDataFlowConstructorInitializer(@" public class BaseX { public BaseX(out int ix, ref string i, in int s, in int s2, out int rrr) { } } public class X : BaseX { public X(int r, out int ix, out int x, ref int i)/*<bind>*/ : base(out ix, ref CalcValue(""ctor"", out x), CalcInt(""int"", out var y) + CalcInt(""int2"", out var y2), x + y + r + y2 + i++, out var rrr) /*</bind>*/ { Console.WriteLine(y); } static string s; static ref string CalcValue(string text, out int i) { Console.WriteLine($""CalcInt({text})""); i = 42; return ref s; } static int CalcInt(string text, out int i) { Console.WriteLine($""CalcInt({text})""); i = 42; return i; } }"); Assert.Equal("r, i", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Equal("ix, x, i, y", GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("r, x, i, y, y2", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal("ix, x, i, y", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Equal("ix, x, i, y, y2, rrr", GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("ix, x, i, y, y2, rrr", GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("this, r, i", GetSymbolNamesJoined(analysis.WrittenOutside)); Assert.Equal("y, y2, rrr", GetSymbolNamesJoined(analysis.VariablesDeclared)); } [Fact] public void TestDataFlowsInCtorInitWrite() { var analysis = CompileAndAnalyzeDataFlowConstructorInitializer(@" class C { C(int x) {} C(int x, int y) /*<bind>*/ : this(x++ + y) /*</bind>*/ {} }"); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Equal("x", GetSymbolNamesJoined(analysis.WrittenInside)); } #endregion #region "primary constructor initializer" [Fact] public void TestDataFlowsInPrimaryCtorInitPublicApi() { var program = @" record Base(int x) record C(int x, int y) /*<bind>*/ : Base(x + y) /*</bind>*/; "; var analysis = CompileAndGetModelAndPrimaryConstructorInitializer(program, (model, primaryConstructorInitializer) => CSharpExtensions.AnalyzeDataFlow(model, primaryConstructorInitializer) ); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.DataFlowsIn)); } [Fact] public void TestDataFlowsInPrimaryCtorInitPublicApi2() { var program = @" record Base(int x) record C(int x, int y) /*<bind>*/ : Base(x + y) /*</bind>*/; "; var analysis = CompileAndGetModelAndPrimaryConstructorInitializer(program, (model, primaryConstructorInitializer) => global::Microsoft.CodeAnalysis.ModelExtensions.AnalyzeDataFlow(model, primaryConstructorInitializer) ); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.DataFlowsIn)); } [Fact] public void TestDataFlowsInPrimaryCtorInit() { var analysis = CompileAndAnalyzeDataFlowPrimaryConstructorInitializer(@" record Base(int x) record C(int x, int y) /*<bind>*/ : Base(x + y) /*</bind>*/; "); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.DataFlowsIn)); } [Fact] public void TestDataFlowsInPrimaryCtorInitVariablesDeclared() { var analysis = CompileAndAnalyzeDataFlowPrimaryConstructorInitializer(@" record Base(int x); record C(int x, int y) /*<bind>*/ : Base((x++ + y is var b) switch { _ => b * 2}) /*</bind>*/; "); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Equal("x, b", GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("b", GetSymbolNamesJoined(analysis.VariablesDeclared)); } #endregion #region "Statements" [Fact] public void TestDataReadWrittenIncDecOperator() { var analysisResults = CompileAndAnalyzeControlAndDataFlowStatements(@" class C { static short Main() { short x = 0, y = 1, z = 2; /*<bind>*/ x++; y--; /*</bind>*/ return y; } } "); var controlFlowAnalysisResults = analysisResults.Item1; var dataFlowAnalysisResults = analysisResults.Item2; Assert.Equal(0, controlFlowAnalysisResults.EntryPoints.Count()); Assert.Equal(0, controlFlowAnalysisResults.ExitPoints.Count()); Assert.Equal(0, controlFlowAnalysisResults.ReturnStatements.Count()); Assert.True(controlFlowAnalysisResults.StartPointIsReachable); Assert.True(controlFlowAnalysisResults.EndPointIsReachable); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Equal("x, y", GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Equal("x, y", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Equal("y", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("x, y", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Equal("y", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Equal("x, y", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("x, y, z", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [Fact] public void TestTernaryExpressionWithAssignments() { var analysisResults = CompileAndAnalyzeControlAndDataFlowStatements(@" class C { static void Main() { bool x = true; int y; /*<bind>*/ int z = x ? y = 1 : y = 2; /*</bind>*/ y.ToString(); } } "); var controlFlowAnalysisResults = analysisResults.Item1; var dataFlowAnalysisResults = analysisResults.Item2; Assert.Equal(0, controlFlowAnalysisResults.EntryPoints.Count()); Assert.Equal(0, controlFlowAnalysisResults.ExitPoints.Count()); Assert.Equal(0, controlFlowAnalysisResults.ReturnStatements.Count()); Assert.True(controlFlowAnalysisResults.EndPointIsReachable); Assert.Equal("z", GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Equal("y, z", GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Equal("y", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Equal("y", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Equal("y, z", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [WorkItem(542231, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542231")] [Fact] public void TestUnreachableRegion() { var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowStatements( @"class C { public static void Main(string[] args) { int i; return; /*<bind>*/ i = i + 1; /*</bind>*/ int j = i; } }"); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); } [WorkItem(542231, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542231")] [Fact] public void TestUnreachableRegion2() { var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowStatements( @"class C { public static void Main(string[] args) { string i = 0, j = 0, k = 0, l = 0; goto l1; /*<bind>*/ Console.WriteLine(i); j = 1; l1: Console.WriteLine(j); k = 1; goto l2; Console.WriteLine(k); l = 1; l3: Console.WriteLine(l); i = 1; /*</bind>*/ l2: Console.WriteLine(i + j + k + l); goto l3; } }"); Assert.Equal("j, l", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Equal("i, k", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); } [WorkItem(542231, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542231")] [Fact] public void TestUnreachableRegionInExpression() { var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowExpression( @"class C { public static bool Main() { int i, j; return false && /*<bind>*/((i = i + 1) == 2 || (j = i) == 3)/*</bind>*/; } }"); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); } [Fact] public void TestDeclarationWithSelfReferenceAndTernaryOperator() { var analysisResults = CompileAndAnalyzeControlAndDataFlowStatements(@" class C { static void Main() { /*<bind>*/ int x = true ? 1 : x; /*</bind>*/ } } "); var controlFlowAnalysisResults = analysisResults.Item1; var dataFlowAnalysisResults = analysisResults.Item2; Assert.Equal(0, controlFlowAnalysisResults.EntryPoints.Count()); Assert.Equal(0, controlFlowAnalysisResults.ExitPoints.Count()); Assert.Equal(0, controlFlowAnalysisResults.ReturnStatements.Count()); Assert.True(controlFlowAnalysisResults.EndPointIsReachable); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [Fact] public void TestDeclarationWithTernaryOperatorAndAssignment() { var analysisResults = CompileAndAnalyzeControlAndDataFlowStatements(@" class C { static void Main() { /*<bind>*/ int x, z, y = true ? 1 : x = z; /*</bind>*/ } } "); var controlFlowAnalysisResults = analysisResults.Item1; var dataFlowAnalysisResults = analysisResults.Item2; Assert.Equal(0, controlFlowAnalysisResults.EntryPoints.Count()); Assert.Equal(0, controlFlowAnalysisResults.ExitPoints.Count()); Assert.Equal(0, controlFlowAnalysisResults.ReturnStatements.Count()); Assert.True(controlFlowAnalysisResults.EndPointIsReachable); Assert.Equal("x, z, y", GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Equal("y", GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("z", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Equal("x, y", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [Fact] public void TestDictionaryInitializer() { var analysisResults = CompileAndAnalyzeControlAndDataFlowStatements(@" class C { static void Goo() { int i, j; /*<bind>*/ var s = new Dictionary<int, int>() {[i = j = 1] = 2 }; /*</bind>*/ System.Console.WriteLine(i + j); } } "); var controlFlowAnalysisResults = analysisResults.Item1; var dataFlowAnalysisResults = analysisResults.Item2; Assert.Equal(0, controlFlowAnalysisResults.EntryPoints.Count()); Assert.Equal(0, controlFlowAnalysisResults.ExitPoints.Count()); Assert.Equal(0, controlFlowAnalysisResults.ReturnStatements.Count()); Assert.True(controlFlowAnalysisResults.StartPointIsReachable); Assert.True(controlFlowAnalysisResults.EndPointIsReachable); Assert.Equal("s", GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Equal("i, j, s", GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Equal("i, j", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Equal("i, j", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Equal("i, j, s", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.Captured)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedOutside)); } [WorkItem(542435, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542435")] [Fact] public void NullArgsToAnalyzeControlFlowStatements() { var compilation = CreateCompilation(@" class C { static void Main() { int i = 10; } } "); var semanticModel = compilation.GetSemanticModel(compilation.SyntaxTrees[0]); var statement = compilation.SyntaxTrees[0].GetCompilationUnitRoot().DescendantNodesAndSelf().OfType<StatementSyntax>().First(); Assert.Throws<ArgumentNullException>(() => semanticModel.AnalyzeControlFlow(statement, null)); Assert.Throws<ArgumentNullException>(() => semanticModel.AnalyzeControlFlow(null, statement)); Assert.Throws<ArgumentNullException>(() => semanticModel.AnalyzeControlFlow(null)); Assert.Throws<ArgumentNullException>(() => semanticModel.AnalyzeDataFlow(null, statement)); Assert.Throws<ArgumentNullException>(() => semanticModel.AnalyzeDataFlow(statement, null)); Assert.Throws<ArgumentNullException>(() => semanticModel.AnalyzeDataFlow((StatementSyntax)null)); } [WorkItem(542507, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542507")] [Fact] public void DateFlowAnalyzeForLocalWithInvalidRHS() { // Case 1 var analysis = CompileAndAnalyzeDataFlowStatements(@" using System; public class Test { public delegate int D(); public void goo(ref D d) { /*<bind>*/ d = { return 10;}; /*</bind>*/ } } "); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); // Case 2 analysis = CompileAndAnalyzeDataFlowStatements(@" using System; public class Gen<T> { public void DefaultTest() { /*<bind>*/ object obj = default (new Gen<T>()); /*</bind>*/ } } "); Assert.Equal("obj", GetSymbolNamesJoined(analysis.VariablesDeclared)); } [Fact] public void TestEntryPoints01() { var analysis = CompileAndAnalyzeControlFlowStatements(@" class C { public void F() { goto L1; // 1 /*<bind>*/ L1: ; /*</bind>*/ goto L1; // 2 } }"); Assert.Equal(1, analysis.EntryPoints.Count()); } [Fact] public void TestExitPoints01() { var analysis = CompileAndAnalyzeControlFlowStatements(@" class C { public void F(int x) { L1: ; // 1 /*<bind>*/ if (x == 0) goto L1; if (x == 1) goto L2; if (x == 3) goto L3; L3: ; /*</bind>*/ L2: ; // 2 } }"); Assert.Equal(2, analysis.ExitPoints.Count()); } [Fact] public void TestRegionCompletesNormally01() { var analysis = CompileAndAnalyzeControlFlowStatements(@" class C { public void F(int x) { /*<bind>*/ goto L1; /*</bind>*/ L1: ; } }"); Assert.True(analysis.StartPointIsReachable); Assert.False(analysis.EndPointIsReachable); } [Fact] public void TestRegionCompletesNormally02() { var analysis = CompileAndAnalyzeControlFlowStatements(@" class C { public void F(int x) { /*<bind>*/ x = 2; /*</bind>*/ } }"); Assert.True(analysis.EndPointIsReachable); } [Fact] public void TestRegionCompletesNormally03() { var analysis = CompileAndAnalyzeControlFlowStatements(@" class C { public void F(int x) { /*<bind>*/ if (x == 0) return; /*</bind>*/ } }"); Assert.True(analysis.EndPointIsReachable); Assert.Equal(1, analysis.ExitPoints.Count()); } [Fact] public void TestVariablesDeclared01() { var analysis = CompileAndAnalyzeDataFlowStatements(@" class C { public void F(int x) { int a; /*<bind>*/ int b; int x, y = 1; { var z = ""a""; } /*</bind>*/ int c; } }"); Assert.Equal("b, x, y, z", GetSymbolNamesJoined(analysis.VariablesDeclared)); } [Fact] public void TestVariablesInitializedWithSelfReference() { var analysis = CompileAndAnalyzeDataFlowStatements(@" class C { public void F(int x) { /*<bind>*/ int x = x = 1; int y, z = 1; /*</bind>*/ } }"); Assert.Equal("x, y, z", GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Equal("x, z", GetSymbolNamesJoined(analysis.AlwaysAssigned)); } [Fact] public void AlwaysAssignedUnreachable() { var analysis = CompileAndAnalyzeDataFlowStatements(@" class C { public void F(int x) { int y; /*<bind>*/ if (x == 1) { y = 2; return; } else { y = 3; throw new Exception(); } /*</bind>*/ int = y; } }"); Assert.Equal("y", GetSymbolNamesJoined(analysis.AlwaysAssigned)); } [WorkItem(538170, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538170")] [Fact] public void TestVariablesDeclared02() { var analysis = CompileAndAnalyzeDataFlowStatements(@" class C { public void F(int x) /*<bind>*/ { int a; int b; int x, y = 1; { string z = ""a""; } int c; } /*</bind>*/ }"); Assert.Equal("a, b, x, y, z, c", GetSymbolNamesJoined(analysis.VariablesDeclared)); } [WorkItem(541280, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/541280")] [Fact] public void TestVariablesDeclared03() { var analysis = CompileAndAnalyzeDataFlowStatements(@" class C { public void F() /*<bind>*/ { int a = 0; long a = 1; } /*</bind>*/ }"); Assert.Equal("a, a", GetSymbolNamesJoined(analysis.VariablesDeclared)); var intsym = analysis.VariablesDeclared.First() as ILocalSymbol; var longsym = analysis.VariablesDeclared.Last() as ILocalSymbol; Assert.Equal("Int32", intsym.Type.Name); Assert.Equal("Int64", longsym.Type.Name); } [WorkItem(539229, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539229")] [Fact] public void UnassignedVariableFlowsOut01() { var analysis = CompileAndAnalyzeDataFlowStatements(@" class C { static void Main(string[] args) { int i = 10; /*<bind>*/ int j = j + i; /*</bind>*/ Console.Write(i); Console.Write(j); } }"); Assert.Equal("j", GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Equal("i", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Equal("j", GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("i, j", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal("i, j", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Equal("j", GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("args, i", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Fact] public void TestDataFlowsIn01() { var analysis = CompileAndAnalyzeDataFlowStatements(@" class C { public void F(int x) { int a = 1, y = 2; /*<bind>*/ int b = a + x + 3; /*</bind>*/ int c = a + 4 + y; } }"); Assert.Equal("x, a", GetSymbolNamesJoined(analysis.DataFlowsIn)); } [Fact] public void TestOutParameter01() { var analysis = CompileAndAnalyzeDataFlowStatements(@" class Program { void Test<T>(out T t) where T : class, new() { /*<bind>*/ T t1; Test(out t1); t = t1; /*</bind>*/ System.Console.WriteLine(t1.ToString()); } } "); Assert.Equal("this", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Equal("t, t1", GetSymbolNamesJoined(analysis.ReadOutside)); } [Fact] public void TestDataFlowsOut01() { var analysis = CompileAndAnalyzeDataFlowStatements(@" class C { public void F(int x) { int a = 1, y; /*<bind>*/ if (x == 1) y = x = 2; /*</bind>*/ int c = a + 4 + x + y; } }"); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.DataFlowsOut)); } [WorkItem(538146, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538146")] [Fact] public void TestDataFlowsOut02() { var analysis = CompileAndAnalyzeDataFlowStatements(@"class Program { void Test(string[] args) { /*<bind>*/ int s = 10, i = 1; int b = s + i; /*</bind>*/ System.Console.WriteLine(s); System.Console.WriteLine(i); } }"); Assert.Equal("s, i", GetSymbolNamesJoined(analysis.DataFlowsOut)); } [Fact] public void TestDataFlowsOut03() { var analysis = CompileAndAnalyzeDataFlowStatements( @"using System.Text; class Program { private static string Main() { StringBuilder builder = new StringBuilder(); /*<bind>*/ builder.Append(""Hello""); builder.Append("" From ""); builder.Append("" Roslyn""); /*</bind>*/ return builder.ToString(); } }"); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); } [Fact] public void TestDataFlowsOut04() { var analysis = CompileAndAnalyzeDataFlowStatements(@"class Program { void F(out int x) { /*<bind>*/ x = 12; /*</bind>*/ } }"); Assert.Equal("x", GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadOutside)); } [Fact] public void TestDataFlowsOut05() { var analysis = CompileAndAnalyzeDataFlowStatements(@"class Program { void F(out int x) { /*<bind>*/ x = 12; return; /*</bind>*/ } }"); Assert.Equal("x", GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadOutside)); } [Fact] public void TestDataFlowsOut06() { var analysis = CompileAndAnalyzeDataFlowStatements(@"class Program { void F(bool b) { int i = 1; while (b) { /*<bind>*/ i = i + 1; /*</bind>*/ } } }"); Assert.Equal("i", GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("i", GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("b", GetSymbolNamesJoined(analysis.ReadOutside)); } [Fact] public void TestDataFlowsOut07() { var analysis = CompileAndAnalyzeDataFlowStatements(@"class Program { void F(bool b) { int i; /*<bind>*/ i = 2; goto next; /*</bind>*/ next: int j = i; } }"); Assert.Equal("i", GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("i", GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("i", GetSymbolNamesJoined(analysis.ReadOutside)); } [WorkItem(540793, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540793")] [Fact] public void TestDataFlowsOut08() { var analysis = CompileAndAnalyzeDataFlowStatements(@"class Program { void F(bool b) { int i = 2; try { /*<bind>*/ i = 1; /*</bind>*/ } finally { int j = i; } } }"); Assert.Equal("i", GetSymbolNamesJoined(analysis.DataFlowsOut)); } [Fact] public void TestDataFlowsOut09() { var analysis = CompileAndAnalyzeDataFlowStatements(@"class Program { void Test(string[] args) { int i; string s; /*<bind>*/i = 10; s = args[0] + i.ToString();/*</bind>*/ } }"); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); } [Fact] public void TestDataFlowsOut10() { var analysis = CompileAndAnalyzeDataFlowStatements(@" class Program { static void Main(string[] args) { int x = 10; /*<bind>*/ int y; if (x == 10) y = 5; /*</bind>*/ Console.WriteLine(y); } } "); Assert.Equal("y", GetSymbolNamesJoined(analysis.DataFlowsOut)); } [Fact] public void TestAlwaysAssigned01() { var analysis = CompileAndAnalyzeDataFlowStatements(@" class C { public void F(int x) { int a = 1, y = 1; /*<bind>*/ if (x == 2) a = 3; else a = 4; x = 4; if (x == 3) y = 12; /*</bind>*/ int c = a + 4 + y; } }"); Assert.Equal("x, a", GetSymbolNamesJoined(analysis.AlwaysAssigned)); } [Fact] public void TestAlwaysAssigned02() { var analysis = CompileAndAnalyzeDataFlowStatements(@" class C { public void F(int x) { /*<bind>*/ const int a = 1; /*</bind>*/ } }"); Assert.Equal("a", GetSymbolNamesJoined(analysis.AlwaysAssigned)); } [WorkItem(540795, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540795")] [Fact] public void TestAlwaysAssigned03() { var analysis = CompileAndAnalyzeDataFlowStatements(@" class Always { public void F() { ushort x = 0, y = 1, z; /*<bind>*/ x++; return; uint z = y; /*</bind>*/ } }"); Assert.Equal("x", GetSymbolNamesJoined(analysis.AlwaysAssigned)); } [Fact] public void TestReadInside01() { var analysis = CompileAndAnalyzeDataFlowStatements(@" class Program { void Test<T>(out T t) where T : class, new() { /*<bind>*/ T t1; Test(out t1); t = t1; /*</bind>*/ System.Console.WriteLine(t1.ToString()); } } "); Assert.Equal("this, t1", GetSymbolNamesJoined(analysis.ReadInside)); } [Fact] public void TestAlwaysAssignedDuplicateVariables() { var analysis = CompileAndAnalyzeDataFlowStatements(@" class C { public void F(int x) { /*<bind>*/ int a, a, b, b; b = 1; /*</bind>*/ } }"); Assert.Equal("b", GetSymbolNamesJoined(analysis.AlwaysAssigned)); } [Fact] public void TestAccessedInsideOutside() { var analysis = CompileAndAnalyzeDataFlowStatements(@" class C { public void F(int x) { int a, b, c, d, e, f, g, h, i; a = 1; c = b = a + x; /*<bind>*/ d = c; e = f = d; /*</bind>*/ g = e; h = i = g; } }"); Assert.Equal("c, d", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal("d, e, f", GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x, a, e, g", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Equal("this, x, a, b, c, g, h, i", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Fact] public void TestAlwaysAssignedThroughParenthesizedExpression() { var analysis = CompileAndAnalyzeDataFlowStatements(@" class C { public void F(int x) { /*<bind>*/ int a = 1, b, c, d, e; b = 2; (c) = 3; ((d)) = 4; /*</bind>*/ } }"); Assert.Equal("a, b, c, d", GetSymbolNamesJoined(analysis.AlwaysAssigned)); } [Fact] public void TestAlwaysAssignedThroughCheckedExpression() { var analysis = CompileAndAnalyzeDataFlowStatements(@" class C { public void F(int x) { /*<bind>*/ int e, f, g; checked(e) = 5; (unchecked(f)) = 5; /*</bind>*/ } }"); Assert.Equal("e, f", GetSymbolNamesJoined(analysis.AlwaysAssigned)); } [Fact] public void TestAlwaysAssignedUsingAlternateNames() { var analysis = CompileAndAnalyzeDataFlowStatements(@" class C { public void F(int x) { /*<bind>*/ int green, blue, red, yellow, brown; @green = 1; blu\u0065 = 2; red = 3; yellow\uFFF9 = 4; @brown\uFFF9 = 5; /*</bind>*/ } }"); Assert.Equal("green, blue, red, yellow, brown", GetSymbolNamesJoined(analysis.AlwaysAssigned)); } [Fact] public void TestAlwaysAssignedViaPassingAsOutParameter() { var analysis = CompileAndAnalyzeDataFlowStatements(@" class C { public void F(int x) { /*<bind>*/ int a; G(out a); /*</bind>*/ } void G(out int x) { x = 1; } }"); Assert.Equal("a", GetSymbolNamesJoined(analysis.AlwaysAssigned)); } [Fact] public void TestAlwaysAssignedWithExcludedAssignment() { var analysis = CompileAndAnalyzeDataFlowStatements(@" partial class C { public void F(int x) { /*<bind>*/ int a, b; G(a = x = 1); H(b = 2); /*</bind>*/ } partial void G(int x); partial void H(int x); partial void H(int x) { } }"); Assert.Equal("b", GetSymbolNamesJoined(analysis.AlwaysAssigned)); } [Fact] public void TestDeclarationWithSelfReference() { var analysisResults = CompileAndAnalyzeControlAndDataFlowStatements(@" class C { static void Main() { /*<bind>*/ int x = x; /*</bind>*/ } } "); var controlFlowAnalysisResults = analysisResults.Item1; var dataFlowAnalysisResults = analysisResults.Item2; Assert.Equal(0, controlFlowAnalysisResults.EntryPoints.Count()); Assert.Equal(0, controlFlowAnalysisResults.ExitPoints.Count()); Assert.Equal(0, controlFlowAnalysisResults.ReturnStatements.Count()); Assert.True(controlFlowAnalysisResults.EndPointIsReachable); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [Fact] public void TestIfStatementWithAssignments() { var analysisResults = CompileAndAnalyzeControlAndDataFlowStatements(@" class C { static void Main() { bool x = true; int y; /*<bind>*/ if (x) y = 1; else y = 2; /*</bind>*/ y.ToString(); } } "); var controlFlowAnalysisResults = analysisResults.Item1; var dataFlowAnalysisResults = analysisResults.Item2; Assert.Equal(0, controlFlowAnalysisResults.EntryPoints.Count()); Assert.Equal(0, controlFlowAnalysisResults.ExitPoints.Count()); Assert.Equal(0, controlFlowAnalysisResults.ReturnStatements.Count()); Assert.True(controlFlowAnalysisResults.EndPointIsReachable); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Equal("y", GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Equal("y", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Equal("y", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Equal("y", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [Fact] public void TestIfStatementWithConstantCondition() { var analysisResults = CompileAndAnalyzeControlAndDataFlowStatements(@" class C { static void Main() { bool x = true; int y; /*<bind>*/ if (true) y = x; /*</bind>*/ y.ToString(); } } "); var controlFlowAnalysisResults = analysisResults.Item1; var dataFlowAnalysisResults = analysisResults.Item2; Assert.Equal(0, controlFlowAnalysisResults.EntryPoints.Count()); Assert.Equal(0, controlFlowAnalysisResults.ExitPoints.Count()); Assert.Equal(0, controlFlowAnalysisResults.ReturnStatements.Count()); Assert.True(controlFlowAnalysisResults.EndPointIsReachable); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Equal("y", GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Equal("y", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Equal("y", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Equal("y", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [Fact] public void TestIfStatementWithNonConstantCondition() { var analysisResults = CompileAndAnalyzeControlAndDataFlowStatements(@" class C { static void Main() { bool x = true; int y; /*<bind>*/ if (true | x) y = x; /*</bind>*/ y.ToString(); } } "); var controlFlowAnalysisResults = analysisResults.Item1; var dataFlowAnalysisResults = analysisResults.Item2; Assert.Equal(0, controlFlowAnalysisResults.EntryPoints.Count()); Assert.Equal(0, controlFlowAnalysisResults.ExitPoints.Count()); Assert.Equal(0, controlFlowAnalysisResults.ReturnStatements.Count()); Assert.True(controlFlowAnalysisResults.EndPointIsReachable); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Equal("y", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Equal("y", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Equal("y", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } // [Obsolete] // [Fact] // public void TestNonStatementSelection() // { // var analysisResults = CompileAndAnalyzeControlAndDataFlowRegion(@" //class C { // static void Main() // { // // /*<bind>*/ //int // /*</bind>*/ // x = 1; // } //} //"); // var controlFlowAnalysisResults = analysisResults.Item1; // var dataFlowAnalysisResults = analysisResults.Item2; // Assert.True(controlFlowAnalysisResults.Succeeded); // Assert.True(dataFlowAnalysisResults.Succeeded); // Assert.Equal(0, controlFlowAnalysisResults.EntryPoints.Count()); // Assert.Equal(0, controlFlowAnalysisResults.ExitPoints.Count()); // Assert.Equal(0, controlFlowAnalysisResults.ReturnStatements.Count()); // Assert.True(controlFlowAnalysisResults.EndPointIsReachable); // Assert.Null(GetSymbolNamesSortedAndJoined(dataFlowAnalysisResults.VariablesDeclared)); // Assert.Null(GetSymbolNamesSortedAndJoined(dataFlowAnalysisResults.DataFlowsIn)); // Assert.Null(GetSymbolNamesSortedAndJoined(dataFlowAnalysisResults.DataFlowsOut)); // Assert.Null(GetSymbolNamesSortedAndJoined(dataFlowAnalysisResults.ReadInside)); // Assert.Null(GetSymbolNamesSortedAndJoined(dataFlowAnalysisResults.ReadOutside)); // Assert.Null(GetSymbolNamesSortedAndJoined(dataFlowAnalysisResults.WrittenInside)); // Assert.Equal("x", GetSymbolNamesSortedAndJoined(dataFlowAnalysisResults.WrittenOutside)); // } [Fact] public void TestInvocation() { var analysisResults = CompileAndAnalyzeControlAndDataFlowStatements(@" class C { static void Main() { int x = 1, y = 1; /*<bind>*/ Goo(x); /*</bind>*/ } static void Goo(int x) { } } "); var controlFlowAnalysisResults = analysisResults.Item1; var dataFlowAnalysisResults = analysisResults.Item2; Assert.Equal(0, controlFlowAnalysisResults.EntryPoints.Count()); Assert.Equal(0, controlFlowAnalysisResults.ExitPoints.Count()); Assert.Equal(0, controlFlowAnalysisResults.ReturnStatements.Count()); Assert.True(controlFlowAnalysisResults.EndPointIsReachable); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("x, y", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [Fact] public void TestInvocationWithAssignmentInArguments() { var analysisResults = CompileAndAnalyzeControlAndDataFlowStatements(@" class C { static void Main() { int x = 1, y = 1; /*<bind>*/ Goo(x = y, y = 2); /*</bind>*/ int z = x + y; } static void Goo(int x, int y) { } } "); var controlFlowAnalysisResults = analysisResults.Item1; var dataFlowAnalysisResults = analysisResults.Item2; Assert.Equal(0, controlFlowAnalysisResults.EntryPoints.Count()); Assert.Equal(0, controlFlowAnalysisResults.ExitPoints.Count()); Assert.Equal(0, controlFlowAnalysisResults.ReturnStatements.Count()); Assert.True(controlFlowAnalysisResults.EndPointIsReachable); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Equal("x, y", GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Equal("y", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Equal("x, y", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("y", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Equal("x, y", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Equal("x, y", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("x, y, z", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [Fact, WorkItem(538979, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538979")] public void AssertFromInvalidLocalDeclaration() { var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowExpression(@" using System; public class MyClass { public static int Main() { variant /*<bind>*/ v = new byte(2) /*</bind>*/; // CS0246 byte b = v; // CS1729 return 1; } } "); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); } [Fact, WorkItem(538979, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538979")] public void AssertFromInvalidKeywordAsExpr() { var analysisResults = CompileAndAnalyzeControlAndDataFlowStatements(@" class B : A { public float M() { /*<bind>*/ { return base; // CS0175 } /*</bind>*/ } } class A {} "); var controlFlowAnalysisResults = analysisResults.Item1; //var dataFlowAnalysisResults = analysisResults.Item2; Assert.Equal(0, controlFlowAnalysisResults.EntryPoints.Count()); Assert.Equal(1, controlFlowAnalysisResults.ExitPoints.Count()); Assert.False(controlFlowAnalysisResults.EndPointIsReachable); } [WorkItem(539071, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539071")] [Fact] public void AssertFromFoldConstantEnumConversion() { var analysisResults = CompileAndAnalyzeControlAndDataFlowStatements(@" enum E { x, y, z } class Test { static int Main() { /*<bind>*/ E v = E.x; if (v != (E)((int)E.z - 1)) return 0; /*</bind>*/ return 1; } } "); var controlFlowAnalysisResults = analysisResults.Item1; //var dataFlowAnalysisResults = analysisResults.Item2; Assert.Equal(0, controlFlowAnalysisResults.EntryPoints.Count()); Assert.Equal(1, controlFlowAnalysisResults.ExitPoints.Count()); Assert.True(controlFlowAnalysisResults.EndPointIsReachable); } [Fact] public void ByRefParameterNotInAppropriateCollections2() { var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowStatements(@" class Program { void Test<T>(ref T t) { /*<bind>*/ T t1 = GetValue<T>(ref t); /*</bind>*/ System.Console.WriteLine(t1.ToString()); } T GetValue<T>(ref T t) { return t; } } "); Assert.Equal("t1", GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Equal("t1", GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Equal("this, t", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Equal("t, t1", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("this, t", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Equal("t, t1", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Equal("t, t1", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("this, t", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [Fact] public void UnreachableDeclaration() { var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowStatements(@" class Program { void F() { /*<bind>*/ int x; /*</bind>*/ System.Console.WriteLine(x); } } "); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("this", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [Fact] public void Parameters01() { var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowStatements(@" class Program { void F(int x, ref int y, out int z) { /*<bind>*/ y = z = 3; /*</bind>*/ } } "); Assert.Equal("y, z", GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Equal("y, z", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("y, z", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Equal("this, x, y", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [WorkItem(528308, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/528308")] [Fact] public void RegionForIfElseIfWithoutElse() { var analysisResults = CompileAndAnalyzeControlAndDataFlowStatements(@" using System; public class Test { ushort TestCase(ushort p) { /*<bind>*/ if (p > 0) { return --p; } else if (p < 0) { return ++p; } /*</bind>*/ // else { return 0; } } } "); var controlFlowAnalysisResults = analysisResults.Item1; var dataFlowAnalysisResults = analysisResults.Item2; Assert.Empty(controlFlowAnalysisResults.EntryPoints); Assert.Equal(2, controlFlowAnalysisResults.ExitPoints.Count()); Assert.True(controlFlowAnalysisResults.EndPointIsReachable); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Equal("p", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("p", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Equal("p", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("this, p", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } // [Obsolete] // [Fact] // public void TestBadRegion() // { // var analysisResults = CompileAndAnalyzeControlAndDataFlowRegion(@" //class C { // static void Main() // { // int a = 1; // int b = 1; // // if(a > 1) // /*<bind>*/ // a = 1; // b = 2; // /*</bind>*/ // } //} //"); // var controlFlowAnalysisResults = analysisResults.Item1; // var dataFlowAnalysisResults = analysisResults.Item2; // Assert.False(controlFlowAnalysisResults.Succeeded); // Assert.False(dataFlowAnalysisResults.Succeeded); // Assert.Equal(0, controlFlowAnalysisResults.EntryPoints.Count()); // Assert.Equal(0, controlFlowAnalysisResults.ExitPoints.Count()); // Assert.Equal(0, controlFlowAnalysisResults.ReturnStatements.Count()); // Assert.True(controlFlowAnalysisResults.EndPointIsReachable); // Assert.Null(GetSymbolNamesSortedAndJoined(dataFlowAnalysisResults.VariablesDeclared)); // Assert.Null(GetSymbolNamesSortedAndJoined(dataFlowAnalysisResults.AlwaysAssigned)); // Assert.Null(GetSymbolNamesSortedAndJoined(dataFlowAnalysisResults.DataFlowsIn)); // Assert.Null(GetSymbolNamesSortedAndJoined(dataFlowAnalysisResults.DataFlowsOut)); // Assert.Null(GetSymbolNamesSortedAndJoined(dataFlowAnalysisResults.ReadInside)); // Assert.Null(GetSymbolNamesSortedAndJoined(dataFlowAnalysisResults.ReadOutside)); // Assert.Null(GetSymbolNamesSortedAndJoined(dataFlowAnalysisResults.WrittenInside)); // Assert.Null(GetSymbolNamesSortedAndJoined(dataFlowAnalysisResults.WrittenOutside)); // } [WorkItem(541331, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/541331")] [Fact] public void AttributeOnAccessorInvalid() { var analysisResults = CompileAndAnalyzeControlAndDataFlowStatements(@" using System; public class C { public class AttributeX : Attribute { } public int Prop { get /*<bind>*/{ return 1; }/*</bind>*/ protected [AttributeX] set { } } } "); var controlFlowAnalysisResults = analysisResults.Item1; Assert.Empty(controlFlowAnalysisResults.EntryPoints); Assert.Equal(1, controlFlowAnalysisResults.ExitPoints.Count()); } [WorkItem(541585, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/541585")] [Fact] public void BadAssignThis() { var analysisResults = CompileAndAnalyzeControlAndDataFlowStatements(@" class Program { static void Main(string[] args) { /*<bind>*/ this = new S(); /*</bind>*/ } } struct S { }"); var controlFlowAnalysisResults = analysisResults.Item1; var dataFlowAnalysisResults = analysisResults.Item2; Assert.Equal(0, controlFlowAnalysisResults.EntryPoints.Count()); Assert.Equal(0, controlFlowAnalysisResults.ExitPoints.Count()); Assert.Equal(0, controlFlowAnalysisResults.ReturnStatements.Count()); Assert.True(controlFlowAnalysisResults.EndPointIsReachable); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("args", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [WorkItem(528623, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/528623")] [Fact] public void TestElementAccess01() { var analysis = CompileAndAnalyzeDataFlowStatements(@" public class Test { public void M(long[] p) { var v = new long[] { 1, 2, 3 }; /*<bind>*/ v[0] = p[0]; p[0] = v[1]; /*</bind>*/ v[1] = v[0]; p[2] = p[0]; } } "); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("p, v", GetSymbolNamesJoined(analysis.DataFlowsIn)); // By Design Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("p, v", GetSymbolNamesJoined(analysis.ReadInside)); // By Design Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("p, v", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Equal("this, p, v", GetSymbolNamesJoined(analysis.WrittenOutside)); } [WorkItem(541947, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/541947")] [Fact] public void BindPropertyAccessorBody() { var results = CompileAndAnalyzeControlAndDataFlowStatements(@" using System; public class A { public int P { get /*<bind>*/ { return 0; } /*</bind>*/ } } "); var ctrlFlows = results.Item1; var dataFlows = results.Item2; Assert.False(ctrlFlows.EndPointIsReachable); Assert.Null(GetSymbolNamesJoined(dataFlows.VariablesDeclared)); } [WorkItem(8926, "DevDiv_Projects/Roslyn")] [WorkItem(542346, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542346")] [WorkItem(528775, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/528775")] [Fact] public void BindEventAccessorBody() { var results = CompileAndAnalyzeControlAndDataFlowStatements(@" using System; public class A { public delegate void D(); public event D E { add { /*NA*/ } remove /*<bind>*/ { /*NA*/ } /*</bind>*/ } } "); var ctrlFlows = results.Item1; var dataFlows = results.Item2; Assert.True(ctrlFlows.EndPointIsReachable); Assert.Null(GetSymbolNamesJoined(dataFlows.VariablesDeclared)); } [WorkItem(541980, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/541980")] [Fact] public void BindDuplicatedAccessor() { var results = CompileAndAnalyzeControlAndDataFlowStatements(@" using System; public class A { public int P { get { return 1;} get /*<bind>*/ { return 0; } /*</bind>*/ } } "); var ctrlFlows = results.Item1; var dataFlows = results.Item2; var tmp = ctrlFlows.EndPointIsReachable; // ensure no exception thrown Assert.Empty(dataFlows.VariablesDeclared); } [WorkItem(543737, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543737")] [Fact] public void BlockSyntaxInAttributeDecl() { { var compilation = CreateCompilation(@" [Attribute(delegate.Class)] public class C { public static int Main () { return 1; } } "); var tree = compilation.SyntaxTrees.First(); var index = tree.GetCompilationUnitRoot().ToFullString().IndexOf(".Class)", StringComparison.Ordinal); var tok = tree.GetCompilationUnitRoot().FindToken(index); var node = tok.Parent as StatementSyntax; Assert.Null(node); } { var results = CompileAndAnalyzeControlAndDataFlowStatements(@" [Attribute(x => { /*<bind>*/int y = 12;/*</bind>*/ })] public class C { public static int Main () { return 1; } } "); Assert.False(results.Item1.Succeeded); Assert.False(results.Item2.Succeeded); } } [Fact, WorkItem(529273, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/529273")] public void IncrementDecrementOnNullable() { var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowStatements(@" class C { void M(ref sbyte p1, ref sbyte? p2) { byte? local_0 = 2; short? local_1; ushort non_nullable = 99; /*<bind>*/ p1++; p2 = (sbyte?) (local_0.Value - 1); local_1 = (byte)(p2.Value + 1); var ret = local_1.HasValue ? local_1.Value : 0; --non_nullable; /*</bind>*/ } } "); Assert.Equal("ret", GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Equal("p1, p2, local_1, non_nullable, ret", GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Equal("p1, local_0, non_nullable", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Equal("p1, p2", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("p1, p2, local_0, local_1, non_nullable", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Equal("p1, p2", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Equal("p1, p2, local_1, non_nullable, ret", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("this, p1, p2, local_0, non_nullable", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [WorkItem(17971, "https://github.com/dotnet/roslyn/issues/17971")] [Fact] public void VariablesDeclaredInBrokenForeach() { var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowStatements(@" struct S { static void Main(string[] args) { /*<bind>*/ Console.WriteLine(1); foreach () Console.WriteLine(2); /*</bind>*/ } } "); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); } [Fact] [WorkItem(4950, "https://github.com/dotnet/roslyn/issues/4950")] public void RegionWithUnsafeBlock() { var source = @"using System; class Program { static void Main(string[] args) { object value = args; // start IntPtr p; unsafe { object t = value; p = IntPtr.Zero; } // end Console.WriteLine(p); } } "; foreach (string keyword in new[] { "unsafe", "checked", "unchecked" }) { var compilation = CreateCompilation(source.Replace("unsafe", keyword)); var tree = compilation.SyntaxTrees[0]; var model = compilation.GetSemanticModel(tree); var stmt1 = tree.GetCompilationUnitRoot().DescendantNodesAndSelf().OfType<StatementSyntax>().Where(n => n.ToString() == "IntPtr p;").Single(); var stmt2 = tree.GetCompilationUnitRoot().DescendantNodesAndSelf().OfType<StatementSyntax>().Where(n => n.ToString().StartsWith(keyword)).First(); var dataFlowAnalysisResults = model.AnalyzeDataFlow(stmt1, stmt2); Assert.True(dataFlowAnalysisResults.Succeeded); Assert.Equal("p, t", GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Equal("p, t", GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.Captured)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedOutside)); Assert.Equal("value", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Equal("p", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("args, value", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("args, value, p, t", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Equal("value", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Equal("args, p", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Equal("p, t", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("args, value", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } } #endregion #region "lambda" [Fact] [WorkItem(41600, "https://github.com/dotnet/roslyn/pull/41600")] public void DataFlowAnalysisLocalFunctions10() { var dataFlow = CompileAndAnalyzeDataFlowExpression(@" class C { public void M() { bool Dummy(params object[] x) {return true;} try {} catch when (/*<bind>*/TakeOutParam(out var x1)/*</bind>*/ && x1 > 0) { Dummy(x1); } var x4 = 11; Dummy(x4); try {} catch when (TakeOutParam(out var x4) && x4 > 0) { Dummy(x4); } try {} catch when (x6 && TakeOutParam(out var x6)) { Dummy(x6); } try {} catch when (TakeOutParam(out var x7) && x7 > 0) { var x7 = 12; Dummy(x7); } try {} catch when (TakeOutParam(out var x8) && x8 > 0) { Dummy(x8); } System.Console.WriteLine(x8); try {} catch when (TakeOutParam(out var x9) && x9 > 0) { Dummy(x9); try {} catch when (TakeOutParam(out var x9) && x9 > 0) // 2 { Dummy(x9); } } try {} catch when (TakeOutParam(y10, out var x10)) { var y10 = 12; Dummy(y10); } // try {} // catch when (TakeOutParam(y11, out var x11) // { // let y11 = 12; // Dummy(y11); // } try {} catch when (Dummy(TakeOutParam(out var x14), TakeOutParam(out var x14), // 2 x14)) { Dummy(x14); } try {} catch (System.Exception x15) when (Dummy(TakeOutParam(out var x15), x15)) { Dummy(x15); } static bool TakeOutParam(out int x) { x = 123; return true; } static bool TakeOutParam(object y, out int x) { x = 123; return true; } } } "); Assert.True(dataFlow.Succeeded); Assert.Null(GetSymbolNamesJoined(dataFlow.Captured)); Assert.Null(GetSymbolNamesJoined(dataFlow.CapturedInside)); Assert.Null(GetSymbolNamesJoined(dataFlow.CapturedOutside)); Assert.Equal("x1", GetSymbolNamesJoined(dataFlow.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(dataFlow.DataFlowsIn)); Assert.Equal("x1", GetSymbolNamesJoined(dataFlow.DataFlowsOut)); Assert.Equal("this", GetSymbolNamesJoined(dataFlow.DefinitelyAssignedOnEntry)); Assert.Equal("this, x1", GetSymbolNamesJoined(dataFlow.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(dataFlow.ReadInside)); Assert.Equal("x1", GetSymbolNamesJoined(dataFlow.WrittenInside)); Assert.Equal("this, x1, x4, x4, x6, x7, x7, x8, x9, x9, y10, x14, x15, x, x", GetSymbolNamesJoined(dataFlow.ReadOutside)); Assert.Equal("this, x, x4, x4, x6, x7, x7, x8, x9, x9, x10, " + "y10, x14, x14, x15, x15, x, y, x", GetSymbolNamesJoined(dataFlow.WrittenOutside)); } [Fact] [WorkItem(39946, "https://github.com/dotnet/roslyn/issues/39946")] public void DataFlowAnalysisLocalFunctions9() { var results = CompileAndAnalyzeControlAndDataFlowStatements(@" class C { int Testing; void M() { local(); /*<bind>*/ NewMethod(); /*</bind>*/ Testing = 5; void local() { } } void NewMethod() { } }"); var dataFlow = results.dataFlowAnalysis; Assert.True(dataFlow.Succeeded); Assert.Null(GetSymbolNamesJoined(dataFlow.Captured)); Assert.Null(GetSymbolNamesJoined(dataFlow.CapturedInside)); Assert.Null(GetSymbolNamesJoined(dataFlow.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(dataFlow.VariablesDeclared)); Assert.Equal("this", GetSymbolNamesJoined(dataFlow.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlow.DataFlowsOut)); Assert.Equal("this", GetSymbolNamesJoined(dataFlow.DefinitelyAssignedOnEntry)); Assert.Equal("this", GetSymbolNamesJoined(dataFlow.DefinitelyAssignedOnExit)); Assert.Equal("this", GetSymbolNamesJoined(dataFlow.ReadInside)); Assert.Null(GetSymbolNamesJoined(dataFlow.WrittenInside)); Assert.Equal("this", GetSymbolNamesJoined(dataFlow.ReadOutside)); Assert.Equal("this", GetSymbolNamesJoined(dataFlow.WrittenOutside)); var controlFlow = results.controlFlowAnalysis; Assert.True(controlFlow.Succeeded); Assert.True(controlFlow.EndPointIsReachable); } [Fact] [WorkItem(39946, "https://github.com/dotnet/roslyn/issues/39946")] public void ControlFlowAnalysisLocalFunctions01() { var controlFlow = CompileAndAnalyzeControlFlowStatements(@" class C { void M() { local(); /*<bind>*/ System.Console.WriteLine(0); /*</bind>*/ void local() { throw null; } } }"); Assert.True(controlFlow.Succeeded); Assert.False(controlFlow.StartPointIsReachable); Assert.False(controlFlow.EndPointIsReachable); } [Fact] [WorkItem(39946, "https://github.com/dotnet/roslyn/issues/39946")] public void ControlFlowAnalysisLocalFunctions02() { var controlFlow = CompileAndAnalyzeControlFlowStatements(@" class C { void M() { /*<bind>*/ local(); System.Console.WriteLine(0); /*</bind>*/ void local() { throw null; } } }"); Assert.True(controlFlow.Succeeded); Assert.True(controlFlow.StartPointIsReachable); Assert.False(controlFlow.EndPointIsReachable); } [Fact] [WorkItem(39946, "https://github.com/dotnet/roslyn/issues/39946")] public void ControlFlowAnalysisLocalFunctions03() { var controlFlow = CompileAndAnalyzeControlFlowStatements(@" class C { void M() { /*<bind>*/ System.Console.WriteLine(0); /*</bind>*/ local(); void local() { throw null; } } }"); Assert.True(controlFlow.Succeeded); Assert.True(controlFlow.StartPointIsReachable); Assert.True(controlFlow.EndPointIsReachable); } [Fact] [WorkItem(39946, "https://github.com/dotnet/roslyn/issues/39946")] public void ControlFlowAnalysisLocalFunctions04() { var controlFlow = CompileAndAnalyzeControlFlowStatements(@" class C { void M() { System.Console.WriteLine(0); local(); void local() { /*<bind>*/ throw null; /*</bind>*/ } } }"); Assert.True(controlFlow.Succeeded); Assert.True(controlFlow.StartPointIsReachable); Assert.False(controlFlow.EndPointIsReachable); } [Fact] [WorkItem(39946, "https://github.com/dotnet/roslyn/issues/39946")] public void ControlFlowAnalysisLocalFunctions05() { var controlFlow = CompileAndAnalyzeControlFlowStatements(@" class C { void M() { local(); void local() { /*<bind>*/ System.Console.WriteLine(0); /*</bind>*/ throw null; } } }"); Assert.True(controlFlow.Succeeded); Assert.True(controlFlow.StartPointIsReachable); Assert.True(controlFlow.EndPointIsReachable); } [Fact] [WorkItem(39946, "https://github.com/dotnet/roslyn/issues/39946")] public void ControlFlowAnalysisLocalFunctions06() { var controlFlow = CompileAndAnalyzeControlFlowStatements(@" class C { void M() { void local() { throw null; } /*<bind>*/ System.Console.WriteLine(0); /*</bind>*/ } }"); Assert.True(controlFlow.Succeeded); Assert.True(controlFlow.StartPointIsReachable); Assert.True(controlFlow.EndPointIsReachable); } [Fact] public void TestReturnStatements03() { var analysis = CompileAndAnalyzeControlFlowStatements(@" using System; class C { public void F(int x) { if (x == 0) return; /*<bind>*/ if (x == 1) return; Func<int,int> f = (int i) => { return i+1; }; if (x == 2) return; /*</bind>*/ } }"); Assert.Equal(2, analysis.ExitPoints.Count()); } [Fact] public void TestReturnStatements04() { var analysis = CompileAndAnalyzeControlFlowStatements(@" using System; class C { public void F(int x) { if (x == 0) return; if (x == 1) return; Func<int,int> f = (int i) => { /*<bind>*/ return i+1; /*</bind>*/ } ; if (x == 2) return; } }"); Assert.Equal(1, analysis.ExitPoints.Count()); } [Fact] public void TestReturnStatements05() { var analysis = CompileAndAnalyzeControlFlowStatements(@" using System; class C { public void F(int x) { if (x == 0) return; if (x == 1) return; /*<bind>*/ Func<int,int?> f = (int i) => { return i == 1 ? i+1 : null; } ; /*</bind>*/ if (x == 2) return; } }"); Assert.True(analysis.Succeeded); Assert.Empty(analysis.ReturnStatements); } [Fact] public void TestReturnStatements06() { var analysis = CompileAndAnalyzeControlFlowStatements(@" using System; class C { public void F(uint? x) { if (x == null) return; if (x.Value == 1) return; /*<bind>*/ Func<uint?, ulong?> f = (i) => { return i.Value +1; } ; if (x.Value == 2) return; /*</bind>*/ } }"); Assert.True(analysis.Succeeded); Assert.Equal(1, analysis.ExitPoints.Count()); } [WorkItem(541198, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/541198")] [Fact] public void TestReturnStatements07() { var analysis = CompileAndAnalyzeControlFlowStatements(@" using System; class C { public int F(int x) { Func<int,int> f = (int i) => { goto XXX; /*<bind>*/ return 1; /*</bind>*/ } ; } }"); Assert.Equal(1, analysis.ExitPoints.Count()); } [Fact] public void TestMultipleLambdaExpressions() { var analysis = CompileAndAnalyzeDataFlowExpression(@" class C { void M() { int i; N(/*<bind>*/() => { M(); }/*</bind>*/, () => { i++; }); } void N(System.Action x, System.Action y) { } }"); Assert.True(analysis.Succeeded); Assert.Equal("this, i", GetSymbolNamesJoined(analysis.Captured)); Assert.Equal("this", GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Equal("i", GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Equal("this", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("this", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); } [Fact, WorkItem(53591, "https://github.com/dotnet/roslyn/issues/53591")] public void TestNameOfInLambda() { var analysis = CompileAndAnalyzeDataFlowExpression(@" class C { void M() { Func<string> x = /*<bind>*/() => nameof(ClosureCreated)/*</bind>*/; } }"); Assert.True(analysis.Succeeded); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); } [Fact, WorkItem(53591, "https://github.com/dotnet/roslyn/issues/53591")] public void TestNameOfWithAssignmentInLambda() { var analysis = CompileAndAnalyzeDataFlowExpression(@" class C { void M() { Func<string> x = /*<bind>*/() => nameof(this = null)/*</bind>*/; } }"); Assert.True(analysis.Succeeded); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); } [Fact, WorkItem(53591, "https://github.com/dotnet/roslyn/issues/53591")] public void TestUnreachableThisInLambda() { var analysis = CompileAndAnalyzeDataFlowExpression(@" class C { void M() { Func<string> x = /*<bind>*/() => false ? this.ToString() : string.Empty/*</bind>*/; } }"); Assert.True(analysis.Succeeded); Assert.Equal("this", GetSymbolNamesJoined(analysis.Captured)); Assert.Equal("this", GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); } [Fact] public void TestReturnFromLambda() { var analysisResults = CompileAndAnalyzeControlAndDataFlowStatements(@" using System; using System.Linq; class Program { static void Main(string[] args) { int i = 1; Func<int> lambda = () => { /*<bind>*/return i;/*</bind>*/ }; } } "); var controlFlowAnalysisResults = analysisResults.Item1; var dataFlowAnalysisResults = analysisResults.Item2; Assert.Equal(0, controlFlowAnalysisResults.EntryPoints.Count()); Assert.Equal(1, controlFlowAnalysisResults.ExitPoints.Count()); Assert.False(controlFlowAnalysisResults.EndPointIsReachable); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Equal("i", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("args, i", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("args, i", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Equal("i", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("args, i, lambda", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [Fact] public void DataFlowsOutLambda01() { var analysisResults = CompileAndAnalyzeControlAndDataFlowStatements(@" using System; delegate void D(); class Program { static void Main(string[] args) { int i = 12; D d = () => { /*<bind>*/ i = 14; return; /*</bind>*/ }; int j = i; } } "); //var controlFlowAnalysisResults = analysisResults.Item1; var dataFlowAnalysisResults = analysisResults.Item2; Assert.Equal("i", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("args, i", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("args, i", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); } [Fact] public void DataFlowsOutLambda02() { var analysisResults = CompileAndAnalyzeControlAndDataFlowStatements(@" using System; delegate void D(); class Program { static void Main() { int? i = 12; D d = () => { /*<bind>*/ i = 14; /*</bind>*/ return; }; int j = i.Value; } } "); //var controlFlowAnalysisResults = analysisResults.Item1; var dataFlowAnalysisResults = analysisResults.Item2; Assert.Equal("i", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("i", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("i", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); } [Fact] public void DataFlowsOutLambda03() { var analysisResults = CompileAndAnalyzeControlAndDataFlowStatements(@" using System; delegate void D(); class Program { static void Main(string[] args) { int i = 12; D d = () => { /*<bind>*/ i = 14; /*</bind>*/ }; int j = i; } } "); //var controlFlowAnalysisResults = analysisResults.Item1; var dataFlowAnalysisResults = analysisResults.Item2; Assert.Equal("i", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("args, i", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("args, i", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); } [WorkItem(538984, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538984")] [Fact] public void TestReadInside02() { var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowExpression(@" class A { void Method() { System.Func<int, int> a = x => /*<bind>*/x * x/*</bind>*/; } }"); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("this, x", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("this, x", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("this, a, x", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [Fact] public void TestCaptured02() { var analysis = CompileAndAnalyzeDataFlowStatements(@" using System; class C { int field = 123; public void F(int x) { const int a = 1, y = 1; /*<bind>*/ Func<int> lambda = () => x + y + field; /*</bind>*/ int c = a + 4 + y; } }"); Assert.Equal("this, x", GetSymbolNamesJoined(analysis.Captured)); Assert.Equal("this, x", GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Equal("this, x, y", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Equal("this, x, a, y", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("this, x, a, y, lambda", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); } [Fact, WorkItem(539648, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539648"), WorkItem(529185, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/529185")] public void ReturnsInsideLambda() { var analysisResults = CompileAndAnalyzeControlAndDataFlowStatements(@" using System; class Program { delegate R Func<T, R>(T t); static void Main(string[] args) { /*<bind>*/ Func<int, int> f = (arg) => { int s = 3; return s; }; /*</bind>*/ f.Invoke(2); } }"); var controlFlowAnalysisResults = analysisResults.Item1; var dataFlowAnalysisResults = analysisResults.Item2; Assert.Empty(controlFlowAnalysisResults.ReturnStatements); Assert.Equal("f", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("args", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("args, f", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Equal("f, arg, s", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); } [WorkItem(539861, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539861")] [Fact] public void VariableDeclaredLambda01() { var analysisResults = CompileAndAnalyzeControlAndDataFlowStatements(@" using System; class Program { delegate void TestDelegate(ref int x); static void Main(string[] args) { /*<bind>*/ TestDelegate testDel = (ref int x) => { }; /*</bind>*/ int p = 2; testDel(ref p); Console.WriteLine(p); } } "); //var controlFlowAnalysisResults = analysisResults.Item1; var dataFlowAnalysisResults = analysisResults.Item2; Assert.Equal("args", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("args, testDel", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Equal("testDel, x", GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Equal("testDel, x", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); } [WorkItem(539861, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539861")] [Fact] public void VariableDeclaredLambda02() { var results1 = CompileAndAnalyzeDataFlowStatements(@" using System; class Program { delegate void TestDelegate(ref int? x); static void Main() { /*<bind>*/ TestDelegate testDel = (ref int? x) => { int y = x; x.Value = 10; }; /*</bind>*/ int? p = 2; testDel(ref p); Console.WriteLine(p); } } "); Assert.Equal("testDel, x, y", GetSymbolNamesJoined(results1.VariablesDeclared)); Assert.Equal("testDel", GetSymbolNamesJoined(results1.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(results1.Captured)); Assert.Null(GetSymbolNamesJoined(results1.CapturedInside)); Assert.Null(GetSymbolNamesJoined(results1.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(results1.DataFlowsIn)); Assert.Equal("testDel", GetSymbolNamesJoined(results1.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(results1.DefinitelyAssignedOnEntry)); Assert.Equal("testDel", GetSymbolNamesJoined(results1.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(results1.ReadInside)); Assert.Equal("testDel, p", GetSymbolNamesJoined(results1.ReadOutside)); Assert.Equal("testDel, x, y", GetSymbolNamesJoined(results1.WrittenInside)); Assert.Equal("p", GetSymbolNamesJoined(results1.WrittenOutside)); } [WorkItem(540449, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540449")] [Fact] public void AnalysisInsideLambdas() { var results1 = CompileAndAnalyzeDataFlowExpression(@" using System; class C { static void Main() { Func<int, int> f = p => { int x = 1; int y = 1; return /*<bind>*/1 + (x=2) + p + y/*</bind>*/; }; } } "); Assert.Equal("x", GetSymbolNamesJoined(results1.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(results1.Captured)); Assert.Null(GetSymbolNamesJoined(results1.CapturedInside)); Assert.Null(GetSymbolNamesJoined(results1.CapturedOutside)); Assert.Equal("p, y", GetSymbolNamesJoined(results1.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(results1.DataFlowsOut)); Assert.Equal("p, x, y", GetSymbolNamesJoined(results1.DefinitelyAssignedOnEntry)); Assert.Equal("p, x, y", GetSymbolNamesJoined(results1.DefinitelyAssignedOnExit)); Assert.Equal("p, y", GetSymbolNamesJoined(results1.ReadInside)); Assert.Null(GetSymbolNamesJoined(results1.ReadOutside)); Assert.Equal("x", GetSymbolNamesJoined(results1.WrittenInside)); Assert.Equal("f, p, x, y", GetSymbolNamesJoined(results1.WrittenOutside)); } [WorkItem(528622, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/528622")] [Fact] public void AlwaysAssignedParameterLambda() { var dataFlows = CompileAndAnalyzeDataFlowExpression(@" using System; internal class Test { void M(sbyte[] ary) { /*<bind>*/ ( (Action<short>)(x => { Console.Write(x); }) )(ary[0])/*</bind>*/; } } "); Assert.Null(GetSymbolNamesJoined(dataFlows.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(dataFlows.Captured)); Assert.Equal("ary", GetSymbolNamesJoined(dataFlows.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlows.DataFlowsOut)); Assert.Equal("this, ary", GetSymbolNamesJoined(dataFlows.DefinitelyAssignedOnEntry)); Assert.Equal("this, ary", GetSymbolNamesJoined(dataFlows.DefinitelyAssignedOnExit)); Assert.Equal("ary, x", GetSymbolNamesJoined(dataFlows.ReadInside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlows.WrittenInside)); Assert.Null(GetSymbolNamesJoined(dataFlows.ReadOutside)); Assert.Equal("this, ary", GetSymbolNamesJoined(dataFlows.WrittenOutside)); } [WorkItem(541946, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/541946")] [Fact] public void LambdaInTernaryWithEmptyBody() { var results = CompileAndAnalyzeControlAndDataFlowStatements(@" using System; public delegate void D(); public class A { void M() { int i = 0; /*<bind>*/ D d = true ? (D)delegate { i++; } : delegate { }; /*</bind>*/ } } "); var ctrlFlows = results.Item1; var dataFlows = results.Item2; Assert.True(ctrlFlows.EndPointIsReachable); Assert.Equal("d", GetSymbolNamesJoined(dataFlows.VariablesDeclared)); Assert.Equal("d", GetSymbolNamesJoined(dataFlows.AlwaysAssigned)); Assert.Equal("i", GetSymbolNamesJoined(dataFlows.Captured)); Assert.Equal("i", GetSymbolNamesJoined(dataFlows.CapturedInside)); Assert.Null(GetSymbolNamesJoined(dataFlows.CapturedOutside)); Assert.Equal("i", GetSymbolNamesJoined(dataFlows.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlows.DataFlowsOut)); Assert.Equal("this, i", GetSymbolNamesJoined(dataFlows.DefinitelyAssignedOnEntry)); Assert.Equal("this, i, d", GetSymbolNamesJoined(dataFlows.DefinitelyAssignedOnExit)); Assert.Equal("i", GetSymbolNamesJoined(dataFlows.ReadInside)); Assert.Equal("i, d", GetSymbolNamesJoined(dataFlows.WrittenInside)); Assert.Null(GetSymbolNamesJoined(dataFlows.ReadOutside)); Assert.Equal("this, i", GetSymbolNamesJoined(dataFlows.WrittenOutside)); } [Fact] public void ForEachVariableInLambda() { var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowExpression(@" using System; class Program { static void Main() { var nums = new int?[] { 4, 5 }; foreach (var num in /*<bind>*/nums/*</bind>*/) { Func<int, int> f = x => x + num.Value; Console.WriteLine(f(0)); } } }"); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Equal("num", GetSymbolNamesJoined(dataFlowAnalysisResults.Captured)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedInside)); Assert.Equal("num", GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedOutside)); Assert.Equal("nums", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("nums", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("nums", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Equal("nums", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Equal("num, f, x", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("nums, num, f, x", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [WorkItem(543398, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543398")] [Fact] public void LambdaBlockSyntax() { var source = @" using System; class c1 { void M() { var a = 0; foreach(var l in """") { Console.WriteLine(l); a = (int) l; l = (char) a; } Func<int> f = ()=> { var c = a; a = c; return 0; }; var b = 0; Console.WriteLine(b); } }"; var tree = SyntaxFactory.ParseSyntaxTree(source); var comp = CSharpCompilation.Create("FlowAnalysis", syntaxTrees: new[] { tree }); var model = comp.GetSemanticModel(tree); var methodBlock = tree.GetCompilationUnitRoot().DescendantNodes().OfType<BlockSyntax>().First(); var foreachStatement = methodBlock.DescendantNodes().OfType<ForEachStatementSyntax>().First(); var foreachBlock = foreachStatement.DescendantNodes().OfType<BlockSyntax>().First(); var lambdaExpression = methodBlock.DescendantNodes().OfType<ParenthesizedLambdaExpressionSyntax>().First(); var lambdaBlock = lambdaExpression.DescendantNodes().OfType<BlockSyntax>().First(); var flowAnalysis = model.AnalyzeDataFlow(methodBlock); Assert.Equal(4, flowAnalysis.ReadInside.Count()); Assert.Equal(5, flowAnalysis.WrittenInside.Count()); Assert.Equal(5, flowAnalysis.VariablesDeclared.Count()); flowAnalysis = model.AnalyzeDataFlow(foreachBlock); Assert.Equal(2, flowAnalysis.ReadInside.Count()); Assert.Equal(2, flowAnalysis.WrittenInside.Count()); Assert.Equal(0, flowAnalysis.VariablesDeclared.Count()); flowAnalysis = model.AnalyzeDataFlow(lambdaBlock); Assert.Equal(2, flowAnalysis.ReadInside.Count()); Assert.Equal(2, flowAnalysis.WrittenInside.Count()); Assert.Equal(1, flowAnalysis.VariablesDeclared.Count()); } [Fact] public void StaticLambda_01() { var source = @" using System; class C { static void Main() { int x = 42; Action fn = static () => Console.Write(x); fn(); } } "; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics( // (9,48): error CS8820: A static anonymous function cannot contain a reference to 'x'. // Action fn = static () => Console.Write(x); Diagnostic(ErrorCode.ERR_StaticAnonymousFunctionCannotCaptureVariable, "x").WithArguments("x").WithLocation(9, 48) ); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var root = tree.GetRoot(); var node = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single(); var flowAnalysis = model.AnalyzeDataFlow(node); Assert.Equal("x", GetSymbolNamesJoined(flowAnalysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(flowAnalysis.WrittenInside)); Assert.Null(GetSymbolNamesJoined(flowAnalysis.VariablesDeclared)); } [Fact] public void StaticLambda_02() { var source = @" using System; class C { static void Main() { int x = 42; Action fn = static () => { int y = x; x = 43; Console.Write(y); }; fn(); } } "; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics( // (11,21): error CS8820: A static anonymous function cannot contain a reference to 'x'. // int y = x; Diagnostic(ErrorCode.ERR_StaticAnonymousFunctionCannotCaptureVariable, "x").WithArguments("x").WithLocation(11, 21), // (12,13): error CS8820: A static anonymous function cannot contain a reference to 'x'. // x = 43; Diagnostic(ErrorCode.ERR_StaticAnonymousFunctionCannotCaptureVariable, "x").WithArguments("x").WithLocation(12, 13) ); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var root = tree.GetRoot(); var node = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single(); var flowAnalysis = model.AnalyzeDataFlow(node); Assert.Equal("x, y", GetSymbolNamesJoined(flowAnalysis.ReadInside)); Assert.Equal("x, y", GetSymbolNamesJoined(flowAnalysis.WrittenInside)); Assert.Equal("y", GetSymbolNamesJoined(flowAnalysis.VariablesDeclared)); } [Fact] public void StaticLambda_03() { var source = @" using System; class C { public static int x = 42; static void Main() { Action fn = static () => { int y = x; x = 43; Console.Write(y); }; fn(); } } "; verify(source); verify(source.Replace("static (", "(")); void verify(string source) { var verifier = CompileAndVerify(source, parseOptions: TestOptions.Regular9, expectedOutput: "42"); verifier.VerifyDiagnostics(); var comp = verifier.Compilation; var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var root = tree.GetRoot(); var node = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single(); var flowAnalysis = model.AnalyzeDataFlow(node); Assert.Equal("y", GetSymbolNamesJoined(flowAnalysis.ReadInside)); Assert.Equal("y", GetSymbolNamesJoined(flowAnalysis.WrittenInside)); Assert.Equal("y", GetSymbolNamesJoined(flowAnalysis.VariablesDeclared)); } } #endregion #region "query expressions" [Fact] public void QueryExpression01() { var analysisResults = CompileAndAnalyzeControlAndDataFlowStatements(@" using System; using System.Linq; class Program { static void Main() { var nums = new int[] { 1, 2, 3, 4 }; /*<bind>*/ var q2 = from x in nums where (x > 2) where x > 3 select x; /*</bind>*/ } }"); var dataFlowAnalysisResults = analysisResults.Item2; Assert.Equal("q2, x", GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Equal("q2", GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Equal("nums", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("nums", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("nums, q2", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Equal("nums, x", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Equal("q2, x", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("nums", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [Fact] public void QueryExpression02() { var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowExpression(@" using System; using System.Linq; class Program { static void Main() { var nums = new sbyte[] { 1, 2, 3, 4 }; var q2 = from x in nums where (x > 2) select /*<bind>*/ x+1 /*</bind>*/; } }"); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("nums", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("nums", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Equal("nums, x", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("nums, q2, x", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [Fact] public void QueryExpression03() { var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowExpression(@" using System; using System.Linq; class Program { static void Main() { var nums = new int?[] { 1, 2, null, 4 }; var q2 = from x in nums group x.Value + 1 by /*<bind>*/ x.Value % 2 /*</bind>*/; } }"); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("nums", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("nums", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Equal("nums, x", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("nums, q2, x", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [Fact] public void QueryExpression04() { var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowExpression(@" using System; using System.Linq; class Program { static void Main() { var nums = new uint[] { 1, 2, 3, 4 }; var q2 = from int x in nums where x < 3 select /*<bind>*/ x /*</bind>*/; } }"); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("nums", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("nums", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Equal("nums, x", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("nums, q2, x", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [Fact] public void QueryExpression05() { var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowExpression(@" using System; using System.Linq; class Program { static void Main() { var nums = new sbyte[] { 1, 2, 3, 4 }; var q2 = from int x in nums where x < 3 group /*<bind>*/ x /*</bind>*/ by x%2; } }"); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("nums", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("nums", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Equal("nums, x", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("nums, q2, x", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [WorkItem(541916, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/541916")] [Fact] public void ForEachVariableInQueryExpr() { var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowExpression(@" using System; using System.Linq; class Program { static void Main() { var nums = new int[] { 4, 5 }; foreach (var num in nums) { var q = from n in /*<bind>*/ nums /*</bind>*/ select num; } } }"); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Equal("num", GetSymbolNamesJoined(dataFlowAnalysisResults.Captured)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedInside)); Assert.Equal("num", GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedOutside)); Assert.Equal("nums", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("nums, num", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("nums, num", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Equal("nums", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Equal("nums, num", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("nums, num, q, n", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [WorkItem(541945, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/541945")] [Fact] public void ForVariableInQueryExpr() { var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowExpression(@" using System; using System.Linq; class Program { static void Main() { var nums = new int[] { 4, 5 }; for (int num = 0; num < 10; num++) { var q = from n in /*<bind>*/ nums /*</bind>*/ select num; } } }"); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Equal("num", GetSymbolNamesJoined(dataFlowAnalysisResults.Captured)); Assert.Equal("nums", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("nums, num", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("nums, num", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Equal("nums", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Equal("num", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("nums, num, q, n", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [WorkItem(541926, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/541926")] [Fact] public void Bug8863() { var analysisResults = CompileAndAnalyzeControlAndDataFlowStatements(@" using System.Linq; class C { static void Main(string[] args) { /*<bind>*/ var temp = from x in ""abc"" let z = x.ToString() select z into w select w; /*</bind>*/ } }"); var dataFlowAnalysisResults = analysisResults.Item2; Assert.Equal("temp, x, z, w", GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Equal("temp", GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.Captured)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("args", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("args, temp", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Equal("x, z, w", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Equal("temp, x, z, w", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("args", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [Fact] public void Bug9415() { var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowExpression(@" using System; using System.Collections.Generic; using System.Linq; class Program { static void Main(string[] args) { var q1 = from x in new int[] { /*<bind>*/4/*</bind>*/, 5 } orderby x select x; } }"); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.Captured)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("args", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("args", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("args, q1, x", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [WorkItem(543546, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543546")] [Fact] public void GroupByClause() { var analysisResults = CompileAndAnalyzeDataFlowExpression(@" using System.Linq; public class Test { public static void Main() { var strings = new string[] { }; var q = from s in strings select s into t /*<bind>*/group t by t.Length/*</bind>*/; } }"); var dataFlowAnalysisResults = analysisResults; Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); } [WorkItem(1291, "https://github.com/dotnet/roslyn/issues/1291")] [Fact] public void CaptureInQuery() { var analysisResults = CompileAndAnalyzeDataFlowExpression(@" using System.Linq; public class Test { public static void Main(int[] data) { int y = 1; { int x = 2; var f2 = from a in data select a + y; var f3 = from a in data where x > 0 select a; var f4 = from a in data let b = 1 where /*<bind>*/M(() => b)/*</bind>*/ select a + b; var f5 = from c in data where M(() => c) select c; } } private static bool M(Func<int> f) => true; }"); var dataFlowAnalysisResults = analysisResults; Assert.Equal("y, x, b", GetSymbolNamesJoined(dataFlowAnalysisResults.Captured)); Assert.Equal("b", GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedInside)); Assert.Equal("y, x", GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedOutside)); } #endregion query expressions #region "switch statement tests" [Fact] public void LocalInOtherSwitchCase() { var dataFlows = CompileAndAnalyzeDataFlowExpression( @"using System; using System.Linq; public class Test { public static void Main() { int ret = 6; switch (ret) { case 1: int i = 10; break; case 2: var q1 = from j in new int[] { 3, 4 } select /*<bind>*/i/*</bind>*/; break; } } }"); Assert.Empty(dataFlows.DataFlowsOut); } [WorkItem(541639, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/541639")] [Fact] public void VariableDeclInsideSwitchCaptureInLambdaExpr() { var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowExpression(@" using System; class C { public static void Main() { switch (10) { default: int i = 10; Func<int> f1 = () => /*<bind>*/i/*</bind>*/; break; } } } "); Assert.Equal("i", GetSymbolNamesJoined(dataFlowAnalysisResults.Captured)); Assert.Equal("i", GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Equal("i", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("i", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("i", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Equal("i", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("i, f1", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [WorkItem(541710, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/541710")] [Fact] public void ArrayCreationExprInForEachInsideSwitchSection() { var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowExpression(@" class Program { static void Main() { switch ('2') { default: break; case '2': foreach (var i100 in new int[] {4, /*<bind>*/5/*</bind>*/ }) { } break; } } } "); Assert.Empty(dataFlowAnalysisResults.Captured); Assert.Empty(dataFlowAnalysisResults.CapturedInside); Assert.Empty(dataFlowAnalysisResults.CapturedOutside); Assert.Empty(dataFlowAnalysisResults.VariablesDeclared); Assert.Empty(dataFlowAnalysisResults.AlwaysAssigned); Assert.Empty(dataFlowAnalysisResults.DataFlowsIn); Assert.Empty(dataFlowAnalysisResults.DataFlowsOut); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Empty(dataFlowAnalysisResults.ReadInside); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Empty(dataFlowAnalysisResults.WrittenInside); Assert.Equal("i100", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [Fact] public void RegionInsideSwitchExpression() { var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowExpression(@" class Program { static void Main() { switch ('2') { default: break; case '2': switch (/*<bind>*/'2'/*</bind>*/) { case '2': break; } break; } } } "); Assert.Empty(dataFlowAnalysisResults.Captured); Assert.Empty(dataFlowAnalysisResults.CapturedInside); Assert.Empty(dataFlowAnalysisResults.CapturedOutside); Assert.Empty(dataFlowAnalysisResults.VariablesDeclared); Assert.Empty(dataFlowAnalysisResults.AlwaysAssigned); Assert.Empty(dataFlowAnalysisResults.DataFlowsIn); Assert.Empty(dataFlowAnalysisResults.DataFlowsOut); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Empty(dataFlowAnalysisResults.ReadInside); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Empty(dataFlowAnalysisResults.WrittenInside); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [Fact] public void NullableAsSwitchExpression() { var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowStatements(@" using System; class C { public void F(ulong? p) { /*<bind>*/ switch (p) { case null: break; case 1: goto case null; default: break; } /*</bind>*/ } } "); Assert.Empty(dataFlowAnalysisResults.Captured); Assert.Empty(dataFlowAnalysisResults.CapturedInside); Assert.Empty(dataFlowAnalysisResults.CapturedOutside); Assert.Empty(dataFlowAnalysisResults.VariablesDeclared); Assert.Empty(dataFlowAnalysisResults.AlwaysAssigned); Assert.Equal("p", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Empty(dataFlowAnalysisResults.DataFlowsOut); Assert.Equal("this, p", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("this, p", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Equal("p", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Empty(dataFlowAnalysisResults.WrittenInside); Assert.Equal("this, p", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [Fact] [WorkItem(17281, "https://github.com/dotnet/roslyn/issues/17281")] public void DiscardVsVariablesDeclared() { var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowStatements(@" class A { } class Test { private void Repro(A node) { /*<bind>*/ switch (node) { case A _: break; case Unknown: break; default: return; } /*</bind>*/ } }"); Assert.Empty(dataFlowAnalysisResults.Captured); Assert.Empty(dataFlowAnalysisResults.CapturedInside); Assert.Empty(dataFlowAnalysisResults.CapturedOutside); Assert.Empty(dataFlowAnalysisResults.VariablesDeclared); Assert.Empty(dataFlowAnalysisResults.AlwaysAssigned); Assert.Equal("node", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Empty(dataFlowAnalysisResults.DataFlowsOut); Assert.Equal("this, node", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("this, node", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Equal("node", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Empty(dataFlowAnalysisResults.WrittenInside); Assert.Equal("this, node", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } #endregion #region "Misc." [Fact, WorkItem(11298, "DevDiv_Projects/Roslyn")] public void BaseExpressionSyntax() { var source = @" using System; public class BaseClass { public virtual void MyMeth() { } } public class MyClass : BaseClass { public override void MyMeth() { base.MyMeth(); } delegate BaseClass D(); public void OtherMeth() { D f = () => base; } public static void Main() { } }"; var comp = CreateCompilation(source); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var invocation = tree.GetCompilationUnitRoot().DescendantNodes().OfType<InvocationExpressionSyntax>().Single(); var flowAnalysis = model.AnalyzeDataFlow(invocation); Assert.Empty(flowAnalysis.Captured); Assert.Empty(flowAnalysis.CapturedInside); Assert.Empty(flowAnalysis.CapturedOutside); Assert.Equal("MyClass this", flowAnalysis.DataFlowsIn.Single().ToTestDisplayString()); Assert.Empty(flowAnalysis.DataFlowsOut); Assert.Equal("MyClass this", flowAnalysis.ReadInside.Single().ToTestDisplayString()); Assert.Empty(flowAnalysis.WrittenInside); Assert.Equal("MyClass this", flowAnalysis.WrittenOutside.Single().ToTestDisplayString()); var lambda = tree.GetCompilationUnitRoot().DescendantNodes().OfType<ParenthesizedLambdaExpressionSyntax>().Single(); flowAnalysis = model.AnalyzeDataFlow(lambda); Assert.Equal("MyClass this", flowAnalysis.Captured.Single().ToTestDisplayString()); Assert.Equal("MyClass this", flowAnalysis.DataFlowsIn.Single().ToTestDisplayString()); Assert.Empty(flowAnalysis.DataFlowsOut); Assert.Equal("MyClass this", flowAnalysis.ReadInside.Single().ToTestDisplayString()); Assert.Empty(flowAnalysis.WrittenInside); Assert.Equal("this, f", GetSymbolNamesJoined(flowAnalysis.WrittenOutside)); } [WorkItem(543101, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543101")] [Fact] public void AnalysisInsideBaseClause() { var analysisResults = CompileAndAnalyzeDataFlowExpression(@" class A { A(int x) : this(/*<bind>*/x.ToString()/*</bind>*/) { } A(string x) { } } "); var dataFlowAnalysisResults = analysisResults; Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.Captured)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedOutside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("this, x", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("this, x", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("this, x", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [WorkItem(543758, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543758")] [Fact] public void BlockSyntaxOfALambdaInAttributeArg() { var controlFlowAnalysisResults = CompileAndAnalyzeControlFlowStatements(@" class Test { [Attrib(() => /*<bind>*/{ }/*</bind>*/)] public static void Main() { } } "); Assert.False(controlFlowAnalysisResults.Succeeded); } [WorkItem(529196, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/529196")] [Fact()] public void DefaultValueOfOptionalParam() { var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowExpression(@" public class Derived { public void Goo(int x = /*<bind>*/ 2 /*</bind>*/) { } } "); Assert.True(dataFlowAnalysisResults.Succeeded); } [Fact] public void GenericStructureCycle() { var source = @"struct S<T> { public S<S<T>> F; } class C { static void M() { S<object> o; } }"; var compilation = CreateEmptyCompilation(source); var tree = compilation.SyntaxTrees[0]; var model = compilation.GetSemanticModel(tree); var root = tree.GetCompilationUnitRoot(); var statement = GetFirstNode<StatementSyntax>(tree, root.ToFullString().IndexOf("S<object> o", StringComparison.Ordinal)); var analysis = model.AnalyzeDataFlow(statement); Assert.True(analysis.Succeeded); Assert.Equal("o", GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Null(GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(analysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenOutside)); } [WorkItem(545372, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545372")] [Fact] public void AnalysisInSyntaxError01() { var source = @"using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; class Program { static void Main(string[] args) { Expression<Func<int>> f3 = () => if (args == null) {}; } }"; var compilation = CreateEmptyCompilation(source); var tree = compilation.SyntaxTrees[0]; var model = compilation.GetSemanticModel(tree); var root = tree.GetCompilationUnitRoot(); var statement = GetLastNode<StatementSyntax>(tree, root.ToFullString().IndexOf("if", StringComparison.Ordinal)); Assert.Equal("if (args == null) {}", statement.ToFullString()); var analysis = model.AnalyzeDataFlow(statement); Assert.True(analysis.Succeeded); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("args, f3", GetSymbolNamesJoined(analysis.WrittenOutside)); } [WorkItem(546964, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546964")] [Fact] public void AnalysisWithMissingMember() { var source = @"class C { void Goo(string[] args) { foreach (var s in args) { this.EditorOperations = 1; } } }"; var compilation = CreateEmptyCompilation(source); var tree = compilation.SyntaxTrees[0]; var model = compilation.GetSemanticModel(tree); var root = tree.GetCompilationUnitRoot(); var statement = GetLastNode<StatementSyntax>(tree, root.ToFullString().IndexOf("EditorOperations", StringComparison.Ordinal)); Assert.Equal("this.EditorOperations = 1;", statement.ToString()); var analysis = model.AnalyzeDataFlow(statement); Assert.True(analysis.Succeeded); var v = analysis.DataFlowsOut; } [Fact, WorkItem(547059, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/547059")] public void ObjectInitIncompleteCodeInQuery() { var source = @" using System.Collections.Generic; using System.Linq; class Program { static void Main() { var symlist = new List<ISymbol>(); var expList = from s in symlist select new ExportedSymbol() { S } } public interface ISymbol { } public class ExportedSymbol { public ISymbol Symbol; public byte UseBits; } "; var compilation = CreateEmptyCompilation(source); var tree = compilation.SyntaxTrees[0]; var model = compilation.GetSemanticModel(tree); var statement = tree.GetCompilationUnitRoot().DescendantNodes().OfType<BlockSyntax>().FirstOrDefault(); var expectedtext = @" { var symlist = new List<ISymbol>(); var expList = from s in symlist select new ExportedSymbol() { S } } "; Assert.Equal(expectedtext, statement.ToFullString()); var analysis = model.AnalyzeDataFlow(statement); Assert.True(analysis.Succeeded); } [Fact] public void StaticSetterAssignedInCtor() { var source = @"class C { C() { P = new object(); } static object P { get; set; } }"; var compilation = CreateCompilation(source); var tree = compilation.SyntaxTrees[0]; var model = compilation.GetSemanticModel(tree); var root = tree.GetCompilationUnitRoot(); var statement = GetFirstNode<StatementSyntax>(tree, root.ToFullString().IndexOf("P = new object()", StringComparison.Ordinal)); var analysis = model.AnalyzeDataFlow(statement); Assert.True(analysis.Succeeded); } [Fact] public void FieldBeforeAssignedInStructCtor() { var source = @"struct S { object value; S(object x) { S.Equals(value , value); this.value = null; } }"; var compilation = CreateCompilation(source, parseOptions: TestOptions.Regular10); compilation.VerifyDiagnostics( // (6,18): error CS9015: Use of possibly unassigned field 'value'. Consider updating to language version '11.0' to auto-default the field. // S.Equals(value , value); Diagnostic(ErrorCode.ERR_UseDefViolationFieldUnsupportedVersion, "value").WithArguments("value", "11.0").WithLocation(6, 18) ); verify(); compilation = CreateCompilation(source, parseOptions: TestOptions.Regular11); compilation.VerifyDiagnostics(); verify(); void verify() { var tree = compilation.SyntaxTrees[0]; var model = compilation.GetSemanticModel(tree); var root = tree.GetRoot(); var expression = GetLastNode<ExpressionSyntax>(tree, root.ToFullString().IndexOf("value ", StringComparison.Ordinal)); var analysis = model.AnalyzeDataFlow(expression); Assert.True(analysis.Succeeded); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); } } [Fact, WorkItem(14110, "https://github.com/dotnet/roslyn/issues/14110")] public void Test14110() { var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowStatements(@" class Program { static void Main() { var (a0, b0) = (1, 2); (var c0, int d0) = (3, 4); bool e0 = a0 is int f0; bool g0 = a0 is var h0; M(out int i0); M(out var j0); /*<bind>*/ var (a, b) = (1, 2); (var c, int d) = (3, 4); bool e = a is int f; bool g = a is var h; M(out int i); M(out var j); /*</bind>*/ var (a1, b1) = (1, 2); (var c1, int d1) = (3, 4); bool e1 = a1 is int f1; bool g1 = a1 is var h1; M(out int i1); M(out var j1); } static void M(out int z) => throw null; } "); Assert.Equal("a, b, c, d, e, f, g, h, i, j", GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); } [Fact, WorkItem(15640, "https://github.com/dotnet/roslyn/issues/15640")] public void Test15640() { var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowStatements(@" using System; class Programand { static void Main() { foreach (var (a0, b0) in new[] { (1, 2) }) {} /*<bind>*/ foreach (var (a, b) in new[] { (1, 2) }) {} /*</bind>*/ foreach (var (a1, b1) in new[] { (1, 2) }) {} } } "); Assert.Equal("a, b", GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); } [Fact] public void RegionAnalysisLocalFunctions() { var results = CompileAndAnalyzeDataFlowStatements(@" using System; class C { static void Main() { /*<bind>*/ void Local() { } /*</bind>*/ } }"); Assert.True(results.Succeeded); Assert.Null(GetSymbolNamesJoined(results.Captured)); Assert.Null(GetSymbolNamesJoined(results.CapturedInside)); Assert.Null(GetSymbolNamesJoined(results.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(results.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(results.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(results.DefinitelyAssignedOnEntry)); Assert.Null(GetSymbolNamesJoined(results.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(results.ReadInside)); Assert.Null(GetSymbolNamesJoined(results.WrittenInside)); Assert.Null(GetSymbolNamesJoined(results.ReadOutside)); Assert.Null(GetSymbolNamesJoined(results.WrittenOutside)); } [Fact] public void RegionAnalysisLocalFunctions2() { var results = CompileAndAnalyzeDataFlowStatements(@" using System; class C { static void Main() { void Local() { } /*<bind>*/ Local(); /*</bind>*/ } }"); Assert.True(results.Succeeded); Assert.Null(GetSymbolNamesJoined(results.Captured)); Assert.Null(GetSymbolNamesJoined(results.CapturedInside)); Assert.Null(GetSymbolNamesJoined(results.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(results.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(results.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(results.DefinitelyAssignedOnEntry)); Assert.Null(GetSymbolNamesJoined(results.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(results.ReadInside)); Assert.Null(GetSymbolNamesJoined(results.WrittenInside)); Assert.Null(GetSymbolNamesJoined(results.ReadOutside)); Assert.Null(GetSymbolNamesJoined(results.WrittenOutside)); } [Fact] public void RegionAnalysisLocalFunctions3() { var results = CompileAndAnalyzeDataFlowStatements(@" using System; class C { static void Main() { void Local() { } /*<bind>*/ Action a = Local; /*</bind>*/ } }"); Assert.True(results.Succeeded); Assert.Null(GetSymbolNamesJoined(results.Captured)); Assert.Null(GetSymbolNamesJoined(results.CapturedInside)); Assert.Null(GetSymbolNamesJoined(results.CapturedOutside)); Assert.Equal("a", GetSymbolNamesJoined(results.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(results.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(results.DefinitelyAssignedOnEntry)); Assert.Equal("a", GetSymbolNamesJoined(results.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(results.ReadInside)); Assert.Equal("a", GetSymbolNamesJoined(results.WrittenInside)); Assert.Null(GetSymbolNamesJoined(results.ReadOutside)); Assert.Null(GetSymbolNamesJoined(results.WrittenOutside)); } [Fact] public void RegionAnalysisLocalFunctions4() { var results = CompileAndAnalyzeDataFlowStatements(@" using System; class C { static void Main() { void Local() { } /*<bind>*/ var a = new Action(Local); /*</bind>*/ } }"); Assert.True(results.Succeeded); Assert.Null(GetSymbolNamesJoined(results.Captured)); Assert.Null(GetSymbolNamesJoined(results.CapturedInside)); Assert.Null(GetSymbolNamesJoined(results.CapturedOutside)); Assert.Equal("a", GetSymbolNamesJoined(results.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(results.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(results.DefinitelyAssignedOnEntry)); Assert.Equal("a", GetSymbolNamesJoined(results.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(results.ReadInside)); Assert.Equal("a", GetSymbolNamesJoined(results.WrittenInside)); Assert.Null(GetSymbolNamesJoined(results.ReadOutside)); Assert.Null(GetSymbolNamesJoined(results.WrittenOutside)); } [Fact] public void RegionAnalysisLocalFunctions5() { var results = CompileAndAnalyzeDataFlowStatements(@" class C { static void Main() { void Local() { /*<bind>*/ int x = 0; x++; x = M(x + 1); /*</bind>*/ } Local(); } int M(int i) => i; }"); Assert.True(results.Succeeded); Assert.Null(GetSymbolNamesJoined(results.Captured)); Assert.Null(GetSymbolNamesJoined(results.CapturedInside)); Assert.Null(GetSymbolNamesJoined(results.CapturedOutside)); Assert.Equal("x", GetSymbolNamesJoined(results.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(results.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(results.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(results.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(results.ReadInside)); Assert.Equal("x", GetSymbolNamesJoined(results.WrittenInside)); Assert.Null(GetSymbolNamesJoined(results.ReadOutside)); Assert.Null(GetSymbolNamesJoined(results.WrittenOutside)); } [Fact] public void RegionAnalysisLocalFunctions6() { var results = CompileAndAnalyzeDataFlowStatements(@" class C { static void Main() { var a = new Action(() => { void Local() { /*<bind>*/ int x = 0; x++; x = M(x + 1); /*</bind>*/ } }); a(); } int M(int i) => i; }"); Assert.True(results.Succeeded); Assert.Null(GetSymbolNamesJoined(results.Captured)); Assert.Null(GetSymbolNamesJoined(results.CapturedInside)); Assert.Null(GetSymbolNamesJoined(results.CapturedOutside)); Assert.Equal("x", GetSymbolNamesJoined(results.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(results.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(results.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(results.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(results.ReadInside)); Assert.Equal("x", GetSymbolNamesJoined(results.WrittenInside)); Assert.Equal("a", GetSymbolNamesJoined(results.ReadOutside)); Assert.Equal("a", GetSymbolNamesJoined(results.WrittenOutside)); } [Fact] public void RegionAnalysisLocalFunctions7() { var results = CompileAndAnalyzeDataFlowStatements(@" using System; class C { static void Main() { void Local() { } /*<bind>*/ var a = (Action)Local; /*</bind>*/ } }"); Assert.True(results.Succeeded); Assert.Null(GetSymbolNamesJoined(results.Captured)); Assert.Null(GetSymbolNamesJoined(results.CapturedInside)); Assert.Null(GetSymbolNamesJoined(results.CapturedOutside)); Assert.Equal("a", GetSymbolNamesJoined(results.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(results.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(results.ReadInside)); Assert.Equal("a", GetSymbolNamesJoined(results.WrittenInside)); Assert.Null(GetSymbolNamesJoined(results.ReadOutside)); Assert.Null(GetSymbolNamesJoined(results.WrittenOutside)); } [Fact] public void RegionAnalysisLocalFunctions8() { var results = CompileAndAnalyzeDataFlowStatements(@" class C { static void Main() { int x = 0; void Local() { x++; } Local(); /*<bind>*/ x++; x = M(x + 1); /*</bind>*/ } int M(int i) => i; }"); Assert.True(results.Succeeded); Assert.Equal("x", GetSymbolNamesJoined(results.Captured)); Assert.Null(GetSymbolNamesJoined(results.CapturedInside)); Assert.Equal("x", GetSymbolNamesJoined(results.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(results.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(results.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(results.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(results.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(results.ReadInside)); Assert.Equal("x", GetSymbolNamesJoined(results.WrittenInside)); Assert.Equal("x", GetSymbolNamesJoined(results.ReadOutside)); Assert.Equal("x", GetSymbolNamesJoined(results.WrittenOutside)); } [Fact] public void LocalFuncCapture1() { var results = CompileAndAnalyzeDataFlowStatements(@" public static class SomeClass { private static void Repro( int arg ) { /*<bind>*/int localValue = arg;/*</bind>*/ int LocalCapture() => arg; } }"); Assert.True(results.Succeeded); Assert.Equal("arg", GetSymbolNamesJoined(results.Captured)); Assert.Null(GetSymbolNamesJoined(results.CapturedInside)); Assert.Equal("arg", GetSymbolNamesJoined(results.CapturedOutside)); Assert.Equal("arg", GetSymbolNamesJoined(results.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(results.DataFlowsOut)); Assert.Equal("arg", GetSymbolNamesJoined(results.DefinitelyAssignedOnEntry)); Assert.Equal("arg, localValue", GetSymbolNamesJoined(results.DefinitelyAssignedOnExit)); Assert.Equal("localValue", GetSymbolNamesJoined(results.AlwaysAssigned)); Assert.Equal("arg", GetSymbolNamesJoined(results.ReadInside)); Assert.Equal("arg", GetSymbolNamesJoined(results.ReadOutside)); Assert.Equal("localValue", GetSymbolNamesJoined(results.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(results.UnsafeAddressTaken)); } [Fact] public void LocalFuncCapture2() { var results = CompileAndAnalyzeDataFlowStatements(@" class C { void M() { int x; Local(); /*<bind>*/int y = x;/*</bind>*/ int Local() { x = 0; } } }"); Assert.True(results.Succeeded); Assert.Equal("x", GetSymbolNamesJoined(results.Captured)); Assert.Null(GetSymbolNamesJoined(results.CapturedInside)); Assert.Equal("x", GetSymbolNamesJoined(results.CapturedOutside)); Assert.Equal("x", GetSymbolNamesJoined(results.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(results.DataFlowsOut)); Assert.Equal("this, x", GetSymbolNamesJoined(results.DefinitelyAssignedOnEntry)); Assert.Equal("this, x, y", GetSymbolNamesJoined(results.DefinitelyAssignedOnExit)); Assert.Equal("y", GetSymbolNamesJoined(results.AlwaysAssigned)); Assert.Equal("x", GetSymbolNamesJoined(results.ReadInside)); Assert.Null(GetSymbolNamesJoined(results.ReadOutside)); Assert.Equal("y", GetSymbolNamesJoined(results.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(results.UnsafeAddressTaken)); } [Fact] public void LocalFuncCapture3() { var results = CompileAndAnalyzeDataFlowStatements(@" class C { void M() { int x; /*<bind>*/int y = x;/*</bind>*/ Local(); int Local() => x; } }"); Assert.True(results.Succeeded); Assert.Equal("x", GetSymbolNamesJoined(results.Captured)); Assert.Null(GetSymbolNamesJoined(results.CapturedInside)); Assert.Equal("x", GetSymbolNamesJoined(results.CapturedOutside)); Assert.Equal("x", GetSymbolNamesJoined(results.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(results.DataFlowsOut)); Assert.Equal("this", GetSymbolNamesJoined(results.DefinitelyAssignedOnEntry)); Assert.Equal("this, y", GetSymbolNamesJoined(results.DefinitelyAssignedOnExit)); Assert.Equal("y", GetSymbolNamesJoined(results.AlwaysAssigned)); Assert.Equal("x", GetSymbolNamesJoined(results.ReadInside)); Assert.Equal("x", GetSymbolNamesJoined(results.ReadOutside)); Assert.Equal("y", GetSymbolNamesJoined(results.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(results.UnsafeAddressTaken)); } [Fact] public void LocalFuncCapture4() { var results = CompileAndAnalyzeDataFlowStatements(@" class C { void M() { int x, y = 0; /*<bind>*/x = y;/*</bind>*/ Local(); int Local() => x; } }"); Assert.True(results.Succeeded); Assert.Equal("x", GetSymbolNamesJoined(results.Captured)); Assert.Null(GetSymbolNamesJoined(results.CapturedInside)); Assert.Equal("x", GetSymbolNamesJoined(results.CapturedOutside)); Assert.Equal("y", GetSymbolNamesJoined(results.DataFlowsIn)); Assert.Equal("x", GetSymbolNamesJoined(results.DataFlowsOut)); Assert.Equal("this, y", GetSymbolNamesJoined(results.DefinitelyAssignedOnEntry)); Assert.Equal("this, x, y", GetSymbolNamesJoined(results.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(results.AlwaysAssigned)); Assert.Equal("y", GetSymbolNamesJoined(results.ReadInside)); Assert.Equal("x", GetSymbolNamesJoined(results.ReadOutside)); Assert.Equal("x", GetSymbolNamesJoined(results.WrittenInside)); Assert.Equal("this, y", GetSymbolNamesJoined(results.WrittenOutside)); Assert.Null(GetSymbolNamesJoined(results.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(results.UnsafeAddressTaken)); } [Fact] public void LocalFuncCapture5() { var results = CompileAndAnalyzeDataFlowStatements(@" class C { int x = 0; void M() { /*<bind>*/ int L(int a) => x; /*</bind>*/ L(); } }"); Assert.Equal("this", GetSymbolNamesJoined(results.Captured)); Assert.Equal("this", GetSymbolNamesJoined(results.CapturedInside)); Assert.Null(GetSymbolNamesJoined(results.CapturedOutside)); Assert.Equal("a", GetSymbolNamesJoined(results.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(results.DataFlowsOut)); Assert.Equal("this", GetSymbolNamesJoined(results.DefinitelyAssignedOnEntry)); Assert.Equal("this", GetSymbolNamesJoined(results.DefinitelyAssignedOnExit)); Assert.Equal("this", GetSymbolNamesJoined(results.ReadInside)); Assert.Equal("a", GetSymbolNamesJoined(results.WrittenInside)); Assert.Equal("this", GetSymbolNamesJoined(results.ReadOutside)); Assert.Equal("this", GetSymbolNamesJoined(results.WrittenOutside)); } [Fact] public void LocalFuncCapture6() { var results = CompileAndAnalyzeDataFlowStatements(@" class C { void M(int x) { int y; int z; void Local() { /*<bind>*/ x++; y = 0; y++; /*</bind>*/ } Local(); } }"); Assert.Equal("x, y", GetSymbolNamesJoined(results.Captured)); Assert.Equal("x, y", GetSymbolNamesJoined(results.CapturedInside)); Assert.Null(GetSymbolNamesJoined(results.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(results.VariablesDeclared)); // TODO(https://github.com/dotnet/roslyn/issues/14214): This is wrong. // Both x and y should flow out. Assert.Equal("y", GetSymbolNamesJoined(results.DataFlowsOut)); Assert.Equal("this, x", GetSymbolNamesJoined(results.DefinitelyAssignedOnEntry)); Assert.Equal("this, x, y", GetSymbolNamesJoined(results.DefinitelyAssignedOnExit)); Assert.Equal("x, y", GetSymbolNamesJoined(results.ReadInside)); Assert.Equal("x, y", GetSymbolNamesJoined(results.WrittenInside)); Assert.Null(GetSymbolNamesJoined(results.ReadOutside)); Assert.Equal("this, x", GetSymbolNamesJoined(results.WrittenOutside)); Assert.Equal("x, y", GetSymbolNamesJoined(results.AlwaysAssigned)); } [Fact] public void LocalFuncCapture7() { var results = CompileAndAnalyzeDataFlowStatements(@" class C { void M() { int x; void L() { /*<bind>*/ int y = 0; y++; x = 0; /*</bind>*/ } x++; } }"); Assert.Equal("x", GetSymbolNamesJoined(results.Captured)); Assert.Equal("x", GetSymbolNamesJoined(results.CapturedInside)); Assert.Null(GetSymbolNamesJoined(results.CapturedOutside)); Assert.Equal("y", GetSymbolNamesJoined(results.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(results.DataFlowsOut)); Assert.Equal("this", GetSymbolNamesJoined(results.DefinitelyAssignedOnEntry)); Assert.Equal("this, x, y", GetSymbolNamesJoined(results.DefinitelyAssignedOnExit)); Assert.Equal("y", GetSymbolNamesJoined(results.ReadInside)); Assert.Equal("x, y", GetSymbolNamesJoined(results.WrittenInside)); Assert.Equal("x", GetSymbolNamesJoined(results.ReadOutside)); Assert.Equal("this, x", GetSymbolNamesJoined(results.WrittenOutside)); Assert.Equal("x, y", GetSymbolNamesJoined(results.AlwaysAssigned)); } [Fact, WorkItem(37421, "https://github.com/dotnet/roslyn/issues/37421")] public void LocalFuncCapture8() { var analysis = CompileAndAnalyzeDataFlowStatements(@" class C { int field = 123; void M(int x) { int a = 1, y = 1; int Outside() => x+field; /*<bind>*/ int Inside() => y; /*</bind>*/ } }"); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("this, x, y", GetSymbolNamesJoined(analysis.Captured)); Assert.Equal("y", GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Equal("this, x", GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("this, x, a, y", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("this, x, a, y", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("y", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("this, x", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Equal("this, x, a, y", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Fact, WorkItem(37421, "https://github.com/dotnet/roslyn/issues/37421")] public void LocalFuncCapture9() { var analysis = CompileAndAnalyzeDataFlowStatements(@" class C { int field = 123; void M(int x) { int a = 1, y = 1; int Outside() => x+field; Inside(); /*<bind>*/ int Inside() => y; /*</bind>*/ } }"); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("this, x, y", GetSymbolNamesJoined(analysis.Captured)); Assert.Equal("y", GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Equal("this, x", GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("this, x, a, y", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("this, x, a, y", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("y", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("this, x, y", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Equal("this, x, a, y", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Fact] public void AssignmentInsideLocal01() { var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowStatements(@" class Program { static void Main() { int x = 3, y = 4; void Local() { /*<bind>*/ x = 1; /*</bind>*/ } Local(); System.Console.WriteLine(x); } } "); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("x, y", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.Captured)); } [Fact] public void AssignmentInsideLocal02() { var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowStatements(@" class Program { static void Main() { int x = 3, y = 4; void Local() { /*<bind>*/ if ("""".Length == 1) { x = 1; } /*</bind>*/ } Local(); System.Console.WriteLine(x); } } "); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("x, y", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.Captured)); } [Fact] public void AssignmentInsideLocal03() { var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowStatements(@" class Program { static void Main() { int x = 3, y = 4; void Local() { /*<bind>*/ if (false) { x = 1; } /*</bind>*/ } Local(); System.Console.WriteLine(x); } } "); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); // This is a conservative approximation, ignoring whether the branch containing // the assignment is reachable Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("x, y", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.Captured)); } [Fact] public void AssignmentInsideLocal04() { var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowStatements(@" class Program { static void Main() { int x = 3, y = 4; void Local() { /*<bind>*/ x = 1; /*</bind>*/ x = 1; } Local(); System.Console.WriteLine(x); } } "); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("x, y", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.Captured)); } [Fact] [WorkItem(39569, "https://github.com/dotnet/roslyn/issues/39569")] public void AssignmentInsideLocal05() { var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowStatements(@" class Program { static void Main() { int x = 3, y = 4; void Local() { x = 1; } /*<bind>*/ Local(); /*</bind>*/ System.Console.WriteLine(x); } } "); // Right now region analysis requires bound nodes for each variable and value being // assigned. This doesn't work with the current local function analysis because we only // store the slots, not the full boundnode of every assignment (which is impossible // anyway). This should be: // Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("x, y", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.Captured)); } [Fact] public void AssignmentInsideLocal06() { var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowStatements(@" class Program { static void Main() { int x = 3, y = 4; /*<bind>*/ void Local() { x = 1; } /*</bind>*/ Local(); System.Console.WriteLine(x); } } "); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("x, y", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.Captured)); } [Fact] public void AssignmentInsideLocal07() { var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowStatements(@" class Program { static void Main() { int x = 3, y = 4; /*<bind>*/ void Local() { x = 1; } Local(); /*</bind>*/ System.Console.WriteLine(x); } } "); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("x, y", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.Captured)); } [Fact] public void AssignmentInsideLocal08() { var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowStatements(@" class Program { static void Main() { int x = 3, y = 4; void Local() { /*<bind>*/ if ("""".Length == 0) { x = 1; return; } else { y = 1; } /*</bind>*/ } Local(); System.Console.WriteLine(x); System.Console.WriteLine(y); } } "); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Equal("x, y", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Equal("x, y", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Equal("x, y", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("x, y", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); Assert.Equal("x, y", GetSymbolNamesJoined(dataFlowAnalysisResults.Captured)); } [Fact] public void AssignmentInsideLocal09() { var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowStatements(@" class Program { static void Main() { int x = 3, y = 4; void Local() { /*<bind>*/ if ("""".Length == 0) { x = 1; return; } else { y = 1; throw new Exception(); } /*</bind>*/ } Local(); System.Console.WriteLine(x); System.Console.WriteLine(y); } } "); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); // N.B. This is not as precise as possible. The branch assigning y is unreachable, so // the result does not technically flow out. This is a conservative approximation. Assert.Equal("x, y", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Equal("x, y", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Equal("x, y", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("x, y", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); Assert.Equal("x, y", GetSymbolNamesJoined(dataFlowAnalysisResults.Captured)); } [Fact, WorkItem(25043, "https://github.com/dotnet/roslyn/issues/25043")] public void FallThroughInSwitch_01() { var analysis = CompileAndAnalyzeControlFlowStatements(@" class C { void M() { /*<bind>*/ switch (true) { case true: void f() { } } /*</bind>*/ } }"); Assert.Equal(0, analysis.EntryPoints.Count()); } [Fact, WorkItem(25043, "https://github.com/dotnet/roslyn/issues/25043")] public void FallThroughInSwitch_02() { var analysis = CompileAndAnalyzeControlFlowStatements(@" class C { void M() { /*<bind>*/ switch (true) { case true when true: void f() { } } /*</bind>*/ } }"); Assert.Equal(0, analysis.EntryPoints.Count()); } [Fact] public void AnalysisOfTupleEquality() { var analysisResults = CompileAndAnalyzeDataFlowExpression(@" class A { void M() { int x = 0; int y = 0; _ = /*<bind>*/(x, y) == (x = 0, 1)/*</bind>*/; } } "); var dataFlowAnalysisResults = analysisResults; Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.Captured)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedOutside)); Assert.Equal("x, y", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("this, x, y", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("this, x, y", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Equal("x, y", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("this, x, y", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [Fact] public void AnalysisOfNestedTupleInTupleEquality() { var analysisResults = CompileAndAnalyzeDataFlowExpression(@" class A { void M() { int x = 0; int y = 0; _ = (1, (2, 3)) == (0, /*<bind>*/(x = 0, y)/*</bind>*/); } } "); var dataFlowAnalysisResults = analysisResults; Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.Captured)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedOutside)); Assert.Equal("y", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("this, x, y", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("this, x, y", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Equal("y", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("this, x, y", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [Fact] public void AnalysisOfExpressionInTupleEquality() { var analysisResults = CompileAndAnalyzeDataFlowExpression(@" class A { void M() { int x = 0; int y = 0; _ = (1, 2) == (0, /*<bind>*/(x = 0) + y/*</bind>*/); } } "); var dataFlowAnalysisResults = analysisResults; Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.Captured)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedOutside)); Assert.Equal("y", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("this, x, y", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("this, x, y", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Equal("y", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("this, x, y", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [Fact] public void AnalysisOfMixedDeconstruction() { var analysisResults = CompileAndAnalyzeDataFlowExpression(@" class A { bool M() { int x = 0; string y; /*<bind>*/ (x, (y, var z)) = (x, ("""", true)) /*</bind>*/ return z; } } "); var dataFlowAnalysisResults = analysisResults; Assert.Equal("z", GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Equal("x, y, z", GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.Captured)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedOutside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Equal("z", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("this, x", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("this, x, y, z", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Equal("z", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Equal("x, y, z", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("this, x", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [Fact] public void AnalysisOfPropertyGetter_Inside_ReferenceType() { var analysisResults = CompileAndAnalyzeDataFlowExpression(@" class MyClass { int _myProp; int MyProp { get => /*<bind>*/this._myProp;/*</bind>*/ set => this._myProp = value; } } "); var dataFlowAnalysisResults = analysisResults; Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.Captured)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedOutside)); Assert.Equal("this", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("this", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("this", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Equal("this", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("this", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [Fact] public void AnalysisOfPropertySetter_Inside_ReferenceType() { var analysisResults = CompileAndAnalyzeDataFlowExpression(@" class MyClass { int _myProp; int MyProp { get => this._myProp; set => /*<bind>*/this._myProp = value;/*</bind>*/ } } "); var dataFlowAnalysisResults = analysisResults; Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.Captured)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedOutside)); Assert.Equal("this, value", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("this, value", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("this, value", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Equal("this, value", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("this, value", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [Fact] public void AnalysisOfPropertyGetter_Inside_ValueType() { var analysisResults = CompileAndAnalyzeDataFlowExpression(@" struct MyStruct { int _myProp; int MyProp { get => /*<bind>*/this._myProp;/*</bind>*/ set => this._myProp = value; } } "); var dataFlowAnalysisResults = analysisResults; Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.Captured)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedOutside)); Assert.Equal("this", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("this", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("this", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Equal("this", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Equal("this", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("this", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [Fact] public void AnalysisOfPropertySetter_Inside_ValueType() { var analysisResults = CompileAndAnalyzeDataFlowExpression(@" struct MyStruct { int _myProp; int MyProp { get => this._myProp; set => /*<bind>*/this._myProp = value;/*</bind>*/ } } "); var dataFlowAnalysisResults = analysisResults; Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Equal("this", GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.Captured)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedOutside)); Assert.Equal("value", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Equal("this", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("this, value", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("this, value", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Equal("value", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Equal("this", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Equal("this", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("this, value", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [Fact] public void AnalysisOfEventAdder_Inside_ReferenceType() { var analysisResults = CompileAndAnalyzeDataFlowExpression(@" class MyClass { EventHandler _myEvent; event EventHandler MyEvent { add => /*<bind>*/ this._myEvent += value; /*</bind>*/ remove => this._myEvent -= value; } } "); var dataFlowAnalysisResults = analysisResults; Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.Captured)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedOutside)); Assert.Equal("this, value", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("this, value", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("this, value", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Equal("this, value", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("this, value", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [Fact] public void AnalysisOfEventRemover_Inside_ReferenceType() { var analysisResults = CompileAndAnalyzeDataFlowExpression(@" class MyClass { EventHandler _myEvent; event EventHandler MyEvent { add => this._myEvent += value; remove => /*<bind>*/ this._myEvent -= value; /*</bind>*/ } } "); var dataFlowAnalysisResults = analysisResults; Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.Captured)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedOutside)); Assert.Equal("this, value", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("this, value", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("this, value", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Equal("this, value", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("this, value", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [Fact] public void AnalysisOfEventAdder_Inside_ValueType() { var analysisResults = CompileAndAnalyzeDataFlowExpression(@" struct MyStruct { EventHandler _myEvent; event EventHandler MyEvent { add => /*<bind>*/ this._myEvent += value; /*</bind>*/ remove => this._myEvent -= value; } } "); var dataFlowAnalysisResults = analysisResults; Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Equal("this", GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.Captured)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedOutside)); Assert.Equal("this, value", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Equal("this", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("this, value", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("this, value", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Equal("this, value", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Equal("this", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Equal("this", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("this, value", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [Fact] public void AnalysisOfEventRemover_Inside_ValueType() { var analysisResults = CompileAndAnalyzeDataFlowExpression(@" struct MyStruct { EventHandler _myEvent; event EventHandler MyEvent { add => this._myEvent += value; remove => /*<bind>*/ this._myEvent -= value; /*</bind>*/ } } "); var dataFlowAnalysisResults = analysisResults; Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Equal("this", GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.Captured)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedOutside)); Assert.Equal("this, value", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Equal("this", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("this, value", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("this, value", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Equal("this, value", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Equal("this", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Equal("this", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("this, value", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [Fact] [WorkItem(27969, "https://github.com/dotnet/roslyn/issues/27969")] public void CodeInInitializer01() { var analysisResults = CompileAndAnalyzeDataFlowExpression(@" using System; class C { object P { get; } = Create(nameof(P), /*<bind>*/x => true/*</bind>*/); static object Create(string name, Func<string, bool> f) => throw null; } "); var dataFlowAnalysisResults = analysisResults; Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.Captured)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [Fact] [WorkItem(27969, "https://github.com/dotnet/roslyn/issues/27969")] public void CodeInInitializer02() { var analysisResults = CompileAndAnalyzeDataFlowExpression(@" using System; class C { object P { get; } = Create(P, /*<bind>*/x => true/*</bind>*/); static object Create(object name, Func<string, bool> f) => throw null; } "); var dataFlowAnalysisResults = analysisResults; Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.Captured)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [Fact] [WorkItem(19845, "https://github.com/dotnet/roslyn/issues/19845")] public void CodeInInitializer03() { var analysisResults = CompileAndAnalyzeDataFlowExpression(@" class C { static int X { get; set; } int Y = /*<bind>*/X/*</bind>*/; }"); var dataFlowAnalysisResults = analysisResults; Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.Captured)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [Fact] [WorkItem(26028, "https://github.com/dotnet/roslyn/issues/26028")] public void BrokenForeach01() { var source = @"class C { void M() { foreach (var x } } "; var compilation = CreateCompilation(source); var tree = compilation.SyntaxTrees[0]; var model = compilation.GetSemanticModel(tree); // The foreach loop is broken, so its embedded statement is filled in during syntax error recovery. It is zero-width. var stmt = tree.GetCompilationUnitRoot().DescendantNodesAndSelf().OfType<ForEachStatementSyntax>().Single().Statement; Assert.Equal(0, stmt.Span.Length); var dataFlowAnalysisResults = model.AnalyzeDataFlow(stmt); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.Captured)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("this, x", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("this, x", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("this, x", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [Fact] [WorkItem(30548, "https://github.com/dotnet/roslyn/issues/30548")] public void SymbolInDataFlowInButNotInReadInside() { var analysisResults = CompileAndAnalyzeControlAndDataFlowStatements(@" using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApp39 { class Program { void Method(out object test) { test = null; var a = test != null; /*<bind>*/if (a) { return; } if (A == a) { test = new object(); }/*</bind>*/ } } }"); var dataFlowAnalysisResults = analysisResults.Item2; Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.Captured)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedOutside)); Assert.Equal("test, a", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Equal("test", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("this, test, a", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("this, test, a", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Equal("a", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Equal("test", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Equal("test", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("this, test, a", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [Fact, WorkItem(37427, "https://github.com/dotnet/roslyn/issues/37427")] public void RegionWithLocalFunctions() { // local functions inside the region var s1 = @" class A { static void M(int p) { int i, j; i = 1; /*<bind>*/ int L1() => 1; int k; j = i; int L2() => 2; /*</bind>*/ k = j; } } "; // local functions outside the region var s2 = @" class A { static void M(int p) { int i, j; i = 1; int L1() => 1; /*<bind>*/ int k; j = i; /*</bind>*/ int L2() => 2; k = j; } } "; foreach (var s in new[] { s1, s2 }) { var analysisResults = CompileAndAnalyzeDataFlowStatements(s); var dataFlowAnalysisResults = analysisResults; Assert.True(dataFlowAnalysisResults.Succeeded); Assert.Equal("k", GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Equal("j", GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.Captured)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedOutside)); Assert.Equal("i", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Equal("j", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("i", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Equal("j", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Equal("j", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("p, i, k", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } } [Fact] public void TestAddressOfUnassignedStructLocal_02() { // This test demonstrates that "data flow analysis" pays attention to private fields // of structs imported from metadata. var libSource = @" public struct Struct { private string Field; }"; var libraryReference = CreateCompilation(libSource).EmitToImageReference(); var analysis = CompileAndAnalyzeDataFlowExpression(@" class Program { static void Main() { Struct x; // considered not definitely assigned because it has a field Struct * px = /*<bind>*/&x/*</bind>*/; // address taken of an unassigned variable } } ", libraryReference); Assert.Equal("x", GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Equal("x", GetSymbolNamesJoined(analysis.UnsafeAddressTaken)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(analysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Equal("x", GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("px", GetSymbolNamesJoined(analysis.WrittenOutside)); } [WorkItem(57428, "https://github.com/dotnet/roslyn/issues/57428")] [Fact] public void AttributeArgumentWithLambdaBody_01() { var source = @"using System.Runtime.InteropServices; class Program { static void F([DefaultParameterValue(() => { return 0; })] object obj) { } }"; var compilation = CreateCompilation(source); compilation.VerifyDiagnostics( // (4,42): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type // static void F([DefaultParameterValue(() => { return 0; })] object obj) Diagnostic(ErrorCode.ERR_BadAttributeArgument, "() => { return 0; }").WithLocation(4, 42)); var tree = compilation.SyntaxTrees[0]; var model = compilation.GetSemanticModel(tree); var expr = tree.GetRoot().DescendantNodes().OfType<LiteralExpressionSyntax>().Single(); var analysis = model.AnalyzeDataFlow(expr); Assert.False(analysis.Succeeded); } [Fact] public void AttributeArgumentWithLambdaBody_02() { var source = @"using System; class A : Attribute { internal A(object o) { } } class Program { static void F([A(() => { return 0; })] object obj) { } }"; var compilation = CreateCompilation(source); compilation.VerifyDiagnostics( // (8,22): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type // static void F([A(() => { return 0; })] object obj) Diagnostic(ErrorCode.ERR_BadAttributeArgument, "() => { return 0; }").WithLocation(8, 22)); var tree = compilation.SyntaxTrees[0]; var model = compilation.GetSemanticModel(tree); var expr = tree.GetRoot().DescendantNodes().OfType<LiteralExpressionSyntax>().Single(); var analysis = model.AnalyzeDataFlow(expr); Assert.False(analysis.Succeeded); } #endregion #region "Used Local Functions" [Fact] public void RegionAnalysisUsedLocalFunctions() { var results = CompileAndAnalyzeDataFlowStatements(@" using System; class C { static void Main() { /*<bind>*/ void Local() { } /*</bind>*/ } }"); Assert.True(results.Succeeded); Assert.Null(GetSymbolNamesJoined(results.Captured)); Assert.Null(GetSymbolNamesJoined(results.CapturedInside)); Assert.Null(GetSymbolNamesJoined(results.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(results.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(results.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(results.DefinitelyAssignedOnEntry)); Assert.Null(GetSymbolNamesJoined(results.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(results.ReadInside)); Assert.Null(GetSymbolNamesJoined(results.WrittenInside)); Assert.Null(GetSymbolNamesJoined(results.ReadOutside)); Assert.Null(GetSymbolNamesJoined(results.WrittenOutside)); Assert.Null(GetSymbolNamesJoined(results.UsedLocalFunctions)); } [Fact] public void RegionAnalysisUsedLocalFunctions2() { var results = CompileAndAnalyzeDataFlowStatements(@" using System; class C { static void Main() { /*<bind>*/ Local(); /*</bind>*/ void Local() { } } }"); Assert.True(results.Succeeded); Assert.Null(GetSymbolNamesJoined(results.Captured)); Assert.Null(GetSymbolNamesJoined(results.CapturedInside)); Assert.Null(GetSymbolNamesJoined(results.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(results.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(results.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(results.DefinitelyAssignedOnEntry)); Assert.Null(GetSymbolNamesJoined(results.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(results.ReadInside)); Assert.Null(GetSymbolNamesJoined(results.WrittenInside)); Assert.Null(GetSymbolNamesJoined(results.ReadOutside)); Assert.Null(GetSymbolNamesJoined(results.WrittenOutside)); Assert.Equal("Local", GetSymbolNamesJoined(results.UsedLocalFunctions)); } [Fact] public void RegionAnalysisUsedLocalFunctions3() { var results = CompileAndAnalyzeDataFlowStatements(@" using System; class C { static void Main() { /*<bind>*/ Local(); /*</bind>*/ void Local() { } void Unused(){ } } }"); Assert.True(results.Succeeded); Assert.Null(GetSymbolNamesJoined(results.Captured)); Assert.Null(GetSymbolNamesJoined(results.CapturedInside)); Assert.Null(GetSymbolNamesJoined(results.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(results.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(results.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(results.DefinitelyAssignedOnEntry)); Assert.Null(GetSymbolNamesJoined(results.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(results.ReadInside)); Assert.Null(GetSymbolNamesJoined(results.WrittenInside)); Assert.Null(GetSymbolNamesJoined(results.ReadOutside)); Assert.Null(GetSymbolNamesJoined(results.WrittenOutside)); Assert.Equal("Local", GetSymbolNamesJoined(results.UsedLocalFunctions)); } [Fact] public void RegionAnalysisUsedLocalFunctions4() { var results = CompileAndAnalyzeDataFlowStatements(@" using System; class C { static void Main() { /*<bind>*/ Local(); /*</bind>*/ void Local() { Second(); } void Second() { } } }"); Assert.True(results.Succeeded); Assert.Null(GetSymbolNamesJoined(results.Captured)); Assert.Null(GetSymbolNamesJoined(results.CapturedInside)); Assert.Null(GetSymbolNamesJoined(results.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(results.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(results.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(results.DefinitelyAssignedOnEntry)); Assert.Null(GetSymbolNamesJoined(results.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(results.ReadInside)); Assert.Null(GetSymbolNamesJoined(results.WrittenInside)); Assert.Null(GetSymbolNamesJoined(results.ReadOutside)); Assert.Null(GetSymbolNamesJoined(results.WrittenOutside)); Assert.Equal("Local, Second", GetSymbolNamesJoined(results.UsedLocalFunctions)); } [Fact] public void RegionAnalysisUsedLocalFunctions5() { var results = CompileAndAnalyzeDataFlowStatements(@" using System; class C { static void Main() { /*<bind>*/ Local(); /*</bind>*/ void Local() { void Sub() { } } } }"); Assert.True(results.Succeeded); Assert.Null(GetSymbolNamesJoined(results.Captured)); Assert.Null(GetSymbolNamesJoined(results.CapturedInside)); Assert.Null(GetSymbolNamesJoined(results.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(results.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(results.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(results.DefinitelyAssignedOnEntry)); Assert.Null(GetSymbolNamesJoined(results.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(results.ReadInside)); Assert.Null(GetSymbolNamesJoined(results.WrittenInside)); Assert.Null(GetSymbolNamesJoined(results.ReadOutside)); Assert.Null(GetSymbolNamesJoined(results.WrittenOutside)); Assert.Equal("Local", GetSymbolNamesJoined(results.UsedLocalFunctions)); } [Fact] public void RegionAnalysisUsedLocalFunctions6() { var results = CompileAndAnalyzeDataFlowStatements(@" using System; class C { static void Main() { /*<bind>*/ Local(); /*</bind>*/ void Local() { Sub(); void Sub() { } } } }"); Assert.True(results.Succeeded); Assert.Null(GetSymbolNamesJoined(results.Captured)); Assert.Null(GetSymbolNamesJoined(results.CapturedInside)); Assert.Null(GetSymbolNamesJoined(results.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(results.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(results.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(results.DefinitelyAssignedOnEntry)); Assert.Null(GetSymbolNamesJoined(results.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(results.ReadInside)); Assert.Null(GetSymbolNamesJoined(results.WrittenInside)); Assert.Null(GetSymbolNamesJoined(results.ReadOutside)); Assert.Null(GetSymbolNamesJoined(results.WrittenOutside)); Assert.Equal("Local, Sub", GetSymbolNamesJoined(results.UsedLocalFunctions)); } [Fact] public void RegionAnalysisUsedLocalFunctions7() { var results = CompileAndAnalyzeDataFlowStatements(@" using System; class C { static void Main() { /*<bind>*/ Local(); /*</bind>*/ void Local() { Second(); } void Second() { Sub(); void Sub() { } } } }"); Assert.True(results.Succeeded); Assert.Null(GetSymbolNamesJoined(results.Captured)); Assert.Null(GetSymbolNamesJoined(results.CapturedInside)); Assert.Null(GetSymbolNamesJoined(results.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(results.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(results.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(results.DefinitelyAssignedOnEntry)); Assert.Null(GetSymbolNamesJoined(results.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(results.ReadInside)); Assert.Null(GetSymbolNamesJoined(results.WrittenInside)); Assert.Null(GetSymbolNamesJoined(results.ReadOutside)); Assert.Null(GetSymbolNamesJoined(results.WrittenOutside)); Assert.Equal("Local, Second, Sub", GetSymbolNamesJoined(results.UsedLocalFunctions)); } [Fact] public void RegionAnalysisUsedLocalFunctions8() { var results = CompileAndAnalyzeDataFlowStatements(@" using System; class C { static void Main() { /*<bind>*/ System.Action a = new System.Action(Local); /*</bind>*/ void Local() { Second(); } void Second() { Sub(); void Sub() { } } } }"); Assert.True(results.Succeeded); Assert.Null(GetSymbolNamesJoined(results.Captured)); Assert.Null(GetSymbolNamesJoined(results.CapturedInside)); Assert.Null(GetSymbolNamesJoined(results.CapturedOutside)); Assert.Equal("a", GetSymbolNamesJoined(results.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(results.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(results.DefinitelyAssignedOnEntry)); Assert.Equal("a", GetSymbolNamesJoined(results.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(results.ReadInside)); Assert.Equal("a", GetSymbolNamesJoined(results.WrittenInside)); Assert.Null(GetSymbolNamesJoined(results.ReadOutside)); Assert.Null(GetSymbolNamesJoined(results.WrittenOutside)); Assert.Equal("Local, Second, Sub", GetSymbolNamesJoined(results.UsedLocalFunctions)); } [Fact] public void RegionAnalysisUsedLocalFunctions9() { var results = CompileAndAnalyzeDataFlowStatements(@" using System; class C { static void Main() { /*<bind>*/ Local(); /*</bind>*/ static void Local() { Sub(); void Sub() { } } } }"); Assert.True(results.Succeeded); Assert.Null(GetSymbolNamesJoined(results.Captured)); Assert.Null(GetSymbolNamesJoined(results.CapturedInside)); Assert.Null(GetSymbolNamesJoined(results.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(results.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(results.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(results.DefinitelyAssignedOnEntry)); Assert.Null(GetSymbolNamesJoined(results.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(results.ReadInside)); Assert.Null(GetSymbolNamesJoined(results.WrittenInside)); Assert.Null(GetSymbolNamesJoined(results.ReadOutside)); Assert.Null(GetSymbolNamesJoined(results.WrittenOutside)); Assert.Equal("Local, Sub", GetSymbolNamesJoined(results.UsedLocalFunctions)); } [Fact] public void RegionAnalysisUsedLocalFunctions10() { var results = CompileAndAnalyzeDataFlowStatements(@" using System; class C { static void Main() { /*<bind>*/ Local(); /*</bind>*/ void Local() { Sub(); static void Sub() { } } } }"); Assert.True(results.Succeeded); Assert.Null(GetSymbolNamesJoined(results.Captured)); Assert.Null(GetSymbolNamesJoined(results.CapturedInside)); Assert.Null(GetSymbolNamesJoined(results.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(results.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(results.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(results.DefinitelyAssignedOnEntry)); Assert.Null(GetSymbolNamesJoined(results.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(results.ReadInside)); Assert.Null(GetSymbolNamesJoined(results.WrittenInside)); Assert.Null(GetSymbolNamesJoined(results.ReadOutside)); Assert.Null(GetSymbolNamesJoined(results.WrittenOutside)); Assert.Equal("Local, Sub", GetSymbolNamesJoined(results.UsedLocalFunctions)); } [Fact] public void RegionAnalysisUsedLocalFunctions11() { var results = CompileAndAnalyzeDataFlowStatements(@" using System; class C { static void Main() { /*<bind>*/ Local(); /*</bind>*/ static void Local() { Sub(); static void Sub() { } } } }"); Assert.True(results.Succeeded); Assert.Null(GetSymbolNamesJoined(results.Captured)); Assert.Null(GetSymbolNamesJoined(results.CapturedInside)); Assert.Null(GetSymbolNamesJoined(results.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(results.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(results.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(results.DefinitelyAssignedOnEntry)); Assert.Null(GetSymbolNamesJoined(results.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(results.ReadInside)); Assert.Null(GetSymbolNamesJoined(results.WrittenInside)); Assert.Null(GetSymbolNamesJoined(results.ReadOutside)); Assert.Null(GetSymbolNamesJoined(results.WrittenOutside)); Assert.Equal("Local, Sub", GetSymbolNamesJoined(results.UsedLocalFunctions)); } [Fact] public void RegionAnalysisUsedLocalFunctions12() { var results = CompileAndAnalyzeDataFlowStatements(@" using System; class C { static void Main() { Action a = () => Local(); /*<bind>*/ a(); /*</bind>*/ void Local() { } } }"); Assert.True(results.Succeeded); Assert.Null(GetSymbolNamesJoined(results.Captured)); Assert.Null(GetSymbolNamesJoined(results.CapturedInside)); Assert.Null(GetSymbolNamesJoined(results.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(results.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(results.DataFlowsOut)); Assert.Equal("a", GetSymbolNamesJoined(results.DefinitelyAssignedOnEntry)); Assert.Equal("a", GetSymbolNamesJoined(results.DefinitelyAssignedOnExit)); Assert.Equal("a", GetSymbolNamesJoined(results.ReadInside)); Assert.Null(GetSymbolNamesJoined(results.WrittenInside)); Assert.Null(GetSymbolNamesJoined(results.ReadOutside)); Assert.Equal("a", GetSymbolNamesJoined(results.WrittenOutside)); Assert.Equal("Local", GetSymbolNamesJoined(results.UsedLocalFunctions)); } [Fact] public void RegionAnalysisUsedLocalFunctions13() { var results = CompileAndAnalyzeDataFlowStatements(@" using System; class C { static void Main() { /*<bind>*/ Action a = () => Local(); /*</bind>*/ a(); void Local() { } } }"); Assert.True(results.Succeeded); Assert.Null(GetSymbolNamesJoined(results.Captured)); Assert.Null(GetSymbolNamesJoined(results.CapturedInside)); Assert.Null(GetSymbolNamesJoined(results.CapturedOutside)); Assert.Equal("a", GetSymbolNamesJoined(results.VariablesDeclared)); Assert.Equal("a", GetSymbolNamesJoined(results.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(results.DefinitelyAssignedOnEntry)); Assert.Equal("a", GetSymbolNamesJoined(results.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(results.ReadInside)); Assert.Equal("a", GetSymbolNamesJoined(results.WrittenInside)); Assert.Equal("a", GetSymbolNamesJoined(results.ReadOutside)); Assert.Null(GetSymbolNamesJoined(results.WrittenOutside)); Assert.Equal("Local", GetSymbolNamesJoined(results.UsedLocalFunctions)); } [Fact] public void RegionAnalysisUsedLocalFunctions14() { var results = CompileAndAnalyzeDataFlowStatements(@" using System; class C { static void Main() { Action a = () => Local(); /*<bind>*/ a(); /*</bind>*/ void Local() { Sub(); void Sub(); } } }"); Assert.True(results.Succeeded); Assert.Null(GetSymbolNamesJoined(results.Captured)); Assert.Null(GetSymbolNamesJoined(results.CapturedInside)); Assert.Null(GetSymbolNamesJoined(results.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(results.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(results.DataFlowsOut)); Assert.Equal("a", GetSymbolNamesJoined(results.DefinitelyAssignedOnEntry)); Assert.Equal("a", GetSymbolNamesJoined(results.DefinitelyAssignedOnExit)); Assert.Equal("a", GetSymbolNamesJoined(results.ReadInside)); Assert.Null(GetSymbolNamesJoined(results.WrittenInside)); Assert.Null(GetSymbolNamesJoined(results.ReadOutside)); Assert.Equal("a", GetSymbolNamesJoined(results.WrittenOutside)); Assert.Equal("Local, Sub", GetSymbolNamesJoined(results.UsedLocalFunctions)); } [Fact] public void RegionAnalysisUsedLocalFunctions15() { var results = CompileAndAnalyzeDataFlowStatements(@" using System; class C { static void Main() { /*<bind>*/ Action a = () => Local(); /*</bind>*/ a(); void Local() { Sub(); void Sub(); } } }"); Assert.True(results.Succeeded); Assert.Null(GetSymbolNamesJoined(results.Captured)); Assert.Null(GetSymbolNamesJoined(results.CapturedInside)); Assert.Null(GetSymbolNamesJoined(results.CapturedOutside)); Assert.Equal("a", GetSymbolNamesJoined(results.VariablesDeclared)); Assert.Equal("a", GetSymbolNamesJoined(results.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(results.DefinitelyAssignedOnEntry)); Assert.Equal("a", GetSymbolNamesJoined(results.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(results.ReadInside)); Assert.Equal("a", GetSymbolNamesJoined(results.WrittenInside)); Assert.Equal("a", GetSymbolNamesJoined(results.ReadOutside)); Assert.Null(GetSymbolNamesJoined(results.WrittenOutside)); Assert.Equal("Local, Sub", GetSymbolNamesJoined(results.UsedLocalFunctions)); } [Fact] public void RegionAnalysisUsedLocalFunctions16() { var results = CompileAndAnalyzeDataFlowStatements(@" using System; class C { static void Main() { Action a = () => Local(); /*<bind>*/ a(); /*</bind>*/ static void Local() { } } }"); Assert.True(results.Succeeded); Assert.Null(GetSymbolNamesJoined(results.Captured)); Assert.Null(GetSymbolNamesJoined(results.CapturedInside)); Assert.Null(GetSymbolNamesJoined(results.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(results.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(results.DataFlowsOut)); Assert.Equal("a", GetSymbolNamesJoined(results.DefinitelyAssignedOnEntry)); Assert.Equal("a", GetSymbolNamesJoined(results.DefinitelyAssignedOnExit)); Assert.Equal("a", GetSymbolNamesJoined(results.ReadInside)); Assert.Null(GetSymbolNamesJoined(results.WrittenInside)); Assert.Null(GetSymbolNamesJoined(results.ReadOutside)); Assert.Equal("a", GetSymbolNamesJoined(results.WrittenOutside)); Assert.Equal("Local", GetSymbolNamesJoined(results.UsedLocalFunctions)); } [Fact] public void RegionAnalysisUsedLocalFunctions17() { var results = CompileAndAnalyzeDataFlowStatements(@" using System; class C { static void Main() { /*<bind>*/ Action a = () => Local(); /*</bind>*/ a(); static void Local() { } } }"); Assert.True(results.Succeeded); Assert.Null(GetSymbolNamesJoined(results.Captured)); Assert.Null(GetSymbolNamesJoined(results.CapturedInside)); Assert.Null(GetSymbolNamesJoined(results.CapturedOutside)); Assert.Equal("a", GetSymbolNamesJoined(results.VariablesDeclared)); Assert.Equal("a", GetSymbolNamesJoined(results.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(results.DefinitelyAssignedOnEntry)); Assert.Equal("a", GetSymbolNamesJoined(results.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(results.ReadInside)); Assert.Equal("a", GetSymbolNamesJoined(results.WrittenInside)); Assert.Equal("a", GetSymbolNamesJoined(results.ReadOutside)); Assert.Null(GetSymbolNamesJoined(results.WrittenOutside)); Assert.Equal("Local", GetSymbolNamesJoined(results.UsedLocalFunctions)); } [Fact] public void RegionAnalysisUsedLocalFunctions18() { var results = CompileAndAnalyzeDataFlowStatements(@" using System; class C { static void Main() { Action a = () => Local(); /*<bind>*/ a(); /*</bind>*/ static void Local() { Sub(); static void Sub(); } } }"); Assert.True(results.Succeeded); Assert.Null(GetSymbolNamesJoined(results.Captured)); Assert.Null(GetSymbolNamesJoined(results.CapturedInside)); Assert.Null(GetSymbolNamesJoined(results.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(results.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(results.DataFlowsOut)); Assert.Equal("a", GetSymbolNamesJoined(results.DefinitelyAssignedOnEntry)); Assert.Equal("a", GetSymbolNamesJoined(results.DefinitelyAssignedOnExit)); Assert.Equal("a", GetSymbolNamesJoined(results.ReadInside)); Assert.Null(GetSymbolNamesJoined(results.WrittenInside)); Assert.Null(GetSymbolNamesJoined(results.ReadOutside)); Assert.Equal("a", GetSymbolNamesJoined(results.WrittenOutside)); Assert.Equal("Local, Sub", GetSymbolNamesJoined(results.UsedLocalFunctions)); } [Fact] public void RegionAnalysisUsedLocalFunctions19() { var results = CompileAndAnalyzeDataFlowStatements(@" using System; class C { static void Main() { /*<bind>*/ Action a = () => Local(); /*</bind>*/ a(); static void Local() { Sub(); static void Sub(); } } }"); Assert.True(results.Succeeded); Assert.Null(GetSymbolNamesJoined(results.Captured)); Assert.Null(GetSymbolNamesJoined(results.CapturedInside)); Assert.Null(GetSymbolNamesJoined(results.CapturedOutside)); Assert.Equal("a", GetSymbolNamesJoined(results.VariablesDeclared)); Assert.Equal("a", GetSymbolNamesJoined(results.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(results.DefinitelyAssignedOnEntry)); Assert.Equal("a", GetSymbolNamesJoined(results.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(results.ReadInside)); Assert.Equal("a", GetSymbolNamesJoined(results.WrittenInside)); Assert.Equal("a", GetSymbolNamesJoined(results.ReadOutside)); Assert.Null(GetSymbolNamesJoined(results.WrittenOutside)); Assert.Equal("Local, Sub", GetSymbolNamesJoined(results.UsedLocalFunctions)); } [Fact] public void RegionAnalysisUsedLocalFunctions20() { var results = CompileAndAnalyzeDataFlowStatements(@" using System; class C { static void Main() { /*<bind>*/ Action a = Local; /*</bind>*/ void Local() { } } }"); Assert.True(results.Succeeded); Assert.Null(GetSymbolNamesJoined(results.Captured)); Assert.Null(GetSymbolNamesJoined(results.CapturedInside)); Assert.Null(GetSymbolNamesJoined(results.CapturedOutside)); Assert.Equal("a", GetSymbolNamesJoined(results.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(results.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(results.DefinitelyAssignedOnEntry)); Assert.Equal("a", GetSymbolNamesJoined(results.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(results.ReadInside)); Assert.Equal("a", GetSymbolNamesJoined(results.WrittenInside)); Assert.Null(GetSymbolNamesJoined(results.ReadOutside)); Assert.Null(GetSymbolNamesJoined(results.WrittenOutside)); Assert.Equal("Local", GetSymbolNamesJoined(results.UsedLocalFunctions)); } [Fact] public void RegionAnalysisUsedLocalFunctions21() { var results = CompileAndAnalyzeDataFlowStatements(@" using System; class C { static void Main() { /*<bind>*/ Action a = Local; /*</bind>*/ void Local() { Sub(); void Sub(); } } }"); Assert.True(results.Succeeded); Assert.Null(GetSymbolNamesJoined(results.Captured)); Assert.Null(GetSymbolNamesJoined(results.CapturedInside)); Assert.Null(GetSymbolNamesJoined(results.CapturedOutside)); Assert.Equal("a", GetSymbolNamesJoined(results.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(results.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(results.DefinitelyAssignedOnEntry)); Assert.Equal("a", GetSymbolNamesJoined(results.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(results.ReadInside)); Assert.Equal("a", GetSymbolNamesJoined(results.WrittenInside)); Assert.Null(GetSymbolNamesJoined(results.ReadOutside)); Assert.Null(GetSymbolNamesJoined(results.WrittenOutside)); Assert.Equal("Local, Sub", GetSymbolNamesJoined(results.UsedLocalFunctions)); } [Fact] public void RegionAnalysisUsedLocalFunctions22() { var results = CompileAndAnalyzeDataFlowStatements(@" using System; class C { static void Main() { /*<bind>*/ Action a = Local; /*</bind>*/ static void Local() { } } }"); Assert.True(results.Succeeded); Assert.Null(GetSymbolNamesJoined(results.Captured)); Assert.Null(GetSymbolNamesJoined(results.CapturedInside)); Assert.Null(GetSymbolNamesJoined(results.CapturedOutside)); Assert.Equal("a", GetSymbolNamesJoined(results.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(results.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(results.DefinitelyAssignedOnEntry)); Assert.Equal("a", GetSymbolNamesJoined(results.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(results.ReadInside)); Assert.Equal("a", GetSymbolNamesJoined(results.WrittenInside)); Assert.Null(GetSymbolNamesJoined(results.ReadOutside)); Assert.Null(GetSymbolNamesJoined(results.WrittenOutside)); Assert.Equal("Local", GetSymbolNamesJoined(results.UsedLocalFunctions)); } [Fact] public void RegionAnalysisUsedLocalFunctions23() { var results = CompileAndAnalyzeDataFlowStatements(@" using System; class C { static void Main() { /*<bind>*/ Action a = Local; /*</bind>*/ static void Local() { Sub(); static void Sub(); } } }"); Assert.True(results.Succeeded); Assert.Null(GetSymbolNamesJoined(results.Captured)); Assert.Null(GetSymbolNamesJoined(results.CapturedInside)); Assert.Null(GetSymbolNamesJoined(results.CapturedOutside)); Assert.Equal("a", GetSymbolNamesJoined(results.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(results.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(results.DefinitelyAssignedOnEntry)); Assert.Equal("a", GetSymbolNamesJoined(results.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(results.ReadInside)); Assert.Equal("a", GetSymbolNamesJoined(results.WrittenInside)); Assert.Null(GetSymbolNamesJoined(results.ReadOutside)); Assert.Null(GetSymbolNamesJoined(results.WrittenOutside)); Assert.Equal("Local, Sub", GetSymbolNamesJoined(results.UsedLocalFunctions)); } #endregion #region "Top level statements" [Fact] public void TestTopLevelStatements() { var analysisResults = CompileAndAnalyzeControlAndDataFlowStatements(@" using System; using System.Linq; /*<bind>*/ Console.Write(1); Console.Write(2); Console.Write(3); Console.Write(4); Console.Write(5); /*</bind>*/ "); var controlFlowAnalysisResults = analysisResults.Item1; var dataFlowAnalysisResults = analysisResults.Item2; Assert.Equal(0, controlFlowAnalysisResults.EntryPoints.Count()); Assert.Equal(0, controlFlowAnalysisResults.ExitPoints.Count()); Assert.True(controlFlowAnalysisResults.EndPointIsReachable); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("args", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("args", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("args", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [Fact] public void TestTopLevelStatements_Lambda() { var analysisResults = CompileAndAnalyzeControlAndDataFlowStatements(@" using System; using System.Linq; int i = 1; Func<int> lambda = () => { /*<bind>*/return i;/*</bind>*/ }; "); var controlFlowAnalysisResults = analysisResults.Item1; var dataFlowAnalysisResults = analysisResults.Item2; Assert.Equal(0, controlFlowAnalysisResults.EntryPoints.Count()); Assert.Equal(1, controlFlowAnalysisResults.ExitPoints.Count()); Assert.False(controlFlowAnalysisResults.EndPointIsReachable); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Equal("i", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("i, args", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("i, args", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Equal("i", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("i, lambda, args", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [Fact] public void TestTopLevelStatements_LambdaCapturingArgs() { var analysisResults = CompileAndAnalyzeControlAndDataFlowStatements(@" using System; using System.Linq; Func<int> lambda = () => { /*<bind>*/return args.Length;/*</bind>*/ }; "); var controlFlowAnalysisResults = analysisResults.Item1; var dataFlowAnalysisResults = analysisResults.Item2; Assert.Equal(0, controlFlowAnalysisResults.EntryPoints.Count()); Assert.Equal(1, controlFlowAnalysisResults.ExitPoints.Count()); Assert.False(controlFlowAnalysisResults.EndPointIsReachable); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Equal("args", GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("args", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); Assert.Equal("args", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Equal("args", GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("lambda, args", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } #endregion #region Interpolated String Handlers [Theory] [CombinatorialData] public void TestInterpolatedStringHandlers(bool validityParameter, bool useBoolReturns) { var code = @" using System.Runtime.CompilerServices; int i1; int i2; /*<bind>*/ CustomHandler c = $""{i1 = 1}{i2 = 2}""; /*</bind>*/ [InterpolatedStringHandler] public struct CustomHandler { public CustomHandler(int literalLength, int formattedCount" + (validityParameter ? ", out bool success" : "") + @") { " + (validityParameter ? "success = true;" : "") + @" } public " + (useBoolReturns ? "bool" : "void") + @" AppendFormatted(int i) => throw null; } " + InterpolatedStringHandlerAttribute; var (controlFlowAnalysisResults, dataFlowAnalysisResults) = CompileAndAnalyzeControlAndDataFlowStatements(code); Assert.Equal(0, controlFlowAnalysisResults.EntryPoints.Count()); Assert.Equal(0, controlFlowAnalysisResults.ExitPoints.Count()); Assert.True(controlFlowAnalysisResults.EndPointIsReachable); Assert.Equal("c", GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("args", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); var definitelyAssigned = (validityParameter, useBoolReturns) switch { (true, _) => "c", (_, true) => "i1, c", (_, false) => "i1, i2, c" }; Assert.Equal(definitelyAssigned + ", args", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Equal("i1, i2, c", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("args", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } [Theory] [CombinatorialData] public void TestRawInterpolatedStringHandlers(bool validityParameter, bool useBoolReturns) { var code = @" using System.Runtime.CompilerServices; int i1; int i2; /*<bind>*/ CustomHandler c = $""""""{i1 = 1}{i2 = 2}""""""; /*</bind>*/ [InterpolatedStringHandler] public struct CustomHandler { public CustomHandler(int literalLength, int formattedCount" + (validityParameter ? ", out bool success" : "") + @") { " + (validityParameter ? "success = true;" : "") + @" } public " + (useBoolReturns ? "bool" : "void") + @" AppendFormatted(int i) => throw null; } " + InterpolatedStringHandlerAttribute; var (controlFlowAnalysisResults, dataFlowAnalysisResults) = CompileAndAnalyzeControlAndDataFlowStatements(code); Assert.Equal(0, controlFlowAnalysisResults.EntryPoints.Count()); Assert.Equal(0, controlFlowAnalysisResults.ExitPoints.Count()); Assert.True(controlFlowAnalysisResults.EndPointIsReachable); Assert.Equal("c", GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); Assert.Equal("args", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); var definitelyAssigned = (validityParameter, useBoolReturns) switch { (true, _) => "c", (_, true) => "i1, c", (_, false) => "i1, i2, c" }; Assert.Equal(definitelyAssigned + ", args", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); Assert.Equal("i1, i2, c", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); Assert.Equal("args", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } #endregion [Fact] public void TestDataFlowsArrayInit_01() { var analysis = CompileAndAnalyzeDataFlowExpression(@" class C { public void F(int x) { int a = 1, y = 2; int[] b = /*<bind>*/{ a + x + 3 } /*</bind>*/; int c = a + 4 + y; } }"); Assert.Equal("x, a", GetSymbolNamesJoined(analysis.DataFlowsIn)); } [Fact] public void TestDataFlowsArrayInit_02() { var analysis = CompileAndAnalyzeDataFlowExpression(@" class C { public void F(int x) { int a = 1, y = 2; int[,] b = /*<bind>*/{ { a + x + 3 } }/*</bind>*/; int c = a + 4 + y; } }"); Assert.Equal("x, a", GetSymbolNamesJoined(analysis.DataFlowsIn)); } [Fact] public void TestDataFlowsArrayInit_03() { var analysis = CompileAndAnalyzeDataFlowExpression(@" class C { public void F(int x) { int a = 1, y = 2; int[,] b = {/*<bind>*/{ a + x + 3 } /*</bind>*/}; int c = a + 4 + y; } }"); Assert.Equal("x, a", GetSymbolNamesJoined(analysis.DataFlowsIn)); } [Fact] [WorkItem(57572, "https://github.com/dotnet/roslyn/issues/57572")] public void TestDataFlowsArrayInit_04() { var analysis = CompileAndAnalyzeDataFlowExpression(@" class C { public void F(int x) { int a = 1, y = 2; int[] b = new int[] /*<bind>*/{ a + x + 3 } /*</bind>*/; int c = a + 4 + y; } }"); Assert.Equal("x, a", GetSymbolNamesJoined(analysis.DataFlowsIn)); } [Fact] [WorkItem(57572, "https://github.com/dotnet/roslyn/issues/57572")] public void TestDataFlowsArrayInit_05() { var analysis = CompileAndAnalyzeDataFlowExpression(@" class C { public void F(int x) { int a = 1, y = 2; int[,] b = new int[,] /*<bind>*/{ {a + x + 3} } /*</bind>*/; int c = a + 4 + y; } }"); Assert.Equal("x, a", GetSymbolNamesJoined(analysis.DataFlowsIn)); } [Fact] [WorkItem(57572, "https://github.com/dotnet/roslyn/issues/57572")] public void TestDataFlowsArrayInit_06() { var analysis = CompileAndAnalyzeDataFlowExpression(@" class C { public void F(int x) { int a = 1, y = 2; int[,] b = new int[,] {/*<bind>*/{ a + x + 3 } /*</bind>*/}; int c = a + 4 + y; } }"); Assert.Equal("x, a", GetSymbolNamesJoined(analysis.DataFlowsIn)); } [Fact] public void TestDataFlowsObjectInit() { var analysis = CompileAndAnalyzeDataFlowExpression(@" class C { public int Data; public void F(int x) { int a = 1, y = 2; var b = new object() /*<bind>*/{ Data = a + x + 3 } /*</bind>*/; int c = a + 4 + y; } }"); Assert.Equal("x, a", GetSymbolNamesJoined(analysis.DataFlowsIn)); } [Fact, WorkItem(60134, "https://github.com/dotnet/roslyn/issues/60134")] public void TestDataFlowsStackArrayInit_01() { var analysis = CompileAndAnalyzeDataFlowExpression(@" class C { public void F(int x) { int a = 1, y = 2; var b = stackalloc int[] /*<bind>*/{ a + x + 3 } /*</bind>*/; int c = a + 4 + y; } } "); Assert.Equal("x, a", GetSymbolNamesJoined(analysis.DataFlowsIn)); } [Fact, WorkItem(60134, "https://github.com/dotnet/roslyn/issues/60134")] public void TestDataFlowsStackArrayInit_02() { var comp = CreateCompilation(@" #nullable enable unsafe class C { void F() { bool b = true; var c = stackalloc int[] { b ? M(out var x) : x }; } static int M(out int i) => throw null!; } ", options: TestOptions.UnsafeDebugDll); comp.VerifyDiagnostics( // (8,49): error CS0165: Use of unassigned local variable 'x' // var c = stackalloc int[] { b ? M(out var x) : x }; Diagnostic(ErrorCode.ERR_UseDefViolation, "x").WithArguments("x").WithLocation(8, 49) ); } [Fact, WorkItem(59738, "https://github.com/dotnet/roslyn/issues/59738")] public void TestDataFlowsOfIdentifierWithDelegateConversion() { var results = CompileAndAnalyzeDataFlowExpression(@" using System; internal static class NoExtensionMethods { internal static Func<T> AsFunc<T>(this T value) where T : class { return new Func<T>(/*<bind>*/ value /*</bind>*/.Return); } private static T Return<T>(this T value) { return value; } static void Main() { Console.WriteLine(((object)42).AsFunc()()); } } "); Assert.True(results.Succeeded); Assert.Null(GetSymbolNamesJoined(results.Captured)); Assert.Null(GetSymbolNamesJoined(results.CapturedInside)); Assert.Null(GetSymbolNamesJoined(results.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(results.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(results.DataFlowsOut)); Assert.Equal("value", GetSymbolNamesJoined(results.DefinitelyAssignedOnEntry)); Assert.Equal("value", GetSymbolNamesJoined(results.DefinitelyAssignedOnExit)); Assert.Equal("value", GetSymbolNamesJoined(results.ReadInside)); Assert.Null(GetSymbolNamesJoined(results.WrittenInside)); Assert.Null(GetSymbolNamesJoined(results.ReadOutside)); Assert.Equal("value", GetSymbolNamesJoined(results.WrittenOutside)); Assert.Null(GetSymbolNamesJoined(results.UsedLocalFunctions)); } [Fact] public void TestDataFlowsOfIdentifierWithDelegateConversionCast() { var analysis = CompileAndAnalyzeDataFlowExpression(@" using System; internal static class NoExtensionMethods { internal static Func<T> AsFunc<T>(this T value) where T : class { return (Func<T>)/*<bind>*/ value /*</bind>*/.Return; } private static T Return<T>(this T value) { return value; } } "); Assert.True(analysis.Succeeded); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Equal("value", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Equal("value", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("value", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("value", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("value", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Fact] public void TestDataFlowsOfIdentifierWithDelegateConversionTarget() { var analysis = CompileAndAnalyzeDataFlowExpression(@" using System; internal static class NoExtensionMethods { internal static Func<T> AsFunc<T>(this T value) where T : class { Func<T> result =/*<bind>*/ value /*</bind>*/.Return; return result; } private static T Return<T>(this T value) { return value; } } "); Assert.True(analysis.Succeeded); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Equal("value", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Equal("value", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("value", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("value", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal("result", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("value, result", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Fact, WorkItem(59738, "https://github.com/dotnet/roslyn/issues/59738")] public void DefiniteAssignmentInReceiverOfExtensionMethodInDelegateCreation() { var comp = CreateCompilation(@" using System; bool b = true; _ = new Func<string>((b ? M(out var i) : i.ToString()).ExtensionMethod); string M(out int i) { throw null; } static class Extension { public static string ExtensionMethod(this string s) => throw null; } "); comp.VerifyDiagnostics( // (4,42): error CS0165: Use of unassigned local variable 'i' // _ = new Func<string>((b ? M(out var i) : i.ToString()).ExtensionMethod); Diagnostic(ErrorCode.ERR_UseDefViolation, "i").WithArguments("i").WithLocation(4, 42) ); } [Fact, WorkItem(59738, "https://github.com/dotnet/roslyn/issues/59738")] public void DefiniteAssignmentShouldSkipImplicitThisInStaticMethodConversion() { var comp = CreateCompilation(@" using System; public struct C { private object field; public C(Action a) { // implicit `this` receiver should be ignored in definite assignment a = new(M); field = 1; } public C(Action a, int ignored) { // implicit `this` receiver should be ignored in definite assignment a = new Action(M); field = 1; } public void Method1(Action a) { // explicit `this` disallowed a = new Action(this.M); } public void Method2(Action a, C c) { // instance receiver disallowed a = new Action(c.M); } private static void M() { } } "); comp.VerifyDiagnostics( // (23,24): error CS0176: Member 'C.M()' cannot be accessed with an instance reference; qualify it with a type name instead // a = new Action(this.M); Diagnostic(ErrorCode.ERR_ObjectProhibited, "this.M").WithArguments("C.M()").WithLocation(23, 24), // (29,24): error CS0176: Member 'C.M()' cannot be accessed with an instance reference; qualify it with a type name instead // a = new Action(c.M); Diagnostic(ErrorCode.ERR_ObjectProhibited, "c.M").WithArguments("C.M()").WithLocation(29, 24) ); } [Fact, WorkItem(59738, "https://github.com/dotnet/roslyn/issues/59738")] public void DefiniteAssignmentWithExplicitThisInStaticMethodConversion() { var comp = CreateCompilation(@" using System; public struct C { private object field; public void Method1(Action a) { a = new Action(this.M); field = 1; } public void Method2(Action a, C c) { a = new Action(c.M); } } public static class Extension { public static void M(this C c) { } } "); comp.VerifyDiagnostics( // (8,24): error CS1113: Extension method 'Extension.M(C)' defined on value type 'C' cannot be used to create delegates // a = new Action(this.M); Diagnostic(ErrorCode.ERR_ValueTypeExtDelegate, "this.M").WithArguments("Extension.M(C)", "C").WithLocation(8, 24), // (14,24): error CS1113: Extension method 'Extension.M(C)' defined on value type 'C' cannot be used to create delegates // a = new Action(c.M); Diagnostic(ErrorCode.ERR_ValueTypeExtDelegate, "c.M").WithArguments("Extension.M(C)", "C").WithLocation(14, 24) ); } [Fact] public void PrimaryConstructors_01() { verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { int X() => /*<bind>*/x/*</bind>*/; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { int X() => /*<bind>*/x/*</bind>*/; int M() => x; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B { void M(int x) { X(); int X() => /*<bind>*/x/*</bind>*/; } } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B { void M(int x) { X(); static int X() => /*<bind>*/x/*</bind>*/; } } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B { void M(int x) { _ = () => /*<bind>*/x/*</bind>*/; } } "), "x"); // https://github.com/dotnet/roslyn/issues/66557 verify(CompileAndAnalyzeDataFlowExpression(@" class B { void M(int x) { _ = static () => /*<bind>*/x/*</bind>*/; } } "), "x"); // https://github.com/dotnet/roslyn/issues/66557 verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { B() : this(1) { _ = /*<bind>*/x/*</bind>*/; } } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { B() : this(1) { _ = /*<bind>*/x/*</bind>*/; } int M() => x; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B { B(int x) { X(); int X() => /*<bind>*/x/*</bind>*/; } } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B { B(int x) { X(); static int X() => /*<bind>*/x/*</bind>*/; } } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B { B(int x) { _ = () => /*<bind>*/x/*</bind>*/; } } "), "x"); // https://github.com/dotnet/roslyn/issues/66557 verify(CompileAndAnalyzeDataFlowExpression(@" class B { B(int x) { _ = static () => /*<bind>*/x/*</bind>*/; } } "), "x"); // https://github.com/dotnet/roslyn/issues/66557 verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { B() : this(/*<bind>*/x/*</bind>*/) {} } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { B() : this(/*<bind>*/x/*</bind>*/) {} int M() => x; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B { B(int x) : this(() => /*<bind>*/x/*</bind>*/) { } B(System.Func<int> x){} } "), "x"); // https://github.com/dotnet/roslyn/issues/66557 verify(CompileAndAnalyzeDataFlowExpression(@" class B { B(int x) : this(static () => /*<bind>*/x/*</bind>*/) { } B(System.Func<int> x){} } "), "x"); // https://github.com/dotnet/roslyn/issues/66557 static void verify(DataFlowAnalysis analysis, string dataFlowsIn = null) { Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("x", GetSymbolNamesJoined(analysis.Captured)); Assert.Equal("x", GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Equal(dataFlowsIn, GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("this, x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry, sort: true)); Assert.Equal("this, x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit, sort: true)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("this, x", GetSymbolNamesJoined(analysis.WrittenOutside, sort: true)); } } [Fact] public void PrimaryConstructors_02() { verify(CompileAndAnalyzeDataFlowExpression(@" struct B(int x) { B() : this(1) { _ = /*<bind>*/x/*</bind>*/; } public int y; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" struct B(int x) { B() : this(1) { _ = /*<bind>*/x/*</bind>*/; } int M() => x; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" struct B { B(int x) : this("""") { X(); int X() => /*<bind>*/x/*</bind>*/; } B(string x) {} public int y; } "), thisIsAssignedOnEntry: false); static void verify(DataFlowAnalysis analysis, bool thisIsAssignedOnEntry = true) { Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("x", GetSymbolNamesJoined(analysis.Captured)); Assert.Equal("x", GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal((thisIsAssignedOnEntry ? "this, " : "") + "x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry, sort: true)); Assert.Equal((thisIsAssignedOnEntry ? "this, " : "") + "x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit, sort: true)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal("this", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("this, x", GetSymbolNamesJoined(analysis.WrittenOutside, sort: true)); } } [Fact] public void PrimaryConstructors_03() { verify(CompileAndAnalyzeDataFlowExpression(@" struct B(int x) { B() : this(/*<bind>*/x/*</bind>*/) {} public int y; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" struct B(int x) { B() : this(/*<bind>*/x/*</bind>*/) {} int M() => x; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" struct B { B(int x) : this(() => /*<bind>*/x/*</bind>*/) { } B(System.Func<int> x){} public int y; } "), "x"); // https://github.com/dotnet/roslyn/issues/66557 static void verify(DataFlowAnalysis analysis, string dataFlowsIn = null) { Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("x", GetSymbolNamesJoined(analysis.Captured)); Assert.Equal("x", GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Equal(dataFlowsIn, GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal("this", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("this, x", GetSymbolNamesJoined(analysis.WrittenOutside, sort: true)); } } [Fact] public void PrimaryConstructors_04() { verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x, int y) { int X() => /*<bind>*/x/*</bind>*/; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B { void M(int x, int y) { X(); int X() => /*<bind>*/x/*</bind>*/; } } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B { void M(int x, int y) { X(); static int X() => /*<bind>*/x/*</bind>*/; } } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B { void M(int x, int y) { _ = () => /*<bind>*/x/*</bind>*/; } } "), "x"); // https://github.com/dotnet/roslyn/issues/66557 verify(CompileAndAnalyzeDataFlowExpression(@" class B { void M(int x, int y) { _ = static () => /*<bind>*/x/*</bind>*/; } } "), "x"); // https://github.com/dotnet/roslyn/issues/66557 verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x, int y) { B() : this(1, 2) { _ = /*<bind>*/x/*</bind>*/; } } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B { B(int x, int y) { X(); int X() => /*<bind>*/x/*</bind>*/; } } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B { B(int x, int y) { X(); static int X() => /*<bind>*/x/*</bind>*/; } } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B { B(int x, int y) { _ = () => /*<bind>*/x/*</bind>*/; } } "), "x"); // https://github.com/dotnet/roslyn/issues/66557 verify(CompileAndAnalyzeDataFlowExpression(@" class B { B(int x, int y) { _ = static () => /*<bind>*/x/*</bind>*/; } } "), "x"); // https://github.com/dotnet/roslyn/issues/66557 verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x, int y) { B() : this(1, /*<bind>*/x/*</bind>*/) { } } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B { B(int x, int y) : this(() => /*<bind>*/x/*</bind>*/) { } B(System.Func<int> x) {} } "), "x"); // https://github.com/dotnet/roslyn/issues/66557 verify(CompileAndAnalyzeDataFlowExpression(@" class B { B(int x, int y) : this(static () => /*<bind>*/x/*</bind>*/) { } B(System.Func<int> x) {} } "), "x"); // https://github.com/dotnet/roslyn/issues/66557 static void verify(DataFlowAnalysis analysis, string dataFlowsIn = null) { Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("x", GetSymbolNamesJoined(analysis.Captured)); Assert.Equal("x", GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Equal(dataFlowsIn, GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("this, x, y", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry, sort: true)); Assert.Equal("this, x, y", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit, sort: true)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("this, x, y", GetSymbolNamesJoined(analysis.WrittenOutside, sort: true)); } } [Fact] public void PrimaryConstructors_05() { verify(CompileAndAnalyzeDataFlowExpression(@" class B(int y) { int X(int x) => /*<bind>*/x/*</bind>*/; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int y) { int X(int x) => /*<bind>*/x/*</bind>*/; int Y() => y; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B { void M(int y) { X(1); int X(int x) => /*<bind>*/x/*</bind>*/; } } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B { void M(int y) { X(1); static int X(int x) => /*<bind>*/x/*</bind>*/; } } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B { void M(int y) { _ = (int x) => /*<bind>*/x/*</bind>*/; } } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B { void M(int y) { _ = static (int x) => /*<bind>*/x/*</bind>*/; } } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int y) { B(short x) : this(1) => /*<bind>*/x/*</bind>*/; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int y) { B(short x) : this(1) => /*<bind>*/x/*</bind>*/; int Y() => y; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B { B(int y) { X(1); int X(int x) => /*<bind>*/x/*</bind>*/; } } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B { B(int y) { X(1); static int X(int x) => /*<bind>*/x/*</bind>*/; } } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B { B(int y) { _ = (int x) => /*<bind>*/x/*</bind>*/; } } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B { B(int y) { _ = static (int x) => /*<bind>*/x/*</bind>*/; } } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int y) { B(short x) : this(/*<bind>*/x/*</bind>*/) {} } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int y) { B(short x) : this(/*<bind>*/x/*</bind>*/) {} int Y() => y; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B { B(int y) : this((int x) => /*<bind>*/x/*</bind>*/) { } B(System.Func<int, int> x) {} } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B { B(int y) : this(static (int x) => /*<bind>*/x/*</bind>*/) { } B(System.Func<int, int> x) {} } ")); static void verify(DataFlowAnalysis analysis) { Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("this, x, y", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry, sort: true)); Assert.Equal("this, x, y", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit, sort: true)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("this, x, y", GetSymbolNamesJoined(analysis.WrittenOutside, sort: true)); } } [Fact] public void PrimaryConstructors_06() { verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { static int X() => /*<bind>*/x/*</bind>*/; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { static int X() => /*<bind>*/x/*</bind>*/; int M() => x; } ")); static void verify(DataFlowAnalysis analysis) { Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("x", GetSymbolNamesJoined(analysis.Captured)); Assert.Equal("x", GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Null(GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenOutside)); } } [Fact] public void PrimaryConstructors_07() { verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x, int y) { static int X() => /*<bind>*/x/*</bind>*/; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x, int y) { static int X() => /*<bind>*/x/*</bind>*/; int M() => y; } ")); static void verify(DataFlowAnalysis analysis) { Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("x", GetSymbolNamesJoined(analysis.Captured)); Assert.Equal("x", GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry, sort: true)); Assert.Null(GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit, sort: true)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenOutside, sort: true)); } } [Fact] public void PrimaryConstructors_08() { verify(CompileAndAnalyzeDataFlowExpression(@" class B(int y) { static int X(int x) => /*<bind>*/x/*</bind>*/; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int y) { static int X(int x) => /*<bind>*/x/*</bind>*/; int Y() => y; } ")); static void verify(DataFlowAnalysis analysis) { Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry, sort: true)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit, sort: true)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x", GetSymbolNamesJoined(analysis.WrittenOutside, sort: true)); } } [Fact] public void PrimaryConstructors_09() { verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { int X = /*<bind>*/x/*</bind>*/; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { int X { get; } = /*<bind>*/x/*</bind>*/; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(System.Action x) { event System.Action X = /*<bind>*/x/*</bind>*/; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { int X = /*<bind>*/x/*</bind>*/; int M() => x; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { int X { get; } = /*<bind>*/x/*</bind>*/; int M() => x; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(System.Action x) { event System.Action X = /*<bind>*/x/*</bind>*/; System.Action M() => x; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B { static void M(int x) { _ = /*<bind>*/x/*</bind>*/; } } ")); static void verify(DataFlowAnalysis analysis) { Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x", GetSymbolNamesJoined(analysis.WrittenOutside)); } } [Fact] public void PrimaryConstructors_10() { verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x, int y) { int X = /*<bind>*/x/*</bind>*/; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x, int y) { int X { get; } = /*<bind>*/x/*</bind>*/; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(System.Action x, int y) { event System.Action X = /*<bind>*/x/*</bind>*/; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x, int y) { int X = /*<bind>*/x/*</bind>*/; int M() => y; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x, int y) { int X { get; } = /*<bind>*/x/*</bind>*/; int M() => y; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(System.Action x, int y) { event System.Action X = /*<bind>*/x/*</bind>*/; int M() => y; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B { static void M(int x, int y) { _ = /*<bind>*/x/*</bind>*/; } } ")); static void verify(DataFlowAnalysis analysis) { Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.WrittenOutside)); } } [Fact] public void PrimaryConstructors_11() { verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { static int X = /*<bind>*/x/*</bind>*/; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { static int X { get; } = /*<bind>*/x/*</bind>*/; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(System.Action x) { static event System.Action X = /*<bind>*/x/*</bind>*/; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { static int X = /*<bind>*/x/*</bind>*/; int M() => x; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { static int X { get; } = /*<bind>*/x/*</bind>*/; int M() => x; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(System.Action x) { static event System.Action X = /*<bind>*/x/*</bind>*/; System.Action M() => x; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x, int y) { static int X = /*<bind>*/x/*</bind>*/; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x, int y) { static int X { get; } = /*<bind>*/x/*</bind>*/; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(System.Action x, int y) { static event System.Action X = /*<bind>*/x/*</bind>*/; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x, int y) { static int X = /*<bind>*/x/*</bind>*/; int M() => y; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x, int y) { static int X { get; } = /*<bind>*/x/*</bind>*/; int M() => y; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(System.Action x, int y) { static event System.Action X = /*<bind>*/x/*</bind>*/; int M() => y; } ")); static void verify(DataFlowAnalysis analysis) { Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Null(GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenOutside)); } } [Fact] public void PrimaryConstructors_12() { verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) : A(/*<bind>*/x/*</bind>*/) { } class A(int x); ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) : A(/*<bind>*/x/*</bind>*/) { int M() => x; } class A(int x); ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B : A { B(int x) : base(/*<bind>*/x/*</bind>*/) { } } class A(int x); ")); static void verify(DataFlowAnalysis analysis) { Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("this, x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry, sort: true)); Assert.Equal("this, x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit, sort: true)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("this, x", GetSymbolNamesJoined(analysis.WrittenOutside, sort: true)); } } [Fact] public void PrimaryConstructors_13() { verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x, int y) : A(/*<bind>*/x/*</bind>*/) { } class A(int x); ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x, int y) : A(/*<bind>*/x/*</bind>*/) { int M() => y; } class A(int x); ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B : A { B(int x, int y) : base(/*<bind>*/x/*</bind>*/) { } } class A(int x); ")); static void verify(DataFlowAnalysis analysis) { Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("this, x, y", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry, sort: true)); Assert.Equal("this, x, y", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit, sort: true)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("this, x, y", GetSymbolNamesJoined(analysis.WrittenOutside, sort: true)); } } [Fact] public void PrimaryConstructors_14() { verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { int X() => /*<bind>*/x = 1/*</bind>*/; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { int X() => /*<bind>*/x = 1/*</bind>*/; int M() => x; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B { void M(int x) { X(); int X() => /*<bind>*/x = 1/*</bind>*/; } } "), null); verify(CompileAndAnalyzeDataFlowExpression(@" class B { void M(int x) { X(); static int X() => /*<bind>*/x = 1/*</bind>*/; } } "), null); verify(CompileAndAnalyzeDataFlowExpression(@" class B { void M(int x) { _ = () => /*<bind>*/x = 1/*</bind>*/; } } "), null); verify(CompileAndAnalyzeDataFlowExpression(@" class B { void M(int x) { _ = static () => /*<bind>*/x = 1/*</bind>*/; } } "), null); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { B() : this(1) { _ = /*<bind>*/x = 1/*</bind>*/; } } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { B() : this(1) { _ = /*<bind>*/x = 1/*</bind>*/; } int M() => x; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B { B(int x) { X(); int X() => /*<bind>*/x = 1/*</bind>*/; } } "), null); verify(CompileAndAnalyzeDataFlowExpression(@" class B { B(int x) { X(); static int X() => /*<bind>*/x = 1/*</bind>*/; } } "), null); verify(CompileAndAnalyzeDataFlowExpression(@" class B { B(int x) { _ = () => /*<bind>*/x = 1/*</bind>*/; } } "), null); verify(CompileAndAnalyzeDataFlowExpression(@" class B { B(int x) { _ = static () => /*<bind>*/x = 1/*</bind>*/; } } "), null); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { B() : this(/*<bind>*/x = 1/*</bind>*/) {} } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { B() : this(/*<bind>*/x = 1/*</bind>*/) {} int M() => x; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B { B(int x) : this(() => /*<bind>*/x = 1/*</bind>*/) { } B(System.Func<int> x){} } "), null); verify(CompileAndAnalyzeDataFlowExpression(@" class B { B(int x) : this(static () => /*<bind>*/x = 1/*</bind>*/) { } B(System.Func<int> x){} } "), null); static void verify(DataFlowAnalysis analysis, string dataFlowsOut = "x") { Assert.Equal("x", GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("x", GetSymbolNamesJoined(analysis.Captured)); Assert.Equal("x", GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Equal(dataFlowsOut, GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("this, x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry, sort: true)); Assert.Equal("this, x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit, sort: true)); Assert.Null(GetSymbolNamesJoined(analysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Equal("x", GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("this, x", GetSymbolNamesJoined(analysis.WrittenOutside, sort: true)); } } [Fact] public void PrimaryConstructors_15() { verify(CompileAndAnalyzeDataFlowExpression(@" class B(out int x) { int X() => /*<bind>*/x = 1/*</bind>*/; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(out int x) { int X() => /*<bind>*/x = 1/*</bind>*/; int M() => x; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B { void M(out int x) { x = 1; X(); int X() => /*<bind>*/x = 1/*</bind>*/; } } "), xIsAssignedOnEntry: false); verify(CompileAndAnalyzeDataFlowExpression(@" class B { void M(out int x) { x = 1; X(); static int X() => /*<bind>*/x = 1/*</bind>*/; } } "), xIsAssignedOnEntry: false); verify(CompileAndAnalyzeDataFlowExpression(@" class B { void M(out int x) { x = 1; _ = () => /*<bind>*/x = 1/*</bind>*/; } } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B { void M(out int x) { x = 1; _ = static () => /*<bind>*/x = 1/*</bind>*/; } } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(out int x) { B() : this(1) { _ = /*<bind>*/x = 1/*</bind>*/; } } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(out int x) { B() : this(1) { _ = /*<bind>*/x = 1/*</bind>*/; } int M() => x; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B { B(out int x) { x = 1; X(); int X() => /*<bind>*/x = 1/*</bind>*/; } } "), xIsAssignedOnEntry: false); verify(CompileAndAnalyzeDataFlowExpression(@" class B { B(out int x) { x = 1; X(); static int X() => /*<bind>*/x = 1/*</bind>*/; } } "), xIsAssignedOnEntry: false); verify(CompileAndAnalyzeDataFlowExpression(@" class B { B(out int x) { x = 1; _ = () => /*<bind>*/x = 1/*</bind>*/; } } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B { B(out int x) { x = 1; _ = static () => /*<bind>*/x = 1/*</bind>*/; } } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(out int x) { B() : this(/*<bind>*/x = 1/*</bind>*/) {} } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(out int x) { B() : this(/*<bind>*/x = 1/*</bind>*/) {} int M() => x; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B { B(out int x) : this(x = 1, () => /*<bind>*/x = 1/*</bind>*/) { } B(int x, System.Func<int> x){} } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B { B(out int x) : this(x = 1, static () => /*<bind>*/x = 1/*</bind>*/) { } B(int x, System.Func<int> x){} } ")); static void verify(DataFlowAnalysis analysis, bool xIsAssignedOnEntry = true) { Assert.Equal("x", GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("x", GetSymbolNamesJoined(analysis.Captured)); Assert.Equal("x", GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("this" + (xIsAssignedOnEntry ? ", x" : ""), GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry, sort: true)); Assert.Equal("this, x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit, sort: true)); Assert.Null(GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Equal("x", GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("this, x", GetSymbolNamesJoined(analysis.WrittenOutside, sort: true)); } } [Fact] public void PrimaryConstructors_16() { verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { int X = /*<bind>*/x = 1/*</bind>*/; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { int X { get; } = /*<bind>*/x = 1/*</bind>*/; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(System.Action x) { event System.Action X = /*<bind>*/x = null/*</bind>*/; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { int X = /*<bind>*/x = 1/*</bind>*/; int M() => x; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { int X { get; } = /*<bind>*/x = 1/*</bind>*/; int M() => x; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(System.Action x) { event System.Action X = /*<bind>*/x = null/*</bind>*/; System.Action M() => x; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B { static void M(int x) { _ = /*<bind>*/x = 1/*</bind>*/; } } "), null); static void verify(DataFlowAnalysis analysis, string dataFlowsOut = "x") { Assert.Equal("x", GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Equal(dataFlowsOut, GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(analysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Equal("x", GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x", GetSymbolNamesJoined(analysis.WrittenOutside)); } } [Fact] public void PrimaryConstructors_17() { verify(CompileAndAnalyzeDataFlowExpression(@" class B(out int x) { int Y = x = 2; int X = /*<bind>*/x = 1/*</bind>*/; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(out int x) { int Y = x = 2; int X { get; } = /*<bind>*/x = 1/*</bind>*/; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(out System.Action x) { int Y = x = null; event System.Action X = /*<bind>*/x = null/*</bind>*/; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(out int x) { int Y = x = 2; int X = /*<bind>*/x = 1/*</bind>*/; int M() => x; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(out int x) { int Y = x = 2; int X { get; } = /*<bind>*/x = 1/*</bind>*/; int M() => x; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(out System.Action x) { int Y = x = null; event System.Action X = /*<bind>*/x = null/*</bind>*/; System.Action M() => x; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B { static void M(out int x) { _ = /*<bind>*/x = 1/*</bind>*/; } } ")); static void verify(DataFlowAnalysis analysis) { Assert.Equal("x", GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Equal("x", GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenOutside)); } } [Fact] public void PrimaryConstructors_18() { verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) : A(/*<bind>*/x = 1/*</bind>*/) { } class A(int x); ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) : A(/*<bind>*/x = 1/*</bind>*/) { int M() => x; } class A(int x); ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B : A { B(int x) : base(/*<bind>*/x = 1/*</bind>*/) { } } class A(int x); "), null); static void verify(DataFlowAnalysis analysis, string dataFlowsOut = "x") { Assert.Equal("x", GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Equal(dataFlowsOut, GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("this, x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry, sort: true)); Assert.Equal("this, x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit, sort: true)); Assert.Null(GetSymbolNamesJoined(analysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Equal("x", GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("this, x", GetSymbolNamesJoined(analysis.WrittenOutside, sort: true)); } } [Fact] public void PrimaryConstructors_19() { verify(CompileAndAnalyzeDataFlowExpression(@" class B(out int x) : A(/*<bind>*/x = 1/*</bind>*/) { } class A(int x); ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(out int x) : A(/*<bind>*/x = 1/*</bind>*/) { int M() => x; } class A(int x); ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B : A { B(out int x) : base(/*<bind>*/x = 1/*</bind>*/) { } } class A(int x); ")); static void verify(DataFlowAnalysis analysis) { Assert.Equal("x", GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("this", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry, sort: true)); Assert.Equal("this, x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit, sort: true)); Assert.Null(GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Equal("x", GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("this", GetSymbolNamesJoined(analysis.WrittenOutside, sort: true)); } } [Fact] public void PrimaryConstructors_20() { verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { void X(int y) { Y(1); int Y(int z) => /*<bind>*/x/*</bind>*/; } } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { void X(int y) { Y(1); static int Y(int z) => /*<bind>*/x/*</bind>*/; } } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { void X(int y) { _ = (int z) => /*<bind>*/x/*</bind>*/; } } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { void X(int y) { _ = static (int z) => /*<bind>*/x/*</bind>*/; } } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { B(string y) : this(1) { Y(1); int Y(int z) => /*<bind>*/x/*</bind>*/; } } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { B(string y) : this(1) { Y(1); static int Y(int z) => /*<bind>*/x/*</bind>*/; } } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { B(string y) : this(1) { _ = (int z) => /*<bind>*/x/*</bind>*/; } } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { B(string y) : this(1) { _ = static (int z) => /*<bind>*/x/*</bind>*/; } } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { B(string y) : this((int z) => /*<bind>*/x/*</bind>*/) {} B(System.Action<int> x) : this(1) {} } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { B(string y) : this(static (int z) => /*<bind>*/x/*</bind>*/) {} B(System.Action<int> x) : this(1) {} } ")); static void verify(DataFlowAnalysis analysis) { Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("x", GetSymbolNamesJoined(analysis.Captured)); Assert.Equal("x", GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("this, x, y, z", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry, sort: true)); Assert.Equal("this, x, y, z", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit, sort: true)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("this, x, y, z", GetSymbolNamesJoined(analysis.WrittenOutside, sort: true)); } } [Fact] public void PrimaryConstructors_21() { verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { static void X(int y) { Y(1); int Y(int z) => /*<bind>*/x/*</bind>*/; } } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { static void X(int y) { Y(1); static int Y(int z) => /*<bind>*/x/*</bind>*/; } } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { static void X(int y) { _ = (int z) => /*<bind>*/x/*</bind>*/; } } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { static void X(int y) { _ = static (int z) => /*<bind>*/x/*</bind>*/; } } ")); static void verify(DataFlowAnalysis analysis) { Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("x", GetSymbolNamesJoined(analysis.Captured)); Assert.Equal("x", GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("y, z", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("y, z", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("y, z", GetSymbolNamesJoined(analysis.WrittenOutside)); } } [Fact] public void PrimaryConstructors_22() { verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { System.Func<int, int> X = (int z) => /*<bind>*/x/*</bind>*/; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { System.Func<int, int> X { get; } = (int z) => /*<bind>*/x/*</bind>*/; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { event System.Func<int, int> X = (int z) => /*<bind>*/x/*</bind>*/; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { System.Func<int, int> X = static (int z) => /*<bind>*/x/*</bind>*/; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { System.Func<int, int> X { get; } = static (int z) => /*<bind>*/x/*</bind>*/; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { event System.Func<int, int> X = static (int z) => /*<bind>*/x/*</bind>*/; } ")); static void verify(DataFlowAnalysis analysis) { Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("x", GetSymbolNamesJoined(analysis.Captured)); Assert.Equal("x", GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x, z", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x, z", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x, z", GetSymbolNamesJoined(analysis.WrittenOutside)); } } [Fact] public void PrimaryConstructors_23() { verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { static System.Func<int, int> X = (int z) => /*<bind>*/x/*</bind>*/; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { static System.Func<int, int> X { get; } = (int z) => /*<bind>*/x/*</bind>*/; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { static event System.Func<int, int> X = (int z) => /*<bind>*/x/*</bind>*/; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { static System.Func<int, int> X = static (int z) => /*<bind>*/x/*</bind>*/; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { static System.Func<int, int> X { get; } = static (int z) => /*<bind>*/x/*</bind>*/; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { static event System.Func<int, int> X = static (int z) => /*<bind>*/x/*</bind>*/; } ")); static void verify(DataFlowAnalysis analysis) { Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("x", GetSymbolNamesJoined(analysis.Captured)); Assert.Equal("x", GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("z", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("z", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("z", GetSymbolNamesJoined(analysis.WrittenOutside)); } } [Fact] public void PrimaryConstructors_24() { verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) : A((int z) => /*<bind>*/x/*</bind>*/) { } class A(System.Func<int, int> x); ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) : A(static (int z) => /*<bind>*/x/*</bind>*/) { } class A(System.Func<int, int> x); ")); static void verify(DataFlowAnalysis analysis) { Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("x", GetSymbolNamesJoined(analysis.Captured)); Assert.Equal("x", GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("this, x, z", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry, sort: true)); Assert.Equal("this, x, z", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit, sort: true)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("this, x, z", GetSymbolNamesJoined(analysis.WrittenOutside, sort: true)); } } [Fact] public void PrimaryConstructors_25() { verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { void X(int y) { Y(1); void Y(int z1) { _ = (int z2) => /*<bind>*/x/*</bind>*/; } } } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { void X(int y) { Y(1); static void Y(int z1) { _ = static (int z2) => /*<bind>*/x/*</bind>*/; } } } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { void X(int y) { _ = (int z1) => { Y(1); int Y(int z2) => /*<bind>*/x/*</bind>*/; } } } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { void X(int y) { _ = static (int z1) => { Y(1); static int Y(int z2) => /*<bind>*/x/*</bind>*/; } } } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { B(string y) : this(1) { Y(1); void Y(int z1) { _ = (int z2) => /*<bind>*/x/*</bind>*/; } } } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { B(string y) : this(1) { Y(1); static void Y(int z1) { _ = static (int z2) => /*<bind>*/x/*</bind>*/; } } } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { B(string y) : this(1) { _ = (int z1) => { Y(1); int Y(int z2) => /*<bind>*/x/*</bind>*/; } } } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { B(string y) : this(1) { _ = static (int z1) => { Y(1); static int Y(int z2) => /*<bind>*/x/*</bind>*/; } } } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { B(string y) : this((int z1) => { Y(1); int Y(int z2) => /*<bind>*/x/*</bind>*/; }) {} B(System.Action<int> x) : this(1) {} } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { B(string y) : this(static (int z1) => { Y(1); static int Y(int z2) => /*<bind>*/x/*</bind>*/; }) {} B(System.Action<int> x) : this(1) {} } ")); static void verify(DataFlowAnalysis analysis) { Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("x", GetSymbolNamesJoined(analysis.Captured)); Assert.Equal("x", GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("this, x, y, z1, z2", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry, sort: true)); Assert.Equal("this, x, y, z1, z2", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit, sort: true)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("this, x, y, z1, z2", GetSymbolNamesJoined(analysis.WrittenOutside, sort: true)); } } [Fact] public void PrimaryConstructors_26() { verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { static void X(int y) { Y(1); void Y(int z1) { _ = (int z2) => /*<bind>*/x/*</bind>*/; } } } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { static void X(int y) { Y(1); static void Y(int z1) { _ = static (int z2) => /*<bind>*/x/*</bind>*/; } } } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { static void X(int y) { _ = (int z1) => { Y(1); int Y(int z2) => /*<bind>*/x/*</bind>*/; } } } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { static void X(int y) { _ = static (int z1) => { Y(1); static int Y(int z2) => /*<bind>*/x/*</bind>*/; } } } ")); static void verify(DataFlowAnalysis analysis) { Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("x", GetSymbolNamesJoined(analysis.Captured)); Assert.Equal("x", GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("y, z1, z2", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("y, z1, z2", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("y, z1, z2", GetSymbolNamesJoined(analysis.WrittenOutside)); } } [Fact] public void PrimaryConstructors_27() { verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { System.Action<int> X = (int z1) => { Y(1); int Y(int z2) => /*<bind>*/x/*</bind>*/; }; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { System.Action<int> X { get; } = (int z1) => { Y(1); int Y(int z2) => /*<bind>*/x/*</bind>*/; }; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { event System.Action<int> X = (int z1) => { Y(1); int Y(int z2) => /*<bind>*/x/*</bind>*/; }; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { System.Action<int> X = (int z1) => { Y(1); static int Y(int z2) => /*<bind>*/x/*</bind>*/; }; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { System.Action<int> X { get; } = (int z1) => { Y(1); static int Y(int z2) => /*<bind>*/x/*</bind>*/; }; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { event System.Action<int> X = (int z1) => { Y(1); static int Y(int z2) => /*<bind>*/x/*</bind>*/; }; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { System.Action<int> X = static (int z1) => { Y(1); int Y(int z2) => /*<bind>*/x/*</bind>*/; }; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { System.Action<int> X { get; } = static (int z1) => { Y(1); int Y(int z2) => /*<bind>*/x/*</bind>*/; }; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { event System.Action<int> X = static (int z1) => { Y(1); int Y(int z2) => /*<bind>*/x/*</bind>*/; }; } ")); static void verify(DataFlowAnalysis analysis) { Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("x", GetSymbolNamesJoined(analysis.Captured)); Assert.Equal("x", GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x, z1, z2", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x, z1, z2", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x, z1, z2", GetSymbolNamesJoined(analysis.WrittenOutside)); } } [Fact] public void PrimaryConstructors_28() { verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { static System.Action<int> X = (int z1) => { Y(1); int Y(int z2) => /*<bind>*/x/*</bind>*/; }; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { static System.Action<int> X { get; } = (int z1) => { Y(1); int Y(int z2) => /*<bind>*/x/*</bind>*/; }; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { static event System.Action<int> X = (int z1) => { Y(1); int Y(int z2) => /*<bind>*/x/*</bind>*/; }; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { static System.Action<int> X = (int z1) => { Y(1); static int Y(int z2) => /*<bind>*/x/*</bind>*/; }; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { static System.Action<int> X { get; } = (int z1) => { Y(1); static int Y(int z2) => /*<bind>*/x/*</bind>*/; }; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { static event System.Action<int> X = (int z1) => { Y(1); static int Y(int z2) => /*<bind>*/x/*</bind>*/; }; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { static System.Action<int> X = static (int z1) => { Y(1); int Y(int z2) => /*<bind>*/x/*</bind>*/; }; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { static System.Action<int> X { get; } = static (int z1) => { Y(1); int Y(int z2) => /*<bind>*/x/*</bind>*/; }; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) { static event System.Action<int> X = static (int z1) => { Y(1); int Y(int z2) => /*<bind>*/x/*</bind>*/; }; } ")); static void verify(DataFlowAnalysis analysis) { Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("x", GetSymbolNamesJoined(analysis.Captured)); Assert.Equal("x", GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("z1, z2", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("z1, z2", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("z1, z2", GetSymbolNamesJoined(analysis.WrittenOutside)); } } [Fact] public void PrimaryConstructors_29() { verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) : A((int z1) => { Y(1); int Y(int z2) => /*<bind>*/x/*</bind>*/; }) { } class A(System.Action<int> x); ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) : A(static (int z1) => { Y(1); int Y(int z2) => /*<bind>*/x/*</bind>*/; }) { } class A(System.Action<int> x); ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(int x) : A((int z1) => { Y(1); static int Y(int z2) => /*<bind>*/x/*</bind>*/; }) { } class A(System.Action<int> x); ")); static void verify(DataFlowAnalysis analysis) { Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("x", GetSymbolNamesJoined(analysis.Captured)); Assert.Equal("x", GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("this, x, z1, z2", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry, sort: true)); Assert.Equal("this, x, z1, z2", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit, sort: true)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("this, x, z1, z2", GetSymbolNamesJoined(analysis.WrittenOutside, sort: true)); } } [Fact] public void PrimaryConstructors_30() { verify(CompileAndAnalyzeDataFlowExpression(@" class B(out int x) { int Y = x = 2; System.Action<int> X = (int z) => /*<bind>*/x = 1/*</bind>*/; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(out int x) { int Y = x = 2; System.Action<int> X { get; } = (int z) => /*<bind>*/x = 1/*</bind>*/; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(out int x) { int Y = x = null; event System.Action<int> X = (int z) => /*<bind>*/x = 1/*</bind>*/; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(out int x) { int Y = x = 2; System.Action<int> X = static (int z) => /*<bind>*/x = 1/*</bind>*/; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(out int x) { int Y = x = 2; System.Action<int> X { get; } = static (int z) => /*<bind>*/x = 1/*</bind>*/; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(out int x) { int Y = x = null; event System.Action<int> X = static (int z) => /*<bind>*/x = 1/*</bind>*/; } ")); static void verify(DataFlowAnalysis analysis) { Assert.Equal("x", GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("x", GetSymbolNamesJoined(analysis.Captured)); Assert.Equal("x", GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("z", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x, z", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Equal("x", GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("z", GetSymbolNamesJoined(analysis.WrittenOutside)); } } [Fact] public void PrimaryConstructors_31() { verify(CompileAndAnalyzeDataFlowExpression(@" class B(out int x) { int Y = x = 2; System.Action<int> X = (int z1) => { Y(1); int Y(int z2) => /*<bind>*/x = 1/*</bind>*/; }; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(out int x) { int Y = x = 2; System.Action<int> X { get; } = (int z1) => { Y(1); int Y(int z2) => /*<bind>*/x = 1/*</bind>*/; }; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(out int x) { int Y = x = null; event System.Action<int> X = (int z1) => { Y(1); int Y(int z2) => /*<bind>*/x = 1/*</bind>*/; }; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(out int x) { int Y = x = 2; System.Action<int> X = static (int z1) => { Y(1); int Y(int z2) => /*<bind>*/x = 1/*</bind>*/; }; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(out int x) { int Y = x = 2; System.Action<int> X { get; } = static (int z1) => { Y(1); int Y(int z2) => /*<bind>*/x = 1/*</bind>*/; }; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(out int x) { int Y = x = null; event System.Action<int> X = static (int z1) => { Y(1); int Y(int z2) => /*<bind>*/x = 1/*</bind>*/; }; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(out int x) { int Y = x = 2; System.Action<int> X = (int z1) => { Y(1); static int Y(int z2) => /*<bind>*/x = 1/*</bind>*/; }; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(out int x) { int Y = x = 2; System.Action<int> X { get; } = (int z1) => { Y(1); static int Y(int z2) => /*<bind>*/x = 1/*</bind>*/; }; } ")); verify(CompileAndAnalyzeDataFlowExpression(@" class B(out int x) { int Y = x = null; event System.Action<int> X = (int z1) => { Y(1); static int Y(int z2) => /*<bind>*/x = 1/*</bind>*/; }; } ")); static void verify(DataFlowAnalysis analysis) { Assert.Equal("x", GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("x", GetSymbolNamesJoined(analysis.Captured)); Assert.Equal("x", GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("z1, z2", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x, z1, z2", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Equal("x", GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("z1, z2", GetSymbolNamesJoined(analysis.WrittenOutside)); } } private const string InlineArray1Definition = @" [System.Runtime.CompilerServices.InlineArray(1)] public struct Buffer1 { private int _element0; } "; private const string InlineArray2Definition = @" [System.Runtime.CompilerServices.InlineArray(2)] public struct Buffer2 { private int _element0; } "; private const string InlineArray22Definition = @" [System.Runtime.CompilerServices.InlineArray(2)] public struct Buffer22 { private Buffer2 _element0; } " + InlineArray2Definition; [Theory] [CombinatorialData] public void InlineArrays_010(bool isRef, [CombinatorialValues(0, 1)] int index) { DataFlowAnalysis analysis = CompileAndAnalyzeDataFlowExpression( @" class B { static void M(" + (isRef ? "ref " : "") + @"Buffer2 x) { /*<bind>*/x[" + index + @"] = 1/*</bind>*/; } } " + InlineArray2Definition, TargetFramework.Net80); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsIn)); if (isRef) { Assert.Equal("x", GetSymbolNamesJoined(analysis.DataFlowsOut)); } else { Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); } Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(analysis.ReadInside)); if (isRef) { Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadOutside)); } else { Assert.Null(GetSymbolNamesJoined(analysis.ReadOutside)); } Assert.Equal("x", GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Theory] [CombinatorialData] public void InlineArrays_011([CombinatorialValues(0, 1)] int index) { DataFlowAnalysis analysis = CompileAndAnalyzeDataFlowExpression( @" class B { static void M(Buffer2 x) { var d = () => /*<bind>*/x[" + index + @"] = 1/*</bind>*/; } } " + InlineArray2Definition, TargetFramework.Net80); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("x", GetSymbolNamesJoined(analysis.Captured)); Assert.Equal("x", GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(analysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Equal("x", GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x, d", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Theory] [CombinatorialData] public void InlineArrays_020(bool isRef, [CombinatorialValues(0, 1)] int index) { DataFlowAnalysis analysis = CompileAndAnalyzeDataFlowExpression( @" class B { static void M(" + (isRef ? "ref " : "") + @"Buffer22 x) { /*<bind>*/x[" + index + @"][" + index + @"] = 1/*</bind>*/; } } " + InlineArray22Definition, TargetFramework.Net80); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsIn)); if (isRef) { Assert.Equal("x", GetSymbolNamesJoined(analysis.DataFlowsOut)); } else { Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); } Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(analysis.ReadInside)); if (isRef) { Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadOutside)); } else { Assert.Null(GetSymbolNamesJoined(analysis.ReadOutside)); } Assert.Equal("x", GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Theory] [CombinatorialData] public void InlineArrays_030(bool isRef, [CombinatorialValues(0, 1)] int index) { DataFlowAnalysis analysis = CompileAndAnalyzeDataFlowExpression( @" class B { static void M(" + (isRef ? "ref " : "") + @"Buffer2 x, int i) { /*<bind>*/x[" + index + @"] = 1/*</bind>*/; _ = x[i]; } } " + InlineArray2Definition, TargetFramework.Net80); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x, i", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x, i", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal("x, i", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Equal("x", GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x, i", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Theory] [CombinatorialData] public void InlineArrays_040(bool isRef, [CombinatorialValues(0, 1)] int index) { DataFlowAnalysis analysis = CompileAndAnalyzeDataFlowExpression( @" class B { static void M(" + (isRef ? "ref " : "") + @"Buffer22 x, int i) { /*<bind>*/x[" + index + @"][" + index + @"] = 1/*</bind>*/; _ = x[i][i]; } } " + InlineArray22Definition, TargetFramework.Net80); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x, i", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x, i", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal("x, i", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Equal("x", GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x, i", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Theory] [CombinatorialData] public void InlineArrays_050(bool isRef, [CombinatorialValues(0, 1)] int index) { DataFlowAnalysis analysis = CompileAndAnalyzeDataFlowExpression( @" class B { static void M(" + (isRef ? "ref " : "") + @"Buffer2 x) { ref int y = ref /*<bind>*/x[" + index + @"]/*</bind>*/; y++; } } " + InlineArray2Definition, TargetFramework.Net80); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Equal("x", GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Theory] [CombinatorialData] public void InlineArrays_051(bool isRef, [CombinatorialValues(0, 1)] int index) { DataFlowAnalysis analysis = CompileAndAnalyzeDataFlowExpression( @" class B { static void M(" + (isRef ? "ref " : "") + @"Buffer2 x) { ref int y = ref /*<bind>*/x/*</bind>*/[" + index + @"]; y++; } } " + InlineArray2Definition, TargetFramework.Net80); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Equal("x", GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Theory] [CombinatorialData] public void InlineArrays_052(bool isRef, [CombinatorialValues(0, 1)] int index) { DataFlowAnalysis analysis = CompileAndAnalyzeDataFlowExpression( @" class B { static void M(" + (isRef ? "ref " : "") + @"Buffer2 x) { ref int y = ref x[/*<bind>*/" + index + @"/*</bind>*/]; y++; } } " + InlineArray2Definition, TargetFramework.Net80); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Theory] [CombinatorialData] public void InlineArrays_060(bool isRef, [CombinatorialValues(0, 1)] int index) { DataFlowAnalysis analysis = CompileAndAnalyzeDataFlowExpression( @" class B { static void M(" + (isRef ? "ref " : "") + @"Buffer22 x) { ref int y = ref /*<bind>*/x[" + index + @"][" + index + @"]/*</bind>*/; y++; } } " + InlineArray22Definition, TargetFramework.Net80); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Equal("x", GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Theory] [CombinatorialData] public void InlineArrays_061(bool isRef, [CombinatorialValues(0, 1)] int index) { DataFlowAnalysis analysis = CompileAndAnalyzeDataFlowExpression( @" class B { static void M(" + (isRef ? "ref " : "") + @"Buffer22 x) { ref int y = ref /*<bind>*/x[" + index + @"]/*</bind>*/[" + index + @"]; y++; } } " + InlineArray22Definition, TargetFramework.Net80); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Equal("x", GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Theory] [CombinatorialData] public void InlineArrays_062(bool isRef, [CombinatorialValues(0, 1)] int index) { DataFlowAnalysis analysis = CompileAndAnalyzeDataFlowExpression( @" class B { static void M(" + (isRef ? "ref " : "") + @"Buffer22 x) { ref int y = ref /*<bind>*/x/*</bind>*/[" + index + @"][" + index + @"]; y++; } } " + InlineArray22Definition, TargetFramework.Net80); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Equal("x", GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Theory] [CombinatorialData] public void InlineArrays_063(bool isRef, [CombinatorialValues(0, 1)] int index) { DataFlowAnalysis analysis = CompileAndAnalyzeDataFlowExpression( @" class B { static void M(" + (isRef ? "ref " : "") + @"Buffer22 x) { ref int y = ref x[/*<bind>*/" + index + @"/*</bind>*/][" + index + @"]; y++; } } " + InlineArray22Definition, TargetFramework.Net80); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Theory] [CombinatorialData] public void InlineArrays_064(bool isRef, [CombinatorialValues(0, 1)] int index) { DataFlowAnalysis analysis = CompileAndAnalyzeDataFlowExpression( @" class B { static void M(" + (isRef ? "ref " : "") + @"Buffer22 x) { ref int y = ref x[" + index + @"][/*<bind>*/" + index + @"/*</bind>*/]; y++; } } " + InlineArray22Definition, TargetFramework.Net80); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Theory] [CombinatorialData] public void InlineArrays_070([CombinatorialValues("ref ", "in ", "")] string refModifier, [CombinatorialValues(0, 1)] int index) { DataFlowAnalysis analysis = CompileAndAnalyzeDataFlowExpression( @" class B { static void M(" + refModifier + @"Buffer2 x) { ref readonly int y = ref /*<bind>*/x[" + index + @"]/*</bind>*/; _ = y; } } " + InlineArray2Definition, TargetFramework.Net80); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal(refModifier != "" ? "x, y" : "y", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Equal("x", GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Theory] [CombinatorialData] public void InlineArrays_071([CombinatorialValues("ref ", "in ", "")] string refModifier, [CombinatorialValues(0, 1)] int index) { DataFlowAnalysis analysis = CompileAndAnalyzeDataFlowExpression( @" class B { static void M(" + refModifier + @"Buffer2 x) { ref readonly int y = ref /*<bind>*/x/*</bind>*/[" + index + @"]; _ = y; } } " + InlineArray2Definition, TargetFramework.Net80); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal(refModifier != "" ? "x, y" : "y", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Equal("x", GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Theory] [CombinatorialData] public void InlineArrays_072([CombinatorialValues("ref ", "in ", "")] string refModifier, [CombinatorialValues(0, 1)] int index) { DataFlowAnalysis analysis = CompileAndAnalyzeDataFlowExpression( @" class B { static void M(" + refModifier + @"Buffer2 x) { ref readonly int y = ref x[/*<bind>*/" + index + @"/*</bind>*/]; _ = y; } } " + InlineArray2Definition, TargetFramework.Net80); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Theory] [CombinatorialData] public void InlineArrays_080([CombinatorialValues("ref ", "in ", "")] string refModifier, [CombinatorialValues(0, 1)] int index) { DataFlowAnalysis analysis = CompileAndAnalyzeDataFlowExpression( @" class B { static void M(" + refModifier + @"Buffer22 x) { ref readonly int y = ref /*<bind>*/x[" + index + @"][" + index + @"]/*</bind>*/; _ = y; } } " + InlineArray22Definition, TargetFramework.Net80); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal(refModifier != "" ? "x, y" : "y", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Equal("x", GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Theory] [CombinatorialData] public void InlineArrays_081([CombinatorialValues("ref ", "in ", "")] string refModifier, [CombinatorialValues(0, 1)] int index) { DataFlowAnalysis analysis = CompileAndAnalyzeDataFlowExpression( @" class B { static void M(" + refModifier + @"Buffer22 x) { ref readonly int y = ref /*<bind>*/x[" + index + @"]/*</bind>*/[" + index + @"]; _ = y; } } " + InlineArray22Definition, TargetFramework.Net80); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal(refModifier != "" ? "x, y" : "y", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Equal("x", GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Theory] [CombinatorialData] public void InlineArrays_082([CombinatorialValues("ref ", "in ", "")] string refModifier, [CombinatorialValues(0, 1)] int index) { DataFlowAnalysis analysis = CompileAndAnalyzeDataFlowExpression( @" class B { static void M(" + refModifier + @"Buffer22 x) { ref readonly int y = ref /*<bind>*/x/*</bind>*/[" + index + @"][" + index + @"]; _ = y; } } " + InlineArray22Definition, TargetFramework.Net80); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal(refModifier != "" ? "x, y" : "y", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Equal("x", GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Theory] [CombinatorialData] public void InlineArrays_083([CombinatorialValues("ref ", "in ", "")] string refModifier, [CombinatorialValues(0, 1)] int index) { DataFlowAnalysis analysis = CompileAndAnalyzeDataFlowExpression( @" class B { static void M(" + refModifier + @"Buffer22 x) { ref readonly int y = ref x[/*<bind>*/" + index + @"/*</bind>*/][" + index + @"]; _ = y; } } " + InlineArray22Definition, TargetFramework.Net80); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Theory] [CombinatorialData] public void InlineArrays_084([CombinatorialValues("ref ", "in ", "")] string refModifier, [CombinatorialValues(0, 1)] int index) { DataFlowAnalysis analysis = CompileAndAnalyzeDataFlowExpression( @" class B { static void M(" + refModifier + @"Buffer22 x) { ref readonly int y = ref x[" + index + @"][/*<bind>*/" + index + @"/*</bind>*/]; _ = y; } } " + InlineArray22Definition, TargetFramework.Net80); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Theory] [CombinatorialData] public void InlineArrays_090([CombinatorialValues(0, 1)] int index) { DataFlowAnalysis analysis = CompileAndAnalyzeDataFlowExpression( @" class B { static void M() { Buffer2 x; /*<bind>*/x[" + index + @"] = 1/*</bind>*/; } } " + InlineArray2Definition, TargetFramework.Net80); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Null(GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(analysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Equal("x", GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenOutside)); } [Theory] [CombinatorialData] public void InlineArrays_091([CombinatorialValues(0, 1)] int index) { DataFlowAnalysis analysis = CompileAndAnalyzeDataFlowExpression( @" class B { static void M() { Buffer2 x = default; /*<bind>*/x[" + index + @"].F += 1/*</bind>*/; } } [System.Runtime.CompilerServices.InlineArray(2)] public struct Buffer2 { private S _element0; } struct S { public int F; } ", TargetFramework.Net80); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Equal("x", GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Fact] public void InlineArrays_100() { DataFlowAnalysis analysis = CompileAndAnalyzeDataFlowExpression( @" class B { static void M() { Buffer1 x; /*<bind>*/x[0] = 1/*</bind>*/; } } " + InlineArray1Definition, TargetFramework.Net80); Assert.Equal("x", GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Null(GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(analysis.ReadInside)); Assert.Null(GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Equal("x", GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenOutside)); } [Theory] [CombinatorialData] public void InlineArrays_110([CombinatorialValues("ref ", "in ", "")] string refModifier, [CombinatorialValues(0, 1)] int index) { DataFlowAnalysis analysis = CompileAndAnalyzeDataFlowExpression( @" class B { static void M(" + refModifier + @"Buffer2 x) { int y = /*<bind>*/x[" + index + @"]/*</bind>*/; _ = y; } } " + InlineArray2Definition, TargetFramework.Net80); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal(refModifier != "" ? "x, y" : "y", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Theory] [CombinatorialData] public void InlineArrays_111([CombinatorialValues("ref ", "in ", "")] string refModifier, [CombinatorialValues(0, 1)] int index) { DataFlowAnalysis analysis = CompileAndAnalyzeDataFlowExpression( @" class B { static void M(" + refModifier + @"Buffer2 x) { int y = /*<bind>*/x/*</bind>*/[" + index + @"]; _ = y; } } " + InlineArray2Definition, TargetFramework.Net80); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal(refModifier != "" ? "x, y" : "y", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Theory] [CombinatorialData] public void InlineArrays_112([CombinatorialValues("ref ", "in ", "")] string refModifier, [CombinatorialValues(0, 1)] int index) { DataFlowAnalysis analysis = CompileAndAnalyzeDataFlowExpression( @" class B { static void M(" + refModifier + @"Buffer2 x) { int y = x[/*<bind>*/" + index + @"/*</bind>*/]; _ = y; } } " + InlineArray2Definition, TargetFramework.Net80); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Theory] [CombinatorialData] public void InlineArrays_113([CombinatorialValues(0, 1)] int index) { DataFlowAnalysis analysis = CompileAndAnalyzeDataFlowExpression( @" class B { static void M(Buffer2 x) { System.Action d = () => { int y = /*<bind>*/x[" + index + @"]/*</bind>*/; _ = y; }; } } " + InlineArray2Definition, TargetFramework.Net80); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("x", GetSymbolNamesJoined(analysis.Captured)); Assert.Equal("x", GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal("y", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x, d, y", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Theory] [CombinatorialData] public void InlineArrays_120([CombinatorialValues("ref ", "in ", "")] string refModifier, [CombinatorialValues(0, 1)] int index) { DataFlowAnalysis analysis = CompileAndAnalyzeDataFlowExpression( @" class B { static void M(" + refModifier + @"Buffer22 x) { int y = /*<bind>*/x[" + index + @"][" + index + @"]/*</bind>*/; _ = y; } } " + InlineArray22Definition, TargetFramework.Net80); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal(refModifier != "" ? "x, y" : "y", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Theory] [CombinatorialData] public void InlineArrays_121([CombinatorialValues("ref ", "in ", "")] string refModifier, [CombinatorialValues(0, 1)] int index) { DataFlowAnalysis analysis = CompileAndAnalyzeDataFlowExpression( @" class B { static void M(" + refModifier + @"Buffer22 x) { int y = /*<bind>*/x[" + index + @"]/*</bind>*/[" + index + @"]; _ = y; } } " + InlineArray22Definition, TargetFramework.Net80); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal(refModifier != "" ? "x, y" : "y", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Theory] [CombinatorialData] public void InlineArrays_122([CombinatorialValues("ref ", "in ", "")] string refModifier, [CombinatorialValues(0, 1)] int index) { DataFlowAnalysis analysis = CompileAndAnalyzeDataFlowExpression( @" class B { static void M(" + refModifier + @"Buffer22 x) { int y = /*<bind>*/x/*</bind>*/[" + index + @"][" + index + @"]; _ = y; } } " + InlineArray22Definition, TargetFramework.Net80); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal(refModifier != "" ? "x, y" : "y", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Theory] [CombinatorialData] public void InlineArrays_123([CombinatorialValues("ref ", "in ", "")] string refModifier, [CombinatorialValues(0, 1)] int index) { DataFlowAnalysis analysis = CompileAndAnalyzeDataFlowExpression( @" class B { static void M(" + refModifier + @"Buffer22 x) { int y = x[/*<bind>*/" + index + @"/*</bind>*/][" + index + @"]; _ = y; } } " + InlineArray22Definition, TargetFramework.Net80); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Theory] [CombinatorialData] public void InlineArrays_124([CombinatorialValues("ref ", "in ", "")] string refModifier, [CombinatorialValues(0, 1)] int index) { DataFlowAnalysis analysis = CompileAndAnalyzeDataFlowExpression( @" class B { static void M(" + refModifier + @"Buffer22 x) { int y = x[" + index + @"][/*<bind>*/" + index + @"/*</bind>*/]; _ = y; } } " + InlineArray22Definition, TargetFramework.Net80); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Theory] [CombinatorialData] public void InlineArrays_130([CombinatorialValues("ref ", "in ", "")] string refModifier) { DataFlowAnalysis analysis = CompileAndAnalyzeDataFlowExpression( @" class B { static void M(" + refModifier + @"Buffer2 x) { var y = /*<bind>*/x[0..2]/*</bind>*/; _ = y; } } " + InlineArray2Definition, TargetFramework.Net80); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal(refModifier != "" ? "x, y" : "y", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Theory] [CombinatorialData] public void InlineArrays_131([CombinatorialValues("ref ", "in ", "")] string refModifier) { DataFlowAnalysis analysis = CompileAndAnalyzeDataFlowExpression( @" class B { static void M(" + refModifier + @"Buffer2 x) { var y = /*<bind>*/x/*</bind>*/[0..2]; _ = y; } } " + InlineArray2Definition, TargetFramework.Net80); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal(refModifier != "" ? "x, y" : "y", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Theory] [CombinatorialData] public void InlineArrays_132([CombinatorialValues("ref ", "in ", "")] string refModifier) { DataFlowAnalysis analysis = CompileAndAnalyzeDataFlowExpression( @" class B { static void M(" + refModifier + @"Buffer2 x) { var y = x[/*<bind>*/0..2/*</bind>*/]; _ = y; } } " + InlineArray2Definition, TargetFramework.Net80); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Fact] public void InlineArrays_133() { DataFlowAnalysis analysis = CompileAndAnalyzeDataFlowExpression( @" class B { static void M(Buffer2 x) { System.Action d = () => { var y = /*<bind>*/x[0..2]/*</bind>*/; _ = y; }; } } " + InlineArray2Definition, TargetFramework.Net80); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("x", GetSymbolNamesJoined(analysis.Captured)); Assert.Equal("x", GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal("y", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x, d, y", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Theory] [CombinatorialData] public void InlineArrays_140([CombinatorialValues("ref ", "in ", "")] string refModifier, [CombinatorialValues(0, 1)] int index) { DataFlowAnalysis analysis = CompileAndAnalyzeDataFlowExpression( @" class B { static void M(" + refModifier + @"Buffer22 x) { var y = /*<bind>*/x[" + index + @"][0..2]/*</bind>*/; _ = y; } } " + InlineArray22Definition, TargetFramework.Net80); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal(refModifier != "" ? "x, y" : "y", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Theory] [CombinatorialData] public void InlineArrays_141([CombinatorialValues("ref ", "in ", "")] string refModifier, [CombinatorialValues(0, 1)] int index) { DataFlowAnalysis analysis = CompileAndAnalyzeDataFlowExpression( @" class B { static void M(" + refModifier + @"Buffer22 x) { var y = /*<bind>*/x[" + index + @"]/*</bind>*/[0..2]; _ = y; } } " + InlineArray22Definition, TargetFramework.Net80); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal(refModifier != "" ? "x, y" : "y", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Theory] [CombinatorialData] public void InlineArrays_142([CombinatorialValues("ref ", "in ", "")] string refModifier, [CombinatorialValues(0, 1)] int index) { DataFlowAnalysis analysis = CompileAndAnalyzeDataFlowExpression( @" class B { static void M(" + refModifier + @"Buffer22 x) { var y = /*<bind>*/x/*</bind>*/[" + index + @"][0..2]; _ = y; } } " + InlineArray22Definition, TargetFramework.Net80); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal(refModifier != "" ? "x, y" : "y", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Theory] [CombinatorialData] public void InlineArrays_143([CombinatorialValues("ref ", "in ", "")] string refModifier, [CombinatorialValues(0, 1)] int index) { DataFlowAnalysis analysis = CompileAndAnalyzeDataFlowExpression( @" class B { static void M(" + refModifier + @"Buffer22 x) { var y = x[/*<bind>*/" + index + @"/*</bind>*/][0..2]; _ = y; } } " + InlineArray22Definition, TargetFramework.Net80); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Theory] [CombinatorialData] public void InlineArrays_144([CombinatorialValues("ref ", "in ", "")] string refModifier, [CombinatorialValues(0, 1)] int index) { DataFlowAnalysis analysis = CompileAndAnalyzeDataFlowExpression( @" class B { static void M(" + refModifier + @"Buffer22 x) { var y = x[" + index + @"][/*<bind>*/0..2/*</bind>*/]; _ = y; } } " + InlineArray22Definition, TargetFramework.Net80); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Theory] [CombinatorialData] public void InlineArrays_150([CombinatorialValues("ref ", "in ", "")] string refModifier, bool readOnly) { if (refModifier == "in " && !readOnly) { return; } DataFlowAnalysis analysis = CompileAndAnalyzeDataFlowExpression( @" class B { static void M(" + refModifier + @"Buffer2 x) { var y = (System." + (readOnly ? "ReadOnly" : "") + @"Span<int>)/*<bind>*/x/*</bind>*/; _ = y; } } " + InlineArray2Definition, TargetFramework.Net80); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal(refModifier != "" ? "x, y" : "y", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Theory] [CombinatorialData] public void InlineArrays_153(bool readOnly) { DataFlowAnalysis analysis = CompileAndAnalyzeDataFlowExpression( @" class B { static void M(Buffer2 x) { System.Action d = () => { var y = (System." + (readOnly ? "ReadOnly" : "") + @"Span<int>)/*<bind>*/x/*</bind>*/; _ = y; }; } } " + InlineArray2Definition, TargetFramework.Net80); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Equal("x", GetSymbolNamesJoined(analysis.Captured)); Assert.Equal("x", GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal("y", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x, d, y", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Theory] [CombinatorialData] public void InlineArrays_160([CombinatorialValues("ref ", "in ", "")] string refModifier, [CombinatorialValues(0, 1)] int index, bool readOnly) { if (refModifier == "in " && !readOnly) { return; } DataFlowAnalysis analysis = CompileAndAnalyzeDataFlowExpression( @" class B { static void M(" + refModifier + @"Buffer22 x) { var y = (System." + (readOnly ? "ReadOnly" : "") + @"Span<int>)/*<bind>*/x[" + index + @"]/*</bind>*/; _ = y; } } " + InlineArray22Definition, TargetFramework.Net80); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal(refModifier != "" ? "x, y" : "y", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Theory] [CombinatorialData] public void InlineArrays_162([CombinatorialValues("ref ", "in ", "")] string refModifier, [CombinatorialValues(0, 1)] int index, bool readOnly) { if (refModifier == "in " && !readOnly) { return; } DataFlowAnalysis analysis = CompileAndAnalyzeDataFlowExpression( @" class B { static void M(" + refModifier + @"Buffer22 x) { var y = (System." + (readOnly ? "ReadOnly" : "") + @"Span<int>)/*<bind>*/x/*</bind>*/[" + index + @"]; _ = y; } } " + InlineArray22Definition, TargetFramework.Net80); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Equal("x", GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal(refModifier != "" ? "x, y" : "y", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Theory] [CombinatorialData] public void InlineArrays_163([CombinatorialValues("ref ", "in ", "")] string refModifier, [CombinatorialValues(0, 1)] int index, bool readOnly) { if (refModifier == "in " && !readOnly) { return; } DataFlowAnalysis analysis = CompileAndAnalyzeDataFlowExpression( @" class B { static void M(" + refModifier + @"Buffer22 x) { var y = (System." + (readOnly ? "ReadOnly" : "") + @"Span<int>)x[/*<bind>*/" + index + @"/*</bind>*/]; _ = y; } } " + InlineArray22Definition, TargetFramework.Net80); Assert.Null(GetSymbolNamesJoined(analysis.AlwaysAssigned)); Assert.Null(GetSymbolNamesJoined(analysis.Captured)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedInside)); Assert.Null(GetSymbolNamesJoined(analysis.CapturedOutside)); Assert.Null(GetSymbolNamesJoined(analysis.VariablesDeclared)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsIn)); Assert.Null(GetSymbolNamesJoined(analysis.DataFlowsOut)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnEntry)); Assert.Equal("x", GetSymbolNamesJoined(analysis.DefinitelyAssignedOnExit)); Assert.Null(GetSymbolNamesJoined(analysis.ReadInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.ReadOutside)); Assert.Null(GetSymbolNamesJoined(analysis.WrittenInside)); Assert.Equal("x, y", GetSymbolNamesJoined(analysis.WrittenOutside)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/69148")] public void RefField_Assignment() { var comp = CreateCompilation(""" ref struct RS { ref int ri; public RS() => ri = 0; } """, targetFramework: TargetFramework.NetCoreApp); comp.VerifyEmitDiagnostics( // (3,13): warning CS9265: Field 'RS.ri' is never ref-assigned to, and will always have its default value (null reference) // ref int ri; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "ri").WithArguments("RS.ri").WithLocation(3, 13), // (4,20): warning CS9201: Ref field 'ri' should be ref-assigned before use. // public RS() => ri = 0; Diagnostic(ErrorCode.WRN_UseDefViolationRefField, "ri").WithArguments("ri").WithLocation(4, 20)); var tree = comp.CommonSyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var assignment = tree.GetRoot().DescendantNodes().OfType<AssignmentExpressionSyntax>().Single(); var flowAnalysis = model.AnalyzeDataFlow(assignment); Assert.Equal("this", GetSymbolNamesJoined(flowAnalysis.ReadInside)); Assert.Equal("this", GetSymbolNamesJoined(flowAnalysis.WrittenInside)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/69148")] public void RefField_RefAssignment() { var comp = CreateCompilation(""" ref struct RS { ref int ri; public unsafe RS() => ri = ref *default(int*); } """, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.UnsafeDebugDll); comp.VerifyEmitDiagnostics(); var tree = comp.CommonSyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var assignment = tree.GetRoot().DescendantNodes().OfType<AssignmentExpressionSyntax>().Single(); var flowAnalysis = model.AnalyzeDataFlow(assignment); Assert.Null(GetSymbolNamesJoined(flowAnalysis.ReadInside)); Assert.Equal("this", GetSymbolNamesJoined(flowAnalysis.WrittenInside)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/38087")] public void Repro_38087() { var comp = CreateCompilation(""" class Program { private static void Repro() { int i = 1, j = 2; int k = i + j + 1; } } """); comp.VerifyEmitDiagnostics(); var tree = comp.CommonSyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var decls = tree.GetRoot().DescendantNodes().OfType<LocalDeclarationStatementSyntax>().ToArray(); Assert.Equal(2, decls.Length); var decl = decls[1]; Assert.Equal("int k = i + j + 1;", decl.ToString()); var flowAnalysis = model.AnalyzeDataFlow(decl); Assert.Equal("i, j", GetSymbolNamesJoined(flowAnalysis.ReadInside)); var binOps = tree.GetRoot().DescendantNodes().OfType<BinaryExpressionSyntax>().ToArray(); Assert.Equal(2, binOps.Length); var add = binOps[0]; Assert.Equal("i + j + 1", add.ToString()); flowAnalysis = model.AnalyzeDataFlow(add); Assert.Equal("i, j", GetSymbolNamesJoined(flowAnalysis.ReadInside)); add = binOps[1]; Assert.Equal("i + j", add.ToString()); flowAnalysis = model.AnalyzeDataFlow(add); Assert.Equal("i, j", GetSymbolNamesJoined(flowAnalysis.ReadInside)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/38087")] public void FourBinaryOperands() { var comp = CreateCompilation(""" class Program { private static void Repro() { int i = 1, j = 2, k = 3, l = 4; _ = i + j + k + l; } } """); comp.VerifyEmitDiagnostics(); var tree = comp.CommonSyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var decl = tree.GetRoot().DescendantNodes().OfType<ExpressionStatementSyntax>().Single(); Assert.Equal("_ = i + j + k + l;", decl.ToString()); var flowAnalysis = model.AnalyzeDataFlow(decl); Assert.Equal("i, j, k, l", GetSymbolNamesJoined(flowAnalysis.ReadInside)); var binOps = tree.GetRoot().DescendantNodes().OfType<BinaryExpressionSyntax>().ToArray(); Assert.Equal(3, binOps.Length); var add = binOps[0]; Assert.Equal("i + j + k + l", add.ToString()); flowAnalysis = model.AnalyzeDataFlow(add); Assert.Equal("i, j, k, l", GetSymbolNamesJoined(flowAnalysis.ReadInside)); add = binOps[1]; Assert.Equal("i + j + k", add.ToString()); flowAnalysis = model.AnalyzeDataFlow(add); Assert.Equal("i, j, k", GetSymbolNamesJoined(flowAnalysis.ReadInside)); add = binOps[2]; Assert.Equal("i + j", add.ToString()); flowAnalysis = model.AnalyzeDataFlow(add); Assert.Equal("i, j", GetSymbolNamesJoined(flowAnalysis.ReadInside)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/38087")] public void BinaryOpConditionalAccess() { var comp = CreateCompilation(""" class C { public bool M(out int x) { x = 0; return false; } private static void Repro(C c) { const bool y = true; const bool z = true; int x; _ = c?.M(out x) == y == z; } } """); comp.VerifyEmitDiagnostics(); var tree = comp.CommonSyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var decl = tree.GetRoot().DescendantNodes().OfType<ExpressionStatementSyntax>().Last(); Assert.Equal("_ = c?.M(out x) == y == z;", decl.ToString()); var flowAnalysis = model.AnalyzeDataFlow(decl); Assert.Equal("c, y, z", GetSymbolNamesJoined(flowAnalysis.ReadInside)); Assert.Equal("x", GetSymbolNamesJoined(flowAnalysis.WrittenInside)); var binOps = tree.GetRoot().DescendantNodes().OfType<BinaryExpressionSyntax>().ToArray(); Assert.Equal(2, binOps.Length); var binOp = binOps[0]; Assert.Equal("c?.M(out x) == y == z", binOp.ToString()); flowAnalysis = model.AnalyzeDataFlow(binOp); Assert.Equal("c, y, z", GetSymbolNamesJoined(flowAnalysis.ReadInside)); Assert.Equal("x", GetSymbolNamesJoined(flowAnalysis.WrittenInside)); binOp = binOps[1]; Assert.Equal("c?.M(out x) == y", binOp.ToString()); flowAnalysis = model.AnalyzeDataFlow(binOp); Assert.Equal("c, y", GetSymbolNamesJoined(flowAnalysis.ReadInside)); Assert.Equal("x", GetSymbolNamesJoined(flowAnalysis.WrittenInside)); } } }