提交 22a3dd62 编写于 作者: M Manish Vasani 提交者: GitHub

Merge pull request #18976 from mavasani/IOperationWithChildren

Ensure that we get a well formed child IOperation tree even for bound…
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.Semantics;
using Roslyn.Utilities;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.Collections;
namespace Microsoft.CodeAnalysis.CSharp
{
internal partial class BoundExpression : IOperation
internal partial class BoundExpression
{
ITypeSymbol IOperation.Type => this.Type;
protected override OperationKind OperationKind => this.ExpressionKind;
protected override ITypeSymbol OperationType => this.Type;
protected abstract OperationKind ExpressionKind { get; }
OperationKind IOperation.Kind => this.ExpressionKind;
public override abstract void Accept(OperationVisitor visitor);
bool IOperation.IsInvalid => this.HasErrors;
public override abstract TResult Accept<TArgument, TResult>(OperationVisitor<TArgument, TResult> visitor, TArgument argument);
Optional<object> IOperation.ConstantValue
protected override Optional<object> OperationConstantValue
{
get
{
......@@ -27,13 +29,6 @@ Optional<object> IOperation.ConstantValue
return value != null ? new Optional<object>(value.Value) : default(Optional<object>);
}
}
SyntaxNode IOperation.Syntax => this.Syntax;
protected abstract OperationKind ExpressionKind { get; }
public abstract void Accept(OperationVisitor visitor);
public abstract TResult Accept<TArgument, TResult>(OperationVisitor<TArgument, TResult> visitor, TArgument argument);
}
internal sealed partial class BoundDeconstructValuePlaceholder : BoundValuePlaceholderBase, IPlaceholderExpression
......@@ -498,6 +493,8 @@ internal partial class BoundTupleExpression
{
protected override OperationKind ExpressionKind => OperationKind.None;
protected override ImmutableArray<IOperation> Children => this.Arguments.As<IOperation>();
public override void Accept(OperationVisitor visitor)
{
visitor.VisitNoneOperation(this);
......@@ -556,6 +553,23 @@ ImmutableArray<ISymbolInitializer> IObjectCreationExpression.MemberInitializers
}
}
internal static ImmutableArray<BoundExpression> GetChildInitializers(BoundExpression objectOrCollectionInitializer)
{
var objectInitializerExpression = objectOrCollectionInitializer as BoundObjectInitializerExpression;
if (objectInitializerExpression != null)
{
return objectInitializerExpression.Initializers;
}
var collectionInitializerExpresion = objectOrCollectionInitializer as BoundCollectionInitializerExpression;
if (collectionInitializerExpresion != null)
{
return collectionInitializerExpresion.Initializers;
}
return ImmutableArray<BoundExpression>.Empty;
}
protected override OperationKind ExpressionKind => OperationKind.ObjectCreationExpression;
public override void Accept(OperationVisitor visitor)
......@@ -1001,6 +1015,8 @@ internal sealed partial class BoundDeconstructionAssignmentOperator : BoundExpre
// TODO: implement IOperation for pattern-matching constructs (https://github.com/dotnet/roslyn/issues/8699)
protected override OperationKind ExpressionKind => OperationKind.None;
protected override ImmutableArray<IOperation> Children => ImmutableArray.Create<IOperation>(this.Left, this.Right);
public override void Accept(OperationVisitor visitor)
{
// TODO: implement IOperation for pattern-matching constructs (https://github.com/dotnet/roslyn/issues/8699)
......@@ -1341,21 +1357,11 @@ internal partial class BoundEqualsValue : ISymbolInitializer
{
IOperation ISymbolInitializer.Value => this.Value;
SyntaxNode IOperation.Syntax => this.Syntax;
bool IOperation.IsInvalid => ((IOperation)this.Value).IsInvalid;
OperationKind IOperation.Kind => this.OperationKind;
protected abstract OperationKind OperationKind { get; }
ITypeSymbol IOperation.Type => null;
Optional<object> IOperation.ConstantValue => default(Optional<object>);
public override abstract void Accept(OperationVisitor visitor);
public abstract void Accept(OperationVisitor visitor);
public abstract TResult Accept<TArgument, TResult>(OperationVisitor<TArgument, TResult> visitor, TArgument argument);
public override abstract TResult Accept<TArgument, TResult>(OperationVisitor<TArgument, TResult> visitor, TArgument argument);
}
internal partial class BoundFieldEqualsValue : IFieldInitializer
......@@ -1413,6 +1419,8 @@ internal partial class BoundDynamicIndexerAccess
{
protected override OperationKind ExpressionKind => OperationKind.None;
protected override ImmutableArray<IOperation> Children => this.Arguments.Insert(0, this.ReceiverOpt).As<IOperation>();
public override void Accept(OperationVisitor visitor)
{
visitor.VisitNoneOperation(this);
......@@ -1428,6 +1436,8 @@ internal partial class BoundUserDefinedConditionalLogicalOperator
{
protected override OperationKind ExpressionKind => OperationKind.None;
protected override ImmutableArray<IOperation> Children => ImmutableArray.Create<IOperation>(this.Left, this.Right);
public override void Accept(OperationVisitor visitor)
{
visitor.VisitNoneOperation(this);
......@@ -1443,6 +1453,8 @@ internal partial class BoundAnonymousObjectCreationExpression
{
protected override OperationKind ExpressionKind => OperationKind.None;
protected override ImmutableArray<IOperation> Children => this.Arguments.As<IOperation>();
public override void Accept(OperationVisitor visitor)
{
visitor.VisitNoneOperation(this);
......@@ -1473,6 +1485,8 @@ internal partial class BoundAttribute
{
protected override OperationKind ExpressionKind => OperationKind.None;
protected override ImmutableArray<IOperation> Children => this.ConstructorArguments.AddRange(this.NamedArguments).As<IOperation>();
public override void Accept(OperationVisitor visitor)
{
visitor.VisitNoneOperation(this);
......@@ -1533,6 +1547,8 @@ internal partial class BoundQueryClause
{
protected override OperationKind ExpressionKind => OperationKind.None;
protected override ImmutableArray<IOperation> Children => ImmutableArray.Create<IOperation>(this.Value);
public override void Accept(OperationVisitor visitor)
{
visitor.VisitNoneOperation(this);
......@@ -1544,10 +1560,32 @@ public override void Accept(OperationVisitor visitor)
}
}
internal partial class BoundPattern
{
protected override abstract ImmutableArray<IOperation> Children { get; }
}
internal partial class BoundDeclarationPattern
{
protected override ImmutableArray<IOperation> Children => ImmutableArray.Create<IOperation>(this.VariableAccess);
}
internal partial class BoundConstantPattern
{
protected override ImmutableArray<IOperation> Children => ImmutableArray.Create<IOperation>(this.Value);
}
internal partial class BoundWildcardPattern
{
protected override ImmutableArray<IOperation> Children => ImmutableArray<IOperation>.Empty;
}
internal partial class BoundArgListOperator
{
protected override OperationKind ExpressionKind => OperationKind.None;
protected override ImmutableArray<IOperation> Children => Arguments.As<IOperation>();
public override void Accept(OperationVisitor visitor)
{
visitor.VisitNoneOperation(this);
......@@ -1578,6 +1616,8 @@ internal partial class BoundCollectionElementInitializer
{
protected override OperationKind ExpressionKind => OperationKind.None;
protected override ImmutableArray<IOperation> Children => this.Arguments.As<IOperation>();
public override void Accept(OperationVisitor visitor)
{
visitor.VisitNoneOperation(this);
......@@ -1593,6 +1633,8 @@ internal partial class BoundNameOfOperator
{
protected override OperationKind ExpressionKind => OperationKind.None;
protected override ImmutableArray<IOperation> Children => ImmutableArray.Create<IOperation>(this.Argument);
public override void Accept(OperationVisitor visitor)
{
visitor.VisitNoneOperation(this);
......@@ -1743,6 +1785,8 @@ internal partial class BoundPointerElementAccess
{
protected override OperationKind ExpressionKind => OperationKind.None;
protected override ImmutableArray<IOperation> Children => ImmutableArray.Create<IOperation>(this.Expression, this.Index);
public override void Accept(OperationVisitor visitor)
{
visitor.VisitNoneOperation(this);
......@@ -1758,6 +1802,8 @@ internal partial class BoundRefTypeOperator
{
protected override OperationKind ExpressionKind => OperationKind.None;
protected override ImmutableArray<IOperation> Children => ImmutableArray.Create<IOperation>(this.Operand);
public override void Accept(OperationVisitor visitor)
{
visitor.VisitNoneOperation(this);
......@@ -1773,6 +1819,8 @@ internal partial class BoundDynamicMemberAccess
{
protected override OperationKind ExpressionKind => OperationKind.None;
protected override ImmutableArray<IOperation> Children => ImmutableArray.Create<IOperation>(this.Receiver);
public override void Accept(OperationVisitor visitor)
{
visitor.VisitNoneOperation(this);
......@@ -1788,6 +1836,8 @@ internal partial class BoundMakeRefOperator
{
protected override OperationKind ExpressionKind => OperationKind.None;
protected override ImmutableArray<IOperation> Children => ImmutableArray.Create<IOperation>(this.Operand);
public override void Accept(OperationVisitor visitor)
{
visitor.VisitNoneOperation(this);
......@@ -1803,6 +1853,8 @@ internal partial class BoundRefValueOperator
{
protected override OperationKind ExpressionKind => OperationKind.None;
protected override ImmutableArray<IOperation> Children => ImmutableArray.Create<IOperation>(this.Operand);
public override void Accept(OperationVisitor visitor)
{
visitor.VisitNoneOperation(this);
......@@ -1818,6 +1870,8 @@ internal partial class BoundDynamicInvocation
{
protected override OperationKind ExpressionKind => OperationKind.None;
protected override ImmutableArray<IOperation> Children => this.Arguments.As<IOperation>().Insert(0, this.Expression);
public override void Accept(OperationVisitor visitor)
{
visitor.VisitNoneOperation(this);
......@@ -1953,6 +2007,8 @@ internal partial class BoundCollectionInitializerExpression
{
protected override OperationKind ExpressionKind => OperationKind.None;
protected override ImmutableArray<IOperation> Children => this.Initializers.As<IOperation>();
public override void Accept(OperationVisitor visitor)
{
visitor.VisitNoneOperation(this);
......@@ -2013,6 +2069,8 @@ internal partial class BoundDynamicCollectionElementInitializer
{
protected override OperationKind ExpressionKind => OperationKind.None;
protected override ImmutableArray<IOperation> Children => this.Arguments.As<IOperation>();
public override void Accept(OperationVisitor visitor)
{
visitor.VisitNoneOperation(this);
......@@ -2043,6 +2101,8 @@ internal partial class BoundFixedLocalCollectionInitializer
{
protected override OperationKind ExpressionKind => OperationKind.None;
protected override ImmutableArray<IOperation> Children => ImmutableArray.Create<IOperation>(this.Expression);
public override void Accept(OperationVisitor visitor)
{
visitor.VisitNoneOperation(this);
......@@ -2058,6 +2118,8 @@ internal partial class BoundStackAllocArrayCreation
{
protected override OperationKind ExpressionKind => OperationKind.None;
protected override ImmutableArray<IOperation> Children => ImmutableArray.Create<IOperation>(this.Count);
public override void Accept(OperationVisitor visitor)
{
visitor.VisitNoneOperation(this);
......@@ -2073,6 +2135,8 @@ internal partial class BoundDynamicObjectCreationExpression
{
protected override OperationKind ExpressionKind => OperationKind.None;
protected override ImmutableArray<IOperation> Children => this.Arguments.AddRange(BoundObjectCreationExpression.GetChildInitializers(this.InitializerExpressionOpt)).As<IOperation>();
public override void Accept(OperationVisitor visitor)
{
visitor.VisitNoneOperation(this);
......@@ -2103,6 +2167,8 @@ internal partial class BoundInterpolatedString
{
protected override OperationKind ExpressionKind => OperationKind.None;
protected override ImmutableArray<IOperation> Children => this.Parts.As<IOperation>();
public override void Accept(OperationVisitor visitor)
{
visitor.VisitNoneOperation(this);
......@@ -2118,6 +2184,8 @@ internal partial class BoundNoPiaObjectCreationExpression
{
protected override OperationKind ExpressionKind => OperationKind.None;
protected override ImmutableArray<IOperation> Children => BoundObjectCreationExpression.GetChildInitializers(this.InitializerExpressionOpt).As<IOperation>();
public override void Accept(OperationVisitor visitor)
{
visitor.VisitNoneOperation(this);
......@@ -2133,6 +2201,8 @@ internal partial class BoundObjectInitializerExpression
{
protected override OperationKind ExpressionKind => OperationKind.None;
protected override ImmutableArray<IOperation> Children => this.Initializers.As<IOperation>();
public override void Accept(OperationVisitor visitor)
{
visitor.VisitNoneOperation(this);
......@@ -2148,6 +2218,8 @@ internal partial class BoundStringInsert
{
protected override OperationKind ExpressionKind => OperationKind.None;
protected override ImmutableArray<IOperation> Children => ImmutableArray.Create<IOperation>(this.Value, this.Alignment, this.Format);
public override void Accept(OperationVisitor visitor)
{
visitor.VisitNoneOperation(this);
......@@ -2961,6 +3033,8 @@ public override void Accept(OperationVisitor visitor)
// TODO: implement IOperation for pattern-matching constructs (https://github.com/dotnet/roslyn/issues/8699)
protected override OperationKind ExpressionKind => OperationKind.None;
protected override ImmutableArray<IOperation> Children => ImmutableArray.Create<IOperation>(this.Expression);
}
internal partial class BoundDeclarationPattern
......
......@@ -9,23 +9,52 @@
namespace Microsoft.CodeAnalysis.CSharp
{
internal partial class BoundStatement : IOperation
internal partial class BoundNode : IOperation, IOperationWithChildren
{
OperationKind IOperation.Kind => this.StatementKind;
OperationKind IOperation.Kind => this.OperationKind;
bool IOperation.IsInvalid => this.HasErrors;
SyntaxNode IOperation.Syntax => this.Syntax;
ITypeSymbol IOperation.Type => null;
ITypeSymbol IOperation.Type => OperationType;
Optional<object> IOperation.ConstantValue => default(Optional<object>);
Optional<object> IOperation.ConstantValue => this.OperationConstantValue;
ImmutableArray<IOperation> IOperationWithChildren.Children => this.Children;
protected virtual OperationKind OperationKind => OperationKind.None;
protected virtual ITypeSymbol OperationType => null;
protected virtual Optional<object> OperationConstantValue => default(Optional<object>);
/// <summary>
/// Override this property to return the child operations if the IOperation API corresponding to this bound node is not yet designed or implemented.
/// </summary>
/// <remarks>Note that any of the child operation nodes may be null.</remarks>
protected virtual ImmutableArray<IOperation> Children => ImmutableArray<IOperation>.Empty;
public virtual void Accept(OperationVisitor visitor)
{
visitor.VisitNoneOperation(this);
}
public virtual TResult Accept<TArgument, TResult>(OperationVisitor<TArgument, TResult> visitor, TArgument argument)
{
return visitor.VisitNoneOperation(this, argument);
}
}
internal partial class BoundStatement
{
protected override OperationKind OperationKind => this.StatementKind;
protected abstract OperationKind StatementKind { get; }
public abstract void Accept(OperationVisitor visitor);
public override abstract void Accept(OperationVisitor visitor);
public abstract TResult Accept<TArgument, TResult>(OperationVisitor<TArgument, TResult> visitor, TArgument argument);
public override abstract TResult Accept<TArgument, TResult>(OperationVisitor<TArgument, TResult> visitor, TArgument argument);
}
internal partial class BoundBlock : IBlockStatement
......@@ -843,6 +872,21 @@ partial class BoundPatternSwitchStatement
// TODO: this may need its own OperationKind.
protected override OperationKind StatementKind => OperationKind.None;
protected override ImmutableArray<IOperation> Children
{
get
{
var builder = ImmutableArray.CreateBuilder<IOperation>(this.SwitchSections.Length + 1);
builder.Add(this.Expression);
foreach (var section in this.SwitchSections)
{
builder.Add(section);
}
return builder.ToImmutable();
}
}
public override void Accept(OperationVisitor visitor)
{
// TODO: implement IOperation for pattern-matching constructs (https://github.com/dotnet/roslyn/issues/8699)
......@@ -855,4 +899,14 @@ public override void Accept(OperationVisitor visitor)
return visitor.VisitNoneOperation(this, argument);
}
}
partial class BoundPatternSwitchSection
{
protected override ImmutableArray<IOperation> Children => this.SwitchLabels.As<IOperation>().AddRange(this.Statements);
}
partial class BoundPatternSwitchLabel
{
protected override ImmutableArray<IOperation> Children => ImmutableArray.Create<IOperation>(this.Pattern, this.Guard);
}
}
......@@ -62,6 +62,8 @@
<Compile Include="Diagnostics\GetDiagnosticsTests.cs" />
<Compile Include="IOperation\IOperationTests_IArgument.cs" />
<Compile Include="IOperation\IOperationTests_IIfStatement.cs" />
<Compile Include="IOperation\IOperationTests_IFieldReferenceExpression.cs" />
<Compile Include="IOperation\IOperationTests_IParameterReferenceExpression.cs" />
<Compile Include="IOperation\IOperationTests_ISymbolInitializer.cs" />
<Compile Include="IOperation\IOperationTests_InvalidExpression.cs" />
<Compile Include="IOperation\IOperationTests_InvalidStatement.cs" />
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
public partial class IOperationTests : SemanticModelTestBase
{
[Fact, WorkItem(8884, "https://github.com/dotnet/roslyn/issues/8884")]
public void FieldReference_Attribute()
{
string source = @"
using System.Diagnostics;
class C
{
private const string field = nameof(field);
[/*<bind>*/Conditional(field)/*</bind>*/]
void M()
{
}
}
";
string expectedOperationTree = @"
IOperation: (OperationKind.None) (Syntax: 'Conditional(field)')
Children(1): IFieldReferenceExpression: System.String C.field (Static) (OperationKind.FieldReferenceExpression, Type: System.String, Constant: ""field"") (Syntax: 'field')
";
var expectedDiagnostics = DiagnosticDescription.None;
VerifyOperationTreeAndDiagnosticsForTest<AttributeSyntax>(source, expectedOperationTree, expectedDiagnostics);
}
}
}
\ No newline at end of file
......@@ -331,28 +331,40 @@ private void M()
{
var s = """";
/*<bind>*/if (int.TryParse(s, out var i))
System.Console.WriteLine($""i ={ i}, s ={ s}"");
System.Console.WriteLine($""i ={i}, s ={s}"");
else
System.Console.WriteLine($""i ={ i}, s ={ s}"");/*</bind>*/
System.Console.WriteLine($""i ={ i}, s ={s}"");/*</bind>*/
}
}
";
string expectedOperationTree = @"
IIfStatement (OperationKind.IfStatement) (Syntax: 'if (int.Try ... s ={ s}"");')
IIfStatement (OperationKind.IfStatement) (Syntax: 'if (int.Try ... , s ={s}"");')
Condition: IInvocationExpression (static System.Boolean System.Int32.TryParse(System.String s, out System.Int32 result)) (OperationKind.InvocationExpression, Type: System.Boolean) (Syntax: 'int.TryPars ... out var i)')
Arguments(2): IArgument (ArgumentKind.Explicit, Matching Parameter: s) (OperationKind.Argument) (Syntax: 's')
ILocalReferenceExpression: s (OperationKind.LocalReferenceExpression, Type: System.String) (Syntax: 's')
IArgument (ArgumentKind.Explicit, Matching Parameter: result) (OperationKind.Argument) (Syntax: 'var i')
ILocalReferenceExpression: i (OperationKind.LocalReferenceExpression, Type: System.Int32) (Syntax: 'var i')
IfTrue: IExpressionStatement (OperationKind.ExpressionStatement) (Syntax: 'System.Cons ... s ={ s}"");')
IInvocationExpression (static void System.Console.WriteLine(System.String value)) (OperationKind.InvocationExpression, Type: System.Void) (Syntax: 'System.Cons ... , s ={ s}"")')
Arguments(1): IArgument (ArgumentKind.Explicit, Matching Parameter: value) (OperationKind.Argument) (Syntax: '$""i ={ i}, s ={ s}""')
IOperation: (OperationKind.None) (Syntax: '$""i ={ i}, s ={ s}""')
IfFalse: IExpressionStatement (OperationKind.ExpressionStatement) (Syntax: 'System.Cons ... s ={ s}"");')
IInvocationExpression (static void System.Console.WriteLine(System.String value)) (OperationKind.InvocationExpression, Type: System.Void) (Syntax: 'System.Cons ... , s ={ s}"")')
Arguments(1): IArgument (ArgumentKind.Explicit, Matching Parameter: value) (OperationKind.Argument) (Syntax: '$""i ={ i}, s ={ s}""')
IOperation: (OperationKind.None) (Syntax: '$""i ={ i}, s ={ s}""')
IfTrue: IExpressionStatement (OperationKind.ExpressionStatement) (Syntax: 'System.Cons ... , s ={s}"");')
IInvocationExpression (static void System.Console.WriteLine(System.String value)) (OperationKind.InvocationExpression, Type: System.Void) (Syntax: 'System.Cons ... }, s ={s}"")')
Arguments(1): IArgument (ArgumentKind.Explicit, Matching Parameter: value) (OperationKind.Argument) (Syntax: '$""i ={i}, s ={s}""')
IOperation: (OperationKind.None) (Syntax: '$""i ={i}, s ={s}""')
Children(4): ILiteralExpression (Text: i =) (OperationKind.LiteralExpression, Type: System.String, Constant: ""i ="") (Syntax: 'i =')
IOperation: (OperationKind.None) (Syntax: '{i}')
Children(1): ILocalReferenceExpression: i (OperationKind.LocalReferenceExpression, Type: System.Int32) (Syntax: 'i')
ILiteralExpression (Text: , s =) (OperationKind.LiteralExpression, Type: System.String, Constant: "", s ="") (Syntax: ', s =')
IOperation: (OperationKind.None) (Syntax: '{s}')
Children(1): ILocalReferenceExpression: s (OperationKind.LocalReferenceExpression, Type: System.String) (Syntax: 's')
IfFalse: IExpressionStatement (OperationKind.ExpressionStatement) (Syntax: 'System.Cons ... , s ={s}"");')
IInvocationExpression (static void System.Console.WriteLine(System.String value)) (OperationKind.InvocationExpression, Type: System.Void) (Syntax: 'System.Cons ... }, s ={s}"")')
Arguments(1): IArgument (ArgumentKind.Explicit, Matching Parameter: value) (OperationKind.Argument) (Syntax: '$""i ={ i}, s ={s}""')
IOperation: (OperationKind.None) (Syntax: '$""i ={ i}, s ={s}""')
Children(4): ILiteralExpression (Text: i =) (OperationKind.LiteralExpression, Type: System.String, Constant: ""i ="") (Syntax: 'i =')
IOperation: (OperationKind.None) (Syntax: '{ i}')
Children(1): ILocalReferenceExpression: i (OperationKind.LocalReferenceExpression, Type: System.Int32) (Syntax: 'i')
ILiteralExpression (Text: , s =) (OperationKind.LiteralExpression, Type: System.String, Constant: "", s ="") (Syntax: ', s =')
IOperation: (OperationKind.None) (Syntax: '{s}')
Children(1): ILocalReferenceExpression: s (OperationKind.LocalReferenceExpression, Type: System.String) (Syntax: 's')
";
var expectedDiagnostics = DiagnosticDescription.None;
......@@ -796,6 +808,8 @@ class C
IBinaryOperatorExpression (BinaryOperationKind.DynamicAnd) (OperationKind.BinaryOperatorExpression, Type: dynamic) (Syntax: 'd.GetType() ... ).Equals(x)')
Left: IBinaryOperatorExpression (BinaryOperationKind.Invalid) (OperationKind.BinaryOperatorExpression, Type: dynamic) (Syntax: 'd.GetType() == t')
Left: IOperation: (OperationKind.None) (Syntax: 'd.GetType()')
Children(1): IOperation: (OperationKind.None) (Syntax: 'd.GetType')
Children(1): IParameterReferenceExpression: d (OperationKind.ParameterReferenceExpression, Type: dynamic) (Syntax: 'd')
Right: IParameterReferenceExpression: t (OperationKind.ParameterReferenceExpression, Type: System.Type) (Syntax: 't')
Right: IInvocationExpression (virtual System.Boolean System.ValueType.Equals(System.Object obj)) (OperationKind.InvocationExpression, Type: System.Boolean) (Syntax: '((T)d).Equals(x)')
Instance Receiver: IConversionExpression (ConversionKind.CSharp, Explicit) (OperationKind.ConversionExpression, Type: T) (Syntax: '(T)d')
......
......@@ -97,6 +97,7 @@
<Compile Include="Operations\InvocationExpression_IHasArgumentsExpression.cs" />
<Compile Include="Operations\IObjectCreationExpression.cs" />
<Compile Include="Operations\IOmittedArgumentExpression.cs" />
<Compile Include="Operations\IOperationWithChildren.cs" />
<Compile Include="Operations\ObjectCreationExpression_IHasArgumentsExpression.cs" />
<Compile Include="Operations\Operation.cs" />
<Compile Include="Operations\IOperationKind.cs" />
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Immutable;
using System.Runtime.CompilerServices;
namespace Microsoft.CodeAnalysis
{
/// <summary>
/// Root type for <see cref="IOperation"/> nodes that are still not fully designed and hence need a backdoor to stitch the child IOperation nodes to the entire IOperation tree.
/// </summary>
/// <remarks>
/// NOTE: This type is a temporary workaround and should be deleted once we ship IOperation APIs.
/// </remarks>
[InternalImplementationOnly]
internal interface IOperationWithChildren: IOperation
{
/// <summary>
/// An array of child operations for this operation.
/// </summary>
/// <remarks>Note that any of the child operation nodes may be null.</remarks>
ImmutableArray<IOperation> Children { get; }
}
}
......@@ -40,6 +40,14 @@ public override void Visit(IOperation operation)
}
}
internal override void VisitNoneOperation(IOperation operation)
{
if (operation is IOperationWithChildren operationWithChildren)
{
VisitArray(operationWithChildren.Children);
}
}
public override void VisitBlockStatement(IBlockStatement operation)
{
VisitArray(operation.Statements);
......
......@@ -239,7 +239,7 @@ protected string GetOperationTreeForTest<TSyntaxNode>(CSharpCompilation compilat
protected string GetOperationTreeForTest<TSyntaxNode>(string testSrc, string expectedOperationTree, CSharpCompilationOptions compilationOptions = null, CSharpParseOptions parseOptions = null)
where TSyntaxNode : SyntaxNode
{
var compilation = CreateStandardCompilation(testSrc, new[] { SystemCoreRef }, options: compilationOptions ?? TestOptions.ReleaseDll, parseOptions: parseOptions);
var compilation = CreateStandardCompilation(testSrc, new[] { SystemCoreRef, ValueTupleRef, SystemRuntimeFacadeRef }, options: compilationOptions ?? TestOptions.ReleaseDll, parseOptions: parseOptions);
return GetOperationTreeForTest<TSyntaxNode>(compilation);
}
......@@ -268,7 +268,7 @@ protected void VerifyOperationTreeAndDiagnosticsForTest<TSyntaxNode>(CSharpCompi
protected void VerifyOperationTreeAndDiagnosticsForTest<TSyntaxNode>(string testSrc, string expectedOperationTree, DiagnosticDescription[] expectedDiagnostics, CSharpCompilationOptions compilationOptions = null, CSharpParseOptions parseOptions = null)
where TSyntaxNode : SyntaxNode
{
var compilation = CreateStandardCompilation(testSrc, new[] { SystemCoreRef }, options: compilationOptions ?? TestOptions.ReleaseDll, parseOptions: parseOptions);
var compilation = CreateStandardCompilation(testSrc, new[] { SystemCoreRef, ValueTupleRef, SystemRuntimeFacadeRef }, options: compilationOptions ?? TestOptions.ReleaseDll, parseOptions: parseOptions);
VerifyOperationTreeAndDiagnosticsForTest<TSyntaxNode>(compilation, expectedOperationTree, expectedDiagnostics);
}
}
......
......@@ -169,7 +169,7 @@ Public MustInherit Class SemanticModelTestBase : Inherits BasicTestBase
Friend Function GetOperationTreeForTest(Of TSyntaxNode As SyntaxNode)(testSrc As String, Optional compilationOptions As VisualBasicCompilationOptions = Nothing, Optional parseOptions As VisualBasicParseOptions = Nothing, Optional which As Integer = 0) As String
Dim fileName = "a.vb"
Dim syntaxTree = Parse(testSrc, fileName, parseOptions)
Dim compilation = CreateCompilationWithMscorlib45AndVBRuntime({syntaxTree}, references:=DefaultVbReferences, options:=If(compilationOptions, TestOptions.ReleaseDll))
Dim compilation = CreateCompilationWithMscorlib45AndVBRuntime({syntaxTree}, references:=DefaultVbReferences.Append({ValueTupleRef, SystemRuntimeFacadeRef}), options:=If(compilationOptions, TestOptions.ReleaseDll))
Return GetOperationTreeForTest(Of TSyntaxNode)(compilation, fileName, which)
End Function
......@@ -196,7 +196,7 @@ Public MustInherit Class SemanticModelTestBase : Inherits BasicTestBase
Friend Sub VerifyOperationTreeAndDiagnosticsForTest(Of TSyntaxNode As SyntaxNode)(testSrc As String, expectedOperationTree As String, expectedDiagnostics As String, Optional compilationOptions As VisualBasicCompilationOptions = Nothing, Optional parseOptions As VisualBasicParseOptions = Nothing, Optional which As Integer = 0)
Dim fileName = "a.vb"
Dim syntaxTree = Parse(testSrc, fileName, parseOptions)
Dim compilation = CreateCompilationWithMscorlib45AndVBRuntime({syntaxTree}, references:=DefaultVbReferences, options:=If(compilationOptions, TestOptions.ReleaseDll))
Dim compilation = CreateCompilationWithMscorlib45AndVBRuntime({syntaxTree}, references:=DefaultVbReferences.Append({ValueTupleRef, SystemRuntimeFacadeRef}), options:=If(compilationOptions, TestOptions.ReleaseDll))
VerifyOperationTreeAndDiagnosticsForTest(Of TSyntaxNode)(compilation, fileName, expectedOperationTree, expectedDiagnostics, which)
End Sub
......
......@@ -93,7 +93,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
End Get
End Property
Public Overridable Function Accept(visitor As BoundTreeVisitor) As BoundNode
Public Overridable Overloads Function Accept(visitor As BoundTreeVisitor) As BoundNode
Throw ExceptionUtilities.Unreachable
End Function
......
......@@ -6,12 +6,12 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Symbols
Namespace Microsoft.CodeAnalysis.VisualBasic
Partial Friend Class BoundStatement
Implements IOperation
Partial Friend Class BoundNode
Implements IOperation, IOperationWithChildren
Private ReadOnly Property IOperation_Kind As OperationKind Implements IOperation.Kind
Get
Return Me.StatementKind()
Return Me.OperationKind
End Get
End Property
......@@ -29,21 +29,74 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Private ReadOnly Property IOperation_Type As ITypeSymbol Implements IOperation.Type
Get
Return Nothing
Return Me.OperationType
End Get
End Property
Private ReadOnly Property IOperation_ConstantValue As [Optional](Of Object) Implements IOperation.ConstantValue
Get
Return Me.OperationConstantValue
End Get
End Property
Public ReadOnly Property IOperationWithChildren_Children As ImmutableArray(Of IOperation) Implements IOperationWithChildren.Children
Get
Return Me.Children
End Get
End Property
Protected Overridable ReadOnly Property OperationKind As OperationKind
Get
Return OperationKind.None
End Get
End Property
Protected Overridable ReadOnly Property OperationType As ITypeSymbol
Get
Return Nothing
End Get
End Property
Protected Overridable ReadOnly Property OperationConstantValue As [Optional](Of Object)
Get
Return New [Optional](Of Object)()
End Get
End Property
''' <summary>
''' Override this property to return the child operations if the IOperation API corresponding to this bound node is not yet designed or implemented.
''' </summary>
''' <remarks>
''' Note that any of the child operation nodes may be null.
''' </remarks>
Protected Overridable ReadOnly Property Children As ImmutableArray(Of IOperation)
Get
Return ImmutableArray(Of IOperation).Empty
End Get
End Property
Public Overridable Overloads Sub Accept(visitor As OperationVisitor) Implements IOperation.Accept
visitor.VisitNoneOperation(Me)
End Sub
Public Overridable Overloads Function Accept(Of TArgument, TResult)(visitor As OperationVisitor(Of TArgument, TResult), argument As TArgument) As TResult Implements IOperation.Accept
visitor.VisitNoneOperation(Me, argument)
End Function
End Class
Partial Friend Class BoundStatement
Protected Overrides ReadOnly Property OperationKind As OperationKind
Get
Return Me.StatementKind
End Get
End Property
Protected MustOverride Function StatementKind() As OperationKind
Public MustOverride Overloads Sub Accept(visitor As OperationVisitor) Implements IOperation.Accept
Public MustOverride Overloads Overrides Sub Accept(visitor As OperationVisitor)
Public MustOverride Overloads Function Accept(Of TArgument, TResult)(visitor As OperationVisitor(Of TArgument, TResult), argument As TArgument) As TResult Implements IOperation.Accept
Public MustOverride Overloads Overrides Function Accept(Of TArgument, TResult)(visitor As OperationVisitor(Of TArgument, TResult), argument As TArgument) As TResult
End Class
Partial Friend Class BoundIfStatement
......@@ -261,6 +314,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return OperationKind.None
End Function
Protected Overrides ReadOnly Property Children As ImmutableArray(Of IOperation)
Get
Return ImmutableArray.Create(Of IOperation)(Me.CaseStatement, Me.Body)
End Get
End Property
Public Overrides Sub Accept(visitor As OperationVisitor)
visitor.VisitNoneOperation(Me)
End Sub
......@@ -486,6 +545,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return OperationKind.None
End Function
Protected Overrides ReadOnly Property Children As ImmutableArray(Of IOperation)
Get
Return Me.CaseClauses.As(Of IOperation).Add(Me.ConditionOpt)
End Get
End Property
Public Overrides Sub Accept(visitor As OperationVisitor)
visitor.VisitNoneOperation(Me)
End Sub
......@@ -943,7 +1008,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Partial Friend Class BoundBadStatement
Implements IInvalidStatement
Public ReadOnly Property Children As ImmutableArray(Of IOperation) Implements IInvalidStatement.Children
Protected Overrides ReadOnly Property Children As ImmutableArray(Of IOperation) Implements IInvalidStatement.Children
Get
Dim builder As ArrayBuilder(Of IOperation) = ArrayBuilder(Of IOperation).GetInstance(Me.ChildBoundNodes.Length)
For Each childNode In Me.ChildBoundNodes
......@@ -1630,6 +1695,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return OperationKind.None
End Function
Protected Overrides ReadOnly Property Children As ImmutableArray(Of IOperation)
Get
Return Me.Clauses.As(Of IOperation)
End Get
End Property
Public Overrides Sub Accept(visitor As OperationVisitor)
visitor.VisitNoneOperation(Me)
End Sub
......@@ -1644,6 +1715,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return OperationKind.None
End Function
Protected Overrides ReadOnly Property Children As ImmutableArray(Of IOperation)
Get
Return Me.Indices.As(Of IOperation).Insert(0, Me.Operand)
End Get
End Property
Public Overrides Sub Accept(visitor As OperationVisitor)
visitor.VisitNoneOperation(Me)
End Sub
......@@ -1658,6 +1735,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return OperationKind.None
End Function
Protected Overrides ReadOnly Property Children As ImmutableArray(Of IOperation)
Get
Return Me.Clauses.As(Of IOperation)
End Get
End Property
Public Overrides Sub Accept(visitor As OperationVisitor)
visitor.VisitNoneOperation(Me)
End Sub
......@@ -1764,6 +1847,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return OperationKind.None
End Function
Protected Overrides ReadOnly Property Children As ImmutableArray(Of IOperation)
Get
Return ImmutableArray.Create(Of IOperation)(Me.LabelExpressionOpt)
End Get
End Property
Public Overrides Sub Accept(visitor As OperationVisitor)
visitor.VisitNoneOperation(Me)
End Sub
......@@ -1778,6 +1867,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return OperationKind.None
End Function
Protected Overrides ReadOnly Property Children As ImmutableArray(Of IOperation)
Get
Return ImmutableArray.Create(Of IOperation)(Me.LabelExpressionOpt)
End Get
End Property
Public Overrides Sub Accept(visitor As OperationVisitor)
visitor.VisitNoneOperation(Me)
End Sub
......@@ -1792,6 +1887,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return OperationKind.None
End Function
Protected Overrides ReadOnly Property Children As ImmutableArray(Of IOperation)
Get
Return ImmutableArray.Create(Of IOperation)(Me.Body)
End Get
End Property
Public Overrides Sub Accept(visitor As OperationVisitor)
visitor.VisitNoneOperation(Me)
End Sub
......
......@@ -107,6 +107,8 @@
<Compile Include="Diagnostics\DiagnosticTests.vb" />
<Compile Include="Diagnostics\GetDiagnosticsTests.vb" />
<Compile Include="IOperation\IOperationTests_IArgument.vb" />
<Compile Include="IOperation\IOperationTests_IFieldReferenceExpression.vb" />
<Compile Include="IOperation\IOperationTests_IParameterReferenceExpression.vb" />
<Compile Include="IOperation\IOperationTests_InvalidStatement.vb" />
<Compile Include="IOperation\IOperationTests_InvalidExpression.vb" />
<Compile Include="IOperation\IOperationTests_IBlockStatement_MethodBlocks.vb" />
......
' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
Imports Microsoft.CodeAnalysis.Semantics
Imports Microsoft.CodeAnalysis.Test.Utilities
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Imports Roslyn.Test.Utilities
Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Semantics
Partial Public Class IOperationTests
Inherits SemanticModelTestBase
<Fact, WorkItem(8884, "https://github.com/dotnet/roslyn/issues/8884")>
Public Sub FieldReference_Attribute()
Dim source = <![CDATA[
Imports System.Diagnostics
Class C
Private Const field As String = NameOf(field)
<Conditional(field)>'BIND:"Conditional(field)"
Private Sub M()
End Sub
End Class]]>.Value
Dim expectedOperationTree = <![CDATA[
IOperation: (OperationKind.None) (Syntax: 'Conditional(field)')
Children(1): IFieldReferenceExpression: C.field As System.String (Static) (OperationKind.FieldReferenceExpression, Type: System.String, Constant: "field") (Syntax: 'field')
]]>.Value
Dim expectedDiagnostics = String.Empty
VerifyOperationTreeAndDiagnosticsForTest(Of AttributeSyntax)(source, expectedOperationTree, expectedDiagnostics)
End Sub
End Class
End Namespace
......@@ -11,6 +11,7 @@
using Microsoft.CodeAnalysis.Test.Extensions;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Test.Utilities;
using Roslyn.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.Test.Utilities
......@@ -255,6 +256,15 @@ internal override void VisitNoneOperation(IOperation operation)
{
LogString("IOperation: ");
LogCommonPropertiesAndNewLine(operation);
if (operation is IOperationWithChildren operationWithChildren)
{
var children = operationWithChildren.Children.WhereNotNull().ToImmutableArray();
if (children.Length > 0)
{
VisitArray(children, "Children", logElementCount: true);
}
}
}
public override void VisitBlockStatement(IBlockStatement operation)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册