| File: Operations\Operation.cs | Web Access |
| Project: src\roslyn\src\Compilers\Core\Portable\Microsoft.CodeAnalysis.csproj (Microsoft.CodeAnalysis) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Threading; using Microsoft.CodeAnalysis.Operations; namespace Microsoft.CodeAnalysis { /// <summary> /// Root type for representing the abstract semantics of C# and VB statements and expressions. /// </summary> [DebuggerDisplay($"{{{nameof(GetDebuggerDisplay)}(), nq}}")] internal abstract partial class Operation : IOperation { protected static readonly IOperation s_unset = new EmptyOperation(semanticModel: null, syntax: null!, isImplicit: true); private readonly SemanticModel? _owningSemanticModelOpt; // this will be lazily initialized. this will be initialized only once // but once initialized, will never change private IOperation? _parentDoNotAccessDirectly; protected Operation(SemanticModel? semanticModel, SyntaxNode syntax, bool isImplicit) { #if DEBUG if (semanticModel != null) { Debug.Assert(semanticModel.ContainingPublicModelOrSelf != null); Debug.Assert(semanticModel.ContainingPublicModelOrSelf != semanticModel); Debug.Assert(semanticModel.ContainingPublicModelOrSelf.ContainingPublicModelOrSelf == semanticModel.ContainingPublicModelOrSelf); } #endif _owningSemanticModelOpt = semanticModel; Syntax = syntax; IsImplicit = isImplicit; _parentDoNotAccessDirectly = s_unset; } /// <summary> /// IOperation that has this operation as a child /// </summary> public IOperation? Parent { get { Debug.Assert(_parentDoNotAccessDirectly != s_unset, "Attempt to access parent node before construction is complete!"); return _parentDoNotAccessDirectly; } } /// <summary> /// Set to True if compiler generated /implicitly computed by compiler code /// </summary> public bool IsImplicit { get; } /// <summary> /// Identifies the kind of the operation. /// </summary> public abstract OperationKind Kind { get; } /// <summary> /// Syntax that was analyzed to produce the operation. /// </summary> public SyntaxNode Syntax { get; } /// <summary> /// Result type of the operation, or null if the operation does not produce a result. /// </summary> public abstract ITypeSymbol? Type { get; } /// <summary> /// The source language of the IOperation. Possible values are <see cref="LanguageNames.CSharp"/> and <see cref="LanguageNames.VisualBasic"/>. /// </summary> public string Language { // It is an eventual goal to support analyzing IL. At that point, we'll need to detect a null // syntax and add a new field to LanguageNames for IL. Until then, though, we'll just assume that // syntax is not null and return its language. get => Syntax.Language; } internal abstract CodeAnalysis.ConstantValue? OperationConstantValue { get; } /// <summary> /// If the operation is an expression that evaluates to a constant value, <see cref="Optional{Object}.HasValue"/> is true and <see cref="Optional{Object}.Value"/> is the value of the expression. Otherwise, <see cref="Optional{Object}.HasValue"/> is false. /// </summary> public Optional<object?> ConstantValue { get { if (OperationConstantValue == null || OperationConstantValue.IsBad) { return default(Optional<object?>); } return new Optional<object?>(OperationConstantValue.Value); } } IEnumerable<IOperation> IOperation.Children => this.ChildOperations; /// <inheritdoc/> public IOperation.OperationList ChildOperations => new IOperation.OperationList(this); internal abstract int ChildOperationsCount { get; } internal abstract IOperation GetCurrent(int slot, int index); /// <summary> /// A slot of -1 means start at the beginning. /// </summary> internal abstract (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex); /// <summary> /// A slot of int.MaxValue means start from the end. /// </summary> internal abstract (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex); SemanticModel? IOperation.SemanticModel => _owningSemanticModelOpt?.ContainingPublicModelOrSelf; /// <summary> /// Gets the owning semantic model for this operation node. /// Note that this may be different than <see cref="IOperation.SemanticModel"/>, which /// is the semantic model on which <see cref="SemanticModel.GetOperation(SyntaxNode, CancellationToken)"/> was invoked /// to create this node. /// </summary> internal SemanticModel? OwningSemanticModel => _owningSemanticModelOpt; public abstract void Accept(OperationVisitor visitor); public abstract TResult? Accept<TArgument, TResult>(OperationVisitor<TArgument, TResult> visitor, TArgument argument); protected void SetParentOperation(IOperation? parent) { Debug.Assert(_parentDoNotAccessDirectly == s_unset); Debug.Assert(parent != s_unset); _parentDoNotAccessDirectly = parent; // tree must belong to same semantic model if parent is given Debug.Assert(parent == null || ((Operation)parent).OwningSemanticModel == OwningSemanticModel); } [return: NotNullIfNotNull(nameof(operation))] public static T? SetParentOperation<T>(T? operation, IOperation? parent) where T : IOperation { // For simplicity of implementation of derived types, we handle `null` children, as some children // are optional. (operation as Operation)?.SetParentOperation(parent); return operation; } public static ImmutableArray<T> SetParentOperation<T>(ImmutableArray<T> operations, IOperation? parent) where T : IOperation { // check quick bail out case first if (operations.Length == 0) { // no element return operations; } foreach (var operation in operations) { SetParentOperation(operation, parent); } return operations; } [Conditional("DEBUG")] internal static void VerifyParentOperation(IOperation? parent, IOperation child) { if (child is object) { Debug.Assert((object?)child.Parent == parent); } } [Conditional("DEBUG")] internal static void VerifyParentOperation<T>(IOperation? parent, ImmutableArray<T> children) where T : IOperation { Debug.Assert(!children.IsDefault); foreach (var child in children) { VerifyParentOperation(parent, child); } } private string GetDebuggerDisplay() => $"{GetType().Name} Type: {(Type is null ? "null" : Type)}"; } }