File: Editing\SyntaxGenerator.cs
Web Access
Project: ..\..\..\src\Workspaces\Core\Portable\Microsoft.CodeAnalysis.Workspaces.csproj (Microsoft.CodeAnalysis.Workspaces)
// 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;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.LanguageService;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Simplification;
using Roslyn.Utilities;
 
namespace Microsoft.CodeAnalysis.Editing
{
    /// <summary>
    /// A language agnostic factory for creating syntax nodes.
    /// 
    /// This API can be used to create language specific syntax nodes that are semantically 
    /// similar between languages.
    /// 
    /// The trees generated by this API will try to respect user preferences when
    /// possible.  For example, generating <see cref="MemberAccessExpression(SyntaxNode, string)"/> 
    /// will be done in a way such that "this." or "Me." will be simplified according to user
    /// preference if <see cref="Simplifier" /> is used.
    /// </summary>
    public abstract class SyntaxGenerator : ILanguageService
    {
        public static readonly SyntaxRemoveOptions DefaultRemoveOptions = SyntaxRemoveOptions.KeepUnbalancedDirectives | SyntaxRemoveOptions.AddElasticMarker;
 
        internal abstract SyntaxTrivia CarriageReturnLineFeed { get; }
        internal abstract SyntaxTrivia ElasticCarriageReturnLineFeed { get; }
        internal abstract SyntaxTrivia ElasticMarker { get; }
 
        internal abstract bool RequiresExplicitImplementationForInterfaceMembers { get; }
        internal ISyntaxFacts SyntaxFacts => SyntaxGeneratorInternal.SyntaxFacts;
        internal abstract SyntaxGeneratorInternal SyntaxGeneratorInternal { get; }
 
        internal abstract SyntaxTrivia Whitespace(string text);
        internal abstract SyntaxTrivia SingleLineComment(string text);
 
        internal abstract SyntaxToken CreateInterpolatedStringStartToken(bool isVerbatim);
        internal abstract SyntaxToken CreateInterpolatedStringEndToken();
 
        /// <summary>
        /// Gets the <see cref="SyntaxGenerator"/> for the specified language.
        /// </summary>
        public static SyntaxGenerator GetGenerator(Workspace workspace, string language)
            => GetGenerator(workspace.Services.SolutionServices, language);
 
        /// <summary>
        /// Gets the <see cref="SyntaxGenerator"/> for the specified language.
        /// </summary>
        internal static SyntaxGenerator GetGenerator(SolutionServices services, string language)
            => services.GetLanguageServices(language).GetRequiredService<SyntaxGenerator>();
 
        /// <summary>
        /// Gets the <see cref="SyntaxGenerator"/> for the language corresponding to the document.
        /// </summary>
        public static SyntaxGenerator GetGenerator(Document document)
            => GetGenerator(document.Project);
 
        /// <summary>
        /// Gets the <see cref="SyntaxGenerator"/> for the language corresponding to the project.
        /// </summary>
        public static SyntaxGenerator GetGenerator(Project project)
            => project.Services.GetRequiredService<SyntaxGenerator>();
 
        #region Declarations
 
        /// <summary>
        /// Returns the node if it is a declaration, the immediate enclosing declaration if one exists, or null.
        /// </summary>
        public SyntaxNode? GetDeclaration(SyntaxNode? node)
        {
            while (node != null)
            {
                if (GetDeclarationKind(node) != DeclarationKind.None)
                {
                    return node;
                }
 
                node = node.Parent;
            }
 
            return null;
        }
 
        /// <summary>
        /// Returns the enclosing declaration of the specified kind or null.
        /// </summary>
        public SyntaxNode? GetDeclaration(SyntaxNode? node, DeclarationKind kind)
        {
            while (node != null)
            {
                if (GetDeclarationKind(node) == kind)
                {
                    return node;
                }
 
                node = node.Parent;
            }
 
            return null;
        }
 
        /// <summary>
        /// Creates a field declaration.
        /// </summary>
        public abstract SyntaxNode FieldDeclaration(
            string name,
            SyntaxNode type,
            Accessibility accessibility = Accessibility.NotApplicable,
            DeclarationModifiers modifiers = default,
            SyntaxNode? initializer = null);
 
        /// <summary>
        /// Creates a field declaration matching an existing field symbol.
        /// </summary>
        public SyntaxNode FieldDeclaration(IFieldSymbol field)
        {
            var initializer = field.HasConstantValue ? this.LiteralExpression(field.ConstantValue) : null;
            return FieldDeclaration(field, initializer);
        }
 
        /// <summary>
        /// Creates a field declaration matching an existing field symbol.
        /// </summary>
        public SyntaxNode FieldDeclaration(IFieldSymbol field, SyntaxNode? initializer)
        {
            return FieldDeclaration(
                field.Name,
                TypeExpression(field.Type),
                field.DeclaredAccessibility,
                DeclarationModifiers.From(field),
                initializer);
        }
 
        //internal abstract SyntaxNode ObjectMemberInitializer(IEnumerable<SyntaxNode> fieldInitializers);
        //internal abstract SyntaxNode NamedFieldInitializer(SyntaxNode name, SyntaxNode value);
        //internal abstract SyntaxNode WithObjectCreationInitializer(SyntaxNode objectCreationExpression, SyntaxNode initializer);
 
        /// <summary>
        /// Creates a method declaration.
        /// </summary>
#pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters
        public SyntaxNode MethodDeclaration(
            string name,
            IEnumerable<SyntaxNode>? parameters = null,
            IEnumerable<string>? typeParameters = null,
            SyntaxNode? returnType = null,
            Accessibility accessibility = Accessibility.NotApplicable,
            DeclarationModifiers modifiers = default,
            IEnumerable<SyntaxNode>? statements = null)
        {
            return MethodDeclaration(
                name, parameters, typeParameters?.Select(n => TypeParameter(n)), returnType, accessibility, modifiers, statements);
        }
#pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters
 
        private protected abstract SyntaxNode MethodDeclaration(
            string name,
            IEnumerable<SyntaxNode>? parameters,
            IEnumerable<SyntaxNode>? typeParameters,
            SyntaxNode? returnType,
            Accessibility accessibility,
            DeclarationModifiers modifiers,
            IEnumerable<SyntaxNode>? statements);
 
        /// <summary>
        /// Creates a method declaration matching an existing method symbol.
        /// </summary>
        public SyntaxNode MethodDeclaration(IMethodSymbol method, IEnumerable<SyntaxNode>? statements = null)
            => MethodDeclaration(method, method.Name, statements);
 
        internal SyntaxNode MethodDeclaration(IMethodSymbol method, string name, IEnumerable<SyntaxNode>? statements = null)
        {
            var decl = MethodDeclaration(
                name,
                typeParameters: method.TypeParameters.Select(p => TypeParameter(p)),
                parameters: method.Parameters.Select(p => ParameterDeclaration(p)),
                returnType: method.ReturnType.IsSystemVoid() ? null : TypeExpression(method.ReturnType, method.RefKind),
                accessibility: method.DeclaredAccessibility,
                modifiers: DeclarationModifiers.From(method),
                statements: statements);
 
            if (method.TypeParameters.Length > 0)
            {
                // Overrides are special.  Specifically, in an override, if a type parameter has no constraints, then we
                // want to still add `where T : default` if that type parameter is used with NRT (e.g. `T?`) that way
                // the language can distinguish if this is a Nullable Value Type or not.
                if (method.IsOverride)
                {
                    foreach (var typeParameter in method.TypeParameters)
                    {
                        if (HasNullableAnnotation(typeParameter, method))
                        {
                            if (!HasSomeConstraint(typeParameter))
                            {
                                // if there are no constraints, add `where T : default` so it's known this not an NVT
                                // and is just an unconstrained type parameter.
                                decl = WithDefaultConstraint(decl, typeParameter.Name);
                            }
                            else if (!typeParameter.HasValueTypeConstraint)
                            {
                                // if there are some constraints, add `where T : class` so it's known this is not an NVT
                                // and must specifically be some reference type.
                                decl = WithTypeConstraint(decl, typeParameter.Name, SpecialTypeConstraintKind.ReferenceType);
                            }
                        }
                    }
                }
                else
                {
                    decl = this.WithTypeParametersAndConstraints(decl, method.TypeParameters);
                }
            }
 
            if (method.ExplicitInterfaceImplementations.Length > 0)
            {
                decl = this.WithExplicitInterfaceImplementations(decl,
                    ImmutableArray<ISymbol>.CastUp(method.ExplicitInterfaceImplementations));
            }
 
            return decl;
 
            bool HasNullableAnnotation(ITypeParameterSymbol typeParameter, IMethodSymbol method)
            {
                return method.ReturnType.GetReferencedTypeParameters().Any(t => IsNullableAnnotatedTypeParameter(typeParameter, t)) ||
                    method.Parameters.Any(p => p.Type.GetReferencedTypeParameters().Any(t => IsNullableAnnotatedTypeParameter(typeParameter, t)));
            }
 
            static bool IsNullableAnnotatedTypeParameter(ITypeParameterSymbol typeParameter, ITypeParameterSymbol current)
            {
                return Equals(current, typeParameter) && current.NullableAnnotation == NullableAnnotation.Annotated;
            }
        }
 
        /// <summary>
        /// Creates a method declaration.
        /// </summary>
        public virtual SyntaxNode OperatorDeclaration(
            OperatorKind kind,
            IEnumerable<SyntaxNode>? parameters = null,
            SyntaxNode? returnType = null,
            Accessibility accessibility = Accessibility.NotApplicable,
            DeclarationModifiers modifiers = default,
            IEnumerable<SyntaxNode>? statements = null)
        {
            throw new NotImplementedException();
        }
 
        /// <summary>
        /// Creates a operator or conversion declaration matching an existing method symbol.
        /// </summary>
        public SyntaxNode OperatorDeclaration(IMethodSymbol method, IEnumerable<SyntaxNode>? statements = null)
        {
            if (method.MethodKind is not (MethodKind.UserDefinedOperator or MethodKind.Conversion))
                throw new ArgumentException("Method is not an operator.");
 
            var decl = OperatorDeclaration(
                GetOperatorKind(method),
                parameters: method.Parameters.Select(p => ParameterDeclaration(p)),
                returnType: method.ReturnType.IsSystemVoid() ? null : TypeExpression(method.ReturnType, method.RefKind),
                accessibility: method.DeclaredAccessibility,
                modifiers: DeclarationModifiers.From(method),
                statements: statements);
 
            return decl;
        }
 
        private static OperatorKind GetOperatorKind(IMethodSymbol method)
            => method.Name switch
            {
                WellKnownMemberNames.ImplicitConversionName => OperatorKind.ImplicitConversion,
                WellKnownMemberNames.ExplicitConversionName => OperatorKind.ExplicitConversion,
                WellKnownMemberNames.AdditionOperatorName => OperatorKind.Addition,
                WellKnownMemberNames.BitwiseAndOperatorName => OperatorKind.BitwiseAnd,
                WellKnownMemberNames.BitwiseOrOperatorName => OperatorKind.BitwiseOr,
                WellKnownMemberNames.DecrementOperatorName => OperatorKind.Decrement,
                WellKnownMemberNames.DivisionOperatorName => OperatorKind.Division,
                WellKnownMemberNames.EqualityOperatorName => OperatorKind.Equality,
                WellKnownMemberNames.ExclusiveOrOperatorName => OperatorKind.ExclusiveOr,
                WellKnownMemberNames.FalseOperatorName => OperatorKind.False,
                WellKnownMemberNames.GreaterThanOperatorName => OperatorKind.GreaterThan,
                WellKnownMemberNames.GreaterThanOrEqualOperatorName => OperatorKind.GreaterThanOrEqual,
                WellKnownMemberNames.IncrementOperatorName => OperatorKind.Increment,
                WellKnownMemberNames.InequalityOperatorName => OperatorKind.Inequality,
                WellKnownMemberNames.LeftShiftOperatorName => OperatorKind.LeftShift,
                WellKnownMemberNames.LessThanOperatorName => OperatorKind.LessThan,
                WellKnownMemberNames.LessThanOrEqualOperatorName => OperatorKind.LessThanOrEqual,
                WellKnownMemberNames.LogicalNotOperatorName => OperatorKind.LogicalNot,
                WellKnownMemberNames.ModulusOperatorName => OperatorKind.Modulus,
                WellKnownMemberNames.MultiplyOperatorName => OperatorKind.Multiply,
                WellKnownMemberNames.OnesComplementOperatorName => OperatorKind.OnesComplement,
                WellKnownMemberNames.RightShiftOperatorName => OperatorKind.RightShift,
                WellKnownMemberNames.UnsignedRightShiftOperatorName => OperatorKind.UnsignedRightShift,
                WellKnownMemberNames.SubtractionOperatorName => OperatorKind.Subtraction,
                WellKnownMemberNames.TrueOperatorName => OperatorKind.True,
                WellKnownMemberNames.UnaryNegationOperatorName => OperatorKind.UnaryNegation,
                WellKnownMemberNames.UnaryPlusOperatorName => OperatorKind.UnaryPlus,
                _ => throw new ArgumentException("Unknown operator kind."),
            };
 
