File: src\Workspaces\SharedUtilitiesAndExtensions\Compiler\Core\Services\SyntaxFacts\ISyntaxFacts.cs
Web Access
Project: src\src\CodeStyle\Core\Analyzers\Microsoft.CodeAnalysis.CodeStyle.csproj (Microsoft.CodeAnalysis.CodeStyle)
// 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.Diagnostics.CodeAnalysis;
using System.Threading;
using Microsoft.CodeAnalysis.Text;
 
namespace Microsoft.CodeAnalysis.LanguageService;
 
/// <summary>
/// Contains helpers to allow features and other algorithms to run over C# and Visual Basic code in a uniform fashion.
/// It should be thought of a generalized way to apply type-pattern-matching and syntax-deconstruction in a uniform
/// fashion over the languages. Helpers in this type should only be one of the following forms:
/// <list type="bullet">
/// <item>
/// 'IsXXX' where 'XXX' exactly matches one of the same named syntax (node, token, trivia, list, etc.) constructs that 
/// both C# and VB have. For example 'IsSimpleName' to correspond to C# and VB's SimpleNameSyntax node.  These 'checking' 
/// methods should never fail.  For non leaf node types this should be implemented as a typecheck ('is' in C#, 'typeof ... is'
/// in VB).  For leaf nodes, this should be implemented by deffering to <see cref="ISyntaxKinds"/> to check against the 
/// raw kind of the node.
/// </item>
/// <item>
/// 'GetPartsOfXXX(SyntaxNode node, out SyntaxNode/SyntaxToken part1, ...)' where 'XXX' one of the same named Syntax constructs
/// that both C# and VB have, and where the returned parts correspond to the members those nodes have in common across the 
/// languages.  For example 'GetPartsOfQualifiedName(SyntaxNode node, out SyntaxNode left, out SyntaxToken dotToken, out SyntaxNode right)'
/// VB.  These functions should throw if passed a node that the corresponding 'IsXXX' did not return <see langword="true"/> for.
/// For nodes that only have a single child, 'GetPartsOfXXX' is not not needed and can be replaced with the easier to use
/// 'GetXXXOfYYY' to get that single child.
/// </item>
/// <item>
/// 'GetXxxOfYYY' where 'XXX' matches the name of a property on a 'YYY' syntax construct that both C# and VB have.  For
/// example 'GetExpressionOfMemberAccessExpression' corresponding to MemberAccessExpressionsyntax.Expression in both C# and
/// VB.  These functions should throw if passed a node that the corresponding 'IsYYY' did not return <see langword="true"/> for.
/// For nodes that only have a single child, these functions can stay here.  For nodes with multiple children, these should migrate
/// to <see cref="ISyntaxFactsExtensions"/> and be built off of 'GetPartsOfXXX'.
/// </item>
/// <item>
/// Absolutely trivial questions that relate to syntax and can be asked sensibly of each language.  For example,
/// if certain constructs (like 'patterns') are supported in that language or not.
/// </item>
/// </list>
///
/// <para>Importantly, avoid:</para>
///
/// <list type="bullet">
/// <item>
/// Functions that attempt to blur the lines between similar constructs in the same language.  For example, a QualifiedName
/// is not the same as a MemberAccessExpression (despite A.B being representable as either depending on context). 
/// Features that need to handle both should make it clear that they are doing so, showing that they're doing the right
/// thing for the contexts each can arise in (for the above example in 'type' vs 'expression' contexts).
/// </item>
/// <item>
/// Functions which are effectively specific to a single feature are are just trying to find a place to place complex
/// feature logic in a place such that it can run over VB or C#.  For example, a function to determine if a position
/// is on the 'header' of a node.  a 'header' is a not a well defined syntax concept that can be trivially asked of
/// nodes in either language.  It is an excapsulation of a feature (or set of features) level idea that should be in
/// its own dedicated service.
/// </item>
/// <item>
/// Functions that mutate or update syntax constructs for example 'WithXXX'.  These should be on SyntaxGenerator or
/// some other feature specific service.
/// </item>
/// <item>
/// Functions that a single item when one language may allow for multiple.  For example 'GetIdentifierOfVariableDeclarator'.
/// In VB a VariableDeclarator can itself have several names, so calling code must be written to check for that and handle
/// it apropriately.  Functions like this make it seem like that doesn't need to be considered, easily allowing for bugs
/// to creep in.
/// </item>
/// <item>
/// Abbreviating or otherwise changing the names that C# and VB share here.  For example use 'ObjectCreationExpression'
/// not 'ObjectCreation'.  This prevents accidental duplication and keeps consistency with all members.
/// </item>
/// </list>
/// </summary>
/// <remarks>
/// Many helpers in this type currently violate the above 'dos' and 'do nots'.  They should be removed and either 
/// inlined directly into the feature that needs if (if only a single feature), or moved into a dedicated service
/// for that purpose if needed by multiple features.
/// </remarks>
internal interface ISyntaxFacts
{
    bool IsCaseSensitive { get; }
    StringComparer StringComparer { get; }
 
