public void DeconstructionFlow_06() { string source = @" class C { int fI1 = 0; void M(bool b, C c1, int i1) /*<bind>*/{ (c1?.fI1, i1) = b ? (1, 2) : (3, 4); }/*</bind>*/ } "; var expectedDiagnostics = new DiagnosticDescription[] { // CS0131: The left-hand side of an assignment must be a variable, property or indexer // (c1?.fI1, i1) = b ? (1, 2) : (3, 4); Diagnostic(ErrorCode.ERR_AssgLvalueExpected, "c1?.fI1").WithLocation(7, 10), }; string expectedFlowGraph = @" Block[B0] - Entry Statements (0) Next (Regular) Block[B1] Block[B1] - Block Predecessors: [B0] Statements (1) IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsInvalid, IsImplicit) (Syntax: 'c1') Value: IParameterReferenceOperation: c1 (OperationKind.ParameterReference, Type: C, IsInvalid) (Syntax: 'c1') Jump if True (Regular) to Block[B3] IIsNullOperation (OperationKind.IsNull, Type: System.Boolean, IsInvalid, IsImplicit) (Syntax: 'c1') Operand: IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: C, IsInvalid, IsImplicit) (Syntax: 'c1') Next (Regular) Block[B2] Block[B2] - Block Predecessors: [B1] Statements (1) IFlowCaptureOperation: 1 (OperationKind.FlowCapture, Type: null, IsInvalid, IsImplicit) (Syntax: '.fI1') Value: IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Int32?, IsInvalid, IsImplicit) (Syntax: '.fI1') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) (ImplicitNullable) Operand: IFieldReferenceOperation: System.Int32 C.fI1 (OperationKind.FieldReference, Type: System.Int32, IsInvalid) (Syntax: '.fI1') Instance Receiver: IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: C, IsInvalid, IsImplicit) (Syntax: 'c1') Next (Regular) Block[B4] Block[B3] - Block Predecessors: [B1] Statements (1) IFlowCaptureOperation: 1 (OperationKind.FlowCapture, Type: null, IsInvalid, IsImplicit) (Syntax: 'c1') Value: IDefaultValueOperation (OperationKind.DefaultValue, Type: System.Int32?, IsInvalid, IsImplicit) (Syntax: 'c1') Next (Regular) Block[B4] Block[B4] - Block Predecessors: [B2] [B3] Statements (2) IFlowCaptureOperation: 2 (OperationKind.FlowCapture, Type: null, IsInvalid, IsImplicit) (Syntax: 'c1?.fI1') Value: IInvalidOperation (OperationKind.Invalid, Type: System.Int32?, IsInvalid, IsImplicit) (Syntax: 'c1?.fI1') Children(1): IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: System.Int32?, IsInvalid, IsImplicit) (Syntax: 'c1?.fI1') IFlowCaptureOperation: 3 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'i1') Value: IParameterReferenceOperation: i1 (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'i1') Jump if False (Regular) to Block[B6] IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'b') Next (Regular) Block[B5] Block[B5] - Block Predecessors: [B4] Statements (1) IFlowCaptureOperation: 4 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: '(1, 2)') Value: ITupleOperation (OperationKind.Tuple, Type: (System.Int32, System.Int32)) (Syntax: '(1, 2)') NaturalType: (System.Int32, System.Int32) Elements(2): ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1') ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 2) (Syntax: '2') Next (Regular) Block[B7] Block[B6] - Block Predecessors: [B4] Statements (1) IFlowCaptureOperation: 4 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: '(3, 4)') Value: ITupleOperation (OperationKind.Tuple, Type: (System.Int32, System.Int32)) (Syntax: '(3, 4)') NaturalType: (System.Int32, System.Int32) Elements(2): ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 3) (Syntax: '3') ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 4) (Syntax: '4') Next (Regular) Block[B7] Block[B7] - Block Predecessors: [B5] [B6] Statements (1) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null, IsInvalid) (Syntax: '(c1?.fI1, i ... ) : (3, 4);') Expression: IDeconstructionAssignmentOperation (OperationKind.DeconstructionAssignment, Type: (System.Int32? fI1, System.Int32 i1), IsInvalid) (Syntax: '(c1?.fI1, i ... 2) : (3, 4)') Left: ITupleOperation (OperationKind.Tuple, Type: (System.Int32? fI1, System.Int32 i1), IsInvalid) (Syntax: '(c1?.fI1, i1)') NaturalType: (System.Int32? fI1, System.Int32 i1) Elements(2): IFlowCaptureReferenceOperation: 2 (OperationKind.FlowCaptureReference, Type: System.Int32?, IsInvalid, IsImplicit) (Syntax: 'c1?.fI1') IFlowCaptureReferenceOperation: 3 (OperationKind.FlowCaptureReference, Type: System.Int32, IsImplicit) (Syntax: 'i1') Right: IFlowCaptureReferenceOperation: 4 (OperationKind.FlowCaptureReference, Type: (System.Int32, System.Int32), IsImplicit) (Syntax: 'b ? (1, 2) : (3, 4)') Next (Regular) Block[B8] Block[B8] - Exit Predecessors: [B7] Statements (0) "; VerifyFlowGraphAndDiagnosticsForTest <BlockSyntax>(source, expectedFlowGraph, expectedDiagnostics); }
public void FieldReference_ControlFlowInReceiver_StaticField() { string source = @" class C { public static int i = 0; void M(C c1, C c2, int p1, int p2) /*<bind>*/{ p1 = c1.i; p2 = (c1 ?? c2).i; }/*</bind>*/ } "; string expectedFlowGraph = @" Block[B0] - Entry Statements (0) Next (Regular) Block[B1] Block[B1] - Block Predecessors: [B0] Statements (2) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null, IsInvalid) (Syntax: 'p1 = c1.i;') Expression: ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, IsInvalid) (Syntax: 'p1 = c1.i') Left: IParameterReferenceOperation: p1 (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'p1') Right: IFieldReferenceOperation: System.Int32 C.i (Static) (OperationKind.FieldReference, Type: System.Int32, IsInvalid) (Syntax: 'c1.i') Instance Receiver: null IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null, IsInvalid) (Syntax: 'p2 = (c1 ?? c2).i;') Expression: ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, IsInvalid) (Syntax: 'p2 = (c1 ?? c2).i') Left: IParameterReferenceOperation: p2 (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'p2') Right: IFieldReferenceOperation: System.Int32 C.i (Static) (OperationKind.FieldReference, Type: System.Int32, IsInvalid) (Syntax: '(c1 ?? c2).i') Instance Receiver: null Next (Regular) Block[B2] Block[B2] - Exit Predecessors: [B1] Statements (0) "; var expectedDiagnostics = new DiagnosticDescription[] { // file.cs(7,14): error CS0176: Member 'C.i' cannot be accessed with an instance reference; qualify it with a type name instead // p1 = c1.i; Diagnostic(ErrorCode.ERR_ObjectProhibited, "c1.i") .WithArguments("C.i") .WithLocation(7, 14), // file.cs(8,14): error CS0176: Member 'C.i' cannot be accessed with an instance reference; qualify it with a type name instead // p2 = (c1 ?? c2).i; Diagnostic(ErrorCode.ERR_ObjectProhibited, "(c1 ?? c2).i") .WithArguments("C.i") .WithLocation(8, 14) }; VerifyFlowGraphAndDiagnosticsForTest <BlockSyntax>( source, expectedFlowGraph, expectedDiagnostics ); }
public void ObjectCreationWithMemberInitializers() { string source = @" struct B { public bool Field; } class F { public int Field; public string Property1 { set; get; } public B Property2 { set; get; } } class C { public void M1() /*<bind>*/{ var x1 = new F(); var x2 = new F() { Field = 2 }; var x3 = new F() { Property1 = """" }; var x4 = new F() { Property1 = """", Field = 2 }; var x5 = new F() { Property2 = new B { Field = true } }; var e1 = new F() { Property2 = 1 }; var e2 = new F() { """" }; }/*</bind>*/ } "; string expectedOperationTree = @" IBlockStatement (7 statements, 7 locals) (OperationKind.BlockStatement, IsInvalid) (Syntax: '{ ... }') Locals: Local_1: F x1 Local_2: F x2 Local_3: F x3 Local_4: F x4 Local_5: F x5 Local_6: F e1 Local_7: F e2 IVariableDeclarationStatement (1 declarations) (OperationKind.VariableDeclarationStatement) (Syntax: 'var x1 = new F();') IVariableDeclaration (1 variables) (OperationKind.VariableDeclaration) (Syntax: 'x1 = new F()') Variables: Local_1: F x1 Initializer: IObjectCreationExpression (Constructor: F..ctor()) (OperationKind.ObjectCreationExpression, Type: F) (Syntax: 'new F()') Arguments(0) Initializer: null IVariableDeclarationStatement (1 declarations) (OperationKind.VariableDeclarationStatement) (Syntax: 'var x2 = ne ... ield = 2 };') IVariableDeclaration (1 variables) (OperationKind.VariableDeclaration) (Syntax: 'x2 = new F( ... Field = 2 }') Variables: Local_1: F x2 Initializer: IObjectCreationExpression (Constructor: F..ctor()) (OperationKind.ObjectCreationExpression, Type: F) (Syntax: 'new F() { Field = 2 }') Arguments(0) Initializer: IObjectOrCollectionInitializerExpression (OperationKind.ObjectOrCollectionInitializerExpression, Type: F) (Syntax: '{ Field = 2 }') Initializers(1): ISimpleAssignmentExpression (OperationKind.SimpleAssignmentExpression, Type: System.Int32) (Syntax: 'Field = 2') Left: IFieldReferenceExpression: System.Int32 F.Field (OperationKind.FieldReferenceExpression, Type: System.Int32) (Syntax: 'Field') Instance Receiver: IInstanceReferenceExpression (OperationKind.InstanceReferenceExpression, Type: F) (Syntax: 'Field') Right: ILiteralExpression (OperationKind.LiteralExpression, Type: System.Int32, Constant: 2) (Syntax: '2') IVariableDeclarationStatement (1 declarations) (OperationKind.VariableDeclarationStatement) (Syntax: 'var x3 = ne ... ty1 = """" };') IVariableDeclaration (1 variables) (OperationKind.VariableDeclaration) (Syntax: 'x3 = new F( ... rty1 = """" }') Variables: Local_1: F x3 Initializer: IObjectCreationExpression (Constructor: F..ctor()) (OperationKind.ObjectCreationExpression, Type: F) (Syntax: 'new F() { P ... rty1 = """" }') Arguments(0) Initializer: IObjectOrCollectionInitializerExpression (OperationKind.ObjectOrCollectionInitializerExpression, Type: F) (Syntax: '{ Property1 = """" }') Initializers(1): ISimpleAssignmentExpression (OperationKind.SimpleAssignmentExpression, Type: System.String) (Syntax: 'Property1 = """"') Left: IPropertyReferenceExpression: System.String F.Property1 { get; set; } (OperationKind.PropertyReferenceExpression, Type: System.String) (Syntax: 'Property1') Instance Receiver: IInstanceReferenceExpression (OperationKind.InstanceReferenceExpression, Type: F) (Syntax: 'Property1') Right: ILiteralExpression (OperationKind.LiteralExpression, Type: System.String, Constant: """") (Syntax: '""""') IVariableDeclarationStatement (1 declarations) (OperationKind.VariableDeclarationStatement) (Syntax: 'var x4 = ne ... ield = 2 };') IVariableDeclaration (1 variables) (OperationKind.VariableDeclaration) (Syntax: 'x4 = new F( ... Field = 2 }') Variables: Local_1: F x4 Initializer: IObjectCreationExpression (Constructor: F..ctor()) (OperationKind.ObjectCreationExpression, Type: F) (Syntax: 'new F() { P ... Field = 2 }') Arguments(0) Initializer: IObjectOrCollectionInitializerExpression (OperationKind.ObjectOrCollectionInitializerExpression, Type: F) (Syntax: '{ Property1 ... Field = 2 }') Initializers(2): ISimpleAssignmentExpression (OperationKind.SimpleAssignmentExpression, Type: System.String) (Syntax: 'Property1 = """"') Left: IPropertyReferenceExpression: System.String F.Property1 { get; set; } (OperationKind.PropertyReferenceExpression, Type: System.String) (Syntax: 'Property1') Instance Receiver: IInstanceReferenceExpression (OperationKind.InstanceReferenceExpression, Type: F) (Syntax: 'Property1') Right: ILiteralExpression (OperationKind.LiteralExpression, Type: System.String, Constant: """") (Syntax: '""""') ISimpleAssignmentExpression (OperationKind.SimpleAssignmentExpression, Type: System.Int32) (Syntax: 'Field = 2') Left: IFieldReferenceExpression: System.Int32 F.Field (OperationKind.FieldReferenceExpression, Type: System.Int32) (Syntax: 'Field') Instance Receiver: IInstanceReferenceExpression (OperationKind.InstanceReferenceExpression, Type: F) (Syntax: 'Field') Right: ILiteralExpression (OperationKind.LiteralExpression, Type: System.Int32, Constant: 2) (Syntax: '2') IVariableDeclarationStatement (1 declarations) (OperationKind.VariableDeclarationStatement) (Syntax: 'var x5 = ne ... = true } };') IVariableDeclaration (1 variables) (OperationKind.VariableDeclaration) (Syntax: 'x5 = new F( ... = true } }') Variables: Local_1: F x5 Initializer: IObjectCreationExpression (Constructor: F..ctor()) (OperationKind.ObjectCreationExpression, Type: F) (Syntax: 'new F() { P ... = true } }') Arguments(0) Initializer: IObjectOrCollectionInitializerExpression (OperationKind.ObjectOrCollectionInitializerExpression, Type: F) (Syntax: '{ Property2 ... = true } }') Initializers(1): ISimpleAssignmentExpression (OperationKind.SimpleAssignmentExpression, Type: B) (Syntax: 'Property2 = ... ld = true }') Left: IPropertyReferenceExpression: B F.Property2 { get; set; } (OperationKind.PropertyReferenceExpression, Type: B) (Syntax: 'Property2') Instance Receiver: IInstanceReferenceExpression (OperationKind.InstanceReferenceExpression, Type: F) (Syntax: 'Property2') Right: IObjectCreationExpression (Constructor: B..ctor()) (OperationKind.ObjectCreationExpression, Type: B) (Syntax: 'new B { Field = true }') Arguments(0) Initializer: IObjectOrCollectionInitializerExpression (OperationKind.ObjectOrCollectionInitializerExpression, Type: B) (Syntax: '{ Field = true }') Initializers(1): ISimpleAssignmentExpression (OperationKind.SimpleAssignmentExpression, Type: System.Boolean) (Syntax: 'Field = true') Left: IFieldReferenceExpression: System.Boolean B.Field (OperationKind.FieldReferenceExpression, Type: System.Boolean) (Syntax: 'Field') Instance Receiver: IInstanceReferenceExpression (OperationKind.InstanceReferenceExpression, Type: B) (Syntax: 'Field') Right: ILiteralExpression (OperationKind.LiteralExpression, Type: System.Boolean, Constant: True) (Syntax: 'true') IVariableDeclarationStatement (1 declarations) (OperationKind.VariableDeclarationStatement, IsInvalid) (Syntax: 'var e1 = ne ... rty2 = 1 };') IVariableDeclaration (1 variables) (OperationKind.VariableDeclaration, IsInvalid) (Syntax: 'e1 = new F( ... erty2 = 1 }') Variables: Local_1: F e1 Initializer: IObjectCreationExpression (Constructor: F..ctor()) (OperationKind.ObjectCreationExpression, Type: F, IsInvalid) (Syntax: 'new F() { P ... erty2 = 1 }') Arguments(0) Initializer: IObjectOrCollectionInitializerExpression (OperationKind.ObjectOrCollectionInitializerExpression, Type: F, IsInvalid) (Syntax: '{ Property2 = 1 }') Initializers(1): ISimpleAssignmentExpression (OperationKind.SimpleAssignmentExpression, Type: B, IsInvalid) (Syntax: 'Property2 = 1') Left: IPropertyReferenceExpression: B F.Property2 { get; set; } (OperationKind.PropertyReferenceExpression, Type: B) (Syntax: 'Property2') Instance Receiver: IInstanceReferenceExpression (OperationKind.InstanceReferenceExpression, Type: F) (Syntax: 'Property2') Right: IConversionExpression (Implicit, TryCast: False, Unchecked) (OperationKind.ConversionExpression, Type: B, IsInvalid) (Syntax: '1') Conversion: CommonConversion (Exists: False, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Operand: ILiteralExpression (OperationKind.LiteralExpression, Type: System.Int32, Constant: 1, IsInvalid) (Syntax: '1') IVariableDeclarationStatement (1 declarations) (OperationKind.VariableDeclarationStatement, IsInvalid) (Syntax: 'var e2 = new F() { """" };') IVariableDeclaration (1 variables) (OperationKind.VariableDeclaration, IsInvalid) (Syntax: 'e2 = new F() { """" }') Variables: Local_1: F e2 Initializer: IObjectCreationExpression (Constructor: F..ctor()) (OperationKind.ObjectCreationExpression, Type: F, IsInvalid) (Syntax: 'new F() { """" }') Arguments(0) Initializer: IObjectOrCollectionInitializerExpression (OperationKind.ObjectOrCollectionInitializerExpression, Type: F, IsInvalid) (Syntax: '{ """" }') Initializers(1): IInvalidExpression (OperationKind.InvalidExpression, Type: ?, IsInvalid) (Syntax: '""""') Children(1): ILiteralExpression (OperationKind.LiteralExpression, Type: System.String, Constant: """", IsInvalid) (Syntax: '""""') "; var expectedDiagnostics = new DiagnosticDescription[] { // CS0029: Cannot implicitly convert type 'int' to 'B' // var e1 = new F() { Property2 = 1 }; Diagnostic(ErrorCode.ERR_NoImplicitConv, "1").WithArguments("int", "B").WithLocation(24, 40), // CS1922: Cannot initialize type 'F' with a collection initializer because it does not implement 'System.Collections.IEnumerable' // var e2 = new F() { "" }; Diagnostic(ErrorCode.ERR_CollectionInitRequiresIEnumerable, @"{ """" }").WithArguments("F").WithLocation(25, 26) }; VerifyOperationTreeAndDiagnosticsForTest <BlockSyntax>(source, expectedOperationTree, expectedDiagnostics); }
public void TryCatch_MultipleCatchClausesWithDuplicateCaughtTypes() { string source = @" class C { static void Main() { /*<bind>*/try { } catch (System.IO.IOException e) { } catch (System.IO.IOException e) when (e.Message != null) { }/*</bind>*/ } } "; string expectedOperationTree = @" ITryOperation (OperationKind.Try, Type: null, IsInvalid) (Syntax: 'try ... }') Body: IBlockOperation (0 statements) (OperationKind.Block, Type: null) (Syntax: '{ ... }') Catch clauses(2): ICatchClauseOperation (Exception type: System.IO.IOException) (OperationKind.CatchClause, Type: null) (Syntax: 'catch (Syst ... }') Locals: Local_1: System.IO.IOException e ExceptionDeclarationOrExpression: IVariableDeclaratorOperation (Symbol: System.IO.IOException e) (OperationKind.VariableDeclarator, Type: null) (Syntax: '(System.IO. ... xception e)') Initializer: null Filter: null Handler: IBlockOperation (0 statements) (OperationKind.Block, Type: null) (Syntax: '{ ... }') ICatchClauseOperation (Exception type: System.IO.IOException) (OperationKind.CatchClause, Type: null, IsInvalid) (Syntax: 'catch (Syst ... }') Locals: Local_1: System.IO.IOException e ExceptionDeclarationOrExpression: IVariableDeclaratorOperation (Symbol: System.IO.IOException e) (OperationKind.VariableDeclarator, Type: null, IsInvalid) (Syntax: '(System.IO. ... xception e)') Initializer: null Filter: IBinaryOperation (BinaryOperatorKind.NotEquals) (OperationKind.BinaryOperator, Type: System.Boolean) (Syntax: 'e.Message != null') Left: IPropertyReferenceOperation: System.String System.Exception.Message { get; } (OperationKind.PropertyReference, Type: System.String) (Syntax: 'e.Message') Instance Receiver: ILocalReferenceOperation: e (OperationKind.LocalReference, Type: System.IO.IOException) (Syntax: 'e') Right: IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.String, Constant: null, IsImplicit) (Syntax: 'null') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: True, IsUserDefined: False) (MethodSymbol: null) Operand: ILiteralOperation (OperationKind.Literal, Type: null, Constant: null) (Syntax: 'null') Handler: IBlockOperation (0 statements) (OperationKind.Block, Type: null) (Syntax: '{ ... }') Finally: null "; var expectedDiagnostics = new DiagnosticDescription[] { // CS0160: A previous catch clause already catches all exceptions of this or of a super type ('IOException') // catch (System.IO.IOException e) when (e.Message != null) Diagnostic(ErrorCode.ERR_UnreachableCatch, "System.IO.IOException").WithArguments("System.IO.IOException").WithLocation(12, 16), // CS0168: The variable 'e' is declared but never used // catch (System.IO.IOException e) Diagnostic(ErrorCode.WRN_UnreferencedVar, "e").WithArguments("e").WithLocation(9, 38) }; VerifyOperationTreeAndDiagnosticsForTest <TryStatementSyntax>(source, expectedOperationTree, expectedDiagnostics); }
public void TestPatternCaseClause_RedundantPatternDeclarationClauses() { string source = @" using System; class X { void M(object p) { /*<bind>*/switch (p) { case int x: break; case int y: break; case X z: break; }/*</bind>*/ } } "; string expectedOperationTree = @" ISwitchStatement (3 cases) (OperationKind.SwitchStatement, IsInvalid) (Syntax: 'switch (p) ... }') Switch expression: IParameterReferenceExpression: p (OperationKind.ParameterReferenceExpression, Type: System.Object) (Syntax: 'p') Sections: ISwitchCase (1 case clauses, 1 statements) (OperationKind.SwitchCase) (Syntax: 'case int x: ... break;') Clauses: IPatternCaseClause (Label Symbol: case int x:) (CaseKind.Pattern) (OperationKind.CaseClause) (Syntax: 'case int x:') Pattern: IDeclarationPattern (Declared Symbol: System.Int32 x) (OperationKind.DeclarationPattern) (Syntax: 'int x') Guard Expression: null Body: IBranchStatement (BranchKind.Break) (OperationKind.BranchStatement) (Syntax: 'break;') ISwitchCase (1 case clauses, 1 statements) (OperationKind.SwitchCase, IsInvalid) (Syntax: 'case int y: ... break;') Clauses: IPatternCaseClause (Label Symbol: case int y:) (CaseKind.Pattern) (OperationKind.CaseClause, IsInvalid) (Syntax: 'case int y:') Pattern: IDeclarationPattern (Declared Symbol: System.Int32 y) (OperationKind.DeclarationPattern, IsInvalid) (Syntax: 'int y') Guard Expression: null Body: IBranchStatement (BranchKind.Break) (OperationKind.BranchStatement) (Syntax: 'break;') ISwitchCase (1 case clauses, 1 statements) (OperationKind.SwitchCase) (Syntax: 'case X z: ... break;') Clauses: IPatternCaseClause (Label Symbol: case X z:) (CaseKind.Pattern) (OperationKind.CaseClause) (Syntax: 'case X z:') Pattern: IDeclarationPattern (Declared Symbol: X z) (OperationKind.DeclarationPattern) (Syntax: 'X z') Guard Expression: null Body: IBranchStatement (BranchKind.Break) (OperationKind.BranchStatement) (Syntax: 'break;') "; var expectedDiagnostics = new DiagnosticDescription[] { // CS8120: The switch case has already been handled by a previous case. // case int y: Diagnostic(ErrorCode.ERR_PatternIsSubsumed, "int y").WithLocation(11, 18), // CS0162: Unreachable code detected // break; Diagnostic(ErrorCode.WRN_UnreachableCode, "break").WithLocation(12, 17) }; VerifyOperationTreeAndDiagnosticsForTest <SwitchStatementSyntax>(source, expectedOperationTree, expectedDiagnostics); }
public void FixedStatement_InvalidBody() { string source = @" using System; class C { private int i1; void M1() { int i3; unsafe { /*<bind>*/fixed (int* p1 = &i1) { i3 = &p1; }/*</bind>*/ } } } "; string expectedOperationTree = @" IFixedOperation (OperationKind.None, Type: null, IsInvalid) (Syntax: 'fixed (int* ... }') Locals: Local_1: System.Int32* p1 Declaration: IVariableDeclarationGroupOperation (1 declarations) (OperationKind.VariableDeclarationGroup, Type: null, IsImplicit) (Syntax: 'int* p1 = &i1') IVariableDeclarationOperation (1 declarators) (OperationKind.VariableDeclaration, Type: null) (Syntax: 'int* p1 = &i1') Declarators: IVariableDeclaratorOperation (Symbol: System.Int32* p1) (OperationKind.VariableDeclarator, Type: null) (Syntax: 'p1 = &i1') Initializer: IVariableInitializerOperation (OperationKind.VariableInitializer, Type: null) (Syntax: '= &i1') IOperation: (OperationKind.None, Type: null, IsImplicit) (Syntax: '&i1') Children(1): IAddressOfOperation (OperationKind.AddressOf, Type: System.Int32*) (Syntax: '&i1') Reference: IFieldReferenceOperation: System.Int32 C.i1 (OperationKind.FieldReference, Type: System.Int32) (Syntax: 'i1') Instance Receiver: IInstanceReferenceOperation (ReferenceKind: ContainingTypeInstance) (OperationKind.InstanceReference, Type: C, IsImplicit) (Syntax: 'i1') Initializer: null Body: IBlockOperation (1 statements) (OperationKind.Block, Type: null, IsInvalid) (Syntax: '{ ... }') IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null, IsInvalid) (Syntax: 'i3 = &p1;') Expression: ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, IsInvalid) (Syntax: 'i3 = &p1') Left: ILocalReferenceOperation: i3 (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i3') Right: IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Int32, IsInvalid, IsImplicit) (Syntax: '&p1') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Operand: IAddressOfOperation (OperationKind.AddressOf, Type: System.Int32**, IsInvalid) (Syntax: '&p1') Reference: ILocalReferenceOperation: p1 (OperationKind.LocalReference, Type: System.Int32*, IsInvalid) (Syntax: 'p1') "; var expectedDiagnostics = new DiagnosticDescription[] { // file.cs(15,22): error CS0266: Cannot implicitly convert type 'int**' to 'int'. An explicit conversion exists (are you missing a cast?) // i3 = &p1; Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "&p1").WithArguments("int**", "int").WithLocation(15, 22) }; VerifyOperationTreeAndDiagnosticsForTest <FixedStatementSyntax>(source, expectedOperationTree, expectedDiagnostics, compilationOptions: TestOptions.UnsafeDebugDll); }
public void FixedStatement_04() { string source = @" unsafe public class MyClass { int i1, i2; unsafe void M(bool b) /*<bind>*/{ fixed (int* p = b ? &i1 : &i2) { if (b) { System.Console.WriteLine($""P is {*p}""); } } }/*</bind>*/ } "; var expectedDiagnostics = new DiagnosticDescription[] { // CS0212: You can only take the address of an unfixed expression inside of a fixed statement initializer // fixed (int* p = b ? &i1 : &i2) Diagnostic(ErrorCode.ERR_FixedNeeded, "&i1").WithLocation(7, 29), // CS0212: You can only take the address of an unfixed expression inside of a fixed statement initializer // fixed (int* p = b ? &i1 : &i2) Diagnostic(ErrorCode.ERR_FixedNeeded, "&i2").WithLocation(7, 35) }; // https://github.com/dotnet/roslyn/issues/27491: This graph verification was added to verify general handling of operations // with OperationKind.None. We have special handling for fixed statements now. // Need to make sure we haven't lost coverage for the general implementation and // add new tests if necessary. string expectedFlowGraph = @" Block[B0] - Entry Statements (0) Next (Regular) Block[B1] Entering: {R1} {R2} .locals {R1} { Locals: [System.Int32* p] .locals {R2} { CaptureIds: [0] Block[B1] - Block Predecessors: [B0] Statements (0) Jump if False (Regular) to Block[B3] IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'b') Next (Regular) Block[B2] Block[B2] - Block Predecessors: [B1] Statements (1) IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsInvalid, IsImplicit) (Syntax: '&i1') Value: IAddressOfOperation (OperationKind.AddressOf, Type: System.Int32*, IsInvalid) (Syntax: '&i1') Reference: IFieldReferenceOperation: System.Int32 MyClass.i1 (OperationKind.FieldReference, Type: System.Int32, IsInvalid) (Syntax: 'i1') Instance Receiver: IInstanceReferenceOperation (ReferenceKind: ContainingTypeInstance) (OperationKind.InstanceReference, Type: MyClass, IsInvalid, IsImplicit) (Syntax: 'i1') Next (Regular) Block[B4] Block[B3] - Block Predecessors: [B1] Statements (1) IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsInvalid, IsImplicit) (Syntax: '&i2') Value: IAddressOfOperation (OperationKind.AddressOf, Type: System.Int32*, IsInvalid) (Syntax: '&i2') Reference: IFieldReferenceOperation: System.Int32 MyClass.i2 (OperationKind.FieldReference, Type: System.Int32, IsInvalid) (Syntax: 'i2') Instance Receiver: IInstanceReferenceOperation (ReferenceKind: ContainingTypeInstance) (OperationKind.InstanceReference, Type: MyClass, IsInvalid, IsImplicit) (Syntax: 'i2') Next (Regular) Block[B4] Block[B4] - Block Predecessors: [B2] [B3] Statements (1) ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32*, IsInvalid, IsImplicit) (Syntax: 'p = b ? &i1 : &i2') Left: ILocalReferenceOperation: p (IsDeclaration: True) (OperationKind.LocalReference, Type: System.Int32*, IsInvalid, IsImplicit) (Syntax: 'p = b ? &i1 : &i2') Right: IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: System.Int32*, IsInvalid, IsImplicit) (Syntax: 'b ? &i1 : &i2') Next (Regular) Block[B5] Leaving: {R2} } Block[B5] - Block Predecessors: [B4] Statements (0) Jump if False (Regular) to Block[B7] IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'b') Leaving: {R1} Next (Regular) Block[B6] Block[B6] - Block Predecessors: [B5] Statements (1) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'System.Cons ... is {*p}"");') Expression: IInvocationOperation (void System.Console.WriteLine(System.String value)) (OperationKind.Invocation, Type: System.Void) (Syntax: 'System.Cons ... P is {*p}"")') Instance Receiver: null Arguments(1): IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: value) (OperationKind.Argument, Type: null) (Syntax: '$""P is {*p}""') IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$""P is {*p}""') Parts(2): IInterpolatedStringTextOperation (OperationKind.InterpolatedStringText, Type: null) (Syntax: 'P is ') Text: ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: ""P is "", IsImplicit) (Syntax: 'P is ') IInterpolationOperation (OperationKind.Interpolation, Type: null) (Syntax: '{*p}') Expression: IOperation: (OperationKind.None, Type: null) (Syntax: '*p') Children(1): ILocalReferenceOperation: p (OperationKind.LocalReference, Type: System.Int32*) (Syntax: 'p') Alignment: null FormatString: null InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Next (Regular) Block[B7] Leaving: {R1} } Block[B7] - Exit Predecessors: [B5] [B6] Statements (0) "; VerifyFlowGraphAndDiagnosticsForTest <BlockSyntax>(source, expectedFlowGraph, expectedDiagnostics, compilationOptions: TestOptions.UnsafeDebugDll); }
public void InvalidVariableDeclarationStatement() { string source = @" using System; class Program { static void Main(string[] args) { /*<bind>*/int x, ( 1 );/*</bind>*/ } } "; string expectedOperationTree = @" IVariableDeclarationGroupOperation (1 declarations) (OperationKind.VariableDeclarationGroup, Type: null, IsInvalid) (Syntax: 'int x, ( 1 );') IVariableDeclarationOperation (2 declarators) (OperationKind.VariableDeclaration, Type: null, IsInvalid) (Syntax: 'int x, ( 1 ') Declarators: IVariableDeclaratorOperation (Symbol: System.Int32 x) (OperationKind.VariableDeclarator, Type: null) (Syntax: 'x') Initializer: null IVariableDeclaratorOperation (Symbol: System.Int32 ) (OperationKind.VariableDeclarator, Type: null, IsInvalid) (Syntax: '( 1 ') Initializer: null IgnoredArguments(1): ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1, IsInvalid) (Syntax: '1') Initializer: null "; var expectedDiagnostics = new DiagnosticDescription[] { // CS1001: Identifier expected // /*<bind>*/int x, ( 1 );/*</bind>*/ Diagnostic(ErrorCode.ERR_IdentifierExpected, "(").WithLocation(8, 26), // CS1528: Expected ; or = (cannot specify constructor arguments in declaration) // /*<bind>*/int x, ( 1 );/*</bind>*/ Diagnostic(ErrorCode.ERR_BadVarDecl, "( 1 ").WithLocation(8, 26), // CS1003: Syntax error, '[' expected // /*<bind>*/int x, ( 1 );/*</bind>*/ Diagnostic(ErrorCode.ERR_SyntaxError, "(") .WithArguments("[", "(") .WithLocation(8, 26), // CS1003: Syntax error, ']' expected // /*<bind>*/int x, ( 1 );/*</bind>*/ Diagnostic(ErrorCode.ERR_SyntaxError, ")") .WithArguments("]", ")") .WithLocation(8, 30), // CS0168: The variable 'x' is declared but never used // /*<bind>*/int x, ( 1 );/*</bind>*/ Diagnostic(ErrorCode.WRN_UnreferencedVar, "x") .WithArguments("x") .WithLocation(8, 23) }; VerifyOperationTreeAndDiagnosticsForTest <LocalDeclarationStatementSyntax>( source, expectedOperationTree, expectedDiagnostics ); }
public void InvalidGotoCaseStatement_BadLabel() { string source = @" using System; class Program { static void Main(string[] args) { switch (args[0], args[1]) { case (string s1, string s2) _: /*<bind>*/goto case args is (var x1, var x2);/*</bind>*/ x1 = x2; case (string str, null) _: break; } } } "; string expectedOperationTree = @" IInvalidOperation (OperationKind.Invalid, Type: null, IsInvalid) (Syntax: 'goto case a ... 1, var x2);') Children(1): IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: (System.String, System.String), IsInvalid, IsImplicit) (Syntax: 'args is (var x1, var x2)') Conversion: CommonConversion (Exists: False, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Operand: IIsPatternOperation (OperationKind.IsPattern, Type: System.Boolean, IsInvalid) (Syntax: 'args is (var x1, var x2)') Value: IParameterReferenceOperation: args (OperationKind.ParameterReference, Type: System.String[], IsInvalid) (Syntax: 'args') Pattern: IRecursivePatternOperation (OperationKind.RecursivePattern, Type: null, IsInvalid) (Syntax: '(var x1, var x2)') (InputType: System.String[], NarrowedType: System.String[], DeclaredSymbol: null, MatchedType: System.String[], DeconstructSymbol: null) DeconstructionSubpatterns (2): IDeclarationPatternOperation (OperationKind.DeclarationPattern, Type: null, IsInvalid) (Syntax: 'var x1') (InputType: ?, NarrowedType: ?, DeclaredSymbol: ?? x1, MatchesNull: True) IDeclarationPatternOperation (OperationKind.DeclarationPattern, Type: null, IsInvalid) (Syntax: 'var x2') (InputType: ?, NarrowedType: ?, DeclaredSymbol: ?? x2, MatchesNull: True) PropertySubpatterns (0) "; var expectedDiagnostics = new DiagnosticDescription[] { // file.cs(10,13): error CS0163: Control cannot fall through from one case label ('case (string s1, string s2) _:') to another // case (string s1, string s2) _: Diagnostic(ErrorCode.ERR_SwitchFallThrough, "case (string s1, string s2) _:") .WithArguments("case (string s1, string s2) _:") .WithLocation(10, 13), // file.cs(11,27): error CS0029: Cannot implicitly convert type 'bool' to '(string, string)' // /*<bind>*/goto case args is (var x1, var x2);/*</bind>*/ Diagnostic(ErrorCode.ERR_NoImplicitConv, "goto case args is (var x1, var x2);") .WithArguments("bool", "(string, string)") .WithLocation(11, 27), // file.cs(11,45): error CS1061: 'string[]' does not contain a definition for 'Deconstruct' and no accessible extension method 'Deconstruct' accepting a first argument of type 'string[]' could be found (are you missing a using directive or an assembly reference?) // /*<bind>*/goto case args is (var x1, var x2);/*</bind>*/ Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "(var x1, var x2)") .WithArguments("string[]", "Deconstruct") .WithLocation(11, 45), // file.cs(11,45): error CS8129: No suitable 'Deconstruct' instance or extension method was found for type 'string[]', with 2 out parameters and a void return type. // /*<bind>*/goto case args is (var x1, var x2);/*</bind>*/ Diagnostic(ErrorCode.ERR_MissingDeconstruct, "(var x1, var x2)") .WithArguments("string[]", "2") .WithLocation(11, 45) }; VerifyOperationTreeAndDiagnosticsForTest <GotoStatementSyntax>( source, expectedOperationTree, expectedDiagnostics ); }
public void TestPatternCaseClause_RedundantPatternDeclarationClauses() { string source = @" using System; class X { void M(object p) { /*<bind>*/switch (p) { case int x: break; case int y: break; case X z: break; }/*</bind>*/ } } "; string expectedOperationTree = @" ISwitchOperation (3 cases, Exit Label Id: 0) (OperationKind.Switch, Type: null, IsInvalid) (Syntax: 'switch (p) ... }') Switch expression: IParameterReferenceOperation: p (OperationKind.ParameterReference, Type: System.Object) (Syntax: 'p') Sections: ISwitchCaseOperation (1 case clauses, 1 statements) (OperationKind.SwitchCase, Type: null) (Syntax: 'case int x: ... break;') Locals: Local_1: System.Int32 x Clauses: IPatternCaseClauseOperation (Label Id: 1) (CaseKind.Pattern) (OperationKind.CaseClause, Type: null) (Syntax: 'case int x:') Pattern: IDeclarationPatternOperation (OperationKind.DeclarationPattern, Type: null) (Syntax: 'int x') (InputType: System.Object, NarrowedType: System.Int32, DeclaredSymbol: System.Int32 x, MatchesNull: False) Body: IBranchOperation (BranchKind.Break, Label Id: 0) (OperationKind.Branch, Type: null) (Syntax: 'break;') ISwitchCaseOperation (1 case clauses, 1 statements) (OperationKind.SwitchCase, Type: null, IsInvalid) (Syntax: 'case int y: ... break;') Locals: Local_1: System.Int32 y Clauses: IPatternCaseClauseOperation (Label Id: 2) (CaseKind.Pattern) (OperationKind.CaseClause, Type: null, IsInvalid) (Syntax: 'case int y:') Pattern: IDeclarationPatternOperation (OperationKind.DeclarationPattern, Type: null, IsInvalid) (Syntax: 'int y') (InputType: System.Object, NarrowedType: System.Int32, DeclaredSymbol: System.Int32 y, MatchesNull: False) Body: IBranchOperation (BranchKind.Break, Label Id: 0) (OperationKind.Branch, Type: null) (Syntax: 'break;') ISwitchCaseOperation (1 case clauses, 1 statements) (OperationKind.SwitchCase, Type: null) (Syntax: 'case X z: ... break;') Locals: Local_1: X z Clauses: IPatternCaseClauseOperation (Label Id: 3) (CaseKind.Pattern) (OperationKind.CaseClause, Type: null) (Syntax: 'case X z:') Pattern: IDeclarationPatternOperation (OperationKind.DeclarationPattern, Type: null) (Syntax: 'X z') (InputType: System.Object, NarrowedType: X, DeclaredSymbol: X z, MatchesNull: False) Body: IBranchOperation (BranchKind.Break, Label Id: 0) (OperationKind.Branch, Type: null) (Syntax: 'break;') "; var expectedDiagnostics = new DiagnosticDescription[] { // file.cs(11,18): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match. // case int y: Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "int y").WithLocation(11, 18) }; VerifyOperationTreeAndDiagnosticsForTest <SwitchStatementSyntax>( source, expectedOperationTree, expectedDiagnostics ); }
public void FunctionPointerInvocation_IncorrectReturnUsage() { var comp = CreateFunctionPointerCompilation( @" unsafe class C { public string Prop { get; } void M(delegate*<string, int> ptr) /*<bind>*/{ string s = ptr(Prop); s = ptr(Prop); }/*</bind>*/ }" ); var expectedOperationTree = @" IBlockOperation (2 statements, 1 locals) (OperationKind.Block, Type: null, IsInvalid) (Syntax: '{ ... }') Locals: Local_1: System.String s IVariableDeclarationGroupOperation (1 declarations) (OperationKind.VariableDeclarationGroup, Type: null, IsInvalid) (Syntax: 'string s = ptr(Prop);') IVariableDeclarationOperation (1 declarators) (OperationKind.VariableDeclaration, Type: null, IsInvalid) (Syntax: 'string s = ptr(Prop)') Declarators: IVariableDeclaratorOperation (Symbol: System.String s) (OperationKind.VariableDeclarator, Type: null, IsInvalid) (Syntax: 's = ptr(Prop)') Initializer: IVariableInitializerOperation (OperationKind.VariableInitializer, Type: null, IsInvalid) (Syntax: '= ptr(Prop)') IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.String, IsInvalid, IsImplicit) (Syntax: 'ptr(Prop)') Conversion: CommonConversion (Exists: False, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Operand: IOperation: (OperationKind.None, Type: System.Int32, IsInvalid) (Syntax: 'ptr(Prop)') Children(2): IParameterReferenceOperation: ptr (OperationKind.ParameterReference, Type: delegate*<System.String, System.Int32>, IsInvalid) (Syntax: 'ptr') IPropertyReferenceOperation: System.String C.Prop { get; } (OperationKind.PropertyReference, Type: System.String, IsInvalid) (Syntax: 'Prop') Instance Receiver: IInstanceReferenceOperation (ReferenceKind: ContainingTypeInstance) (OperationKind.InstanceReference, Type: C, IsInvalid, IsImplicit) (Syntax: 'Prop') Initializer: null IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null, IsInvalid) (Syntax: 's = ptr(Prop);') Expression: ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.String, IsInvalid) (Syntax: 's = ptr(Prop)') Left: ILocalReferenceOperation: s (OperationKind.LocalReference, Type: System.String) (Syntax: 's') Right: IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.String, IsInvalid, IsImplicit) (Syntax: 'ptr(Prop)') Conversion: CommonConversion (Exists: False, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Operand: IOperation: (OperationKind.None, Type: System.Int32, IsInvalid) (Syntax: 'ptr(Prop)') Children(2): IParameterReferenceOperation: ptr (OperationKind.ParameterReference, Type: delegate*<System.String, System.Int32>, IsInvalid) (Syntax: 'ptr') IPropertyReferenceOperation: System.String C.Prop { get; } (OperationKind.PropertyReference, Type: System.String, IsInvalid) (Syntax: 'Prop') Instance Receiver: IInstanceReferenceOperation (ReferenceKind: ContainingTypeInstance) (OperationKind.InstanceReference, Type: C, IsInvalid, IsImplicit) (Syntax: 'Prop') "; var expectedDiagnostics = new DiagnosticDescription[] { // (7,20): error CS0029: Cannot implicitly convert type 'int' to 'string' // string s = ptr(Prop); Diagnostic(ErrorCode.ERR_NoImplicitConv, "ptr(Prop)") .WithArguments("int", "string") .WithLocation(7, 20), // (8,13): error CS0029: Cannot implicitly convert type 'int' to 'string' // s = ptr(Prop); Diagnostic(ErrorCode.ERR_NoImplicitConv, "ptr(Prop)") .WithArguments("int", "string") .WithLocation(8, 13) }; VerifyOperationTreeAndDiagnosticsForTest <BlockSyntax>( comp, expectedOperationTree, expectedDiagnostics ); }
public void TypeParameterObjectCreationFlow_04() { string source = @" using System.Collections; using System.Collections.Generic; class C1 { /*<bind>*/void M<T>(T t1, bool b) where T : C1, IEnumerable<int> { t1 = new T() { 1, 2 }; }/*</bind>*/ void Add(int i) { } } "; var expectedDiagnostics = new DiagnosticDescription[] { // CS0304: Cannot create an instance of the variable type 'T' because it does not have the new() constraint // t1 = /*<bind>*/new T() { 1, b ? 2 : 3 }; Diagnostic(ErrorCode.ERR_NoNewTyvar, "new T() { 1, 2 }").WithArguments("T").WithLocation(9, 14) }; string expectedFlowGraph = @" Block[B0] - Entry Statements (0) Next (Regular) Block[B1] Entering: {R1} .locals {R1} { CaptureIds: [0] [1] Block[B1] - Block Predecessors: [B0] Statements (5) IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 't1') Value: IParameterReferenceOperation: t1 (OperationKind.ParameterReference, Type: T) (Syntax: 't1') IFlowCaptureOperation: 1 (OperationKind.FlowCapture, Type: null, IsInvalid, IsImplicit) (Syntax: 'new T() { 1, 2 }') Value: IInvalidOperation (OperationKind.Invalid, Type: T, IsInvalid) (Syntax: 'new T() { 1, 2 }') Children(0) IInvocationOperation ( void C1.Add(System.Int32 i)) (OperationKind.Invocation, Type: System.Void, IsInvalid, IsImplicit) (Syntax: '1') Instance Receiver: IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: T, IsInvalid, IsImplicit) (Syntax: 'new T() { 1, 2 }') Arguments(1): IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: i) (OperationKind.Argument, Type: null, IsInvalid, IsImplicit) (Syntax: '1') ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1, IsInvalid) (Syntax: '1') InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) IInvocationOperation ( void C1.Add(System.Int32 i)) (OperationKind.Invocation, Type: System.Void, IsInvalid, IsImplicit) (Syntax: '2') Instance Receiver: IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: T, IsInvalid, IsImplicit) (Syntax: 'new T() { 1, 2 }') Arguments(1): IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: i) (OperationKind.Argument, Type: null, IsInvalid, IsImplicit) (Syntax: '2') ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 2, IsInvalid) (Syntax: '2') InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null, IsInvalid) (Syntax: 't1 = new T() { 1, 2 };') Expression: ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: T, IsInvalid) (Syntax: 't1 = new T() { 1, 2 }') Left: IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: T, IsImplicit) (Syntax: 't1') Right: IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: T, IsInvalid, IsImplicit) (Syntax: 'new T() { 1, 2 }') Next (Regular) Block[B2] Leaving: {R1} } Block[B2] - Exit Predecessors: [B1] Statements (0) "; VerifyFlowGraphAndDiagnosticsForTest <MethodDeclarationSyntax>(source, expectedFlowGraph, expectedDiagnostics); }
public void CoalesceAssignmentFlow_BothSidesHaveFlow() { string source = @" class C { static void M(object o1, object o2, string s1, string s2) /*<bind>*/{ (o1 ?? o2) ??= (s1 ?? s2); }/*</bind>*/ } "; string expectedFlowGraph = @" Block[B0] - Entry Statements (0) Next (Regular) Block[B1] Entering: {R1} {R2} {R3} .locals {R1} { CaptureIds: [2] .locals {R2} { CaptureIds: [1] .locals {R3} { CaptureIds: [0] Block[B1] - Block Predecessors: [B0] Statements (1) IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsInvalid, IsImplicit) (Syntax: 'o1') Value: IParameterReferenceOperation: o1 (OperationKind.ParameterReference, Type: System.Object, IsInvalid) (Syntax: 'o1') Jump if True (Regular) to Block[B3] IIsNullOperation (OperationKind.IsNull, Type: System.Boolean, IsInvalid, IsImplicit) (Syntax: 'o1') Operand: IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: System.Object, IsInvalid, IsImplicit) (Syntax: 'o1') Leaving: {R3} Next (Regular) Block[B2] Block[B2] - Block Predecessors: [B1] Statements (1) IFlowCaptureOperation: 1 (OperationKind.FlowCapture, Type: null, IsInvalid, IsImplicit) (Syntax: 'o1') Value: IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: System.Object, IsInvalid, IsImplicit) (Syntax: 'o1') Next (Regular) Block[B4] Leaving: {R3} } Block[B3] - Block Predecessors: [B1] Statements (1) IFlowCaptureOperation: 1 (OperationKind.FlowCapture, Type: null, IsInvalid, IsImplicit) (Syntax: 'o2') Value: IParameterReferenceOperation: o2 (OperationKind.ParameterReference, Type: System.Object, IsInvalid) (Syntax: 'o2') Next (Regular) Block[B4] Block[B4] - Block Predecessors: [B2] [B3] Statements (1) IFlowCaptureOperation: 2 (OperationKind.FlowCapture, Type: null, IsInvalid, IsImplicit) (Syntax: 'o1 ?? o2') Value: IInvalidOperation (OperationKind.Invalid, Type: System.Object, IsInvalid, IsImplicit) (Syntax: 'o1 ?? o2') Children(1): IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: System.Object, IsInvalid, IsImplicit) (Syntax: 'o1 ?? o2') Next (Regular) Block[B5] Leaving: {R2} Entering: {R4} } .locals {R4} { CaptureIds: [3] Block[B5] - Block Predecessors: [B4] Statements (1) IFlowCaptureOperation: 3 (OperationKind.FlowCapture, Type: null, IsInvalid, IsImplicit) (Syntax: 'o1 ?? o2') Value: IFlowCaptureReferenceOperation: 2 (OperationKind.FlowCaptureReference, Type: System.Object, IsInvalid, IsImplicit) (Syntax: 'o1 ?? o2') Jump if True (Regular) to Block[B6] IIsNullOperation (OperationKind.IsNull, Type: System.Boolean, IsInvalid, IsImplicit) (Syntax: 'o1 ?? o2') Operand: IFlowCaptureReferenceOperation: 3 (OperationKind.FlowCaptureReference, Type: System.Object, IsInvalid, IsImplicit) (Syntax: 'o1 ?? o2') Leaving: {R4} Entering: {R5} {R6} Next (Regular) Block[B10] Leaving: {R4} {R1} } .locals {R5} { CaptureIds: [5] .locals {R6} { CaptureIds: [4] Block[B6] - Block Predecessors: [B5] Statements (1) IFlowCaptureOperation: 4 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 's1') Value: IParameterReferenceOperation: s1 (OperationKind.ParameterReference, Type: System.String) (Syntax: 's1') Jump if True (Regular) to Block[B8] IIsNullOperation (OperationKind.IsNull, Type: System.Boolean, IsImplicit) (Syntax: 's1') Operand: IFlowCaptureReferenceOperation: 4 (OperationKind.FlowCaptureReference, Type: System.String, IsImplicit) (Syntax: 's1') Leaving: {R6} Next (Regular) Block[B7] Block[B7] - Block Predecessors: [B6] Statements (1) IFlowCaptureOperation: 5 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 's1') Value: IFlowCaptureReferenceOperation: 4 (OperationKind.FlowCaptureReference, Type: System.String, IsImplicit) (Syntax: 's1') Next (Regular) Block[B9] Leaving: {R6} } Block[B8] - Block Predecessors: [B6] Statements (1) IFlowCaptureOperation: 5 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 's2') Value: IParameterReferenceOperation: s2 (OperationKind.ParameterReference, Type: System.String) (Syntax: 's2') Next (Regular) Block[B9] Block[B9] - Block Predecessors: [B7] [B8] Statements (1) ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: ?, IsInvalid, IsImplicit) (Syntax: '(o1 ?? o2) ... (s1 ?? s2)') Left: IFlowCaptureReferenceOperation: 2 (OperationKind.FlowCaptureReference, Type: System.Object, IsInvalid, IsImplicit) (Syntax: 'o1 ?? o2') Right: IFlowCaptureReferenceOperation: 5 (OperationKind.FlowCaptureReference, Type: System.String, IsImplicit) (Syntax: 's1 ?? s2') Next (Regular) Block[B10] Leaving: {R5} {R1} } } Block[B10] - Exit Predecessors: [B5] [B9] Statements (0) "; var expectedDiagnostics = new DiagnosticDescription[] { // file.cs(6,10): error CS0131: The left-hand side of an assignment must be a variable, property or indexer // (o1 ?? o2) ??= (s1 ?? s2); Diagnostic(ErrorCode.ERR_AssgLvalueExpected, "o1 ?? o2").WithLocation(6, 10) }; VerifyFlowGraphAndDiagnosticsForTest <BlockSyntax>(source, expectedFlowGraph, expectedDiagnostics); }
public void CoalesceAssignment_NullValueAndTarget() { var comp = CreateCompilation(@" class C { static void M() { /*<bind>*/??=/*</bind>*/; } } "); string expectedOperationTree = @" ICoalesceAssignmentOperation (OperationKind.CoalesceAssignment, Type: ?, IsInvalid) (Syntax: '/*<bind>*/? ... /*</bind>*/') Target: IInvalidOperation (OperationKind.Invalid, Type: null) (Syntax: '') Children(0) Value: IInvalidOperation (OperationKind.Invalid, Type: null, IsInvalid) (Syntax: '') Children(0) "; var expectedDiagnostics = new DiagnosticDescription[] { // file.cs(5,6): error CS1525: Invalid expression term '??=' // { Diagnostic(ErrorCode.ERR_InvalidExprTerm, "").WithArguments("??=").WithLocation(5, 6), // file.cs(6,33): error CS1525: Invalid expression term ';' // /*<bind>*/??=/*</bind>*/; Diagnostic(ErrorCode.ERR_InvalidExprTerm, ";").WithArguments(";").WithLocation(6, 33) }; VerifyOperationTreeAndDiagnosticsForTest <AssignmentExpressionSyntax>(comp, expectedOperationTree, expectedDiagnostics); var tree = comp.SyntaxTrees[0]; var m = tree.GetRoot().DescendantNodes().OfType <MethodDeclarationSyntax>().Single(); VerifyFlowGraph(comp, m, @" Block[B0] - Entry Statements (0) Next (Regular) Block[B1] Entering: {R1} .locals {R1} { CaptureIds: [0] Block[B1] - Block Predecessors: [B0] Statements (1) IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: '') Value: IInvalidOperation (OperationKind.Invalid, Type: null) (Syntax: '') Children(0) Next (Regular) Block[B2] Entering: {R2} .locals {R2} { CaptureIds: [1] Block[B2] - Block Predecessors: [B1] Statements (1) IFlowCaptureOperation: 1 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: '') Value: IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: null, IsImplicit) (Syntax: '') Jump if True (Regular) to Block[B3] IIsNullOperation (OperationKind.IsNull, Type: System.Boolean, IsImplicit) (Syntax: '') Operand: IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: null, IsImplicit) (Syntax: '') Leaving: {R2} Next (Regular) Block[B4] Leaving: {R2} {R1} } Block[B3] - Block Predecessors: [B2] Statements (1) ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: ?, IsInvalid, IsImplicit) (Syntax: '/*<bind>*/? ... /*</bind>*/') Left: IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: null, IsImplicit) (Syntax: '') Right: IInvalidOperation (OperationKind.Invalid, Type: null, IsInvalid) (Syntax: '') Children(0) Next (Regular) Block[B4] Leaving: {R1} } Block[B4] - Exit Predecessors: [B2] [B3] Statements (0) "); }
public void FixedStatement_InvalidVariable() { string source = @" using System; class C { void M1() { int i3; unsafe { /*<bind>*/fixed (int* p1 =) { i3 = *p1; }/*</bind>*/ } } } "; string expectedOperationTree = @" IFixedOperation (OperationKind.None, Type: null, IsInvalid) (Syntax: 'fixed (int* ... }') Locals: Local_1: System.Int32* p1 Declaration: IVariableDeclarationGroupOperation (1 declarations) (OperationKind.VariableDeclarationGroup, Type: null, IsInvalid, IsImplicit) (Syntax: 'int* p1 =') IVariableDeclarationOperation (1 declarators) (OperationKind.VariableDeclaration, Type: null, IsInvalid) (Syntax: 'int* p1 =') Declarators: IVariableDeclaratorOperation (Symbol: System.Int32* p1) (OperationKind.VariableDeclarator, Type: null, IsInvalid) (Syntax: 'p1 =') Initializer: IVariableInitializerOperation (OperationKind.VariableInitializer, Type: null, IsInvalid) (Syntax: '=') IInvalidOperation (OperationKind.Invalid, Type: null, IsInvalid) (Syntax: '') Children(0) Initializer: null Body: IBlockOperation (1 statements) (OperationKind.Block, Type: null) (Syntax: '{ ... }') IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'i3 = *p1;') Expression: ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32) (Syntax: 'i3 = *p1') Left: ILocalReferenceOperation: i3 (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i3') Right: IOperation: (OperationKind.None, Type: null) (Syntax: '*p1') Children(1): ILocalReferenceOperation: p1 (OperationKind.LocalReference, Type: System.Int32*) (Syntax: 'p1') "; var expectedDiagnostics = new DiagnosticDescription[] { // CS1525: Invalid expression term ')' // /*<bind>*/fixed (int* p1 =) Diagnostic(ErrorCode.ERR_InvalidExprTerm, ")") .WithArguments(")") .WithLocation(11, 39), }; VerifyOperationTreeAndDiagnosticsForTest <FixedStatementSyntax>( source, expectedOperationTree, expectedDiagnostics, compilationOptions: TestOptions.UnsafeDebugDll ); }
public void InvalidIfElseStatement() { string source = @" using System; class Program { static void Main(string[] args) { var x = new Program(); /*<bind>*/if () { } else if (x) x; else /*</bind>*/ } } "; string expectedOperationTree = @" IConditionalOperation (OperationKind.Conditional, Type: null, IsInvalid) (Syntax: 'if () ... else') Condition: IInvalidOperation (OperationKind.Invalid, Type: null, IsInvalid) (Syntax: '') Children(0) WhenTrue: IBlockOperation (0 statements) (OperationKind.Block, Type: null) (Syntax: '{ ... }') WhenFalse: IConditionalOperation (OperationKind.Conditional, Type: null, IsInvalid) (Syntax: 'if (x) x; ... else') Condition: IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Boolean, IsInvalid, IsImplicit) (Syntax: 'x') Conversion: CommonConversion (Exists: False, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Operand: ILocalReferenceOperation: x (OperationKind.LocalReference, Type: Program, IsInvalid) (Syntax: 'x') WhenTrue: IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null, IsInvalid) (Syntax: 'x;') Expression: ILocalReferenceOperation: x (OperationKind.LocalReference, Type: Program, IsInvalid) (Syntax: 'x') WhenFalse: IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: '') Expression: IInvalidOperation (OperationKind.Invalid, Type: null) (Syntax: '') Children(0) "; var expectedDiagnostics = new DiagnosticDescription[] { // CS1525: Invalid expression term ')' // /*<bind>*/if () Diagnostic(ErrorCode.ERR_InvalidExprTerm, ")").WithArguments(")").WithLocation(9, 23), // CS1525: Invalid expression term '}' // else Diagnostic(ErrorCode.ERR_InvalidExprTerm, "").WithArguments("}").WithLocation(13, 13), // CS1002: ; expected // else Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(13, 13), // CS0029: Cannot implicitly convert type 'Program' to 'bool' // else if (x) x; Diagnostic(ErrorCode.ERR_NoImplicitConv, "x").WithArguments("Program", "bool").WithLocation(12, 18), // CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement // else if (x) x; Diagnostic(ErrorCode.ERR_IllegalStatement, "x").WithLocation(12, 21) }; VerifyOperationTreeAndDiagnosticsForTest <IfStatementSyntax>(source, expectedOperationTree, expectedDiagnostics); }
public void EventAssignment_ControlFlow_NotAStatement() { string source = @" using System; class C { #pragma warning disable CS0067 // Event is unused. public event EventHandler MyEvent; void M(C c, EventHandler handler, int? x1, int x2) /*<bind>*/{ (c.MyEvent += handler) = x1 ?? x2; }/*</bind>*/ } "; string expectedFlowGraph = @" Block[B0] - Entry Statements (0) Next (Regular) Block[B1] Entering: {R1} .locals {R1} { CaptureIds: [0] [2] Block[B1] - Block Predecessors: [B0] Statements (1) IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsInvalid, IsImplicit) (Syntax: 'c.MyEvent += handler') Value: IInvalidOperation (OperationKind.Invalid, Type: System.Void, IsInvalid, IsImplicit) (Syntax: 'c.MyEvent += handler') Children(1): IEventAssignmentOperation (EventAdd) (OperationKind.EventAssignment, Type: System.Void, IsInvalid) (Syntax: 'c.MyEvent += handler') Event Reference: IEventReferenceOperation: event System.EventHandler C.MyEvent (OperationKind.EventReference, Type: System.EventHandler, IsInvalid) (Syntax: 'c.MyEvent') Instance Receiver: IParameterReferenceOperation: c (OperationKind.ParameterReference, Type: C, IsInvalid) (Syntax: 'c') Handler: IParameterReferenceOperation: handler (OperationKind.ParameterReference, Type: System.EventHandler, IsInvalid) (Syntax: 'handler') Next (Regular) Block[B2] Entering: {R2} .locals {R2} { CaptureIds: [1] Block[B2] - Block Predecessors: [B1] Statements (1) IFlowCaptureOperation: 1 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'x1') Value: IParameterReferenceOperation: x1 (OperationKind.ParameterReference, Type: System.Int32?) (Syntax: 'x1') Jump if True (Regular) to Block[B4] IIsNullOperation (OperationKind.IsNull, Type: System.Boolean, IsImplicit) (Syntax: 'x1') Operand: IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: System.Int32?, IsImplicit) (Syntax: 'x1') Leaving: {R2} Next (Regular) Block[B3] Block[B3] - Block Predecessors: [B2] Statements (1) IFlowCaptureOperation: 2 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'x1') Value: IInvocationOperation ( System.Int32 System.Int32?.GetValueOrDefault()) (OperationKind.Invocation, Type: System.Int32, IsImplicit) (Syntax: 'x1') Instance Receiver: IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: System.Int32?, IsImplicit) (Syntax: 'x1') Arguments(0) Next (Regular) Block[B5] Leaving: {R2} } Block[B4] - Block Predecessors: [B2] Statements (1) IFlowCaptureOperation: 2 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'x2') Value: IParameterReferenceOperation: x2 (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'x2') Next (Regular) Block[B5] Block[B5] - Block Predecessors: [B3] [B4] Statements (1) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null, IsInvalid) (Syntax: '(c.MyEvent ... = x1 ?? x2;') Expression: ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Void, IsInvalid) (Syntax: '(c.MyEvent ... = x1 ?? x2') Left: IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: System.Void, IsInvalid, IsImplicit) (Syntax: 'c.MyEvent += handler') Right: IFlowCaptureReferenceOperation: 2 (OperationKind.FlowCaptureReference, Type: System.Int32, IsImplicit) (Syntax: 'x1 ?? x2') Next (Regular) Block[B6] Leaving: {R1} } Block[B6] - Exit Predecessors: [B5] Statements (0) "; var expectedDiagnostics = new DiagnosticDescription[] { // file.cs(11,10): error CS0131: The left-hand side of an assignment must be a variable, property or indexer // (c.MyEvent += handler) = x1 ?? x2; Diagnostic(ErrorCode.ERR_AssgLvalueExpected, "c.MyEvent += handler").WithLocation(11, 10) }; VerifyFlowGraphAndDiagnosticsForTest <BlockSyntax>(source, expectedFlowGraph, expectedDiagnostics); }
public void InvalidStatementFlow_01() { string source = @" using System; class Program { static void Main(string[] args) /*<bind>*/{ switch (args.Length) { case 0: /*<bind>*/goto case 1;/*</bind>*/ break; } }/*</bind>*/ } "; var expectedDiagnostics = new DiagnosticDescription[] { // file.cs(11,27): error CS0159: No such label 'case 1:' within the scope of the goto statement // /*<bind>*/goto case 1;/*</bind>*/ Diagnostic(ErrorCode.ERR_LabelNotFound, "goto case 1;").WithArguments("case 1:").WithLocation(11, 27) }; string expectedFlowGraph = @" Block[B0] - Entry Statements (0) Next (Regular) Block[B1] Entering: {R1} .locals {R1} { CaptureIds: [0] Block[B1] - Block Predecessors: [B0] Statements (1) IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'args.Length') Value: IPropertyReferenceOperation: System.Int32 System.Array.Length { get; } (OperationKind.PropertyReference, Type: System.Int32) (Syntax: 'args.Length') Instance Receiver: IParameterReferenceOperation: args (OperationKind.ParameterReference, Type: System.String[]) (Syntax: 'args') Jump if False (Regular) to Block[B3] IBinaryOperation (BinaryOperatorKind.Equals) (OperationKind.Binary, Type: System.Boolean, IsImplicit) (Syntax: '0') Left: IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: System.Int32, IsImplicit) (Syntax: 'args.Length') Right: ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0) (Syntax: '0') Leaving: {R1} Next (Regular) Block[B2] Block[B2] - Block Predecessors: [B1] Statements (2) ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1, IsInvalid) (Syntax: '1') IInvalidOperation (OperationKind.Invalid, Type: null, IsInvalid) (Syntax: 'goto case 1;') Children(0) Next (Regular) Block[B3] Leaving: {R1} } Block[B3] - Exit Predecessors: [B1] [B2] Statements (0) "; VerifyFlowGraphAndDiagnosticsForTest <BlockSyntax>(source, expectedFlowGraph, expectedDiagnostics); }
public void FixedStatement_02() { string source = @" unsafe public class MyClass { int i; unsafe void M(bool b) /*<bind>*/{ fixed (int* p = &i) { if (b) { System.Console.WriteLine($""P is {p}""); } } }/*</bind>*/ } "; var expectedDiagnostics = new DiagnosticDescription[] { // CS0029: Cannot implicitly convert type 'int*' to 'object' // System.Console.WriteLine($"P is {p}"); Diagnostic(ErrorCode.ERR_NoImplicitConv, "p").WithArguments("int*", "object").WithLocation(11, 50) }; // https://github.com/dotnet/roslyn/issues/27491: This graph verification was added to verify general handling of operations // with OperationKind.None. We have special handling for fixed statements now. // Need to make sure we haven't lost coverage for the general implementation and // add new tests if necessary. string expectedFlowGraph = @" Block[B0] - Entry Statements (0) Next (Regular) Block[B1] Entering: {R1} .locals {R1} { Locals: [System.Int32* p] Block[B1] - Block Predecessors: [B0] Statements (1) ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32*, IsImplicit) (Syntax: 'p = &i') Left: ILocalReferenceOperation: p (IsDeclaration: True) (OperationKind.LocalReference, Type: System.Int32*, IsImplicit) (Syntax: 'p = &i') Right: IOperation: (OperationKind.None, Type: null, IsImplicit) (Syntax: '&i') Children(1): IAddressOfOperation (OperationKind.AddressOf, Type: System.Int32*) (Syntax: '&i') Reference: IFieldReferenceOperation: System.Int32 MyClass.i (OperationKind.FieldReference, Type: System.Int32) (Syntax: 'i') Instance Receiver: IInstanceReferenceOperation (ReferenceKind: ContainingTypeInstance) (OperationKind.InstanceReference, Type: MyClass, IsImplicit) (Syntax: 'i') Jump if False (Regular) to Block[B3] IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'b') Leaving: {R1} Next (Regular) Block[B2] Block[B2] - Block Predecessors: [B1] Statements (1) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null, IsInvalid) (Syntax: 'System.Cons ... P is {p}"");') Expression: IInvocationOperation (void System.Console.WriteLine(System.String value)) (OperationKind.Invocation, Type: System.Void, IsInvalid) (Syntax: 'System.Cons ... ""P is {p}"")') Instance Receiver: null Arguments(1): IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: value) (OperationKind.Argument, Type: null, IsInvalid) (Syntax: '$""P is {p}""') IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String, IsInvalid) (Syntax: '$""P is {p}""') Parts(2): IInterpolatedStringTextOperation (OperationKind.InterpolatedStringText, Type: null) (Syntax: 'P is ') Text: ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: ""P is "", IsImplicit) (Syntax: 'P is ') IInterpolationOperation (OperationKind.Interpolation, Type: null, IsInvalid) (Syntax: '{p}') Expression: ILocalReferenceOperation: p (OperationKind.LocalReference, Type: System.Int32*, IsInvalid) (Syntax: 'p') Alignment: null FormatString: null InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Next (Regular) Block[B3] Leaving: {R1} } Block[B3] - Exit Predecessors: [B1] [B2] Statements (0) "; VerifyFlowGraphAndDiagnosticsForTest <BlockSyntax>(source, expectedFlowGraph, expectedDiagnostics, compilationOptions: TestOptions.UnsafeDebugDll); }
public void EventReference_ControlFlowInReceiver_StaticEvent() { string source = @" using System; class C { #pragma warning disable CS0067 // The event is never used private static event EventHandler Event1; public void M(C c1, C c2, EventHandler handler1, EventHandler handler2) /*<bind>*/ { handler1 = c1.Event1; handler2 = (c1 ?? c2).Event1; }/*</bind>*/ } "; string expectedFlowGraph = @" Block[B0] - Entry Statements (0) Next (Regular) Block[B1] Block[B1] - Block Predecessors: [B0] Statements (2) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null, IsInvalid) (Syntax: 'handler1 = c1.Event1;') Expression: ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.EventHandler, IsInvalid) (Syntax: 'handler1 = c1.Event1') Left: IParameterReferenceOperation: handler1 (OperationKind.ParameterReference, Type: System.EventHandler) (Syntax: 'handler1') Right: IEventReferenceOperation: event System.EventHandler C.Event1 (Static) (OperationKind.EventReference, Type: System.EventHandler, IsInvalid) (Syntax: 'c1.Event1') Instance Receiver: null IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null, IsInvalid) (Syntax: 'handler2 = ... c2).Event1;') Expression: ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.EventHandler, IsInvalid) (Syntax: 'handler2 = ... c2).Event1') Left: IParameterReferenceOperation: handler2 (OperationKind.ParameterReference, Type: System.EventHandler) (Syntax: 'handler2') Right: IEventReferenceOperation: event System.EventHandler C.Event1 (Static) (OperationKind.EventReference, Type: System.EventHandler, IsInvalid) (Syntax: '(c1 ?? c2).Event1') Instance Receiver: null Next (Regular) Block[B2] Block[B2] - Exit Predecessors: [B1] Statements (0) "; var expectedDiagnostics = new DiagnosticDescription[] { // file.cs(12,20): error CS0176: Member 'C.Event1' cannot be accessed with an instance reference; qualify it with a type name instead // handler1 = c1.Event1; Diagnostic(ErrorCode.ERR_ObjectProhibited, "c1.Event1").WithArguments("C.Event1").WithLocation(12, 20), // file.cs(13,20): error CS0176: Member 'C.Event1' cannot be accessed with an instance reference; qualify it with a type name instead // handler2 = (c1 ?? c2).Event1; Diagnostic(ErrorCode.ERR_ObjectProhibited, "(c1 ?? c2).Event1").WithArguments("C.Event1").WithLocation(13, 20) }; VerifyFlowGraphAndDiagnosticsForTest <BlockSyntax>(source, expectedFlowGraph, expectedDiagnostics); }
public void MethodReference_ControlFlowInReceiver_StaticMethod() { string source = @" class C { public static int M1() => 0; void M(C c1, C c2, System.Func<int> m1, System.Func<int> m2) /*<bind>*/{ m1 = c1.M1; m2 = (c1 ?? c2).M1; }/*</bind>*/ } "; string expectedFlowGraph = @" Block[B0] - Entry Statements (0) Next (Regular) Block[B1] Block[B1] - Block Predecessors: [B0] Statements (3) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null, IsInvalid) (Syntax: 'm1 = c1.M1;') Expression: ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Func<System.Int32>, IsInvalid) (Syntax: 'm1 = c1.M1') Left: IParameterReferenceOperation: m1 (OperationKind.ParameterReference, Type: System.Func<System.Int32>) (Syntax: 'm1') Right: IDelegateCreationOperation (OperationKind.DelegateCreation, Type: System.Func<System.Int32>, IsInvalid, IsImplicit) (Syntax: 'c1.M1') Target: IOperation: (OperationKind.None, Type: null, IsInvalid) (Syntax: 'c1.M1') Children(1): IParameterReferenceOperation: c1 (OperationKind.ParameterReference, Type: C, IsInvalid) (Syntax: 'c1') IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'm2') Value: IParameterReferenceOperation: m2 (OperationKind.ParameterReference, Type: System.Func<System.Int32>) (Syntax: 'm2') IFlowCaptureOperation: 1 (OperationKind.FlowCapture, Type: null, IsInvalid, IsImplicit) (Syntax: 'c1') Value: IParameterReferenceOperation: c1 (OperationKind.ParameterReference, Type: C, IsInvalid) (Syntax: 'c1') Jump if True (Regular) to Block[B3] IIsNullOperation (OperationKind.IsNull, Type: System.Boolean, IsInvalid, IsImplicit) (Syntax: 'c1') Operand: IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: C, IsInvalid, IsImplicit) (Syntax: 'c1') Next (Regular) Block[B2] Block[B2] - Block Predecessors: [B1] Statements (1) IFlowCaptureOperation: 2 (OperationKind.FlowCapture, Type: null, IsInvalid, IsImplicit) (Syntax: 'c1') Value: IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: C, IsInvalid, IsImplicit) (Syntax: 'c1') Next (Regular) Block[B4] Block[B3] - Block Predecessors: [B1] Statements (1) IFlowCaptureOperation: 2 (OperationKind.FlowCapture, Type: null, IsInvalid, IsImplicit) (Syntax: 'c2') Value: IParameterReferenceOperation: c2 (OperationKind.ParameterReference, Type: C, IsInvalid) (Syntax: 'c2') Next (Regular) Block[B4] Block[B4] - Block Predecessors: [B2] [B3] Statements (1) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null, IsInvalid) (Syntax: 'm2 = (c1 ?? c2).M1;') Expression: ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Func<System.Int32>, IsInvalid) (Syntax: 'm2 = (c1 ?? c2).M1') Left: IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: System.Func<System.Int32>, IsImplicit) (Syntax: 'm2') Right: IDelegateCreationOperation (OperationKind.DelegateCreation, Type: System.Func<System.Int32>, IsInvalid, IsImplicit) (Syntax: '(c1 ?? c2).M1') Target: IOperation: (OperationKind.None, Type: null, IsInvalid) (Syntax: '(c1 ?? c2).M1') Children(1): IFlowCaptureReferenceOperation: 2 (OperationKind.FlowCaptureReference, Type: C, IsInvalid, IsImplicit) (Syntax: 'c1 ?? c2') Next (Regular) Block[B5] Block[B5] - Exit Predecessors: [B4] Statements (0) "; var expectedDiagnostics = new DiagnosticDescription[] { // file.cs(7,14): error CS0176: Member 'C.M1()' cannot be accessed with an instance reference; qualify it with a type name instead // m1 = c1.M1; Diagnostic(ErrorCode.ERR_ObjectProhibited, "c1.M1").WithArguments("C.M1()").WithLocation(7, 14), // file.cs(8,14): error CS0176: Member 'C.M1()' cannot be accessed with an instance reference; qualify it with a type name instead // m2 = (c1 ?? c2).M1; Diagnostic(ErrorCode.ERR_ObjectProhibited, "(c1 ?? c2).M1").WithArguments("C.M1()").WithLocation(8, 14) }; VerifyFlowGraphAndDiagnosticsForTest <BlockSyntax>(source, expectedFlowGraph, expectedDiagnostics); }
public void IAnonymousFunctionExpression_StaticLambda() { string source = @" using System; class Program { static void Main(string[] args) { /*<bind>*/Action x = static () => F();/*</bind>*/ } static void F() { } } "; string expectedOperationTree = @" IVariableDeclarationGroupOperation (1 declarations) (OperationKind.VariableDeclarationGroup, Type: null, IsInvalid) (Syntax: 'Action x = ... () => F();') IVariableDeclarationOperation (1 declarators) (OperationKind.VariableDeclaration, Type: null, IsInvalid) (Syntax: 'Action x = ... c () => F()') Declarators: IVariableDeclaratorOperation (Symbol: System.Action x) (OperationKind.VariableDeclarator, Type: null, IsInvalid) (Syntax: 'x = static () => F()') Initializer: IVariableInitializerOperation (OperationKind.VariableInitializer, Type: null, IsInvalid) (Syntax: '= static () => F()') IDelegateCreationOperation (OperationKind.DelegateCreation, Type: System.Action, IsInvalid, IsImplicit) (Syntax: 'static () => F()') Target: IAnonymousFunctionOperation (Symbol: lambda expression) (OperationKind.AnonymousFunction, Type: null, IsInvalid) (Syntax: 'static () => F()') IBlockOperation (2 statements) (OperationKind.Block, Type: null, IsImplicit) (Syntax: 'F()') IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null, IsImplicit) (Syntax: 'F()') Expression: IInvocationOperation (void Program.F()) (OperationKind.Invocation, Type: System.Void) (Syntax: 'F()') Instance Receiver: null Arguments(0) IReturnOperation (OperationKind.Return, Type: null, IsImplicit) (Syntax: 'F()') ReturnedValue: null Initializer: null "; var expectedDiagnostics = new DiagnosticDescription[] { // file.cs(8,30): error CS8400: Feature 'static anonymous function' is not available in C# 8.0. Please use language version 9.0 or greater. // /*<bind>*/Action x = static () => F();/*</bind>*/ Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "static").WithArguments("static anonymous function", "9.0").WithLocation(8, 30) }; VerifyOperationTreeAndDiagnosticsForTest <LocalDeclarationStatementSyntax>( source, expectedOperationTree, expectedDiagnostics, parseOptions: TestOptions.Regular8 ); var compilation = CreateCompilationWithMscorlib40AndSystemCore(source); var syntaxTree = compilation.SyntaxTrees[0]; var semanticModel = compilation.GetSemanticModel(syntaxTree); var variableDeclaration = syntaxTree.GetRoot().DescendantNodes().OfType <LocalDeclarationStatementSyntax>().Single(); var lambdaSyntax = (LambdaExpressionSyntax)variableDeclaration.Declaration.Variables.Single().Initializer.Value; var lambdaOperation = (IAnonymousFunctionOperation)semanticModel.GetOperation(lambdaSyntax); Assert.True(lambdaOperation.Symbol.IsStatic); }
public void DeclarationFlow_01() { string source = @" class C { void M(bool b) /*<bind>*/{ M2(b ? out var i1 : out var i2); }/*</bind>*/ public void M2(out int i) { i = 0; } } "; var expectedDiagnostics = new DiagnosticDescription[] { // CS1525: Invalid expression term 'out' // M2(b ? out var i1 : out var i2); Diagnostic(ErrorCode.ERR_InvalidExprTerm, "out").WithArguments("out").WithLocation(6, 16), // CS1003: Syntax error, ':' expected // M2(b ? out var i1 : out var i2); Diagnostic(ErrorCode.ERR_SyntaxError, "out").WithArguments(":", "out").WithLocation(6, 16), // CS1525: Invalid expression term 'out' // M2(b ? out var i1 : out var i2); Diagnostic(ErrorCode.ERR_InvalidExprTerm, "out").WithArguments("out").WithLocation(6, 16), // CS1003: Syntax error, ',' expected // M2(b ? out var i1 : out var i2); Diagnostic(ErrorCode.ERR_SyntaxError, "out").WithArguments(",", "out").WithLocation(6, 16), // CS1003: Syntax error, ',' expected // M2(b ? out var i1 : out var i2); Diagnostic(ErrorCode.ERR_SyntaxError, ":").WithArguments(",", ":").WithLocation(6, 27), // CS1003: Syntax error, ',' expected // M2(b ? out var i1 : out var i2); Diagnostic(ErrorCode.ERR_SyntaxError, "out").WithArguments(",", "out").WithLocation(6, 29) }; string expectedFlowGraph = @" Block[B0] - Entry Statements (0) Next (Regular) Block[B1] Entering: {R1} .locals {R1} { Locals: [var i1] [var i2] CaptureIds: [0] Block[B1] - Block Predecessors: [B0] Statements (0) Jump if False (Regular) to Block[B3] IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'b') Next (Regular) Block[B2] Block[B2] - Block Predecessors: [B1] Statements (1) IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsInvalid, IsImplicit) (Syntax: '') Value: IInvalidOperation (OperationKind.Invalid, Type: null, IsInvalid) (Syntax: '') Children(0) Next (Regular) Block[B4] Block[B3] - Block Predecessors: [B1] Statements (1) IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsInvalid, IsImplicit) (Syntax: '') Value: IInvalidOperation (OperationKind.Invalid, Type: null, IsInvalid) (Syntax: '') Children(0) Next (Regular) Block[B4] Block[B4] - Block Predecessors: [B2] [B3] Statements (1) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null, IsInvalid) (Syntax: 'M2(b ? out ... ut var i2);') Expression: IInvalidOperation (OperationKind.Invalid, Type: System.Void, IsInvalid) (Syntax: 'M2(b ? out ... out var i2)') Children(3): IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: ?, IsInvalid, IsImplicit) (Syntax: 'b ? ') IDeclarationExpressionOperation (OperationKind.DeclarationExpression, Type: var) (Syntax: 'var i1') ILocalReferenceOperation: i1 (IsDeclaration: True) (OperationKind.LocalReference, Type: var) (Syntax: 'i1') IDeclarationExpressionOperation (OperationKind.DeclarationExpression, Type: var) (Syntax: 'var i2') ILocalReferenceOperation: i2 (IsDeclaration: True) (OperationKind.LocalReference, Type: var) (Syntax: 'i2') Next (Regular) Block[B5] Leaving: {R1} } Block[B5] - Exit Predecessors: [B4] Statements (0) "; VerifyFlowGraphAndDiagnosticsForTest <BlockSyntax>(source, expectedFlowGraph, expectedDiagnostics); }
public static void ParseAndValidateFirst(string text, DiagnosticDescription expectedFirstError) { var parsedTree = ParseWithRoundTripCheck(text); var actualErrors = parsedTree.GetDiagnostics(); actualErrors.Take(1).Verify(expectedFirstError); }
protected override DiagnosticDescription WithArguments(DiagnosticDescription d, params string[] arguments) { // TODO: Round tripping between Diagnostic and DiagnosticData seems to cause us to lose the arguments info. // For now return just the original diagnostic, we need to clean this up to handle this scenario better. return(d); }
public void DynamicMemberReference_ControlFlowInReceiver_TypeArguments() { string source = @" using System; namespace ConsoleApp1 { class C1 { static void M1(dynamic d1, dynamic d2, dynamic p) /*<bind>*/{ p = (d1 ?? d2).Prop1<int>; }/*</bind>*/ } } "; string expectedFlowGraph = @" Block[B0] - Entry Statements (0) Next (Regular) Block[B1] Entering: {R1} .locals {R1} { CaptureIds: [0] [2] Block[B1] - Block Predecessors: [B0] Statements (1) IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'p') Value: IParameterReferenceOperation: p (OperationKind.ParameterReference, Type: dynamic) (Syntax: 'p') Next (Regular) Block[B2] Entering: {R2} .locals {R2} { CaptureIds: [1] Block[B2] - Block Predecessors: [B1] Statements (1) IFlowCaptureOperation: 1 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'd1') Value: IParameterReferenceOperation: d1 (OperationKind.ParameterReference, Type: dynamic) (Syntax: 'd1') Jump if True (Regular) to Block[B4] IIsNullOperation (OperationKind.IsNull, Type: System.Boolean, IsImplicit) (Syntax: 'd1') Operand: IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: dynamic, IsImplicit) (Syntax: 'd1') Leaving: {R2} Next (Regular) Block[B3] Block[B3] - Block Predecessors: [B2] Statements (1) IFlowCaptureOperation: 2 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'd1') Value: IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: dynamic, IsImplicit) (Syntax: 'd1') Next (Regular) Block[B5] Leaving: {R2} } Block[B4] - Block Predecessors: [B2] Statements (1) IFlowCaptureOperation: 2 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'd2') Value: IParameterReferenceOperation: d2 (OperationKind.ParameterReference, Type: dynamic) (Syntax: 'd2') Next (Regular) Block[B5] Block[B5] - Block Predecessors: [B3] [B4] Statements (1) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null, IsInvalid) (Syntax: 'p = (d1 ?? ... Prop1<int>;') Expression: ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: dynamic, IsInvalid) (Syntax: 'p = (d1 ?? ... .Prop1<int>') Left: IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: dynamic, IsImplicit) (Syntax: 'p') Right: IDynamicMemberReferenceOperation (Member Name: ""Prop1"", Containing Type: null) (OperationKind.DynamicMemberReference, Type: dynamic, IsInvalid) (Syntax: '(d1 ?? d2).Prop1<int>') Type Arguments(1): Symbol: System.Int32 Instance Receiver: IFlowCaptureReferenceOperation: 2 (OperationKind.FlowCaptureReference, Type: dynamic, IsImplicit) (Syntax: 'd1 ?? d2') Next (Regular) Block[B6] Leaving: {R1} } Block[B6] - Exit Predecessors: [B5] Statements (0) "; var expectedDiagnostics = new DiagnosticDescription[] { // file.cs(10,28): error CS0307: The property 'Prop1' cannot be used with type arguments // p = (d1 ?? d2).Prop1<int>; Diagnostic(ErrorCode.ERR_TypeArgsNotAllowed, "Prop1<int>").WithArguments("Prop1", "property").WithLocation(10, 28) }; VerifyFlowGraphAndDiagnosticsForTest <BlockSyntax>(source, expectedFlowGraph, expectedDiagnostics); }
public void DiscardFlow_04() { string source = @" class C { static void M(int i1, int i2, bool b) /*<bind>*/{ (_, (b ? i1 : i2)) = (1, 2); }/*</bind>*/ }"; var expectedDiagnostics = new DiagnosticDescription[] { // file.cs(6,14): error CS0131: The left-hand side of an assignment must be a variable, property or indexer // (_, (b ? i1 : i2)) = (1, 2); Diagnostic(ErrorCode.ERR_AssgLvalueExpected, "b ? i1 : i2").WithLocation(6, 14) }; var expectedFlowGraph = @" Block[B0] - Entry Statements (0) Next (Regular) Block[B1] Entering: {R1} .locals {R1} { CaptureIds: [0] Block[B1] - Block Predecessors: [B0] Statements (0) Jump if False (Regular) to Block[B3] IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Boolean, IsInvalid) (Syntax: 'b') Next (Regular) Block[B2] Block[B2] - Block Predecessors: [B1] Statements (1) IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsInvalid, IsImplicit) (Syntax: 'i1') Value: IParameterReferenceOperation: i1 (OperationKind.ParameterReference, Type: System.Int32, IsInvalid) (Syntax: 'i1') Next (Regular) Block[B4] Block[B3] - Block Predecessors: [B1] Statements (1) IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsInvalid, IsImplicit) (Syntax: 'i2') Value: IParameterReferenceOperation: i2 (OperationKind.ParameterReference, Type: System.Int32, IsInvalid) (Syntax: 'i2') Next (Regular) Block[B4] Block[B4] - Block Predecessors: [B2] [B3] Statements (1) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null, IsInvalid) (Syntax: '(_, (b ? i1 ... ) = (1, 2);') Expression: IDeconstructionAssignmentOperation (OperationKind.DeconstructionAssignment, Type: (System.Int32, System.Int32), IsInvalid) (Syntax: '(_, (b ? i1 ... )) = (1, 2)') Left: ITupleOperation (OperationKind.Tuple, Type: (System.Int32, System.Int32), IsInvalid) (Syntax: '(_, (b ? i1 : i2))') NaturalType: (System.Int32, System.Int32) Elements(2): IDiscardOperation (Symbol: System.Int32 _) (OperationKind.Discard, Type: System.Int32) (Syntax: '_') IInvalidOperation (OperationKind.Invalid, Type: System.Int32, IsInvalid, IsImplicit) (Syntax: 'b ? i1 : i2') Children(1): IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: System.Int32, IsInvalid, IsImplicit) (Syntax: 'b ? i1 : i2') Right: ITupleOperation (OperationKind.Tuple, Type: (System.Int32, System.Int32)) (Syntax: '(1, 2)') NaturalType: (System.Int32, System.Int32) Elements(2): ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1') ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 2) (Syntax: '2') Next (Regular) Block[B5] Leaving: {R1} } Block[B5] - Exit Predecessors: [B4] Statements (0) "; VerifyFlowGraphAndDiagnosticsForTest <BlockSyntax>(source, expectedFlowGraph, expectedDiagnostics); }
internal void VerifySemantics( EditScript <SyntaxNode> editScript, ActiveStatementsDescription activeStatements = null, IEnumerable <string> additionalOldSources = null, IEnumerable <string> additionalNewSources = null, SemanticEditDescription[] expectedSemanticEdits = null, DiagnosticDescription expectedDeclarationError = null, RudeEditDiagnosticDescription[] expectedDiagnostics = null) { activeStatements ??= ActiveStatementsDescription.Empty; var editMap = Analyzer.BuildEditMap(editScript); var oldRoot = editScript.Match.OldRoot; var newRoot = editScript.Match.NewRoot; var oldSource = oldRoot.SyntaxTree.ToString(); var newSource = newRoot.SyntaxTree.ToString(); var oldText = SourceText.From(oldSource); var newText = SourceText.From(newSource); IEnumerable <SyntaxTree> oldTrees = new[] { oldRoot.SyntaxTree }; IEnumerable <SyntaxTree> newTrees = new[] { newRoot.SyntaxTree }; if (additionalOldSources != null) { oldTrees = oldTrees.Concat(additionalOldSources.Select(s => ParseText(s))); } if (additionalOldSources != null) { newTrees = newTrees.Concat(additionalNewSources.Select(s => ParseText(s))); } var oldCompilation = CreateLibraryCompilation("Old", oldTrees); var newCompilation = CreateLibraryCompilation("New", newTrees); var oldModel = oldCompilation.GetSemanticModel(oldRoot.SyntaxTree); var newModel = newCompilation.GetSemanticModel(newRoot.SyntaxTree); var oldActiveStatements = activeStatements.OldStatements.AsImmutable(); var updatedActiveMethodMatches = new List <AbstractEditAndContinueAnalyzer.UpdatedMemberInfo>(); var triviaEdits = new List <(SyntaxNode OldNode, SyntaxNode NewNode)>(); var actualLineEdits = new List <LineChange>(); var actualSemanticEdits = new List <SemanticEdit>(); var diagnostics = new List <RudeEditDiagnostic>(); var actualNewActiveStatements = new ActiveStatement[activeStatements.OldStatements.Length]; var actualNewExceptionRegions = new ImmutableArray <LinePositionSpan> [activeStatements.OldStatements.Length]; Analyzer.GetTestAccessor().AnalyzeSyntax( editScript, editMap, oldText, newText, null, null, oldActiveStatements, actualNewActiveStatements, actualNewExceptionRegions, updatedActiveMethodMatches, diagnostics); diagnostics.Verify(newSource); Analyzer.GetTestAccessor().AnalyzeTrivia( oldText, newText, editScript.Match, editMap, triviaEdits, actualLineEdits, diagnostics, CancellationToken.None); diagnostics.Verify(newSource); Analyzer.GetTestAccessor().AnalyzeSemantics( editScript, editMap, oldText, oldActiveStatements, triviaEdits, updatedActiveMethodMatches, oldModel, newModel, actualSemanticEdits, diagnostics, out var firstDeclarationErrorOpt, CancellationToken.None); var actualDeclarationErrors = (firstDeclarationErrorOpt != null) ? new[] { firstDeclarationErrorOpt } : Array.Empty <Diagnostic>(); var expectedDeclarationErrors = (expectedDeclarationError != null) ? new[] { expectedDeclarationError } : Array.Empty <DiagnosticDescription>(); actualDeclarationErrors.Verify(expectedDeclarationErrors); diagnostics.Verify(newSource, expectedDiagnostics); if (expectedSemanticEdits == null) { return; } Assert.Equal(expectedSemanticEdits.Length, actualSemanticEdits.Count); for (var i = 0; i < actualSemanticEdits.Count; i++) { var editKind = expectedSemanticEdits[i].Kind; Assert.Equal(editKind, actualSemanticEdits[i].Kind); var expectedOldSymbol = (editKind == SemanticEditKind.Update) ? expectedSemanticEdits[i].SymbolProvider(oldCompilation) : null; var expectedNewSymbol = expectedSemanticEdits[i].SymbolProvider(newCompilation); var actualOldSymbol = actualSemanticEdits[i].OldSymbol; var actualNewSymbol = actualSemanticEdits[i].NewSymbol; Assert.Equal(expectedOldSymbol, actualOldSymbol); Assert.Equal(expectedNewSymbol, actualNewSymbol); var expectedSyntaxMap = expectedSemanticEdits[i].SyntaxMap; var actualSyntaxMap = actualSemanticEdits[i].SyntaxMap; Assert.Equal(expectedSemanticEdits[i].PreserveLocalVariables, actualSemanticEdits[i].PreserveLocalVariables); if (expectedSyntaxMap != null) { Assert.NotNull(actualSyntaxMap); Assert.True(expectedSemanticEdits[i].PreserveLocalVariables); var newNodes = new List <SyntaxNode>(); foreach (var expectedSpanMapping in expectedSyntaxMap) { var newNode = FindNode(newRoot, expectedSpanMapping.Value); var expectedOldNode = FindNode(oldRoot, expectedSpanMapping.Key); var actualOldNode = actualSyntaxMap(newNode); Assert.Equal(expectedOldNode, actualOldNode); newNodes.Add(newNode); } } else if (!expectedSemanticEdits[i].PreserveLocalVariables) { Assert.Null(actualSyntaxMap); } } }
public void NoneOperation_Expression_04() { string source = @" unsafe public class MyClass { public static void Main(bool a, int b, int c, int* i, int j) /*<bind>*/{ j = i[1, (a ? b : c)]; }/*</bind>*/ } "; var expectedDiagnostics = new DiagnosticDescription[] { // CS0196: A pointer must be indexed by only one value // j = i[1, (a ? b : c)]; Diagnostic(ErrorCode.ERR_PtrIndexSingle, "i[1, (a ? b : c)]").WithLocation(6, 13) }; string expectedFlowGraph = @" Block[B0] - Entry Statements (0) Next (Regular) Block[B1] Entering: {R1} .locals {R1} { CaptureIds: [0] [1] [2] [3] Block[B1] - Block Predecessors: [B0] Statements (3) IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'j') Value: IParameterReferenceOperation: j (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'j') IFlowCaptureOperation: 1 (OperationKind.FlowCapture, Type: null, IsInvalid, IsImplicit) (Syntax: 'i') Value: IParameterReferenceOperation: i (OperationKind.ParameterReference, Type: System.Int32*, IsInvalid) (Syntax: 'i') IFlowCaptureOperation: 2 (OperationKind.FlowCapture, Type: null, IsInvalid, IsImplicit) (Syntax: '1') Value: ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1, IsInvalid) (Syntax: '1') Jump if False (Regular) to Block[B3] IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Boolean, IsInvalid) (Syntax: 'a') Next (Regular) Block[B2] Block[B2] - Block Predecessors: [B1] Statements (1) IFlowCaptureOperation: 3 (OperationKind.FlowCapture, Type: null, IsInvalid, IsImplicit) (Syntax: 'b') Value: IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Int32, IsInvalid) (Syntax: 'b') Next (Regular) Block[B4] Block[B3] - Block Predecessors: [B1] Statements (1) IFlowCaptureOperation: 3 (OperationKind.FlowCapture, Type: null, IsInvalid, IsImplicit) (Syntax: 'c') Value: IParameterReferenceOperation: c (OperationKind.ParameterReference, Type: System.Int32, IsInvalid) (Syntax: 'c') Next (Regular) Block[B4] Block[B4] - Block Predecessors: [B2] [B3] Statements (1) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null, IsInvalid) (Syntax: 'j = i[1, (a ? b : c)];') Expression: ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, IsInvalid) (Syntax: 'j = i[1, (a ? b : c)]') Left: IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: System.Int32, IsImplicit) (Syntax: 'j') Right: IOperation: (OperationKind.None, Type: null, IsInvalid) (Syntax: 'i[1, (a ? b : c)]') Children(2): IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: System.Int32*, IsInvalid, IsImplicit) (Syntax: 'i') IInvalidOperation (OperationKind.Invalid, Type: ?, IsInvalid, IsImplicit) (Syntax: 'i[1, (a ? b : c)]') Children(2): IFlowCaptureReferenceOperation: 2 (OperationKind.FlowCaptureReference, Type: System.Int32, Constant: 1, IsInvalid, IsImplicit) (Syntax: '1') IFlowCaptureReferenceOperation: 3 (OperationKind.FlowCaptureReference, Type: System.Int32, IsInvalid, IsImplicit) (Syntax: 'a ? b : c') Next (Regular) Block[B5] Leaving: {R1} } Block[B5] - Exit Predecessors: [B4] Statements (0) "; VerifyFlowGraphAndDiagnosticsForTest <BlockSyntax>(source, expectedFlowGraph, expectedDiagnostics, compilationOptions: TestOptions.UnsafeDebugDll); }
public void DeconstructionFlow_05() { string source = @" class C { void M(bool b) /*<bind>*/{ int i2; (int i1, i2) = b ? (1, 2) : (3, 4); }/*</bind>*/ public void M2(out (int, int) i) { i = (0, 0); } } "; var expectedDiagnostics = new DiagnosticDescription[] { // CS8184: A deconstruction cannot mix declarations and expressions on the left-hand-side. // (int i2, i1) = b ? (1, 2) : (3, 4); Diagnostic(ErrorCode.ERR_MixedDeconstructionUnsupported, "(int i1, i2)").WithLocation(7, 9) }; string expectedFlowGraph = @" Block[B0] - Entry Statements (0) Next (Regular) Block[B1] Entering: {R1} .locals {R1} { Locals: [System.Int32 i2] [System.Int32 i1] Block[B1] - Block Predecessors: [B0] Statements (1) IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsInvalid, IsImplicit) (Syntax: 'i2') Value: ILocalReferenceOperation: i2 (OperationKind.LocalReference, Type: System.Int32, IsInvalid) (Syntax: 'i2') Jump if False (Regular) to Block[B3] IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'b') Next (Regular) Block[B2] Block[B2] - Block Predecessors: [B1] Statements (1) IFlowCaptureOperation: 1 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: '(1, 2)') Value: ITupleOperation (OperationKind.Tuple, Type: (System.Int32, System.Int32)) (Syntax: '(1, 2)') NaturalType: (System.Int32, System.Int32) Elements(2): ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1') ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 2) (Syntax: '2') Next (Regular) Block[B4] Block[B3] - Block Predecessors: [B1] Statements (1) IFlowCaptureOperation: 1 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: '(3, 4)') Value: ITupleOperation (OperationKind.Tuple, Type: (System.Int32, System.Int32)) (Syntax: '(3, 4)') NaturalType: (System.Int32, System.Int32) Elements(2): ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 3) (Syntax: '3') ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 4) (Syntax: '4') Next (Regular) Block[B4] Block[B4] - Block Predecessors: [B2] [B3] Statements (1) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null, IsInvalid) (Syntax: '(int i1, i2 ... ) : (3, 4);') Expression: IDeconstructionAssignmentOperation (OperationKind.DeconstructionAssignment, Type: (System.Int32 i1, System.Int32 i2), IsInvalid) (Syntax: '(int i1, i2 ... 2) : (3, 4)') Left: ITupleOperation (OperationKind.Tuple, Type: (System.Int32 i1, System.Int32 i2), IsInvalid) (Syntax: '(int i1, i2)') NaturalType: (System.Int32 i1, System.Int32 i2) Elements(2): IDeclarationExpressionOperation (OperationKind.DeclarationExpression, Type: System.Int32, IsInvalid) (Syntax: 'int i1') ILocalReferenceOperation: i1 (IsDeclaration: True) (OperationKind.LocalReference, Type: System.Int32, IsInvalid) (Syntax: 'i1') IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: System.Int32, IsInvalid, IsImplicit) (Syntax: 'i2') Right: IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: (System.Int32, System.Int32), IsImplicit) (Syntax: 'b ? (1, 2) : (3, 4)') Next (Regular) Block[B5] Leaving: {R1} } Block[B5] - Exit Predecessors: [B4] Statements (0) "; VerifyFlowGraphAndDiagnosticsForTest <BlockSyntax>(source, expectedFlowGraph, expectedDiagnostics); }