        /// <summary>
        /// Creates a parameter declaration.
        /// </summary>
#pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters
        public SyntaxNode ParameterDeclaration(
            string name,
            SyntaxNode? type = null,
            SyntaxNode? initializer = null,
            RefKind refKind = RefKind.None)
        {
            return ParameterDeclaration(name, type, initializer, refKind, isExtension: false, isParams: false);
        }
#pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters
 
        private protected abstract SyntaxNode ParameterDeclaration(
            string name,
            SyntaxNode? type,
            SyntaxNode? initializer,
            RefKind refKind,
            bool isExtension,
            bool isParams);
 
        /// <summary>
        /// Creates a parameter declaration matching an existing parameter symbol.
        /// </summary>
        public SyntaxNode ParameterDeclaration(IParameterSymbol symbol, SyntaxNode? initializer = null)
        {
            return ParameterDeclaration(
                symbol.Name,
                TypeExpression(symbol.Type),
                initializer is not null ? initializer :
                symbol.HasExplicitDefaultValue ? GenerateExpression(symbol.Type, symbol.ExplicitDefaultValue, canUseFieldReference: true) : null,
                symbol.RefKind,
                isExtension: symbol is { Ordinal: 0, ContainingSymbol: IMethodSymbol { IsExtensionMethod: true } },
                symbol.IsParams);
        }
 
        private protected abstract SyntaxNode TypeParameter(ITypeParameterSymbol typeParameter);
        private protected abstract SyntaxNode TypeParameter(string name);
 
        private protected abstract SyntaxNode GenerateExpression(ITypeSymbol? type, object? value, bool canUseFieldReference);
 
        /// <summary>
        /// Creates a property declaration. The property will have a <c>get</c> accessor if
        /// <see cref="DeclarationModifiers.IsWriteOnly"/> is <see langword="false"/> and will have
        /// a <c>set</c> accessor if <see cref="DeclarationModifiers.IsReadOnly"/> is <see
        /// langword="false"/>.
        /// </summary>
        /// <remarks>
        /// In C# there is a distinction between passing in <see langword="null"/> for <paramref
        /// name="getAccessorStatements"/> or <paramref name="setAccessorStatements"/> versus
        /// passing in an empty list. <see langword="null"/> will produce an auto-property-accessor
        /// (i.e. <c>get;</c>) whereas an empty list will produce an accessor with an empty block
        /// (i.e. <c>get { }</c>).
        /// </remarks>
        public abstract SyntaxNode PropertyDeclaration(
            string name,
            SyntaxNode type,
            Accessibility accessibility = Accessibility.NotApplicable,
            DeclarationModifiers modifiers = default,
            IEnumerable<SyntaxNode>? getAccessorStatements = null,
            IEnumerable<SyntaxNode>? setAccessorStatements = null);
 
        /// <summary>
        /// Creates a property declaration using an existing property symbol as a signature.
        /// </summary>
        public SyntaxNode PropertyDeclaration(
            IPropertySymbol property,
            IEnumerable<SyntaxNode>? getAccessorStatements = null,
            IEnumerable<SyntaxNode>? setAccessorStatements = null)
        {
            var propertyAccessibility = property.DeclaredAccessibility;
            var getMethodSymbol = property.GetMethod;
            var setMethodSymbol = property.SetMethod;
 
            SyntaxNode? getAccessor = null;
            SyntaxNode? setAccessor = null;
 
            if (getMethodSymbol is not null)
            {
                var getMethodAccessibility = getMethodSymbol.DeclaredAccessibility;
                getAccessor = GetAccessorDeclaration(getMethodAccessibility < propertyAccessibility ? getMethodAccessibility : Accessibility.NotApplicable, getAccessorStatements);
            }
 
            if (setMethodSymbol is not null)
            {
                var setMethodAccessibility = setMethodSymbol.DeclaredAccessibility;
                setAccessor = SetAccessorDeclaration(setMethodAccessibility < propertyAccessibility ? setMethodAccessibility : Accessibility.NotApplicable, setAccessorStatements);
            }
 
            var propDecl = PropertyDeclaration(
                property.Name,
                TypeExpression(property.Type, property.RefKind),
                getAccessor,
                setAccessor,
                propertyAccessibility,
                DeclarationModifiers.From(property));
 
            if (property.ExplicitInterfaceImplementations.Length > 0)
            {
                propDecl = this.WithExplicitInterfaceImplementations(propDecl,
                    ImmutableArray<ISymbol>.CastUp(property.ExplicitInterfaceImplementations));
            }
 
            return propDecl;
        }
 
        private protected abstract SyntaxNode PropertyDeclaration(
            string name,
            SyntaxNode type,
            SyntaxNode? getAccessor,
            SyntaxNode? setAccessor,
            Accessibility accessibility,
            DeclarationModifiers modifiers);
 
        public SyntaxNode WithAccessorDeclarations(SyntaxNode declaration, params SyntaxNode[] accessorDeclarations)
            => WithAccessorDeclarations(declaration, (IEnumerable<SyntaxNode>)accessorDeclarations);
 
        public abstract SyntaxNode WithAccessorDeclarations(SyntaxNode declaration, IEnumerable<SyntaxNode> accessorDeclarations);
 
        public abstract SyntaxNode GetAccessorDeclaration(
            Accessibility accessibility = Accessibility.NotApplicable,
            IEnumerable<SyntaxNode>? statements = null);
 
        public abstract SyntaxNode SetAccessorDeclaration(
            Accessibility accessibility = Accessibility.NotApplicable,
            IEnumerable<SyntaxNode>? statements = null);
 
        /// <summary>
        /// Creates an indexer declaration.
        /// </summary>
        public abstract SyntaxNode IndexerDeclaration(
            IEnumerable<SyntaxNode> parameters,
            SyntaxNode type,
            Accessibility accessibility = Accessibility.NotApplicable,
            DeclarationModifiers modifiers = default,
            IEnumerable<SyntaxNode>? getAccessorStatements = null,
            IEnumerable<SyntaxNode>? setAccessorStatements = null);
 
        /// <summary>
        /// Creates an indexer declaration matching an existing indexer symbol.
        /// </summary>
        public SyntaxNode IndexerDeclaration(
            IPropertySymbol indexer,
            IEnumerable<SyntaxNode>? getAccessorStatements = null,
            IEnumerable<SyntaxNode>? setAccessorStatements = null)
        {
            var indexerDecl = IndexerDeclaration(
                indexer.Parameters.Select(p => this.ParameterDeclaration(p)),
                TypeExpression(indexer.Type, indexer.RefKind),
                indexer.DeclaredAccessibility,
                DeclarationModifiers.From(indexer),
                getAccessorStatements,
                setAccessorStatements);
 
            if (indexer.ExplicitInterfaceImplementations.Length > 0)
            {
                indexerDecl = this.WithExplicitInterfaceImplementations(indexerDecl,
                    ImmutableArray<ISymbol>.CastUp(indexer.ExplicitInterfaceImplementations));
            }
 
            return indexerDecl;
        }
 
        /// <summary>
        /// Creates a statement that adds the given handler to the given event.
        /// </summary>
        public abstract SyntaxNode AddEventHandler(SyntaxNode @event, SyntaxNode handler);
 
        /// <summary>
        /// Creates a statement that removes the given handler from the given event.
        /// </summary>
        public abstract SyntaxNode RemoveEventHandler(SyntaxNode @event, SyntaxNode handler);
 
        /// <summary>
        /// Creates an event declaration.
        /// </summary>
        public abstract SyntaxNode EventDeclaration(
            string name,
            SyntaxNode type,
            Accessibility accessibility = Accessibility.NotApplicable,
            DeclarationModifiers modifiers = default);
 
        /// <summary>
        /// Creates an event declaration from an existing event symbol
        /// </summary>
        public SyntaxNode EventDeclaration(IEventSymbol symbol)
        {
            var ev = EventDeclaration(
                symbol.Name,
                TypeExpression(symbol.Type),
                symbol.DeclaredAccessibility,
                DeclarationModifiers.From(symbol));
 
            if (symbol.ExplicitInterfaceImplementations.Length > 0)
            {
                ev = this.WithExplicitInterfaceImplementations(ev,
                    ImmutableArray<ISymbol>.CastUp(symbol.ExplicitInterfaceImplementations));
            }
 
            return ev;
        }
 
        /// <summary>
        /// Creates a custom event declaration.
        /// </summary>
        public abstract SyntaxNode CustomEventDeclaration(
            string name,
            SyntaxNode type,
            Accessibility accessibility = Accessibility.NotApplicable,
            DeclarationModifiers modifiers = default,
            IEnumerable<SyntaxNode>? parameters = null,
            IEnumerable<SyntaxNode>? addAccessorStatements = null,
            IEnumerable<SyntaxNode>? removeAccessorStatements = null);
 
        /// <summary>
        /// Creates a custom event declaration from an existing event symbol.
        /// </summary>
        public SyntaxNode CustomEventDeclaration(
            IEventSymbol symbol,
            IEnumerable<SyntaxNode>? addAccessorStatements = null,
            IEnumerable<SyntaxNode>? removeAccessorStatements = null)
        {
            var invoke = symbol.Type.GetMembers("Invoke").FirstOrDefault(m => m.Kind == SymbolKind.Method) as IMethodSymbol;
            var parameters = invoke?.Parameters.Select(p => this.ParameterDeclaration(p));
 
            return CustomEventDeclaration(
                symbol.Name,
                TypeExpression(symbol.Type),
                symbol.DeclaredAccessibility,
                DeclarationModifiers.From(symbol),
                parameters: parameters,
                addAccessorStatements: addAccessorStatements,
                removeAccessorStatements: removeAccessorStatements);
        }
 
        /// <summary>
        /// Creates a constructor declaration.
        /// </summary>
        public abstract SyntaxNode ConstructorDeclaration(
            string? containingTypeName = null,
            IEnumerable<SyntaxNode>? parameters = null,
            Accessibility accessibility = Accessibility.NotApplicable,
            DeclarationModifiers modifiers = default,
            IEnumerable<SyntaxNode>? baseConstructorArguments = null,
            IEnumerable<SyntaxNode>? statements = null);
 
        /// <summary>
        /// Create a constructor declaration using 
        /// </summary>
        public SyntaxNode ConstructorDeclaration(
            IMethodSymbol constructorMethod,
            IEnumerable<SyntaxNode>? baseConstructorArguments = null,
            IEnumerable<SyntaxNode>? statements = null)
        {
            return ConstructorDeclaration(
                constructorMethod.ContainingType != null ? constructorMethod.ContainingType.Name : "New",
                constructorMethod.Parameters.Select(p => ParameterDeclaration(p)),
                constructorMethod.DeclaredAccessibility,
                DeclarationModifiers.From(constructorMethod),
                baseConstructorArguments,
                statements);
        }
 
        private protected abstract SyntaxNode DestructorDeclaration(IMethodSymbol destructorMethod);
 
        /// <summary>
        /// Converts method, property and indexer declarations into public interface implementations.
        /// This is equivalent to an implicit C# interface implementation (you can access it via the interface or directly via the named member.)
        /// </summary>
        public SyntaxNode? AsPublicInterfaceImplementation(SyntaxNode declaration, SyntaxNode interfaceType)
            => AsPublicInterfaceImplementation(declaration, interfaceType, interfaceMemberName: null);
 
        /// <summary>
        /// Converts method, property and indexer declarations into public interface implementations.
        /// This is equivalent to an implicit C# interface implementation (you can access it via the interface or directly via the named member.)
        /// </summary>
        public abstract SyntaxNode? AsPublicInterfaceImplementation(SyntaxNode declaration, SyntaxNode interfaceType, string? interfaceMemberName);
 
        /// <summary>
        /// Converts method, property and indexer declarations into private interface implementations.
        /// This is equivalent to a C# explicit interface implementation (you can declare it for access via the interface, but cannot call it directly).
        /// </summary>
        public SyntaxNode? AsPrivateInterfaceImplementation(SyntaxNode declaration, SyntaxNode interfaceType)
            => AsPrivateInterfaceImplementation(declaration, interfaceType, interfaceMemberName: null);
 
        /// <summary>
        /// Converts method, property and indexer declarations into private interface implementations.
        /// This is equivalent to a C# explicit interface implementation (you can declare it for access via the interface, but cannot call it directly).
        /// </summary>
        public abstract SyntaxNode? AsPrivateInterfaceImplementation(SyntaxNode declaration, SyntaxNode interfaceType, string? interfaceMemberName);
 