    SyntaxTrivia ElasticMarker { get; }
    SyntaxTrivia ElasticCarriageReturnLineFeed { get; }
 
    ISyntaxKinds SyntaxKinds { get; }
 
    bool SupportsIndexingInitializer(ParseOptions options);
    bool SupportsLocalFunctionDeclaration(ParseOptions options);
    bool SupportsNotPattern(ParseOptions options);
    bool SupportsRecord(ParseOptions options);
    bool SupportsRecordStruct(ParseOptions options);
    bool SupportsThrowExpression(ParseOptions options);
    bool SupportsTargetTypedConditionalExpression(ParseOptions options);
    bool SupportsIsNotTypeExpression(ParseOptions options);
    bool SupportsConstantInterpolatedStrings(ParseOptions options);
    bool SupportsTupleDeconstruction(ParseOptions options);
    bool SupportsCollectionExpressionNaturalType(ParseOptions options);
 
    SyntaxToken ParseToken(string text);
    SyntaxTriviaList ParseLeadingTrivia(string text);
    string EscapeIdentifier(string identifier);
    bool IsVerbatimIdentifier(SyntaxToken token);
    bool IsOperator(SyntaxToken token);
    bool IsPredefinedOperator(SyntaxToken token);
    bool IsPredefinedOperator(SyntaxToken token, PredefinedOperator op);
 
    bool IsPredefinedType(SyntaxToken token);
    bool IsPredefinedType(SyntaxToken token, PredefinedType type);
 
    bool IsPredefinedType([NotNullWhen(true)] SyntaxNode? node);
    bool IsPredefinedType([NotNullWhen(true)] SyntaxNode? node, PredefinedType type);
 
    /// <summary>
    /// Returns 'true' if this a 'reserved' keyword for the language.  A 'reserved' keyword is a
    /// identifier that is always treated as being a special keyword, regardless of where it is
    /// found in the token stream.  Examples of this are tokens like <see langword="class"/> and
    /// <see langword="Class"/> in C# and VB respectively.
    ///
    /// Importantly, this does *not* include contextual keywords.  If contextual keywords are
    /// important for your scenario, use <see cref="IsContextualKeyword"/> or <see
    /// cref="ISyntaxFactsExtensions.IsReservedOrContextualKeyword"/>.  Also, consider using
    /// <see cref="ISyntaxFactsExtensions.IsWord"/> if all you need is the ability to know
    /// if this is effectively any identifier in the language, regardless of whether the language
    /// is treating it as a keyword or not.
    /// </summary>
    bool IsReservedKeyword(SyntaxToken token);
 
    /// <summary>
    /// Returns <see langword="true"/> if this a 'contextual' keyword for the language.  A
    /// 'contextual' keyword is a identifier that is only treated as being a special keyword in
    /// certain *syntactic* contexts.  Examples of this is 'yield' in C#.  This is only a
    /// keyword if used as 'yield return' or 'yield break'.  Importantly, identifiers like <see
    /// langword="var"/>, <see langword="dynamic"/> and <see langword="nameof"/> are *not*
    /// 'contextual' keywords.  This is because they are not treated as keywords depending on
    /// the syntactic context around them.  Instead, the language always treats them identifiers
    /// that have special *semantic* meaning if they end up not binding to an existing symbol.
    ///
    /// Importantly, if <paramref name="token"/> is not in the syntactic construct where the
    /// language thinks an identifier should be contextually treated as a keyword, then this
    /// will return <see langword="false"/>.
    ///
    /// Or, in other words, the parser must be able to identify these cases in order to be a
    /// contextual keyword.  If identification happens afterwards, it's not contextual.
    /// </summary>
    bool IsContextualKeyword(SyntaxToken token);
 
    /// <summary>
    /// The set of identifiers that have special meaning directly after the `#` token in a
    /// preprocessor directive.  For example `if` or `pragma`.
    /// </summary>
    bool IsPreprocessorKeyword(SyntaxToken token);
    bool IsPreProcessorDirectiveContext(SyntaxTree syntaxTree, int position, CancellationToken cancellationToken);
 
