-
Notifications
You must be signed in to change notification settings - Fork 4.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
IOperation API extensions to expose low-level operations (v2) #21810
Closed
edgardozoppi
wants to merge
11
commits into
dotnet:features/ioperation
from
edgardozoppi:features/low-level-ioperation-2
Closed
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
c43b7c0
Adding IConditionalGotoStatement and ISequenceExpression operations.
edgardozoppi ead54e3
Adding GetOperation extension method.
edgardozoppi dc35a74
Adding some unit tests for IConditionalGotoStatement operation.
edgardozoppi a25f71f
Fixing bug when the method symbol is null.
edgardozoppi 1ab6a05
Call Operation.SetParentOperation method in ConditionalGotoStatement …
edgardozoppi 1d55424
Some changes requested in the PR.
edgardozoppi 3bf6f22
Fixing renaming bug.
edgardozoppi f68be6b
Displaying and verifying compiler generated labels.
edgardozoppi 3fb1216
Adding more unit tests for IConditionalGotoStatement.
edgardozoppi 65e05b1
Adding some unit tests for ISequenceExpression.
edgardozoppi c5430aa
Adding some unit tests for GetLowLevelOperation method.
edgardozoppi File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -254,6 +254,21 @@ private IOperation CreateInternal(BoundNode boundNode) | |
return CreateBoundPatternSwitchLabelOperation((BoundPatternSwitchLabel)boundNode); | ||
case BoundKind.IsPatternExpression: | ||
return CreateBoundIsPatternExpressionOperation((BoundIsPatternExpression)boundNode); | ||
|
||
// To support BoundNodes after lowering phase. | ||
case BoundKind.SequencePoint: | ||
return CreateBoundSequencePointOperation((BoundSequencePoint)boundNode); | ||
case BoundKind.SequencePointWithSpan: | ||
return CreateBoundSequencePointWithSpanOperation((BoundSequencePointWithSpan)boundNode); | ||
case BoundKind.SequencePointExpression: | ||
return CreateBoundSequencePointExpressionOperation((BoundSequencePointExpression)boundNode); | ||
case BoundKind.StatementList: | ||
return CreateBoundStatementListOperation((BoundStatementList)boundNode); | ||
case BoundKind.ConditionalGoto: | ||
return CreateBoundConditionalGotoOperation((BoundConditionalGoto)boundNode); | ||
case BoundKind.Sequence: | ||
return CreateBoundSequenceOperation((BoundSequence)boundNode); | ||
|
||
default: | ||
var constantValue = ConvertToOptional((boundNode as BoundExpression)?.ConstantValue); | ||
bool isImplicit = boundNode.WasCompilerGenerated; | ||
|
@@ -426,7 +441,7 @@ private IEventAssignmentExpression CreateBoundEventAssignmentOperatorOperation(B | |
return new LazyEventAssignmentExpression(eventReference, handlerValue, adds, _semanticModel, syntax, type, constantValue, isImplicit); | ||
} | ||
|
||
private IParameterReferenceExpression CreateBoundParameterOperation(BoundParameter boundParameter) | ||
private IParameterReferenceExpression CreateBoundParameterOperation(BoundParameter boundParameter) | ||
{ | ||
IParameterSymbol parameter = boundParameter.ParameterSymbol; | ||
SyntaxNode syntax = boundParameter.Syntax; | ||
|
@@ -1064,7 +1079,7 @@ private IParameterInitializer CreateBoundParameterEqualsValueOperation(BoundPara | |
private IBlockStatement CreateBoundBlockOperation(BoundBlock boundBlock) | ||
{ | ||
Lazy<ImmutableArray<IOperation>> statements = | ||
new Lazy<ImmutableArray<IOperation>>(() => boundBlock.Statements.Select(s => Create(s)).Where(s => s.Kind != OperationKind.None).ToImmutableArray()); | ||
new Lazy<ImmutableArray<IOperation>>(() => boundBlock.Statements.Select(s => Create(s)).Where(s => s != null && s.Kind != OperationKind.None).ToImmutableArray()); | ||
|
||
ImmutableArray<ILocalSymbol> locals = boundBlock.Locals.As<ILocalSymbol>(); | ||
SyntaxNode syntax = boundBlock.Syntax; | ||
|
@@ -1506,5 +1521,59 @@ private IIsPatternExpression CreateBoundIsPatternExpressionOperation(BoundIsPatt | |
bool isImplicit = boundIsPatternExpression.WasCompilerGenerated; | ||
return new LazyIsPatternExpression(expression, pattern, _semanticModel, syntax, type, constantValue, isImplicit); | ||
} | ||
|
||
private IOperation CreateBoundSequencePointOperation(BoundSequencePoint boundSequencePoint) | ||
{ | ||
return Create(boundSequencePoint.StatementOpt); | ||
} | ||
|
||
private IOperation CreateBoundSequencePointWithSpanOperation(BoundSequencePointWithSpan boundSequencePointWithSpan) | ||
{ | ||
return Create(boundSequencePointWithSpan.StatementOpt); | ||
} | ||
|
||
private IOperation CreateBoundSequencePointExpressionOperation(BoundSequencePointExpression boundSequencePointExpression) | ||
{ | ||
return Create(boundSequencePointExpression.Expression); | ||
} | ||
|
||
private IBlockStatement CreateBoundStatementListOperation(BoundStatementList boundStatementList) | ||
{ | ||
Lazy<ImmutableArray<IOperation>> statements = | ||
new Lazy<ImmutableArray<IOperation>>(() => boundStatementList.Statements.Select(s => Create(s)).Where(s => s != null).ToImmutableArray()); | ||
|
||
ImmutableArray<ILocalSymbol> locals = ImmutableArray<ILocalSymbol>.Empty; | ||
SyntaxNode syntax = boundStatementList.Syntax; | ||
ITypeSymbol type = null; | ||
Optional<object> constantValue = default(Optional<object>); | ||
bool isImplicit = boundStatementList.WasCompilerGenerated; | ||
return new LazyBlockStatement(statements, locals, _semanticModel, syntax, type, constantValue, isImplicit); | ||
} | ||
|
||
private IConditionalGotoStatement CreateBoundConditionalGotoOperation(BoundConditionalGoto boundConditionalGoto) | ||
{ | ||
Lazy<IOperation> condition = new Lazy<IOperation>(() => Create(boundConditionalGoto.Condition)); | ||
ILabelSymbol target = boundConditionalGoto.Label; | ||
bool jumpIfTrue = boundConditionalGoto.JumpIfTrue; | ||
SyntaxNode syntax = boundConditionalGoto.Syntax; | ||
ITypeSymbol type = null; | ||
Optional<object> constantValue = default(Optional<object>); | ||
bool isImplicit = boundConditionalGoto.WasCompilerGenerated; | ||
return new LazyConditionalGotoStatement(condition, target, jumpIfTrue, _semanticModel, syntax, type, constantValue, isImplicit); | ||
} | ||
|
||
private ISequenceExpression CreateBoundSequenceOperation(BoundSequence boundSequence) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
It looks like there are no tests for this node. |
||
{ | ||
Lazy<ImmutableArray<IOperation>> expressions = | ||
new Lazy<ImmutableArray<IOperation>>(() => boundSequence.SideEffects.Select(s => Create(s)).Where(s => s != null).ToImmutableArray()); | ||
|
||
Lazy<IOperation> value = new Lazy<IOperation>(() => Create(boundSequence.Value)); | ||
ImmutableArray<ILocalSymbol> locals = boundSequence.Locals.As<ILocalSymbol>(); | ||
SyntaxNode syntax = boundSequence.Syntax; | ||
ITypeSymbol type = null; | ||
Optional<object> constantValue = default(Optional<object>); | ||
bool isImplicit = boundSequence.WasCompilerGenerated; | ||
return new LazySequenceExpression(expressions, value, locals, _semanticModel, syntax, type, constantValue, isImplicit); | ||
} | ||
} | ||
} |
168 changes: 168 additions & 0 deletions
168
src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_GetLowLevelOperation.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
// 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.Diagnostics; | ||
using Microsoft.CodeAnalysis.CSharp.Syntax; | ||
using Microsoft.CodeAnalysis.Semantics; | ||
using Microsoft.CodeAnalysis.Test.Utilities; | ||
using Roslyn.Test.Utilities; | ||
using Xunit; | ||
|
||
namespace Microsoft.CodeAnalysis.CSharp.UnitTests | ||
{ | ||
public partial class IOperationTests : SemanticModelTestBase | ||
{ | ||
[CompilerTrait(CompilerFeature.IOperation)] | ||
[Fact] | ||
public void GetLowLevelOperation_FromMethod() | ||
{ | ||
string source = @" | ||
class C | ||
{ | ||
/*<bind>*/ | ||
static int Method(int p) | ||
{ | ||
return p; | ||
} | ||
/*</bind>*/ | ||
} | ||
"; | ||
string expectedOperationTree = @" | ||
IBlockStatement (1 statements) (OperationKind.BlockStatement) (Syntax: '{ ... }') | ||
IReturnStatement (OperationKind.ReturnStatement) (Syntax: 'return p;') | ||
ReturnedValue: IParameterReferenceExpression: p (OperationKind.ParameterReferenceExpression, Type: System.Int32) (Syntax: 'p') | ||
"; | ||
var expectedDiagnostics = DiagnosticDescription.None; | ||
VerifyOperationTreeAndDiagnosticsForTest<BaseMethodDeclarationSyntax>(source, expectedOperationTree, expectedDiagnostics, useLoweredTree: true); | ||
} | ||
|
||
[CompilerTrait(CompilerFeature.IOperation)] | ||
[Fact] | ||
public void GetLowLevelOperation_FromConstructor() | ||
{ | ||
string source = @" | ||
class C | ||
{ | ||
private int _field = 0; | ||
|
||
/*<bind>*/ | ||
public C(int p) | ||
{ | ||
_field = p; | ||
} | ||
/*</bind>*/ | ||
} | ||
"; | ||
string expectedOperationTree = @" | ||
IBlockStatement (2 statements) (OperationKind.BlockStatement) (Syntax: 'public C(in ... }') | ||
IExpressionStatement (OperationKind.ExpressionStatement) (Syntax: 'public C(in ... }') | ||
Expression: IInvocationExpression ( System.Object..ctor()) (OperationKind.InvocationExpression, Type: System.Object) (Syntax: 'public C(in ... }') | ||
Instance Receiver: IInstanceReferenceExpression (InstanceReferenceKind.Implicit) (OperationKind.InstanceReferenceExpression, Type: C) (Syntax: 'public C(in ... }') | ||
Arguments(0) | ||
IBlockStatement (1 statements) (OperationKind.BlockStatement) (Syntax: '{ ... }') | ||
IExpressionStatement (OperationKind.ExpressionStatement) (Syntax: '_field = p;') | ||
Expression: ISimpleAssignmentExpression (OperationKind.SimpleAssignmentExpression, Type: System.Int32) (Syntax: '_field = p') | ||
Left: IFieldReferenceExpression: System.Int32 C._field (OperationKind.FieldReferenceExpression, Type: System.Int32) (Syntax: '_field') | ||
Instance Receiver: IInstanceReferenceExpression (InstanceReferenceKind.Implicit) (OperationKind.InstanceReferenceExpression, Type: C) (Syntax: '_field') | ||
Right: IParameterReferenceExpression: p (OperationKind.ParameterReferenceExpression, Type: System.Int32) (Syntax: 'p') | ||
"; | ||
var expectedDiagnostics = DiagnosticDescription.None; | ||
VerifyOperationTreeAndDiagnosticsForTest<BaseMethodDeclarationSyntax>(source, expectedOperationTree, expectedDiagnostics, useLoweredTree: true); | ||
} | ||
|
||
[CompilerTrait(CompilerFeature.IOperation)] | ||
[Fact] | ||
public void GetLowLevelOperation_FromFinalizer() | ||
{ | ||
string source = @" | ||
class C | ||
{ | ||
private int _field = 0; | ||
|
||
/*<bind>*/ | ||
~C() | ||
{ | ||
_field += 0; | ||
} | ||
/*</bind>*/ | ||
} | ||
"; | ||
string expectedOperationTree = @" | ||
IBlockStatement (1 statements) (OperationKind.BlockStatement) (Syntax: '{ ... }') | ||
ITryStatement (OperationKind.TryStatement) (Syntax: '{ ... }') | ||
Body: IBlockStatement (1 statements) (OperationKind.BlockStatement) (Syntax: '{ ... }') | ||
IExpressionStatement (OperationKind.ExpressionStatement) (Syntax: '_field += 0;') | ||
Expression: ISimpleAssignmentExpression (OperationKind.SimpleAssignmentExpression, Type: System.Int32) (Syntax: '_field += 0') | ||
Left: IFieldReferenceExpression: System.Int32 C._field (OperationKind.FieldReferenceExpression, Type: System.Int32) (Syntax: '_field') | ||
Instance Receiver: IInstanceReferenceExpression (InstanceReferenceKind.Implicit) (OperationKind.InstanceReferenceExpression, Type: C) (Syntax: '_field') | ||
Right: IFieldReferenceExpression: System.Int32 C._field (OperationKind.FieldReferenceExpression, Type: System.Int32) (Syntax: '_field') | ||
Instance Receiver: IInstanceReferenceExpression (InstanceReferenceKind.Implicit) (OperationKind.InstanceReferenceExpression, Type: C) (Syntax: '_field') | ||
Catch clauses(0) | ||
Finally: IBlockStatement (1 statements) (OperationKind.BlockStatement) (Syntax: '{ ... }') | ||
IExpressionStatement (OperationKind.ExpressionStatement) (Syntax: '{ ... }') | ||
Expression: IInvocationExpression ( void System.Object.Finalize()) (OperationKind.InvocationExpression, Type: System.Void) (Syntax: '{ ... }') | ||
Instance Receiver: IInstanceReferenceExpression (InstanceReferenceKind.BaseClass) (OperationKind.InstanceReferenceExpression, Type: C) (Syntax: '{ ... }') | ||
Arguments(0) | ||
"; | ||
var expectedDiagnostics = DiagnosticDescription.None; | ||
VerifyOperationTreeAndDiagnosticsForTest<BaseMethodDeclarationSyntax>(source, expectedOperationTree, expectedDiagnostics, useLoweredTree: true); | ||
} | ||
|
||
[CompilerTrait(CompilerFeature.IOperation)] | ||
[Fact] | ||
public void GetLowLevelOperation_FromPropertyAccessorGet() | ||
{ | ||
string source = @" | ||
class C | ||
{ | ||
private int _property = 0; | ||
|
||
int Property | ||
{ | ||
/*<bind>*/ | ||
get { return _property; } | ||
/*</bind>*/ | ||
} | ||
} | ||
"; | ||
string expectedOperationTree = @" | ||
IBlockStatement (1 statements) (OperationKind.BlockStatement) (Syntax: '{ return _property; }') | ||
IReturnStatement (OperationKind.ReturnStatement) (Syntax: 'return _property;') | ||
ReturnedValue: IFieldReferenceExpression: System.Int32 C._property (OperationKind.FieldReferenceExpression, Type: System.Int32) (Syntax: '_property') | ||
Instance Receiver: IInstanceReferenceExpression (InstanceReferenceKind.Implicit) (OperationKind.InstanceReferenceExpression, Type: C) (Syntax: '_property') | ||
"; | ||
var expectedDiagnostics = DiagnosticDescription.None; | ||
VerifyOperationTreeAndDiagnosticsForTest<AccessorDeclarationSyntax>(source, expectedOperationTree, expectedDiagnostics, useLoweredTree: true); | ||
} | ||
|
||
[CompilerTrait(CompilerFeature.IOperation)] | ||
[Fact] | ||
public void GetLowLevelOperation_FromPropertyAccessorSet() | ||
{ | ||
string source = @" | ||
class C | ||
{ | ||
private int _property = 0; | ||
|
||
int Property | ||
{ | ||
get { return _property; } | ||
/*<bind>*/ | ||
set { _property = value; } | ||
/*</bind>*/ | ||
} | ||
} | ||
"; | ||
string expectedOperationTree = @" | ||
IBlockStatement (1 statements) (OperationKind.BlockStatement) (Syntax: '{ _property = value; }') | ||
IExpressionStatement (OperationKind.ExpressionStatement) (Syntax: '_property = value;') | ||
Expression: ISimpleAssignmentExpression (OperationKind.SimpleAssignmentExpression, Type: System.Int32) (Syntax: '_property = value') | ||
Left: IFieldReferenceExpression: System.Int32 C._property (OperationKind.FieldReferenceExpression, Type: System.Int32) (Syntax: '_property') | ||
Instance Receiver: IInstanceReferenceExpression (InstanceReferenceKind.Implicit) (OperationKind.InstanceReferenceExpression, Type: C) (Syntax: '_property') | ||
Right: IParameterReferenceExpression: value (OperationKind.ParameterReferenceExpression, Type: System.Int32) (Syntax: 'value') | ||
|
||
"; | ||
var expectedDiagnostics = DiagnosticDescription.None; | ||
VerifyOperationTreeAndDiagnosticsForTest<AccessorDeclarationSyntax>(source, expectedOperationTree, expectedDiagnostics, useLoweredTree: true); | ||
} | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where are we returning
null
for a BoundNode? This seems like a bug.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The CSharpOperationFactory.Create(BoundNode boundNode) method returns null if the boundNode parameter is null. This could happen when there is an optional operation child, like Instance property of IMemberReferenceExpression.