        /// <summary>
        /// Creates a class declaration.
        /// </summary>
        public SyntaxNode ClassDeclaration(
            string name,
            IEnumerable<string>? typeParameters = null,
            Accessibility accessibility = Accessibility.NotApplicable,
            DeclarationModifiers modifiers = default,
            SyntaxNode? baseType = null,
            IEnumerable<SyntaxNode>? interfaceTypes = null,
            IEnumerable<SyntaxNode>? members = null)
        {
            return ClassDeclaration(
                isRecord: false, name, typeParameters?.Select(TypeParameter), accessibility, modifiers, baseType, interfaceTypes, members);
        }
 
        private protected abstract SyntaxNode ClassDeclaration(
            bool isRecord,
            string name,
            IEnumerable<SyntaxNode>? typeParameters,
            Accessibility accessibility,
            DeclarationModifiers modifiers,
            SyntaxNode? baseType,
            IEnumerable<SyntaxNode>? interfaceTypes,
            IEnumerable<SyntaxNode>? members);
 
        /// <summary>
        /// Creates a struct declaration.
        /// </summary>
        public SyntaxNode StructDeclaration(
            string name,
            IEnumerable<string>? typeParameters = null,
            Accessibility accessibility = Accessibility.NotApplicable,
            DeclarationModifiers modifiers = default,
            IEnumerable<SyntaxNode>? interfaceTypes = null,
            IEnumerable<SyntaxNode>? members = null)
        {
            return StructDeclaration(
                isRecord: false, name, typeParameters?.Select(TypeParameter), accessibility, modifiers, interfaceTypes, members);
        }
 
        private protected abstract SyntaxNode StructDeclaration(
            bool isRecord,
            string name,
            IEnumerable<SyntaxNode>? typeParameters,
            Accessibility accessibility,
            DeclarationModifiers modifiers,
            IEnumerable<SyntaxNode>? interfaceTypes,
            IEnumerable<SyntaxNode>? members);
 
        /// <summary>
        /// Creates a interface declaration.
        /// </summary>
        public SyntaxNode InterfaceDeclaration(
            string name,
            IEnumerable<string>? typeParameters = null,
            Accessibility accessibility = Accessibility.NotApplicable,
            IEnumerable<SyntaxNode>? interfaceTypes = null,
            IEnumerable<SyntaxNode>? members = null)
        {
            return InterfaceDeclaration(
                name, typeParameters?.Select(n => TypeParameter(n)), accessibility, interfaceTypes, members);
        }
 
        private protected abstract SyntaxNode InterfaceDeclaration(
            string name,
            IEnumerable<SyntaxNode>? typeParameters,
            Accessibility accessibility,
            IEnumerable<SyntaxNode>? interfaceTypes,
            IEnumerable<SyntaxNode>? members);
 
        /// <summary>
        /// Creates an enum declaration.
        /// </summary>
        public abstract SyntaxNode EnumDeclaration(
            string name,
            Accessibility accessibility = Accessibility.NotApplicable,
            DeclarationModifiers modifiers = default,
            IEnumerable<SyntaxNode>? members = null);
 
        /// <summary>
        /// Creates an enum declaration
        /// </summary>
        internal abstract SyntaxNode EnumDeclaration(
            string name,
            SyntaxNode? underlyingType,
            Accessibility accessibility = Accessibility.NotApplicable,
            DeclarationModifiers modifiers = default,
            IEnumerable<SyntaxNode>? members = null);
 
        /// <summary>
        /// Creates an enum member
        /// </summary>
        public abstract SyntaxNode EnumMember(string name, SyntaxNode? expression = null);
 
        /// <summary>
        /// Creates a delegate declaration.
        /// </summary>
        public SyntaxNode DelegateDeclaration(
            string name,
            IEnumerable<SyntaxNode>? parameters = null,
            IEnumerable<string>? typeParameters = null,
            SyntaxNode? returnType = null,
            Accessibility accessibility = Accessibility.NotApplicable,
            DeclarationModifiers modifiers = default)
        {
            return DelegateDeclaration(
                name, parameters, typeParameters?.Select(n => TypeParameter(n)), returnType, accessibility, modifiers);
        }
 
        private protected abstract SyntaxNode DelegateDeclaration(
            string name,
            IEnumerable<SyntaxNode>? parameters,
            IEnumerable<SyntaxNode>? typeParameters,
            SyntaxNode? returnType,
            Accessibility accessibility,
            DeclarationModifiers modifiers);
 
        /// <summary>
        /// Creates a declaration matching an existing symbol.
        /// </summary>
        public SyntaxNode Declaration(ISymbol symbol)
        {
            switch (symbol.Kind)
            {
                case SymbolKind.Field:
                    return FieldDeclaration((IFieldSymbol)symbol);
 
                case SymbolKind.Property:
                    var property = (IPropertySymbol)symbol;
                    if (property.IsIndexer)
                    {
                        return IndexerDeclaration(property);
                    }
                    else
                    {
                        return PropertyDeclaration(property);
                    }
 
                case SymbolKind.Event:
                    var ev = (IEventSymbol)symbol;
                    return EventDeclaration(ev);
 
                case SymbolKind.Method:
                    var method = (IMethodSymbol)symbol;
                    switch (method.MethodKind)
                    {
                        case MethodKind.Constructor:
                        case MethodKind.SharedConstructor:
                            return ConstructorDeclaration(method);
 
                        case MethodKind.Destructor:
                            return DestructorDeclaration(method);
 
                        case MethodKind.Ordinary or MethodKind.ExplicitInterfaceImplementation:
                            return MethodDeclaration(method);
 
                        case MethodKind.UserDefinedOperator or MethodKind.Conversion:
                            return OperatorDeclaration(method);
                    }
 
                    break;
 
                case SymbolKind.Parameter:
                    return ParameterDeclaration((IParameterSymbol)symbol);
 
                case SymbolKind.NamedType:
                    var type = (INamedTypeSymbol)symbol;
 
                    var declaration = type.TypeKind switch
                    {
                        TypeKind.Class => ClassDeclaration(
                            type.IsRecord,
                            type.Name,
                            type.TypeParameters.Select(TypeParameter),
                            accessibility: type.DeclaredAccessibility,
                            modifiers: DeclarationModifiers.From(type),
                            baseType: type.BaseType != null ? TypeExpression(type.BaseType) : null,
                            interfaceTypes: type.Interfaces.Select(TypeExpression),
                            members: type.GetMembers().Where(CanBeDeclared).Select(Declaration)),
                        TypeKind.Struct => StructDeclaration(
                            type.IsRecord,
                            type.Name,
                            type.TypeParameters.Select(TypeParameter),
                            accessibility: type.DeclaredAccessibility,
                            modifiers: DeclarationModifiers.From(type),
                            interfaceTypes: type.Interfaces.Select(TypeExpression),
                            members: type.GetMembers().Where(CanBeDeclared).Select(Declaration)),
                        TypeKind.Interface => InterfaceDeclaration(
                            type.Name,
                            type.TypeParameters.Select(TypeParameter),
                            accessibility: type.DeclaredAccessibility,
                            interfaceTypes: type.Interfaces.Select(TypeExpression),
                            members: type.GetMembers().Where(CanBeDeclared).Select(Declaration)),
                        TypeKind.Enum => EnumDeclaration(
                            type.Name,
                            underlyingType: type.EnumUnderlyingType is null or { SpecialType: SpecialType.System_Int32 }
                                ? null
                                : TypeExpression(type.EnumUnderlyingType.SpecialType),
                            accessibility: type.DeclaredAccessibility,
                            members: type.GetMembers().Where(s => s.Kind == SymbolKind.Field).Select(Declaration)),
                        TypeKind.Delegate => type.GetMembers(WellKnownMemberNames.DelegateInvokeName) is [IMethodSymbol invoke, ..]
                            ? DelegateDeclaration(
                                type.Name,
                                typeParameters: type.TypeParameters.Select(TypeParameter),
                                parameters: invoke.Parameters.Select(p => ParameterDeclaration(p)),
                                returnType: invoke.ReturnsVoid ? null : TypeExpression(invoke.ReturnType),
                                accessibility: type.DeclaredAccessibility,
                                modifiers: DeclarationModifiers.From(type))
                            : null,
                        _ => null,
                    };
 
                    if (declaration != null)
                        return WithTypeParametersAndConstraints(declaration, type.TypeParameters);
 
                    break;
            }
 
            throw new ArgumentException("Symbol cannot be converted to a declaration");
        }
 
        private static bool CanBeDeclared(ISymbol symbol)
        {
            // Skip implicitly declared members from a record.  No need to synthesize those as the compiler will do it
            // anyways.
            if (symbol.ContainingType?.IsRecord is true)
            {
                if (symbol.IsImplicitlyDeclared)
                    return false;
            }
 
            switch (symbol.Kind)
            {
                case SymbolKind.Field:
                case SymbolKind.Property:
                case SymbolKind.Event:
                case SymbolKind.Parameter:
                    return symbol.CanBeReferencedByName;
 
                case SymbolKind.Method:
                    var method = (IMethodSymbol)symbol;
                    switch (method.MethodKind)
                    {
                        case MethodKind.Constructor:
                        case MethodKind.SharedConstructor:
                            return true;
                        case MethodKind.Ordinary:
                            return method.CanBeReferencedByName;
                    }
 
                    break;
 
                case SymbolKind.NamedType:
                    var type = (INamedTypeSymbol)symbol;
                    switch (type.TypeKind)
                    {
                        case TypeKind.Class:
                        case TypeKind.Struct:
                        case TypeKind.Interface:
                        case TypeKind.Enum:
                        case TypeKind.Delegate:
                            return type.CanBeReferencedByName;
                    }
 
                    break;
            }
 
            return false;
        }
 
        private SyntaxNode WithTypeParametersAndConstraints(SyntaxNode declaration, ImmutableArray<ITypeParameterSymbol> typeParameters)
        {
            if (typeParameters.Length > 0)
            {
                declaration = WithTypeParameters(declaration, typeParameters.Select(tp => TypeParameter(tp)));
 
                foreach (var tp in typeParameters)
                {
                    if (HasSomeConstraint(tp))
                    {
                        declaration = this.WithTypeConstraint(declaration, tp.Name,
                            kinds: (tp.HasConstructorConstraint ? SpecialTypeConstraintKind.Constructor : SpecialTypeConstraintKind.None)
                                   | (tp.HasReferenceTypeConstraint ? SpecialTypeConstraintKind.ReferenceType : SpecialTypeConstraintKind.None)
                                   | (tp.HasValueTypeConstraint ? SpecialTypeConstraintKind.ValueType : SpecialTypeConstraintKind.None),
                            types: tp.ConstraintTypes.Select(TypeExpression));
                    }
                }
            }
 
            return declaration;
        }
 
        private static bool HasSomeConstraint(ITypeParameterSymbol typeParameter)
            => typeParameter.HasConstructorConstraint || typeParameter.HasReferenceTypeConstraint || typeParameter.HasValueTypeConstraint || typeParameter.ConstraintTypes.Length > 0;
 
        internal abstract SyntaxNode WithExplicitInterfaceImplementations(
            SyntaxNode declaration, ImmutableArray<ISymbol> explicitInterfaceImplementations, bool removeDefaults = true);
 
        /// <summary>
        /// Converts a declaration (method, class, etc) into a declaration with type parameters.
        /// </summary>
        public SyntaxNode WithTypeParameters(SyntaxNode declaration, IEnumerable<string> typeParameters)
            => WithTypeParameters(declaration, typeParameters.Select(n => TypeParameter(n)));
 
        private protected abstract SyntaxNode WithTypeParameters(SyntaxNode declaration, IEnumerable<SyntaxNode> typeParameters);
 
        /// <summary>
        /// Converts a declaration (method, class, etc) into a declaration with type parameters.
        /// </summary>
        public SyntaxNode WithTypeParameters(SyntaxNode declaration, params string[] typeParameters)
            => WithTypeParameters(declaration, (IEnumerable<string>)typeParameters);
 
        /// <summary>
        /// Adds a type constraint to a type parameter of a declaration.
        /// </summary>
        public abstract SyntaxNode WithTypeConstraint(SyntaxNode declaration, string typeParameterName, SpecialTypeConstraintKind kinds, IEnumerable<SyntaxNode>? types = null);
 
        private protected abstract SyntaxNode WithDefaultConstraint(SyntaxNode declaration, string typeParameterName);
 
        /// <summary>
        /// Adds a type constraint to a type parameter of a declaration.
        /// </summary>
        public SyntaxNode WithTypeConstraint(SyntaxNode declaration, string typeParameterName, SpecialTypeConstraintKind kinds, params SyntaxNode[] types)
            => WithTypeConstraint(declaration, typeParameterName, kinds, (IEnumerable<SyntaxNode>)types);
 