    bool IsLiteral(SyntaxToken token);
    bool IsStringLiteralOrInterpolatedStringLiteral(SyntaxToken token);
 
    bool IsNumericLiteral(SyntaxToken token);
    bool IsVerbatimStringLiteral(SyntaxToken token);
 
    bool IsUsingOrExternOrImport([NotNullWhen(true)] SyntaxNode? node);
    bool IsGlobalAssemblyAttribute([NotNullWhen(true)] SyntaxNode? node);
    bool IsGlobalModuleAttribute([NotNullWhen(true)] SyntaxNode? node);
    bool IsDeclaration([NotNullWhen(true)] SyntaxNode? node);
    bool IsTypeDeclaration(SyntaxNode node);
 
    bool IsUsingAliasDirective([NotNullWhen(true)] SyntaxNode? node);
 
    bool IsRegularComment(SyntaxTrivia trivia);
    bool IsDocumentationComment(SyntaxTrivia trivia);
    bool IsElastic(SyntaxTrivia trivia);
    bool IsPragmaDirective(SyntaxTrivia trivia, out bool isDisable, out bool isActive, out SeparatedSyntaxList<SyntaxNode> errorCodes);
 
    bool IsPreprocessorDirective(SyntaxTrivia trivia);
 
    bool IsDocumentationComment(SyntaxNode node);
 
    string GetText(int kind);
    bool IsEntirelyWithinStringOrCharOrNumericLiteral([NotNullWhen(true)] SyntaxTree? syntaxTree, int position, CancellationToken cancellationToken);
 
    bool TryGetPredefinedType(SyntaxToken token, out PredefinedType type);
    bool TryGetPredefinedOperator(SyntaxToken token, out PredefinedOperator op);
    bool TryGetExternalSourceInfo([NotNullWhen(true)] SyntaxNode? directive, out ExternalSourceInfo info);
 
    bool IsDeclarationExpression([NotNullWhen(true)] SyntaxNode? node);
 
    bool IsConversionExpression([NotNullWhen(true)] SyntaxNode? node);
    bool IsCastExpression([NotNullWhen(true)] SyntaxNode? node);
 
    bool IsExpressionOfForeach([NotNullWhen(true)] SyntaxNode? node);
    SyntaxNode GetExpressionOfForeachStatement(SyntaxNode statement);
 
    void GetPartsOfTupleExpression<TArgumentSyntax>(SyntaxNode node,
        out SyntaxToken openParen, out SeparatedSyntaxList<TArgumentSyntax> arguments, out SyntaxToken closeParen) where TArgumentSyntax : SyntaxNode;
 
    bool IsVerbatimInterpolatedStringExpression([NotNullWhen(true)] SyntaxNode? node);
 
    // Left side of = assignment.
    bool IsLeftSideOfAssignment([NotNullWhen(true)] SyntaxNode? node);
 
    bool IsAnyAssignmentStatement([NotNullWhen(true)] SyntaxNode? statement);
    bool IsSimpleAssignmentStatement([NotNullWhen(true)] SyntaxNode? statement);
    void GetPartsOfAssignmentStatement(SyntaxNode statement, out SyntaxNode left, out SyntaxToken operatorToken, out SyntaxNode right);
    void GetPartsOfAssignmentExpressionOrStatement(SyntaxNode statement, out SyntaxNode left, out SyntaxToken operatorToken, out SyntaxNode right);
 
    // Left side of any assignment (for example = or ??= or *=  or += )
    bool IsLeftSideOfAnyAssignment([NotNullWhen(true)] SyntaxNode? node);
    // Left side of compound assignment (for example ??= or *=  or += )
    bool IsLeftSideOfCompoundAssignment([NotNullWhen(true)] SyntaxNode? node);
    SyntaxNode GetRightHandSideOfAssignment(SyntaxNode node);
 
    bool IsInferredAnonymousObjectMemberDeclarator([NotNullWhen(true)] SyntaxNode? node);
    bool IsOperandOfIncrementExpression([NotNullWhen(true)] SyntaxNode? node);
    bool IsOperandOfIncrementOrDecrementExpression([NotNullWhen(true)] SyntaxNode? node);
 
    bool IsLeftSideOfDot([NotNullWhen(true)] SyntaxNode? node);
    SyntaxNode? GetRightSideOfDot(SyntaxNode? node);
 
