|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable disable
using System.Diagnostics;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Operations;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
public class IOperationTests_IReturnStatement : SemanticModelTestBase
{
[CompilerTrait(CompilerFeature.IOperation)]
[Fact]
public void SimpleReturnFromRegularMethod()
{
string source = @"
class C
{
static void Method()
{
/*<bind>*/return;/*</bind>*/
}
}
";
string expectedOperationTree = @"
IReturnOperation (OperationKind.Return, Type: null) (Syntax: 'return;')
ReturnedValue:
null
";
var expectedDiagnostics = DiagnosticDescription.None;
VerifyOperationTreeAndDiagnosticsForTest<ReturnStatementSyntax>(source, expectedOperationTree, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation)]
[Fact]
public void ReturnWithValueFromRegularMethod()
{
string source = @"
class C
{
static bool Method()
{
/*<bind>*/return true;/*</bind>*/
}
}
";
string expectedOperationTree = @"
IReturnOperation (OperationKind.Return, Type: null) (Syntax: 'return true;')
ReturnedValue:
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
";
var expectedDiagnostics = DiagnosticDescription.None;
VerifyOperationTreeAndDiagnosticsForTest<ReturnStatementSyntax>(source, expectedOperationTree, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation)]
[Fact]
public void YieldReturnFromRegularMethod()
{
string source = @"
using System.Collections.Generic;
class C
{
static IEnumerable<int> Method()
{
/*<bind>*/yield return 0;/*</bind>*/
}
}
";
string expectedOperationTree = @"
IReturnOperation (OperationKind.YieldReturn, Type: null) (Syntax: 'yield return 0;')
ReturnedValue:
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0) (Syntax: '0')
";
var expectedDiagnostics = DiagnosticDescription.None;
VerifyOperationTreeAndDiagnosticsForTest<YieldStatementSyntax>(source, expectedOperationTree, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation)]
[Fact]
public void YieldBreakFromRegularMethod()
{
string source = @"
using System.Collections.Generic;
class C
{
static IEnumerable<int> Method()
{
yield return 0;
/*<bind>*/yield break;/*</bind>*/
}
}
";
string expectedOperationTree = @"
IReturnOperation (OperationKind.YieldBreak, Type: null) (Syntax: 'yield break;')
ReturnedValue:
null
";
var expectedDiagnostics = DiagnosticDescription.None;
VerifyOperationTreeAndDiagnosticsForTest<YieldStatementSyntax>(source, expectedOperationTree, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation)]
[Fact, WorkItem(7299, "https://github.com/dotnet/roslyn/issues/7299")]
public void Return_ConstantConversions_01()
{
string source = @"
class C
{
static float Method()
{
/*<bind>*/return 0.0;/*</bind>*/
}
}
";
string expectedOperationTree = @"
IReturnOperation (OperationKind.Return, Type: null, IsInvalid) (Syntax: 'return 0.0;')
ReturnedValue:
IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Single, Constant: 0, IsInvalid, IsImplicit) (Syntax: '0.0')
Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: True, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
Operand:
ILiteralOperation (OperationKind.Literal, Type: System.Double, Constant: 0, IsInvalid) (Syntax: '0.0')
";
var expectedDiagnostics = new DiagnosticDescription[] {
// (6,26): error CS0664: Literal of type double cannot be implicitly converted to type 'float'; use an 'F' suffix to create a literal of this type
// /*<bind>*/return 0.0;/*</bind>*/
Diagnostic(ErrorCode.ERR_LiteralDoubleCast, "0.0").WithArguments("F", "float").WithLocation(6, 26)
};
VerifyOperationTreeAndDiagnosticsForTest<ReturnStatementSyntax>(source, expectedOperationTree, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ReturnFlow_01()
{
var source = @"
class C
{
void F()
/*<bind>*/{
return;
}/*</bind>*/
}";
var compilation = CreateCompilation(source);
compilation.VerifyDiagnostics();
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Block[B1] - Exit
Predecessors: [B0]
Statements (0)
";
VerifyFlowGraphForTest<BlockSyntax>(compilation, expectedGraph);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ReturnFlow_02()
{
var source = @"
class C
{
int F()
/*<bind>*/{
return 1;
}/*</bind>*/
}";
var compilation = CreateCompilation(source);
compilation.VerifyDiagnostics();
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Block[B1] - Block
Predecessors: [B0]
Statements (0)
Next (Return) Block[B2]
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1')
Block[B2] - Exit
Predecessors: [B1]
Statements (0)
";
VerifyFlowGraphForTest<BlockSyntax>(compilation, expectedGraph);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ReturnFlow_03()
{
var source = @"
class C
{
void F(bool a)
/*<bind>*/{
return;
a = true;
}/*</bind>*/
}";
var compilation = CreateCompilation(source);
compilation.VerifyDiagnostics(
// (7,9): warning CS0162: Unreachable code detected
// a = true;
Diagnostic(ErrorCode.WRN_UnreachableCode, "a").WithLocation(7, 9)
);
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B2]
Block[B1] - Block [UnReachable]
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a = true;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'a = true')
Left:
IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'a')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Next (Regular) Block[B2]
Block[B2] - Exit
Predecessors: [B0] [B1]
Statements (0)
";
VerifyFlowGraphForTest<BlockSyntax>(compilation, expectedGraph);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ReturnFlow_04()
{
var source = @"
class C
{
int F(bool a)
/*<bind>*/{
return 1;
a = true;
}/*</bind>*/
}";
var compilation = CreateCompilation(source);
compilation.VerifyDiagnostics(
// (7,9): warning CS0162: Unreachable code detected
// a = true;
Diagnostic(ErrorCode.WRN_UnreachableCode, "a").WithLocation(7, 9)
);
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Block[B1] - Block
Predecessors: [B0]
Statements (0)
Next (Return) Block[B3]
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1')
Block[B2] - Block [UnReachable]
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a = true;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'a = true')
Left:
IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'a')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Next (Regular) Block[B3]
Block[B3] - Exit
Predecessors: [B1] [B2]
Statements (0)
";
VerifyFlowGraphForTest<BlockSyntax>(compilation, expectedGraph);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ReturnFlow_05()
{
var source = @"
class C
{
object F(object a, object b)
/*<bind>*/{
return a ?? b;
}/*</bind>*/
}";
var compilation = CreateCompilation(source);
compilation.VerifyDiagnostics();
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Entering: {R1} {R2}
.locals {R1}
{
CaptureIds: [1]
.locals {R2}
{
CaptureIds: [0]
Block[B1] - Block
Predecessors: [B0]
Statements (1)
IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'a')
Value:
IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Object) (Syntax: 'a')
Jump if True (Regular) to Block[B3]
IIsNullOperation (OperationKind.IsNull, Type: System.Boolean, IsImplicit) (Syntax: 'a')
Operand:
IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: System.Object, IsImplicit) (Syntax: 'a')
Leaving: {R2}
Next (Regular) Block[B2]
Block[B2] - Block
Predecessors: [B1]
Statements (1)
IFlowCaptureOperation: 1 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'a')
Value:
IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: System.Object, IsImplicit) (Syntax: 'a')
Next (Regular) Block[B4]
Leaving: {R2}
}
Block[B3] - Block
Predecessors: [B1]
Statements (1)
IFlowCaptureOperation: 1 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'b')
Value:
IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Object) (Syntax: 'b')
Next (Regular) Block[B4]
Block[B4] - Block
Predecessors: [B2] [B3]
Statements (0)
Next (Return) Block[B5]
IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: System.Object, IsImplicit) (Syntax: 'a ?? b')
Leaving: {R1}
}
Block[B5] - Exit
Predecessors: [B4]
Statements (0)
";
VerifyFlowGraphForTest<BlockSyntax>(compilation, expectedGraph);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ReturnFlow_06()
{
var source = @"
class C
{
int F(bool a)
/*<bind>*/{
if (a)
{
return 1;
}
else
{
return 2;
}
}/*</bind>*/
}";
var compilation = CreateCompilation(source);
compilation.VerifyDiagnostics();
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Block[B1] - Block
Predecessors: [B0]
Statements (0)
Jump if False (Regular) to Block[B3]
IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'a')
Next (Regular) Block[B2]
Block[B2] - Block
Predecessors: [B1]
Statements (0)
Next (Return) Block[B4]
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1')
Block[B3] - Block
Predecessors: [B1]
Statements (0)
Next (Return) Block[B4]
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 2) (Syntax: '2')
Block[B4] - Exit
Predecessors: [B2] [B3]
Statements (0)
";
VerifyFlowGraphForTest<BlockSyntax>(compilation, expectedGraph);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ReturnFlow_07()
{
var source = @"
class C
{
void F(bool a)
/*<bind>*/{
if (a)
{
return;
}
else
{
a = true;
}
}/*</bind>*/
}";
var compilation = CreateCompilation(source);
compilation.VerifyDiagnostics();
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Block[B1] - Block
Predecessors: [B0]
Statements (0)
Jump if False (Regular) to Block[B2]
IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'a')
Next (Regular) Block[B3]
Block[B2] - Block
Predecessors: [B1]
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a = true;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'a = true')
Left:
IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'a')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Next (Regular) Block[B3]
Block[B3] - Exit
Predecessors: [B1] [B2]
Statements (0)
";
VerifyFlowGraphForTest<BlockSyntax>(compilation, expectedGraph);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ReturnFlow_08()
{
var source = @"
class C
{
void F(bool a)
/*<bind>*/{
if (a)
{
a = false;
}
else
{
return;
}
a = true;
}/*</bind>*/
}";
var compilation = CreateCompilation(source);
compilation.VerifyDiagnostics();
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Block[B1] - Block
Predecessors: [B0]
Statements (0)
Jump if False (Regular) to Block[B3]
IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'a')
Next (Regular) Block[B2]
Block[B2] - Block
Predecessors: [B1]
Statements (2)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a = false;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'a = false')
Left:
IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'a')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: False) (Syntax: 'false')
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a = true;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'a = true')
Left:
IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'a')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Next (Regular) Block[B3]
Block[B3] - Exit
Predecessors: [B1] [B2]
Statements (0)
";
VerifyFlowGraphForTest<BlockSyntax>(compilation, expectedGraph);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ReturnFlow_09()
{
var source = @"
class C
{
int F(bool a, bool b)
/*<bind>*/{
if (a)
{
b = false;
}
else
{
b = true;
}
return 1;
}/*</bind>*/
}";
var compilation = CreateCompilation(source);
compilation.VerifyDiagnostics();
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Block[B1] - Block
Predecessors: [B0]
Statements (0)
Jump if False (Regular) to Block[B3]
IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'a')
Next (Regular) Block[B2]
Block[B2] - Block
Predecessors: [B1]
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[B4]
Block[B3] - Block
Predecessors: [B1]
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]
Block[B4] - Block
Predecessors: [B2] [B3]
Statements (0)
Next (Return) Block[B5]
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1')
Block[B5] - Exit
Predecessors: [B4]
Statements (0)
";
VerifyFlowGraphForTest<BlockSyntax>(compilation, expectedGraph);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ReturnFlow_10()
{
var source = @"
class C
{
int F()
/*<bind>*/{
return 1;
return 2;
}/*</bind>*/
}";
var compilation = CreateCompilation(source);
compilation.VerifyDiagnostics(
// (7,9): warning CS0162: Unreachable code detected
// return 2;
Diagnostic(ErrorCode.WRN_UnreachableCode, "return").WithLocation(7, 9)
);
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Block[B1] - Block
Predecessors: [B0]
Statements (0)
Next (Return) Block[B3]
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1')
Block[B2] - Block [UnReachable]
Predecessors (0)
Statements (0)
Next (Return) Block[B3]
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 2) (Syntax: '2')
Block[B3] - Exit
Predecessors: [B1] [B2]
Statements (0)
";
VerifyFlowGraphForTest<BlockSyntax>(compilation, expectedGraph);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ReturnFlow_11()
{
var source = @"
class C
{
void F()
/*<bind>*/{
return;
return;
}/*</bind>*/
}";
var compilation = CreateCompilation(source);
compilation.VerifyDiagnostics(
// (7,9): warning CS0162: Unreachable code detected
// return;
Diagnostic(ErrorCode.WRN_UnreachableCode, "return").WithLocation(7, 9)
);
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Block[B1] - Exit
Predecessors: [B0]
Statements (0)
";
VerifyFlowGraphForTest<BlockSyntax>(compilation, expectedGraph);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ReturnFlow_12()
{
var source = @"
class C
{
int F(int a)
/*<bind>*/{
{
int b = 0;
a = b;
}
return 1;
}/*</bind>*/
}";
var compilation = CreateCompilation(source);
compilation.VerifyDiagnostics();
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Entering: {R1}
.locals {R1}
{
Locals: [System.Int32 b]
Block[B1] - Block
Predecessors: [B0]
Statements (2)
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, IsImplicit) (Syntax: 'b = 0')
Left:
ILocalReferenceOperation: b (IsDeclaration: True) (OperationKind.LocalReference, Type: System.Int32, IsImplicit) (Syntax: 'b = 0')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0) (Syntax: '0')
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a = b;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32) (Syntax: 'a = b')
Left:
IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'a')
Right:
ILocalReferenceOperation: b (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'b')
Next (Regular) Block[B2]
Leaving: {R1}
}
Block[B2] - Block
Predecessors: [B1]
Statements (0)
Next (Return) Block[B3]
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1')
Block[B3] - Exit
Predecessors: [B2]
Statements (0)
";
VerifyFlowGraphForTest<BlockSyntax>(compilation, expectedGraph);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ReturnFlow_13()
{
var source = @"
class C
{
int F(int a)
/*<bind>*/{
a = 0;
try
{
return 1;
}
finally
{
a = 2;
}
}/*</bind>*/
}";
var compilation = CreateCompilation(source);
compilation.VerifyDiagnostics();
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Block[B1] - Block
Predecessors: [B0]
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a = 0;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32) (Syntax: 'a = 0')
Left:
IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'a')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0) (Syntax: '0')
Next (Regular) Block[B2]
Entering: {R1} {R2}
.try {R1, R2}
{
Block[B2] - Block
Predecessors: [B1]
Statements (0)
Next (Return) Block[B4]
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1')
Finalizing: {R3}
Leaving: {R2} {R1}
}
.finally {R3}
{
Block[B3] - Block
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a = 2;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32) (Syntax: 'a = 2')
Left:
IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'a')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 2) (Syntax: '2')
Next (StructuredExceptionHandling) Block[null]
}
Block[B4] - Exit
Predecessors: [B2]
Statements (0)
";
VerifyFlowGraphForTest<BlockSyntax>(compilation, expectedGraph);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ReturnFlow_14()
{
var source = @"
class C
{
int F(int a)
/*<bind>*/{
try
{
a = 2;
}
catch
{
}
return 1;
}/*</bind>*/
}";
var compilation = CreateCompilation(source);
compilation.VerifyDiagnostics();
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: 'a = 2;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32) (Syntax: 'a = 2')
Left:
IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'a')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 2) (Syntax: '2')
Next (Regular) Block[B3]
Leaving: {R2} {R1}
}
.catch {R3} (System.Object)
{
Block[B2] - Block
Predecessors (0)
Statements (0)
Next (Regular) Block[B3]
Leaving: {R3} {R1}
}
Block[B3] - Block
Predecessors: [B1] [B2]
Statements (0)
Next (Return) Block[B4]
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1')
Block[B4] - Exit
Predecessors: [B3]
Statements (0)
";
VerifyFlowGraphForTest<BlockSyntax>(compilation, expectedGraph);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ReturnFlow_15()
{
var source = @"
class C
{
int F(int a)
/*<bind>*/{
try
{
a = 2;
}
finally
{
a = 3;
}
return 1;
}/*</bind>*/
}";
var compilation = CreateCompilation(source);
compilation.VerifyDiagnostics();
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: 'a = 2;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32) (Syntax: 'a = 2')
Left:
IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'a')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 2) (Syntax: '2')
Next (Regular) Block[B3]
Finalizing: {R3}
Leaving: {R2} {R1}
}
.finally {R3}
{
Block[B2] - Block
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a = 3;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32) (Syntax: 'a = 3')
Left:
IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'a')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 3) (Syntax: '3')
Next (StructuredExceptionHandling) Block[null]
}
Block[B3] - Block
Predecessors: [B1]
Statements (0)
Next (Return) Block[B4]
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1')
Block[B4] - Exit
Predecessors: [B3]
Statements (0)
";
VerifyFlowGraphForTest<BlockSyntax>(compilation, expectedGraph);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ReturnFlow_16()
{
var source = @"
class C
{
int F(bool a)
/*<bind>*/{
do
{
}
while (a);
return 1;
}/*</bind>*/
}";
var compilation = CreateCompilation(source);
compilation.VerifyDiagnostics();
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Block[B1] - Block
Predecessors: [B0] [B1]
Statements (0)
Jump if True (Regular) to Block[B1]
IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'a')
Next (Regular) Block[B2]
Block[B2] - Block
Predecessors: [B1]
Statements (0)
Next (Return) Block[B3]
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1')
Block[B3] - Exit
Predecessors: [B2]
Statements (0)
";
VerifyFlowGraphForTest<BlockSyntax>(compilation, expectedGraph);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ReturnFlow_17()
{
var source = @"
class C
{
int F(bool a)
/*<bind>*/{
if (a) return 1;
goto label1;
label1:
goto label2;
label2:
return 2;
}/*</bind>*/
}";
var compilation = CreateCompilation(source);
compilation.VerifyDiagnostics();
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Block[B1] - Block
Predecessors: [B0]
Statements (0)
Jump if False (Regular) to Block[B3]
IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'a')
Next (Regular) Block[B2]
Block[B2] - Block
Predecessors: [B1]
Statements (0)
Next (Return) Block[B4]
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1')
Block[B3] - Block
Predecessors: [B1]
Statements (0)
Next (Return) Block[B4]
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 2) (Syntax: '2')
Block[B4] - Exit
Predecessors: [B2] [B3]
Statements (0)
";
VerifyFlowGraphForTest<BlockSyntax>(compilation, expectedGraph);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void ReturnFlow_18()
{
var source = @"
class C
{
int F(bool a)
/*<bind>*/{
a = true;
goto label1;
label2:
if (a) return 1;
return 2;
label1:
goto label2;
}/*</bind>*/
}";
var compilation = CreateCompilation(source);
compilation.VerifyDiagnostics();
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Block[B1] - Block
Predecessors: [B0]
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a = true;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'a = true')
Left:
IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'a')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Jump if False (Regular) to Block[B3]
IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'a')
Next (Regular) Block[B2]
Block[B2] - Block
Predecessors: [B1]
Statements (0)
Next (Return) Block[B4]
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1')
Block[B3] - Block
Predecessors: [B1]
Statements (0)
Next (Return) Block[B4]
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 2) (Syntax: '2')
Block[B4] - Exit
Predecessors: [B2] [B3]
Statements (0)
";
VerifyFlowGraphForTest<BlockSyntax>(compilation, expectedGraph);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void YieldFlow_01()
{
var source = @"
class C
{
System.Collections.Generic.IEnumerable<int> F()
/*<bind>*/{
yield break;
}/*</bind>*/
}";
var compilation = CreateCompilation(source);
compilation.VerifyDiagnostics();
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Block[B1] - Exit
Predecessors: [B0]
Statements (0)
";
VerifyFlowGraphForTest<BlockSyntax>(compilation, expectedGraph);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void YieldFlow_02()
{
var source = @"
class C
{
System.Collections.Generic.IEnumerable<int> F()
/*<bind>*/{
yield return 1;
}/*</bind>*/
}";
var compilation = CreateCompilation(source);
compilation.VerifyDiagnostics();
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Block[B1] - Block
Predecessors: [B0]
Statements (1)
IReturnOperation (OperationKind.YieldReturn, Type: null) (Syntax: 'yield return 1;')
ReturnedValue:
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1')
Next (Regular) Block[B2]
Block[B2] - Exit
Predecessors: [B1]
Statements (0)
";
VerifyFlowGraphForTest<BlockSyntax>(compilation, expectedGraph);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void YieldFlow_03()
{
var source = @"
class C
{
System.Collections.Generic.IEnumerable<int> F(bool a)
/*<bind>*/{
yield break;
a = true;
}/*</bind>*/
}";
var compilation = CreateCompilation(source);
compilation.VerifyDiagnostics(
// (7,9): warning CS0162: Unreachable code detected
// a = true;
Diagnostic(ErrorCode.WRN_UnreachableCode, "a").WithLocation(7, 9)
);
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B2]
Block[B1] - Block [UnReachable]
Predecessors (0)
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a = true;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'a = true')
Left:
IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'a')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Next (Regular) Block[B2]
Block[B2] - Exit
Predecessors: [B0] [B1]
Statements (0)
";
VerifyFlowGraphForTest<BlockSyntax>(compilation, expectedGraph);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void YieldFlow_04()
{
var source = @"
class C
{
System.Collections.Generic.IEnumerable<int> F(bool a)
/*<bind>*/{
yield return 1;
a = true;
}/*</bind>*/
}";
var compilation = CreateCompilation(source);
compilation.VerifyDiagnostics();
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Block[B1] - Block
Predecessors: [B0]
Statements (2)
IReturnOperation (OperationKind.YieldReturn, Type: null) (Syntax: 'yield return 1;')
ReturnedValue:
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1')
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a = true;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'a = true')
Left:
IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'a')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Next (Regular) Block[B2]
Block[B2] - Exit
Predecessors: [B1]
Statements (0)
";
VerifyFlowGraphForTest<BlockSyntax>(compilation, expectedGraph);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void YieldFlow_05()
{
var source = @"
class C
{
System.Collections.Generic.IEnumerable<object> F(object a, object b)
/*<bind>*/{
yield return a ?? b;
}/*</bind>*/
}";
var compilation = CreateCompilation(source);
compilation.VerifyDiagnostics();
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Entering: {R1} {R2}
.locals {R1}
{
CaptureIds: [1]
.locals {R2}
{
CaptureIds: [0]
Block[B1] - Block
Predecessors: [B0]
Statements (1)
IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'a')
Value:
IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Object) (Syntax: 'a')
Jump if True (Regular) to Block[B3]
IIsNullOperation (OperationKind.IsNull, Type: System.Boolean, IsImplicit) (Syntax: 'a')
Operand:
IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: System.Object, IsImplicit) (Syntax: 'a')
Leaving: {R2}
Next (Regular) Block[B2]
Block[B2] - Block
Predecessors: [B1]
Statements (1)
IFlowCaptureOperation: 1 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'a')
Value:
IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: System.Object, IsImplicit) (Syntax: 'a')
Next (Regular) Block[B4]
Leaving: {R2}
}
Block[B3] - Block
Predecessors: [B1]
Statements (1)
IFlowCaptureOperation: 1 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'b')
Value:
IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Object) (Syntax: 'b')
Next (Regular) Block[B4]
Block[B4] - Block
Predecessors: [B2] [B3]
Statements (1)
IReturnOperation (OperationKind.YieldReturn, Type: null) (Syntax: 'yield return a ?? b;')
ReturnedValue:
IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: System.Object, IsImplicit) (Syntax: 'a ?? b')
Next (Regular) Block[B5]
Leaving: {R1}
}
Block[B5] - Exit
Predecessors: [B4]
Statements (0)
";
VerifyFlowGraphForTest<BlockSyntax>(compilation, expectedGraph);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void YieldFlow_06()
{
var source = @"
class C
{
System.Collections.Generic.IEnumerable<int> F(bool a)
/*<bind>*/{
if (a)
{
yield return 1;
}
else
{
yield return 2;
}
}/*</bind>*/
}";
var compilation = CreateCompilation(source);
compilation.VerifyDiagnostics();
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Block[B1] - Block
Predecessors: [B0]
Statements (0)
Jump if False (Regular) to Block[B3]
IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'a')
Next (Regular) Block[B2]
Block[B2] - Block
Predecessors: [B1]
Statements (1)
IReturnOperation (OperationKind.YieldReturn, Type: null) (Syntax: 'yield return 1;')
ReturnedValue:
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1')
Next (Regular) Block[B4]
Block[B3] - Block
Predecessors: [B1]
Statements (1)
IReturnOperation (OperationKind.YieldReturn, Type: null) (Syntax: 'yield return 2;')
ReturnedValue:
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 2) (Syntax: '2')
Next (Regular) Block[B4]
Block[B4] - Exit
Predecessors: [B2] [B3]
Statements (0)
";
VerifyFlowGraphForTest<BlockSyntax>(compilation, expectedGraph);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void YieldFlow_07()
{
var source = @"
class C
{
System.Collections.Generic.IEnumerable<int> F(bool a)
/*<bind>*/{
if (a)
{
yield break;
}
else
{
a = true;
}
}/*</bind>*/
}";
var compilation = CreateCompilation(source);
compilation.VerifyDiagnostics();
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Block[B1] - Block
Predecessors: [B0]
Statements (0)
Jump if False (Regular) to Block[B2]
IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'a')
Next (Regular) Block[B3]
Block[B2] - Block
Predecessors: [B1]
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a = true;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'a = true')
Left:
IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'a')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Next (Regular) Block[B3]
Block[B3] - Exit
Predecessors: [B1] [B2]
Statements (0)
";
VerifyFlowGraphForTest<BlockSyntax>(compilation, expectedGraph);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void YieldFlow_08()
{
var source = @"
class C
{
System.Collections.Generic.IEnumerable<int> F(bool a)
/*<bind>*/{
if (a)
{
a = false;
}
else
{
yield break;
}
a = true;
}/*</bind>*/
}";
var compilation = CreateCompilation(source);
compilation.VerifyDiagnostics();
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Block[B1] - Block
Predecessors: [B0]
Statements (0)
Jump if False (Regular) to Block[B3]
IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'a')
Next (Regular) Block[B2]
Block[B2] - Block
Predecessors: [B1]
Statements (2)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a = false;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'a = false')
Left:
IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'a')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: False) (Syntax: 'false')
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a = true;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'a = true')
Left:
IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'a')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Next (Regular) Block[B3]
Block[B3] - Exit
Predecessors: [B1] [B2]
Statements (0)
";
VerifyFlowGraphForTest<BlockSyntax>(compilation, expectedGraph);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void YieldFlow_09()
{
var source = @"
class C
{
System.Collections.Generic.IEnumerable<int> F()
/*<bind>*/{
yield return 1;
yield return 2;
}/*</bind>*/
}";
var compilation = CreateCompilation(source);
compilation.VerifyDiagnostics();
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Block[B1] - Block
Predecessors: [B0]
Statements (2)
IReturnOperation (OperationKind.YieldReturn, Type: null) (Syntax: 'yield return 1;')
ReturnedValue:
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1')
IReturnOperation (OperationKind.YieldReturn, Type: null) (Syntax: 'yield return 2;')
ReturnedValue:
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 2) (Syntax: '2')
Next (Regular) Block[B2]
Block[B2] - Exit
Predecessors: [B1]
Statements (0)
";
VerifyFlowGraphForTest<BlockSyntax>(compilation, expectedGraph);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void YieldFlow_10()
{
var source = @"
class C
{
System.Collections.Generic.IEnumerable<int> F()
/*<bind>*/{
yield break;
yield break;
}/*</bind>*/
}";
var compilation = CreateCompilation(source);
compilation.VerifyDiagnostics(
// (7,9): warning CS0162: Unreachable code detected
// yield break;
Diagnostic(ErrorCode.WRN_UnreachableCode, "yield").WithLocation(7, 9)
);
string expectedGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Block[B1] - Exit
Predecessors: [B0]
Statements (0)
";
VerifyFlowGraphForTest<BlockSyntax>(compilation, expectedGraph);
}
}
}
|