        /// <summary>
        /// Adds a type constraint to a type parameter of a declaration.
        /// </summary>
        public SyntaxNode WithTypeConstraint(SyntaxNode declaration, string typeParameterName, params SyntaxNode[] types)
            => WithTypeConstraint(declaration, typeParameterName, SpecialTypeConstraintKind.None, (IEnumerable<SyntaxNode>)types);
 
        /// <summary>
        /// Creates a namespace declaration.
        /// </summary>
        /// <param name="name">The name of the namespace.</param>
        /// <param name="declarations">Zero or more namespace or type declarations.</param>
        public abstract SyntaxNode NamespaceDeclaration(SyntaxNode name, IEnumerable<SyntaxNode> declarations);
 
        /// <summary>
        /// Creates a namespace declaration.
        /// </summary>
        /// <param name="name">The name of the namespace.</param>
        /// <param name="declarations">Zero or more namespace or type declarations.</param>
        public SyntaxNode NamespaceDeclaration(SyntaxNode name, params SyntaxNode[] declarations)
            => NamespaceDeclaration(name, (IEnumerable<SyntaxNode>)declarations);
 
        /// <summary>
        /// Creates a namespace declaration.
        /// </summary>
        /// <param name="name">The name of the namespace.</param>
        /// <param name="declarations">Zero or more namespace or type declarations.</param>
        public SyntaxNode NamespaceDeclaration(string name, IEnumerable<SyntaxNode> declarations)
            => NamespaceDeclaration(DottedName(name), declarations);
 
        /// <summary>
        /// Creates a namespace declaration.
        /// </summary>
        /// <param name="name">The name of the namespace.</param>
        /// <param name="declarations">Zero or more namespace or type declarations.</param>
        public SyntaxNode NamespaceDeclaration(string name, params SyntaxNode[] declarations)
            => NamespaceDeclaration(DottedName(name), (IEnumerable<SyntaxNode>)declarations);
 
        /// <summary>
        /// Creates a compilation unit declaration
        /// </summary>
        /// <param name="declarations">Zero or more namespace import, namespace or type declarations.</param>
        public abstract SyntaxNode CompilationUnit(IEnumerable<SyntaxNode> declarations);
 
        /// <summary>
        /// Creates a compilation unit declaration
        /// </summary>
        /// <param name="declarations">Zero or more namespace import, namespace or type declarations.</param>
        public SyntaxNode CompilationUnit(params SyntaxNode[] declarations)
            => CompilationUnit((IEnumerable<SyntaxNode>)declarations);
 
        /// <summary>
        /// Creates a namespace import declaration.
        /// </summary>
        /// <param name="name">The name of the namespace being imported.</param>
        public abstract SyntaxNode NamespaceImportDeclaration(SyntaxNode name);
 
        /// <summary>
        /// Creates a namespace import declaration.
        /// </summary>
        /// <param name="name">The name of the namespace being imported.</param>
        public SyntaxNode NamespaceImportDeclaration(string name)
            => NamespaceImportDeclaration(DottedName(name));
 
        /// <summary>
        /// Creates an alias import declaration.
        /// </summary>
        /// <param name="aliasIdentifierName">The name of the alias.</param>
        /// <param name="symbol">The namespace or type to be aliased.</param>
        public SyntaxNode AliasImportDeclaration(string aliasIdentifierName, INamespaceOrTypeSymbol symbol)
            => AliasImportDeclaration(aliasIdentifierName, NameExpression(symbol));
 
        /// <summary>
        /// Creates an alias import declaration.
        /// </summary>
        /// <param name="aliasIdentifierName">The name of the alias.</param>
        /// <param name="name">The namespace or type to be aliased.</param>
        public abstract SyntaxNode AliasImportDeclaration(string aliasIdentifierName, SyntaxNode name);
 
        /// <summary>
        /// Creates an attribute.
        /// </summary>
        public abstract SyntaxNode Attribute(SyntaxNode name, IEnumerable<SyntaxNode>? attributeArguments = null);
 
        /// <summary>
        /// Creates an attribute.
        /// </summary>
        public SyntaxNode Attribute(string name, IEnumerable<SyntaxNode>? attributeArguments = null)
            => Attribute(DottedName(name), attributeArguments);
 
        /// <summary>
        /// Creates an attribute.
        /// </summary>
        public SyntaxNode Attribute(string name, params SyntaxNode[] attributeArguments)
            => Attribute(name, (IEnumerable<SyntaxNode>)attributeArguments);
 
        /// <summary>
        /// Creates an attribute matching existing attribute data.
        /// </summary>
        public SyntaxNode Attribute(AttributeData attribute)
        {
            Contract.ThrowIfNull(attribute.AttributeClass);
 
            var args = attribute.ConstructorArguments.Select(a => this.AttributeArgument(this.TypedConstantExpression(a)))
                    .Concat(attribute.NamedArguments.Select(n => this.AttributeArgument(n.Key, this.TypedConstantExpression(n.Value))))
                    .ToBoxedImmutableArray();
 
            return Attribute(
                name: this.TypeExpression(attribute.AttributeClass),
                attributeArguments: args.Count > 0 ? args : null);
        }
 
        /// <summary>
        /// Creates an attribute argument.
        /// </summary>
        public abstract SyntaxNode AttributeArgument(string? name, SyntaxNode expression);
 
        /// <summary>
        /// Creates an attribute argument.
        /// </summary>
        public SyntaxNode AttributeArgument(SyntaxNode expression)
            => AttributeArgument(name: null, expression);
 
        /// <summary>
        /// Removes all attributes from the declaration, including return attributes.
        /// </summary>
        public SyntaxNode RemoveAllAttributes(SyntaxNode declaration)
            => RemoveNodes(declaration, GetAttributes(declaration).Concat(GetReturnAttributes(declaration)));
 
        /// <summary>
        /// Removes comments from leading and trailing trivia, as well
        /// as potentially removing comments from opening and closing tokens.
        /// </summary>
        internal abstract SyntaxNode RemoveAllComments(SyntaxNode node);
 
        internal SyntaxNode RemoveLeadingAndTrailingComments(SyntaxNode node)
        {
            return node.WithLeadingTrivia(RemoveCommentLines(node.GetLeadingTrivia()))
                .WithTrailingTrivia(RemoveCommentLines(node.GetTrailingTrivia()));
        }
 
        internal SyntaxToken RemoveLeadingAndTrailingComments(SyntaxToken token)
        {
            return token.WithLeadingTrivia(RemoveCommentLines(token.LeadingTrivia))
                .WithTrailingTrivia(RemoveCommentLines(token.TrailingTrivia));
        }
 
        internal abstract SyntaxTriviaList RemoveCommentLines(SyntaxTriviaList syntaxTriviaList);
 
        internal abstract bool IsRegularOrDocComment(SyntaxTrivia trivia);
 
        internal SyntaxNode RemoveAllTypeInheritance(SyntaxNode declaration)
            => RemoveNodes(declaration, GetTypeInheritance(declaration));
 
        internal abstract ImmutableArray<SyntaxNode> GetTypeInheritance(SyntaxNode declaration);
 
        /// <summary>
        /// Gets the attributes of a declaration, not including the return attributes.
        /// </summary>
        public abstract IReadOnlyList<SyntaxNode> GetAttributes(SyntaxNode declaration);
 
        /// <summary>
        /// Creates a new instance of the declaration with the attributes inserted.
        /// </summary>
        public abstract SyntaxNode InsertAttributes(SyntaxNode declaration, int index, IEnumerable<SyntaxNode> attributes);
 
        /// <summary>
        /// Creates a new instance of the declaration with the attributes inserted.
        /// </summary>
        public SyntaxNode InsertAttributes(SyntaxNode declaration, int index, params SyntaxNode[] attributes)
            => this.InsertAttributes(declaration, index, (IEnumerable<SyntaxNode>)attributes);
 
        /// <summary>
        /// Creates a new instance of a declaration with the specified attributes added.
        /// </summary>
        public SyntaxNode AddAttributes(SyntaxNode declaration, IEnumerable<SyntaxNode> attributes)
            => this.InsertAttributes(declaration, this.GetAttributes(declaration).Count, attributes);
 
        /// <summary>
        /// Creates a new instance of a declaration with the specified attributes added.
        /// </summary>
        public SyntaxNode AddAttributes(SyntaxNode declaration, params SyntaxNode[] attributes)
            => AddAttributes(declaration, (IEnumerable<SyntaxNode>)attributes);
 
        /// <summary>
        /// Gets the return attributes from the declaration.
        /// </summary>
        public abstract IReadOnlyList<SyntaxNode> GetReturnAttributes(SyntaxNode declaration);
 
        /// <summary>
        /// Creates a new instance of a method declaration with return attributes inserted.
        /// </summary>
        public abstract SyntaxNode InsertReturnAttributes(SyntaxNode declaration, int index, IEnumerable<SyntaxNode> attributes);
 
        /// <summary>
        /// Creates a new instance of a method declaration with return attributes inserted.
        /// </summary>
        public SyntaxNode InsertReturnAttributes(SyntaxNode declaration, int index, params SyntaxNode[] attributes)
            => this.InsertReturnAttributes(declaration, index, (IEnumerable<SyntaxNode>)attributes);
 
        /// <summary>
        /// Creates a new instance of a method declaration with return attributes added.
        /// </summary>
        public SyntaxNode AddReturnAttributes(SyntaxNode declaration, IEnumerable<SyntaxNode> attributes)
            => this.InsertReturnAttributes(declaration, this.GetReturnAttributes(declaration).Count, attributes);
 
        /// <summary>
        /// Creates a new instance of a method declaration node with return attributes added.
        /// </summary>
        public SyntaxNode AddReturnAttributes(SyntaxNode declaration, params SyntaxNode[] attributes)
            => AddReturnAttributes(declaration, (IEnumerable<SyntaxNode>)attributes);
 
        /// <summary>
        /// Gets the attribute arguments for the attribute declaration.
        /// </summary>
        public abstract IReadOnlyList<SyntaxNode> GetAttributeArguments(SyntaxNode attributeDeclaration);
 
        /// <summary>
        /// Creates a new instance of the attribute with the arguments inserted.
        /// </summary>
        public abstract SyntaxNode InsertAttributeArguments(SyntaxNode attributeDeclaration, int index, IEnumerable<SyntaxNode> attributeArguments);
 
        /// <summary>
        /// Creates a new instance of the attribute with the arguments added.
        /// </summary>
        public SyntaxNode AddAttributeArguments(SyntaxNode attributeDeclaration, IEnumerable<SyntaxNode> attributeArguments)
            => this.InsertAttributeArguments(attributeDeclaration, this.GetAttributeArguments(attributeDeclaration).Count, attributeArguments);
 
        /// <summary>
        /// Gets the namespace imports that are part of the declaration.
        /// </summary>
        public abstract IReadOnlyList<SyntaxNode> GetNamespaceImports(SyntaxNode declaration);
 
        /// <summary>
        /// Creates a new instance of the declaration with the namespace imports inserted.
        /// </summary>
        public abstract SyntaxNode InsertNamespaceImports(SyntaxNode declaration, int index, IEnumerable<SyntaxNode> imports);
 
        /// <summary>
        /// Creates a new instance of the declaration with the namespace imports inserted.
        /// </summary>
        public SyntaxNode InsertNamespaceImports(SyntaxNode declaration, int index, params SyntaxNode[] imports)
            => this.InsertNamespaceImports(declaration, index, (IEnumerable<SyntaxNode>)imports);
 
        /// <summary>
        /// Creates a new instance of the declaration with the namespace imports added.
        /// </summary>
        public SyntaxNode AddNamespaceImports(SyntaxNode declaration, IEnumerable<SyntaxNode> imports)
            => this.InsertNamespaceImports(declaration, this.GetNamespaceImports(declaration).Count, imports);
 
        /// <summary>
        /// Creates a new instance of the declaration with the namespace imports added.
        /// </summary>
        public SyntaxNode AddNamespaceImports(SyntaxNode declaration, params SyntaxNode[] imports)
            => this.AddNamespaceImports(declaration, (IEnumerable<SyntaxNode>)imports);
 
        /// <summary>
        /// Gets the current members of the declaration.
        /// </summary>
        public abstract IReadOnlyList<SyntaxNode> GetMembers(SyntaxNode declaration);
 
        /// <summary>
        /// Creates a new instance of the declaration with the members inserted.
        /// </summary>
        public abstract SyntaxNode InsertMembers(SyntaxNode declaration, int index, IEnumerable<SyntaxNode> members);
 