    /// <summary>
    /// Get the node on the left side of the dot if given a dotted expression.
    /// </summary>
    /// <param name="allowImplicitTarget">
    /// In VB, we have a member access expression with a null expression, this may be one of the
    /// following forms:
    ///     1) new With { .a = 1, .b = .a      .a refers to the anonymous type
    ///     2) With obj : .m                   .m refers to the obj type
    ///     3) new T() With { .a = 1, .b = .a  'a refers to the T type
    /// If `allowImplicitTarget` is set to true, the returned node will be set to approperiate node, otherwise, it will return null.
    /// This parameter has no affect on C# node.
    /// </param>
    SyntaxNode? GetLeftSideOfDot(SyntaxNode? node, bool allowImplicitTarget = false);
 
    bool IsLeftSideOfExplicitInterfaceSpecifier([NotNullWhen(true)] SyntaxNode? node);
 
    bool IsNameOfSimpleMemberAccessExpression([NotNullWhen(true)] SyntaxNode? node);
    bool IsNameOfAnyMemberAccessExpression([NotNullWhen(true)] SyntaxNode? node);
    bool IsNameOfMemberBindingExpression([NotNullWhen(true)] SyntaxNode? node);
 
    /// <summary>
    /// Gets the containing expression that is actually a language expression and not just typed
    /// as an ExpressionSyntax for convenience. For example, NameSyntax nodes on the right side
    /// of qualified names and member access expressions are not language expressions, yet the
    /// containing qualified names or member access expressions are indeed expressions.
    /// </summary>
    [return: NotNullIfNotNull(nameof(node))]
    SyntaxNode? GetStandaloneExpression(SyntaxNode? node);
 
    /// <summary>
    /// Call on the `.y` part of a `x?.y` to get the entire `x?.y` conditional access expression.  This also works
    /// when there are multiple chained conditional accesses.  For example, calling this on '.y' or '.z' in
    /// `x?.y?.z` will both return the full `x?.y?.z` node.  This can be used to effectively get 'out' of the RHS of
    /// a conditional access, and commonly represents the full standalone expression that can be operated on
    /// atomically.
    /// </summary>
    SyntaxNode? GetRootConditionalAccessExpression(SyntaxNode? node);
 
    /// <summary>
    /// Returns the expression node the member is being accessed off of.  If <paramref name="allowImplicitTarget"/>
    /// is <see langword="false"/>, this will be the node directly to the left of the dot-token.  If <paramref name="allowImplicitTarget"/>
    /// is <see langword="true"/>, then this can return another node in the tree that the member will be accessed
    /// off of.  For example, in VB, if you have a member-access-expression of the form ".Length" then this
    /// may return the expression in the surrounding With-statement.
    /// </summary>
    SyntaxNode? GetExpressionOfMemberAccessExpression(SyntaxNode node, bool allowImplicitTarget = false);
 
    SyntaxNode? GetTargetOfMemberBinding(SyntaxNode? node);
 
    SyntaxNode GetNameOfMemberBindingExpression(SyntaxNode node);
 
    bool IsPointerMemberAccessExpression([NotNullWhen(true)] SyntaxNode? node);
 
    bool IsNamedArgument([NotNullWhen(true)] SyntaxNode? node);
    bool IsNameOfNamedArgument([NotNullWhen(true)] SyntaxNode? node);
    SyntaxNode? GetParameterList(SyntaxNode node);
    bool IsParameterList([NotNullWhen(true)] SyntaxNode? node);
 
    bool IsDocumentationCommentExteriorTrivia(SyntaxTrivia trivia);
 
    void GetPartsOfElementAccessExpression(SyntaxNode node, out SyntaxNode expression, out SyntaxNode argumentList);
 
    SyntaxNode GetExpressionOfArgument(SyntaxNode node);
    SyntaxNode GetExpressionOfAttributeArgument(SyntaxNode node);
    SyntaxNode GetExpressionOfInterpolation(SyntaxNode node);
 
    bool IsElementBindingExpression([NotNullWhen(true)] SyntaxNode? node);
    bool IsMemberBindingExpression([NotNullWhen(true)] SyntaxNode? node);
    bool IsPostfixUnaryExpression([NotNullWhen(true)] SyntaxNode? node);
 
    SyntaxToken GetIdentifierOfSimpleName(SyntaxNode node);
    SyntaxToken GetIdentifierOfTypeDeclaration(SyntaxNode node);
    SyntaxToken GetIdentifierOfVariableDeclarator(SyntaxNode node);
    SyntaxNode GetTypeOfVariableDeclarator(SyntaxNode node);
 
