Skip to content

Commit 0269b90

Browse files
authored
Test IOperation and CFG for extension operators (#79002)
1 parent f5de354 commit 0269b90

File tree

4 files changed

+1131
-0
lines changed

4 files changed

+1131
-0
lines changed

src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IBinaryOperatorExpression.cs

Lines changed: 331 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8280,5 +8280,336 @@ void M(int? start)
82808280
var operation = (IRangeOperation)VerifyOperationTreeForTest<RangeExpressionSyntax>(compilation, expectedOperationTree);
82818281
Assert.Equal(RangeStartAtSignature, operation.Method.ToTestDisplayString());
82828282
}
8283+
8284+
[CompilerTrait(CompilerFeature.IOperation)]
8285+
[Fact]
8286+
public void Extensions_01()
8287+
{
8288+
var source = @"
8289+
struct C
8290+
{
8291+
void F(C x, C y)
8292+
{
8293+
var z = /*<bind>*/x + y/*</bind>*/;
8294+
}
8295+
}
8296+
8297+
static class Extensions
8298+
{
8299+
extension(C)
8300+
{
8301+
public static C operator +(C c1, C c2) { }
8302+
}
8303+
}
8304+
";
8305+
8306+
string expectedOperationTree =
8307+
@"
8308+
IBinaryOperation (BinaryOperatorKind.Add) (OperatorMethod: C Extensions.<>E__0.op_Addition(C c1, C c2)) (OperationKind.Binary, Type: C) (Syntax: 'x + y')
8309+
Left:
8310+
IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: C) (Syntax: 'x')
8311+
Right:
8312+
IParameterReferenceOperation: y (OperationKind.ParameterReference, Type: C) (Syntax: 'y')
8313+
";
8314+
8315+
VerifyOperationTreeForTest<BinaryExpressionSyntax>(source, expectedOperationTree);
8316+
}
8317+
8318+
[CompilerTrait(CompilerFeature.IOperation)]
8319+
[Fact]
8320+
public void Extensions_02_Logical()
8321+
{
8322+
var source = @"
8323+
struct C
8324+
{
8325+
void F(C x, C y)
8326+
{
8327+
var z = /*<bind>*/x || y/*</bind>*/;
8328+
}
8329+
}
8330+
8331+
static class Extensions
8332+
{
8333+
extension(C)
8334+
{
8335+
public static C operator &(C x, C y) => throw null;
8336+
public static C operator |(C x, C y) => throw null;
8337+
public static bool operator true(C c) => throw null;
8338+
public static bool operator false(C c) => throw null;
8339+
}
8340+
}
8341+
";
8342+
8343+
string expectedOperationTree =
8344+
@"
8345+
IBinaryOperation (BinaryOperatorKind.ConditionalOr) (OperatorMethod: C Extensions.<>E__0.op_BitwiseOr(C x, C y)) (OperationKind.Binary, Type: C) (Syntax: 'x || y')
8346+
Left:
8347+
IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: C) (Syntax: 'x')
8348+
Right:
8349+
IParameterReferenceOperation: y (OperationKind.ParameterReference, Type: C) (Syntax: 'y')
8350+
";
8351+
8352+
VerifyOperationTreeForTest<BinaryExpressionSyntax>(source, expectedOperationTree);
8353+
}
8354+
8355+
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
8356+
[Fact]
8357+
public void Extensions_03_Flow()
8358+
{
8359+
string source = @"
8360+
using System;
8361+
class C
8362+
{
8363+
void M(C a, C b)
8364+
/*<bind>*/{
8365+
GetArray()[0] = (a ?? b) + (a ?? b);
8366+
}/*</bind>*/
8367+
8368+
static int[] GetArray() => null;
8369+
}
8370+
8371+
static class Extensions
8372+
{
8373+
extension(C)
8374+
{
8375+
public static int operator +(C c1, C c2) => 0;
8376+
}
8377+
}
8378+
";
8379+
var expectedDiagnostics = DiagnosticDescription.None;
8380+
8381+
string expectedGraph = @"
8382+
Block[B0] - Entry
8383+
Statements (0)
8384+
Next (Regular) Block[B1]
8385+
Entering: {R1}
8386+
8387+
.locals {R1}
8388+
{
8389+
CaptureIds: [0] [2] [4]
8390+
Block[B1] - Block
8391+
Predecessors: [B0]
8392+
Statements (1)
8393+
IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'GetArray()[0]')
8394+
Value:
8395+
IArrayElementReferenceOperation (OperationKind.ArrayElementReference, Type: System.Int32) (Syntax: 'GetArray()[0]')
8396+
Array reference:
8397+
IInvocationOperation (System.Int32[] C.GetArray()) (OperationKind.Invocation, Type: System.Int32[]) (Syntax: 'GetArray()')
8398+
Instance Receiver:
8399+
null
8400+
Arguments(0)
8401+
Indices(1):
8402+
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0) (Syntax: '0')
8403+
8404+
Next (Regular) Block[B2]
8405+
Entering: {R2}
8406+
8407+
.locals {R2}
8408+
{
8409+
CaptureIds: [1]
8410+
Block[B2] - Block
8411+
Predecessors: [B1]
8412+
Statements (1)
8413+
IFlowCaptureOperation: 1 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'a')
8414+
Value:
8415+
IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: C) (Syntax: 'a')
8416+
8417+
Jump if True (Regular) to Block[B4]
8418+
IIsNullOperation (OperationKind.IsNull, Type: System.Boolean, IsImplicit) (Syntax: 'a')
8419+
Operand:
8420+
IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: C, IsImplicit) (Syntax: 'a')
8421+
Leaving: {R2}
8422+
8423+
Next (Regular) Block[B3]
8424+
Block[B3] - Block
8425+
Predecessors: [B2]
8426+
Statements (1)
8427+
IFlowCaptureOperation: 2 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'a')
8428+
Value:
8429+
IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: C, IsImplicit) (Syntax: 'a')
8430+
8431+
Next (Regular) Block[B5]
8432+
Leaving: {R2}
8433+
Entering: {R3}
8434+
}
8435+
8436+
Block[B4] - Block
8437+
Predecessors: [B2]
8438+
Statements (1)
8439+
IFlowCaptureOperation: 2 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'b')
8440+
Value:
8441+
IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: C) (Syntax: 'b')
8442+
8443+
Next (Regular) Block[B5]
8444+
Entering: {R3}
8445+
8446+
.locals {R3}
8447+
{
8448+
CaptureIds: [3]
8449+
Block[B5] - Block
8450+
Predecessors: [B3] [B4]
8451+
Statements (1)
8452+
IFlowCaptureOperation: 3 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'a')
8453+
Value:
8454+
IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: C) (Syntax: 'a')
8455+
8456+
Jump if True (Regular) to Block[B7]
8457+
IIsNullOperation (OperationKind.IsNull, Type: System.Boolean, IsImplicit) (Syntax: 'a')
8458+
Operand:
8459+
IFlowCaptureReferenceOperation: 3 (OperationKind.FlowCaptureReference, Type: C, IsImplicit) (Syntax: 'a')
8460+
Leaving: {R3}
8461+
8462+
Next (Regular) Block[B6]
8463+
Block[B6] - Block
8464+
Predecessors: [B5]
8465+
Statements (1)
8466+
IFlowCaptureOperation: 4 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'a')
8467+
Value:
8468+
IFlowCaptureReferenceOperation: 3 (OperationKind.FlowCaptureReference, Type: C, IsImplicit) (Syntax: 'a')
8469+
8470+
Next (Regular) Block[B8]
8471+
Leaving: {R3}
8472+
}
8473+
8474+
Block[B7] - Block
8475+
Predecessors: [B5]
8476+
Statements (1)
8477+
IFlowCaptureOperation: 4 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'b')
8478+
Value:
8479+
IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: C) (Syntax: 'b')
8480+
8481+
Next (Regular) Block[B8]
8482+
Block[B8] - Block
8483+
Predecessors: [B6] [B7]
8484+
Statements (1)
8485+
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'GetArray()[ ... + (a ?? b);')
8486+
Expression:
8487+
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32) (Syntax: 'GetArray()[ ... + (a ?? b)')
8488+
Left:
8489+
IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: System.Int32, IsImplicit) (Syntax: 'GetArray()[0]')
8490+
Right:
8491+
IBinaryOperation (BinaryOperatorKind.Add) (OperatorMethod: System.Int32 Extensions.<>E__0.op_Addition(C c1, C c2)) (OperationKind.Binary, Type: System.Int32) (Syntax: '(a ?? b) + (a ?? b)')
8492+
Left:
8493+
IFlowCaptureReferenceOperation: 2 (OperationKind.FlowCaptureReference, Type: C, IsImplicit) (Syntax: 'a ?? b')
8494+
Right:
8495+
IFlowCaptureReferenceOperation: 4 (OperationKind.FlowCaptureReference, Type: C, IsImplicit) (Syntax: 'a ?? b')
8496+
8497+
Next (Regular) Block[B9]
8498+
Leaving: {R1}
8499+
}
8500+
8501+
Block[B9] - Exit
8502+
Predecessors: [B8]
8503+
Statements (0)
8504+
";
8505+
VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(source, expectedGraph, expectedDiagnostics);
8506+
}
8507+
8508+
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
8509+
[Fact]
8510+
public void Extensions_04_Logical_Flow()
8511+
{
8512+
string source = @"
8513+
class C
8514+
{
8515+
void M(C a, C b, C result)
8516+
/*<bind>*/{
8517+
result = a || b;
8518+
}/*</bind>*/
8519+
}
8520+
8521+
static class Extensions
8522+
{
8523+
extension(C)
8524+
{
8525+
public static C operator &(C x, C y) => throw null;
8526+
public static C operator |(C x, C y) => throw null;
8527+
public static bool operator true(C c) => throw null;
8528+
public static bool operator false(C c) => throw null;
8529+
}
8530+
}
8531+
";
8532+
string expectedGraph = @"
8533+
Block[B0] - Entry
8534+
Statements (0)
8535+
Next (Regular) Block[B1]
8536+
Entering: {R1}
8537+
8538+
.locals {R1}
8539+
{
8540+
CaptureIds: [0] [2]
8541+
Block[B1] - Block
8542+
Predecessors: [B0]
8543+
Statements (1)
8544+
IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'result')
8545+
Value:
8546+
IParameterReferenceOperation: result (OperationKind.ParameterReference, Type: C) (Syntax: 'result')
8547+
8548+
Next (Regular) Block[B2]
8549+
Entering: {R2}
8550+
8551+
.locals {R2}
8552+
{
8553+
CaptureIds: [1]
8554+
Block[B2] - Block
8555+
Predecessors: [B1]
8556+
Statements (1)
8557+
IFlowCaptureOperation: 1 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'a')
8558+
Value:
8559+
IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: C) (Syntax: 'a')
8560+
8561+
Jump if False (Regular) to Block[B4]
8562+
IUnaryOperation (UnaryOperatorKind.True) (OperatorMethod: System.Boolean Extensions.<>E__0.op_True(C c)) (OperationKind.Unary, Type: System.Boolean, IsImplicit) (Syntax: 'a')
8563+
Operand:
8564+
IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: C, IsImplicit) (Syntax: 'a')
8565+
8566+
Next (Regular) Block[B3]
8567+
Block[B3] - Block
8568+
Predecessors: [B2]
8569+
Statements (1)
8570+
IFlowCaptureOperation: 2 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'a || b')
8571+
Value:
8572+
IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: C, IsImplicit) (Syntax: 'a')
8573+
8574+
Next (Regular) Block[B5]
8575+
Leaving: {R2}
8576+
Block[B4] - Block
8577+
Predecessors: [B2]
8578+
Statements (1)
8579+
IFlowCaptureOperation: 2 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'a || b')
8580+
Value:
8581+
IBinaryOperation (BinaryOperatorKind.Or) (OperatorMethod: C Extensions.<>E__0.op_BitwiseOr(C x, C y)) (OperationKind.Binary, Type: C) (Syntax: 'a || b')
8582+
Left:
8583+
IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: C, IsImplicit) (Syntax: 'a')
8584+
Right:
8585+
IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: C) (Syntax: 'b')
8586+
8587+
Next (Regular) Block[B5]
8588+
Leaving: {R2}
8589+
}
8590+
8591+
Block[B5] - Block
8592+
Predecessors: [B3] [B4]
8593+
Statements (1)
8594+
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'result = a || b;')
8595+
Expression:
8596+
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: C) (Syntax: 'result = a || b')
8597+
Left:
8598+
IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: C, IsImplicit) (Syntax: 'result')
8599+
Right:
8600+
IFlowCaptureReferenceOperation: 2 (OperationKind.FlowCaptureReference, Type: C, IsImplicit) (Syntax: 'a || b')
8601+
8602+
Next (Regular) Block[B6]
8603+
Leaving: {R1}
8604+
}
8605+
8606+
Block[B6] - Exit
8607+
Predecessors: [B5]
8608+
Statements (0)
8609+
";
8610+
var expectedDiagnostics = DiagnosticDescription.None;
8611+
8612+
VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(source, expectedGraph, expectedDiagnostics);
8613+
}
82838614
}
82848615
}

0 commit comments

Comments
 (0)