        /// <summary>
        /// Creates a new instance of the declaration with the members inserted.
        /// </summary>
        public SyntaxNode InsertMembers(SyntaxNode declaration, int index, params SyntaxNode[] members)
            => this.InsertMembers(declaration, index, (IEnumerable<SyntaxNode>)members);
 
        /// <summary>
        /// Creates a new instance of the declaration with the members added to the end.
        /// </summary>
        public SyntaxNode AddMembers(SyntaxNode declaration, IEnumerable<SyntaxNode> members)
            => this.InsertMembers(declaration, this.GetMembers(declaration).Count, members);
 
        /// <summary>
        /// Creates a new instance of the declaration with the members added to the end.
        /// </summary>
        public SyntaxNode AddMembers(SyntaxNode declaration, params SyntaxNode[] members)
            => this.AddMembers(declaration, (IEnumerable<SyntaxNode>)members);
 
        /// <summary>
        /// Gets the accessibility of the declaration.
        /// </summary>
        public abstract Accessibility GetAccessibility(SyntaxNode declaration);
 
        /// <summary>
        /// Changes the accessibility of the declaration.
        /// </summary>
        public abstract SyntaxNode WithAccessibility(SyntaxNode declaration, Accessibility accessibility);
 
        /// <summary>
        /// Gets the <see cref="DeclarationModifiers"/> for the declaration.
        /// </summary>
        public abstract DeclarationModifiers GetModifiers(SyntaxNode declaration);
 
        /// <summary>
        /// Changes the <see cref="DeclarationModifiers"/> for the declaration.
        /// </summary>
        public abstract SyntaxNode WithModifiers(SyntaxNode declaration, DeclarationModifiers modifiers);
 
        /// <summary>
        /// Gets the <see cref="DeclarationKind"/> for the declaration.
        /// </summary>
        public abstract DeclarationKind GetDeclarationKind(SyntaxNode declaration);
 
        /// <summary>
        /// Gets the name of the declaration.
        /// </summary>
        public abstract string GetName(SyntaxNode declaration);
 
        /// <summary>
        /// Changes the name of the declaration.
        /// </summary>
        public abstract SyntaxNode WithName(SyntaxNode declaration, string name);
 
        /// <summary>
        /// Gets the type of the declaration.
        /// </summary>
        public abstract SyntaxNode? GetType(SyntaxNode declaration);
 
        /// <summary>
        /// Changes the type of the declaration.
        /// </summary>
        public abstract SyntaxNode WithType(SyntaxNode declaration, SyntaxNode type);
 
        /// <summary>
        /// Gets the list of parameters for the declaration.
        /// </summary>
        public abstract IReadOnlyList<SyntaxNode> GetParameters(SyntaxNode declaration);
 
        internal abstract SyntaxNode? GetParameterListNode(SyntaxNode declaration);
 
        /// <summary>
        /// Inserts the parameters at the specified index into the declaration.
        /// </summary>
        public abstract SyntaxNode InsertParameters(SyntaxNode declaration, int index, IEnumerable<SyntaxNode> parameters);
 
        /// <summary>
        /// Adds the parameters to the declaration.
        /// </summary>
        public SyntaxNode AddParameters(SyntaxNode declaration, IEnumerable<SyntaxNode> parameters)
            => this.InsertParameters(declaration, this.GetParameters(declaration).Count, parameters);
 
        /// <summary>
        /// Gets the list of switch sections for the statement.
        /// </summary>
        public abstract IReadOnlyList<SyntaxNode> GetSwitchSections(SyntaxNode switchStatement);
 
        /// <summary>
        /// Inserts the switch sections at the specified index into the statement.
        /// </summary>
        public abstract SyntaxNode InsertSwitchSections(SyntaxNode switchStatement, int index, IEnumerable<SyntaxNode> switchSections);
 
        /// <summary>
        /// Adds the switch sections to the statement.
        /// </summary>
        public SyntaxNode AddSwitchSections(SyntaxNode switchStatement, IEnumerable<SyntaxNode> switchSections)
            => this.InsertSwitchSections(switchStatement, this.GetSwitchSections(switchStatement).Count, switchSections);
 
        /// <summary>
        /// Gets the expression associated with the declaration.
        /// </summary>
        public abstract SyntaxNode? GetExpression(SyntaxNode declaration);
 
        /// <summary>
        /// Changes the expression associated with the declaration.
        /// </summary>
        public abstract SyntaxNode WithExpression(SyntaxNode declaration, SyntaxNode expression);
 
        /// <summary>
        /// Gets the statements for the body of the declaration.
        /// </summary>
        public abstract IReadOnlyList<SyntaxNode> GetStatements(SyntaxNode declaration);
 
        /// <summary>
        /// Changes the statements for the body of the declaration.
        /// </summary>
        public abstract SyntaxNode WithStatements(SyntaxNode declaration, IEnumerable<SyntaxNode> statements);
 
        /// <summary>
        /// Gets the accessors for the declaration.
        /// </summary>
        public abstract IReadOnlyList<SyntaxNode> GetAccessors(SyntaxNode declaration);
 
        /// <summary>
        /// Gets the accessor of the specified kind for the declaration.
        /// </summary>
        public SyntaxNode? GetAccessor(SyntaxNode declaration, DeclarationKind kind)
            => this.GetAccessors(declaration).FirstOrDefault(a => GetDeclarationKind(a) == kind);
 
        /// <summary>
        /// Creates a new instance of the declaration with the accessors inserted.
        /// </summary>
        public abstract SyntaxNode InsertAccessors(SyntaxNode declaration, int index, IEnumerable<SyntaxNode> accessors);
 
        /// <summary>
        /// Creates a new instance of the declaration with the accessors added.
        /// </summary>
        public SyntaxNode AddAccessors(SyntaxNode declaration, IEnumerable<SyntaxNode> accessors)
            => this.InsertAccessors(declaration, this.GetAccessors(declaration).Count, accessors);
 
        /// <summary>
        /// Gets the statements for the body of the get-accessor of the declaration.
        /// </summary>
        public abstract IReadOnlyList<SyntaxNode> GetGetAccessorStatements(SyntaxNode declaration);
 
        /// <summary>
        /// Changes the statements for the body of the get-accessor of the declaration.
        /// </summary>
        public abstract SyntaxNode WithGetAccessorStatements(SyntaxNode declaration, IEnumerable<SyntaxNode> statements);
 
        /// <summary>
        /// Gets the statements for the body of the set-accessor of the declaration.
        /// </summary>
        public abstract IReadOnlyList<SyntaxNode> GetSetAccessorStatements(SyntaxNode declaration);
 
        /// <summary>
        /// Changes the statements for the body of the set-accessor of the declaration.
        /// </summary>
        public abstract SyntaxNode WithSetAccessorStatements(SyntaxNode declaration, IEnumerable<SyntaxNode> statements);
 
        /// <summary>
        /// Gets a list of the base and interface types for the declaration.
        /// </summary>
        public abstract IReadOnlyList<SyntaxNode> GetBaseAndInterfaceTypes(SyntaxNode declaration);
 
        /// <summary>
        /// Adds a base type to the declaration
        /// </summary>
        public abstract SyntaxNode AddBaseType(SyntaxNode declaration, SyntaxNode baseType);
 
        /// <summary>
        /// Adds an interface type to the declaration
        /// </summary>
        public abstract SyntaxNode AddInterfaceType(SyntaxNode declaration, SyntaxNode interfaceType);
 
        internal abstract SyntaxNode AsInterfaceMember(SyntaxNode member);
 
        #endregion
 
        #region Remove, Replace, Insert
 
        /// <summary>
        /// Replaces the node in the root's tree with the new node.
        /// </summary>
        public virtual SyntaxNode ReplaceNode(SyntaxNode root, SyntaxNode node, SyntaxNode? newDeclaration)
            => (newDeclaration != null) ? root.ReplaceNode(node, newDeclaration) : RemoveNode(root, node);
 
        internal static SyntaxNode ReplaceNode(SyntaxNode root, SyntaxNode node, IEnumerable<SyntaxNode> newDeclarations)
        {
            Contract.ThrowIfTrue(ReferenceEquals(root, node));
            return root.ReplaceNode(node, newDeclarations);
        }
 
        /// <summary>
        /// Inserts the new node before the specified declaration.
        /// </summary>
        public virtual SyntaxNode InsertNodesBefore(SyntaxNode root, SyntaxNode node, IEnumerable<SyntaxNode> newDeclarations)
            => root.InsertNodesBefore(node, newDeclarations);
 
        /// <summary>
        /// Inserts the new node before the specified declaration.
        /// </summary>
        public virtual SyntaxNode InsertNodesAfter(SyntaxNode root, SyntaxNode node, IEnumerable<SyntaxNode> newDeclarations)
            => root.InsertNodesAfter(node, newDeclarations);
 
        /// <summary>
        /// Removes the node from the sub tree starting at the root.
        /// </summary>
        public virtual SyntaxNode RemoveNode(SyntaxNode root, SyntaxNode node)
            => RemoveNode(root, node, DefaultRemoveOptions);
 
        /// <summary>
        /// Removes the node from the sub tree starting at the root.
        /// </summary>
        public virtual SyntaxNode RemoveNode(SyntaxNode root, SyntaxNode node, SyntaxRemoveOptions options)
            => root.RemoveNode(node, options) ?? throw new InvalidOperationException($"Can't remove root node.");
 
        /// <summary>
        /// Removes all the declarations from the sub tree starting at the root.
        /// </summary>
        public SyntaxNode RemoveNodes(SyntaxNode root, IEnumerable<SyntaxNode> declarations)
        {
            var newRoot = root.TrackNodes(declarations);
 
            foreach (var declaration in declarations)
            {
                var newDeclaration = newRoot.GetCurrentNode(declaration);
                if (newDeclaration == null)
                {
                    continue;
                }
 
                newRoot = RemoveNode(newRoot, newDeclaration);
            }
 
            return newRoot;
        }
 
        #endregion
 
        #region Utility
 
        internal abstract SeparatedSyntaxList<TElement> SeparatedList<TElement>(SyntaxNodeOrTokenList list) where TElement : SyntaxNode;
 
        internal abstract SeparatedSyntaxList<TElement> SeparatedList<TElement>(IEnumerable<TElement> nodes, IEnumerable<SyntaxToken> separators) where TElement : SyntaxNode;
 
        internal static SyntaxTokenList Merge(SyntaxTokenList original, SyntaxTokenList newList)
        {
            // return tokens from newList, but use original tokens of kind matches
            return new SyntaxTokenList(newList.Select(
                token => Any(original, token.RawKind)
                    ? original.First(tk => tk.RawKind == token.RawKind)
                    : token));
        }
 
        private static bool Any(SyntaxTokenList original, int rawKind)
        {
            foreach (var token in original)
            {
                if (token.RawKind == rawKind)
                {
                    return true;
                }
            }
 
            return false;
        }
 
        [return: NotNullIfNotNull(nameof(node))]
        protected static SyntaxNode? PreserveTrivia<TNode>(TNode? node, Func<TNode, SyntaxNode> nodeChanger) where TNode : SyntaxNode
        {
            if (node == null)
            {
                return node;
            }
 
            var nodeWithoutTrivia = node.WithoutLeadingTrivia().WithoutTrailingTrivia();
 
            var changedNode = nodeChanger(nodeWithoutTrivia);
            if (changedNode == nodeWithoutTrivia)
            {
                return node;
            }
 
            return changedNode
                .WithLeadingTrivia(node.GetLeadingTrivia().Concat(changedNode.GetLeadingTrivia()))
                .WithTrailingTrivia(changedNode.GetTrailingTrivia().Concat(node.GetTrailingTrivia()));
        }
 
        protected static SyntaxNode ReplaceWithTrivia(SyntaxNode root, SyntaxNode original, SyntaxNode replacement)
        {
            var combinedTriviaReplacement =
                replacement.WithLeadingTrivia(original.GetLeadingTrivia().AddRange(replacement.GetLeadingTrivia()))
                           .WithTrailingTrivia(replacement.GetTrailingTrivia().AddRange(original.GetTrailingTrivia()));
 
            return root.ReplaceNode(original, combinedTriviaReplacement);
        }
 
        protected static SyntaxNode ReplaceWithTrivia<TNode>(SyntaxNode root, TNode original, Func<TNode, SyntaxNode> replacer)
            where TNode : SyntaxNode
        {
            return ReplaceWithTrivia(root, original, replacer(original));
        }
 
        protected static SyntaxNode ReplaceWithTrivia(SyntaxNode root, SyntaxToken original, SyntaxToken replacement)
        {
            var combinedTriviaReplacement =
                replacement.WithLeadingTrivia(original.LeadingTrivia.AddRange(replacement.LeadingTrivia))
                           .WithTrailingTrivia(replacement.TrailingTrivia.AddRange(original.TrailingTrivia));
 
            return root.ReplaceToken(original, combinedTriviaReplacement);
        }
 