    /// <summary>
    /// True if this is an argument with just an expression and nothing else (i.e. no ref/out,
    /// no named params, no omitted args).
    /// </summary>
    bool IsSimpleArgument([NotNullWhen(true)] SyntaxNode? node);
    bool IsArgument([NotNullWhen(true)] SyntaxNode? node);
    bool IsAttributeArgument([NotNullWhen(true)] SyntaxNode? node);
    RefKind GetRefKindOfArgument(SyntaxNode node);
 
    void GetNameAndArityOfSimpleName(SyntaxNode node, out string name, out int arity);
    bool LooksGeneric(SyntaxNode simpleName);
 
    SeparatedSyntaxList<SyntaxNode> GetTypeArgumentsOfGenericName(SyntaxNode? genericName);
 
    SyntaxList<SyntaxNode> GetContentsOfInterpolatedString(SyntaxNode interpolatedString);
 
    SeparatedSyntaxList<SyntaxNode> GetArgumentsOfObjectCreationExpression(SyntaxNode node);
    SeparatedSyntaxList<SyntaxNode> GetArgumentsOfArgumentList(SyntaxNode node);
    SeparatedSyntaxList<SyntaxNode> GetArgumentsOfAttributeArgumentList(SyntaxNode node);
 
    bool IsUsingDirectiveName([NotNullWhen(true)] SyntaxNode? node);
 
    // Violation.  Doesn't correspond to any shared structure for vb/c#
    SyntaxList<SyntaxNode> GetAttributeLists(SyntaxNode? node);
    SeparatedSyntaxList<SyntaxNode> GetAttributesOfAttributeList(SyntaxNode node);
 
    bool IsAttributeNamedArgumentIdentifier([NotNullWhen(true)] SyntaxNode? node);
    bool IsMemberInitializerNamedAssignmentIdentifier([NotNullWhen(true)] SyntaxNode? node, [NotNullWhen(true)] out SyntaxNode? initializedInstance);
    bool IsAnyInitializerExpression([NotNullWhen(true)] SyntaxNode? node, [NotNullWhen(true)] out SyntaxNode? creationExpression);
 
    bool IsDirective([NotNullWhen(true)] SyntaxNode? node);
    bool IsStatement([NotNullWhen(true)] SyntaxNode? node);
    bool IsExecutableStatement([NotNullWhen(true)] SyntaxNode? node);
    bool IsGlobalStatement([NotNullWhen(true)] SyntaxNode? node);
    SyntaxNode GetStatementOfGlobalStatement(SyntaxNode node);
    bool AreStatementsInSameContainer(SyntaxNode firstStatement, SyntaxNode secondStatement);
 
    bool IsDeconstructionAssignment([NotNullWhen(true)] SyntaxNode? node);
    bool IsDeconstructionForEachStatement([NotNullWhen(true)] SyntaxNode? node);
 
    /// <summary>
    /// Returns true for nodes that represent the body of a method.
    ///
    /// For VB this will be
    /// MethodBlockBaseSyntax.  This will be true for things like constructor, method, operator
    /// bodies as well as accessor bodies.  It will not be true for things like sub() function()
    /// lambdas.
    ///
    /// For C# this will be the BlockSyntax or ArrowExpressionSyntax for a
    /// method/constructor/deconstructor/operator/accessor.  It will not be included for local
    /// functions.
    /// </summary>
    bool IsMethodBody([NotNullWhen(true)] SyntaxNode? node);
 
    bool IsDeclaratorOfLocalDeclarationStatement(SyntaxNode declarator, SyntaxNode localDeclarationStatement);
    SeparatedSyntaxList<SyntaxNode> GetVariablesOfLocalDeclarationStatement(SyntaxNode node);
    SyntaxNode? GetInitializerOfVariableDeclarator(SyntaxNode node);
    SyntaxNode? GetInitializerOfPropertyDeclaration(SyntaxNode node);
 
    bool IsThisConstructorInitializer(SyntaxToken token);
    bool IsBaseConstructorInitializer(SyntaxToken token);
    bool IsQueryKeyword(SyntaxToken token);
    bool IsElementAccessExpression([NotNullWhen(true)] SyntaxNode? node);
    bool IsIdentifierStartCharacter(char c);
    bool IsIdentifierPartCharacter(char c);
    bool IsIdentifierEscapeCharacter(char c);
    bool IsStartOfUnicodeEscapeSequence(char c);
 
    bool IsValidIdentifier(string identifier);
    bool IsVerbatimIdentifier(string identifier);
 
    /// <summary>
    /// Returns true if the given character is a character which may be included in an
    /// identifier to specify the type of a variable.
    /// </summary>
    bool IsTypeCharacter(char c);
 
