// 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.CodeAnalysis; using System.Threading; using Microsoft.CodeAnalysis.PooledObjects; 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 SupportsCollectionExpressionNaturalType(ParseOptions options); bool SupportsConstantInterpolatedStrings(ParseOptions options); bool SupportsFieldExpression(ParseOptions options); bool SupportsImplicitImplementationOfNonPublicInterfaceMembers(ParseOptions options); bool SupportsIndexingInitializer(ParseOptions options); bool SupportsIsNotTypeExpression(ParseOptions options); bool SupportsLocalFunctionDeclaration(ParseOptions options); bool SupportsNotPattern(ParseOptions options); bool SupportsNullConditionalAssignment(ParseOptions options); bool SupportsRecord(ParseOptions options); bool SupportsRecordStruct(ParseOptions options); bool SupportsTargetTypedConditionalExpression(ParseOptions options); bool SupportsThrowExpression(ParseOptions options); bool SupportsTupleDeconstruction(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 IsRawStringLiteral(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); SyntaxNode? GetMatchingDirective(SyntaxNode directive, CancellationToken cancellationToken); ImmutableArray<SyntaxNode> GetMatchingConditionalDirectives(SyntaxNode directive, CancellationToken cancellationToken); 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 IsDeconstructionAssignment([NotNullWhen(true)] SyntaxNode? node); bool IsDeconstructionForEachStatement([NotNullWhen(true)] SyntaxNode? node); bool IsUsingLocalDeclarationStatement(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(SemanticModel? semanticModel, 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. void AddTopLevelAndMethodLevelMembers(SyntaxNode? root, ArrayBuilder<SyntaxNode> result); // Violation. This is a feature level API. void AddTopLevelMembers(SyntaxNode? root, ArrayBuilder<SyntaxNode> result); // Violation. This is a feature level API. void AddMethodLevelMembers(SyntaxNode? root, ArrayBuilder<SyntaxNode> result); SyntaxList<SyntaxNode> GetMembersOfTypeDeclaration(SyntaxNode typeDeclaration); // 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 GetPartsOfAliasQualifiedName(SyntaxNode node, out SyntaxNode alias, out SyntaxToken colonColonToken, out SyntaxNode name); 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 } |