        /// <summary>
        /// Creates a new instance of the node with the leading and trailing trivia removed and replaced with elastic markers.
        /// </summary>
        [return: MaybeNull, NotNullIfNotNull(nameof(node))]
        public abstract TNode ClearTrivia<TNode>([MaybeNull] TNode node) where TNode : SyntaxNode;
 
#pragma warning disable CA1822 // Mark members as static - shipped public API
        protected int IndexOf<T>(IReadOnlyList<T> list, T element)
#pragma warning restore CA1822 // Mark members as static
        {
            for (int i = 0, count = list.Count; i < count; i++)
            {
                if (EqualityComparer<T>.Default.Equals(list[i], element))
                {
                    return i;
                }
            }
 
            return -1;
        }
 
        protected static SyntaxNode ReplaceRange(SyntaxNode root, SyntaxNode node, IEnumerable<SyntaxNode> replacements)
        {
            var first = replacements.First();
            var trackedFirst = first.TrackNodes(first);
            var newRoot = root.ReplaceNode(node, trackedFirst);
            var currentFirst = newRoot.GetCurrentNode(first);
            Contract.ThrowIfNull(currentFirst);
 
            return newRoot.InsertNodesAfter(currentFirst, replacements.Skip(1));
        }
 
        protected static SeparatedSyntaxList<TNode> RemoveRange<TNode>(SeparatedSyntaxList<TNode> list, int offset, int count)
            where TNode : SyntaxNode
        {
            for (; count > 0 && offset < list.Count; count--)
            {
                list = list.RemoveAt(offset);
            }
 
            return list;
        }
 
        protected static SyntaxList<TNode> RemoveRange<TNode>(SyntaxList<TNode> list, int offset, int count)
            where TNode : SyntaxNode
        {
            for (; count > 0 && offset < list.Count; count--)
            {
                list = list.RemoveAt(offset);
            }
 
            return list;
        }
 
        #endregion
 
        #region Statements
        /// <summary>
        /// Creates statement that allows an expression to execute in a statement context.
        /// This is typically an invocation or assignment expression.
        /// </summary>
        /// <param name="expression">The expression that is to be executed. This is usually a method invocation expression.</param>
        public abstract SyntaxNode ExpressionStatement(SyntaxNode expression);
 
        /// <summary>
        /// Creates a statement that can be used to return a value from a method body.
        /// </summary>
        /// <param name="expression">An optional expression that can be returned.</param>
        public abstract SyntaxNode ReturnStatement(SyntaxNode? expression = null);
 
        /// <summary>
        /// Creates a statement that can be used to yield a value from an iterator method.
        /// </summary>
        /// <param name="expression">An expression that can be yielded.</param>
        internal SyntaxNode YieldReturnStatement(SyntaxNode expression)
            => SyntaxGeneratorInternal.YieldReturnStatement(expression);
 
        /// <summary>
        /// Creates a statement that can be used to throw an exception.
        /// </summary>
        /// <param name="expression">An optional expression that can be thrown.</param>
        public abstract SyntaxNode ThrowStatement(SyntaxNode? expression = null);
 
        /// <summary>
        /// Creates an expression that can be used to throw an exception.
        /// </summary>
        public abstract SyntaxNode ThrowExpression(SyntaxNode expression);
 
        /// <summary>
        /// True if <see cref="ThrowExpression"/> can be used
        /// </summary>
        internal abstract bool SupportsThrowExpression();
 
        /// <summary>
        /// <see langword="true"/> if the language requires a <see cref="TypeExpression(ITypeSymbol)"/>
        /// (including <see langword="var"/>) to be stated when making a 
        /// <see cref="LocalDeclarationStatement(ITypeSymbol, string, SyntaxNode, bool)"/>.
        /// <see langword="false"/> if the language allows the type node to be entirely elided.
        /// </summary>
        internal bool RequiresLocalDeclarationType() => SyntaxGeneratorInternal.RequiresLocalDeclarationType();
 
        /// <summary>
        /// Creates a statement that declares a single local variable.
        /// </summary>
        public abstract SyntaxNode LocalDeclarationStatement(
            SyntaxNode? type, string identifier, SyntaxNode? initializer = null, bool isConst = false);
 
        internal SyntaxNode LocalDeclarationStatement(SyntaxNode? type, SyntaxToken identifier, SyntaxNode? initializer = null, bool isConst = false)
            => SyntaxGeneratorInternal.LocalDeclarationStatement(type, identifier, initializer, isConst);
 
        internal SyntaxNode WithInitializer(SyntaxNode variableDeclarator, SyntaxNode initializer)
            => SyntaxGeneratorInternal.WithInitializer(variableDeclarator, initializer);
 
        internal SyntaxNode EqualsValueClause(SyntaxToken operatorToken, SyntaxNode value)
            => SyntaxGeneratorInternal.EqualsValueClause(operatorToken, value);
 
        /// <summary>
        /// Creates a statement that declares a single local variable.
        /// </summary>
        public SyntaxNode LocalDeclarationStatement(ITypeSymbol type, string name, SyntaxNode? initializer = null, bool isConst = false)
            => LocalDeclarationStatement(TypeExpression(type), name, initializer, isConst);
 
        /// <summary>
        /// Creates a statement that declares a single local variable.
        /// </summary>
        public SyntaxNode LocalDeclarationStatement(string name, SyntaxNode initializer)
            => LocalDeclarationStatement(type: (SyntaxNode?)null, name, initializer);
 
        /// <summary>
        /// Creates a statement that declares a single local variable.
        /// </summary>
        internal SyntaxNode LocalDeclarationStatement(SyntaxToken name, SyntaxNode initializer)
            => LocalDeclarationStatement(type: null, name, initializer);
 
        /// <summary>
        /// Creates an if-statement
        /// </summary>
        /// <param name="condition">A condition expression.</param>
        /// <param name="trueStatements">The statements that are executed if the condition is true.</param>
        /// <param name="falseStatements">The statements that are executed if the condition is false.</param>
        public abstract SyntaxNode IfStatement(
            SyntaxNode condition, IEnumerable<SyntaxNode> trueStatements, IEnumerable<SyntaxNode>? falseStatements = null);
 
        /// <summary>
        /// Creates an if statement
        /// </summary>
        /// <param name="condition">A condition expression.</param>
        /// <param name="trueStatements">The statements that are executed if the condition is true.</param>
        /// <param name="falseStatement">A single statement that is executed if the condition is false.</param>
        public SyntaxNode IfStatement(SyntaxNode condition, IEnumerable<SyntaxNode> trueStatements, SyntaxNode falseStatement)
            => IfStatement(condition, trueStatements, new[] { falseStatement });
 
        /// <summary>
        /// Creates a switch statement that branches to individual sections based on the value of the specified expression.
        /// </summary>
        public abstract SyntaxNode SwitchStatement(SyntaxNode expression, IEnumerable<SyntaxNode> sections);
 
        /// <summary>
        /// Creates a switch statement that branches to individual sections based on the value of the specified expression.
        /// </summary>
        public SyntaxNode SwitchStatement(SyntaxNode expression, params SyntaxNode[] sections)
            => SwitchStatement(expression, (IEnumerable<SyntaxNode>)sections);
 
        /// <summary>
        /// Creates a section for a switch statement.
        /// </summary>
        public abstract SyntaxNode SwitchSection(IEnumerable<SyntaxNode> caseExpressions, IEnumerable<SyntaxNode> statements);
 
        internal abstract SyntaxNode SwitchSectionFromLabels(IEnumerable<SyntaxNode> labels, IEnumerable<SyntaxNode> statements);
 
        /// <summary>
        /// Creates a single-case section a switch statement.
        /// </summary>
        public SyntaxNode SwitchSection(SyntaxNode caseExpression, IEnumerable<SyntaxNode> statements)
            => SwitchSection(new[] { caseExpression }, statements);
 
        /// <summary>
        /// Creates a default section for a switch statement.
        /// </summary>
        public abstract SyntaxNode DefaultSwitchSection(IEnumerable<SyntaxNode> statements);
 
        /// <summary>
        /// Create a statement that exits a switch statement and continues after it.
        /// </summary>
        public abstract SyntaxNode ExitSwitchStatement();
 
        /// <summary>
        /// Creates a statement that represents a using-block pattern.
        /// </summary>
        public abstract SyntaxNode UsingStatement(SyntaxNode? type, string name, SyntaxNode expression, IEnumerable<SyntaxNode> statements);
 
        /// <summary>
        /// Creates a statement that represents a using-block pattern.
        /// </summary>
        public SyntaxNode UsingStatement(string name, SyntaxNode expression, IEnumerable<SyntaxNode> statements)
            => UsingStatement(type: null, name, expression, statements);
 
        /// <summary>
        /// Creates a statement that represents a using-block pattern.
        /// </summary>
        public abstract SyntaxNode UsingStatement(SyntaxNode expression, IEnumerable<SyntaxNode> statements);
 
        /// <summary>
        /// Creates a statement that represents a lock-block pattern.
        /// </summary>
        public abstract SyntaxNode LockStatement(SyntaxNode expression, IEnumerable<SyntaxNode> statements);
 
        /// <summary>
        /// Creates a try-catch or try-catch-finally statement.
        /// </summary>
        public abstract SyntaxNode TryCatchStatement(IEnumerable<SyntaxNode> tryStatements, IEnumerable<SyntaxNode>? catchClauses, IEnumerable<SyntaxNode>? finallyStatements = null);
 
        /// <summary>
        /// Creates a try-catch or try-catch-finally statement.
        /// </summary>
        public SyntaxNode TryCatchStatement(IEnumerable<SyntaxNode> tryStatements, params SyntaxNode[] catchClauses)
            => TryCatchStatement(tryStatements, (IEnumerable<SyntaxNode>?)catchClauses);
 
        /// <summary>
        /// Creates a try-finally statement.
        /// </summary>
        public SyntaxNode TryFinallyStatement(IEnumerable<SyntaxNode> tryStatements, IEnumerable<SyntaxNode> finallyStatements)
            => TryCatchStatement(tryStatements, catchClauses: null, finallyStatements: finallyStatements);
 
        /// <summary>
        /// Creates a catch-clause.
        /// </summary>
        public abstract SyntaxNode CatchClause(SyntaxNode type, string identifier, IEnumerable<SyntaxNode> statements);
 
        /// <summary>
        /// Creates a catch-clause.
        /// </summary>
        public SyntaxNode CatchClause(ITypeSymbol type, string identifier, IEnumerable<SyntaxNode> statements)
            => CatchClause(TypeExpression(type), identifier, statements);
 
        /// <summary>
        /// Creates a while-loop statement
        /// </summary>
        public abstract SyntaxNode WhileStatement(SyntaxNode condition, IEnumerable<SyntaxNode> statements);
 
        /// <summary>
        /// Creates a block of statements. Not supported in VB.
        /// </summary>
        internal abstract SyntaxNode ScopeBlock(IEnumerable<SyntaxNode> statements);
 
        internal abstract SyntaxNode GlobalStatement(SyntaxNode statement);
 
        #endregion
 
        #region Expressions
 
        internal abstract SyntaxToken NumericLiteralToken(string text, ulong value);
 
        internal SyntaxToken InterpolatedStringTextToken(string content, string value)
            => SyntaxGeneratorInternal.InterpolatedStringTextToken(content, value);
        internal SyntaxNode InterpolatedStringText(SyntaxToken textToken)
            => SyntaxGeneratorInternal.InterpolatedStringText(textToken);
        internal SyntaxNode Interpolation(SyntaxNode syntaxNode)
            => SyntaxGeneratorInternal.Interpolation(syntaxNode);
        internal SyntaxNode InterpolatedStringExpression(SyntaxToken startToken, IEnumerable<SyntaxNode> content, SyntaxToken endToken)
            => SyntaxGeneratorInternal.InterpolatedStringExpression(startToken, content, endToken);
        internal SyntaxNode InterpolationAlignmentClause(SyntaxNode alignment)
            => SyntaxGeneratorInternal.InterpolationAlignmentClause(alignment);
        internal SyntaxNode InterpolationFormatClause(string format)
            => SyntaxGeneratorInternal.InterpolationFormatClause(format);
 
        /// <summary>
        /// An expression that represents the default value of a type.
        /// This is typically a null value for reference types or a zero-filled value for value types.
        /// </summary>
        public abstract SyntaxNode DefaultExpression(SyntaxNode type);
        public abstract SyntaxNode DefaultExpression(ITypeSymbol type);
 
        /// <summary>
        /// Creates an expression that denotes the containing method's this-parameter.
        /// </summary>
        public abstract SyntaxNode ThisExpression();
 
        /// <summary>
        /// Creates an expression that denotes the containing method's base-parameter.
        /// </summary>
        public abstract SyntaxNode BaseExpression();
 