    // Violation.  This is a feature level API for QuickInfo.
    bool IsBindableToken(SyntaxToken token);
 
    bool IsInStaticContext(SyntaxNode node);
    bool IsUnsafeContext(SyntaxNode node);
 
    bool IsInNamespaceOrTypeContext([NotNullWhen(true)] SyntaxNode? node);
 
    bool IsBaseTypeList([NotNullWhen(true)] SyntaxNode? node);
 
    bool IsInConstantContext([NotNullWhen(true)] SyntaxNode? node);
    bool IsInConstructor(SyntaxNode node);
    bool IsMethodLevelMember([NotNullWhen(true)] SyntaxNode? node);
    bool IsTopLevelNodeWithMembers([NotNullWhen(true)] SyntaxNode? node);
 
    bool AreEquivalent(SyntaxToken token1, SyntaxToken token2);
    bool AreEquivalent(SyntaxNode? node1, SyntaxNode? node2);
 
    string GetDisplayName(SyntaxNode? node, DisplayNameOptions options, string? rootNamespace = null);
 
    // Violation.  This is a feature level API.  How 'position' relates to 'containment' is not defined.
    SyntaxNode? GetContainingTypeDeclaration(SyntaxNode root, int position);
    SyntaxNode? GetContainingMemberDeclaration(SyntaxNode root, int position, bool useFullSpan = true);
    SyntaxNode? GetContainingMethodDeclaration(SyntaxNode root, int position, bool useFullSpan = true);
    SyntaxNode? GetContainingVariableDeclaratorOfFieldDeclaration(SyntaxNode? node);
 
    // Violation.  This is a feature level API.
    [return: NotNullIfNotNull(nameof(node))]
    SyntaxNode? ConvertToSingleLine(SyntaxNode? node, bool useElasticTrivia = false);
 
    // Violation.  This is a feature level API.
    PooledObject<List<SyntaxNode>> GetTopLevelAndMethodLevelMembers(SyntaxNode? root);
    // Violation.  This is a feature level API.
    PooledObject<List<SyntaxNode>> GetMethodLevelMembers(SyntaxNode? root);
    SyntaxList<SyntaxNode> GetMembersOfTypeDeclaration(SyntaxNode typeDeclaration);
 
    // Violation.  This is a feature level API.
    bool ContainsInMemberBody([NotNullWhen(true)] SyntaxNode? node, TextSpan span);
    // Violation.  This is a feature level API.
    TextSpan GetInactiveRegionSpanAroundPosition(SyntaxTree tree, int position, CancellationToken cancellationToken);
 
    /// <summary>
    /// Given a <see cref="SyntaxNode"/>, return the <see cref="TextSpan"/> representing the span of the member body
    /// it is contained within. This <see cref="TextSpan"/> is used to determine whether speculative binding should be
    /// used in performance-critical typing scenarios. Note: if this method fails to find a relevant span, it returns
    /// an empty <see cref="TextSpan"/> at position 0.
    /// </summary>
    // Violation.  This is a feature level API.
    TextSpan GetMemberBodySpanForSpeculativeBinding(SyntaxNode node);
 
    /// <summary>
    /// Returns the parent node that binds to the symbols that the IDE prefers for features like Quick Info and Find
    /// All References. For example, if the token is part of the type of an object creation, the parenting object
    /// creation expression is returned so that binding will return constructor symbols.
    /// </summary>
    // Violation.  This is a feature level API.
    SyntaxNode? TryGetBindableParent(SyntaxToken token);
 
    // Violation.  This is a feature level API.
    IEnumerable<SyntaxNode> GetConstructors(SyntaxNode? root, CancellationToken cancellationToken);
 
    /// <summary>
    /// Given a <see cref="SyntaxNode"/>, that represents and argument return the string representation of
    /// that arguments name.
    /// </summary>
    // Violation.  This is a feature level API.
    string GetNameForArgument(SyntaxNode? argument);
 
    /// <summary>
    /// Given a <see cref="SyntaxNode"/>, that represents an attribute argument return the string representation of
    /// that arguments name.
    /// </summary>
    // Violation.  This is a feature level API.
    string GetNameForAttributeArgument(SyntaxNode? argument);
 
    bool IsNameOfSubpattern([NotNullWhen(true)] SyntaxNode? node);
    bool IsPropertyPatternClause(SyntaxNode node);
 
