未验证 提交 3f4dbb52 编写于 作者: A AlekseyTs 提交者: GitHub

Add BasicBlock.IsReachable property. (#25698)

上级 9888b3a4
......@@ -1050,7 +1050,7 @@ void M(bool x)
Leaving: {R6} {R1}
}
Block[B5] - Block
Block[B5] - Block [UnReachable]
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x = true;')
......
......@@ -622,7 +622,7 @@ void F(dynamic alternative, dynamic result)
IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: null, Constant: null, IsImplicit) (Syntax: 'null')
Next (Regular) Block[B2]
Block[B2] - Block
Block[B2] - Block [UnReachable]
Predecessors: [B1]
Statements (1)
IFlowCaptureOperation: 2 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'null')
......@@ -717,7 +717,7 @@ void F(int alternative, int result)
IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: null, Constant: null, IsInvalid, IsImplicit) (Syntax: 'null')
Next (Regular) Block[B2]
Block[B2] - Block
Block[B2] - Block [UnReachable]
Predecessors: [B1]
Statements (1)
IFlowCaptureOperation: 2 (OperationKind.FlowCapture, Type: null, IsInvalid, IsImplicit) (Syntax: 'null')
......@@ -810,7 +810,7 @@ void F(int? alternative, int? result)
IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: null, Constant: null, IsImplicit) (Syntax: 'null')
Next (Regular) Block[B2]
Block[B2] - Block
Block[B2] - Block [UnReachable]
Predecessors: [B1]
Statements (1)
IFlowCaptureOperation: 2 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'null')
......@@ -1203,7 +1203,7 @@ void F(object alternative, object result)
IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: System.String, Constant: ""a"", IsImplicit) (Syntax: 'input')
Next (Regular) Block[B4]
Block[B3] - Block
Block[B3] - Block [UnReachable]
Predecessors: [B1]
Statements (1)
IFlowCaptureOperation: 2 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'alternative')
......
......@@ -1277,7 +1277,7 @@ void M()
Next (Regular) Block[B3]
Leaving: {R1}
Block[B2] - Block
Block[B2] - Block [UnReachable]
Predecessors: [B1]
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'condition = true;')
......
......@@ -223,7 +223,7 @@ void F(bool a)
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B2]
Block[B1] - Block
Block[B1] - Block [UnReachable]
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a = true;')
......@@ -273,7 +273,7 @@ int F(bool a)
Statements (0)
Next (Return) Block[B3]
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1')
Block[B2] - Block
Block[B2] - Block [UnReachable]
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a = true;')
......@@ -624,7 +624,7 @@ int F()
Statements (0)
Next (Return) Block[B3]
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1')
Block[B2] - Block
Block[B2] - Block [UnReachable]
Predecessors (0)
Statements (0)
Next (Return) Block[B3]
......@@ -1189,7 +1189,7 @@ System.Collections.Generic.IEnumerable<int> F(bool a)
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B2]
Block[B1] - Block
Block[B1] - Block [UnReachable]
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a = true;')
......
......@@ -39,7 +39,7 @@ void F()
Predecessors: [B0]
Statements (0)
Next (ReThrow) Block[null]
Block[B2] - Exit
Block[B2] - Exit [UnReachable]
Predecessors (0)
Statements (0)
";
......@@ -88,7 +88,7 @@ void F(int x)
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1')
Next (ReThrow) Block[null]
Block[B2] - Block
Block[B2] - Block [UnReachable]
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x = 2;')
......@@ -100,7 +100,7 @@ void F(int x)
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 2) (Syntax: '2')
Next (Regular) Block[B3]
Block[B3] - Exit
Block[B3] - Exit [UnReachable]
Predecessors: [B2]
Statements (0)
";
......@@ -133,7 +133,7 @@ void F(System.Exception ex)
Statements (0)
Next (Throw) Block[null]
IParameterReferenceOperation: ex (OperationKind.ParameterReference, Type: System.Exception) (Syntax: 'ex')
Block[B2] - Exit
Block[B2] - Exit [UnReachable]
Predecessors (0)
Statements (0)
";
......@@ -186,7 +186,7 @@ void F(System.Exception ex)
Next (Throw) Block[null]
IParameterReferenceOperation: ex (OperationKind.ParameterReference, Type: System.Exception) (Syntax: 'ex')
Block[B2] - Block
Block[B2] - Block [UnReachable]
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x = 2;')
......@@ -201,7 +201,7 @@ void F(System.Exception ex)
Leaving: {R1}
}
Block[B3] - Exit
Block[B3] - Exit [UnReachable]
Predecessors: [B2]
Statements (0)
";
......@@ -249,7 +249,7 @@ void F(int x, System.Exception ex)
IParameterReferenceOperation: ex (OperationKind.ParameterReference, Type: System.Exception, IsInvalid) (Syntax: 'ex')
Right:
IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.Int32, IsInvalid) (Syntax: 'x')
Block[B2] - Block
Block[B2] - Block [UnReachable]
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null, IsInvalid) (Syntax: 'x = throw ex + x;')
......@@ -267,7 +267,7 @@ void F(int x, System.Exception ex)
IOperation: (OperationKind.None, Type: null, IsInvalid, IsImplicit) (Syntax: 'throw ex + x')
Next (Regular) Block[B3]
Block[B3] - Exit
Block[B3] - Exit [UnReachable]
Predecessors: [B2]
Statements (0)
";
......@@ -308,7 +308,7 @@ void F(int x, System.Exception ex)
Next (Throw) Block[null]
IParameterReferenceOperation: ex (OperationKind.ParameterReference, Type: System.Exception) (Syntax: 'ex')
Block[B2] - Block
Block[B2] - Block [UnReachable]
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null, IsInvalid) (Syntax: 'x = (throw ex) + x;')
......@@ -330,7 +330,7 @@ void F(int x, System.Exception ex)
IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'x')
Next (Regular) Block[B3]
Block[B3] - Exit
Block[B3] - Exit [UnReachable]
Predecessors: [B2]
Statements (0)
";
......@@ -375,7 +375,7 @@ void F(int x, System.Exception ex)
Next (Throw) Block[null]
IParameterReferenceOperation: ex (OperationKind.ParameterReference, Type: System.Exception, IsInvalid) (Syntax: 'ex')
Block[B2] - Block
Block[B2] - Block [UnReachable]
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null, IsInvalid) (Syntax: 'x = x + throw ex;')
......@@ -397,7 +397,7 @@ void F(int x, System.Exception ex)
IOperation: (OperationKind.None, Type: null, IsInvalid, IsImplicit) (Syntax: 'throw ex')
Next (Regular) Block[B3]
Block[B3] - Exit
Block[B3] - Exit [UnReachable]
Predecessors: [B2]
Statements (0)
";
......@@ -442,7 +442,7 @@ void F(int x, System.Exception ex)
Next (Throw) Block[null]
IParameterReferenceOperation: ex (OperationKind.ParameterReference, Type: System.Exception) (Syntax: 'ex')
Block[B2] - Block
Block[B2] - Block [UnReachable]
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null, IsInvalid) (Syntax: 'x = x + (throw ex);')
......@@ -464,7 +464,7 @@ void F(int x, System.Exception ex)
IOperation: (OperationKind.None, Type: null, IsInvalid, IsImplicit) (Syntax: 'throw ex')
Next (Regular) Block[B3]
Block[B3] - Exit
Block[B3] - Exit [UnReachable]
Predecessors: [B2]
Statements (0)
";
......@@ -522,7 +522,7 @@ void F(object x, object y, System.Exception ex)
Statements (0)
Next (Throw) Block[null]
IParameterReferenceOperation: ex (OperationKind.ParameterReference, Type: System.Exception) (Syntax: 'ex')
Block[B4] - Block
Block[B4] - Block [UnReachable]
Predecessors (0)
Statements (1)
IFlowCaptureOperation: 2 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'throw ex')
......@@ -606,7 +606,7 @@ void F(object x, object y, object z, System.Exception ex)
Statements (0)
Next (Throw) Block[null]
IParameterReferenceOperation: ex (OperationKind.ParameterReference, Type: System.Exception) (Syntax: 'ex')
Block[B4] - Block
Block[B4] - Block [UnReachable]
Predecessors (0)
Statements (1)
IFlowCaptureOperation: 2 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'throw ex')
......@@ -779,7 +779,7 @@ void F(int u)
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 2) (Syntax: '2')
Next (ReThrow) Block[null]
Block[B3] - Block
Block[B3] - Block [UnReachable]
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'u = 3;')
......@@ -885,7 +885,7 @@ void F(object x, object y, object z, int u)
Next (Throw) Block[null]
IInvalidOperation (OperationKind.Invalid, Type: null, IsInvalid) (Syntax: '')
Children(0)
Block[B5] - Block
Block[B5] - Block [UnReachable]
Predecessors (0)
Statements (1)
IFlowCaptureOperation: 1 (OperationKind.FlowCapture, Type: null, IsInvalid, IsImplicit) (Syntax: 'throw')
......@@ -958,7 +958,7 @@ void F(System.Exception ex)
Next (Throw) Block[null]
IParameterReferenceOperation: ex (OperationKind.ParameterReference, Type: System.Exception) (Syntax: 'ex')
Block[B2] - Exit
Block[B2] - Exit [UnReachable]
Predecessors (0)
Statements (0)
";
......@@ -1072,7 +1072,7 @@ void F(System.Exception ex, bool a)
Statements (0)
Next (Throw) Block[null]
IParameterReferenceOperation: ex (OperationKind.ParameterReference, Type: System.Exception) (Syntax: 'ex')
Block[B3] - Exit
Block[B3] - Exit [UnReachable]
Predecessors (0)
Statements (0)
";
......@@ -1195,7 +1195,7 @@ void F(System.Exception ex)
Statements (0)
Next (Throw) Block[null]
IParameterReferenceOperation: ex (OperationKind.ParameterReference, Type: System.Exception) (Syntax: 'ex')
Block[B3] - Exit
Block[B3] - Exit [UnReachable]
Predecessors (0)
Statements (0)
";
......@@ -1345,7 +1345,7 @@ void F(System.Exception ex, int x)
Statements (0)
Next (Throw) Block[null]
IParameterReferenceOperation: ex (OperationKind.ParameterReference, Type: System.Exception) (Syntax: 'ex')
Block[B3] - Block
Block[B3] - Block [UnReachable]
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x = 2;')
......@@ -1425,7 +1425,7 @@ void F(int x)
Predecessors: [B3]
Statements (0)
Next (ReThrow) Block[null]
Block[B3] - Block
Block[B3] - Block [UnReachable]
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x = 2;')
......@@ -1486,7 +1486,7 @@ int F(bool a, System.Exception ex1, System.Exception ex2)
Statements (0)
Next (Throw) Block[null]
IParameterReferenceOperation: ex2 (OperationKind.ParameterReference, Type: System.Exception) (Syntax: 'ex2')
Block[B3] - Exit
Block[B3] - Exit [UnReachable]
Predecessors (0)
Statements (0)
";
......@@ -1541,7 +1541,7 @@ void F(int x, System.Exception ex1, System.Exception ex2, bool a)
Statements (0)
Next (Throw) Block[null]
IParameterReferenceOperation: ex2 (OperationKind.ParameterReference, Type: System.Exception) (Syntax: 'ex2')
Block[B3] - Exit
Block[B3] - Exit [UnReachable]
Predecessors (0)
Statements (0)
";
......@@ -1843,7 +1843,7 @@ void F(int u)
Next (ReThrow) Block[null]
}
Block[B3] - Exit
Block[B3] - Exit [UnReachable]
Predecessors: [B1]
Statements (0)
";
......@@ -1906,7 +1906,7 @@ void F(int u, System.Exception ex)
IParameterReferenceOperation: ex (OperationKind.ParameterReference, Type: System.Exception) (Syntax: 'ex')
}
Block[B3] - Exit
Block[B3] - Exit [UnReachable]
Predecessors: [B1]
Statements (0)
";
......
......@@ -989,7 +989,7 @@ void F()
}
.catch {R3} (System.Object)
{
Block[B2] - Block
Block[B2] - Block [UnReachable]
Predecessors (0)
Statements (0)
Next (Regular) Block[B3]
......@@ -1437,7 +1437,7 @@ void F()
}
.catch {R3} (System.Object)
{
Block[B2] - Block
Block[B2] - Block [UnReachable]
Predecessors (0)
Statements (0)
Next (Regular) Block[B3]
......@@ -1579,7 +1579,7 @@ void F()
.catch {R5} (Exception1)
{
Locals: [Exception1 e]
Block[B2] - Block
Block[B2] - Block [UnReachable]
Predecessors (0)
Statements (1)
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: null, IsImplicit) (Syntax: '(Exception1 e)')
......@@ -1594,7 +1594,7 @@ void F()
.locals {R6}
{
Locals: [System.Int32 j]
Block[B3] - Block
Block[B3] - Block [UnReachable]
Predecessors: [B2]
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'j = 2;')
......@@ -1691,7 +1691,7 @@ void F()
.catch {R3} (Exception1)
{
Locals: [Exception1 e]
Block[B2] - Block
Block[B2] - Block [UnReachable]
Predecessors (0)
Statements (1)
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: null, IsImplicit) (Syntax: '(Exception1 e)')
......@@ -1759,7 +1759,7 @@ void F()
Locals: [Exception1 e] [System.Int32 i]
.filter {R4}
{
Block[B2] - Block
Block[B2] - Block [UnReachable]
Predecessors (0)
Statements (1)
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: null, IsImplicit) (Syntax: '(Exception1 e)')
......@@ -1786,7 +1786,7 @@ void F()
.handler {R5}
{
Locals: [System.Int32 j]
Block[B3] - Block
Block[B3] - Block [UnReachable]
Predecessors: [B2]
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'j = 2;')
......@@ -1856,7 +1856,7 @@ void F()
Locals: [Exception1 e] [System.Int32 i]
.filter {R4}
{
Block[B2] - Block
Block[B2] - Block [UnReachable]
Predecessors (0)
Statements (1)
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: null, IsImplicit) (Syntax: '(Exception1 e)')
......@@ -1882,7 +1882,7 @@ void F()
}
.handler {R5}
{
Block[B3] - Block
Block[B3] - Block [UnReachable]
Predecessors: [B2]
Statements (0)
Next (Regular) Block[B4]
......@@ -1945,7 +1945,7 @@ void F()
Locals: [System.Int32 i]
.filter {R4}
{
Block[B2] - Block
Block[B2] - Block [UnReachable]
Predecessors (0)
Statements (0)
Jump if True (Regular) to Block[B3]
......@@ -1966,7 +1966,7 @@ void F()
.handler {R5}
{
Locals: [System.Int32 j]
Block[B3] - Block
Block[B3] - Block [UnReachable]
Predecessors: [B2]
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'j = 2;')
......@@ -2036,7 +2036,7 @@ void F()
Locals: [System.Int32 i]
.filter {R4}
{
Block[B2] - Block
Block[B2] - Block [UnReachable]
Predecessors (0)
Statements (0)
Jump if True (Regular) to Block[B3]
......@@ -2056,7 +2056,7 @@ void F()
}
.handler {R5}
{
Block[B3] - Block
Block[B3] - Block [UnReachable]
Predecessors: [B2]
Statements (0)
Next (Regular) Block[B4]
......@@ -2119,7 +2119,7 @@ void F()
Locals: [System.Int32 i]
.filter {R4}
{
Block[B2] - Block
Block[B2] - Block [UnReachable]
Predecessors (0)
Statements (0)
Jump if True (Regular) to Block[B3]
......@@ -2140,7 +2140,7 @@ void F()
.handler {R5}
{
Locals: [System.Int32 j]
Block[B3] - Block
Block[B3] - Block [UnReachable]
Predecessors: [B2]
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'j = 2;')
......@@ -2210,7 +2210,7 @@ void F()
Locals: [System.Int32 i]
.filter {R4}
{
Block[B2] - Block
Block[B2] - Block [UnReachable]
Predecessors (0)
Statements (0)
Jump if True (Regular) to Block[B3]
......@@ -2230,7 +2230,7 @@ void F()
}
.handler {R5}
{
Block[B3] - Block
Block[B3] - Block [UnReachable]
Predecessors: [B2]
Statements (0)
Next (Regular) Block[B4]
......@@ -2289,7 +2289,7 @@ void F()
.catch {R3} (Exception1)
{
Locals: [System.Int32 j]
Block[B2] - Block
Block[B2] - Block [UnReachable]
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'j = 2;')
......@@ -2353,7 +2353,7 @@ void F()
}
.catch {R3} (Exception1)
{
Block[B2] - Block
Block[B2] - Block [UnReachable]
Predecessors (0)
Statements (0)
Next (Regular) Block[B3]
......@@ -2415,7 +2415,7 @@ void F()
Locals: [System.Int32 i]
.filter {R4}
{
Block[B2] - Block
Block[B2] - Block [UnReachable]
Predecessors (0)
Statements (0)
Jump if True (Regular) to Block[B3]
......@@ -2436,7 +2436,7 @@ void F()
.handler {R5}
{
Locals: [System.Int32 j]
Block[B3] - Block
Block[B3] - Block [UnReachable]
Predecessors: [B2]
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'j = 2;')
......@@ -2506,7 +2506,7 @@ void F()
Locals: [System.Int32 i]
.filter {R4}
{
Block[B2] - Block
Block[B2] - Block [UnReachable]
Predecessors (0)
Statements (0)
Jump if True (Regular) to Block[B3]
......@@ -2526,7 +2526,7 @@ void F()
}
.handler {R5}
{
Block[B3] - Block
Block[B3] - Block [UnReachable]
Predecessors: [B2]
Statements (0)
Next (Regular) Block[B4]
......@@ -3399,6 +3399,4317 @@ void F()
VerifyFlowGraphForTest<BlockSyntax>(compilation, expectedGraph);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ExceptionDispatch_01()
{
string source = @"
class P
{
void M(bool b)
/*<bind>*/{
try
{
ThisCanThrow();
}
catch
{
b = true;
}
}/*</bind>*/
static bool ThisCanThrow() => throw null;
}
";
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Entering: {R1} {R2}
.try {R1, R2}
{
Block[B1] - Block
Predecessors: [B0]
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'ThisCanThrow();')
Expression:
IInvocationOperation (System.Boolean P.ThisCanThrow()) (OperationKind.Invocation, Type: System.Boolean) (Syntax: 'ThisCanThrow()')
Instance Receiver:
null
Arguments(0)
Next (Regular) Block[B3]
Leaving: {R2} {R1}
}
.catch {R3} (System.Object)
{
Block[B2] - Block
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'b = true;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'b = true')
Left:
IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'b')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Next (Regular) Block[B3]
Leaving: {R3} {R1}
}
Block[B3] - Exit
Predecessors: [B1] [B2]
Statements (0)
";
var expectedDiagnostics = DiagnosticDescription.None;
VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(source, expectedGraph, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ExceptionDispatch_02()
{
string source = @"
class P
{
void M(bool b)
/*<bind>*/{
try
{
if (ThisCanThrow()) return;
}
catch
{
b = true;
}
}/*</bind>*/
static bool ThisCanThrow() => throw null;
}
";
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Entering: {R1} {R2}
.try {R1, R2}
{
Block[B1] - Block
Predecessors: [B0]
Statements (0)
Jump if False (Regular) to Block[B3]
IInvocationOperation (System.Boolean P.ThisCanThrow()) (OperationKind.Invocation, Type: System.Boolean) (Syntax: 'ThisCanThrow()')
Instance Receiver:
null
Arguments(0)
Leaving: {R2} {R1}
Next (Regular) Block[B3]
Leaving: {R2} {R1}
}
.catch {R3} (System.Object)
{
Block[B2] - Block
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'b = true;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'b = true')
Left:
IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'b')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Next (Regular) Block[B3]
Leaving: {R3} {R1}
}
Block[B3] - Exit
Predecessors: [B1] [B2]
Statements (0)
";
var expectedDiagnostics = DiagnosticDescription.None;
VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(source, expectedGraph, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ExceptionDispatch_03()
{
string source = @"
class P
{
bool M(bool b)
/*<bind>*/{
try
{
return ThisCanThrow();
}
catch
{
b = true;
}
return false;
}/*</bind>*/
static bool ThisCanThrow() => throw null;
}
";
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Entering: {R1} {R2}
.try {R1, R2}
{
Block[B1] - Block
Predecessors: [B0]
Statements (0)
Next (Return) Block[B4]
IInvocationOperation (System.Boolean P.ThisCanThrow()) (OperationKind.Invocation, Type: System.Boolean) (Syntax: 'ThisCanThrow()')
Instance Receiver:
null
Arguments(0)
Leaving: {R2} {R1}
}
.catch {R3} (System.Object)
{
Block[B2] - Block
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'b = true;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'b = true')
Left:
IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'b')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Next (Regular) Block[B3]
Leaving: {R3} {R1}
}
Block[B3] - Block
Predecessors: [B2]
Statements (0)
Next (Return) Block[B4]
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: False) (Syntax: 'false')
Block[B4] - Exit
Predecessors: [B1] [B3]
Statements (0)
";
var expectedDiagnostics = DiagnosticDescription.None;
VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(source, expectedGraph, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ExceptionDispatch_04()
{
string source = @"
class P
{
void M(bool b)
/*<bind>*/{
try
{
throw null;
}
catch
{
b = true;
}
}/*</bind>*/
}
";
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Entering: {R1} {R2}
.try {R1, R2}
{
Block[B1] - Block
Predecessors: [B0]
Statements (0)
Next (Throw) Block[null]
ILiteralOperation (OperationKind.Literal, Type: null, Constant: null) (Syntax: 'null')
}
.catch {R3} (System.Object)
{
Block[B2] - Block
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'b = true;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'b = true')
Left:
IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'b')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Next (Regular) Block[B3]
Leaving: {R3} {R1}
}
Block[B3] - Exit
Predecessors: [B2]
Statements (0)
";
var expectedDiagnostics = DiagnosticDescription.None;
VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(source, expectedGraph, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ExceptionDispatch_05()
{
string source = @"
class P
{
void M(bool b)
/*<bind>*/{
try
{
if (true) throw null;
}
catch
{
b = true;
}
}/*</bind>*/
}
";
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Entering: {R1} {R2}
.try {R1, R2}
{
Block[B1] - Block
Predecessors: [B0]
Statements (0)
Jump if False (Regular) to Block[B3]
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Leaving: {R2} {R1}
Next (Throw) Block[null]
ILiteralOperation (OperationKind.Literal, Type: null, Constant: null) (Syntax: 'null')
}
.catch {R3} (System.Object)
{
Block[B2] - Block
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'b = true;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'b = true')
Left:
IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'b')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Next (Regular) Block[B3]
Leaving: {R3} {R1}
}
Block[B3] - Exit
Predecessors: [B1] [B2]
Statements (0)
";
var expectedDiagnostics = DiagnosticDescription.None;
VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(source, expectedGraph, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ExceptionDispatch_06()
{
string source = @"
class P
{
void M(bool b)
/*<bind>*/{
try
{
if (false) throw null;
}
catch
{
b = true;
}
}/*</bind>*/
}
";
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Entering: {R1} {R2}
.try {R1, R2}
{
Block[B1] - Block
Predecessors: [B0]
Statements (0)
Jump if False (Regular) to Block[B3]
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: False) (Syntax: 'false')
Leaving: {R2} {R1}
Next (Throw) Block[null]
ILiteralOperation (OperationKind.Literal, Type: null, Constant: null) (Syntax: 'null')
}
.catch {R3} (System.Object)
{
Block[B2] - Block [UnReachable]
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'b = true;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'b = true')
Left:
IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'b')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Next (Regular) Block[B3]
Leaving: {R3} {R1}
}
Block[B3] - Exit
Predecessors: [B1] [B2]
Statements (0)
";
var expectedDiagnostics = DiagnosticDescription.None;
VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(source, expectedGraph, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ExceptionDispatch_07()
{
string source = @"
class P
{
void M(bool b)
/*<bind>*/{
try
{
ThisCanThrow();
}
catch
{
try
{
if (true) throw;
}
catch
{
b = true;
}
}
}/*</bind>*/
static bool ThisCanThrow() => throw null;
}
";
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Entering: {R1} {R2}
.try {R1, R2}
{
Block[B1] - Block
Predecessors: [B0]
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'ThisCanThrow();')
Expression:
IInvocationOperation (System.Boolean P.ThisCanThrow()) (OperationKind.Invocation, Type: System.Boolean) (Syntax: 'ThisCanThrow()')
Instance Receiver:
null
Arguments(0)
Next (Regular) Block[B4]
Leaving: {R2} {R1}
}
.catch {R3} (System.Object)
{
.try {R4, R5}
{
Block[B2] - Block
Predecessors (0)
Statements (0)
Jump if False (Regular) to Block[B4]
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Leaving: {R5} {R4} {R3} {R1}
Next (ReThrow) Block[null]
}
.catch {R6} (System.Object)
{
Block[B3] - Block
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'b = true;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'b = true')
Left:
IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'b')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Next (Regular) Block[B4]
Leaving: {R6} {R4} {R3} {R1}
}
}
Block[B4] - Exit
Predecessors: [B1] [B2] [B3]
Statements (0)
";
var expectedDiagnostics = DiagnosticDescription.None;
VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(source, expectedGraph, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ExceptionDispatch_08()
{
string source = @"
class P
{
void M(bool b)
/*<bind>*/{
try
{
ThisCanThrow();
}
catch
{
try
{
if (false) throw;
}
catch
{
b = true;
}
}
}/*</bind>*/
static bool ThisCanThrow() => throw null;
}
";
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Entering: {R1} {R2}
.try {R1, R2}
{
Block[B1] - Block
Predecessors: [B0]
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'ThisCanThrow();')
Expression:
IInvocationOperation (System.Boolean P.ThisCanThrow()) (OperationKind.Invocation, Type: System.Boolean) (Syntax: 'ThisCanThrow()')
Instance Receiver:
null
Arguments(0)
Next (Regular) Block[B4]
Leaving: {R2} {R1}
}
.catch {R3} (System.Object)
{
.try {R4, R5}
{
Block[B2] - Block
Predecessors (0)
Statements (0)
Jump if False (Regular) to Block[B4]
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: False) (Syntax: 'false')
Leaving: {R5} {R4} {R3} {R1}
Next (ReThrow) Block[null]
}
.catch {R6} (System.Object)
{
Block[B3] - Block [UnReachable]
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'b = true;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'b = true')
Left:
IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'b')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Next (Regular) Block[B4]
Leaving: {R6} {R4} {R3} {R1}
}
}
Block[B4] - Exit
Predecessors: [B1] [B2] [B3]
Statements (0)
";
var expectedDiagnostics = DiagnosticDescription.None;
VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(source, expectedGraph, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ExceptionDispatch_09()
{
string source = @"
class P
{
void M(bool b)
/*<bind>*/{
try
{
ThisCanThrow();
if (false) return;
}
catch
{
b = true;
}
}/*</bind>*/
static bool[] ThisCanThrow() => null;
}
";
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Entering: {R1} {R2}
.try {R1, R2}
{
Block[B1] - Block
Predecessors: [B0]
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'ThisCanThrow();')
Expression:
IInvocationOperation (System.Boolean[] P.ThisCanThrow()) (OperationKind.Invocation, Type: System.Boolean[]) (Syntax: 'ThisCanThrow()')
Instance Receiver:
null
Arguments(0)
Jump if False (Regular) to Block[B3]
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: False) (Syntax: 'false')
Leaving: {R2} {R1}
Next (Regular) Block[B3]
Leaving: {R2} {R1}
}
.catch {R3} (System.Object)
{
Block[B2] - Block
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'b = true;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'b = true')
Left:
IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'b')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Next (Regular) Block[B3]
Leaving: {R3} {R1}
}
Block[B3] - Exit
Predecessors: [B1] [B2]
Statements (0)
";
var expectedDiagnostics = new[] {
// file.cs(9,24): warning CS0162: Unreachable code detected
// if (false) return;
Diagnostic(ErrorCode.WRN_UnreachableCode, "return").WithLocation(9, 24)
};
VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(source, expectedGraph, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ExceptionDispatch_10()
{
string source = @"
class P
{
void M(bool b)
/*<bind>*/{
try
{
ThisCanThrow();
if (true) return;
}
catch
{
b = true;
}
}/*</bind>*/
static bool[] ThisCanThrow() => null;
}
";
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Entering: {R1} {R2}
.try {R1, R2}
{
Block[B1] - Block
Predecessors: [B0]
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'ThisCanThrow();')
Expression:
IInvocationOperation (System.Boolean[] P.ThisCanThrow()) (OperationKind.Invocation, Type: System.Boolean[]) (Syntax: 'ThisCanThrow()')
Instance Receiver:
null
Arguments(0)
Jump if False (Regular) to Block[B3]
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Leaving: {R2} {R1}
Next (Regular) Block[B3]
Leaving: {R2} {R1}
}
.catch {R3} (System.Object)
{
Block[B2] - Block
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'b = true;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'b = true')
Left:
IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'b')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Next (Regular) Block[B3]
Leaving: {R3} {R1}
}
Block[B3] - Exit
Predecessors: [B1] [B2]
Statements (0)
";
var expectedDiagnostics = DiagnosticDescription.None;
VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(source, expectedGraph, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ExceptionDispatch_11()
{
string source = @"
class P
{
bool[] M(bool b)
/*<bind>*/{
try
{
if (true) return ThisCanThrow();
}
catch
{
b = true;
}
return null;
}/*</bind>*/
static bool[] ThisCanThrow() => null;
}
";
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Entering: {R1} {R2}
.try {R1, R2}
{
Block[B1] - Block
Predecessors: [B0]
Statements (0)
Jump if False (Regular) to Block[B3]
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Leaving: {R2} {R1}
Next (Return) Block[B4]
IInvocationOperation (System.Boolean[] P.ThisCanThrow()) (OperationKind.Invocation, Type: System.Boolean[]) (Syntax: 'ThisCanThrow()')
Instance Receiver:
null
Arguments(0)
Leaving: {R2} {R1}
}
.catch {R3} (System.Object)
{
Block[B2] - Block
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'b = true;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'b = true')
Left:
IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'b')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Next (Regular) Block[B3]
Leaving: {R3} {R1}
}
Block[B3] - Block
Predecessors: [B1] [B2]
Statements (0)
Next (Return) Block[B4]
IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Boolean[], Constant: null, IsImplicit) (Syntax: 'null')
Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: True, IsUserDefined: False) (MethodSymbol: null)
(ImplicitReference)
Operand:
ILiteralOperation (OperationKind.Literal, Type: null, Constant: null) (Syntax: 'null')
Block[B4] - Exit
Predecessors: [B1] [B3]
Statements (0)
";
var expectedDiagnostics = DiagnosticDescription.None;
VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(source, expectedGraph, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ExceptionDispatch_12()
{
string source = @"
class P
{
bool[] M(bool b)
/*<bind>*/{
try
{
if (false) return ThisCanThrow();
}
catch
{
b = true;
}
return null;
}/*</bind>*/
static bool[] ThisCanThrow() => null;
}
";
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Entering: {R1} {R2}
.try {R1, R2}
{
Block[B1] - Block
Predecessors: [B0]
Statements (0)
Jump if False (Regular) to Block[B3]
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: False) (Syntax: 'false')
Leaving: {R2} {R1}
Next (Return) Block[B4]
IInvocationOperation (System.Boolean[] P.ThisCanThrow()) (OperationKind.Invocation, Type: System.Boolean[]) (Syntax: 'ThisCanThrow()')
Instance Receiver:
null
Arguments(0)
Leaving: {R2} {R1}
}
.catch {R3} (System.Object)
{
Block[B2] - Block [UnReachable]
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'b = true;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'b = true')
Left:
IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'b')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Next (Regular) Block[B3]
Leaving: {R3} {R1}
}
Block[B3] - Block
Predecessors: [B1] [B2]
Statements (0)
Next (Return) Block[B4]
IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Boolean[], Constant: null, IsImplicit) (Syntax: 'null')
Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: True, IsUserDefined: False) (MethodSymbol: null)
(ImplicitReference)
Operand:
ILiteralOperation (OperationKind.Literal, Type: null, Constant: null) (Syntax: 'null')
Block[B4] - Exit
Predecessors: [B1] [B3]
Statements (0)
";
var expectedDiagnostics = new[] {
// file.cs(8,24): warning CS0162: Unreachable code detected
// if (false) return ThisCanThrow();
Diagnostic(ErrorCode.WRN_UnreachableCode, "return").WithLocation(8, 24)
};
VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(source, expectedGraph, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ExceptionDispatch_13()
{
string source = @"
class P
{
void M(bool b)
/*<bind>*/{
try
{
try
{
}
finally
{
ThisCanThrow();
}
}
catch
{
b = true;
}
}/*</bind>*/
static bool ThisCanThrow() => throw null;
}
";
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Entering: {R1} {R2} {R3} {R4}
.try {R1, R2}
{
.try {R3, R4}
{
Block[B1] - Block
Predecessors: [B0]
Statements (0)
Next (Regular) Block[B4]
Finalizing: {R5}
Leaving: {R4} {R3} {R2} {R1}
}
.finally {R5}
{
Block[B2] - Block
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'ThisCanThrow();')
Expression:
IInvocationOperation (System.Boolean P.ThisCanThrow()) (OperationKind.Invocation, Type: System.Boolean) (Syntax: 'ThisCanThrow()')
Instance Receiver:
null
Arguments(0)
Next (StructuredExceptionHandling) Block[null]
}
}
.catch {R6} (System.Object)
{
Block[B3] - Block
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'b = true;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'b = true')
Left:
IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'b')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Next (Regular) Block[B4]
Leaving: {R6} {R1}
}
Block[B4] - Exit
Predecessors: [B1] [B3]
Statements (0)
";
var expectedDiagnostics = DiagnosticDescription.None;
VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(source, expectedGraph, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ExceptionDispatch_14()
{
string source = @"
class P
{
void M(bool b)
/*<bind>*/{
try
{
try
{
ThisCanThrow();
}
catch
{
}
}
catch
{
b = true;
}
}/*</bind>*/
static bool ThisCanThrow() => throw null;
}
";
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Entering: {R1} {R2} {R3} {R4}
.try {R1, R2}
{
.try {R3, R4}
{
Block[B1] - Block
Predecessors: [B0]
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'ThisCanThrow();')
Expression:
IInvocationOperation (System.Boolean P.ThisCanThrow()) (OperationKind.Invocation, Type: System.Boolean) (Syntax: 'ThisCanThrow()')
Instance Receiver:
null
Arguments(0)
Next (Regular) Block[B4]
Leaving: {R4} {R3} {R2} {R1}
}
.catch {R5} (System.Object)
{
Block[B2] - Block
Predecessors (0)
Statements (0)
Next (Regular) Block[B4]
Leaving: {R5} {R3} {R2} {R1}
}
}
.catch {R6} (System.Object)
{
Block[B3] - Block [UnReachable]
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'b = true;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'b = true')
Left:
IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'b')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Next (Regular) Block[B4]
Leaving: {R6} {R1}
}
Block[B4] - Exit
Predecessors: [B1] [B2] [B3]
Statements (0)
";
var expectedDiagnostics = DiagnosticDescription.None;
VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(source, expectedGraph, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ExceptionDispatch_15()
{
string source = @"
class P
{
void M(bool b)
/*<bind>*/{
try
{
try
{
ThisCanThrow();
}
catch when (true)
{
}
}
catch
{
b = true;
}
}/*</bind>*/
static bool ThisCanThrow() => throw null;
}
";
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Entering: {R1} {R2} {R3} {R4}
.try {R1, R2}
{
.try {R3, R4}
{
Block[B1] - Block
Predecessors: [B0]
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'ThisCanThrow();')
Expression:
IInvocationOperation (System.Boolean P.ThisCanThrow()) (OperationKind.Invocation, Type: System.Boolean) (Syntax: 'ThisCanThrow()')
Instance Receiver:
null
Arguments(0)
Next (Regular) Block[B5]
Leaving: {R4} {R3} {R2} {R1}
}
.catch {R5} (System.Object)
{
.filter {R6}
{
Block[B2] - Block
Predecessors (0)
Statements (0)
Jump if True (Regular) to Block[B3]
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Leaving: {R6}
Entering: {R7}
Next (StructuredExceptionHandling) Block[null]
}
.handler {R7}
{
Block[B3] - Block
Predecessors: [B2]
Statements (0)
Next (Regular) Block[B5]
Leaving: {R7} {R5} {R3} {R2} {R1}
}
}
}
.catch {R8} (System.Object)
{
Block[B4] - Block [UnReachable]
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'b = true;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'b = true')
Left:
IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'b')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Next (Regular) Block[B5]
Leaving: {R8} {R1}
}
Block[B5] - Exit
Predecessors: [B1] [B3] [B4]
Statements (0)
";
var expectedDiagnostics = new[] {
// file.cs(12,25): warning CS7095: Filter expression is a constant 'true', consider removing the filter
// catch when (true)
Diagnostic(ErrorCode.WRN_FilterIsConstantTrue, "true").WithLocation(12, 25)
};
VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(source, expectedGraph, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ExceptionDispatch_16()
{
string source = @"
class P
{
void M(bool b)
/*<bind>*/{
try
{
try
{
ThisCanThrow();
}
catch when (false)
{
}
}
catch
{
b = true;
}
}/*</bind>*/
static bool ThisCanThrow() => throw null;
}
";
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Entering: {R1} {R2} {R3} {R4}
.try {R1, R2}
{
.try {R3, R4}
{
Block[B1] - Block
Predecessors: [B0]
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'ThisCanThrow();')
Expression:
IInvocationOperation (System.Boolean P.ThisCanThrow()) (OperationKind.Invocation, Type: System.Boolean) (Syntax: 'ThisCanThrow()')
Instance Receiver:
null
Arguments(0)
Next (Regular) Block[B5]
Leaving: {R4} {R3} {R2} {R1}
}
.catch {R5} (System.Object)
{
.filter {R6}
{
Block[B2] - Block
Predecessors (0)
Statements (0)
Jump if True (Regular) to Block[B3]
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: False) (Syntax: 'false')
Leaving: {R6}
Entering: {R7}
Next (StructuredExceptionHandling) Block[null]
}
.handler {R7}
{
Block[B3] - Block [UnReachable]
Predecessors: [B2]
Statements (0)
Next (Regular) Block[B5]
Leaving: {R7} {R5} {R3} {R2} {R1}
}
}
}
.catch {R8} (System.Object)
{
Block[B4] - Block
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'b = true;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'b = true')
Left:
IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'b')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Next (Regular) Block[B5]
Leaving: {R8} {R1}
}
Block[B5] - Exit
Predecessors: [B1] [B3] [B4]
Statements (0)
";
var expectedDiagnostics = new[] {
// file.cs(12,25): warning CS8360: Filter expression is a constant 'false', consider removing the try-catch block
// catch when (false)
Diagnostic(ErrorCode.WRN_FilterIsConstantFalseRedundantTryCatch, "false").WithLocation(12, 25)
};
VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(source, expectedGraph, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ExceptionDispatch_17()
{
string source = @"
class P
{
void M(bool b)
/*<bind>*/{
try
{
try
{
ThisCanThrow();
}
catch when (ThisCanThrow())
{
}
}
catch
{
b = true;
}
}/*</bind>*/
static bool ThisCanThrow() => throw null;
}
";
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Entering: {R1} {R2} {R3} {R4}
.try {R1, R2}
{
.try {R3, R4}
{
Block[B1] - Block
Predecessors: [B0]
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'ThisCanThrow();')
Expression:
IInvocationOperation (System.Boolean P.ThisCanThrow()) (OperationKind.Invocation, Type: System.Boolean) (Syntax: 'ThisCanThrow()')
Instance Receiver:
null
Arguments(0)
Next (Regular) Block[B5]
Leaving: {R4} {R3} {R2} {R1}
}
.catch {R5} (System.Object)
{
.filter {R6}
{
Block[B2] - Block
Predecessors (0)
Statements (0)
Jump if True (Regular) to Block[B3]
IInvocationOperation (System.Boolean P.ThisCanThrow()) (OperationKind.Invocation, Type: System.Boolean) (Syntax: 'ThisCanThrow()')
Instance Receiver:
null
Arguments(0)
Leaving: {R6}
Entering: {R7}
Next (StructuredExceptionHandling) Block[null]
}
.handler {R7}
{
Block[B3] - Block
Predecessors: [B2]
Statements (0)
Next (Regular) Block[B5]
Leaving: {R7} {R5} {R3} {R2} {R1}
}
}
}
.catch {R8} (System.Object)
{
Block[B4] - Block
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'b = true;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'b = true')
Left:
IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'b')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Next (Regular) Block[B5]
Leaving: {R8} {R1}
}
Block[B5] - Exit
Predecessors: [B1] [B3] [B4]
Statements (0)
";
var expectedDiagnostics = DiagnosticDescription.None;
VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(source, expectedGraph, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ExceptionDispatch_18()
{
string source = @"
class P
{
void M(bool b)
/*<bind>*/{
try
{
try
{
ThisCanThrow();
}
catch when (ThisCanThrow() || true)
{
}
}
catch
{
b = true;
}
}/*</bind>*/
static bool ThisCanThrow() => throw null;
}
";
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Entering: {R1} {R2} {R3} {R4}
.try {R1, R2}
{
.try {R3, R4}
{
Block[B1] - Block
Predecessors: [B0]
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'ThisCanThrow();')
Expression:
IInvocationOperation (System.Boolean P.ThisCanThrow()) (OperationKind.Invocation, Type: System.Boolean) (Syntax: 'ThisCanThrow()')
Instance Receiver:
null
Arguments(0)
Next (Regular) Block[B6]
Leaving: {R4} {R3} {R2} {R1}
}
.catch {R5} (System.Object)
{
.filter {R6}
{
Block[B2] - Block
Predecessors (0)
Statements (0)
Jump if True (Regular) to Block[B4]
IInvocationOperation (System.Boolean P.ThisCanThrow()) (OperationKind.Invocation, Type: System.Boolean) (Syntax: 'ThisCanThrow()')
Instance Receiver:
null
Arguments(0)
Leaving: {R6}
Entering: {R7}
Next (Regular) Block[B3]
Block[B3] - Block
Predecessors: [B2]
Statements (0)
Jump if True (Regular) to Block[B4]
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Leaving: {R6}
Entering: {R7}
Next (StructuredExceptionHandling) Block[null]
}
.handler {R7}
{
Block[B4] - Block
Predecessors: [B2] [B3]
Statements (0)
Next (Regular) Block[B6]
Leaving: {R7} {R5} {R3} {R2} {R1}
}
}
}
.catch {R8} (System.Object)
{
Block[B5] - Block
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'b = true;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'b = true')
Left:
IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'b')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Next (Regular) Block[B6]
Leaving: {R8} {R1}
}
Block[B6] - Exit
Predecessors: [B1] [B4] [B5]
Statements (0)
";
var expectedDiagnostics = DiagnosticDescription.None;
VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(source, expectedGraph, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ExceptionDispatch_19()
{
string source = @"
class P
{
void M(bool b)
/*<bind>*/{
try
{
try
{
ThisCanThrow();
}
catch when (true || ThisCanThrow())
{
}
}
catch
{
b = true;
}
}/*</bind>*/
static bool ThisCanThrow() => throw null;
}
";
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Entering: {R1} {R2} {R3} {R4}
.try {R1, R2}
{
.try {R3, R4}
{
Block[B1] - Block
Predecessors: [B0]
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'ThisCanThrow();')
Expression:
IInvocationOperation (System.Boolean P.ThisCanThrow()) (OperationKind.Invocation, Type: System.Boolean) (Syntax: 'ThisCanThrow()')
Instance Receiver:
null
Arguments(0)
Next (Regular) Block[B6]
Leaving: {R4} {R3} {R2} {R1}
}
.catch {R5} (System.Object)
{
.filter {R6}
{
Block[B2] - Block
Predecessors (0)
Statements (0)
Jump if True (Regular) to Block[B4]
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Leaving: {R6}
Entering: {R7}
Next (Regular) Block[B3]
Block[B3] - Block [UnReachable]
Predecessors: [B2]
Statements (0)
Jump if True (Regular) to Block[B4]
IInvocationOperation (System.Boolean P.ThisCanThrow()) (OperationKind.Invocation, Type: System.Boolean) (Syntax: 'ThisCanThrow()')
Instance Receiver:
null
Arguments(0)
Leaving: {R6}
Entering: {R7}
Next (StructuredExceptionHandling) Block[null]
}
.handler {R7}
{
Block[B4] - Block
Predecessors: [B2] [B3]
Statements (0)
Next (Regular) Block[B6]
Leaving: {R7} {R5} {R3} {R2} {R1}
}
}
}
.catch {R8} (System.Object)
{
Block[B5] - Block [UnReachable]
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'b = true;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'b = true')
Left:
IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'b')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Next (Regular) Block[B6]
Leaving: {R8} {R1}
}
Block[B6] - Exit
Predecessors: [B1] [B4] [B5]
Statements (0)
";
var expectedDiagnostics = DiagnosticDescription.None;
VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(source, expectedGraph, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ExceptionDispatch_20()
{
string source = @"
class P
{
void M(bool b)
/*<bind>*/{
try
{
try
{
ThisCanThrow();
}
catch when (ThisCanThrow() && false)
{
}
}
catch
{
b = true;
}
}/*</bind>*/
static bool ThisCanThrow() => throw null;
}
";
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Entering: {R1} {R2} {R3} {R4}
.try {R1, R2}
{
.try {R3, R4}
{
Block[B1] - Block
Predecessors: [B0]
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'ThisCanThrow();')
Expression:
IInvocationOperation (System.Boolean P.ThisCanThrow()) (OperationKind.Invocation, Type: System.Boolean) (Syntax: 'ThisCanThrow()')
Instance Receiver:
null
Arguments(0)
Next (Regular) Block[B7]
Leaving: {R4} {R3} {R2} {R1}
}
.catch {R5} (System.Object)
{
.filter {R6}
{
Block[B2] - Block
Predecessors (0)
Statements (0)
Jump if False (Regular) to Block[B4]
IInvocationOperation (System.Boolean P.ThisCanThrow()) (OperationKind.Invocation, Type: System.Boolean) (Syntax: 'ThisCanThrow()')
Instance Receiver:
null
Arguments(0)
Next (Regular) Block[B3]
Block[B3] - Block
Predecessors: [B2]
Statements (0)
Jump if True (Regular) to Block[B5]
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: False) (Syntax: 'false')
Leaving: {R6}
Entering: {R7}
Next (Regular) Block[B4]
Block[B4] - Block
Predecessors: [B2] [B3]
Statements (0)
Next (StructuredExceptionHandling) Block[null]
}
.handler {R7}
{
Block[B5] - Block [UnReachable]
Predecessors: [B3]
Statements (0)
Next (Regular) Block[B7]
Leaving: {R7} {R5} {R3} {R2} {R1}
}
}
}
.catch {R8} (System.Object)
{
Block[B6] - Block
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'b = true;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'b = true')
Left:
IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'b')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Next (Regular) Block[B7]
Leaving: {R8} {R1}
}
Block[B7] - Exit
Predecessors: [B1] [B5] [B6]
Statements (0)
";
var expectedDiagnostics = DiagnosticDescription.None;
VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(source, expectedGraph, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ExceptionDispatch_21()
{
string source = @"
class P
{
void M(bool b)
/*<bind>*/{
try
{
try
{
ThisCanThrow();
}
catch when (false && ThisCanThrow())
{
}
}
catch
{
b = true;
}
}/*</bind>*/
static bool ThisCanThrow() => throw null;
}
";
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Entering: {R1} {R2} {R3} {R4}
.try {R1, R2}
{
.try {R3, R4}
{
Block[B1] - Block
Predecessors: [B0]
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'ThisCanThrow();')
Expression:
IInvocationOperation (System.Boolean P.ThisCanThrow()) (OperationKind.Invocation, Type: System.Boolean) (Syntax: 'ThisCanThrow()')
Instance Receiver:
null
Arguments(0)
Next (Regular) Block[B7]
Leaving: {R4} {R3} {R2} {R1}
}
.catch {R5} (System.Object)
{
.filter {R6}
{
Block[B2] - Block
Predecessors (0)
Statements (0)
Jump if False (Regular) to Block[B4]
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: False) (Syntax: 'false')
Next (Regular) Block[B3]
Block[B3] - Block [UnReachable]
Predecessors: [B2]
Statements (0)
Jump if True (Regular) to Block[B5]
IInvocationOperation (System.Boolean P.ThisCanThrow()) (OperationKind.Invocation, Type: System.Boolean) (Syntax: 'ThisCanThrow()')
Instance Receiver:
null
Arguments(0)
Leaving: {R6}
Entering: {R7}
Next (Regular) Block[B4]
Block[B4] - Block
Predecessors: [B2] [B3]
Statements (0)
Next (StructuredExceptionHandling) Block[null]
}
.handler {R7}
{
Block[B5] - Block [UnReachable]
Predecessors: [B3]
Statements (0)
Next (Regular) Block[B7]
Leaving: {R7} {R5} {R3} {R2} {R1}
}
}
}
.catch {R8} (System.Object)
{
Block[B6] - Block
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'b = true;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'b = true')
Left:
IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'b')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Next (Regular) Block[B7]
Leaving: {R8} {R1}
}
Block[B7] - Exit
Predecessors: [B1] [B5] [B6]
Statements (0)
";
var expectedDiagnostics = DiagnosticDescription.None;
VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(source, expectedGraph, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ExceptionDispatch_22()
{
string source = @"
class P
{
void M(bool b)
/*<bind>*/{
try
{
ThisCanThrow();
}
catch
{
}
catch
{
b = true;
}
}/*</bind>*/
static bool ThisCanThrow() => throw null;
}
";
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Entering: {R1} {R2}
.try {R1, R2}
{
Block[B1] - Block
Predecessors: [B0]
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'ThisCanThrow();')
Expression:
IInvocationOperation (System.Boolean P.ThisCanThrow()) (OperationKind.Invocation, Type: System.Boolean) (Syntax: 'ThisCanThrow()')
Instance Receiver:
null
Arguments(0)
Next (Regular) Block[B4]
Leaving: {R2} {R1}
}
.catch {R3} (System.Object)
{
Block[B2] - Block
Predecessors (0)
Statements (0)
Next (Regular) Block[B4]
Leaving: {R3} {R1}
}
.catch {R4} (System.Object)
{
Block[B3] - Block [UnReachable]
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'b = true;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'b = true')
Left:
IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'b')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Next (Regular) Block[B4]
Leaving: {R4} {R1}
}
Block[B4] - Exit
Predecessors: [B1] [B2] [B3]
Statements (0)
";
var expectedDiagnostics = new[] {
// file.cs(13,9): error CS1017: Catch clauses cannot follow the general catch clause of a try statement
// catch
Diagnostic(ErrorCode.ERR_TooManyCatches, "catch").WithLocation(13, 9)
};
VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(source, expectedGraph, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ExceptionDispatch_23()
{
string source = @"
class P
{
void M(bool b)
/*<bind>*/{
try
{
ThisCanThrow();
}
catch when (true)
{
}
catch
{
b = true;
}
}/*</bind>*/
static bool ThisCanThrow() => throw null;
}
";
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Entering: {R1} {R2}
.try {R1, R2}
{
Block[B1] - Block
Predecessors: [B0]
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'ThisCanThrow();')
Expression:
IInvocationOperation (System.Boolean P.ThisCanThrow()) (OperationKind.Invocation, Type: System.Boolean) (Syntax: 'ThisCanThrow()')
Instance Receiver:
null
Arguments(0)
Next (Regular) Block[B5]
Leaving: {R2} {R1}
}
.catch {R3} (System.Object)
{
.filter {R4}
{
Block[B2] - Block
Predecessors (0)
Statements (0)
Jump if True (Regular) to Block[B3]
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Leaving: {R4}
Entering: {R5}
Next (StructuredExceptionHandling) Block[null]
}
.handler {R5}
{
Block[B3] - Block
Predecessors: [B2]
Statements (0)
Next (Regular) Block[B5]
Leaving: {R5} {R3} {R1}
}
}
.catch {R6} (System.Object)
{
Block[B4] - Block [UnReachable]
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'b = true;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'b = true')
Left:
IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'b')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Next (Regular) Block[B5]
Leaving: {R6} {R1}
}
Block[B5] - Exit
Predecessors: [B1] [B3] [B4]
Statements (0)
";
var expectedDiagnostics = new[] {
// file.cs(10,21): warning CS7095: Filter expression is a constant 'true', consider removing the filter
// catch when (true)
Diagnostic(ErrorCode.WRN_FilterIsConstantTrue, "true").WithLocation(10, 21)
};
VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(source, expectedGraph, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ExceptionDispatch_24()
{
string source = @"
class P
{
void M(bool b)
/*<bind>*/{
try
{
ThisCanThrow();
}
catch when (false)
{
}
catch
{
b = true;
}
}/*</bind>*/
static bool ThisCanThrow() => throw null;
}
";
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Entering: {R1} {R2}
.try {R1, R2}
{
Block[B1] - Block
Predecessors: [B0]
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'ThisCanThrow();')
Expression:
IInvocationOperation (System.Boolean P.ThisCanThrow()) (OperationKind.Invocation, Type: System.Boolean) (Syntax: 'ThisCanThrow()')
Instance Receiver:
null
Arguments(0)
Next (Regular) Block[B5]
Leaving: {R2} {R1}
}
.catch {R3} (System.Object)
{
.filter {R4}
{
Block[B2] - Block
Predecessors (0)
Statements (0)
Jump if True (Regular) to Block[B3]
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: False) (Syntax: 'false')
Leaving: {R4}
Entering: {R5}
Next (StructuredExceptionHandling) Block[null]
}
.handler {R5}
{
Block[B3] - Block [UnReachable]
Predecessors: [B2]
Statements (0)
Next (Regular) Block[B5]
Leaving: {R5} {R3} {R1}
}
}
.catch {R6} (System.Object)
{
Block[B4] - Block
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'b = true;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'b = true')
Left:
IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'b')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Next (Regular) Block[B5]
Leaving: {R6} {R1}
}
Block[B5] - Exit
Predecessors: [B1] [B3] [B4]
Statements (0)
";
var expectedDiagnostics = new[] {
// file.cs(10,21): warning CS8359: Filter expression is a constant 'false', consider removing the catch clause
// catch when (false)
Diagnostic(ErrorCode.WRN_FilterIsConstantFalse, "false").WithLocation(10, 21)
};
VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(source, expectedGraph, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ExceptionDispatch_25()
{
string source = @"
class P
{
void M(bool b)
/*<bind>*/{
try
{
ThisCanThrow();
}
catch when (ThisCanThrow())
{
}
catch
{
b = true;
}
}/*</bind>*/
static bool ThisCanThrow() => throw null;
}
";
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Entering: {R1} {R2}
.try {R1, R2}
{
Block[B1] - Block
Predecessors: [B0]
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'ThisCanThrow();')
Expression:
IInvocationOperation (System.Boolean P.ThisCanThrow()) (OperationKind.Invocation, Type: System.Boolean) (Syntax: 'ThisCanThrow()')
Instance Receiver:
null
Arguments(0)
Next (Regular) Block[B5]
Leaving: {R2} {R1}
}
.catch {R3} (System.Object)
{
.filter {R4}
{
Block[B2] - Block
Predecessors (0)
Statements (0)
Jump if True (Regular) to Block[B3]
IInvocationOperation (System.Boolean P.ThisCanThrow()) (OperationKind.Invocation, Type: System.Boolean) (Syntax: 'ThisCanThrow()')
Instance Receiver:
null
Arguments(0)
Leaving: {R4}
Entering: {R5}
Next (StructuredExceptionHandling) Block[null]
}
.handler {R5}
{
Block[B3] - Block
Predecessors: [B2]
Statements (0)
Next (Regular) Block[B5]
Leaving: {R5} {R3} {R1}
}
}
.catch {R6} (System.Object)
{
Block[B4] - Block
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'b = true;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'b = true')
Left:
IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'b')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Next (Regular) Block[B5]
Leaving: {R6} {R1}
}
Block[B5] - Exit
Predecessors: [B1] [B3] [B4]
Statements (0)
";
var expectedDiagnostics = DiagnosticDescription.None;
VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(source, expectedGraph, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ExceptionDispatch_26()
{
string source = @"
class P
{
void M(bool b)
/*<bind>*/{
try
{
try
{
ThisCanThrow();
}
catch when (ThisCanThrow())
{
}
catch
{
}
}
catch
{
b = true;
}
}/*</bind>*/
static bool ThisCanThrow() => throw null;
}
";
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Entering: {R1} {R2} {R3} {R4}
.try {R1, R2}
{
.try {R3, R4}
{
Block[B1] - Block
Predecessors: [B0]
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'ThisCanThrow();')
Expression:
IInvocationOperation (System.Boolean P.ThisCanThrow()) (OperationKind.Invocation, Type: System.Boolean) (Syntax: 'ThisCanThrow()')
Instance Receiver:
null
Arguments(0)
Next (Regular) Block[B6]
Leaving: {R4} {R3} {R2} {R1}
}
.catch {R5} (System.Object)
{
.filter {R6}
{
Block[B2] - Block
Predecessors (0)
Statements (0)
Jump if True (Regular) to Block[B3]
IInvocationOperation (System.Boolean P.ThisCanThrow()) (OperationKind.Invocation, Type: System.Boolean) (Syntax: 'ThisCanThrow()')
Instance Receiver:
null
Arguments(0)
Leaving: {R6}
Entering: {R7}
Next (StructuredExceptionHandling) Block[null]
}
.handler {R7}
{
Block[B3] - Block
Predecessors: [B2]
Statements (0)
Next (Regular) Block[B6]
Leaving: {R7} {R5} {R3} {R2} {R1}
}
}
.catch {R8} (System.Object)
{
Block[B4] - Block
Predecessors (0)
Statements (0)
Next (Regular) Block[B6]
Leaving: {R8} {R3} {R2} {R1}
}
}
.catch {R9} (System.Object)
{
Block[B5] - Block [UnReachable]
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'b = true;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'b = true')
Left:
IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'b')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Next (Regular) Block[B6]
Leaving: {R9} {R1}
}
Block[B6] - Exit
Predecessors: [B1] [B3] [B4] [B5]
Statements (0)
";
var expectedDiagnostics = DiagnosticDescription.None;
VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(source, expectedGraph, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ExceptionDispatch_27()
{
string source = @"
class P
{
void M(bool b)
/*<bind>*/{
try
{
ThisCanThrow();
}
catch when (ThisCanThrow() || true)
{
}
catch
{
b = true;
}
}/*</bind>*/
static bool ThisCanThrow() => throw null;
}
";
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Entering: {R1} {R2}
.try {R1, R2}
{
Block[B1] - Block
Predecessors: [B0]
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'ThisCanThrow();')
Expression:
IInvocationOperation (System.Boolean P.ThisCanThrow()) (OperationKind.Invocation, Type: System.Boolean) (Syntax: 'ThisCanThrow()')
Instance Receiver:
null
Arguments(0)
Next (Regular) Block[B6]
Leaving: {R2} {R1}
}
.catch {R3} (System.Object)
{
.filter {R4}
{
Block[B2] - Block
Predecessors (0)
Statements (0)
Jump if True (Regular) to Block[B4]
IInvocationOperation (System.Boolean P.ThisCanThrow()) (OperationKind.Invocation, Type: System.Boolean) (Syntax: 'ThisCanThrow()')
Instance Receiver:
null
Arguments(0)
Leaving: {R4}
Entering: {R5}
Next (Regular) Block[B3]
Block[B3] - Block
Predecessors: [B2]
Statements (0)
Jump if True (Regular) to Block[B4]
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Leaving: {R4}
Entering: {R5}
Next (StructuredExceptionHandling) Block[null]
}
.handler {R5}
{
Block[B4] - Block
Predecessors: [B2] [B3]
Statements (0)
Next (Regular) Block[B6]
Leaving: {R5} {R3} {R1}
}
}
.catch {R6} (System.Object)
{
Block[B5] - Block
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'b = true;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'b = true')
Left:
IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'b')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Next (Regular) Block[B6]
Leaving: {R6} {R1}
}
Block[B6] - Exit
Predecessors: [B1] [B4] [B5]
Statements (0)
";
var expectedDiagnostics = DiagnosticDescription.None;
VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(source, expectedGraph, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ExceptionDispatch_28()
{
string source = @"
class P
{
void M(bool b)
/*<bind>*/{
try
{
ThisCanThrow();
}
catch when (true || ThisCanThrow())
{
}
catch
{
b = true;
}
}/*</bind>*/
static bool ThisCanThrow() => throw null;
}
";
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Entering: {R1} {R2}
.try {R1, R2}
{
Block[B1] - Block
Predecessors: [B0]
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'ThisCanThrow();')
Expression:
IInvocationOperation (System.Boolean P.ThisCanThrow()) (OperationKind.Invocation, Type: System.Boolean) (Syntax: 'ThisCanThrow()')
Instance Receiver:
null
Arguments(0)
Next (Regular) Block[B6]
Leaving: {R2} {R1}
}
.catch {R3} (System.Object)
{
.filter {R4}
{
Block[B2] - Block
Predecessors (0)
Statements (0)
Jump if True (Regular) to Block[B4]
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Leaving: {R4}
Entering: {R5}
Next (Regular) Block[B3]
Block[B3] - Block [UnReachable]
Predecessors: [B2]
Statements (0)
Jump if True (Regular) to Block[B4]
IInvocationOperation (System.Boolean P.ThisCanThrow()) (OperationKind.Invocation, Type: System.Boolean) (Syntax: 'ThisCanThrow()')
Instance Receiver:
null
Arguments(0)
Leaving: {R4}
Entering: {R5}
Next (StructuredExceptionHandling) Block[null]
}
.handler {R5}
{
Block[B4] - Block
Predecessors: [B2] [B3]
Statements (0)
Next (Regular) Block[B6]
Leaving: {R5} {R3} {R1}
}
}
.catch {R6} (System.Object)
{
Block[B5] - Block [UnReachable]
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'b = true;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'b = true')
Left:
IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'b')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Next (Regular) Block[B6]
Leaving: {R6} {R1}
}
Block[B6] - Exit
Predecessors: [B1] [B4] [B5]
Statements (0)
";
var expectedDiagnostics = DiagnosticDescription.None;
VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(source, expectedGraph, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ExceptionDispatch_29()
{
string source = @"
class P
{
void M(bool b)
/*<bind>*/{
try
{
ThisCanThrow();
}
catch when (ThisCanThrow() && false)
{
}
catch
{
b = true;
}
}/*</bind>*/
static bool ThisCanThrow() => throw null;
}
";
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Entering: {R1} {R2}
.try {R1, R2}
{
Block[B1] - Block
Predecessors: [B0]
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'ThisCanThrow();')
Expression:
IInvocationOperation (System.Boolean P.ThisCanThrow()) (OperationKind.Invocation, Type: System.Boolean) (Syntax: 'ThisCanThrow()')
Instance Receiver:
null
Arguments(0)
Next (Regular) Block[B7]
Leaving: {R2} {R1}
}
.catch {R3} (System.Object)
{
.filter {R4}
{
Block[B2] - Block
Predecessors (0)
Statements (0)
Jump if False (Regular) to Block[B4]
IInvocationOperation (System.Boolean P.ThisCanThrow()) (OperationKind.Invocation, Type: System.Boolean) (Syntax: 'ThisCanThrow()')
Instance Receiver:
null
Arguments(0)
Next (Regular) Block[B3]
Block[B3] - Block
Predecessors: [B2]
Statements (0)
Jump if True (Regular) to Block[B5]
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: False) (Syntax: 'false')
Leaving: {R4}
Entering: {R5}
Next (Regular) Block[B4]
Block[B4] - Block
Predecessors: [B2] [B3]
Statements (0)
Next (StructuredExceptionHandling) Block[null]
}
.handler {R5}
{
Block[B5] - Block [UnReachable]
Predecessors: [B3]
Statements (0)
Next (Regular) Block[B7]
Leaving: {R5} {R3} {R1}
}
}
.catch {R6} (System.Object)
{
Block[B6] - Block
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'b = true;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'b = true')
Left:
IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'b')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Next (Regular) Block[B7]
Leaving: {R6} {R1}
}
Block[B7] - Exit
Predecessors: [B1] [B5] [B6]
Statements (0)
";
var expectedDiagnostics = DiagnosticDescription.None;
VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(source, expectedGraph, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ExceptionDispatch_30()
{
string source = @"
class P
{
void M(bool b)
/*<bind>*/{
try
{
ThisCanThrow();
}
catch when (false && ThisCanThrow())
{
}
catch
{
b = true;
}
}/*</bind>*/
static bool ThisCanThrow() => throw null;
}
";
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Entering: {R1} {R2}
.try {R1, R2}
{
Block[B1] - Block
Predecessors: [B0]
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'ThisCanThrow();')
Expression:
IInvocationOperation (System.Boolean P.ThisCanThrow()) (OperationKind.Invocation, Type: System.Boolean) (Syntax: 'ThisCanThrow()')
Instance Receiver:
null
Arguments(0)
Next (Regular) Block[B7]
Leaving: {R2} {R1}
}
.catch {R3} (System.Object)
{
.filter {R4}
{
Block[B2] - Block
Predecessors (0)
Statements (0)
Jump if False (Regular) to Block[B4]
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: False) (Syntax: 'false')
Next (Regular) Block[B3]
Block[B3] - Block [UnReachable]
Predecessors: [B2]
Statements (0)
Jump if True (Regular) to Block[B5]
IInvocationOperation (System.Boolean P.ThisCanThrow()) (OperationKind.Invocation, Type: System.Boolean) (Syntax: 'ThisCanThrow()')
Instance Receiver:
null
Arguments(0)
Leaving: {R4}
Entering: {R5}
Next (Regular) Block[B4]
Block[B4] - Block
Predecessors: [B2] [B3]
Statements (0)
Next (StructuredExceptionHandling) Block[null]
}
.handler {R5}
{
Block[B5] - Block [UnReachable]
Predecessors: [B3]
Statements (0)
Next (Regular) Block[B7]
Leaving: {R5} {R3} {R1}
}
}
.catch {R6} (System.Object)
{
Block[B6] - Block
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'b = true;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'b = true')
Left:
IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'b')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Next (Regular) Block[B7]
Leaving: {R6} {R1}
}
Block[B7] - Exit
Predecessors: [B1] [B5] [B6]
Statements (0)
";
var expectedDiagnostics = DiagnosticDescription.None;
VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(source, expectedGraph, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ExceptionDispatch_31()
{
string source = @"
class P
{
void M(bool b)
/*<bind>*/{
try
{
try
{
ThisCanThrow();
}
catch
{
ThisCanThrow();
}
}
catch
{
b = true;
}
}/*</bind>*/
static bool ThisCanThrow() => throw null;
}
";
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Entering: {R1} {R2} {R3} {R4}
.try {R1, R2}
{
.try {R3, R4}
{
Block[B1] - Block
Predecessors: [B0]
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'ThisCanThrow();')
Expression:
IInvocationOperation (System.Boolean P.ThisCanThrow()) (OperationKind.Invocation, Type: System.Boolean) (Syntax: 'ThisCanThrow()')
Instance Receiver:
null
Arguments(0)
Next (Regular) Block[B4]
Leaving: {R4} {R3} {R2} {R1}
}
.catch {R5} (System.Object)
{
Block[B2] - Block
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'ThisCanThrow();')
Expression:
IInvocationOperation (System.Boolean P.ThisCanThrow()) (OperationKind.Invocation, Type: System.Boolean) (Syntax: 'ThisCanThrow()')
Instance Receiver:
null
Arguments(0)
Next (Regular) Block[B4]
Leaving: {R5} {R3} {R2} {R1}
}
}
.catch {R6} (System.Object)
{
Block[B3] - Block
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'b = true;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'b = true')
Left:
IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'b')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Next (Regular) Block[B4]
Leaving: {R6} {R1}
}
Block[B4] - Exit
Predecessors: [B1] [B2] [B3]
Statements (0)
";
var expectedDiagnostics = DiagnosticDescription.None;
VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(source, expectedGraph, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ExceptionDispatch_32()
{
string source = @"
class P
{
void M(bool b)
/*<bind>*/{
try
{
ThisCanThrow();
}
catch (System.NullReferenceException e)
{
ThisCanThrow();
}
catch
{
b = true;
}
}/*</bind>*/
static bool ThisCanThrow() => throw null;
}
";
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Entering: {R1} {R2}
.try {R1, R2}
{
Block[B1] - Block
Predecessors: [B0]
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'ThisCanThrow();')
Expression:
IInvocationOperation (System.Boolean P.ThisCanThrow()) (OperationKind.Invocation, Type: System.Boolean) (Syntax: 'ThisCanThrow()')
Instance Receiver:
null
Arguments(0)
Next (Regular) Block[B4]
Leaving: {R2} {R1}
}
.catch {R3} (System.NullReferenceException)
{
Locals: [System.NullReferenceException e]
Block[B2] - Block
Predecessors (0)
Statements (2)
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: null, IsImplicit) (Syntax: '(System.Nul ... xception e)')
Left:
ILocalReferenceOperation: e (IsDeclaration: True) (OperationKind.LocalReference, Type: System.NullReferenceException, IsImplicit) (Syntax: '(System.Nul ... xception e)')
Right:
ICaughtExceptionOperation (OperationKind.CaughtException, Type: System.NullReferenceException, IsImplicit) (Syntax: '(System.Nul ... xception e)')
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'ThisCanThrow();')
Expression:
IInvocationOperation (System.Boolean P.ThisCanThrow()) (OperationKind.Invocation, Type: System.Boolean) (Syntax: 'ThisCanThrow()')
Instance Receiver:
null
Arguments(0)
Next (Regular) Block[B4]
Leaving: {R3} {R1}
}
.catch {R4} (System.Object)
{
Block[B3] - Block
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'b = true;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'b = true')
Left:
IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'b')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Next (Regular) Block[B4]
Leaving: {R4} {R1}
}
Block[B4] - Exit
Predecessors: [B1] [B2] [B3]
Statements (0)
";
var expectedDiagnostics = new[] {
// file.cs(10,46): warning CS0168: The variable 'e' is declared but never used
// catch (System.NullReferenceException e)
Diagnostic(ErrorCode.WRN_UnreferencedVar, "e").WithArguments("e").WithLocation(10, 46)
};
VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(source, expectedGraph, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ExceptionDispatch_33()
{
string source = @"
class P
{
void M(bool b)
/*<bind>*/{
try
{
try
{
ThisCanThrow();
}
catch (System.NullReferenceException e)
{
}
}
catch
{
b = true;
}
}/*</bind>*/
static bool ThisCanThrow() => throw null;
}
";
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Entering: {R1} {R2} {R3} {R4}
.try {R1, R2}
{
.try {R3, R4}
{
Block[B1] - Block
Predecessors: [B0]
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'ThisCanThrow();')
Expression:
IInvocationOperation (System.Boolean P.ThisCanThrow()) (OperationKind.Invocation, Type: System.Boolean) (Syntax: 'ThisCanThrow()')
Instance Receiver:
null
Arguments(0)
Next (Regular) Block[B4]
Leaving: {R4} {R3} {R2} {R1}
}
.catch {R5} (System.NullReferenceException)
{
Locals: [System.NullReferenceException e]
Block[B2] - Block
Predecessors (0)
Statements (1)
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: null, IsImplicit) (Syntax: '(System.Nul ... xception e)')
Left:
ILocalReferenceOperation: e (IsDeclaration: True) (OperationKind.LocalReference, Type: System.NullReferenceException, IsImplicit) (Syntax: '(System.Nul ... xception e)')
Right:
ICaughtExceptionOperation (OperationKind.CaughtException, Type: System.NullReferenceException, IsImplicit) (Syntax: '(System.Nul ... xception e)')
Next (Regular) Block[B4]
Leaving: {R5} {R3} {R2} {R1}
}
}
.catch {R6} (System.Object)
{
Block[B3] - Block
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'b = true;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'b = true')
Left:
IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'b')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Next (Regular) Block[B4]
Leaving: {R6} {R1}
}
Block[B4] - Exit
Predecessors: [B1] [B2] [B3]
Statements (0)
";
var expectedDiagnostics = new[] {
// file.cs(12,50): warning CS0168: The variable 'e' is declared but never used
// catch (System.NullReferenceException e)
Diagnostic(ErrorCode.WRN_UnreferencedVar, "e").WithArguments("e").WithLocation(12, 50)
};
VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(source, expectedGraph, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ExceptionDispatch_34()
{
string source = @"
class P
{
void M(bool b)
/*<bind>*/{
try
{
}
finally
{
if (true) throw null;
}
}/*</bind>*/
}
";
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Entering: {R1} {R2}
.try {R1, R2}
{
Block[B1] - Block
Predecessors: [B0]
Statements (0)
Next (Regular) Block[B4]
Finalizing: {R3}
Leaving: {R2} {R1}
}
.finally {R3}
{
Block[B2] - Block
Predecessors (0)
Statements (0)
Jump if False (Regular) to Block[B3]
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Next (Throw) Block[null]
ILiteralOperation (OperationKind.Literal, Type: null, Constant: null) (Syntax: 'null')
Block[B3] - Block [UnReachable]
Predecessors: [B2]
Statements (0)
Next (StructuredExceptionHandling) Block[null]
}
Block[B4] - Exit [UnReachable]
Predecessors: [B1]
Statements (0)
";
var expectedDiagnostics = DiagnosticDescription.None;
VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(source, expectedGraph, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ExceptionDispatch_35()
{
string source = @"
class P
{
void M(bool b)
/*<bind>*/{
try
{
}
finally
{
if (false) throw null;
}
}/*</bind>*/
}
";
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Entering: {R1} {R2}
.try {R1, R2}
{
Block[B1] - Block
Predecessors: [B0]
Statements (0)
Next (Regular) Block[B4]
Finalizing: {R3}
Leaving: {R2} {R1}
}
.finally {R3}
{
Block[B2] - Block
Predecessors (0)
Statements (0)
Jump if False (Regular) to Block[B3]
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: False) (Syntax: 'false')
Next (Throw) Block[null]
ILiteralOperation (OperationKind.Literal, Type: null, Constant: null) (Syntax: 'null')
Block[B3] - Block
Predecessors: [B2]
Statements (0)
Next (StructuredExceptionHandling) Block[null]
}
Block[B4] - Exit
Predecessors: [B1]
Statements (0)
";
var expectedDiagnostics = DiagnosticDescription.None;
VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(source, expectedGraph, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ExceptionDispatch_36()
{
string source = @"
class P
{
void M(bool b)
/*<bind>*/{
try
{
}
finally
{
if (b) throw null;
}
}/*</bind>*/
}
";
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Entering: {R1} {R2}
.try {R1, R2}
{
Block[B1] - Block
Predecessors: [B0]
Statements (0)
Next (Regular) Block[B4]
Finalizing: {R3}
Leaving: {R2} {R1}
}
.finally {R3}
{
Block[B2] - Block
Predecessors (0)
Statements (0)
Jump if False (Regular) to Block[B3]
IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'b')
Next (Throw) Block[null]
ILiteralOperation (OperationKind.Literal, Type: null, Constant: null) (Syntax: 'null')
Block[B3] - Block
Predecessors: [B2]
Statements (0)
Next (StructuredExceptionHandling) Block[null]
}
Block[B4] - Exit
Predecessors: [B1]
Statements (0)
";
var expectedDiagnostics = DiagnosticDescription.None;
VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(source, expectedGraph, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ExceptionDispatch_37()
{
string source = @"
class P
{
void M(bool b)
/*<bind>*/{
try
{
}
finally
{
if (true) goto label1;
throw null;
label1: ;
}
}/*</bind>*/
}
";
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Entering: {R1} {R2}
.try {R1, R2}
{
Block[B1] - Block
Predecessors: [B0]
Statements (0)
Next (Regular) Block[B5]
Finalizing: {R3}
Leaving: {R2} {R1}
}
.finally {R3}
{
Block[B2] - Block
Predecessors (0)
Statements (0)
Jump if False (Regular) to Block[B3]
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Next (Regular) Block[B4]
Block[B3] - Block [UnReachable]
Predecessors: [B2]
Statements (0)
Next (Throw) Block[null]
ILiteralOperation (OperationKind.Literal, Type: null, Constant: null) (Syntax: 'null')
Block[B4] - Block
Predecessors: [B2]
Statements (0)
Next (StructuredExceptionHandling) Block[null]
}
Block[B5] - Exit
Predecessors: [B1]
Statements (0)
";
var expectedDiagnostics = DiagnosticDescription.None;
VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(source, expectedGraph, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ExceptionDispatch_38()
{
string source = @"
class P
{
void M(bool b)
/*<bind>*/{
try
{
}
finally
{
if (false) goto label1;
throw null;
label1: ;
}
}/*</bind>*/
}
";
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Entering: {R1} {R2}
.try {R1, R2}
{
Block[B1] - Block
Predecessors: [B0]
Statements (0)
Next (Regular) Block[B5]
Finalizing: {R3}
Leaving: {R2} {R1}
}
.finally {R3}
{
Block[B2] - Block
Predecessors (0)
Statements (0)
Jump if False (Regular) to Block[B3]
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: False) (Syntax: 'false')
Next (Regular) Block[B4]
Block[B3] - Block
Predecessors: [B2]
Statements (0)
Next (Throw) Block[null]
ILiteralOperation (OperationKind.Literal, Type: null, Constant: null) (Syntax: 'null')
Block[B4] - Block [UnReachable]
Predecessors: [B2]
Statements (0)
Next (StructuredExceptionHandling) Block[null]
}
Block[B5] - Exit [UnReachable]
Predecessors: [B1]
Statements (0)
";
var expectedDiagnostics = new[] {
// file.cs(11,24): warning CS0162: Unreachable code detected
// if (false) goto label1;
Diagnostic(ErrorCode.WRN_UnreachableCode, "goto").WithLocation(11, 24),
// file.cs(13,1): warning CS0162: Unreachable code detected
// label1: ;
Diagnostic(ErrorCode.WRN_UnreachableCode, "label1").WithLocation(13, 1)
};
VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(source, expectedGraph, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ExceptionDispatch_39()
{
string source = @"
class P
{
void M(bool b)
/*<bind>*/{
try
{
ThisCanThrow();
}
catch
{
try
{
ThisCanThrow();
}
finally
{
if (false) goto label1;
throw;
label1: ;
}
b = false;
}
}/*</bind>*/
static bool ThisCanThrow() => throw null;
}
";
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Entering: {R1} {R2}
.try {R1, R2}
{
Block[B1] - Block
Predecessors: [B0]
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'ThisCanThrow();')
Expression:
IInvocationOperation (System.Boolean P.ThisCanThrow()) (OperationKind.Invocation, Type: System.Boolean) (Syntax: 'ThisCanThrow()')
Instance Receiver:
null
Arguments(0)
Next (Regular) Block[B5]
Leaving: {R2} {R1}
}
.catch {R3} (System.Object)
{
.try {R4, R5}
{
Block[B2] - Block
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'ThisCanThrow();')
Expression:
IInvocationOperation (System.Boolean P.ThisCanThrow()) (OperationKind.Invocation, Type: System.Boolean) (Syntax: 'ThisCanThrow()')
Instance Receiver:
null
Arguments(0)
Next (Regular) Block[B4]
Finalizing: {R6}
Leaving: {R5} {R4}
}
.finally {R6}
{
Block[B3] - Block
Predecessors (0)
Statements (0)
Jump if False (ReThrow) to Block[null]
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: False) (Syntax: 'false')
Next (StructuredExceptionHandling) Block[null]
}
Block[B4] - Block [UnReachable]
Predecessors: [B2]
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'b = false;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'b = false')
Left:
IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'b')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: False) (Syntax: 'false')
Next (Regular) Block[B5]
Leaving: {R3} {R1}
}
Block[B5] - Exit
Predecessors: [B1] [B4]
Statements (0)
";
var expectedDiagnostics = new[] {
// file.cs(19,17): error CS0724: A throw statement with no arguments is not allowed in a finally clause that is nested inside the nearest enclosing catch clause
// throw;
Diagnostic(ErrorCode.ERR_BadEmptyThrowInFinally, "throw").WithLocation(19, 17),
// file.cs(18,28): warning CS0162: Unreachable code detected
// if (false) goto label1;
Diagnostic(ErrorCode.WRN_UnreachableCode, "goto").WithLocation(18, 28),
// file.cs(20,5): warning CS0162: Unreachable code detected
// label1: ;
Diagnostic(ErrorCode.WRN_UnreachableCode, "label1").WithLocation(20, 5),
// file.cs(23,13): warning CS0162: Unreachable code detected
// b = false;
Diagnostic(ErrorCode.WRN_UnreachableCode, "b").WithLocation(23, 13)
};
VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(source, expectedGraph, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ExceptionDispatch_40()
{
string source = @"
class P
{
void M(bool b)
/*<bind>*/{
try
{
ThisCanThrow();
}
catch (System.NullReferenceException) when (true)
{
}
catch
{
b = true;
}
}/*</bind>*/
static bool ThisCanThrow() => throw null;
}
";
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Entering: {R1} {R2}
.try {R1, R2}
{
Block[B1] - Block
Predecessors: [B0]
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'ThisCanThrow();')
Expression:
IInvocationOperation (System.Boolean P.ThisCanThrow()) (OperationKind.Invocation, Type: System.Boolean) (Syntax: 'ThisCanThrow()')
Instance Receiver:
null
Arguments(0)
Next (Regular) Block[B5]
Leaving: {R2} {R1}
}
.catch {R3} (System.NullReferenceException)
{
.filter {R4}
{
Block[B2] - Block
Predecessors (0)
Statements (0)
Jump if True (Regular) to Block[B3]
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Leaving: {R4}
Entering: {R5}
Next (StructuredExceptionHandling) Block[null]
}
.handler {R5}
{
Block[B3] - Block
Predecessors: [B2]
Statements (0)
Next (Regular) Block[B5]
Leaving: {R5} {R3} {R1}
}
}
.catch {R6} (System.Object)
{
Block[B4] - Block
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'b = true;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'b = true')
Left:
IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'b')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Next (Regular) Block[B5]
Leaving: {R6} {R1}
}
Block[B5] - Exit
Predecessors: [B1] [B3] [B4]
Statements (0)
";
var expectedDiagnostics = new[] {
// file.cs(10,53): warning CS7095: Filter expression is a constant 'true', consider removing the filter
// catch (System.NullReferenceException) when (true)
Diagnostic(ErrorCode.WRN_FilterIsConstantTrue, "true").WithLocation(10, 53)
};
VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(source, expectedGraph, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ExceptionDispatch_41()
{
string source = @"
class P
{
void M(int x)
/*<bind>*/{
try
{
try
{
throw null;
}
finally
{
x = 1;
}
x = 2;
}
finally
{
x = 3;
}
}/*</bind>*/
static bool ThisCanThrow() => throw null;
}
";
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Entering: {R1} {R2} {R3} {R4}
.try {R1, R2}
{
.try {R3, R4}
{
Block[B1] - Block
Predecessors: [B0]
Statements (0)
Next (Throw) Block[null]
ILiteralOperation (OperationKind.Literal, Type: null, Constant: null) (Syntax: 'null')
}
.finally {R5}
{
Block[B2] - Block
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x = 1;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32) (Syntax: 'x = 1')
Left:
IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'x')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1')
Next (StructuredExceptionHandling) Block[null]
}
Block[B3] - Block [UnReachable]
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x = 2;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32) (Syntax: 'x = 2')
Left:
IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'x')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 2) (Syntax: '2')
Next (Regular) Block[B5]
Finalizing: {R6}
Leaving: {R2} {R1}
}
.finally {R6}
{
Block[B4] - Block
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x = 3;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32) (Syntax: 'x = 3')
Left:
IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'x')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 3) (Syntax: '3')
Next (StructuredExceptionHandling) Block[null]
}
Block[B5] - Exit [UnReachable]
Predecessors: [B3]
Statements (0)
";
var expectedDiagnostics = new[] {
// file.cs(17,13): warning CS0162: Unreachable code detected
// x = 2;
Diagnostic(ErrorCode.WRN_UnreachableCode, "x").WithLocation(17, 13)
};
VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(source, expectedGraph, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ExceptionDispatch_42()
{
string source = @"
class P
{
void M(int x)
/*<bind>*/{
try
{
try
{
throw null;
}
finally
{
throw null;
}
x = 2;
}
finally
{
x = 3;
}
}/*</bind>*/
static bool ThisCanThrow() => throw null;
}
";
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Entering: {R1} {R2} {R3} {R4}
.try {R1, R2}
{
.try {R3, R4}
{
Block[B1] - Block
Predecessors: [B0]
Statements (0)
Next (Throw) Block[null]
ILiteralOperation (OperationKind.Literal, Type: null, Constant: null) (Syntax: 'null')
}
.finally {R5}
{
Block[B2] - Block
Predecessors (0)
Statements (0)
Next (Throw) Block[null]
ILiteralOperation (OperationKind.Literal, Type: null, Constant: null) (Syntax: 'null')
}
Block[B3] - Block [UnReachable]
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x = 2;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32) (Syntax: 'x = 2')
Left:
IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'x')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 2) (Syntax: '2')
Next (Regular) Block[B5]
Finalizing: {R6}
Leaving: {R2} {R1}
}
.finally {R6}
{
Block[B4] - Block
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x = 3;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32) (Syntax: 'x = 3')
Left:
IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'x')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 3) (Syntax: '3')
Next (StructuredExceptionHandling) Block[null]
}
Block[B5] - Exit [UnReachable]
Predecessors: [B3]
Statements (0)
";
var expectedDiagnostics = new[] {
// file.cs(17,13): warning CS0162: Unreachable code detected
// x = 2;
Diagnostic(ErrorCode.WRN_UnreachableCode, "x").WithLocation(17, 13)
};
VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(source, expectedGraph, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ExceptionDispatch_43()
{
string source = @"
class P
{
void M(int x)
/*<bind>*/{
try
{
try
{
throw null;
}
finally
{
while (true) {}
}
x = 2;
}
finally
{
x = 3;
}
}/*</bind>*/
static bool ThisCanThrow() => throw null;
}
";
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Entering: {R1} {R2} {R3} {R4}
.try {R1, R2}
{
.try {R3, R4}
{
Block[B1] - Block
Predecessors: [B0]
Statements (0)
Next (Throw) Block[null]
ILiteralOperation (OperationKind.Literal, Type: null, Constant: null) (Syntax: 'null')
}
.finally {R5}
{
Block[B2] - Block
Predecessors: [B2]
Statements (0)
Jump if False (Regular) to Block[B3]
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Next (Regular) Block[B2]
Block[B3] - Block [UnReachable]
Predecessors: [B2]
Statements (0)
Next (StructuredExceptionHandling) Block[null]
}
Block[B4] - Block [UnReachable]
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x = 2;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32) (Syntax: 'x = 2')
Left:
IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'x')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 2) (Syntax: '2')
Next (Regular) Block[B6]
Finalizing: {R6}
Leaving: {R2} {R1}
}
.finally {R6}
{
Block[B5] - Block [UnReachable]
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x = 3;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32) (Syntax: 'x = 3')
Left:
IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'x')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 3) (Syntax: '3')
Next (StructuredExceptionHandling) Block[null]
}
Block[B6] - Exit [UnReachable]
Predecessors: [B4]
Statements (0)
";
var expectedDiagnostics = new[] {
// file.cs(17,13): warning CS0162: Unreachable code detected
// x = 2;
Diagnostic(ErrorCode.WRN_UnreachableCode, "x").WithLocation(17, 13)
};
VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(source, expectedGraph, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ExceptionDispatch_44()
{
string source = @"
class P
{
void M()
/*<bind>*/{
try
{
try
{
try
{
}
finally
{
return;
}
}
catch
{
}
}
finally
{
throw null;
}
}/*</bind>*/
}
";
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Entering: {R1} {R2} {R3} {R4} {R5} {R6}
.try {R1, R2}
{
.try {R3, R4}
{
.try {R5, R6}
{
Block[B1] - Block
Predecessors: [B0]
Statements (0)
Next (Regular) Block[B5]
Finalizing: {R7} {R9}
Leaving: {R6} {R5} {R4} {R3} {R2} {R1}
}
.finally {R7}
{
Block[B2] - Block
Predecessors (0)
Statements (0)
Next (Regular) Block[B5]
Finalizing: {R9}
Leaving: {R7} {R5} {R4} {R3} {R2} {R1}
}
}
.catch {R8} (System.Object)
{
Block[B3] - Block [UnReachable]
Predecessors (0)
Statements (0)
Next (Regular) Block[B5]
Finalizing: {R9}
Leaving: {R8} {R3} {R2} {R1}
}
}
.finally {R9}
{
Block[B4] - Block
Predecessors (0)
Statements (0)
Next (Throw) Block[null]
ILiteralOperation (OperationKind.Literal, Type: null, Constant: null) (Syntax: 'null')
}
Block[B5] - Exit [UnReachable]
Predecessors: [B1] [B2] [B3]
Statements (0)
";
var expectedDiagnostics = new[] {
// file.cs(15,21): error CS0157: Control cannot leave the body of a finally clause
// return;
Diagnostic(ErrorCode.ERR_BadFinallyLeave, "return").WithLocation(15, 21)
};
VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(source, expectedGraph, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void FinallyDispatch_01()
{
string source = @"
class P
{
void M(int x)
/*<bind>*/{
try
{
try
{
return;
}
finally
{
x = 1;
}
x = 2;
}
finally
{
x = 3;
}
}/*</bind>*/
static bool ThisCanThrow() => throw null;
}
";
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Entering: {R1} {R2} {R3} {R4}
.try {R1, R2}
{
.try {R3, R4}
{
Block[B1] - Block
Predecessors: [B0]
Statements (0)
Next (Regular) Block[B5]
Finalizing: {R5} {R6}
Leaving: {R4} {R3} {R2} {R1}
}
.finally {R5}
{
Block[B2] - Block
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x = 1;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32) (Syntax: 'x = 1')
Left:
IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'x')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1')
Next (StructuredExceptionHandling) Block[null]
}
Block[B3] - Block [UnReachable]
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x = 2;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32) (Syntax: 'x = 2')
Left:
IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'x')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 2) (Syntax: '2')
Next (Regular) Block[B5]
Finalizing: {R6}
Leaving: {R2} {R1}
}
.finally {R6}
{
Block[B4] - Block
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x = 3;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32) (Syntax: 'x = 3')
Left:
IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'x')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 3) (Syntax: '3')
Next (StructuredExceptionHandling) Block[null]
}
Block[B5] - Exit
Predecessors: [B1] [B3]
Statements (0)
";
var expectedDiagnostics = new[] {
// file.cs(17,13): warning CS0162: Unreachable code detected
// x = 2;
Diagnostic(ErrorCode.WRN_UnreachableCode, "x").WithLocation(17, 13)
};
VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(source, expectedGraph, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void FinallyDispatch_02()
{
string source = @"
class P
{
void M(int x)
/*<bind>*/{
try
{
try
{
return;
}
finally
{
throw null;
}
x = 2;
}
finally
{
x = 3;
}
}/*</bind>*/
static bool ThisCanThrow() => throw null;
}
";
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Entering: {R1} {R2} {R3} {R4}
.try {R1, R2}
{
.try {R3, R4}
{
Block[B1] - Block
Predecessors: [B0]
Statements (0)
Next (Regular) Block[B5]
Finalizing: {R5} {R6}
Leaving: {R4} {R3} {R2} {R1}
}
.finally {R5}
{
Block[B2] - Block
Predecessors (0)
Statements (0)
Next (Throw) Block[null]
ILiteralOperation (OperationKind.Literal, Type: null, Constant: null) (Syntax: 'null')
}
Block[B3] - Block [UnReachable]
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x = 2;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32) (Syntax: 'x = 2')
Left:
IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'x')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 2) (Syntax: '2')
Next (Regular) Block[B5]
Finalizing: {R6}
Leaving: {R2} {R1}
}
.finally {R6}
{
Block[B4] - Block
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x = 3;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32) (Syntax: 'x = 3')
Left:
IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'x')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 3) (Syntax: '3')
Next (StructuredExceptionHandling) Block[null]
}
Block[B5] - Exit [UnReachable]
Predecessors: [B1] [B3]
Statements (0)
";
var expectedDiagnostics = new[] {
// file.cs(17,13): warning CS0162: Unreachable code detected
// x = 2;
Diagnostic(ErrorCode.WRN_UnreachableCode, "x").WithLocation(17, 13)
};
VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(source, expectedGraph, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void FinallyDispatch_03()
{
string source = @"
class P
{
void M(int x)
/*<bind>*/{
try
{
try
{
return;
}
finally
{
while (true) {}
}
x = 2;
}
finally
{
x = 3;
}
}/*</bind>*/
static bool ThisCanThrow() => throw null;
}
";
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Entering: {R1} {R2} {R3} {R4}
.try {R1, R2}
{
.try {R3, R4}
{
Block[B1] - Block
Predecessors: [B0]
Statements (0)
Next (Regular) Block[B6]
Finalizing: {R5} {R6}
Leaving: {R4} {R3} {R2} {R1}
}
.finally {R5}
{
Block[B2] - Block
Predecessors: [B2]
Statements (0)
Jump if False (Regular) to Block[B3]
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Next (Regular) Block[B2]
Block[B3] - Block [UnReachable]
Predecessors: [B2]
Statements (0)
Next (StructuredExceptionHandling) Block[null]
}
Block[B4] - Block [UnReachable]
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x = 2;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32) (Syntax: 'x = 2')
Left:
IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'x')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 2) (Syntax: '2')
Next (Regular) Block[B6]
Finalizing: {R6}
Leaving: {R2} {R1}
}
.finally {R6}
{
Block[B5] - Block [UnReachable]
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x = 3;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32) (Syntax: 'x = 3')
Left:
IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'x')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 3) (Syntax: '3')
Next (StructuredExceptionHandling) Block[null]
}
Block[B6] - Exit [UnReachable]
Predecessors: [B1] [B4]
Statements (0)
";
var expectedDiagnostics = new[] {
// file.cs(17,13): warning CS0162: Unreachable code detected
// x = 2;
Diagnostic(ErrorCode.WRN_UnreachableCode, "x").WithLocation(17, 13)
};
VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(source, expectedGraph, expectedDiagnostics);
}
// PROTOTYPE(dataflow): Add flow graph tests to VB.
}
}
......@@ -54,6 +54,8 @@ public BasicBlock(BasicBlockKind kind)
public int Ordinal { get; internal set; } = -1;
public bool IsReachable { get; internal set; } = false;
/// <summary>
/// Enclosing region
/// </summary>
......
......@@ -190,6 +190,11 @@ public sealed class Region
}
#endif
}
internal bool ContainsBlock(int destinationOrdinal)
{
return FirstBlockOrdinal <= destinationOrdinal && LastBlockOrdinal >= destinationOrdinal;
}
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Concurrent;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
......@@ -58,6 +57,7 @@ public static ControlFlowGraph Create(IBlockOperation body)
ControlFlowGraph.Region region = root.ToImmutableRegionAndFree(blocks);
root = null;
CalculateBranchLeaveEnterLists(blocks);
MarkReachableBlocks(blocks);
Debug.Assert(builder._evalStack.Count == 0);
builder._evalStack.Free();
......@@ -67,6 +67,351 @@ public static ControlFlowGraph Create(IBlockOperation body)
return new ControlFlowGraph(blocks.ToImmutableAndFree(), region);
}
private static void MarkReachableBlocks(ArrayBuilder<BasicBlock> blocks)
{
var continueDispatchAfterFilterOrFinally = PooledDictionary<ControlFlowGraph.Region, bool>.GetInstance();
var dispatchedExceptionsFromRegions = PooledHashSet<ControlFlowGraph.Region>.GetInstance();
MarkReachableBlocks(blocks, firstBlockOrdinal: 0, lastBlockOrdinal: blocks.Count - 1,
outOfRangeBlocksToVisit: null,
continueDispatchAfterFilterOrFinally,
dispatchedExceptionsFromRegions,
out _);
continueDispatchAfterFilterOrFinally.Free();
dispatchedExceptionsFromRegions.Free();
}
private static BitVector MarkReachableBlocks(
ArrayBuilder<BasicBlock> blocks,
int firstBlockOrdinal,
int lastBlockOrdinal,
ArrayBuilder<BasicBlock> outOfRangeBlocksToVisit,
PooledDictionary<ControlFlowGraph.Region, bool> continueDispatchAfterFilterOrFinally,
PooledHashSet<ControlFlowGraph.Region> dispatchedExceptionsFromRegions,
out bool fellThrough)
{
var visited = BitVector.Empty;
var toVisit = ArrayBuilder<BasicBlock>.GetInstance();
fellThrough = false;
toVisit.Push(blocks[firstBlockOrdinal]);
do
{
BasicBlock current = toVisit.Pop();
if (current.Ordinal < firstBlockOrdinal || current.Ordinal > lastBlockOrdinal)
{
outOfRangeBlocksToVisit.Push(current);
continue;
}
if (visited[current.Ordinal])
{
continue;
}
visited[current.Ordinal] = true;
current.IsReachable = true;
bool canThrow = false;
bool fallThrough = true;
foreach (IOperation operation in current.Statements)
{
if (operationCanThrow(operation))
{
canThrow = true;
break;
}
}
(IOperation Condition, bool JumpIfTrue, BasicBlock.Branch Branch) conditional = current.Conditional;
if (conditional.Condition != null)
{
if (conditional.Condition.ConstantValue.HasValue && conditional.Condition.ConstantValue.Value is bool constant)
{
if (constant == conditional.JumpIfTrue)
{
followBranch(current, conditional.Branch, ref canThrow);
fallThrough = false;
}
}
else
{
if (operationCanThrow(conditional.Condition))
{
canThrow = true;
}
followBranch(current, conditional.Branch, ref canThrow);
}
}
if (fallThrough)
{
(IOperation Value, BasicBlock.Branch Branch) next = current.Next;
if (operationCanThrow(next.Value))
{
canThrow = true;
}
followBranch(current, current.Next.Branch, ref canThrow);
if (current.Ordinal == lastBlockOrdinal)
{
fellThrough = true;
}
}
if (canThrow)
{
dispatchException(current.Region);
}
}
while (toVisit.Count != 0);
toVisit.Free();
return visited;
// A simplified, imprecise way to detect if operation can throw
bool operationCanThrow(IOperation operation)
{
if (operation == null)
{
return false;
}
// PROTOTYPE(dataflow): Should we treat only primitive value type constant values as non throwing.
// For example, strings, decimal, datetime constants are not primitive value
// type constants.
if (operation.ConstantValue.HasValue)
{
return false;
}
// Treat an exception assignment to a local or a parameter as non-throwing
if (operation.Kind == OperationKind.SimpleAssignment)
{
var assignment = (ISimpleAssignmentOperation)operation;
if (assignment.Value.Kind == OperationKind.CaughtException &&
(assignment.Target.Kind == OperationKind.LocalReference || assignment.Target.Kind == OperationKind.ParameterReference))
{
return false;
}
}
return true;
}
void followBranch(BasicBlock current, BasicBlock.Branch branch, ref bool canThrow)
{
switch (branch.Kind)
{
case BasicBlock.BranchKind.None:
case BasicBlock.BranchKind.ProgramTermination:
case BasicBlock.BranchKind.StructuredExceptionHandling:
Debug.Assert(branch.Destination == null);
return;
case BasicBlock.BranchKind.Throw:
case BasicBlock.BranchKind.ReThrow:
Debug.Assert(branch.Destination == null);
canThrow = true;
return;
case BasicBlock.BranchKind.Regular:
case BasicBlock.BranchKind.Return:
Debug.Assert(branch.Destination != null);
if (stepThroughFinally(current.Region, branch.Destination))
{
toVisit.Add(branch.Destination);
}
return;
default:
throw ExceptionUtilities.UnexpectedValue(branch.Kind);
}
}
// Returns whether we should proceed to the destination after finallies were taken care of.
bool stepThroughFinally(ControlFlowGraph.Region region, BasicBlock destination)
{
int destinationOrdinal = destination.Ordinal;
while (!region.ContainsBlock(destinationOrdinal))
{
ControlFlowGraph.Region enclosing = region.Enclosing;
if (region.Kind == ControlFlowGraph.RegionKind.Try && enclosing.Kind == ControlFlowGraph.RegionKind.TryAndFinally)
{
Debug.Assert(enclosing.Regions[0] == region);
Debug.Assert(enclosing.Regions[1].Kind == ControlFlowGraph.RegionKind.Finally);
if (!stepThroughFilterOrFinally(enclosing.Regions[1]))
{
// The point that continues dispatch is not reachable. Cancel the dispatch.
return false;
}
}
region = enclosing;
}
return true;
}
// Returns whether we should proceed with dispatch after filter or finally was taken care of.
bool stepThroughFilterOrFinally(ControlFlowGraph.Region filterOrFinally)
{
Debug.Assert(filterOrFinally.Kind == ControlFlowGraph.RegionKind.Finally ||
filterOrFinally.Kind == ControlFlowGraph.RegionKind.Filter);
if (!continueDispatchAfterFilterOrFinally.TryGetValue(filterOrFinally, out bool continueDispatch))
{
// For simplicity, we do a complete walk of the finally/filter region in isolation
// to make sure that the resume dispatch point is reachable from its beginning.
// It could also be reachable through invalid branches into the finally and we don't want to consider
// these cases for regular finally handling.
BitVector isolated = MarkReachableBlocks(blocks,
filterOrFinally.FirstBlockOrdinal,
filterOrFinally.LastBlockOrdinal,
outOfRangeBlocksToVisit: toVisit,
continueDispatchAfterFilterOrFinally,
dispatchedExceptionsFromRegions,
out bool isolatedFellThrough);
visited.UnionWith(isolated);
continueDispatch = isolatedFellThrough &&
blocks[filterOrFinally.LastBlockOrdinal].Next.Branch.Kind == BasicBlock.BranchKind.StructuredExceptionHandling;
continueDispatchAfterFilterOrFinally.Add(filterOrFinally, continueDispatch);
}
return continueDispatch;
}
void dispatchException(ControlFlowGraph.Region fromRegion)
{
do
{
if (!dispatchedExceptionsFromRegions.Add(fromRegion))
{
return;
}
ControlFlowGraph.Region enclosing = fromRegion.Enclosing;
if (fromRegion.Kind == ControlFlowGraph.RegionKind.Try)
{
switch (enclosing.Kind)
{
case ControlFlowGraph.RegionKind.TryAndFinally:
Debug.Assert(enclosing.Regions[0] == fromRegion);
Debug.Assert(enclosing.Regions[1].Kind == ControlFlowGraph.RegionKind.Finally);
if (!stepThroughFilterOrFinally(enclosing.Regions[1]))
{
// The point that continues dispatch is not reachable. Cancel the dispatch.
return;
}
break;
case ControlFlowGraph.RegionKind.TryAndCatch:
Debug.Assert(enclosing.Regions[0] == fromRegion);
if (dispatchExceptionThroughCatches(enclosing, startAt: 1))
{
// Stop dispatch, an exception is handled
return;
}
break;
default:
throw ExceptionUtilities.UnexpectedValue(enclosing.Kind);
}
}
else if (fromRegion.Kind == ControlFlowGraph.RegionKind.Filter)
{
// If filter throws, dispatch is resumed at the next catch with an original exception
Debug.Assert(enclosing.Kind == ControlFlowGraph.RegionKind.FilterAndHandler);
ControlFlowGraph.Region tryAndCatch = enclosing.Enclosing;
Debug.Assert(tryAndCatch.Kind == ControlFlowGraph.RegionKind.TryAndCatch);
int index = tryAndCatch.Regions.IndexOf(enclosing, startIndex: 1);
if (index > 0)
{
if (dispatchExceptionThroughCatches(tryAndCatch, startAt: index + 1))
{
// Stop dispatch, an exception is handled
return;
}
fromRegion = tryAndCatch;
continue;
}
throw ExceptionUtilities.Unreachable;
}
fromRegion = enclosing;
}
while (fromRegion != null);
}
// Returns true if exception is handled
bool dispatchExceptionThroughCatches(ControlFlowGraph.Region tryAndCatch, int startAt)
{
Debug.Assert(tryAndCatch.Kind == ControlFlowGraph.RegionKind.TryAndCatch);
Debug.Assert(startAt > 0);
Debug.Assert(startAt <= tryAndCatch.Regions.Length);
for (int i = startAt; i < tryAndCatch.Regions.Length; i++)
{
ControlFlowGraph.Region @catch = tryAndCatch.Regions[i];
switch (@catch.Kind)
{
case ControlFlowGraph.RegionKind.Catch:
toVisit.Add(blocks[@catch.FirstBlockOrdinal]);
if (isCatchAllException(@catch.ExceptionType))
{
// Stop dispatch, an exception is handled
return true;
}
break;
case ControlFlowGraph.RegionKind.FilterAndHandler:
BasicBlock entryBlock = blocks[@catch.FirstBlockOrdinal];
ControlFlowGraph.Region filter = @catch.Regions[0];
Debug.Assert(filter.Kind == ControlFlowGraph.RegionKind.Filter);
Debug.Assert(entryBlock.Ordinal == filter.FirstBlockOrdinal);
toVisit.Add(entryBlock);
if (isCatchAllException(@catch.ExceptionType))
{
if (!stepThroughFilterOrFinally(filter))
{
// Stop dispatch, an exception is handled
return true;
}
}
break;
default:
throw ExceptionUtilities.UnexpectedValue(@catch.Kind);
}
}
return false;
}
bool isCatchAllException(ITypeSymbol exceptionType)
{
// PROTOTYPE(dataflow): Should we also consider System.Exception as catch all, at least for VB?
return exceptionType == null || exceptionType.SpecialType == SpecialType.System_Object;
}
}
private static void CalculateBranchLeaveEnterLists(ArrayBuilder<BasicBlock> blocks)
{
var builder = ArrayBuilder<ControlFlowGraph.Region>.GetInstance();
......@@ -111,7 +456,7 @@ void collectRegions(int destinationOrdinal, ControlFlowGraph.Region source)
{
builder.Clear();
while (source.FirstBlockOrdinal > destinationOrdinal || source.LastBlockOrdinal < destinationOrdinal)
while (!source.ContainsBlock(destinationOrdinal))
{
builder.Add(source);
source = source.Enclosing;
......@@ -393,9 +738,6 @@ private static bool PackBlocks(ArrayBuilder<BasicBlock> blocks, PooledDictionary
// It is safe to drop an unreachable empty basic block
if (predecessors.Count > 0)
{
// PROTOTYPE(dataflow): It should be safe to merge other branches with null destination, even when there are more than one predecessor
// and more than one incoming branch
if (predecessors.Count != 1)
{
continue;
......@@ -411,6 +753,8 @@ private static bool PackBlocks(ArrayBuilder<BasicBlock> blocks, PooledDictionary
// Do not merge StructuredExceptionHandling into the middle of the filter or finally,
// Do not merge StructuredExceptionHandling into conditional branch
// Do not merge StructuredExceptionHandling into a different region
// It is much easier to walk the graph when we can rely on the fact that a StructuredExceptionHandling
// branch is only in the last block in the region, if it is present.
continue;
}
......
......@@ -32,6 +32,7 @@ Microsoft.CodeAnalysis.Operations.BasicBlock.BranchKind.Return = 2 -> Microsoft.
Microsoft.CodeAnalysis.Operations.BasicBlock.BranchKind.StructuredExceptionHandling = 3 -> Microsoft.CodeAnalysis.Operations.BasicBlock.BranchKind
Microsoft.CodeAnalysis.Operations.BasicBlock.BranchKind.Throw = 5 -> Microsoft.CodeAnalysis.Operations.BasicBlock.BranchKind
Microsoft.CodeAnalysis.Operations.BasicBlock.Conditional.get -> (Microsoft.CodeAnalysis.IOperation Condition, bool JumpIfTrue, Microsoft.CodeAnalysis.Operations.BasicBlock.Branch Branch)
Microsoft.CodeAnalysis.Operations.BasicBlock.IsReachable.get -> bool
Microsoft.CodeAnalysis.Operations.BasicBlock.Kind.get -> Microsoft.CodeAnalysis.Operations.BasicBlockKind
Microsoft.CodeAnalysis.Operations.BasicBlock.Next.get -> (Microsoft.CodeAnalysis.IOperation Value, Microsoft.CodeAnalysis.Operations.BasicBlock.Branch Branch)
Microsoft.CodeAnalysis.Operations.BasicBlock.Ordinal.get -> int
......
......@@ -909,7 +909,7 @@ Block[B0] - Entry
{
.try {R3, R4}
{
Block[B1] - Block
Block[B1] - Block [UnReachable]
Predecessors (0)
Statements (0)
Next (Regular) Block[B3]
......@@ -936,7 +936,7 @@ Block[B0] - Entry
Entering: {R2} {R3} {R5}
}
Block[B4] - Block
Block[B4] - Block [UnReachable]
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x = true')
......@@ -948,7 +948,7 @@ Block[B4] - Block
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Next (Regular) Block[B5]
Block[B5] - Exit
Block[B5] - Exit [UnReachable]
Predecessors: [B4]
Statements (0)
]]>.Value
......@@ -985,7 +985,7 @@ Block[B0] - Entry
.try {R1, R2}
{
Block[B1] - Block
Block[B1] - Block [UnReachable]
Predecessors (0)
Statements (0)
Next (Regular) Block[B3]
......@@ -1000,7 +1000,7 @@ Block[B0] - Entry
Next (StructuredExceptionHandling) Block[null]
}
Block[B3] - Exit
Block[B3] - Exit [UnReachable]
Predecessors: [B1]
Statements (0)
]]>.Value
......@@ -1048,7 +1048,7 @@ Block[B0] - Entry
{
.try {R3, R4}
{
Block[B1] - Block
Block[B1] - Block [UnReachable]
Predecessors (0)
Statements (0)
Next (Regular) Block[B4]
......@@ -1057,7 +1057,7 @@ Block[B0] - Entry
}
.catch {R5} (System.Exception)
{
Block[B2] - Block
Block[B2] - Block [UnReachable]
Predecessors (0)
Statements (0)
Next (Regular) Block[B3]
......@@ -1073,7 +1073,7 @@ Block[B0] - Entry
Next (StructuredExceptionHandling) Block[null]
}
Block[B4] - Exit
Block[B4] - Exit [UnReachable]
Predecessors: [B1]
Statements (0)
]]>.Value
......@@ -1112,7 +1112,7 @@ Block[B0] - Entry
Statements (0)
Next (Regular) Block[B3]
Entering: {R1} {R3}
Block[B1] - Block
Block[B1] - Block [UnReachable]
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x = true')
......@@ -1128,7 +1128,7 @@ Block[B1] - Block
.try {R1, R2}
{
Block[B2] - Block
Block[B2] - Block [UnReachable]
Predecessors: [B1]
Statements (0)
Next (Regular) Block[B3]
......@@ -1143,7 +1143,7 @@ Block[B1] - Block
Next (StructuredExceptionHandling) Block[null]
}
Block[B4] - Exit
Block[B4] - Exit [UnReachable]
Predecessors (0)
Statements (0)
]]>.Value
......@@ -1181,7 +1181,7 @@ Block[B0] - Entry
.try {R1, R2}
{
Block[B1] - Block
Block[B1] - Block [UnReachable]
Predecessors (0)
Statements (0)
Next (Regular) Block[B3]
......@@ -1248,7 +1248,7 @@ Block[B0] - Entry
{
.try {R3, R4}
{
Block[B1] - Block
Block[B1] - Block [UnReachable]
Predecessors (0)
Statements (0)
Next (Regular) Block[B4]
......@@ -1275,7 +1275,7 @@ Block[B0] - Entry
Entering: {R2} {R3} {R5}
}
Block[B4] - Exit
Block[B4] - Exit [UnReachable]
Predecessors: [B1] [B2]
Statements (0)
]]>.Value
......@@ -1322,7 +1322,7 @@ Block[B0] - Entry
Statements (0)
Next (Regular) Block[B3]
Entering: {R1} {R2} {R3} {R5}
Block[B1] - Block
Block[B1] - Block [UnReachable]
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x = true')
......@@ -1340,7 +1340,7 @@ Block[B1] - Block
{
.try {R3, R4}
{
Block[B2] - Block
Block[B2] - Block [UnReachable]
Predecessors: [B1]
Statements (0)
Next (Regular) Block[B3]
......@@ -1367,7 +1367,7 @@ Block[B1] - Block
Entering: {R2} {R3} {R5}
}
Block[B5] - Exit
Block[B5] - Exit [UnReachable]
Predecessors: [B3]
Statements (0)
]]>.Value
......@@ -1402,7 +1402,7 @@ Block[B0] - Entry
Statements (0)
Next (Regular) Block[B2]
Entering: {R1} {R2}
Block[B1] - Block
Block[B1] - Block [UnReachable]
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x = true')
......@@ -1426,7 +1426,7 @@ Block[B1] - Block
}
.catch {R3} (System.Exception)
{
Block[B3] - Block
Block[B3] - Block [UnReachable]
Predecessors (0)
Statements (0)
Next (Regular) Block[B4]
......@@ -1474,7 +1474,7 @@ Block[B0] - Entry
}
.catch {R3} (System.Exception)
{
Block[B2] - Block
Block[B2] - Block [UnReachable]
Predecessors (0)
Statements (0)
Next (Regular) Block[B1]
......@@ -1599,7 +1599,7 @@ Block[B0] - Entry
Statements (0)
Next (Regular) Block[B2]
Entering: {R1} {R2}
Block[B1] - Block
Block[B1] - Block [UnReachable]
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x = true')
......@@ -1632,7 +1632,7 @@ Block[B1] - Block
Entering: {R2}
}
Block[B4] - Exit
Block[B4] - Exit [UnReachable]
Predecessors: [B2]
Statements (0)
]]>.Value
......@@ -1698,7 +1698,7 @@ Block[B1] - Block
}
.catch {R5} (System.Exception)
{
Block[B3] - Block
Block[B3] - Block [UnReachable]
Predecessors (0)
Statements (0)
Next (Regular) Block[B6]
......@@ -1715,7 +1715,7 @@ Block[B1] - Block
Leaving: {R6} {R1}
}
Block[B5] - Block
Block[B5] - Block [UnReachable]
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x = true')
......@@ -1801,7 +1801,7 @@ Block[B0] - Entry
Next (Regular) Block[B2]
Leaving: {R8} {R7} {R6}
Entering: {R2} {R3} {R5}
Block[B4] - Block
Block[B4] - Block [UnReachable]
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x = true')
......@@ -1817,20 +1817,20 @@ Block[B0] - Entry
}
.catch {R9} (System.Exception)
{
Block[B5] - Block
Block[B5] - Block [UnReachable]
Predecessors (0)
Statements (0)
Next (Regular) Block[B6]
Leaving: {R9} {R7}
}
Block[B6] - Block
Block[B6] - Block [UnReachable]
Predecessors: [B4] [B5]
Statements (0)
Next (StructuredExceptionHandling) Block[null]
}
Block[B7] - Exit
Block[B7] - Exit [UnReachable]
Predecessors: [B1] [B2]
Statements (0)
]]>.Value
......@@ -1857,7 +1857,7 @@ End Class]]>.Value
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B2]
Block[B1] - Block
Block[B1] - Block [UnReachable]
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x = true')
......@@ -1898,7 +1898,7 @@ Block[B1] - Block
Predecessors: [B0] [B1]
Statements (0)
Next (Regular) Block[B1]
Block[B2] - Exit
Block[B2] - Exit [UnReachable]
Predecessors (0)
Statements (0)]]>.Value
......@@ -1952,7 +1952,7 @@ Block[B0] - Entry
Predecessors: [B2] [B3]
Statements (0)
Next (Regular) Block[B2]
Block[B3] - Block
Block[B3] - Block [UnReachable]
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x = false')
......@@ -2022,7 +2022,7 @@ Block[B0] - Entry
Predecessors: [B2] [B3]
Statements (0)
Next (Regular) Block[B2]
Block[B3] - Block
Block[B3] - Block [UnReachable]
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x = false')
......@@ -2036,7 +2036,7 @@ Block[B0] - Entry
Next (Regular) Block[B2]
}
Block[B4] - Exit
Block[B4] - Exit [UnReachable]
Predecessors: [B1]
Statements (0)
]]>.Value
......@@ -2181,7 +2181,7 @@ Block[B0] - Entry
Next (Regular) Block[B2]
}
Block[B4] - Exit
Block[B4] - Exit [UnReachable]
Predecessors: [B1]
Statements (0)
]]>.Value
......@@ -2242,7 +2242,7 @@ Block[B0] - Entry
Leaving: {R3} {R1}
Next (Regular) Block[B2]
Block[B3] - Block
Block[B3] - Block [UnReachable]
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x = false')
......@@ -2317,7 +2317,7 @@ Block[B0] - Entry
IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'x')
Next (Regular) Block[B2]
Block[B3] - Block
Block[B3] - Block [UnReachable]
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x = false')
......@@ -2381,7 +2381,7 @@ Block[B2] - Block
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: False) (Syntax: 'false')
Next (Regular) Block[B1]
Block[B3] - Exit
Block[B3] - Exit [UnReachable]
Predecessors (0)
Statements (0)
]]>.Value
......@@ -2408,7 +2408,7 @@ End Class]]>.Value
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B2]
Block[B1] - Block
Block[B1] - Block [UnReachable]
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x = false')
......@@ -2463,7 +2463,7 @@ Block[B1] - Block
IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'x')
Next (Regular) Block[B1]
Block[B2] - Block
Block[B2] - Block [UnReachable]
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x = false')
......@@ -2475,7 +2475,7 @@ Block[B2] - Block
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: False) (Syntax: 'false')
Next (Regular) Block[B1]
Block[B3] - Exit
Block[B3] - Exit [UnReachable]
Predecessors (0)
Statements (0)
]]>.Value
......
......@@ -659,7 +659,7 @@ Block[B1] - Block
IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: null, Constant: null, IsImplicit) (Syntax: 'Nothing')
Next (Regular) Block[B2]
Block[B2] - Block
Block[B2] - Block [UnReachable]
Predecessors: [B1]
Statements (1)
IFlowCaptureOperation: 2 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'Nothing')
......@@ -755,7 +755,7 @@ Block[B1] - Block
IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: null, Constant: null, IsImplicit) (Syntax: 'Nothing')
Next (Regular) Block[B2]
Block[B2] - Block
Block[B2] - Block [UnReachable]
Predecessors: [B1]
Statements (1)
IFlowCaptureOperation: 2 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'Nothing')
......@@ -851,7 +851,7 @@ Block[B1] - Block
IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: null, Constant: null, IsImplicit) (Syntax: 'Nothing')
Next (Regular) Block[B2]
Block[B2] - Block
Block[B2] - Block [UnReachable]
Predecessors: [B1]
Statements (1)
IFlowCaptureOperation: 2 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'Nothing')
......
......@@ -28,7 +28,7 @@ Block[B1] - Block
Predecessors: [B0]
Statements (0)
Next (ProgramTermination) Block[null]
Block[B2] - Exit
Block[B2] - Exit [UnReachable]
Predecessors (0)
Statements (0)
]]>.Value
......@@ -69,7 +69,7 @@ Block[B1] - Block
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1')
Next (ProgramTermination) Block[null]
Block[B2] - Block
Block[B2] - Block [UnReachable]
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x = 2')
......@@ -81,7 +81,7 @@ Block[B2] - Block
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 2) (Syntax: '2')
Next (Regular) Block[B3]
Block[B3] - Exit
Block[B3] - Exit [UnReachable]
Predecessors: [B2]
Statements (0)
]]>.Value
......@@ -139,7 +139,7 @@ Block[B0] - Entry
Next (ProgramTermination) Block[null]
}
Block[B3] - Exit
Block[B3] - Exit [UnReachable]
Predecessors: [B1]
Statements (0)
]]>.Value
......@@ -182,7 +182,7 @@ Block[B1] - Block
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1')
Next (ProgramTermination) Block[null]
Block[B2] - Exit
Block[B2] - Exit [UnReachable]
Predecessors (0)
Statements (0)
]]>.Value
......@@ -218,7 +218,7 @@ Block[B1] - Block
IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'x')
Next (ProgramTermination) Block[null]
Block[B2] - Exit
Block[B2] - Exit [UnReachable]
Predecessors (0)
Statements (0)
]]>.Value
......@@ -276,7 +276,7 @@ Block[B3] - Block
Predecessors: [B1] [B2]
Statements (0)
Next (ProgramTermination) Block[null]
Block[B4] - Exit
Block[B4] - Exit [UnReachable]
Predecessors (0)
Statements (0)
]]>.Value
......@@ -324,7 +324,7 @@ Block[B1] - Block
IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'a')
Next (ProgramTermination) Block[null]
Block[B2] - Exit
Block[B2] - Exit [UnReachable]
Predecessors (0)
Statements (0)
]]>.Value
......@@ -463,7 +463,7 @@ Block[B0] - Entry
}
.finally {R3}
{
Block[B2] - Block
Block[B2] - Block [UnReachable]
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x = 1')
......@@ -477,7 +477,7 @@ Block[B0] - Entry
Next (StructuredExceptionHandling) Block[null]
}
Block[B3] - Exit
Block[B3] - Exit [UnReachable]
Predecessors (0)
Statements (0)
]]>.Value
......
......@@ -1172,5 +1172,220 @@ IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (S
VerifyOperationTreeAndDiagnosticsForTest(Of ExpressionStatementSyntax)(source, expectedOperationTree, expectedDiagnostics)
End Sub
<CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)>
<Fact()>
Public Sub ExceptionDispatch_45()
Dim source = <![CDATA[
Imports System
Public Class C
Shared Sub Main()
End Sub
Sub M(x As Integer) 'BIND:"Sub M"
Try
Throw New NullReferenceException()
label1:
x = 1
End
Catch
x = 3
GoTo label1
Finally
x = 4
end Try
End Sub
End Class]]>.Value
Dim expectedDiagnostics = String.Empty
Dim expectedFlowGraph = <![CDATA[
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Entering: {R1} {R2} {R3} {R4}
.try {R1, R2}
{
.try {R3, R4}
{
Block[B1] - Block
Predecessors: [B0]
Statements (0)
Next (Throw) Block[null]
IObjectCreationOperation (Constructor: Sub System.NullReferenceException..ctor()) (OperationKind.ObjectCreation, Type: System.NullReferenceException) (Syntax: 'New NullRef ... Exception()')
Arguments(0)
Initializer:
null
Block[B2] - Block
Predecessors: [B3]
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x = 1')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, IsImplicit) (Syntax: 'x = 1')
Left:
IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'x')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1')
Next (ProgramTermination) Block[null]
}
.catch {R5} (System.Exception)
{
Block[B3] - Block
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x = 3')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, IsImplicit) (Syntax: 'x = 3')
Left:
IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'x')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 3) (Syntax: '3')
Next (Regular) Block[B2]
Leaving: {R5}
Entering: {R4}
}
}
.finally {R6}
{
Block[B4] - Block
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x = 4')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, IsImplicit) (Syntax: 'x = 4')
Left:
IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'x')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 4) (Syntax: '4')
Next (StructuredExceptionHandling) Block[null]
}
Block[B5] - Exit [UnReachable]
Predecessors (0)
Statements (0)
]]>.Value
VerifyFlowGraphAndDiagnosticsForTest(Of MethodBlockSyntax)(source, expectedFlowGraph, expectedDiagnostics, TestOptions.ReleaseExe)
End Sub
<CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)>
<Fact()>
Public Sub FinallyDispatch_04()
Dim source = <![CDATA[
Imports System
Public Class C
Sub M(x As Integer) 'BIND:"Sub M"
GoTo label2
Try
Try
label1:
x = 1
label2:
x = 2
Finally
x = 3
end Try
Finally
x = 4
goto label1
end Try
End Sub
End Class]]>.Value
Dim expectedDiagnostics = <![CDATA[
BC30754: 'GoTo label2' is not valid because 'label2' is inside a 'Try', 'Catch' or 'Finally' statement that does not contain this statement.
GoTo label2
~~~~~~
BC30101: Branching out of a 'Finally' is not valid.
goto label1
~~~~~~
BC30754: 'GoTo label1' is not valid because 'label1' is inside a 'Try', 'Catch' or 'Finally' statement that does not contain this statement.
goto label1
~~~~~~
]]>.Value
Dim expectedFlowGraph = <![CDATA[
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B2]
Entering: {R1} {R2} {R3} {R4}
.try {R1, R2}
{
.try {R3, R4}
{
Block[B1] - Block
Predecessors: [B4]
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x = 1')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, IsImplicit) (Syntax: 'x = 1')
Left:
IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'x')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1')
Next (Regular) Block[B2]
Block[B2] - Block
Predecessors: [B0] [B1]
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x = 2')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, IsImplicit) (Syntax: 'x = 2')
Left:
IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'x')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 2) (Syntax: '2')
Next (Regular) Block[B5]
Finalizing: {R5} {R6}
Leaving: {R4} {R3} {R2} {R1}
}
.finally {R5}
{
Block[B3] - Block
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x = 3')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, IsImplicit) (Syntax: 'x = 3')
Left:
IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'x')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 3) (Syntax: '3')
Next (StructuredExceptionHandling) Block[null]
}
}
.finally {R6}
{
Block[B4] - Block
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x = 4')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, IsImplicit) (Syntax: 'x = 4')
Left:
IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'x')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 4) (Syntax: '4')
Next (Regular) Block[B1]
Leaving: {R6}
Entering: {R2} {R3} {R4}
}
Block[B5] - Exit [UnReachable]
Predecessors: [B2]
Statements (0)
]]>.Value
VerifyFlowGraphAndDiagnosticsForTest(Of MethodBlockSyntax)(source, expectedFlowGraph, expectedDiagnostics)
End Sub
End Class
End Namespace
......@@ -57,6 +57,7 @@ public static string GetFlowGraph(Compilation compilation, ControlFlowGraph grap
Assert.Null(currentRegion.ExceptionType);
Assert.Empty(currentRegion.Locals);
Assert.Equal(ControlFlowGraph.RegionKind.Root, currentRegion.Kind);
Assert.True(block.IsReachable);
break;
case BasicBlockKind.Exit:
......@@ -85,7 +86,7 @@ public static string GetFlowGraph(Compilation compilation, ControlFlowGraph grap
stringBuilder.AppendLine();
}
appendLine($"Block[B{i}] - {block.Kind}");
appendLine($"Block[B{i}] - {block.Kind}{(block.IsReachable ? "" : " [UnReachable]")}");
var predecessors = block.Predecessors;
......@@ -130,6 +131,7 @@ public static string GetFlowGraph(Compilation compilation, ControlFlowGraph grap
Assert.Same(blocks[conditionalBranch.Destination.Ordinal], conditionalBranch.Destination);
}
Assert.NotEqual(BasicBlock.BranchKind.StructuredExceptionHandling, conditionalBranch.Kind);
appendLine($" Jump if {(block.Conditional.JumpIfTrue ? "True" : "False")} ({conditionalBranch.Kind}) to Block[{getDestinationString(ref conditionalBranch)}]");
IOperation value = block.Conditional.Condition;
......@@ -153,6 +155,13 @@ public static string GetFlowGraph(Compilation compilation, ControlFlowGraph grap
Assert.Same(blocks[nextBranch.Destination.Ordinal], nextBranch.Destination);
}
if (nextBranch.Kind == BasicBlock.BranchKind.StructuredExceptionHandling)
{
Assert.Null(nextBranch.Destination);
Assert.Equal(block.Region.LastBlockOrdinal, block.Ordinal);
Assert.True(block.Region.Kind == ControlFlowGraph.RegionKind.Filter || block.Region.Kind == ControlFlowGraph.RegionKind.Finally);
}
appendLine($" Next ({nextBranch.Kind}) Block[{getDestinationString(ref nextBranch)}]");
IOperation value = block.Next.Value;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册