        /// <summary>
        /// Creates a literal expression. This is typically numeric primitives, strings or chars.
        /// </summary>
        public SyntaxNode LiteralExpression(object? value)
            => GenerateExpression(type: null, value, canUseFieldReference: true);
 
        /// <summary>
        /// Creates an expression for a typed constant.
        /// </summary>
        public abstract SyntaxNode TypedConstantExpression(TypedConstant value);
 
        /// <summary>
        /// Creates an expression that denotes the boolean false literal.
        /// </summary>
        public SyntaxNode FalseLiteralExpression()
            => LiteralExpression(false);
 
        /// <summary>
        /// Creates an expression that denotes the boolean true literal.
        /// </summary>
        public SyntaxNode TrueLiteralExpression()
            => LiteralExpression(true);
 
        /// <summary>
        /// Creates an expression that denotes the null literal.
        /// </summary>
        public SyntaxNode NullLiteralExpression()
            => LiteralExpression(value: null);
 
        /// <summary>
        /// Creates an expression that denotes a simple identifier name.
        /// </summary>
        /// <param name="identifier"></param>
        /// <returns></returns>
        public abstract SyntaxNode IdentifierName(string identifier);
 
        internal abstract SyntaxNode IdentifierName(SyntaxToken identifier);
        internal SyntaxToken Identifier(string identifier) => SyntaxGeneratorInternal.Identifier(identifier);
        internal abstract SyntaxNode NamedAnonymousObjectMemberDeclarator(SyntaxNode identifier, SyntaxNode expression);
 
        /// <summary>
        /// Creates an expression that denotes a generic identifier name.
        /// </summary>
        public abstract SyntaxNode GenericName(string identifier, IEnumerable<SyntaxNode> typeArguments);
 
        internal abstract SyntaxNode GenericName(SyntaxToken identifier, IEnumerable<SyntaxNode> typeArguments);
 
        /// <summary>
        /// Creates an expression that denotes a generic identifier name.
        /// </summary>
        public SyntaxNode GenericName(string identifier, IEnumerable<ITypeSymbol> typeArguments)
            => GenericName(identifier, typeArguments.Select(TypeExpression));
 
        /// <summary>
        /// Creates an expression that denotes a generic identifier name.
        /// </summary>
        public SyntaxNode GenericName(string identifier, params SyntaxNode[] typeArguments)
            => GenericName(identifier, (IEnumerable<SyntaxNode>)typeArguments);
 
        /// <summary>
        /// Creates an expression that denotes a generic identifier name.
        /// </summary>
        public SyntaxNode GenericName(string identifier, params ITypeSymbol[] typeArguments)
            => GenericName(identifier, (IEnumerable<ITypeSymbol>)typeArguments);
 
        /// <summary>
        /// Converts an expression that ends in a name into an expression that ends in a generic name.
        /// If the expression already ends in a generic name, the new type arguments are used instead.
        /// </summary>
        public abstract SyntaxNode WithTypeArguments(SyntaxNode expression, IEnumerable<SyntaxNode> typeArguments);
 
        /// <summary>
        /// Converts an expression that ends in a name into an expression that ends in a generic name.
        /// If the expression already ends in a generic name, the new type arguments are used instead.
        /// </summary>
        public SyntaxNode WithTypeArguments(SyntaxNode expression, params SyntaxNode[] typeArguments)
            => WithTypeArguments(expression, (IEnumerable<SyntaxNode>)typeArguments);
 
        /// <summary>
        /// Creates a name expression that denotes a qualified name. 
        /// The left operand can be any name expression.
        /// The right operand can be either and identifier or generic name.
        /// </summary>
        public abstract SyntaxNode QualifiedName(SyntaxNode left, SyntaxNode right);
 
        /// <summary>
        /// Returns a new name node qualified with the 'global' alias ('Global' in VB).
        /// </summary>
        internal abstract SyntaxNode GlobalAliasedName(SyntaxNode name);
 
        /// <summary>
        /// Creates a name expression from a dotted name string.
        /// </summary>
        public SyntaxNode DottedName(string dottedName)
        {
            if (dottedName == null)
            {
                throw new ArgumentNullException(nameof(dottedName));
            }
 
            var parts = dottedName.Split(s_dotSeparator);
            Debug.Assert(!parts.IsEmpty());
 
            SyntaxNode? name = null;
            foreach (var part in parts)
            {
                if (name == null)
                {
                    name = IdentifierName(part);
                }
                else
                {
                    name = QualifiedName(name, IdentifierName(part)).WithAdditionalAnnotations(Simplifier.Annotation);
                }
            }
 
            Contract.ThrowIfNull(name);
            return name;
        }
 
        private static readonly char[] s_dotSeparator = new char[] { '.' };
 
        /// <summary>
        /// Creates a name that denotes a type or namespace.
        /// </summary>
        /// <param name="namespaceOrTypeSymbol">The symbol to create a name for.</param>
        /// <returns></returns>
        public abstract SyntaxNode NameExpression(INamespaceOrTypeSymbol namespaceOrTypeSymbol);
 
        /// <summary>
        /// Creates an expression that denotes a type.
        /// </summary>
        public SyntaxNode TypeExpression(ITypeSymbol typeSymbol)
            => TypeExpression(typeSymbol, RefKind.None);
 
        private protected abstract SyntaxNode TypeExpression(ITypeSymbol typeSymbol, RefKind refKind);
 
        /// <summary>
        /// Creates an expression that denotes a type. If addImport is false,
        /// adds a <see cref="DoNotAddImportsAnnotation"/> which will prevent any
        /// imports or usings from being added for the type.
        /// </summary>
        public SyntaxNode TypeExpression(ITypeSymbol typeSymbol, bool addImport)
        {
            var expression = TypeExpression(typeSymbol);
            return addImport
                ? expression
                : expression.WithAdditionalAnnotations(DoNotAddImportsAnnotation.Annotation);
        }
 
        /// <summary>
        /// Creates an expression that denotes a special type name.
        /// </summary>
        public abstract SyntaxNode TypeExpression(SpecialType specialType);
 
        /// <summary>
        /// Creates an expression that denotes an array type.
        /// </summary>
        public abstract SyntaxNode ArrayTypeExpression(SyntaxNode type);
 
        /// <summary>
        /// Creates an expression that denotes a nullable type.
        /// </summary>
        public abstract SyntaxNode NullableTypeExpression(SyntaxNode type);
 
        /// <summary>
        /// Creates an expression that denotes a tuple type.
        /// </summary>
        public SyntaxNode TupleTypeExpression(IEnumerable<SyntaxNode> elements)
        {
            if (elements == null)
            {
                throw new ArgumentNullException(nameof(elements));
            }
 
            if (elements.Count() <= 1)
            {
                throw new ArgumentException("Tuples must have at least two elements.", nameof(elements));
            }
 
            return CreateTupleType(elements);
        }
 
        internal abstract SyntaxNode CreateTupleType(IEnumerable<SyntaxNode> elements);
 
        /// <summary>
        /// Creates an expression that denotes a tuple type.
        /// </summary>
        public SyntaxNode TupleTypeExpression(params SyntaxNode[] elements)
            => TupleTypeExpression((IEnumerable<SyntaxNode>)elements);
 
        /// <summary>
        /// Creates an expression that denotes a tuple type.
        /// </summary>
        public SyntaxNode TupleTypeExpression(IEnumerable<ITypeSymbol> elementTypes, IEnumerable<string>? elementNames = null)
        {
            if (elementTypes == null)
            {
                throw new ArgumentNullException(nameof(elementTypes));
            }
 
            if (elementNames != null)
            {
                if (elementNames.Count() != elementTypes.Count())
                {
                    throw new ArgumentException("The number of element names must match the cardinality of the tuple.", nameof(elementNames));
                }
 
                return TupleTypeExpression(elementTypes.Zip(elementNames, TupleElementExpression));
            }
 
            return TupleTypeExpression(elementTypes.Select(type => TupleElementExpression(type, name: null)));
        }
 
#pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters
        /// <summary>
        /// Creates an expression that denotes a tuple element.
        /// </summary>
        public abstract SyntaxNode TupleElementExpression(SyntaxNode type, string? name = null);
 
        /// <summary>
        /// Creates an expression that denotes a tuple element.
        /// </summary>
        public SyntaxNode TupleElementExpression(ITypeSymbol type, string? name = null)
            => TupleElementExpression(TypeExpression(type), name);
#pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters
 
        /// <summary>
        /// Creates an expression that denotes an assignment from the right argument to left argument.
        /// </summary>
        public abstract SyntaxNode AssignmentStatement(SyntaxNode left, SyntaxNode right);
 
        /// <summary>
        /// Creates an expression that denotes a value-type equality test operation.
        /// </summary>
        public abstract SyntaxNode ValueEqualsExpression(SyntaxNode left, SyntaxNode right);
 
        /// <summary>
        /// Creates an expression that denotes a reference-type equality test operation.
        /// </summary>
        public abstract SyntaxNode ReferenceEqualsExpression(SyntaxNode left, SyntaxNode right);
 
        /// <summary>
        /// Creates an expression that denotes a value-type inequality test operation.
        /// </summary>
        public abstract SyntaxNode ValueNotEqualsExpression(SyntaxNode left, SyntaxNode right);
 
        /// <summary>
        /// Creates an expression that denotes a reference-type inequality test operation.
        /// </summary>
        public abstract SyntaxNode ReferenceNotEqualsExpression(SyntaxNode left, SyntaxNode right);
 
        /// <summary>
        /// Creates an expression that denotes a less-than test operation.
        /// </summary>
        public abstract SyntaxNode LessThanExpression(SyntaxNode left, SyntaxNode right);
 
        /// <summary>
        /// Creates an expression that denotes a less-than-or-equal test operation.
        /// </summary>
        public abstract SyntaxNode LessThanOrEqualExpression(SyntaxNode left, SyntaxNode right);
 
        /// <summary>
        /// Creates an expression that denotes a greater-than test operation.
        /// </summary>
        public abstract SyntaxNode GreaterThanExpression(SyntaxNode left, SyntaxNode right);
 
        /// <summary>
        /// Creates an expression that denotes a greater-than-or-equal test operation.
        /// </summary>
        public abstract SyntaxNode GreaterThanOrEqualExpression(SyntaxNode left, SyntaxNode right);
 
        /// <summary>
        /// Creates an expression that denotes a unary negation operation.
        /// </summary>
        public abstract SyntaxNode NegateExpression(SyntaxNode expression);
 
        /// <summary>
        /// Creates an expression that denotes an addition operation.
        /// </summary>
        public abstract SyntaxNode AddExpression(SyntaxNode left, SyntaxNode right);
 
        /// <summary>
        /// Creates an expression that denotes an subtraction operation.
        /// </summary>
        public abstract SyntaxNode SubtractExpression(SyntaxNode left, SyntaxNode right);
 
        /// <summary>
        /// Creates an expression that denotes a multiplication operation.
        /// </summary>
        public abstract SyntaxNode MultiplyExpression(SyntaxNode left, SyntaxNode right);
 
        /// <summary>
        /// Creates an expression that denotes a division operation.
        /// </summary>
        public abstract SyntaxNode DivideExpression(SyntaxNode left, SyntaxNode right);
 
        /// <summary>
        /// Creates an expression that denotes a modulo operation.
        /// </summary>
        public abstract SyntaxNode ModuloExpression(SyntaxNode left, SyntaxNode right);
 
        /// <summary>
        /// Creates an expression that denotes a bitwise-and operation.
        /// </summary>
        public abstract SyntaxNode BitwiseAndExpression(SyntaxNode left, SyntaxNode right);
 
        /// <summary>
        /// Creates an expression that denotes a bitwise-or operation.
        /// </summary>
        public abstract SyntaxNode BitwiseOrExpression(SyntaxNode left, SyntaxNode right);
 
        /// <summary>
        /// Creates an expression that denotes a bitwise-not operation
        /// </summary>
        public abstract SyntaxNode BitwiseNotExpression(SyntaxNode operand);
 
        /// <summary>
        /// Creates an expression that denotes a logical-and operation.
        /// </summary>
        public abstract SyntaxNode LogicalAndExpression(SyntaxNode left, SyntaxNode right);
 
        /// <summary>
        /// Creates an expression that denotes a logical-or operation.
        /// </summary>
        public abstract SyntaxNode LogicalOrExpression(SyntaxNode left, SyntaxNode right);
 
        /// <summary>
        /// Creates an expression that denotes a logical not operation.
        /// </summary>
        public abstract SyntaxNode LogicalNotExpression(SyntaxNode expression);
 
        /// <summary>
        /// Creates an expression that denotes a conditional evaluation operation.
        /// </summary>
        public abstract SyntaxNode ConditionalExpression(SyntaxNode condition, SyntaxNode whenTrue, SyntaxNode whenFalse);
 