    bool IsAnyPattern([NotNullWhen(true)] SyntaxNode? node);
    bool IsBinaryPattern([NotNullWhen(true)] SyntaxNode? node);
    bool IsUnaryPattern([NotNullWhen(true)] SyntaxNode? node);
 
    SyntaxNode GetExpressionOfConstantPattern(SyntaxNode node);
    SyntaxNode GetTypeOfTypePattern(SyntaxNode node);
 
    void GetPartsOfParenthesizedPattern(SyntaxNode node, out SyntaxToken openParen, out SyntaxNode pattern, out SyntaxToken closeParen);
    void GetPartsOfBinaryPattern(SyntaxNode node, out SyntaxNode left, out SyntaxToken operatorToken, out SyntaxNode right);
    void GetPartsOfDeclarationPattern(SyntaxNode node, out SyntaxNode type, out SyntaxNode designation);
    void GetPartsOfRecursivePattern(SyntaxNode node, out SyntaxNode? type, out SyntaxNode? positionalPart, out SyntaxNode? propertyPart, out SyntaxNode? designation);
    void GetPartsOfRelationalPattern(SyntaxNode node, out SyntaxToken operatorToken, out SyntaxNode expression);
    void GetPartsOfUnaryPattern(SyntaxNode node, out SyntaxToken operatorToken, out SyntaxNode pattern);
 
    bool ContainsInterleavedDirective(TextSpan span, SyntaxToken token, CancellationToken cancellationToken);
 
    SyntaxTokenList GetModifiers(SyntaxNode? node);
 
    // Violation.  WithXXX methods should not be here, but should be in SyntaxGenerator.
    [return: NotNullIfNotNull(nameof(node))]
    SyntaxNode? WithModifiers(SyntaxNode? node, SyntaxTokenList modifiers);
 
    // Violation.  This is a feature level API.
    Location GetDeconstructionReferenceLocation(SyntaxNode node);
 
    // Violation.  This is a feature level API.
    SyntaxToken? GetDeclarationIdentifierIfOverride(SyntaxToken token);
 
    bool IsParameterNameXmlElementSyntax([NotNullWhen(true)] SyntaxNode? node);
 
    SyntaxList<SyntaxNode> GetContentFromDocumentationCommentTriviaSyntax(SyntaxTrivia trivia);
 
    bool IsInInactiveRegion(SyntaxTree syntaxTree, int position, CancellationToken cancellationToken);
 
    #region IsXXX members
 
    bool IsAnonymousFunctionExpression([NotNullWhen(true)] SyntaxNode? node);
    bool IsBaseNamespaceDeclaration([NotNullWhen(true)] SyntaxNode? node);
    bool IsBinaryExpression([NotNullWhen(true)] SyntaxNode? node);
    bool IsLiteralExpression([NotNullWhen(true)] SyntaxNode? node);
    bool IsMemberAccessExpression([NotNullWhen(true)] SyntaxNode? node);
    bool IsMethodDeclaration([NotNullWhen(true)] SyntaxNode? node);
    bool IsSimpleName([NotNullWhen(true)] SyntaxNode? node);
    bool IsAnyName([NotNullWhen(true)] SyntaxNode? node);
    bool IsAnyType([NotNullWhen(true)] SyntaxNode? node);
 
    bool IsNamedMemberInitializer([NotNullWhen(true)] SyntaxNode? node);
    bool IsElementAccessInitializer([NotNullWhen(true)] SyntaxNode? node);
 
    bool IsObjectMemberInitializer([NotNullWhen(true)] SyntaxNode? node);
    bool IsObjectCollectionInitializer([NotNullWhen(true)] SyntaxNode? node);
 
    #endregion
 
    #region GetPartsOfXXX members
 
