提交 72b8f88b 编写于 作者: M Manish Vasani 提交者: AlekseyTs

Fix InvalidCastException in CSharpOperationFactory for invalid nested member initializer (#22983)

Fixes #22967
上级 79fc0a89
......@@ -964,7 +964,7 @@ private IMemberInitializerOperation CreateBoundMemberInitializerOperation(BoundA
{
Debug.Assert(IsMemberInitializer(boundAssignmentOperator));
Lazy<IMemberReferenceOperation> target = new Lazy<IMemberReferenceOperation>(() => (IMemberReferenceOperation)Create(boundAssignmentOperator.Left));
Lazy<IOperation> target = new Lazy<IOperation>(() => Create(boundAssignmentOperator.Left));
Lazy<IObjectOrCollectionInitializerOperation> value = new Lazy<IObjectOrCollectionInitializerOperation>(() => (IObjectOrCollectionInitializerOperation)Create(boundAssignmentOperator.Right));
SyntaxNode syntax = boundAssignmentOperator.Syntax;
ITypeSymbol type = boundAssignmentOperator.Type;
......
......@@ -472,5 +472,137 @@ static void Main()
VerifyOperationTreeAndDiagnosticsForTest<ObjectCreationExpressionSyntax>(source, expectedOperationTree, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation)]
[Fact, WorkItem(22967, "https://github.com/dotnet/roslyn/issues/22967")]
public void ObjectCreationWithInvalidInitializer()
{
string source = @"
class C
{
public void M1()
{
var x1 = /*<bind>*/new C() { MissingMember = 1 }/*</bind>*/;
}
}
";
string expectedOperationTree = @"
IObjectCreationOperation (Constructor: C..ctor()) (OperationKind.ObjectCreation, Type: C, IsInvalid) (Syntax: 'new C() { M ... ember = 1 }')
Arguments(0)
Initializer:
IObjectOrCollectionInitializerOperation (OperationKind.ObjectOrCollectionInitializer, Type: C, IsInvalid) (Syntax: '{ MissingMember = 1 }')
Initializers(1):
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: ?, IsInvalid) (Syntax: 'MissingMember = 1')
Left:
IInvalidOperation (OperationKind.Invalid, Type: ?, IsInvalid, IsImplicit) (Syntax: 'MissingMember')
Children(1):
IOperation: (OperationKind.None, Type: null, IsInvalid) (Syntax: 'MissingMember')
Children(1):
IInstanceReferenceOperation (OperationKind.InstanceReference, Type: C, IsImplicit) (Syntax: 'C')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1')
";
var expectedDiagnostics = new DiagnosticDescription[] {
// file.cs(6,38): error CS0117: 'C' does not contain a definition for 'MissingMember'
// var x1 = /*<bind>*/new C() { MissingMember = 1 }/*</bind>*/;
Diagnostic(ErrorCode.ERR_NoSuchMember, "MissingMember").WithArguments("C", "MissingMember").WithLocation(6, 38)
};
VerifyOperationTreeAndDiagnosticsForTest<ObjectCreationExpressionSyntax>(source, expectedOperationTree, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation)]
[Fact, WorkItem(22967, "https://github.com/dotnet/roslyn/issues/22967")]
public void ObjectCreationWithInvalidMemberInitializer()
{
string source = @"
class C
{
public void M1()
{
var x1 = /*<bind>*/new C(){ MissingField = { x = 1 } }/*</bind>*/;
}
}
";
string expectedOperationTree = @"
IObjectCreationOperation (Constructor: C..ctor()) (OperationKind.ObjectCreation, Type: C, IsInvalid) (Syntax: 'new C(){ Mi ... { x = 1 } }')
Arguments(0)
Initializer:
IObjectOrCollectionInitializerOperation (OperationKind.ObjectOrCollectionInitializer, Type: C, IsInvalid) (Syntax: '{ MissingFi ... { x = 1 } }')
Initializers(1):
IMemberInitializerOperation (OperationKind.MemberInitializer, Type: ?, IsInvalid) (Syntax: 'MissingField = { x = 1 }')
InitializedMember:
IInvalidOperation (OperationKind.Invalid, Type: ?, IsInvalid, IsImplicit) (Syntax: 'MissingField')
Children(1):
IOperation: (OperationKind.None, Type: null, IsInvalid) (Syntax: 'MissingField')
Children(1):
IInstanceReferenceOperation (OperationKind.InstanceReference, Type: C, IsImplicit) (Syntax: 'C')
Initializer:
IObjectOrCollectionInitializerOperation (OperationKind.ObjectOrCollectionInitializer, Type: ?) (Syntax: '{ x = 1 }')
Initializers(1):
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: ?) (Syntax: 'x = 1')
Left:
IInvalidOperation (OperationKind.Invalid, Type: ?, IsImplicit) (Syntax: 'x')
Children(1):
IOperation: (OperationKind.None, Type: null) (Syntax: 'x')
Children(1):
IInstanceReferenceOperation (OperationKind.InstanceReference, Type: ?, IsInvalid, IsImplicit) (Syntax: 'MissingField')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1')
";
var expectedDiagnostics = new DiagnosticDescription[] {
// file.cs(6,37): error CS0117: 'C' does not contain a definition for 'MissingField'
// var x1 = /*<bind>*/new C(){ MissingField = { x = 1 } }/*</bind>*/;
Diagnostic(ErrorCode.ERR_NoSuchMember, "MissingField").WithArguments("C", "MissingField").WithLocation(6, 37)
};
VerifyOperationTreeAndDiagnosticsForTest<ObjectCreationExpressionSyntax>(source, expectedOperationTree, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation)]
[Fact, WorkItem(22967, "https://github.com/dotnet/roslyn/issues/22967")]
public void ObjectCreationWithInvalidCollectionInitializer()
{
string source = @"
using System.Collections.Generic;
class C
{
public void M1()
{
var x1 = /*<bind>*/new C(){ MissingField = new List<int>() { 1 }}/*</bind>*/;
}
}
";
string expectedOperationTree = @"
IObjectCreationOperation (Constructor: C..ctor()) (OperationKind.ObjectCreation, Type: C, IsInvalid) (Syntax: 'new C(){ Mi ... t>() { 1 }}')
Arguments(0)
Initializer:
IObjectOrCollectionInitializerOperation (OperationKind.ObjectOrCollectionInitializer, Type: C, IsInvalid) (Syntax: '{ MissingFi ... t>() { 1 }}')
Initializers(1):
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: ?, IsInvalid) (Syntax: 'MissingFiel ... nt>() { 1 }')
Left:
IInvalidOperation (OperationKind.Invalid, Type: ?, IsInvalid, IsImplicit) (Syntax: 'MissingField')
Children(1):
IOperation: (OperationKind.None, Type: null, IsInvalid) (Syntax: 'MissingField')
Children(1):
IInstanceReferenceOperation (OperationKind.InstanceReference, Type: C, IsImplicit) (Syntax: 'C')
Right:
IObjectCreationOperation (Constructor: System.Collections.Generic.List<System.Int32>..ctor()) (OperationKind.ObjectCreation, Type: System.Collections.Generic.List<System.Int32>) (Syntax: 'new List<int>() { 1 }')
Arguments(0)
Initializer:
IObjectOrCollectionInitializerOperation (OperationKind.ObjectOrCollectionInitializer, Type: System.Collections.Generic.List<System.Int32>) (Syntax: '{ 1 }')
Initializers(1):
ICollectionElementInitializerOperation (AddMethod: void System.Collections.Generic.List<System.Int32>.Add(System.Int32 item)) (IsDynamic: False) (OperationKind.CollectionElementInitializer, Type: System.Void, IsImplicit) (Syntax: '1')
Arguments(1):
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1')
";
var expectedDiagnostics = new DiagnosticDescription[] {
// file.cs(8,37): error CS0117: 'C' does not contain a definition for 'MissingField'
// var x1 = /*<bind>*/new C(){ MissingField = new List<int>() { 1 }}/*</bind>*/;
Diagnostic(ErrorCode.ERR_NoSuchMember, "MissingField").WithArguments("C", "MissingField").WithLocation(8, 37)
};
VerifyOperationTreeAndDiagnosticsForTest<ObjectCreationExpressionSyntax>(source, expectedOperationTree, expectedDiagnostics);
}
}
}
......@@ -6304,7 +6304,7 @@ internal abstract partial class BaseMemberInitializerExpression : Operation, IMe
{
}
protected abstract IMemberReferenceOperation InitializedMemberImpl { get; }
protected abstract IOperation InitializedMemberImpl { get; }
protected abstract IObjectOrCollectionInitializerOperation InitializerImpl { get; }
public override IEnumerable<IOperation> Children
{
......@@ -6323,7 +6323,7 @@ public override IEnumerable<IOperation> Children
/// <summary>
/// Initialized member.
/// </summary>
public IMemberReferenceOperation InitializedMember => Operation.SetParentOperation(InitializedMemberImpl, this);
public IOperation InitializedMember => Operation.SetParentOperation(InitializedMemberImpl, this);
/// <summary>
/// Member initializer.
......@@ -6344,14 +6344,14 @@ public override void Accept(OperationVisitor visitor)
/// </summary>
internal sealed partial class MemberInitializerExpression : BaseMemberInitializerExpression, IMemberInitializerOperation
{
public MemberInitializerExpression(IMemberReferenceOperation initializedMember, IObjectOrCollectionInitializerOperation initializer, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional<object> constantValue, bool isImplicit) :
public MemberInitializerExpression(IOperation initializedMember, IObjectOrCollectionInitializerOperation initializer, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional<object> constantValue, bool isImplicit) :
base(semanticModel, syntax, type, constantValue, isImplicit)
{
InitializedMemberImpl = initializedMember;
InitializerImpl = initializer;
}
protected override IMemberReferenceOperation InitializedMemberImpl { get; }
protected override IOperation InitializedMemberImpl { get; }
protected override IObjectOrCollectionInitializerOperation InitializerImpl { get; }
}
......@@ -6360,17 +6360,17 @@ internal sealed partial class MemberInitializerExpression : BaseMemberInitialize
/// </summary>
internal sealed partial class LazyMemberInitializerExpression : BaseMemberInitializerExpression, IMemberInitializerOperation
{
private readonly Lazy<IMemberReferenceOperation> _lazyInitializedMember;
private readonly Lazy<IOperation> _lazyInitializedMember;
private readonly Lazy<IObjectOrCollectionInitializerOperation> _lazyInitializer;
public LazyMemberInitializerExpression(Lazy<IMemberReferenceOperation> initializedMember, Lazy<IObjectOrCollectionInitializerOperation> initializer, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional<object> constantValue, bool isImplicit) :
public LazyMemberInitializerExpression(Lazy<IOperation> initializedMember, Lazy<IObjectOrCollectionInitializerOperation> initializer, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional<object> constantValue, bool isImplicit) :
base(semanticModel, syntax, type, constantValue, isImplicit)
{
_lazyInitializedMember = initializedMember ?? throw new System.ArgumentNullException(nameof(initializedMember));
_lazyInitializer = initializer ?? throw new System.ArgumentNullException(nameof(initializer));
}
protected override IMemberReferenceOperation InitializedMemberImpl => _lazyInitializedMember.Value;
protected override IOperation InitializedMemberImpl => _lazyInitializedMember.Value;
protected override IObjectOrCollectionInitializerOperation InitializerImpl => _lazyInitializer.Value;
}
......
......@@ -3,11 +3,10 @@
namespace Microsoft.CodeAnalysis.Operations
{
/// <summary>
/// Represents an initialization of member within an object initializer.
/// Represents an initialization of member within an object initializer with a nested object or collection initializer.
/// <para>
/// Current usage:
/// (1) C# member initializer expression.
/// (2) VB member initializer expression.
/// (1) C# nested member initializer expression.
/// For example, given an object creation with initializer "new Class() { X = x, Y = { x, y, 3 }, Z = { X = z } }",
/// member initializers for Y and Z, i.e. "Y = { x, y, 3 }", and "Z = { X = z }" are nested member initializers represented by this operation.
/// </para>
......@@ -19,9 +18,9 @@ namespace Microsoft.CodeAnalysis.Operations
public interface IMemberInitializerOperation : IOperation
{
/// <summary>
/// Initialized member.
/// Initialized member reference <see cref="IMemberReferenceOperation"/> or an invalid operation for error cases.
/// </summary>
IMemberReferenceOperation InitializedMember { get; }
IOperation InitializedMember { get; }
/// <summary>
/// Member initializer.
......
......@@ -375,7 +375,7 @@ Microsoft.CodeAnalysis.Operations.ILoopOperation.Body.get -> Microsoft.CodeAnaly
Microsoft.CodeAnalysis.Operations.ILoopOperation.Locals.get -> System.Collections.Immutable.ImmutableArray<Microsoft.CodeAnalysis.ILocalSymbol>
Microsoft.CodeAnalysis.Operations.ILoopOperation.LoopKind.get -> Microsoft.CodeAnalysis.Operations.LoopKind
Microsoft.CodeAnalysis.Operations.IMemberInitializerOperation
Microsoft.CodeAnalysis.Operations.IMemberInitializerOperation.InitializedMember.get -> Microsoft.CodeAnalysis.Operations.IMemberReferenceOperation
Microsoft.CodeAnalysis.Operations.IMemberInitializerOperation.InitializedMember.get -> Microsoft.CodeAnalysis.IOperation
Microsoft.CodeAnalysis.Operations.IMemberInitializerOperation.Initializer.get -> Microsoft.CodeAnalysis.Operations.IObjectOrCollectionInitializerOperation
Microsoft.CodeAnalysis.Operations.IMemberReferenceOperation
Microsoft.CodeAnalysis.Operations.IMemberReferenceOperation.Instance.get -> Microsoft.CodeAnalysis.IOperation
......
......@@ -404,5 +404,140 @@ IObjectCreationOperation (Constructor: Sub [Class]..ctor()) (OperationKind.Objec
VerifyOperationTreeAndDiagnosticsForTest(Of ObjectCreationExpressionSyntax)(source, expectedOperationTree, expectedDiagnostics)
End Sub
<CompilerTrait(CompilerFeature.IOperation)>
<Fact, WorkItem(22967, "https://github.com/dotnet/roslyn/issues/22967")>
Public Sub ObjectCreationWithInvalidInitializer()
Dim source = <![CDATA[
Class C
Public Sub M1()
Dim x1 = New C With {.MissingField = 1}'BIND:"New C With {.MissingField = 1}"
End Sub
End Class]]>.Value
Dim expectedOperationTree = <![CDATA[
IObjectCreationOperation (Constructor: Sub C..ctor()) (OperationKind.ObjectCreation, Type: C, IsInvalid) (Syntax: 'New C With ... gField = 1}')
Arguments(0)
Initializer:
IObjectOrCollectionInitializerOperation (OperationKind.ObjectOrCollectionInitializer, Type: C, IsInvalid) (Syntax: 'With {.MissingField = 1}')
Initializers(1):
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: ?, IsInvalid) (Syntax: '.MissingField = 1')
Left:
IInvalidOperation (OperationKind.Invalid, Type: ?, IsInvalid, IsImplicit) (Syntax: '.MissingField = 1')
Children(1):
IInvalidOperation (OperationKind.Invalid, Type: ?, IsInvalid) (Syntax: 'MissingField')
Children(1):
IInstanceReferenceOperation (OperationKind.InstanceReference, Type: C, IsInvalid, IsImplicit) (Syntax: 'New C With ... gField = 1}')
Right:
IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: ?, IsImplicit) (Syntax: '1')
Conversion: CommonConversion (Exists: False, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
Operand:
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1')
]]>.Value
Dim expectedDiagnostics = <![CDATA[
BC30456: 'MissingField' is not a member of 'C'.
Dim x1 = New C With {.MissingField = 1}'BIND:"New C With {.MissingField = 1}"
~~~~~~~~~~~~
]]>.Value
VerifyOperationTreeAndDiagnosticsForTest(Of ObjectCreationExpressionSyntax)(source, expectedOperationTree, expectedDiagnostics)
End Sub
<CompilerTrait(CompilerFeature.IOperation)>
<Fact(Skip:="https://github.com/dotnet/roslyn/issues/22980"), WorkItem(22967, "https://github.com/dotnet/roslyn/issues/22967")>
Public Sub ObjectCreationWithInvalidCollectionInitializer()
Dim source = <![CDATA[
Class C
Public Sub M1()
Dim x1 = New C With {.MissingField = {x = 1}}'BIND:"New C With {.MissingField = {x = 1}}"
End Sub
End Class]]>.Value
Dim expectedOperationTree = <![CDATA[
IObjectCreationOperation (Constructor: Sub C..ctor()) (OperationKind.ObjectCreation, Type: C, IsInvalid) (Syntax: 'New C With ... = {x = 1}}')
Arguments(0)
Initializer:
IObjectOrCollectionInitializerOperation (OperationKind.ObjectOrCollectionInitializer, Type: C, IsInvalid) (Syntax: 'With {.Miss ... = {x = 1}}')
Initializers(1):
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: ?, IsInvalid) (Syntax: '.MissingField = {x = 1}')
Left:
IInvalidOperation (OperationKind.Invalid, Type: ?, IsInvalid, IsImplicit) (Syntax: '.MissingField = {x = 1}')
Children(1):
IInvalidOperation (OperationKind.Invalid, Type: ?, IsInvalid) (Syntax: 'MissingField')
Children(1):
IInstanceReferenceOperation (OperationKind.InstanceReference, Type: C, IsInvalid, IsImplicit) (Syntax: 'New C With ... = {x = 1}}')
Right:
IInvalidOperation (OperationKind.Invalid, Type: ?, IsInvalid, IsImplicit) (Syntax: '{x = 1}')
Children(1):
IOperation: (OperationKind.None, Type: null, IsInvalid) (Syntax: '{x = 1}')
Children(2):
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1, IsInvalid, IsImplicit) (Syntax: '{x = 1}')
IArrayInitializerOperation (1 elements) (OperationKind.ArrayInitializer, Type: null, IsInvalid) (Syntax: '{x = 1}')
Element Values(1):
IBinaryOperation (BinaryOperatorKind.Equals, Checked) (OperationKind.BinaryOperator, Type: ?, IsInvalid) (Syntax: 'x = 1')
Left:
IInvalidOperation (OperationKind.Invalid, Type: ?, IsInvalid) (Syntax: 'x')
Children(0)
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1')
]]>.Value
Dim expectedDiagnostics = <![CDATA[
BC30456: 'MissingField' is not a member of 'C'.
Dim x1 = New C With {.MissingField = {x = 1}}'BIND:"New C With {.MissingField = {x = 1}}"
~~~~~~~~~~~~
BC30451: 'x' is not declared. It may be inaccessible due to its protection level.
Dim x1 = New C With {.MissingField = {x = 1}}'BIND:"New C With {.MissingField = {x = 1}}"
~
]]>.Value
VerifyOperationTreeAndDiagnosticsForTest(Of ObjectCreationExpressionSyntax)(source, expectedOperationTree, expectedDiagnostics)
End Sub
<CompilerTrait(CompilerFeature.IOperation)>
<Fact, WorkItem(22967, "https://github.com/dotnet/roslyn/issues/22967")>
Public Sub ObjectCreationWithInvalidCollectionInitializer02()
Dim source = <![CDATA[
Class C
Public Sub M1()
Dim x1 = New C With {.MissingField = {1}}'BIND:"New C With {.MissingField = {1}}"
End Sub
End Class]]>.Value
Dim expectedOperationTree = <![CDATA[
IObjectCreationOperation (Constructor: Sub C..ctor()) (OperationKind.ObjectCreation, Type: C, IsInvalid) (Syntax: 'New C With ... ield = {1}}')
Arguments(0)
Initializer:
IObjectOrCollectionInitializerOperation (OperationKind.ObjectOrCollectionInitializer, Type: C, IsInvalid) (Syntax: 'With {.Miss ... ield = {1}}')
Initializers(1):
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: ?, IsInvalid) (Syntax: '.MissingField = {1}')
Left:
IInvalidOperation (OperationKind.Invalid, Type: ?, IsInvalid, IsImplicit) (Syntax: '.MissingField = {1}')
Children(1):
IInvalidOperation (OperationKind.Invalid, Type: ?, IsInvalid) (Syntax: 'MissingField')
Children(1):
IInstanceReferenceOperation (OperationKind.InstanceReference, Type: C, IsInvalid, IsImplicit) (Syntax: 'New C With ... ield = {1}}')
Right:
IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: ?, IsImplicit) (Syntax: '{1}')
Conversion: CommonConversion (Exists: False, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
Operand:
IArrayCreationOperation (OperationKind.ArrayCreation, Type: System.Int32()) (Syntax: '{1}')
Dimension Sizes(1):
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1, IsImplicit) (Syntax: '{1}')
Initializer:
IArrayInitializerOperation (1 elements) (OperationKind.ArrayInitializer, Type: null, IsImplicit) (Syntax: '{1}')
Element Values(1):
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1')
]]>.Value
Dim expectedDiagnostics = <![CDATA[
BC30456: 'MissingField' is not a member of 'C'.
Dim x1 = New C With {.MissingField = {1}}'BIND:"New C With {.MissingField = {1}}"
~~~~~~~~~~~~
]]>.Value
VerifyOperationTreeAndDiagnosticsForTest(Of ObjectCreationExpressionSyntax)(source, expectedOperationTree, expectedDiagnostics)
End Sub
End Class
End Namespace
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册