提交 2ea3675b 编写于 作者: G Gen Lu

Merge pull request #8002 from genlu/CaseOperation

Make `ICase` an `IOperation`
......@@ -64,6 +64,10 @@ public override BoundNode Visit(BoundNode node)
if (operation != null)
{
this.nodes.Add(operation);
// Following operations are not bound node, therefore have to be added explicitly:
// 1. IArgument
// 2. IMemberInitializer
// 3. ICase
switch (operation.Kind)
{
case OperationKind.InvocationExpression:
......@@ -74,6 +78,9 @@ public override BoundNode Visit(BoundNode node)
nodes.AddRange(objCreationExp.ConstructorArguments);
nodes.AddRange(objCreationExp.MemberInitializers);
break;
case OperationKind.SwitchStatement:
nodes.AddRange(((ISwitchStatement)operation).Cases);
break;
}
}
return base.Visit(node);
......
......@@ -146,20 +146,50 @@ partial class BoundForEachStatement : IForEachLoopStatement
partial class BoundSwitchStatement : ISwitchStatement
{
private static readonly ConditionalWeakTable<BoundSwitchStatement, object> s_switchSectionsMappings =
new ConditionalWeakTable<BoundSwitchStatement, object>();
IExpression ISwitchStatement.Value => this.BoundExpression;
ImmutableArray<ICase> ISwitchStatement.Cases => this.SwitchSections.As<ICase>();
ImmutableArray<ICase> ISwitchStatement.Cases
{
get
{
return (ImmutableArray<ICase>) s_switchSectionsMappings.GetValue(this,
switchStatement =>
{
return switchStatement.SwitchSections.SelectAsArray(switchSection => (ICase)new SwitchSection(switchSection));
});
}
}
protected override OperationKind StatementKind => OperationKind.SwitchStatement;
}
partial class BoundSwitchSection : ICase
{
ImmutableArray<ICaseClause> ICase.Clauses => this.BoundSwitchLabels.As<ICaseClause>();
private class SwitchSection : ICase
{
public SwitchSection(BoundSwitchSection boundNode)
{
this.Body = boundNode.Statements.As<IStatement>();
this.Clauses = boundNode.BoundSwitchLabels.As<ICaseClause>();
this.IsInvalid = boundNode.HasErrors;
this.Syntax = boundNode.Syntax;
}
public ImmutableArray<IStatement> Body { get; }
public ImmutableArray<ICaseClause> Clauses { get; }
public bool IsInvalid { get; }
ImmutableArray<IStatement> ICase.Body => this.Statements.As<IStatement>();
public OperationKind Kind => OperationKind.SwitchSection;
protected override OperationKind StatementKind => OperationKind.SwitchSection;
public SyntaxNode Syntax { get; }
}
}
partial class BoundSwitchSection
{
protected override OperationKind StatementKind => OperationKind.None;
}
partial class BoundSwitchLabel : ISingleValueCaseClause
......
......@@ -70,7 +70,7 @@ public interface ISwitchStatement : IStatement
/// <summary>
/// Represents a C# case or VB Case statement.
/// </summary>
public interface ICase : IStatement
public interface ICase : IOperation
{
/// <summary>
/// Clauses of the case. For C# there is one clause per case, but for VB there can be multiple.
......
......@@ -37,6 +37,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Dim operation = TryCast(node, IOperation)
If operation IsNot Nothing Then
Me.nodes.Add(operation)
' Following operations are not bound node, therefore have to be added explicitly:
' 1. IArgument
' 2. IMemberInitializer
' 3. ICase
' 4. ICaseClause with CaseKind == CaseKind.Default (i.e. Case Else)
' 5. IEventAssignmentExpression
Select Case operation.Kind
Case OperationKind.InvocationExpression
Me.nodes.AddRange(DirectCast(operation, IInvocationExpression).ArgumentsInSourceOrder)
......@@ -44,15 +50,19 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Dim objectCreationExpression = DirectCast(operation, IObjectCreationExpression)
Me.nodes.AddRange(objectCreationExpression.ConstructorArguments)
Me.nodes.AddRange(objectCreationExpression.MemberInitializers)
Case OperationKind.SwitchSection
' "Case Else" clause is not a bound node, so it needs to be added explicitly.
Dim caseClauses = DirectCast(operation, ICase).Clauses
If caseClauses.IsSingle Then
Dim caseClause = caseClauses(0)
If caseClause.CaseKind = CaseKind.Default Then
Me.nodes.Add(caseClause)
Case OperationKind.SwitchStatement
Dim switchStatement = DirectCast(operation, ISwitchStatement)
For Each caseBlock In switchStatement.Cases
Me.nodes.Add(caseBlock)
' "Case Else" clause needs to be added explicitly.
Dim caseClauses = caseBlock.Clauses
If caseClauses.IsSingle Then
Dim caseClause = caseClauses(0)
If caseClause.CaseKind = CaseKind.Default Then
Me.nodes.Add(caseClause)
End If
End If
End If
Next
Case OperationKind.ExpressionStatement
Dim expression = DirectCast(operation, IExpressionStatement).Expression
If expression.Kind = OperationKind.EventAssignmentExpression Then
......
......@@ -64,9 +64,16 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Partial Class BoundSelectStatement
Implements ISwitchStatement
Private Shared ReadOnly s_caseBlocksMappings As New System.Runtime.CompilerServices.ConditionalWeakTable(Of BoundSelectStatement, Object)
Private ReadOnly Property ICases As ImmutableArray(Of ICase) Implements ISwitchStatement.Cases
Get
Return Me.CaseBlocks.As(Of ICase)()
Dim cases = s_caseBlocksMappings.GetValue(Me, Function(boundSelect)
Return boundSelect.CaseBlocks.SelectAsArray(Function(boundCaseBlock)
Return DirectCast(New CaseBlock(boundCaseBlock), ICase)
End Function)
End Function)
Return DirectCast(cases, ImmutableArray(Of ICase))
End Get
End Property
......@@ -79,88 +86,118 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Protected Overrides Function StatementKind() As OperationKind
Return OperationKind.SwitchStatement
End Function
End Class
Partial Class BoundCaseBlock
Implements ICase
Private ReadOnly Property IBody As ImmutableArray(Of IStatement) Implements ICase.Body
Get
Return ImmutableArray.Create(Of IStatement)(Me.Body)
End Get
End Property
Private Class CaseBlock
Implements ICase
Private Shared ReadOnly CaseElseMappings As New System.Runtime.CompilerServices.ConditionalWeakTable(Of BoundCaseStatement, Object)
Private ReadOnly _clauses As ImmutableArray(Of ICaseClause)
Private ReadOnly _body As ImmutableArray(Of IStatement)
Private ReadOnly _isInvalid As Boolean
Private ReadOnly _syntax As SyntaxNode
Private ReadOnly Property IClauses As ImmutableArray(Of ICaseClause) Implements ICase.Clauses
Get
Public Sub New(boundCaseBlock As BoundCaseBlock)
' `CaseElseClauseSyntax` is bound to `BoundCaseStatement` with an empty list of case clauses,
' so we explicitly create an IOperation node for Case-Else clause to differentiate it from Case clause.
If Me.CaseStatement.CaseClauses.IsEmpty AndAlso Me.CaseStatement.Syntax.Kind() = SyntaxKind.CaseElseStatement Then
Dim caseElse = CaseElseMappings.GetValue(Me.CaseStatement, Function(caseStatement) ImmutableArray.Create(Of ICaseClause)(New CaseElse(caseStatement)))
Return DirectCast(caseElse, ImmutableArray(Of ICaseClause))
Dim caseStatement = boundCaseBlock.CaseStatement
If caseStatement.CaseClauses.IsEmpty AndAlso caseStatement.Syntax.Kind() = SyntaxKind.CaseElseStatement Then
_clauses = ImmutableArray.Create(Of ICaseClause)(New CaseElse(caseStatement))
Else
_clauses = caseStatement.CaseClauses.As(Of ICaseClause)()
End If
Return Me.CaseStatement.CaseClauses.As(Of ICaseClause)()
End Get
End Property
Protected Overrides Function StatementKind() As OperationKind
Return OperationKind.SwitchSection
End Function
Private Class CaseElse
Implements ISingleValueCaseClause
Private _boundCaseStatement As BoundCaseStatement
Public Sub New(boundCaseStatement As BoundCaseStatement)
_boundCaseStatement = boundCaseStatement
_body = ImmutableArray.Create(Of IStatement)(boundCaseBlock.Body)
_isInvalid = boundCaseBlock.HasErrors
_syntax = boundCaseBlock.Syntax
End Sub
Public ReadOnly Property Equality As BinaryOperationKind Implements ISingleValueCaseClause.Equality
Public ReadOnly Property Body As ImmutableArray(Of IStatement) Implements ICase.Body
Get
Return BinaryOperationKind.None
Return _body
End Get
End Property
Public ReadOnly Property Value As IExpression Implements ISingleValueCaseClause.Value
Public ReadOnly Property Clauses As ImmutableArray(Of ICaseClause) Implements ICase.Clauses
Get
Return Nothing
Return _clauses
End Get
End Property
Public ReadOnly Property IsInvalid As Boolean Implements IOperation.IsInvalid
Get
Return _boundCaseStatement.HasErrors
Return _isInvalid
End Get
End Property
Public ReadOnly Property Kind As OperationKind Implements IOperation.Kind
Get
Return OperationKind.SingleValueCaseClause
Return OperationKind.SwitchSection
End Get
End Property
Public ReadOnly Property Syntax As SyntaxNode Implements IOperation.Syntax
Get
Return _boundCaseStatement.Syntax
Return _syntax
End Get
End Property
Private ReadOnly Property ICaseClass As CaseKind Implements ICaseClause.CaseKind
Get
Return CaseKind.Default
End Get
End Property
Private Class CaseElse
Implements ISingleValueCaseClause
Private ReadOnly _boundCaseStatement As BoundCaseStatement
Public Sub New(boundCaseStatement As BoundCaseStatement)
_boundCaseStatement = boundCaseStatement
End Sub
Public ReadOnly Property Equality As BinaryOperationKind Implements ISingleValueCaseClause.Equality
Get
Return BinaryOperationKind.None
End Get
End Property
Public ReadOnly Property Value As IExpression Implements ISingleValueCaseClause.Value
Get
Return Nothing
End Get
End Property
Public ReadOnly Property IsInvalid As Boolean Implements IOperation.IsInvalid
Get
Return _boundCaseStatement.HasErrors
End Get
End Property
Public ReadOnly Property Kind As OperationKind Implements IOperation.Kind
Get
Return OperationKind.SingleValueCaseClause
End Get
End Property
Public ReadOnly Property Syntax As SyntaxNode Implements IOperation.Syntax
Get
Return _boundCaseStatement.Syntax
End Get
End Property
Private ReadOnly Property ICaseClass As CaseKind Implements ICaseClause.CaseKind
Get
Return CaseKind.Default
End Get
End Property
End Class
End Class
End Class
Partial Class BoundCaseBlock
Protected Overrides Function StatementKind() As OperationKind
Return OperationKind.None
End Function
End Class
Partial Class BoundCaseClause
Implements ICaseClause
Private ReadOnly Property IIsInvalid As Boolean Implements IOperation.IsInvalid
Get
Return Me.HasErrors
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册