    void GetPartsOfAnyIsTypeExpression(SyntaxNode node, out SyntaxNode expression, out SyntaxNode type);
    void GetPartsOfArgumentList(SyntaxNode node, out SyntaxToken openParenToken, out SeparatedSyntaxList<SyntaxNode> arguments, out SyntaxToken closeParenToken);
    void GetPartsOfAttribute(SyntaxNode node, out SyntaxNode name, out SyntaxNode? argumentList);
    void GetPartsOfBaseNamespaceDeclaration(SyntaxNode node, out SyntaxNode name, out SyntaxList<SyntaxNode> imports, out SyntaxList<SyntaxNode> members);
    void GetPartsOfBaseObjectCreationExpression(SyntaxNode node, out SyntaxNode? argumentList, out SyntaxNode? initializer);
    void GetPartsOfBinaryExpression(SyntaxNode node, out SyntaxNode left, out SyntaxToken operatorToken, out SyntaxNode right);
    void GetPartsOfCastExpression(SyntaxNode node, out SyntaxNode type, out SyntaxNode expression);
    void GetPartsOfCompilationUnit(SyntaxNode node, out SyntaxList<SyntaxNode> imports, out SyntaxList<SyntaxNode> attributeLists, out SyntaxList<SyntaxNode> members);
    void GetPartsOfConditionalAccessExpression(SyntaxNode node, out SyntaxNode expression, out SyntaxToken operatorToken, out SyntaxNode whenNotNull);
    void GetPartsOfConditionalExpression(SyntaxNode node, out SyntaxNode condition, out SyntaxNode whenTrue, out SyntaxNode whenFalse);
    void GetPartsOfGenericName(SyntaxNode node, out SyntaxToken identifier, out SeparatedSyntaxList<SyntaxNode> typeArguments);
    void GetPartsOfInterpolationExpression(SyntaxNode node, out SyntaxToken stringStartToken, out SyntaxList<SyntaxNode> contents, out SyntaxToken stringEndToken);
    void GetPartsOfInvocationExpression(SyntaxNode node, out SyntaxNode expression, out SyntaxNode? argumentList);
    void GetPartsOfIsPatternExpression(SyntaxNode node, out SyntaxNode left, out SyntaxToken isToken, out SyntaxNode right);
    void GetPartsOfMemberAccessExpression(SyntaxNode node, out SyntaxNode expression, out SyntaxToken operatorToken, out SyntaxNode name);
    void GetPartsOfNamedMemberInitializer(SyntaxNode node, out SyntaxNode name, out SyntaxNode expression);
    void GetPartsOfObjectCreationExpression(SyntaxNode node, out SyntaxToken keyword, out SyntaxNode type, out SyntaxNode? argumentList, out SyntaxNode? initializer);
    void GetPartsOfImplicitObjectCreationExpression(SyntaxNode node, out SyntaxToken keyword, out SyntaxNode argumentList, out SyntaxNode? initializer);
    void GetPartsOfParameter(SyntaxNode node, out SyntaxToken identifier, out SyntaxNode? @default);
    void GetPartsOfParenthesizedExpression(SyntaxNode node, out SyntaxToken openParen, out SyntaxNode expression, out SyntaxToken closeParen);
    void GetPartsOfPrefixUnaryExpression(SyntaxNode node, out SyntaxToken operatorToken, out SyntaxNode operand);
    void GetPartsOfQualifiedName(SyntaxNode node, out SyntaxNode left, out SyntaxToken dotToken, out SyntaxNode right);
    void GetPartsOfUsingAliasDirective(SyntaxNode node, out SyntaxToken globalKeyword, out SyntaxToken alias, out SyntaxNode name);
 
    #endregion
 
    #region GetXXXOfYYYMembers
 
    // note: this is only for nodes that have a single child nodes.  If a node has multiple child nodes, then
    // ISyntaxFacts should have a GetPartsOfXXX helper instead, and GetXXXOfYYY should be built off of that
    // inside ISyntaxFactsExtensions
 
    SyntaxNode GetArgumentListOfImplicitElementAccess(SyntaxNode node);
 
    SyntaxNode GetExpressionOfAwaitExpression(SyntaxNode node);
    SyntaxNode GetExpressionOfExpressionStatement(SyntaxNode node);
    SyntaxNode GetExpressionOfRefExpression(SyntaxNode node);
    SyntaxNode? GetExpressionOfReturnStatement(SyntaxNode node);
    SyntaxNode GetExpressionOfThrowExpression(SyntaxNode node);
    SyntaxNode? GetExpressionOfThrowStatement(SyntaxNode node);
 
    bool IsEqualsValueOfPropertyDeclaration([NotNullWhen(true)] SyntaxNode? node);
    SyntaxNode GetValueOfEqualsValueClause(SyntaxNode node);
 
    SeparatedSyntaxList<SyntaxNode> GetInitializersOfObjectMemberInitializer(SyntaxNode node);
    SeparatedSyntaxList<SyntaxNode> GetExpressionsOfObjectCollectionInitializer(SyntaxNode node);
 
    SyntaxToken GetTokenOfLiteralExpression(SyntaxNode node);
 
    #endregion
}
 
[Flags]
internal enum DisplayNameOptions
{
    None = 0,
    IncludeMemberKeyword = 1,
    IncludeNamespaces = 1 << 1,
    IncludeParameters = 1 << 2,
    IncludeType = 1 << 3,
    IncludeTypeParameters = 1 << 4
}