// 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.Concurrent; using System.Collections.Immutable; using System.Diagnostics; using System.Linq; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Operations { internal sealed partial class CSharpOperationFactory { private readonly ConcurrentDictionary _cache = new ConcurrentDictionary(concurrencyLevel: 2, capacity: 10); private readonly SemanticModel _semanticModel; public CSharpOperationFactory(SemanticModel semanticModel) { _semanticModel = semanticModel; } public IOperation Create(BoundNode boundNode) { if (boundNode == null) { return null; } // implicit receiver can be shared between multiple bound nodes. // always return cloned one if (boundNode.Kind == BoundKind.ImplicitReceiver) { return OperationCloner.CloneOperation(CreateInternal(boundNode)); } return _cache.GetOrAdd(boundNode, n => CreateInternal(n)); } private IOperation CreateInternal(BoundNode boundNode) { switch (boundNode.Kind) { case BoundKind.DeconstructValuePlaceholder: return CreateBoundDeconstructValuePlaceholderOperation((BoundDeconstructValuePlaceholder)boundNode); case BoundKind.DeconstructionAssignmentOperator: return CreateBoundDeconstructionAssignmentOperator((BoundDeconstructionAssignmentOperator)boundNode); case BoundKind.Call: return CreateBoundCallOperation((BoundCall)boundNode); case BoundKind.Local: return CreateBoundLocalOperation((BoundLocal)boundNode); case BoundKind.FieldAccess: return CreateBoundFieldAccessOperation((BoundFieldAccess)boundNode); case BoundKind.PropertyAccess: return CreateBoundPropertyAccessOperation((BoundPropertyAccess)boundNode); case BoundKind.IndexerAccess: return CreateBoundIndexerAccessOperation((BoundIndexerAccess)boundNode); case BoundKind.EventAccess: return CreateBoundEventAccessOperation((BoundEventAccess)boundNode); case BoundKind.EventAssignmentOperator: return CreateBoundEventAssignmentOperatorOperation((BoundEventAssignmentOperator)boundNode); case BoundKind.Parameter: return CreateBoundParameterOperation((BoundParameter)boundNode); case BoundKind.Literal: return CreateBoundLiteralOperation((BoundLiteral)boundNode); case BoundKind.DynamicInvocation: return CreateBoundDynamicInvocationExpressionOperation((BoundDynamicInvocation)boundNode); case BoundKind.DynamicIndexerAccess: return CreateBoundDynamicIndexerAccessExpressionOperation((BoundDynamicIndexerAccess)boundNode); case BoundKind.ObjectCreationExpression: return CreateBoundObjectCreationExpressionOperation((BoundObjectCreationExpression)boundNode); case BoundKind.DynamicObjectCreationExpression: return CreateBoundDynamicObjectCreationExpressionOperation((BoundDynamicObjectCreationExpression)boundNode); case BoundKind.ObjectInitializerExpression: return CreateBoundObjectInitializerExpressionOperation((BoundObjectInitializerExpression)boundNode); case BoundKind.CollectionInitializerExpression: return CreateBoundCollectionInitializerExpressionOperation((BoundCollectionInitializerExpression)boundNode); case BoundKind.ObjectInitializerMember: return CreateBoundObjectInitializerMemberOperation((BoundObjectInitializerMember)boundNode); case BoundKind.CollectionElementInitializer: return CreateBoundCollectionElementInitializerOperation((BoundCollectionElementInitializer)boundNode); case BoundKind.DynamicMemberAccess: return CreateBoundDynamicMemberAccessOperation((BoundDynamicMemberAccess)boundNode); case BoundKind.DynamicCollectionElementInitializer: return CreateBoundDynamicCollectionElementInitializerOperation((BoundDynamicCollectionElementInitializer)boundNode); case BoundKind.UnboundLambda: return CreateUnboundLambdaOperation((UnboundLambda)boundNode); case BoundKind.Lambda: return CreateBoundLambdaOperation((BoundLambda)boundNode); case BoundKind.Conversion: return CreateBoundConversionOperation((BoundConversion)boundNode); case BoundKind.AsOperator: return CreateBoundAsOperatorOperation((BoundAsOperator)boundNode); case BoundKind.IsOperator: return CreateBoundIsOperatorOperation((BoundIsOperator)boundNode); case BoundKind.SizeOfOperator: return CreateBoundSizeOfOperatorOperation((BoundSizeOfOperator)boundNode); case BoundKind.TypeOfOperator: return CreateBoundTypeOfOperatorOperation((BoundTypeOfOperator)boundNode); case BoundKind.ArrayCreation: return CreateBoundArrayCreationOperation((BoundArrayCreation)boundNode); case BoundKind.ArrayInitialization: return CreateBoundArrayInitializationOperation((BoundArrayInitialization)boundNode); case BoundKind.DefaultExpression: return CreateBoundDefaultExpressionOperation((BoundDefaultExpression)boundNode); case BoundKind.BaseReference: return CreateBoundBaseReferenceOperation((BoundBaseReference)boundNode); case BoundKind.ThisReference: return CreateBoundThisReferenceOperation((BoundThisReference)boundNode); case BoundKind.AssignmentOperator: return CreateBoundAssignmentOperatorOrMemberInitializerOperation((BoundAssignmentOperator)boundNode); case BoundKind.CompoundAssignmentOperator: return CreateBoundCompoundAssignmentOperatorOperation((BoundCompoundAssignmentOperator)boundNode); case BoundKind.IncrementOperator: return CreateBoundIncrementOperatorOperation((BoundIncrementOperator)boundNode); case BoundKind.BadExpression: return CreateBoundBadExpressionOperation((BoundBadExpression)boundNode); case BoundKind.NewT: return CreateBoundNewTOperation((BoundNewT)boundNode); case BoundKind.UnaryOperator: return CreateBoundUnaryOperatorOperation((BoundUnaryOperator)boundNode); case BoundKind.BinaryOperator: return CreateBoundBinaryOperatorOperation((BoundBinaryOperator)boundNode); case BoundKind.ConditionalOperator: return CreateBoundConditionalOperatorOperation((BoundConditionalOperator)boundNode); case BoundKind.NullCoalescingOperator: return CreateBoundNullCoalescingOperatorOperation((BoundNullCoalescingOperator)boundNode); case BoundKind.AwaitExpression: return CreateBoundAwaitExpressionOperation((BoundAwaitExpression)boundNode); case BoundKind.ArrayAccess: return CreateBoundArrayAccessOperation((BoundArrayAccess)boundNode); case BoundKind.NameOfOperator: return CreateBoundNameOfOperatorOperation((BoundNameOfOperator)boundNode); case BoundKind.ThrowExpression: return CreateBoundThrowExpressionOperation((BoundThrowExpression)boundNode); case BoundKind.AddressOfOperator: return CreateBoundAddressOfOperatorOperation((BoundAddressOfOperator)boundNode); case BoundKind.ImplicitReceiver: return CreateBoundImplicitReceiverOperation((BoundImplicitReceiver)boundNode); case BoundKind.ConditionalAccess: return CreateBoundConditionalAccessOperation((BoundConditionalAccess)boundNode); case BoundKind.ConditionalReceiver: return CreateBoundConditionalReceiverOperation((BoundConditionalReceiver)boundNode); case BoundKind.FieldEqualsValue: return CreateBoundFieldEqualsValueOperation((BoundFieldEqualsValue)boundNode); case BoundKind.PropertyEqualsValue: return CreateBoundPropertyEqualsValueOperation((BoundPropertyEqualsValue)boundNode); case BoundKind.ParameterEqualsValue: return CreateBoundParameterEqualsValueOperation((BoundParameterEqualsValue)boundNode); case BoundKind.Block: return CreateBoundBlockOperation((BoundBlock)boundNode); case BoundKind.ContinueStatement: return CreateBoundContinueStatementOperation((BoundContinueStatement)boundNode); case BoundKind.BreakStatement: return CreateBoundBreakStatementOperation((BoundBreakStatement)boundNode); case BoundKind.YieldBreakStatement: return CreateBoundYieldBreakStatementOperation((BoundYieldBreakStatement)boundNode); case BoundKind.GotoStatement: return CreateBoundGotoStatementOperation((BoundGotoStatement)boundNode); case BoundKind.NoOpStatement: return CreateBoundNoOpStatementOperation((BoundNoOpStatement)boundNode); case BoundKind.IfStatement: return CreateBoundIfStatementOperation((BoundIfStatement)boundNode); case BoundKind.WhileStatement: return CreateBoundWhileStatementOperation((BoundWhileStatement)boundNode); case BoundKind.DoStatement: return CreateBoundDoStatementOperation((BoundDoStatement)boundNode); case BoundKind.ForStatement: return CreateBoundForStatementOperation((BoundForStatement)boundNode); case BoundKind.ForEachStatement: return CreateBoundForEachStatementOperation((BoundForEachStatement)boundNode); case BoundKind.SwitchStatement: return CreateBoundSwitchStatementOperation((BoundSwitchStatement)boundNode); case BoundKind.SwitchLabel: return CreateBoundSwitchLabelOperation((BoundSwitchLabel)boundNode); case BoundKind.TryStatement: return CreateBoundTryStatementOperation((BoundTryStatement)boundNode); case BoundKind.CatchBlock: return CreateBoundCatchBlockOperation((BoundCatchBlock)boundNode); // https://github.com/dotnet/roslyn/issues/21281 //case BoundKind.FixedStatement: // return CreateBoundFixedStatementOperation((BoundFixedStatement)boundNode); case BoundKind.UsingStatement: return CreateBoundUsingStatementOperation((BoundUsingStatement)boundNode); case BoundKind.ThrowStatement: return CreateBoundThrowStatementOperation((BoundThrowStatement)boundNode); case BoundKind.ReturnStatement: return CreateBoundReturnStatementOperation((BoundReturnStatement)boundNode); case BoundKind.YieldReturnStatement: return CreateBoundYieldReturnStatementOperation((BoundYieldReturnStatement)boundNode); case BoundKind.LockStatement: return CreateBoundLockStatementOperation((BoundLockStatement)boundNode); case BoundKind.BadStatement: return CreateBoundBadStatementOperation((BoundBadStatement)boundNode); case BoundKind.LocalDeclaration: return CreateBoundLocalDeclarationOperation((BoundLocalDeclaration)boundNode); case BoundKind.MultipleLocalDeclarations: return CreateBoundMultipleLocalDeclarationsOperation((BoundMultipleLocalDeclarations)boundNode); case BoundKind.LabelStatement: return CreateBoundLabelStatementOperation((BoundLabelStatement)boundNode); case BoundKind.LabeledStatement: return CreateBoundLabeledStatementOperation((BoundLabeledStatement)boundNode); case BoundKind.ExpressionStatement: return CreateBoundExpressionStatementOperation((BoundExpressionStatement)boundNode); case BoundKind.TupleLiteral: return CreateBoundTupleLiteralOperation((BoundTupleLiteral)boundNode); case BoundKind.ConvertedTupleLiteral: return CreateBoundConvertedTupleLiteralOperation((BoundConvertedTupleLiteral)boundNode); case BoundKind.InterpolatedString: return CreateBoundInterpolatedStringExpressionOperation((BoundInterpolatedString)boundNode); case BoundKind.StringInsert: 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: throw ExceptionUtilities.Unreachable; case BoundKind.PatternSwitchStatement: return CreateBoundPatternSwitchStatementOperation((BoundPatternSwitchStatement)boundNode); case BoundKind.PatternSwitchLabel: return CreateBoundPatternSwitchLabelOperation((BoundPatternSwitchLabel)boundNode); case BoundKind.IsPatternExpression: return CreateBoundIsPatternExpressionOperation((BoundIsPatternExpression)boundNode); case BoundKind.QueryClause: return CreateBoundQueryClauseOperation((BoundQueryClause)boundNode); case BoundKind.DelegateCreationExpression: return CreateBoundDelegateCreationExpressionOperation((BoundDelegateCreationExpression)boundNode); case BoundKind.RangeVariable: return CreateBoundRangeVariableOperation((BoundRangeVariable)boundNode); default: Optional constantValue = ConvertToOptional((boundNode as BoundExpression)?.ConstantValue); bool isImplicit = boundNode.WasCompilerGenerated; if (!isImplicit) { switch (boundNode.Kind) { case BoundKind.FixedLocalCollectionInitializer: isImplicit = true; break; } } return Operation.CreateOperationNone(_semanticModel, boundNode.Syntax, constantValue, getChildren: () => GetIOperationChildren(boundNode), isImplicit: isImplicit); } } private ImmutableArray GetIOperationChildren(BoundNode boundNode) { var boundNodeWithChildren = (IBoundNodeWithIOperationChildren)boundNode; var children = boundNodeWithChildren.Children; if (children.IsDefaultOrEmpty) { return ImmutableArray.Empty; } var builder = ArrayBuilder.GetInstance(children.Length); foreach (BoundNode childNode in children) { IOperation operation = Create(childNode); if (operation == null) { continue; } builder.Add(operation); } return builder.ToImmutableAndFree(); } private IVariableDeclaratorOperation CreateVariableDeclarator(BoundLocalDeclaration boundNode) { return (IVariableDeclaratorOperation)_cache.GetOrAdd(boundNode, n => CreateVariableDeclaratorInternal((BoundLocalDeclaration)n, n.Syntax)); } private IPlaceholderOperation CreateBoundDeconstructValuePlaceholderOperation(BoundDeconstructValuePlaceholder boundDeconstructValuePlaceholder) { SyntaxNode syntax = boundDeconstructValuePlaceholder.Syntax; ITypeSymbol type = boundDeconstructValuePlaceholder.Type; Optional constantValue = ConvertToOptional(boundDeconstructValuePlaceholder.ConstantValue); bool isImplicit = boundDeconstructValuePlaceholder.WasCompilerGenerated; return new PlaceholderExpression(_semanticModel, syntax, type, constantValue, isImplicit); } private IDeconstructionAssignmentOperation CreateBoundDeconstructionAssignmentOperator(BoundDeconstructionAssignmentOperator boundDeconstructionAssignmentOperator) { Lazy target = new Lazy(() => Create(boundDeconstructionAssignmentOperator.Left)); // Skip the synthetic deconstruction conversion wrapping the right operand. Lazy value = new Lazy(() => Create(boundDeconstructionAssignmentOperator.Right.Operand)); SyntaxNode syntax = boundDeconstructionAssignmentOperator.Syntax; ITypeSymbol type = boundDeconstructionAssignmentOperator.Type; Optional constantValue = ConvertToOptional(boundDeconstructionAssignmentOperator.ConstantValue); bool isImplicit = boundDeconstructionAssignmentOperator.WasCompilerGenerated; return new LazyDeconstructionAssignmentExpression(target, value, _semanticModel, syntax, type, constantValue, isImplicit); } private IOperation CreateBoundCallOperation(BoundCall boundCall) { MethodSymbol targetMethod = boundCall.Method; SyntaxNode syntax = boundCall.Syntax; ITypeSymbol type = boundCall.Type; Optional constantValue = ConvertToOptional(boundCall.ConstantValue); bool isImplicit = boundCall.WasCompilerGenerated; if (!boundCall.OriginalMethodsOpt.IsDefault || boundCall.ResultKind == LookupResultKind.OverloadResolutionFailure || targetMethod == null || targetMethod.OriginalDefinition is ErrorMethodSymbol) { return CreateInvalidExpressionForHasArgumentsExpression(boundCall.ReceiverOpt, boundCall.Arguments, null, syntax, type, constantValue, isImplicit); } Lazy instance = CreateReceiverOperation(boundCall.ReceiverOpt, targetMethod); bool isVirtual = (object)targetMethod != null && boundCall.ReceiverOpt != null && (targetMethod.IsVirtual || targetMethod.IsAbstract || targetMethod.IsOverride) && !boundCall.ReceiverOpt.SuppressVirtualCalls; Lazy> arguments = new Lazy>(() => { return DeriveArguments( boundCall, boundCall.BinderOpt, targetMethod, targetMethod, boundCall.Arguments, boundCall.ArgumentNamesOpt, boundCall.ArgsToParamsOpt, boundCall.ArgumentRefKindsOpt, boundCall.Method.Parameters, boundCall.Expanded, syntax, boundCall.InvokedAsExtensionMethod); }); return new LazyInvocationExpression(targetMethod, instance, isVirtual, arguments, _semanticModel, syntax, type, constantValue, isImplicit); } private IOperation CreateBoundLocalOperation(BoundLocal boundLocal) { ILocalSymbol local = boundLocal.LocalSymbol; bool isDeclaration = boundLocal.IsDeclaration; SyntaxNode syntax = boundLocal.Syntax; ITypeSymbol type = boundLocal.Type; Optional constantValue = ConvertToOptional(boundLocal.ConstantValue); bool isImplicit = boundLocal.WasCompilerGenerated; if (isDeclaration && syntax is DeclarationExpressionSyntax declarationExpressionSyntax) { syntax = declarationExpressionSyntax.Designation; Lazy localReferenceExpression = new Lazy(() => new LocalReferenceExpression(local, isDeclaration, _semanticModel, syntax, type, constantValue, isImplicit)); return new LazyDeclarationExpression(localReferenceExpression, _semanticModel, declarationExpressionSyntax, type, constantValue: default, isImplicit: false); } return new LocalReferenceExpression(local, isDeclaration, _semanticModel, syntax, type, constantValue, isImplicit); } private IOperation CreateBoundFieldAccessOperation(BoundFieldAccess boundFieldAccess) { IFieldSymbol field = boundFieldAccess.FieldSymbol; bool isDeclaration = boundFieldAccess.IsDeclaration; Lazy instance = CreateReceiverOperation(boundFieldAccess.ReceiverOpt, field); SyntaxNode syntax = boundFieldAccess.Syntax; ITypeSymbol type = boundFieldAccess.Type; Optional constantValue = ConvertToOptional(boundFieldAccess.ConstantValue); bool isImplicit = boundFieldAccess.WasCompilerGenerated; if (isDeclaration && syntax is DeclarationExpressionSyntax declarationExpressionSyntax) { syntax = declarationExpressionSyntax.Designation; Lazy fieldReferenceExpression = new Lazy(() => new LazyFieldReferenceExpression(field, isDeclaration, instance, _semanticModel, syntax, type, constantValue, isImplicit)); return new LazyDeclarationExpression(fieldReferenceExpression, _semanticModel, declarationExpressionSyntax, type, constantValue: default, isImplicit: false); } return new LazyFieldReferenceExpression(field, isDeclaration, instance, _semanticModel, syntax, type, constantValue, isImplicit); } private IPropertyReferenceOperation CreateBoundPropertyAccessOperation(BoundPropertyAccess boundPropertyAccess) { IPropertySymbol property = boundPropertyAccess.PropertySymbol; Lazy instance = CreateReceiverOperation(boundPropertyAccess.ReceiverOpt, property); Lazy> arguments = new Lazy>(() => ImmutableArray.Empty); SyntaxNode syntax = boundPropertyAccess.Syntax; ITypeSymbol type = boundPropertyAccess.Type; Optional constantValue = ConvertToOptional(boundPropertyAccess.ConstantValue); bool isImplicit = boundPropertyAccess.WasCompilerGenerated; return new LazyPropertyReferenceExpression(property, instance, arguments, _semanticModel, syntax, type, constantValue, isImplicit); } private IOperation CreateBoundIndexerAccessOperation(BoundIndexerAccess boundIndexerAccess) { PropertySymbol property = boundIndexerAccess.Indexer; SyntaxNode syntax = boundIndexerAccess.Syntax; ITypeSymbol type = boundIndexerAccess.Type; Optional constantValue = ConvertToOptional(boundIndexerAccess.ConstantValue); bool isImplicit = boundIndexerAccess.WasCompilerGenerated; MethodSymbol accessor = boundIndexerAccess.UseSetterForDefaultArgumentGeneration ? property.GetOwnOrInheritedSetMethod() : property.GetOwnOrInheritedGetMethod(); if (!boundIndexerAccess.OriginalIndexersOpt.IsDefault || boundIndexerAccess.ResultKind == LookupResultKind.OverloadResolutionFailure || accessor == null || accessor.OriginalDefinition is ErrorMethodSymbol) { return CreateInvalidExpressionForHasArgumentsExpression(boundIndexerAccess.ReceiverOpt, boundIndexerAccess.Arguments, null, syntax, type, constantValue, isImplicit); } Lazy instance = CreateReceiverOperation(boundIndexerAccess.ReceiverOpt, property); Lazy> arguments = new Lazy>(() => DeriveArguments( boundIndexerAccess, boundIndexerAccess.BinderOpt, property, accessor, boundIndexerAccess.Arguments, boundIndexerAccess.ArgumentNamesOpt, boundIndexerAccess.ArgsToParamsOpt, boundIndexerAccess.ArgumentRefKindsOpt, property.Parameters, boundIndexerAccess.Expanded, syntax)); return new LazyPropertyReferenceExpression(property, instance, arguments, _semanticModel, syntax, type, constantValue, isImplicit); } private IEventReferenceOperation CreateBoundEventAccessOperation(BoundEventAccess boundEventAccess) { IEventSymbol @event = boundEventAccess.EventSymbol; Lazy instance = CreateReceiverOperation(boundEventAccess.ReceiverOpt, @event); SyntaxNode syntax = boundEventAccess.Syntax; ITypeSymbol type = boundEventAccess.Type; Optional constantValue = ConvertToOptional(boundEventAccess.ConstantValue); bool isImplicit = boundEventAccess.WasCompilerGenerated; return new LazyEventReferenceExpression(@event, instance, _semanticModel, syntax, type, constantValue, isImplicit); } private IEventAssignmentOperation CreateBoundEventAssignmentOperatorOperation(BoundEventAssignmentOperator boundEventAssignmentOperator) { Lazy eventReference = new Lazy(() => CreateBoundEventAccessOperation(boundEventAssignmentOperator)); Lazy handlerValue = new Lazy(() => Create(boundEventAssignmentOperator.Argument)); SyntaxNode syntax = boundEventAssignmentOperator.Syntax; bool adds = boundEventAssignmentOperator.IsAddition; ITypeSymbol type = boundEventAssignmentOperator.Type; Optional constantValue = ConvertToOptional(boundEventAssignmentOperator.ConstantValue); bool isImplicit = boundEventAssignmentOperator.WasCompilerGenerated; return new LazyEventAssignmentOperation(eventReference, handlerValue, adds, _semanticModel, syntax, type, constantValue, isImplicit); } private IParameterReferenceOperation CreateBoundParameterOperation(BoundParameter boundParameter) { IParameterSymbol parameter = boundParameter.ParameterSymbol; SyntaxNode syntax = boundParameter.Syntax; ITypeSymbol type = boundParameter.Type; Optional constantValue = ConvertToOptional(boundParameter.ConstantValue); bool isImplicit = boundParameter.WasCompilerGenerated; return new ParameterReferenceExpression(parameter, _semanticModel, syntax, type, constantValue, isImplicit); } private ILiteralOperation CreateBoundLiteralOperation(BoundLiteral boundLiteral, bool @implicit = false) { SyntaxNode syntax = boundLiteral.Syntax; ITypeSymbol type = boundLiteral.Type; Optional constantValue = ConvertToOptional(boundLiteral.ConstantValue); bool isImplicit = boundLiteral.WasCompilerGenerated || @implicit; return new LiteralExpression(_semanticModel, syntax, type, constantValue, isImplicit); } private IAnonymousObjectCreationOperation CreateBoundAnonymousObjectCreationExpressionOperation(BoundAnonymousObjectCreationExpression boundAnonymousObjectCreationExpression) { Lazy> memberInitializers = new Lazy>(() => GetAnonymousObjectCreationInitializers(boundAnonymousObjectCreationExpression)); SyntaxNode syntax = boundAnonymousObjectCreationExpression.Syntax; ITypeSymbol type = boundAnonymousObjectCreationExpression.Type; Optional constantValue = ConvertToOptional(boundAnonymousObjectCreationExpression.ConstantValue); bool isImplicit = boundAnonymousObjectCreationExpression.WasCompilerGenerated; return new LazyAnonymousObjectCreationExpression(memberInitializers, _semanticModel, syntax, type, constantValue, isImplicit); } private IPropertyReferenceOperation CreateBoundAnonymousPropertyDeclarationOperation(BoundAnonymousPropertyDeclaration boundAnonymousPropertyDeclaration) { PropertySymbol property = boundAnonymousPropertyDeclaration.Property; Lazy instance = OperationFactory.NullOperation; Lazy> arguments = new Lazy>(() => ImmutableArray.Empty); SyntaxNode syntax = boundAnonymousPropertyDeclaration.Syntax; ITypeSymbol type = boundAnonymousPropertyDeclaration.Type; Optional constantValue = ConvertToOptional(boundAnonymousPropertyDeclaration.ConstantValue); bool isImplicit = boundAnonymousPropertyDeclaration.WasCompilerGenerated; return new LazyPropertyReferenceExpression(property, instance, arguments, _semanticModel, syntax, type, constantValue, isImplicit); } private IOperation CreateBoundObjectCreationExpressionOperation(BoundObjectCreationExpression boundObjectCreationExpression) { MethodSymbol constructor = boundObjectCreationExpression.Constructor; SyntaxNode syntax = boundObjectCreationExpression.Syntax; ITypeSymbol type = boundObjectCreationExpression.Type; Optional constantValue = ConvertToOptional(boundObjectCreationExpression.ConstantValue); bool isImplicit = boundObjectCreationExpression.WasCompilerGenerated; if (boundObjectCreationExpression.ResultKind == LookupResultKind.OverloadResolutionFailure || constructor == null || constructor.OriginalDefinition is ErrorMethodSymbol) { return CreateInvalidExpressionForHasArgumentsExpression(null, boundObjectCreationExpression.Arguments, boundObjectCreationExpression.InitializerExpressionOpt, syntax, type, constantValue, isImplicit); } Lazy initializer = new Lazy(() => (IObjectOrCollectionInitializerOperation)Create(boundObjectCreationExpression.InitializerExpressionOpt)); Lazy> arguments = new Lazy>(() => { return DeriveArguments( boundObjectCreationExpression, boundObjectCreationExpression.BinderOpt, constructor, constructor, boundObjectCreationExpression.Arguments, boundObjectCreationExpression.ArgumentNamesOpt, boundObjectCreationExpression.ArgsToParamsOpt, boundObjectCreationExpression.ArgumentRefKindsOpt, constructor.Parameters, boundObjectCreationExpression.Expanded, syntax); }); return new LazyObjectCreationExpression(constructor, initializer, arguments, _semanticModel, syntax, type, constantValue, isImplicit); } private IDynamicObjectCreationOperation CreateBoundDynamicObjectCreationExpressionOperation(BoundDynamicObjectCreationExpression boundDynamicObjectCreationExpression) { Lazy> arguments = new Lazy>(() => boundDynamicObjectCreationExpression.Arguments.SelectAsArray(n => Create(n))); ImmutableArray argumentNames = boundDynamicObjectCreationExpression.ArgumentNamesOpt.NullToEmpty(); ImmutableArray argumentRefKinds = boundDynamicObjectCreationExpression.ArgumentRefKindsOpt.NullToEmpty(); Lazy initializer = new Lazy(() => (IObjectOrCollectionInitializerOperation)Create(boundDynamicObjectCreationExpression.InitializerExpressionOpt)); SyntaxNode syntax = boundDynamicObjectCreationExpression.Syntax; ITypeSymbol type = boundDynamicObjectCreationExpression.Type; Optional constantValue = ConvertToOptional(boundDynamicObjectCreationExpression.ConstantValue); bool isImplicit = boundDynamicObjectCreationExpression.WasCompilerGenerated; return new LazyDynamicObjectCreationExpression(arguments, argumentNames, argumentRefKinds, initializer, _semanticModel, syntax, type, constantValue, isImplicit); } private IDynamicInvocationOperation CreateBoundDynamicInvocationExpressionOperation(BoundDynamicInvocation boundDynamicInvocation) { Lazy expression; if (boundDynamicInvocation.Expression.Kind == BoundKind.MethodGroup) { var methodGroup = (BoundMethodGroup)boundDynamicInvocation.Expression; expression = new Lazy(() => CreateBoundDynamicMemberAccessOperation(methodGroup.ReceiverOpt, methodGroup.TypeArgumentsOpt, methodGroup.Name, methodGroup.Syntax, methodGroup.Type, methodGroup.ConstantValue, methodGroup.WasCompilerGenerated)); } else { expression = new Lazy(() => Create(boundDynamicInvocation.Expression)); } Lazy> arguments = new Lazy>(() => boundDynamicInvocation.Arguments.SelectAsArray(n => Create(n))); ImmutableArray argumentNames = boundDynamicInvocation.ArgumentNamesOpt.NullToEmpty(); ImmutableArray argumentRefKinds = boundDynamicInvocation.ArgumentRefKindsOpt.NullToEmpty(); SyntaxNode syntax = boundDynamicInvocation.Syntax; ITypeSymbol type = boundDynamicInvocation.Type; Optional constantValue = ConvertToOptional(boundDynamicInvocation.ConstantValue); bool isImplicit = boundDynamicInvocation.WasCompilerGenerated; return new LazyDynamicInvocationExpression(expression, arguments, argumentNames, argumentRefKinds, _semanticModel, syntax, type, constantValue, isImplicit); } private IDynamicIndexerAccessOperation CreateBoundDynamicIndexerAccessExpressionOperation(BoundDynamicIndexerAccess boundDynamicIndexerAccess) { Lazy expression = new Lazy(() => Create(boundDynamicIndexerAccess.ReceiverOpt)); Lazy> arguments = new Lazy>(() => boundDynamicIndexerAccess.Arguments.SelectAsArray(n => Create(n))); ImmutableArray argumentNames = boundDynamicIndexerAccess.ArgumentNamesOpt.NullToEmpty(); ImmutableArray argumentRefKinds = boundDynamicIndexerAccess.ArgumentRefKindsOpt.NullToEmpty(); SyntaxNode syntax = boundDynamicIndexerAccess.Syntax; ITypeSymbol type = boundDynamicIndexerAccess.Type; Optional constantValue = ConvertToOptional(boundDynamicIndexerAccess.ConstantValue); bool isImplicit = boundDynamicIndexerAccess.WasCompilerGenerated; return new LazyDynamicIndexerAccessExpression(expression, arguments, argumentNames, argumentRefKinds, _semanticModel, syntax, type, constantValue, isImplicit); } private IObjectOrCollectionInitializerOperation CreateBoundObjectInitializerExpressionOperation(BoundObjectInitializerExpression boundObjectInitializerExpression) { Lazy> initializers = new Lazy>(() => BoundObjectCreationExpression.GetChildInitializers(boundObjectInitializerExpression).SelectAsArray(n => Create(n))); SyntaxNode syntax = boundObjectInitializerExpression.Syntax; ITypeSymbol type = boundObjectInitializerExpression.Type; Optional constantValue = ConvertToOptional(boundObjectInitializerExpression.ConstantValue); bool isImplicit = boundObjectInitializerExpression.WasCompilerGenerated; return new LazyObjectOrCollectionInitializerExpression(initializers, _semanticModel, syntax, type, constantValue, isImplicit); } private IObjectOrCollectionInitializerOperation CreateBoundCollectionInitializerExpressionOperation(BoundCollectionInitializerExpression boundCollectionInitializerExpression) { Lazy> initializers = new Lazy>(() => BoundObjectCreationExpression.GetChildInitializers(boundCollectionInitializerExpression).SelectAsArray(n => Create(n))); SyntaxNode syntax = boundCollectionInitializerExpression.Syntax; ITypeSymbol type = boundCollectionInitializerExpression.Type; Optional constantValue = ConvertToOptional(boundCollectionInitializerExpression.ConstantValue); bool isImplicit = boundCollectionInitializerExpression.WasCompilerGenerated; return new LazyObjectOrCollectionInitializerExpression(initializers, _semanticModel, syntax, type, constantValue, isImplicit); } private IOperation CreateBoundObjectInitializerMemberOperation(BoundObjectInitializerMember boundObjectInitializerMember) { Symbol memberSymbol = boundObjectInitializerMember.MemberSymbol; Lazy instance = memberSymbol?.IsStatic == true ? OperationFactory.NullOperation : new Lazy(() => new InstanceReferenceExpression( semanticModel: _semanticModel, syntax: boundObjectInitializerMember.Syntax, type: boundObjectInitializerMember.ReceiverType, constantValue: default(Optional), isImplicit: true)); SyntaxNode syntax = boundObjectInitializerMember.Syntax; ITypeSymbol type = boundObjectInitializerMember.Type; Optional constantValue = ConvertToOptional(boundObjectInitializerMember.ConstantValue); bool isImplicit = boundObjectInitializerMember.WasCompilerGenerated; if ((object)memberSymbol == null) { Debug.Assert(boundObjectInitializerMember.Type.IsDynamic()); Lazy> arguments = new Lazy>(() => boundObjectInitializerMember.Arguments.SelectAsArray(n => Create(n))); ImmutableArray argumentNames = boundObjectInitializerMember.ArgumentNamesOpt.NullToEmpty(); ImmutableArray argumentRefKinds = boundObjectInitializerMember.ArgumentRefKindsOpt.NullToEmpty(); return new LazyDynamicIndexerAccessExpression(instance, arguments, argumentNames, argumentRefKinds, _semanticModel, syntax, type, constantValue, isImplicit); } switch (memberSymbol.Kind) { case SymbolKind.Field: var field = (FieldSymbol)memberSymbol; bool isDeclaration = false; return new LazyFieldReferenceExpression(field, isDeclaration, instance, _semanticModel, syntax, type, constantValue, isImplicit); case SymbolKind.Event: var eventSymbol = (EventSymbol)memberSymbol; return new LazyEventReferenceExpression(eventSymbol, instance, _semanticModel, syntax, type, constantValue, isImplicit); case SymbolKind.Property: var property = (PropertySymbol)memberSymbol; Lazy> arguments; if (!boundObjectInitializerMember.Arguments.Any()) { // Simple property reference. arguments = new Lazy>(() => ImmutableArray.Empty); } else { var accessor = property.GetOwnOrInheritedSetMethod(); if (accessor == null || boundObjectInitializerMember.ResultKind == LookupResultKind.OverloadResolutionFailure || accessor.OriginalDefinition is ErrorMethodSymbol) { Lazy> children = new Lazy>(() => boundObjectInitializerMember.Arguments.SelectAsArray(a => Create(a))); return new LazyInvalidOperation(children, _semanticModel, syntax, type, constantValue, isImplicit); } // Indexed property reference. arguments = new Lazy>(() => { return DeriveArguments( boundObjectInitializerMember, boundObjectInitializerMember.BinderOpt, property, accessor, boundObjectInitializerMember.Arguments, boundObjectInitializerMember.ArgumentNamesOpt, boundObjectInitializerMember.ArgsToParamsOpt, boundObjectInitializerMember.ArgumentRefKindsOpt, property.Parameters, boundObjectInitializerMember.Expanded, boundObjectInitializerMember.Syntax); }); } return new LazyPropertyReferenceExpression(property, instance, arguments, _semanticModel, syntax, type, constantValue, isImplicit); default: throw ExceptionUtilities.Unreachable; } } private ICollectionElementInitializerOperation CreateBoundCollectionElementInitializerOperation(BoundCollectionElementInitializer boundCollectionElementInitializer) { IMethodSymbol addMethod = boundCollectionElementInitializer.AddMethod; Lazy> arguments = new Lazy>(() => boundCollectionElementInitializer.Arguments.SelectAsArray(n => Create(n))); bool isDynamic = false; SyntaxNode syntax = boundCollectionElementInitializer.Syntax; ITypeSymbol type = boundCollectionElementInitializer.Type; Optional constantValue = ConvertToOptional(boundCollectionElementInitializer.ConstantValue); bool isImplicit = boundCollectionElementInitializer.WasCompilerGenerated; return new LazyCollectionElementInitializerExpression(addMethod, isDynamic, arguments, _semanticModel, syntax, type, constantValue, isImplicit); } private IDynamicMemberReferenceOperation CreateBoundDynamicMemberAccessOperation(BoundDynamicMemberAccess boundDynamicMemberAccess) { return CreateBoundDynamicMemberAccessOperation(boundDynamicMemberAccess.Receiver, boundDynamicMemberAccess.TypeArgumentsOpt, boundDynamicMemberAccess.Name, boundDynamicMemberAccess.Syntax, boundDynamicMemberAccess.Type, boundDynamicMemberAccess.ConstantValue, boundDynamicMemberAccess.WasCompilerGenerated); } private IDynamicMemberReferenceOperation CreateBoundDynamicMemberAccessOperation( BoundExpression receiverOpt, ImmutableArray typeArgumentsOpt, string memberName, SyntaxNode syntaxNode, ITypeSymbol type, ConstantValue value, bool isImplicit) { Lazy instance = receiverOpt == null || receiverOpt.Kind == BoundKind.TypeExpression ? OperationFactory.NullOperation : new Lazy(() => Create(receiverOpt)); ImmutableArray typeArguments = ImmutableArray.Empty; if (!typeArgumentsOpt.IsDefault) { typeArguments = ImmutableArray.CastUp(typeArgumentsOpt); } ITypeSymbol containingType = receiverOpt?.Kind == BoundKind.TypeExpression ? receiverOpt.Type : null; Optional constantValue = ConvertToOptional(value); return new LazyDynamicMemberReferenceExpression(instance, memberName, typeArguments, containingType, _semanticModel, syntaxNode, type, constantValue, isImplicit); } private ICollectionElementInitializerOperation CreateBoundDynamicCollectionElementInitializerOperation(BoundDynamicCollectionElementInitializer boundCollectionElementInitializer) { IMethodSymbol addMethod = null; Lazy> arguments = new Lazy>(() => boundCollectionElementInitializer.Arguments.SelectAsArray(n => Create(n))); bool isDynamic = true; SyntaxNode syntax = boundCollectionElementInitializer.Syntax; ITypeSymbol type = boundCollectionElementInitializer.Type; Optional constantValue = ConvertToOptional(boundCollectionElementInitializer.ConstantValue); bool isImplicit = boundCollectionElementInitializer.WasCompilerGenerated; return new LazyCollectionElementInitializerExpression(addMethod, isDynamic, arguments, _semanticModel, syntax, type, constantValue, isImplicit); } private IOperation CreateUnboundLambdaOperation(UnboundLambda unboundLambda) { // We want to ensure that we never see the UnboundLambda node, and that we don't end up having two different IOperation // nodes for the lambda expression. So, we ask the semantic model for the IOperation node for the unbound lambda syntax. // We are counting on the fact that will do the error recovery and actually create the BoundLambda node appropriate for // this syntax node. BoundLambda boundLambda = unboundLambda.BindForErrorRecovery(); return CreateInternal(boundLambda); } private IAnonymousFunctionOperation CreateBoundLambdaOperation(BoundLambda boundLambda) { IMethodSymbol symbol = boundLambda.Symbol; Lazy body = new Lazy(() => (IBlockOperation)Create(boundLambda.Body)); SyntaxNode syntax = boundLambda.Syntax; // This matches the SemanticModel implementation. This is because in VB, lambdas by themselves // do not have a type. To get the type of a lambda expression in the SemanticModel, you need to look at // TypeInfo.ConvertedType, rather than TypeInfo.Type. We replicate that behavior here. To get the type of // an IAnonymousFunctionExpression, you need to look at the parent IConversionExpression. ITypeSymbol type = null; Optional constantValue = ConvertToOptional(boundLambda.ConstantValue); bool isImplicit = boundLambda.WasCompilerGenerated; return new LazyAnonymousFunctionExpression(symbol, body, _semanticModel, syntax, type, constantValue, isImplicit); } private ILocalFunctionOperation CreateBoundLocalFunctionStatementOperation(BoundLocalFunctionStatement boundLocalFunctionStatement) { IMethodSymbol symbol = boundLocalFunctionStatement.Symbol; Lazy body = new Lazy(() => (IBlockOperation)Create(boundLocalFunctionStatement.Body)); SyntaxNode syntax = boundLocalFunctionStatement.Syntax; ITypeSymbol type = null; Optional constantValue = default(Optional); bool isImplicit = boundLocalFunctionStatement.WasCompilerGenerated; return new LazyLocalFunctionStatement(symbol, body, _semanticModel, syntax, type, constantValue, isImplicit); } private IOperation CreateBoundConversionOperation(BoundConversion boundConversion) { bool isImplicit = boundConversion.WasCompilerGenerated || !boundConversion.ExplicitCastInCode; BoundExpression boundOperand = boundConversion.Operand; if (boundConversion.ConversionKind == CSharp.ConversionKind.MethodGroup) { // We don't check HasErrors on the conversion here because if we actually have a MethodGroup conversion, // overload resolution succeeded. The resulting method could be invalid for other reasons, but we don't // hide the resolved method. Lazy target = new Lazy(() => CreateBoundMethodGroupSingleMethodOperation((BoundMethodGroup)boundOperand, boundConversion.SymbolOpt, boundConversion.SuppressVirtualCalls)); SyntaxNode syntax = boundConversion.Syntax; ITypeSymbol type = boundConversion.Type; Optional constantValue = ConvertToOptional(boundConversion.ConstantValue); return new LazyDelegateCreationExpression(target, _semanticModel, syntax, type, constantValue, isImplicit); } else { SyntaxNode syntax = boundConversion.Syntax; if (syntax.IsMissing) { // If the underlying syntax IsMissing, then that means we're in case where the compiler generated a piece of syntax to fill in for // an error, such as this case: // // int i = ; // // Semantic model has a special case here that we match: if the underlying syntax is missing, don't create a conversion expression, // and instead directly return the operand, which will be a BoundBadExpression. When we generate a node for the BoundBadExpression, // the resulting IOperation will also have a null Type. Debug.Assert(boundOperand.Kind == BoundKind.BadExpression || ((boundOperand as BoundLambda)?.Body.Statements.SingleOrDefault() as BoundReturnStatement)?. ExpressionOpt?.Kind == BoundKind.BadExpression); return Create(boundOperand); } Lazy operand = null; Conversion conversion = boundConversion.Conversion; if (boundOperand.Syntax == boundConversion.Syntax) { if (boundOperand.Kind == BoundKind.ConvertedTupleLiteral && boundOperand.Type == boundConversion.Type) { // Erase this conversion, this is an artificial conversion added on top of BoundConvertedTupleLiteral // in Binder.CreateTupleLiteralConversion return Create(boundOperand); } else { // Make this conversion implicit isImplicit = true; } } if (boundConversion.ExplicitCastInCode && conversion.IsIdentity && boundOperand.Kind == BoundKind.Conversion) { var nestedConversion = (BoundConversion)boundOperand; BoundExpression nestedOperand = nestedConversion.Operand; if (nestedConversion.Syntax == nestedOperand.Syntax && nestedConversion.ExplicitCastInCode && nestedOperand.Kind == BoundKind.ConvertedTupleLiteral && nestedConversion.Type != nestedOperand.Type) { // Let's erase the nested conversion, this is an artificial conversion added on top of BoundConvertedTupleLiteral // in Binder.CreateTupleLiteralConversion. // We need to use conversion information from the nested conversion because that is where the real conversion // information is stored. conversion = nestedConversion.Conversion; operand = new Lazy(() => Create(nestedOperand)); } } if (operand == null) { operand = new Lazy(() => Create(boundOperand)); } ITypeSymbol type = boundConversion.Type; Optional constantValue = ConvertToOptional(boundConversion.ConstantValue); // If this is a lambda or method group conversion to a delegate type, we return a delegate creation instead of a conversion if ((boundOperand.Kind == BoundKind.Lambda || boundOperand.Kind == BoundKind.UnboundLambda || boundOperand.Kind == BoundKind.MethodGroup) && boundConversion.Type.IsDelegateType()) { return new LazyDelegateCreationExpression(operand, _semanticModel, syntax, type, constantValue, isImplicit); } else { bool isTryCast = false; // Checked conversions only matter if the conversion is a Numeric conversion. Don't have true unless the conversion is actually numeric. bool isChecked = conversion.IsNumeric && boundConversion.Checked; return new LazyConversionOperation(operand, conversion, isTryCast, isChecked, _semanticModel, syntax, type, constantValue, isImplicit); } } } private IConversionOperation CreateBoundAsOperatorOperation(BoundAsOperator boundAsOperator) { Lazy operand = new Lazy(() => Create(boundAsOperator.Operand)); SyntaxNode syntax = boundAsOperator.Syntax; Conversion conversion = boundAsOperator.Conversion; bool isTryCast = true; bool isChecked = false; ITypeSymbol type = boundAsOperator.Type; Optional constantValue = ConvertToOptional(boundAsOperator.ConstantValue); bool isImplicit = boundAsOperator.WasCompilerGenerated; return new LazyConversionOperation(operand, conversion, isTryCast, isChecked, _semanticModel, syntax, type, constantValue, isImplicit); } private IDelegateCreationOperation CreateBoundDelegateCreationExpressionOperation(BoundDelegateCreationExpression boundDelegateCreationExpression) { Lazy target = new Lazy(() => { if (boundDelegateCreationExpression.Argument.Kind == BoundKind.MethodGroup && boundDelegateCreationExpression.MethodOpt != null) { // If this is a method binding, and a valid candidate method was found, then we want to expose // this child as an IMethodBindingReference. Otherwise, we want to just delegate to the standard // CSharpOperationFactory behavior. Note we don't check HasErrors here because if we have a method group, // overload resolution succeeded, even if the resulting method isn't valid for some other reason. BoundMethodGroup boundMethodGroup = (BoundMethodGroup)boundDelegateCreationExpression.Argument; return CreateBoundMethodGroupSingleMethodOperation(boundMethodGroup, boundDelegateCreationExpression.MethodOpt, boundMethodGroup.SuppressVirtualCalls); } else { return Create(boundDelegateCreationExpression.Argument); } }); SyntaxNode syntax = boundDelegateCreationExpression.Syntax; ITypeSymbol type = boundDelegateCreationExpression.Type; Optional constantValue = ConvertToOptional(boundDelegateCreationExpression.ConstantValue); bool isImplicit = boundDelegateCreationExpression.WasCompilerGenerated; return new LazyDelegateCreationExpression(target, _semanticModel, syntax, type, constantValue, isImplicit); } private IMethodReferenceOperation CreateBoundMethodGroupSingleMethodOperation(BoundMethodGroup boundMethodGroup, IMethodSymbol methodSymbol, bool suppressVirtualCalls) { bool isVirtual = (methodSymbol.IsAbstract || methodSymbol.IsOverride || methodSymbol.IsVirtual) && !suppressVirtualCalls; Lazy instance = CreateReceiverOperation(boundMethodGroup.ReceiverOpt, methodSymbol); SyntaxNode bindingSyntax = boundMethodGroup.Syntax; ITypeSymbol bindingType = null; Optional bindingConstantValue = ConvertToOptional(boundMethodGroup.ConstantValue); bool isImplicit = boundMethodGroup.WasCompilerGenerated; return new LazyMethodReferenceExpression(methodSymbol, isVirtual, instance, _semanticModel, bindingSyntax, bindingType, bindingConstantValue, boundMethodGroup.WasCompilerGenerated); } private IIsTypeOperation CreateBoundIsOperatorOperation(BoundIsOperator boundIsOperator) { Lazy valueOperand = new Lazy(() => Create(boundIsOperator.Operand)); ITypeSymbol typeOperand = boundIsOperator.TargetType.Type; SyntaxNode syntax = boundIsOperator.Syntax; ITypeSymbol type = boundIsOperator.Type; bool isNegated = false; Optional constantValue = ConvertToOptional(boundIsOperator.ConstantValue); bool isImplicit = boundIsOperator.WasCompilerGenerated; return new LazyIsTypeExpression(valueOperand, typeOperand, isNegated, _semanticModel, syntax, type, constantValue, isImplicit); } private ISizeOfOperation CreateBoundSizeOfOperatorOperation(BoundSizeOfOperator boundSizeOfOperator) { ITypeSymbol typeOperand = boundSizeOfOperator.SourceType.Type; SyntaxNode syntax = boundSizeOfOperator.Syntax; ITypeSymbol type = boundSizeOfOperator.Type; Optional constantValue = ConvertToOptional(boundSizeOfOperator.ConstantValue); bool isImplicit = boundSizeOfOperator.WasCompilerGenerated; return new SizeOfExpression(typeOperand, _semanticModel, syntax, type, constantValue, isImplicit); } private ITypeOfOperation CreateBoundTypeOfOperatorOperation(BoundTypeOfOperator boundTypeOfOperator) { ITypeSymbol typeOperand = boundTypeOfOperator.SourceType.Type; SyntaxNode syntax = boundTypeOfOperator.Syntax; ITypeSymbol type = boundTypeOfOperator.Type; Optional constantValue = ConvertToOptional(boundTypeOfOperator.ConstantValue); bool isImplicit = boundTypeOfOperator.WasCompilerGenerated; return new TypeOfExpression(typeOperand, _semanticModel, syntax, type, constantValue, isImplicit); } private IArrayCreationOperation CreateBoundArrayCreationOperation(BoundArrayCreation boundArrayCreation) { Lazy> dimensionSizes = new Lazy>(() => boundArrayCreation.Bounds.SelectAsArray(n => Create(n))); Lazy initializer = new Lazy(() => (IArrayInitializerOperation)Create(boundArrayCreation.InitializerOpt)); SyntaxNode syntax = boundArrayCreation.Syntax; ITypeSymbol type = boundArrayCreation.Type; Optional constantValue = ConvertToOptional(boundArrayCreation.ConstantValue); bool isImplicit = boundArrayCreation.WasCompilerGenerated || (boundArrayCreation.InitializerOpt?.Syntax == syntax && !boundArrayCreation.InitializerOpt.WasCompilerGenerated); return new LazyArrayCreationExpression(dimensionSizes, initializer, _semanticModel, syntax, type, constantValue, isImplicit); } private IArrayInitializerOperation CreateBoundArrayInitializationOperation(BoundArrayInitialization boundArrayInitialization) { Lazy> elementValues = new Lazy>(() => boundArrayInitialization.Initializers.SelectAsArray(n => Create(n))); SyntaxNode syntax = boundArrayInitialization.Syntax; Optional constantValue = ConvertToOptional(boundArrayInitialization.ConstantValue); bool isImplicit = boundArrayInitialization.WasCompilerGenerated; return new LazyArrayInitializer(elementValues, _semanticModel, syntax, constantValue, isImplicit); } private IDefaultValueOperation CreateBoundDefaultExpressionOperation(BoundDefaultExpression boundDefaultExpression) { SyntaxNode syntax = boundDefaultExpression.Syntax; ITypeSymbol type = boundDefaultExpression.Type; Optional constantValue = ConvertToOptional(boundDefaultExpression.ConstantValue); bool isImplicit = boundDefaultExpression.WasCompilerGenerated; return new DefaultValueExpression(_semanticModel, syntax, type, constantValue, isImplicit); } private IInstanceReferenceOperation CreateBoundBaseReferenceOperation(BoundBaseReference boundBaseReference) { SyntaxNode syntax = boundBaseReference.Syntax; ITypeSymbol type = boundBaseReference.Type; Optional constantValue = ConvertToOptional(boundBaseReference.ConstantValue); bool isImplicit = boundBaseReference.WasCompilerGenerated; return new InstanceReferenceExpression(_semanticModel, syntax, type, constantValue, isImplicit); } private IInstanceReferenceOperation CreateBoundThisReferenceOperation(BoundThisReference boundThisReference) { SyntaxNode syntax = boundThisReference.Syntax; ITypeSymbol type = boundThisReference.Type; Optional constantValue = ConvertToOptional(boundThisReference.ConstantValue); bool isImplicit = boundThisReference.WasCompilerGenerated; return new InstanceReferenceExpression(_semanticModel, syntax, type, constantValue, isImplicit); } private IOperation CreateBoundAssignmentOperatorOrMemberInitializerOperation(BoundAssignmentOperator boundAssignmentOperator) { return IsMemberInitializer(boundAssignmentOperator) ? (IOperation)CreateBoundMemberInitializerOperation(boundAssignmentOperator) : CreateBoundAssignmentOperatorOperation(boundAssignmentOperator); } private static bool IsMemberInitializer(BoundAssignmentOperator boundAssignmentOperator) => boundAssignmentOperator.Right?.Kind == BoundKind.ObjectInitializerExpression || boundAssignmentOperator.Right?.Kind == BoundKind.CollectionInitializerExpression; private ISimpleAssignmentOperation CreateBoundAssignmentOperatorOperation(BoundAssignmentOperator boundAssignmentOperator) { Debug.Assert(!IsMemberInitializer(boundAssignmentOperator)); Lazy target = new Lazy(() => Create(boundAssignmentOperator.Left)); bool isRef = boundAssignmentOperator.IsRef; Lazy value = new Lazy(() => Create(boundAssignmentOperator.Right)); SyntaxNode syntax = boundAssignmentOperator.Syntax; ITypeSymbol type = boundAssignmentOperator.Type; Optional constantValue = ConvertToOptional(boundAssignmentOperator.ConstantValue); bool isImplicit = boundAssignmentOperator.WasCompilerGenerated; return new LazySimpleAssignmentExpression(target, isRef, value, _semanticModel, syntax, type, constantValue, isImplicit); } private IMemberInitializerOperation CreateBoundMemberInitializerOperation(BoundAssignmentOperator boundAssignmentOperator) { Debug.Assert(IsMemberInitializer(boundAssignmentOperator)); Lazy target = new Lazy(() => Create(boundAssignmentOperator.Left)); Lazy value = new Lazy(() => (IObjectOrCollectionInitializerOperation)Create(boundAssignmentOperator.Right)); SyntaxNode syntax = boundAssignmentOperator.Syntax; ITypeSymbol type = boundAssignmentOperator.Type; Optional constantValue = ConvertToOptional(boundAssignmentOperator.ConstantValue); bool isImplicit = boundAssignmentOperator.WasCompilerGenerated; return new LazyMemberInitializerExpression(target, value, _semanticModel, syntax, type, constantValue, isImplicit); } private ICompoundAssignmentOperation CreateBoundCompoundAssignmentOperatorOperation(BoundCompoundAssignmentOperator boundCompoundAssignmentOperator) { BinaryOperatorKind operatorKind = Helper.DeriveBinaryOperatorKind(boundCompoundAssignmentOperator.Operator.Kind); Lazy target = new Lazy(() => Create(boundCompoundAssignmentOperator.Left)); Lazy value = new Lazy(() => Create(boundCompoundAssignmentOperator.Right)); Conversion inConversion = boundCompoundAssignmentOperator.LeftConversion; Conversion outConversion = boundCompoundAssignmentOperator.FinalConversion; bool isLifted = boundCompoundAssignmentOperator.Operator.Kind.IsLifted(); bool isChecked = boundCompoundAssignmentOperator.Operator.Kind.IsChecked(); IMethodSymbol operatorMethod = boundCompoundAssignmentOperator.Operator.Method; SyntaxNode syntax = boundCompoundAssignmentOperator.Syntax; ITypeSymbol type = boundCompoundAssignmentOperator.Type; Optional constantValue = ConvertToOptional(boundCompoundAssignmentOperator.ConstantValue); bool isImplicit = boundCompoundAssignmentOperator.WasCompilerGenerated; return new LazyCompoundAssignmentOperation(target, value, inConversion, outConversion, operatorKind, isLifted, isChecked, operatorMethod, _semanticModel, syntax, type, constantValue, isImplicit); } private IIncrementOrDecrementOperation CreateBoundIncrementOperatorOperation(BoundIncrementOperator boundIncrementOperator) { bool isDecrement = Helper.IsDecrement(boundIncrementOperator.OperatorKind); bool isPostfix = Helper.IsPostfixIncrementOrDecrement(boundIncrementOperator.OperatorKind); bool isLifted = boundIncrementOperator.OperatorKind.IsLifted(); bool isChecked = boundIncrementOperator.OperatorKind.IsChecked(); Lazy target = new Lazy(() => Create(boundIncrementOperator.Operand)); IMethodSymbol operatorMethod = boundIncrementOperator.MethodOpt; SyntaxNode syntax = boundIncrementOperator.Syntax; ITypeSymbol type = boundIncrementOperator.Type; Optional constantValue = ConvertToOptional(boundIncrementOperator.ConstantValue); bool isImplicit = boundIncrementOperator.WasCompilerGenerated; return new LazyIncrementExpression(isDecrement, isPostfix, isLifted, isChecked, target, operatorMethod, _semanticModel, syntax, type, constantValue, isImplicit); } private IInvalidOperation CreateBoundBadExpressionOperation(BoundBadExpression boundBadExpression) { Lazy> children = new Lazy>(() => boundBadExpression.ChildBoundNodes.Select(n => Create(n)).WhereNotNull().ToImmutableArray()); SyntaxNode syntax = boundBadExpression.Syntax; // We match semantic model here: if the expression IsMissing, we have a null type, rather than the ErrorType of the bound node. ITypeSymbol type = syntax.IsMissing ? null : boundBadExpression.Type; Optional constantValue = ConvertToOptional(boundBadExpression.ConstantValue); // if child has syntax node point to same syntax node as bad expression, then this invalid expression is implicit bool isImplicit = boundBadExpression.WasCompilerGenerated || boundBadExpression.ChildBoundNodes.Any(e => e?.Syntax == boundBadExpression.Syntax); return new LazyInvalidOperation(children, _semanticModel, syntax, type, constantValue, isImplicit); } private ITypeParameterObjectCreationOperation CreateBoundNewTOperation(BoundNewT boundNewT) { Lazy initializer = new Lazy(() => (IObjectOrCollectionInitializerOperation)Create(boundNewT.InitializerExpressionOpt)); SyntaxNode syntax = boundNewT.Syntax; ITypeSymbol type = boundNewT.Type; Optional constantValue = ConvertToOptional(boundNewT.ConstantValue); bool isImplicit = boundNewT.WasCompilerGenerated; return new LazyTypeParameterObjectCreationExpression(initializer, _semanticModel, syntax, type, constantValue, isImplicit); } private IUnaryOperation CreateBoundUnaryOperatorOperation(BoundUnaryOperator boundUnaryOperator) { UnaryOperatorKind unaryOperatorKind = Helper.DeriveUnaryOperatorKind(boundUnaryOperator.OperatorKind); Lazy operand = new Lazy(() => Create(boundUnaryOperator.Operand)); IMethodSymbol operatorMethod = boundUnaryOperator.MethodOpt; SyntaxNode syntax = boundUnaryOperator.Syntax; ITypeSymbol type = boundUnaryOperator.Type; Optional constantValue = ConvertToOptional(boundUnaryOperator.ConstantValue); bool isLifted = boundUnaryOperator.OperatorKind.IsLifted(); bool isChecked = boundUnaryOperator.OperatorKind.IsChecked(); bool isImplicit = boundUnaryOperator.WasCompilerGenerated; return new LazyUnaryOperatorExpression(unaryOperatorKind, operand, isLifted, isChecked, operatorMethod, _semanticModel, syntax, type, constantValue, isImplicit); } private IBinaryOperation CreateBoundBinaryOperatorOperation(BoundBinaryOperator boundBinaryOperator) { BinaryOperatorKind operatorKind = Helper.DeriveBinaryOperatorKind(boundBinaryOperator.OperatorKind); Lazy leftOperand = new Lazy(() => Create(boundBinaryOperator.Left)); Lazy rightOperand = new Lazy(() => Create(boundBinaryOperator.Right)); IMethodSymbol operatorMethod = boundBinaryOperator.MethodOpt; SyntaxNode syntax = boundBinaryOperator.Syntax; ITypeSymbol type = boundBinaryOperator.Type; Optional constantValue = ConvertToOptional(boundBinaryOperator.ConstantValue); bool isLifted = boundBinaryOperator.OperatorKind.IsLifted(); bool isChecked = boundBinaryOperator.OperatorKind.IsChecked(); bool isCompareText = false; bool isImplicit = boundBinaryOperator.WasCompilerGenerated; return new LazyBinaryOperatorExpression(operatorKind, leftOperand, rightOperand, isLifted, isChecked, isCompareText, operatorMethod, _semanticModel, syntax, type, constantValue, isImplicit); } private IConditionalOperation CreateBoundConditionalOperatorOperation(BoundConditionalOperator boundConditionalOperator) { Lazy condition = new Lazy(() => Create(boundConditionalOperator.Condition)); Lazy whenTrue = new Lazy(() => Create(boundConditionalOperator.Consequence)); Lazy whenFalse = new Lazy(() => Create(boundConditionalOperator.Alternative)); bool isRef = boundConditionalOperator.IsRef; SyntaxNode syntax = boundConditionalOperator.Syntax; ITypeSymbol type = boundConditionalOperator.Type; Optional constantValue = ConvertToOptional(boundConditionalOperator.ConstantValue); bool isImplicit = boundConditionalOperator.WasCompilerGenerated; return new LazyConditionalOperation(condition, whenTrue, whenFalse, isRef, _semanticModel, syntax, type, constantValue, isImplicit); } private ICoalesceOperation CreateBoundNullCoalescingOperatorOperation(BoundNullCoalescingOperator boundNullCoalescingOperator) { Lazy expression = new Lazy(() => Create(boundNullCoalescingOperator.LeftOperand)); Lazy whenNull = new Lazy(() => Create(boundNullCoalescingOperator.RightOperand)); SyntaxNode syntax = boundNullCoalescingOperator.Syntax; ITypeSymbol type = boundNullCoalescingOperator.Type; Optional constantValue = ConvertToOptional(boundNullCoalescingOperator.ConstantValue); bool isImplicit = boundNullCoalescingOperator.WasCompilerGenerated; return new LazyCoalesceExpression(expression, whenNull, _semanticModel, syntax, type, constantValue, isImplicit); } private IAwaitOperation CreateBoundAwaitExpressionOperation(BoundAwaitExpression boundAwaitExpression) { Lazy awaitedValue = new Lazy(() => Create(boundAwaitExpression.Expression)); SyntaxNode syntax = boundAwaitExpression.Syntax; ITypeSymbol type = boundAwaitExpression.Type; Optional constantValue = ConvertToOptional(boundAwaitExpression.ConstantValue); bool isImplicit = boundAwaitExpression.WasCompilerGenerated; return new LazyAwaitExpression(awaitedValue, _semanticModel, syntax, type, constantValue, isImplicit); } private IArrayElementReferenceOperation CreateBoundArrayAccessOperation(BoundArrayAccess boundArrayAccess) { // The compiler will dedupe the boundArrayAccess.Expression between different array references. Some example code: // // class C // { // int[] a; // static void Main() // { // // Compiler dedupes the array access receiver for [0] and [1] // var a = new C { a = { [0] = 1, [1] = 2 } }; // } // } // // In order to prevent parent pointer from having an issue with this, we intentionally create a new IOperation node every time // we encounter an array access. Since we create from the top down, it should be impossible for us to see the node in // boundArrayAccess.Expression before seeing the boundArrayAccess itself, so this should not create any other parent pointer // issues. Lazy arrayReference = new Lazy(() => CreateInternal(boundArrayAccess.Expression)); Lazy> indices = new Lazy>(() => boundArrayAccess.Indices.SelectAsArray(n => Create(n))); SyntaxNode syntax = boundArrayAccess.Syntax; ITypeSymbol type = boundArrayAccess.Type; Optional constantValue = ConvertToOptional(boundArrayAccess.ConstantValue); bool isImplicit = boundArrayAccess.WasCompilerGenerated; return new LazyArrayElementReferenceExpression(arrayReference, indices, _semanticModel, syntax, type, constantValue, isImplicit); } private IPointerIndirectionReferenceOperation CreateBoundPointerIndirectionOperatorOperation(BoundPointerIndirectionOperator boundPointerIndirectionOperator) { Lazy pointer = new Lazy(() => Create(boundPointerIndirectionOperator.Operand)); SyntaxNode syntax = boundPointerIndirectionOperator.Syntax; ITypeSymbol type = boundPointerIndirectionOperator.Type; Optional constantValue = ConvertToOptional(boundPointerIndirectionOperator.ConstantValue); bool isImplicit = boundPointerIndirectionOperator.WasCompilerGenerated; return new LazyPointerIndirectionReferenceExpression(pointer, _semanticModel, syntax, type, constantValue, isImplicit); } private INameOfOperation CreateBoundNameOfOperatorOperation(BoundNameOfOperator boundNameOfOperator) { Lazy argument = new Lazy(() => Create(boundNameOfOperator.Argument)); SyntaxNode syntax = boundNameOfOperator.Syntax; ITypeSymbol type = boundNameOfOperator.Type; Optional constantValue = ConvertToOptional(boundNameOfOperator.ConstantValue); bool isImplicit = boundNameOfOperator.WasCompilerGenerated; return new LazyNameOfExpression(argument, _semanticModel, syntax, type, constantValue, isImplicit); } private IThrowOperation CreateBoundThrowExpressionOperation(BoundThrowExpression boundThrowExpression) { Lazy expression = new Lazy(() => Create(boundThrowExpression.Expression)); SyntaxNode syntax = boundThrowExpression.Syntax; ITypeSymbol type = boundThrowExpression.Type; Optional constantValue = ConvertToOptional(boundThrowExpression.ConstantValue); bool isImplicit = boundThrowExpression.WasCompilerGenerated; return new LazyThrowExpression(expression, _semanticModel, syntax, type, constantValue, isImplicit); } private IAddressOfOperation CreateBoundAddressOfOperatorOperation(BoundAddressOfOperator boundAddressOfOperator) { Lazy reference = new Lazy(() => Create(boundAddressOfOperator.Operand)); SyntaxNode syntax = boundAddressOfOperator.Syntax; ITypeSymbol type = boundAddressOfOperator.Type; Optional constantValue = ConvertToOptional(boundAddressOfOperator.ConstantValue); bool isImplicit = boundAddressOfOperator.WasCompilerGenerated; return new LazyAddressOfExpression(reference, _semanticModel, syntax, type, constantValue, isImplicit); } private IInstanceReferenceOperation CreateBoundImplicitReceiverOperation(BoundImplicitReceiver boundImplicitReceiver) { SyntaxNode syntax = boundImplicitReceiver.Syntax; ITypeSymbol type = boundImplicitReceiver.Type; Optional constantValue = ConvertToOptional(boundImplicitReceiver.ConstantValue); bool isImplicit = boundImplicitReceiver.WasCompilerGenerated; return new InstanceReferenceExpression(_semanticModel, syntax, type, constantValue, isImplicit); } private IConditionalAccessOperation CreateBoundConditionalAccessOperation(BoundConditionalAccess boundConditionalAccess) { Lazy whenNotNull = new Lazy(() => Create(boundConditionalAccess.AccessExpression)); Lazy expression = new Lazy(() => Create(boundConditionalAccess.Receiver)); SyntaxNode syntax = boundConditionalAccess.Syntax; ITypeSymbol type = boundConditionalAccess.Type; Optional constantValue = ConvertToOptional(boundConditionalAccess.ConstantValue); bool isImplicit = boundConditionalAccess.WasCompilerGenerated; return new LazyConditionalAccessExpression(whenNotNull, expression, _semanticModel, syntax, type, constantValue, isImplicit); } private IConditionalAccessInstanceOperation CreateBoundConditionalReceiverOperation(BoundConditionalReceiver boundConditionalReceiver) { SyntaxNode syntax = boundConditionalReceiver.Syntax; ITypeSymbol type = boundConditionalReceiver.Type; Optional constantValue = ConvertToOptional(boundConditionalReceiver.ConstantValue); bool isImplicit = boundConditionalReceiver.WasCompilerGenerated; return new ConditionalAccessInstanceExpression(_semanticModel, syntax, type, constantValue, isImplicit); } private IFieldInitializerOperation CreateBoundFieldEqualsValueOperation(BoundFieldEqualsValue boundFieldEqualsValue) { ImmutableArray initializedFields = ImmutableArray.Create(boundFieldEqualsValue.Field); Lazy value = new Lazy(() => Create(boundFieldEqualsValue.Value)); OperationKind kind = OperationKind.FieldInitializer; SyntaxNode syntax = boundFieldEqualsValue.Syntax; ITypeSymbol type = null; Optional constantValue = default(Optional); bool isImplicit = boundFieldEqualsValue.WasCompilerGenerated; return new LazyFieldInitializer(initializedFields, value, kind, _semanticModel, syntax, type, constantValue, isImplicit); } private IPropertyInitializerOperation CreateBoundPropertyEqualsValueOperation(BoundPropertyEqualsValue boundPropertyEqualsValue) { ImmutableArray initializedProperties = ImmutableArray.Create(boundPropertyEqualsValue.Property); Lazy value = new Lazy(() => Create(boundPropertyEqualsValue.Value)); OperationKind kind = OperationKind.PropertyInitializer; SyntaxNode syntax = boundPropertyEqualsValue.Syntax; ITypeSymbol type = null; Optional constantValue = default(Optional); bool isImplicit = boundPropertyEqualsValue.WasCompilerGenerated; return new LazyPropertyInitializer(initializedProperties, value, kind, _semanticModel, syntax, type, constantValue, isImplicit); } private IParameterInitializerOperation CreateBoundParameterEqualsValueOperation(BoundParameterEqualsValue boundParameterEqualsValue) { IParameterSymbol parameter = boundParameterEqualsValue.Parameter; Lazy value = new Lazy(() => Create(boundParameterEqualsValue.Value)); OperationKind kind = OperationKind.ParameterInitializer; SyntaxNode syntax = boundParameterEqualsValue.Syntax; ITypeSymbol type = null; Optional constantValue = default(Optional); bool isImplicit = boundParameterEqualsValue.WasCompilerGenerated; return new LazyParameterInitializer(parameter, value, kind, _semanticModel, syntax, type, constantValue, isImplicit); } private IBlockOperation CreateBoundBlockOperation(BoundBlock boundBlock) { Lazy> statements = new Lazy>(() => boundBlock.Statements.Select(s => (bound: s, operation: Create(s))) // Filter out all OperationKind.None except fixed statements for now. // https://github.com/dotnet/roslyn/issues/21776 .Where(s => s.operation.Kind != OperationKind.None || s.bound.Kind == BoundKind.FixedStatement) .Select(s => s.operation).ToImmutableArray()); ImmutableArray locals = boundBlock.Locals.As(); SyntaxNode syntax = boundBlock.Syntax; ITypeSymbol type = null; Optional constantValue = default(Optional); bool isImplicit = boundBlock.WasCompilerGenerated; return new LazyBlockStatement(statements, locals, _semanticModel, syntax, type, constantValue, isImplicit); } private IBranchOperation CreateBoundContinueStatementOperation(BoundContinueStatement boundContinueStatement) { ILabelSymbol target = boundContinueStatement.Label; BranchKind branchKind = BranchKind.Continue; SyntaxNode syntax = boundContinueStatement.Syntax; ITypeSymbol type = null; Optional constantValue = default(Optional); bool isImplicit = boundContinueStatement.WasCompilerGenerated; return new BranchStatement(target, branchKind, _semanticModel, syntax, type, constantValue, isImplicit); } private IBranchOperation CreateBoundBreakStatementOperation(BoundBreakStatement boundBreakStatement) { ILabelSymbol target = boundBreakStatement.Label; BranchKind branchKind = BranchKind.Break; SyntaxNode syntax = boundBreakStatement.Syntax; ITypeSymbol type = null; Optional constantValue = default(Optional); bool isImplicit = boundBreakStatement.WasCompilerGenerated; return new BranchStatement(target, branchKind, _semanticModel, syntax, type, constantValue, isImplicit); } private IReturnOperation CreateBoundYieldBreakStatementOperation(BoundYieldBreakStatement boundYieldBreakStatement) { Lazy returnedValue = new Lazy(() => Create(null)); SyntaxNode syntax = boundYieldBreakStatement.Syntax; ITypeSymbol type = null; Optional constantValue = default(Optional); bool isImplicit = boundYieldBreakStatement.WasCompilerGenerated; return new LazyReturnStatement(OperationKind.YieldBreak, returnedValue, _semanticModel, syntax, type, constantValue, isImplicit); } private IBranchOperation CreateBoundGotoStatementOperation(BoundGotoStatement boundGotoStatement) { ILabelSymbol target = boundGotoStatement.Label; BranchKind branchKind = BranchKind.GoTo; SyntaxNode syntax = boundGotoStatement.Syntax; ITypeSymbol type = null; Optional constantValue = default(Optional); bool isImplicit = boundGotoStatement.WasCompilerGenerated; return new BranchStatement(target, branchKind, _semanticModel, syntax, type, constantValue, isImplicit); } private IEmptyOperation CreateBoundNoOpStatementOperation(BoundNoOpStatement boundNoOpStatement) { SyntaxNode syntax = boundNoOpStatement.Syntax; ITypeSymbol type = null; Optional constantValue = default(Optional); bool isImplicit = boundNoOpStatement.WasCompilerGenerated; return new EmptyStatement(_semanticModel, syntax, type, constantValue, isImplicit); } private IConditionalOperation CreateBoundIfStatementOperation(BoundIfStatement boundIfStatement) { Lazy condition = new Lazy(() => Create(boundIfStatement.Condition)); Lazy ifTrueStatement = new Lazy(() => Create(boundIfStatement.Consequence)); Lazy ifFalseStatement = new Lazy(() => Create(boundIfStatement.AlternativeOpt)); bool isRef = false; SyntaxNode syntax = boundIfStatement.Syntax; ITypeSymbol type = null; Optional constantValue = default(Optional); bool isImplicit = boundIfStatement.WasCompilerGenerated; return new LazyConditionalOperation(condition, ifTrueStatement, ifFalseStatement, isRef, _semanticModel, syntax, type, constantValue, isImplicit); } private IWhileLoopOperation CreateBoundWhileStatementOperation(BoundWhileStatement boundWhileStatement) { Lazy condition = new Lazy(() => Create(boundWhileStatement.Condition)); Lazy body = new Lazy(() => Create(boundWhileStatement.Body)); Lazy ignoredCondition = OperationFactory.NullOperation; ImmutableArray locals = boundWhileStatement.Locals.As(); bool conditionIsTop = true; bool conditionIsUntil = false; SyntaxNode syntax = boundWhileStatement.Syntax; ITypeSymbol type = null; Optional constantValue = default(Optional); bool isImplicit = boundWhileStatement.WasCompilerGenerated; return new LazyWhileLoopStatement(condition, body, ignoredCondition, locals, conditionIsTop, conditionIsUntil, _semanticModel, syntax, type, constantValue, isImplicit); } private IWhileLoopOperation CreateBoundDoStatementOperation(BoundDoStatement boundDoStatement) { Lazy condition = new Lazy(() => Create(boundDoStatement.Condition)); Lazy body = new Lazy(() => Create(boundDoStatement.Body)); Lazy ignoredCondition = OperationFactory.NullOperation; bool conditionIsTop = false; bool conditionIsUntil = false; ImmutableArray locals = boundDoStatement.Locals.As(); SyntaxNode syntax = boundDoStatement.Syntax; ITypeSymbol type = null; Optional constantValue = default(Optional); bool isImplicit = boundDoStatement.WasCompilerGenerated; return new LazyWhileLoopStatement(condition, body, ignoredCondition, locals, conditionIsTop, conditionIsUntil, _semanticModel, syntax, type, constantValue, isImplicit); } private IForLoopOperation CreateBoundForStatementOperation(BoundForStatement boundForStatement) { Lazy> before = new Lazy>(() => ToStatements(boundForStatement.Initializer)); Lazy condition = new Lazy(() => Create(boundForStatement.Condition)); Lazy> atLoopBottom = new Lazy>(() => ToStatements(boundForStatement.Increment)); ImmutableArray locals = boundForStatement.OuterLocals.As(); Lazy body = new Lazy(() => Create(boundForStatement.Body)); SyntaxNode syntax = boundForStatement.Syntax; ITypeSymbol type = null; Optional constantValue = default(Optional); bool isImplicit = boundForStatement.WasCompilerGenerated; return new LazyForLoopStatement(before, condition, atLoopBottom, locals, body, _semanticModel, syntax, type, constantValue, isImplicit); } private IForEachLoopOperation CreateBoundForEachStatementOperation(BoundForEachStatement boundForEachStatement) { ImmutableArray locals = boundForEachStatement.IterationVariables.As(); Lazy loopControlVariable; if (boundForEachStatement.DeconstructionOpt != null) { loopControlVariable = new Lazy(() => Create(boundForEachStatement.DeconstructionOpt.DeconstructionAssignment.Left)); } else if (locals.Length == 1) { var local = (LocalSymbol)locals.Single(); // We use iteration variable type syntax as the underlying syntax node as there is no variable declarator syntax in the syntax tree. var declaratorSyntax = boundForEachStatement.IterationVariableType.Syntax; loopControlVariable = new Lazy(() => new VariableDeclarator(local, initializer: null, ignoredArguments: ImmutableArray.Empty, semanticModel: _semanticModel, syntax: declaratorSyntax, type: null, constantValue: default, isImplicit: false)); } else { loopControlVariable = OperationFactory.NullOperation; } Lazy collection = new Lazy(() => Create(boundForEachStatement.Expression)); Lazy body = new Lazy(() => Create(boundForEachStatement.Body)); Lazy> nextVariables = new Lazy>(() => ImmutableArray.Empty); SyntaxNode syntax = boundForEachStatement.Syntax; ITypeSymbol type = null; Optional constantValue = default(Optional); bool isImplicit = boundForEachStatement.WasCompilerGenerated; return new LazyForEachLoopStatement(locals, loopControlVariable, collection, nextVariables, body, _semanticModel, syntax, type, constantValue, isImplicit); } private ISwitchOperation CreateBoundSwitchStatementOperation(BoundSwitchStatement boundSwitchStatement) { Lazy value = new Lazy(() => Create(boundSwitchStatement.Expression)); Lazy> cases = new Lazy>(() => GetSwitchStatementCases(boundSwitchStatement)); SyntaxNode syntax = boundSwitchStatement.Syntax; ITypeSymbol type = null; Optional constantValue = default(Optional); bool isImplicit = boundSwitchStatement.WasCompilerGenerated; return new LazySwitchStatement(value, cases, _semanticModel, syntax, type, constantValue, isImplicit); } private ICaseClauseOperation CreateBoundSwitchLabelOperation(BoundSwitchLabel boundSwitchLabel) { SyntaxNode syntax = boundSwitchLabel.Syntax; ITypeSymbol type = null; Optional constantValue = default(Optional); bool isImplicit = boundSwitchLabel.WasCompilerGenerated; if (boundSwitchLabel.ExpressionOpt != null) { Lazy value = new Lazy(() => Create(boundSwitchLabel.ExpressionOpt)); return new LazySingleValueCaseClause(value, _semanticModel, syntax, type, constantValue, isImplicit); } else { return new DefaultCaseClause(_semanticModel, syntax, type, constantValue, isImplicit); } } private ITryOperation CreateBoundTryStatementOperation(BoundTryStatement boundTryStatement) { Lazy body = new Lazy(() => (IBlockOperation)Create(boundTryStatement.TryBlock)); Lazy> catches = new Lazy>(() => boundTryStatement.CatchBlocks.SelectAsArray(n => (ICatchClauseOperation)Create(n))); Lazy finallyHandler = new Lazy(() => (IBlockOperation)Create(boundTryStatement.FinallyBlockOpt)); SyntaxNode syntax = boundTryStatement.Syntax; ITypeSymbol type = null; Optional constantValue = default(Optional); bool isImplicit = boundTryStatement.WasCompilerGenerated; return new LazyTryStatement(body, catches, finallyHandler, _semanticModel, syntax, type, constantValue, isImplicit); } private ICatchClauseOperation CreateBoundCatchBlockOperation(BoundCatchBlock boundCatchBlock) { var exceptionSourceOpt = (BoundLocal)boundCatchBlock.ExceptionSourceOpt; Lazy expressionDeclarationOrExpression = new Lazy(() => exceptionSourceOpt != null ? CreateVariableDeclarator(exceptionSourceOpt) : null); ITypeSymbol exceptionType = boundCatchBlock.ExceptionTypeOpt; ImmutableArray locals = boundCatchBlock.Locals.As(); Lazy filter = new Lazy(() => Create(boundCatchBlock.ExceptionFilterOpt)); Lazy handler = new Lazy(() => (IBlockOperation)Create(boundCatchBlock.Body)); SyntaxNode syntax = boundCatchBlock.Syntax; ITypeSymbol type = null; Optional constantValue = default(Optional); bool isImplicit = boundCatchBlock.WasCompilerGenerated; return new LazyCatchClause(expressionDeclarationOrExpression, exceptionType, locals, filter, handler, _semanticModel, syntax, type, constantValue, isImplicit); } private IFixedOperation CreateBoundFixedStatementOperation(BoundFixedStatement boundFixedStatement) { Lazy variables = new Lazy(() => (IVariableDeclarationGroupOperation)Create(boundFixedStatement.Declarations)); Lazy body = new Lazy(() => Create(boundFixedStatement.Body)); SyntaxNode syntax = boundFixedStatement.Syntax; ITypeSymbol type = null; Optional constantValue = default(Optional); bool isImplicit = boundFixedStatement.WasCompilerGenerated; return new LazyFixedStatement(variables, body, _semanticModel, syntax, type, constantValue, isImplicit); } private IUsingOperation CreateBoundUsingStatementOperation(BoundUsingStatement boundUsingStatement) { Lazy resources = new Lazy(() => Create((BoundNode)boundUsingStatement.DeclarationsOpt ?? boundUsingStatement.ExpressionOpt)); Lazy body = new Lazy(() => Create(boundUsingStatement.Body)); SyntaxNode syntax = boundUsingStatement.Syntax; ITypeSymbol type = null; Optional constantValue = default(Optional); bool isImplicit = boundUsingStatement.WasCompilerGenerated; return new LazyUsingStatement(resources, body, _semanticModel, syntax, type, constantValue, isImplicit); } private IThrowOperation CreateBoundThrowStatementOperation(BoundThrowStatement boundThrowStatement) { Lazy thrownObject = new Lazy(() => Create(boundThrowStatement.ExpressionOpt)); SyntaxNode syntax = boundThrowStatement.Syntax; ITypeSymbol statementType = null; Optional constantValue = default(Optional); bool isImplicit = boundThrowStatement.WasCompilerGenerated; return new LazyThrowExpression(thrownObject, _semanticModel, syntax, statementType, constantValue, isImplicit); } private IReturnOperation CreateBoundReturnStatementOperation(BoundReturnStatement boundReturnStatement) { Lazy returnedValue = new Lazy(() => Create(boundReturnStatement.ExpressionOpt)); SyntaxNode syntax = boundReturnStatement.Syntax; ITypeSymbol type = null; Optional constantValue = default(Optional); bool isImplicit = boundReturnStatement.WasCompilerGenerated; return new LazyReturnStatement(OperationKind.Return, returnedValue, _semanticModel, syntax, type, constantValue, isImplicit); } private IReturnOperation CreateBoundYieldReturnStatementOperation(BoundYieldReturnStatement boundYieldReturnStatement) { Lazy returnedValue = new Lazy(() => Create(boundYieldReturnStatement.Expression)); SyntaxNode syntax = boundYieldReturnStatement.Syntax; ITypeSymbol type = null; Optional constantValue = default(Optional); bool isImplicit = boundYieldReturnStatement.WasCompilerGenerated; return new LazyReturnStatement(OperationKind.YieldReturn, returnedValue, _semanticModel, syntax, type, constantValue, isImplicit); } private ILockOperation CreateBoundLockStatementOperation(BoundLockStatement boundLockStatement) { Lazy expression = new Lazy(() => Create(boundLockStatement.Argument)); Lazy body = new Lazy(() => Create(boundLockStatement.Body)); SyntaxNode syntax = boundLockStatement.Syntax; ITypeSymbol type = null; Optional constantValue = default(Optional); bool isImplicit = boundLockStatement.WasCompilerGenerated; return new LazyLockStatement(expression, body, _semanticModel, syntax, type, constantValue, isImplicit); } private IInvalidOperation CreateBoundBadStatementOperation(BoundBadStatement boundBadStatement) { Lazy> children = new Lazy>(() => boundBadStatement.ChildBoundNodes.Select(n => Create(n)).WhereNotNull().ToImmutableArray()); SyntaxNode syntax = boundBadStatement.Syntax; ITypeSymbol type = null; Optional constantValue = default(Optional); // if child has syntax node point to same syntax node as bad statement, then this invalid statement is implicit bool isImplicit = boundBadStatement.WasCompilerGenerated || boundBadStatement.ChildBoundNodes.Any(e => e?.Syntax == boundBadStatement.Syntax); return new LazyInvalidOperation(children, _semanticModel, syntax, type, constantValue, isImplicit); } private IOperation CreateBoundLocalDeclarationOperation(BoundLocalDeclaration boundLocalDeclaration) { var node = boundLocalDeclaration.Syntax; var kind = node.Kind(); SyntaxNode varStatement; SyntaxNode varDeclaration; SyntaxNode varDeclarator; switch (kind) { case SyntaxKind.LocalDeclarationStatement: { var statement = (LocalDeclarationStatementSyntax)node; // this happen for simple int i = 0; // var statement points to LocalDeclarationStatementSyntax varStatement = statement; varDeclaration = statement.Declaration; varDeclarator = statement.Declaration.Variables.First(); break; } case SyntaxKind.VariableDeclarator: { // this happen for 'for loop' initializer // We generate a DeclarationGroup for this scenario to maintain tree shape consistency across IOperation. // var statement points to VariableDeclarationSyntax varStatement = node.Parent; varDeclaration = node.Parent; // var declaration points to VariableDeclaratorSyntax varDeclarator = node; break; } default: { Debug.Fail($"Unexpected syntax: {kind}"); // otherwise, they points to whatever bound nodes are pointing to. varStatement = varDeclaration = varDeclarator = node; break; } } Lazy> declarations = new Lazy>(() => ImmutableArray.Create(CreateVariableDeclaratorInternal(boundLocalDeclaration, varDeclarator))); bool multiVariableImplicit = boundLocalDeclaration.WasCompilerGenerated; // In C#, the MultiVariable initializer will always be null, but we can't pass null as the actual lazy. We assume that all lazy elements always exist Lazy initializer = OperationFactory.NullInitializer; IVariableDeclarationOperation multiVariableDeclaration = new LazyVariableDeclaration(declarations, initializer, _semanticModel, varDeclaration, null, default, multiVariableImplicit); ITypeSymbol type = null; Optional constantValue = default(Optional); // In the case of a for loop, varStatement and varDeclaration will be the same syntax node. // We can only have one explicit operation, so make sure this node is implicit in that scenario. bool isImplicit = (varStatement == varDeclaration) || boundLocalDeclaration.WasCompilerGenerated; return new VariableDeclarationGroupOperation(ImmutableArray.Create(multiVariableDeclaration), _semanticModel, varStatement, type, constantValue, isImplicit); } private IVariableDeclarationGroupOperation CreateBoundMultipleLocalDeclarationsOperation(BoundMultipleLocalDeclarations boundMultipleLocalDeclarations) { Lazy> declarators = new Lazy>(() => boundMultipleLocalDeclarations.LocalDeclarations.SelectAsArray(declaration => CreateVariableDeclarator(declaration))); // In C#, the MultiVariable initializer will always be null, but we can't pass null as the actual lazy. We assume that all lazy elements always exist Lazy initializer = OperationFactory.NullInitializer; // The syntax for the boundMultipleLocalDeclarations can either be a LocalDeclarationStatement or a VariableDeclaration, depending on the context // (using/fixed statements vs variable declaration) // We generate a DeclarationGroup for these scenarios (using/fixed) to maintain tree shape consistency across IOperation. SyntaxNode declarationGroupSyntax = boundMultipleLocalDeclarations.Syntax; SyntaxNode declarationSyntax = declarationGroupSyntax.IsKind(SyntaxKind.LocalDeclarationStatement) ? ((LocalDeclarationStatementSyntax)declarationGroupSyntax).Declaration : declarationGroupSyntax; bool declarationIsImplicit = boundMultipleLocalDeclarations.WasCompilerGenerated; IVariableDeclarationOperation multiVariableDeclaration = new LazyVariableDeclaration(declarators, initializer, _semanticModel, declarationSyntax, null, default, declarationIsImplicit); ITypeSymbol type = null; Optional constantValue = default(Optional); // If the syntax was the same, we're in a fixed statement or using statement. We make the Group operation implicit in this scenario, as the // syntax itself is a VariableDeclaration bool isImplicit = declarationGroupSyntax == declarationSyntax || boundMultipleLocalDeclarations.WasCompilerGenerated; return new VariableDeclarationGroupOperation(ImmutableArray.Create(multiVariableDeclaration), _semanticModel, declarationGroupSyntax, type, constantValue, isImplicit); } private ILabeledOperation CreateBoundLabelStatementOperation(BoundLabelStatement boundLabelStatement) { ILabelSymbol label = boundLabelStatement.Label; Lazy statement = new Lazy(() => Create(null)); SyntaxNode syntax = boundLabelStatement.Syntax; ITypeSymbol type = null; Optional constantValue = default(Optional); bool isImplicit = boundLabelStatement.WasCompilerGenerated; return new LazyLabeledStatement(label, statement, _semanticModel, syntax, type, constantValue, isImplicit); } private ILabeledOperation CreateBoundLabeledStatementOperation(BoundLabeledStatement boundLabeledStatement) { ILabelSymbol label = boundLabeledStatement.Label; Lazy labeledStatement = new Lazy(() => Create(boundLabeledStatement.Body)); SyntaxNode syntax = boundLabeledStatement.Syntax; ITypeSymbol type = null; Optional constantValue = default(Optional); bool isImplicit = boundLabeledStatement.WasCompilerGenerated; return new LazyLabeledStatement(label, labeledStatement, _semanticModel, syntax, type, constantValue, isImplicit); } private IExpressionStatementOperation CreateBoundExpressionStatementOperation(BoundExpressionStatement boundExpressionStatement) { Lazy expression = new Lazy(() => Create(boundExpressionStatement.Expression)); SyntaxNode syntax = boundExpressionStatement.Syntax; ITypeSymbol type = null; Optional constantValue = default(Optional); // lambda body can point to expression directly and binder can insert expression statement there. and end up statement pointing to // expression syntax node since there is no statement syntax node to point to. this will mark such one as implicit since it doesn't // actually exist in code bool isImplicit = boundExpressionStatement.WasCompilerGenerated || boundExpressionStatement.Syntax == boundExpressionStatement.Expression.Syntax; return new LazyExpressionStatement(expression, _semanticModel, syntax, type, constantValue, isImplicit); } private IOperation CreateBoundTupleLiteralOperation(BoundTupleLiteral boundTupleLiteral) { return CreateTupleOperation(boundTupleLiteral, boundTupleLiteral.Type); } private IOperation CreateBoundConvertedTupleLiteralOperation(BoundConvertedTupleLiteral boundConvertedTupleLiteral) { return CreateTupleOperation(boundConvertedTupleLiteral, boundConvertedTupleLiteral.NaturalTypeOpt); } private IOperation CreateTupleOperation(BoundTupleExpression boundTupleExpression, ITypeSymbol naturalType) { Lazy> elements = new Lazy>(() => boundTupleExpression.Arguments.SelectAsArray(element => Create(element))); SyntaxNode syntax = boundTupleExpression.Syntax; bool isImplicit = boundTupleExpression.WasCompilerGenerated; ITypeSymbol type = boundTupleExpression.Type; Optional constantValue = default; if (syntax is DeclarationExpressionSyntax declarationExpressionSyntax) { var tupleSyntax = declarationExpressionSyntax.Designation; Lazy tupleExpression = new Lazy(() => new LazyTupleExpression(elements, _semanticModel, tupleSyntax, type, naturalType, constantValue, isImplicit)); return new LazyDeclarationExpression(tupleExpression, _semanticModel, declarationExpressionSyntax, type, constantValue: default, isImplicit: false); } return new LazyTupleExpression(elements, _semanticModel, syntax, type, naturalType, constantValue, isImplicit); } private IInterpolatedStringOperation CreateBoundInterpolatedStringExpressionOperation(BoundInterpolatedString boundInterpolatedString) { Lazy> parts = new Lazy>(() => boundInterpolatedString.Parts.SelectAsArray(interpolatedStringContent => CreateBoundInterpolatedStringContentOperation(interpolatedStringContent))); SyntaxNode syntax = boundInterpolatedString.Syntax; ITypeSymbol type = boundInterpolatedString.Type; Optional constantValue = ConvertToOptional(boundInterpolatedString.ConstantValue); bool isImplicit = boundInterpolatedString.WasCompilerGenerated; return new LazyInterpolatedStringExpression(parts, _semanticModel, syntax, type, constantValue, isImplicit); } private IInterpolatedStringContentOperation CreateBoundInterpolatedStringContentOperation(BoundNode boundNode) { if (boundNode.Kind == BoundKind.StringInsert) { return (IInterpolatedStringContentOperation)Create(boundNode); } else { return CreateBoundInterpolatedStringTextOperation((BoundLiteral)boundNode); } } private IInterpolationOperation CreateBoundInterpolationOperation(BoundStringInsert boundStringInsert) { Lazy expression = new Lazy(() => Create(boundStringInsert.Value)); Lazy alignment = new Lazy(() => Create(boundStringInsert.Alignment)); Lazy format = new Lazy(() => Create(boundStringInsert.Format)); SyntaxNode syntax = boundStringInsert.Syntax; ITypeSymbol type = null; Optional constantValue = default(Optional); bool isImplicit = boundStringInsert.WasCompilerGenerated; return new LazyInterpolation(expression, alignment, format, _semanticModel, syntax, type, constantValue, isImplicit); } private IInterpolatedStringTextOperation CreateBoundInterpolatedStringTextOperation(BoundLiteral boundNode) { Lazy text = new Lazy(() => CreateBoundLiteralOperation(boundNode, @implicit: true)); SyntaxNode syntax = boundNode.Syntax; ITypeSymbol type = null; Optional constantValue = default(Optional); bool isImplicit = boundNode.WasCompilerGenerated; return new LazyInterpolatedStringText(text, _semanticModel, syntax, type, constantValue, isImplicit); } private IConstantPatternOperation CreateBoundConstantPatternOperation(BoundConstantPattern boundConstantPattern) { Lazy value = new Lazy(() => Create(boundConstantPattern.Value)); SyntaxNode syntax = boundConstantPattern.Syntax; ITypeSymbol type = null; Optional constantValue = default(Optional); bool isImplicit = boundConstantPattern.WasCompilerGenerated; return new LazyConstantPattern(value, _semanticModel, syntax, type, constantValue, isImplicit); } private IDeclarationPatternOperation CreateBoundDeclarationPatternOperation(BoundDeclarationPattern boundDeclarationPattern) { ISymbol variable = boundDeclarationPattern.Variable; SyntaxNode syntax = boundDeclarationPattern.Syntax; ITypeSymbol type = null; Optional constantValue = default(Optional); bool isImplicit = boundDeclarationPattern.WasCompilerGenerated; return new DeclarationPattern(variable, _semanticModel, syntax, type, constantValue, isImplicit); } private ISwitchOperation CreateBoundPatternSwitchStatementOperation(BoundPatternSwitchStatement boundPatternSwitchStatement) { Lazy value = new Lazy(() => Create(boundPatternSwitchStatement.Expression)); Lazy> cases = new Lazy>(() => GetPatternSwitchStatementCases(boundPatternSwitchStatement)); SyntaxNode syntax = boundPatternSwitchStatement.Syntax; ITypeSymbol type = null; Optional constantValue = default(Optional); bool isImplicit = boundPatternSwitchStatement.WasCompilerGenerated; return new LazySwitchStatement(value, cases, _semanticModel, syntax, type, constantValue, isImplicit); } private ICaseClauseOperation CreateBoundPatternSwitchLabelOperation(BoundPatternSwitchLabel boundPatternSwitchLabel) { SyntaxNode syntax = boundPatternSwitchLabel.Syntax; ITypeSymbol type = null; Optional constantValue = default(Optional); bool isImplicit = boundPatternSwitchLabel.WasCompilerGenerated; if (boundPatternSwitchLabel.Pattern.Kind == BoundKind.WildcardPattern) { // Default switch label in pattern switch statement is represented as a default case clause. return new DefaultCaseClause(_semanticModel, syntax, type, constantValue, isImplicit); } else { LabelSymbol label = boundPatternSwitchLabel.Label; Lazy pattern = new Lazy(() => (IPatternOperation)Create(boundPatternSwitchLabel.Pattern)); Lazy guardExpression = new Lazy(() => Create(boundPatternSwitchLabel.Guard)); return new LazyPatternCaseClause(label, pattern, guardExpression, _semanticModel, syntax, type, constantValue, isImplicit); } } private IIsPatternOperation CreateBoundIsPatternExpressionOperation(BoundIsPatternExpression boundIsPatternExpression) { Lazy expression = new Lazy(() => Create(boundIsPatternExpression.Expression)); Lazy pattern = new Lazy(() => (IPatternOperation)Create(boundIsPatternExpression.Pattern)); SyntaxNode syntax = boundIsPatternExpression.Syntax; ITypeSymbol type = boundIsPatternExpression.Type; Optional constantValue = ConvertToOptional(boundIsPatternExpression.ConstantValue); bool isImplicit = boundIsPatternExpression.WasCompilerGenerated; return new LazyIsPatternExpression(expression, pattern, _semanticModel, syntax, type, constantValue, isImplicit); } private IOperation CreateBoundQueryClauseOperation(BoundQueryClause boundQueryClause) { if (boundQueryClause.Syntax.Kind() != SyntaxKind.QueryExpression) { // Currently we have no IOperation APIs for different query clauses or continuation. return Create(boundQueryClause.Value); } Lazy expression = new Lazy(() => Create(boundQueryClause.Value)); SyntaxNode syntax = boundQueryClause.Syntax; ITypeSymbol type = boundQueryClause.Type; Optional constantValue = ConvertToOptional(boundQueryClause.ConstantValue); bool isImplicit = boundQueryClause.WasCompilerGenerated; return new LazyTranslatedQueryExpression(expression, _semanticModel, syntax, type, constantValue, isImplicit); } private IOperation CreateBoundRangeVariableOperation(BoundRangeVariable boundRangeVariable) { // We do not have operation nodes for the bound range variables, just it's value. return Create(boundRangeVariable.Value); } } }