|
// 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
}
|