        /// <summary>
        /// Creates an expression that denotes a conditional access operation. Use <see
        /// cref="MemberBindingExpression"/> and <see
        /// cref="ElementBindingExpression(IEnumerable{SyntaxNode})"/> to generate the <paramref
        /// name="whenNotNull"/> argument.
        /// </summary>
        public abstract SyntaxNode ConditionalAccessExpression(SyntaxNode expression, SyntaxNode whenNotNull);
 
        /// <summary>
        /// Creates an expression that denotes a member binding operation.
        /// </summary>
        public abstract SyntaxNode MemberBindingExpression(SyntaxNode name);
 
        /// <summary>
        /// Creates an expression that denotes an element binding operation.
        /// </summary>
        public abstract SyntaxNode ElementBindingExpression(IEnumerable<SyntaxNode> arguments);
 
        /// <summary>
        /// Creates an expression that denotes an element binding operation.
        /// </summary>
        public SyntaxNode ElementBindingExpression(params SyntaxNode[] arguments)
            => ElementBindingExpression((IEnumerable<SyntaxNode>)arguments);
 
        /// <summary>
        /// Creates an expression that denotes a coalesce operation. 
        /// </summary>
        public abstract SyntaxNode CoalesceExpression(SyntaxNode left, SyntaxNode right);
 
        /// <summary>
        /// Creates a member access expression.
        /// </summary>
        public virtual SyntaxNode MemberAccessExpression(SyntaxNode? expression, SyntaxNode memberName)
        {
            return MemberAccessExpressionWorker(expression, memberName)
                .WithAdditionalAnnotations(Simplifier.Annotation);
        }
 
        internal abstract SyntaxNode MemberAccessExpressionWorker(SyntaxNode? expression, SyntaxNode memberName);
 
        internal SyntaxNode RefExpression(SyntaxNode expression)
            => SyntaxGeneratorInternal.RefExpression(expression);
 
        /// <summary>
        /// Creates a member access expression.
        /// </summary>
        public SyntaxNode MemberAccessExpression(SyntaxNode? expression, string memberName)
            => MemberAccessExpression(expression, IdentifierName(memberName));
 
        /// <summary>
        /// Creates an array creation expression for a single dimensional array of specified size.
        /// </summary>
        public abstract SyntaxNode ArrayCreationExpression(SyntaxNode elementType, SyntaxNode size);
 
        /// <summary>
        /// Creates an array creation expression for a single dimensional array with specified initial element values.
        /// </summary>
        public abstract SyntaxNode ArrayCreationExpression(SyntaxNode elementType, IEnumerable<SyntaxNode> elements);
 
        /// <summary>
        /// Creates an object creation expression.
        /// </summary>
        public abstract SyntaxNode ObjectCreationExpression(SyntaxNode namedType, IEnumerable<SyntaxNode> arguments);
 
        internal abstract SyntaxNode ObjectCreationExpression(
            SyntaxNode namedType, SyntaxToken openParen, SeparatedSyntaxList<SyntaxNode> arguments, SyntaxToken closeParen);
 
        /// <summary>
        /// Creates an object creation expression.
        /// </summary>
        public SyntaxNode ObjectCreationExpression(ITypeSymbol type, IEnumerable<SyntaxNode> arguments)
            => ObjectCreationExpression(TypeExpression(type), arguments);
 
        /// <summary>
        /// Creates an object creation expression.
        /// </summary>
        public SyntaxNode ObjectCreationExpression(SyntaxNode type, params SyntaxNode[] arguments)
            => ObjectCreationExpression(type, (IEnumerable<SyntaxNode>)arguments);
 
        /// <summary>
        /// Creates an object creation expression.
        /// </summary>
        public SyntaxNode ObjectCreationExpression(ITypeSymbol type, params SyntaxNode[] arguments)
            => ObjectCreationExpression(type, (IEnumerable<SyntaxNode>)arguments);
 
        /// <summary>
        /// Creates a invocation expression.
        /// </summary>
        public abstract SyntaxNode InvocationExpression(SyntaxNode expression, IEnumerable<SyntaxNode> arguments);
 
        /// <summary>
        /// Creates a invocation expression
        /// </summary>
        public SyntaxNode InvocationExpression(SyntaxNode expression, params SyntaxNode[] arguments)
            => InvocationExpression(expression, (IEnumerable<SyntaxNode>)arguments);
 
        /// <summary>
        /// Creates a node that is an argument to an invocation.
        /// </summary>
        public abstract SyntaxNode Argument(string? name, RefKind refKind, SyntaxNode expression);
 
        /// <summary>
        /// Creates a node that is an argument to an invocation.
        /// </summary>
        public SyntaxNode Argument(RefKind refKind, SyntaxNode expression)
            => Argument(name: null, refKind, expression);
 
        /// <summary>
        /// Creates a node that is an argument to an invocation.
        /// </summary>
        public SyntaxNode Argument(SyntaxNode expression)
            => Argument(name: null, RefKind.None, expression);
 
        /// <summary>
        /// Creates an expression that access an element of an array or indexer.
        /// </summary>
        public abstract SyntaxNode ElementAccessExpression(SyntaxNode expression, IEnumerable<SyntaxNode> arguments);
 
        /// <summary>
        /// Creates an expression that access an element of an array or indexer.
        /// </summary>
        public SyntaxNode ElementAccessExpression(SyntaxNode expression, params SyntaxNode[] arguments)
            => ElementAccessExpression(expression, (IEnumerable<SyntaxNode>)arguments);
 
        /// <summary>
        /// Creates an expression that evaluates to the type at runtime.
        /// </summary>
        public abstract SyntaxNode TypeOfExpression(SyntaxNode type);
 
        /// <summary>
        /// Creates an expression that denotes an is-type-check operation.
        /// </summary>
        public abstract SyntaxNode IsTypeExpression(SyntaxNode expression, SyntaxNode type);
 
        /// <summary>
        /// Creates an expression that denotes an is-type-check operation.
        /// </summary>
        public SyntaxNode IsTypeExpression(SyntaxNode expression, ITypeSymbol type)
            => IsTypeExpression(expression, TypeExpression(type));
 
        /// <summary>
        /// Creates an expression that denotes an try-cast operation.
        /// </summary>
        public abstract SyntaxNode TryCastExpression(SyntaxNode expression, SyntaxNode type);
 
        /// <summary>
        /// Creates an expression that denotes an try-cast operation.
        /// </summary>
        public SyntaxNode TryCastExpression(SyntaxNode expression, ITypeSymbol type)
            => TryCastExpression(expression, TypeExpression(type));
 
        /// <summary>
        /// Creates an expression that denotes a type cast operation.
        /// </summary>
        public abstract SyntaxNode CastExpression(SyntaxNode type, SyntaxNode expression);
 
        /// <summary>
        /// Creates an expression that denotes a type cast operation.
        /// </summary>
        public SyntaxNode CastExpression(ITypeSymbol type, SyntaxNode expression)
            => CastExpression(TypeExpression(type), expression);
 
        /// <summary>
        /// Creates an expression that denotes a type conversion operation.
        /// </summary>
        public abstract SyntaxNode ConvertExpression(SyntaxNode type, SyntaxNode expression);
 
        /// <summary>
        /// Creates an expression that denotes a type conversion operation.
        /// </summary>
        public SyntaxNode ConvertExpression(ITypeSymbol type, SyntaxNode expression)
            => ConvertExpression(TypeExpression(type), expression);
 
        /// <summary>
        /// Creates an expression that declares a value returning lambda expression.
        /// </summary>
        public abstract SyntaxNode ValueReturningLambdaExpression(IEnumerable<SyntaxNode>? lambdaParameters, SyntaxNode expression);
 
        /// <summary>
        /// Creates an expression that declares a void returning lambda expression
        /// </summary>
        public abstract SyntaxNode VoidReturningLambdaExpression(IEnumerable<SyntaxNode>? lambdaParameters, SyntaxNode expression);
 
        /// <summary>
        /// Creates an expression that declares a value returning lambda expression.
        /// </summary>
        public abstract SyntaxNode ValueReturningLambdaExpression(IEnumerable<SyntaxNode>? lambdaParameters, IEnumerable<SyntaxNode> statements);
 
        /// <summary>
        /// Creates an expression that declares a void returning lambda expression.
        /// </summary>
        public abstract SyntaxNode VoidReturningLambdaExpression(IEnumerable<SyntaxNode>? lambdaParameters, IEnumerable<SyntaxNode> statements);
 
        /// <summary>
        /// Creates an expression that declares a single parameter value returning lambda expression.
        /// </summary>
        public SyntaxNode ValueReturningLambdaExpression(string parameterName, SyntaxNode expression)
            => ValueReturningLambdaExpression(new[] { LambdaParameter(parameterName) }, expression);
 
        /// <summary>
        /// Creates an expression that declares a single parameter void returning lambda expression.
        /// </summary>
        public SyntaxNode VoidReturningLambdaExpression(string parameterName, SyntaxNode expression)
            => VoidReturningLambdaExpression(new[] { LambdaParameter(parameterName) }, expression);
 
        /// <summary>
        /// Creates an expression that declares a single parameter value returning lambda expression.
        /// </summary>
        public SyntaxNode ValueReturningLambdaExpression(string parameterName, IEnumerable<SyntaxNode> statements)
            => ValueReturningLambdaExpression(new[] { LambdaParameter(parameterName) }, statements);
 
        /// <summary>
        /// Creates an expression that declares a single parameter void returning lambda expression.
        /// </summary>
        public SyntaxNode VoidReturningLambdaExpression(string parameterName, IEnumerable<SyntaxNode> statements)
            => VoidReturningLambdaExpression(new[] { LambdaParameter(parameterName) }, statements);
 
        /// <summary>
        /// Creates an expression that declares a zero parameter value returning lambda expression.
        /// </summary>
        public SyntaxNode ValueReturningLambdaExpression(SyntaxNode expression)
            => ValueReturningLambdaExpression((IEnumerable<SyntaxNode>?)null, expression);
 
        /// <summary>
        /// Creates an expression that declares a zero parameter void returning lambda expression.
        /// </summary>
        public SyntaxNode VoidReturningLambdaExpression(SyntaxNode expression)
            => VoidReturningLambdaExpression((IEnumerable<SyntaxNode>?)null, expression);
 
        /// <summary>
        /// Creates an expression that declares a zero parameter value returning lambda expression.
        /// </summary>
        public SyntaxNode ValueReturningLambdaExpression(IEnumerable<SyntaxNode> statements)
            => ValueReturningLambdaExpression((IEnumerable<SyntaxNode>?)null, statements);
 
        /// <summary>
        /// Creates an expression that declares a zero parameter void returning lambda expression.
        /// </summary>
        public SyntaxNode VoidReturningLambdaExpression(IEnumerable<SyntaxNode> statements)
            => VoidReturningLambdaExpression((IEnumerable<SyntaxNode>?)null, statements);
 
        /// <summary>
        /// Creates a lambda parameter.
        /// </summary>
        public abstract SyntaxNode LambdaParameter(string identifier, SyntaxNode? type = null);
 
        /// <summary>
        /// Creates a lambda parameter.
        /// </summary>
        public SyntaxNode LambdaParameter(string identifier, ITypeSymbol type)
            => LambdaParameter(identifier, TypeExpression(type));
 
        /// <summary>
        /// Creates an await expression.
        /// </summary>
        public abstract SyntaxNode AwaitExpression(SyntaxNode expression);
 
        /// <summary>
        /// Wraps with parens.
        /// </summary>
        internal SyntaxNode AddParentheses(SyntaxNode expression, bool includeElasticTrivia = true, bool addSimplifierAnnotation = true)
            => SyntaxGeneratorInternal.AddParentheses(expression, includeElasticTrivia, addSimplifierAnnotation);
 
        /// <summary>
        /// Creates an nameof expression.
        /// </summary>
        public abstract SyntaxNode NameOfExpression(SyntaxNode expression);
 
        /// <summary>
        /// Creates an tuple expression.
        /// </summary>
        public abstract SyntaxNode TupleExpression(IEnumerable<SyntaxNode> arguments);
 
        /// <summary>
        /// Parses an expression from string
        /// </summary>
        internal abstract SyntaxNode ParseExpression(string stringToParse);
 
        internal abstract SyntaxTrivia Trivia(SyntaxNode node);
 
        internal abstract SyntaxNode DocumentationCommentTrivia(IEnumerable<SyntaxNode> nodes, SyntaxTriviaList trailingTrivia, string endOfLineString);
 
        internal abstract SyntaxNode? DocumentationCommentTriviaWithUpdatedContent(SyntaxTrivia trivia, IEnumerable<SyntaxNode> content);
 
        #endregion
    }
}