-
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
Add IOperation support for anonymous object creation expressions. #20364
Changes from all commits
bf65c3e
f215734
ce4d0eb
a8a169a
8c1e32f
9638d11
3d990dc
0ad037b
181934d
9bd67cc
f49daed
a18024a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,6 +7,7 @@ | |
using System.Linq; | ||
using Microsoft.CodeAnalysis.CSharp; | ||
using Microsoft.CodeAnalysis.CSharp.Symbols; | ||
using Roslyn.Utilities; | ||
|
||
namespace Microsoft.CodeAnalysis.Semantics | ||
{ | ||
|
@@ -179,12 +180,16 @@ private IOperation CreateInternal(BoundNode boundNode) | |
return CreateBoundInterpolationOperation((BoundStringInsert)boundNode); | ||
case BoundKind.LocalFunctionStatement: | ||
return CreateBoundLocalFunctionStatementOperation((BoundLocalFunctionStatement)boundNode); | ||
case BoundKind.AnonymousObjectCreationExpression: | ||
return CreateBoundAnonymousObjectCreationExpressionOperation((BoundAnonymousObjectCreationExpression)boundNode); | ||
case BoundKind.AnonymousPropertyDeclaration: | ||
return CreateBoundAnonymousPropertyDeclarationOperation((BoundAnonymousPropertyDeclaration)boundNode); | ||
case BoundKind.ConstantPattern: | ||
return CreateBoundConstantPatternOperation((BoundConstantPattern)boundNode); | ||
case BoundKind.DeclarationPattern: | ||
return CreateBoundDeclarationPatternOperation((BoundDeclarationPattern)boundNode); | ||
case BoundKind.WildcardPattern: | ||
return null; | ||
throw ExceptionUtilities.Unreachable; | ||
case BoundKind.PatternSwitchStatement: | ||
return CreateBoundPatternSwitchStatementOperation((BoundPatternSwitchStatement)boundNode); | ||
case BoundKind.PatternSwitchLabel: | ||
|
@@ -352,6 +357,29 @@ private ILiteralExpression CreateBoundLiteralOperation(BoundLiteral boundLiteral | |
return new LiteralExpression(text, isInvalid, syntax, type, constantValue); | ||
} | ||
|
||
private IAnonymousObjectCreationExpression CreateBoundAnonymousObjectCreationExpressionOperation(BoundAnonymousObjectCreationExpression boundAnonymousObjectCreationExpression) | ||
{ | ||
Lazy<ImmutableArray<IOperation>> memberInitializers = new Lazy<ImmutableArray<IOperation>>(() => GetAnonymousObjectCreationInitializers(boundAnonymousObjectCreationExpression)); | ||
bool isInvalid = boundAnonymousObjectCreationExpression.HasErrors; | ||
SyntaxNode syntax = boundAnonymousObjectCreationExpression.Syntax; | ||
ITypeSymbol type = boundAnonymousObjectCreationExpression.Type; | ||
Optional<object> constantValue = ConvertToOptional(boundAnonymousObjectCreationExpression.ConstantValue); | ||
return new LazyAnonymousObjectCreationExpression(memberInitializers, isInvalid, syntax, type, constantValue); | ||
} | ||
|
||
private IPropertyReferenceExpression CreateBoundAnonymousPropertyDeclarationOperation(BoundAnonymousPropertyDeclaration boundAnonymousPropertyDeclaration) | ||
{ | ||
PropertySymbol property = boundAnonymousPropertyDeclaration.Property; | ||
Lazy<IOperation> instance = new Lazy<IOperation>(() => null); | ||
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. Why have a lazy that always returns 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. I have followed the pattern used in this file. @heejaechang Will having a null child node be handled by the operation factory? I have added a comment to #20204 to track this feedback for the entire file. #Resolved |
||
ISymbol member = boundAnonymousPropertyDeclaration.Property; | ||
Lazy<ImmutableArray<IArgument>> argumentsInEvaluationOrder = new Lazy<ImmutableArray<IArgument>>(() => ImmutableArray<IArgument>.Empty); | ||
bool isInvalid = boundAnonymousPropertyDeclaration.HasErrors; | ||
SyntaxNode syntax = boundAnonymousPropertyDeclaration.Syntax; | ||
ITypeSymbol type = boundAnonymousPropertyDeclaration.Type; | ||
Optional<object> constantValue = ConvertToOptional(boundAnonymousPropertyDeclaration.ConstantValue); | ||
return new LazyPropertyReferenceExpression(property, instance, member, argumentsInEvaluationOrder, isInvalid, syntax, type, constantValue); | ||
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. Is this change (adding 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. Currently the dumper doesn't print out child operation arrays which are empty, hence we cannot cover it in tests. @jinujoseph is working on updating the operation tree dumper to print a header with 0 element count for this case, at which point the unit tests will cover it. |
||
} | ||
|
||
private IObjectCreationExpression CreateBoundObjectCreationExpressionOperation(BoundObjectCreationExpression boundObjectCreationExpression) | ||
{ | ||
IMethodSymbol constructor = boundObjectCreationExpression.Constructor; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,8 @@ | ||
// 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.Linq; | ||
using Microsoft.CodeAnalysis.CSharp; | ||
using Microsoft.CodeAnalysis.CSharp.Symbols; | ||
|
@@ -92,6 +94,33 @@ private ImmutableArray<IArgument> DeriveArguments( | |
invokedAsExtensionMethod: invokedAsExtensionMethod); | ||
} | ||
|
||
private ImmutableArray<IOperation> GetAnonymousObjectCreationInitializers(BoundAnonymousObjectCreationExpression expression) | ||
{ | ||
// For error cases, the binder generates only the argument. | ||
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. See #20338 for additional gotchas here. #Resolved |
||
Debug.Assert(expression.Arguments.Length >= expression.Declarations.Length); | ||
|
||
var builder = ArrayBuilder<IOperation>.GetInstance(expression.Arguments.Length); | ||
for (int i = 0; i < expression.Arguments.Length; i++) | ||
{ | ||
IOperation value = Create(expression.Arguments[i]); | ||
if (i >= expression.Declarations.Length) | ||
{ | ||
builder.Add(value); | ||
continue; | ||
} | ||
|
||
IOperation target = Create(expression.Declarations[i]); | ||
bool isInvalid = target.IsInvalid || value.IsInvalid; | ||
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. Is it necessary to consider the entire assignment invalid if either 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. @heejaechang Is actually working on a PR to remove IOperation.IsInvalid flag. It is currently a very fragile heuristic, and we are replacing it with an extension method on IOperation that determines the result by computing if the span has syntax or semantic diagnostics within it. |
||
SyntaxNode syntax = value.Syntax?.Parent ?? expression.Syntax; | ||
ITypeSymbol type = target.Type; | ||
Optional<object> constantValue = value.ConstantValue; | ||
var assignment = new SimpleAssignmentExpression(target, value, isInvalid, syntax, type, constantValue); | ||
builder.Add(assignment); | ||
} | ||
|
||
return builder.ToImmutableAndFree(); | ||
} | ||
|
||
private ImmutableArray<IOperation> GetObjectCreationInitializers(BoundObjectCreationExpression expression) | ||
{ | ||
return BoundObjectCreationExpression.GetChildInitializers(expression.InitializerExpressionOpt).SelectAsArray(n => Create(n)); | ||
|
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.
I didn't understand this change. How do you know this is unreachable? #Closed
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.
@jcouv - This is addressing feedback from #20276 (comment). We handle this bound node while operation on it's parent here: https://github.com/dotnet/roslyn/pull/20276/files#diff-df80689b64fbe29db28a562eb0dac8caR1154 #Resolved