// 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.Linq; using System.Threading; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.LanguageService; internal static class ISyntaxFactsExtensions { private static readonly ObjectPool<Stack<(SyntaxNodeOrToken nodeOrToken, bool leading, bool trailing)>> s_stackPool = SharedPools.Default<Stack<(SyntaxNodeOrToken nodeOrToken, bool leading, bool trailing)>>(); public static bool IsMemberInitializerNamedAssignmentIdentifier(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => syntaxFacts.IsMemberInitializerNamedAssignmentIdentifier(node, out _); public static bool IsOnSingleLine(this ISyntaxFacts syntaxFacts, SyntaxNode node, bool fullSpan) { // The stack logic assumes the initial node is not null Contract.ThrowIfNull(node); // Use an actual Stack so we can write out deeply recursive structures without overflowing. // Note: algorithm is taken from GreenNode.WriteTo. // // General approach is that we recurse down the nodes, using a real stack object to // keep track of what node we're on. If full-span is true we'll examine all tokens // and all the trivia on each token. If full-span is false we'll examine all tokens // but we'll ignore the leading trivia on the very first trivia and the trailing trivia // on the very last token. using var _ = s_stackPool.GetPooledObject(out var stack); stack.Push((node, leading: fullSpan, trailing: fullSpan)); var result = IsOnSingleLine(syntaxFacts, stack); return result; } private static bool IsOnSingleLine( ISyntaxFacts syntaxFacts, Stack<(SyntaxNodeOrToken nodeOrToken, bool leading, bool trailing)> stack) { while (stack.TryPop(out var tuple)) { var (currentNodeOrToken, currentLeading, currentTrailing) = tuple; if (currentNodeOrToken.IsToken) { // If this token isn't on a single line, then the original node definitely // isn't on a single line. if (!IsOnSingleLine(syntaxFacts, currentNodeOrToken.AsToken(), currentLeading, currentTrailing)) return false; } else { var currentNode = currentNodeOrToken.AsNode()!; var childNodesAndTokens = currentNode.ChildNodesAndTokens(); var childCount = childNodesAndTokens.Count; // Walk the children of this node in reverse, putting on the stack to process. // This way we process the children in the actual child-order they are in for // this node. var index = 0; foreach (var child in childNodesAndTokens.Reverse()) { // Since we're walking the children in reverse, if we're on hte 0th item, // that's the last child. var last = index == 0; // Once we get all the way to the end of the reversed list, we're actually // on the first. var first = index == childCount - 1; // We want the leading trivia if we've asked for it, or if we're not the first // token being processed. We want the trailing trivia if we've asked for it, // or if we're not the last token being processed. stack.Push((child, currentLeading | !first, currentTrailing | !last)); index++; } } } // All tokens were on a single line. This node is on a single line. return true; } private static bool IsOnSingleLine(ISyntaxFacts syntaxFacts, SyntaxToken token, bool leading, bool trailing) { // If any of our trivia is not on a single line, then we're not on a single line. if (!IsOnSingleLine(syntaxFacts, token.LeadingTrivia, leading) || !IsOnSingleLine(syntaxFacts, token.TrailingTrivia, trailing)) { return false; } // Only string literals can span multiple lines. Only need to check those. if (syntaxFacts.SyntaxKinds.StringLiteralToken == token.RawKind || syntaxFacts.SyntaxKinds.InterpolatedStringTextToken == token.RawKind) { // This allocated. But we only do it in the string case. For all other tokens // we don't need any allocations. if (!IsOnSingleLine(token.ToString())) { return false; } } // Any other type of token is on a single line. return true; } private static bool IsOnSingleLine(ISyntaxFacts syntaxFacts, SyntaxTriviaList triviaList, bool checkTrivia) { if (checkTrivia) { foreach (var trivia in triviaList) { if (trivia.HasStructure) { // For structured trivia, we recurse into the trivia to see if it // is on a single line or not. If it isn't, then we're definitely // not on a single line. if (!IsOnSingleLine(syntaxFacts, trivia.GetStructure()!, fullSpan: true)) { return false; } } else if (syntaxFacts.IsEndOfLineTrivia(trivia)) { // Contained an end-of-line trivia. Definitely not on a single line. return false; } else if (!syntaxFacts.IsWhitespaceTrivia(trivia)) { // Was some other form of trivia (like a comment). Easiest thing // to do is just stringify this and count the number of newlines. // these should be rare. So the allocation here is ok. if (!IsOnSingleLine(trivia.ToString())) { return false; } } } } return true; } private static bool IsOnSingleLine(string value) => value.GetNumberOfLineBreaks() == 0; public static bool ContainsInterleavedDirective( this ISyntaxFacts syntaxFacts, ImmutableArray<SyntaxNode> nodes, CancellationToken cancellationToken) { if (nodes.Length > 0) { var span = TextSpan.FromBounds(nodes.First().Span.Start, nodes.Last().Span.End); foreach (var node in nodes) { cancellationToken.ThrowIfCancellationRequested(); if (ContainsInterleavedDirective(syntaxFacts, span, node, cancellationToken)) return true; } } return false; } public static bool ContainsInterleavedDirective(this ISyntaxFacts syntaxFacts, SyntaxNode node, CancellationToken cancellationToken) => ContainsInterleavedDirective(syntaxFacts, node.Span, node, cancellationToken); public static bool ContainsInterleavedDirective( this ISyntaxFacts syntaxFacts, TextSpan span, SyntaxNode node, CancellationToken cancellationToken) { foreach (var token in node.DescendantTokens()) { if (syntaxFacts.ContainsInterleavedDirective(span, token, cancellationToken)) return true; } return false; } public static bool SpansPreprocessorDirective(this ISyntaxFacts syntaxFacts, IEnumerable<SyntaxNode> nodes) { if (nodes == null || nodes.IsEmpty()) { return false; } return SpansPreprocessorDirective(syntaxFacts, nodes.SelectMany(n => n.DescendantTokens())); } /// <summary> /// Determines if there is preprocessor trivia *between* any of the <paramref name="tokens"/> /// provided. The <paramref name="tokens"/> will be deduped and then ordered by position. /// Specifically, the first token will not have it's leading trivia checked, and the last /// token will not have it's trailing trivia checked. All other trivia will be checked to /// see if it contains a preprocessor directive. /// </summary> public static bool SpansPreprocessorDirective(this ISyntaxFacts syntaxFacts, IEnumerable<SyntaxToken> tokens) { // we want to check all leading trivia of all tokens (except the // first one), and all trailing trivia of all tokens (except the // last one). var first = true; var previousToken = default(SyntaxToken); // Allow duplicate nodes/tokens to be passed in. Also, allow the nodes/tokens // to not be in any particular order when passed in. var orderedTokens = tokens.Distinct().OrderBy(t => t.SpanStart); foreach (var token in orderedTokens) { if (first) { first = false; } else { // check the leading trivia of this token, and the trailing trivia // of the previous token. if (SpansPreprocessorDirective(syntaxFacts, token.LeadingTrivia) || SpansPreprocessorDirective(syntaxFacts, previousToken.TrailingTrivia)) { return true; } } previousToken = token; } return false; } private static bool SpansPreprocessorDirective(this ISyntaxFacts syntaxFacts, SyntaxTriviaList list) => list.Any(syntaxFacts.IsPreprocessorDirective); public static bool IsLegalIdentifier(this ISyntaxFacts syntaxFacts, string name) { if (name.Length == 0) { return false; } if (!syntaxFacts.IsIdentifierStartCharacter(name[0])) { return false; } for (var i = 1; i < name.Length; i++) { if (!syntaxFacts.IsIdentifierPartCharacter(name[i])) { return false; } } return true; } public static bool IsReservedOrContextualKeyword(this ISyntaxFacts syntaxFacts, SyntaxToken token) => syntaxFacts.IsReservedKeyword(token) || syntaxFacts.IsContextualKeyword(token); public static bool IsWord(this ISyntaxFacts syntaxFacts, SyntaxToken token) { return syntaxFacts.IsIdentifier(token) || syntaxFacts.IsReservedOrContextualKeyword(token) || syntaxFacts.IsPreprocessorKeyword(token); } public static bool IsRegularOrDocumentationComment(this ISyntaxFacts syntaxFacts, SyntaxTrivia trivia) => syntaxFacts.IsRegularComment(trivia) || syntaxFacts.IsDocumentationComment(trivia); [return: NotNullIfNotNull(nameof(node))] public static SyntaxNode? WalkDownParentheses(this ISyntaxFacts syntaxFacts, SyntaxNode? node) { while (syntaxFacts.IsParenthesizedExpression(node)) { syntaxFacts.GetPartsOfParenthesizedExpression(node, out _, out var child, out _); node = child; } return node; } [return: NotNullIfNotNull(nameof(node))] public static SyntaxNode? WalkUpParentheses(this ISyntaxFacts syntaxFacts, SyntaxNode? node) { while (syntaxFacts.IsParenthesizedExpression(node?.Parent)) node = node.Parent; return node; } public static void GetPartsOfAssignmentStatement( this ISyntaxFacts syntaxFacts, SyntaxNode statement, out SyntaxNode left, out SyntaxNode right) { syntaxFacts.GetPartsOfAssignmentStatement(statement, out left, out _, out right); } public static SyntaxNode GetExpressionOfInvocationExpression( this ISyntaxFacts syntaxFacts, SyntaxNode node) { syntaxFacts.GetPartsOfInvocationExpression(node, out var expression, out _); return expression; } public static SyntaxNode Unparenthesize( this ISyntaxFacts syntaxFacts, SyntaxNode node) { SyntaxToken openParenToken; SyntaxNode operand; SyntaxToken closeParenToken; if (syntaxFacts.IsParenthesizedPattern(node)) { syntaxFacts.GetPartsOfParenthesizedPattern(node, out openParenToken, out operand, out closeParenToken); } else { syntaxFacts.GetPartsOfParenthesizedExpression(node, out openParenToken, out operand, out closeParenToken); } var leadingTrivia = openParenToken.LeadingTrivia .Concat(openParenToken.TrailingTrivia) .Where(t => !syntaxFacts.IsElastic(t)) .Concat(operand.GetLeadingTrivia()); var trailingTrivia = operand.GetTrailingTrivia() .Concat(closeParenToken.LeadingTrivia) .Where(t => !syntaxFacts.IsElastic(t)) .Concat(closeParenToken.TrailingTrivia); var resultNode = operand .WithLeadingTrivia(leadingTrivia) .WithTrailingTrivia(trailingTrivia); // If there's no trivia between the original node and the tokens around it, then add // elastic markers so the formatting engine will spaces if necessary to keep things // parseable. if (resultNode.GetLeadingTrivia().Count == 0) { var previousToken = node.GetFirstToken().GetPreviousToken(); if (previousToken.TrailingTrivia.Count == 0 && syntaxFacts.IsWordOrNumber(previousToken) && syntaxFacts.IsWordOrNumber(resultNode.GetFirstToken())) { resultNode = resultNode.WithPrependedLeadingTrivia(syntaxFacts.ElasticMarker); } } if (resultNode.GetTrailingTrivia().Count == 0) { var nextToken = node.GetLastToken().GetNextToken(); if (nextToken.LeadingTrivia.Count == 0 && syntaxFacts.IsWordOrNumber(nextToken) && syntaxFacts.IsWordOrNumber(resultNode.GetLastToken())) { resultNode = resultNode.WithAppendedTrailingTrivia(syntaxFacts.ElasticMarker); } } return resultNode; } private static bool IsWordOrNumber(this ISyntaxFacts syntaxFacts, SyntaxToken token) => syntaxFacts.IsWord(token) || syntaxFacts.IsNumericLiteral(token); public static bool SpansPreprocessorDirective(this ISyntaxFacts service, SyntaxNode node) => service.SpansPreprocessorDirective([node]); public static bool SpansPreprocessorDirective(this ISyntaxFacts service, params SyntaxNode[] nodes) => service.SpansPreprocessorDirective((IEnumerable<SyntaxNode>)nodes); public static bool IsWhitespaceOrEndOfLineTrivia(this ISyntaxFacts syntaxFacts, SyntaxTrivia trivia) => syntaxFacts.IsWhitespaceTrivia(trivia) || syntaxFacts.IsEndOfLineTrivia(trivia); public static void GetPartsOfBinaryExpression(this ISyntaxFacts syntaxFacts, SyntaxNode node, out SyntaxNode left, out SyntaxNode right) => syntaxFacts.GetPartsOfBinaryExpression(node, out left, out _, out right); public static SyntaxNode GetPatternOfParenthesizedPattern(this ISyntaxFacts syntaxFacts, SyntaxNode node) { syntaxFacts.GetPartsOfParenthesizedPattern(node, out _, out var pattern, out _); return pattern; } public static SyntaxToken GetOperatorTokenOfBinaryExpression(this ISyntaxFacts syntaxFacts, SyntaxNode node) { syntaxFacts.GetPartsOfBinaryExpression(node, out _, out var token, out _); return token; } public static bool IsAnonymousOrLocalFunction(this ISyntaxFacts syntaxFacts, SyntaxNode node) => syntaxFacts.IsAnonymousFunctionExpression(node) || syntaxFacts.IsLocalFunctionStatement(node); public static SyntaxNode? GetExpressionOfElementAccessExpression(this ISyntaxFacts syntaxFacts, SyntaxNode node) { syntaxFacts.GetPartsOfElementAccessExpression(node, out var expression, out _); return expression; } public static SyntaxNode? GetArgumentListOfElementAccessExpression(this ISyntaxFacts syntaxFacts, SyntaxNode node) { syntaxFacts.GetPartsOfElementAccessExpression(node, out _, out var argumentList); return argumentList; } public static SyntaxNode GetExpressionOfConditionalAccessExpression(this ISyntaxFacts syntaxFacts, SyntaxNode node) { syntaxFacts.GetPartsOfConditionalAccessExpression(node, out var expression, out _); return expression; } public static SyntaxToken GetOperatorTokenOfMemberAccessExpression(this ISyntaxFacts syntaxFacts, SyntaxNode node) { syntaxFacts.GetPartsOfMemberAccessExpression(node, out _, out var operatorToken, out _); return operatorToken; } public static void GetPartsOfMemberAccessExpression(this ISyntaxFacts syntaxFacts, SyntaxNode node, out SyntaxNode expression, out SyntaxNode name) => syntaxFacts.GetPartsOfMemberAccessExpression(node, out expression, out _, out name); public static void GetPartsOfConditionalAccessExpression(this ISyntaxFacts syntaxFacts, SyntaxNode node, out SyntaxNode expression, out SyntaxNode whenNotNull) => syntaxFacts.GetPartsOfConditionalAccessExpression(node, out expression, out _, out whenNotNull); public static TextSpan GetSpanWithoutAttributes(this ISyntaxFacts syntaxFacts, SyntaxNode root, SyntaxNode node) { // Span without AttributeLists // - No AttributeLists -> original .Span // - Some AttributeLists -> (first non-trivia/comment Token.Span.Begin, original.Span.End) // - We need to be mindful about comments due to: // // [Test1] // //Comment1 // [||]object Property1 { get; set; } // the comment node being part of the next token's (`object`) leading trivia and not the AttributeList's node. // - In case only attribute is written we need to be careful to not to use next (unrelated) token as beginning current the node. var attributeList = syntaxFacts.GetAttributeLists(node); if (attributeList.Any()) { var endOfAttributeLists = attributeList.Last().Span.End; var afterAttributesToken = root.FindTokenOnRightOfPosition(endOfAttributeLists); var endOfNode = node.Span.End; var startOfNodeWithoutAttributes = Math.Min(afterAttributesToken.Span.Start, endOfNode); return TextSpan.FromBounds(startOfNodeWithoutAttributes, endOfNode); } return node.Span; } /// <summary> /// Similar to <see cref="ISyntaxFacts.GetStandaloneExpression(SyntaxNode)"/>, this gets the containing /// expression that is actually a language expression and not just typed as an ExpressionSyntax for convenience. /// However, this goes beyond that that method in that if this expression is the RHS of a conditional access /// (i.e. <c>a?.b()</c>) it will also return the root of the conditional access expression tree. /// <para/> The intuition here is that this will give the topmost expression node that could realistically be /// replaced with any other expression. For example, with <c>a?.b()</c> technically <c>.b()</c> is an /// expression. But that cannot be replaced with something like <c>(1 + 1)</c> (as <c>a?.(1 + 1)</c> is not /// legal). However, in <c>a?.b()</c>, then <c>a</c> itself could be replaced with <c>(1 + 1)?.b()</c> to form /// a legal expression. /// </summary> public static SyntaxNode GetRootStandaloneExpression(this ISyntaxFacts syntaxFacts, SyntaxNode node) { // First, make sure we're on a construct the language things is a standalone expression. var standalone = syntaxFacts.GetStandaloneExpression(node); // Then, if this is the RHS of a `?`, walk up to the top of that tree to get the final standalone expression. return syntaxFacts.GetRootConditionalAccessExpression(standalone) ?? standalone; } #region GetXXXOfYYY Members public static SyntaxNode? GetArgumentListOfInvocationExpression(this ISyntaxFacts syntaxFacts, SyntaxNode node) { syntaxFacts.GetPartsOfInvocationExpression(node, out _, out var argumentList); return argumentList; } public static SeparatedSyntaxList<SyntaxNode> GetArgumentsOfInvocationExpression(this ISyntaxFacts syntaxFacts, SyntaxNode node) { var argumentList = syntaxFacts.GetArgumentListOfInvocationExpression(node); return argumentList is null ? default : syntaxFacts.GetArgumentsOfArgumentList(argumentList); } public static SyntaxNode? GetArgumentListOfBaseObjectCreationExpression(this ISyntaxFacts syntaxFacts, SyntaxNode node) { syntaxFacts.GetPartsOfBaseObjectCreationExpression(node, out var argumentList, out _); return argumentList; } public static SyntaxNode? GetDefaultOfParameter(this ISyntaxFacts syntaxFacts, SyntaxNode node) { syntaxFacts.GetPartsOfParameter(node, out _, out var @default); return @default; } public static SyntaxNode GetExpressionOfParenthesizedExpression(this ISyntaxFacts syntaxFacts, SyntaxNode node) { syntaxFacts.GetPartsOfParenthesizedExpression(node, out _, out var expression, out _); return expression; } public static SyntaxToken GetIdentifierOfGenericName(this ISyntaxFacts syntaxFacts, SyntaxNode node) { syntaxFacts.GetPartsOfGenericName(node, out var identifier, out _); return identifier; } public static SyntaxToken GetIdentifierOfIdentifierName(this ISyntaxFacts syntaxFacts, SyntaxNode node) => syntaxFacts.GetIdentifierOfSimpleName(node); public static SyntaxToken GetIdentifierOfParameter(this ISyntaxFacts syntaxFacts, SyntaxNode node) { syntaxFacts.GetPartsOfParameter(node, out var identifier, out _); return identifier; } public static SyntaxList<SyntaxNode> GetImportsOfBaseNamespaceDeclaration(this ISyntaxFacts syntaxFacts, SyntaxNode node) { syntaxFacts.GetPartsOfBaseNamespaceDeclaration(node, out _, out var imports, out _); return imports; } public static SyntaxList<SyntaxNode> GetImportsOfCompilationUnit(this ISyntaxFacts syntaxFacts, SyntaxNode node) { syntaxFacts.GetPartsOfCompilationUnit(node, out var imports, out _, out _); return imports; } public static SyntaxNode? GetInitializerOfBaseObjectCreationExpression(this ISyntaxFacts syntaxFacts, SyntaxNode node) { syntaxFacts.GetPartsOfBaseObjectCreationExpression(node, out _, out var initializer); return initializer; } public static SyntaxList<SyntaxNode> GetMembersOfBaseNamespaceDeclaration(this ISyntaxFacts syntaxFacts, SyntaxNode node) { syntaxFacts.GetPartsOfBaseNamespaceDeclaration(node, out _, out _, out var members); return members; } public static SyntaxList<SyntaxNode> GetMembersOfCompilationUnit(this ISyntaxFacts syntaxFacts, SyntaxNode node) { syntaxFacts.GetPartsOfCompilationUnit(node, out _, out _, out var members); return members; } public static SyntaxNode GetNameOfAttribute(this ISyntaxFacts syntaxFacts, SyntaxNode node) { syntaxFacts.GetPartsOfAttribute(node, out var name, out _); return name; } public static SyntaxNode GetNameOfBaseNamespaceDeclaration(this ISyntaxFacts syntaxFacts, SyntaxNode node) { syntaxFacts.GetPartsOfBaseNamespaceDeclaration(node, out var name, out _, out _); return name; } public static SyntaxNode GetNameOfMemberAccessExpression(this ISyntaxFacts syntaxFacts, SyntaxNode node) { syntaxFacts.GetPartsOfMemberAccessExpression(node, out _, out var name); return name; } public static SyntaxNode GetOperandOfPrefixUnaryExpression(this ISyntaxFacts syntaxFacts, SyntaxNode node) { syntaxFacts.GetPartsOfPrefixUnaryExpression(node, out _, out var operand); return operand; } public static SyntaxToken GetOperatorTokenOfPrefixUnaryExpression(this ISyntaxFacts syntaxFacts, SyntaxNode node) { syntaxFacts.GetPartsOfPrefixUnaryExpression(node, out var operatorToken, out _); return operatorToken; } public static SeparatedSyntaxList<SyntaxNode> GetTypeArgumentsOfGenericName(this ISyntaxFacts syntaxFacts, SyntaxNode node) { syntaxFacts.GetPartsOfGenericName(node, out _, out var typeArguments); return typeArguments; } public static SyntaxNode GetTypeOfObjectCreationExpression(this ISyntaxFacts syntaxFacts, SyntaxNode node) { syntaxFacts.GetPartsOfObjectCreationExpression(node, out _, out var type, out _, out _); return type; } #endregion #region IsXXXOfYYY members public static bool IsExpressionOfAwaitExpression(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) { var parent = node?.Parent; if (!syntaxFacts.IsAwaitExpression(parent)) return false; return node == syntaxFacts.GetExpressionOfAwaitExpression(parent); } public static bool IsExpressionOfInvocationExpression(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) { var parent = node?.Parent; if (!syntaxFacts.IsInvocationExpression(parent)) return false; syntaxFacts.GetPartsOfInvocationExpression(parent, out var expression, out _); return node == expression; } public static bool IsExpressionOfMemberAccessExpression(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) { var parent = node?.Parent; if (!syntaxFacts.IsMemberAccessExpression(parent)) return false; syntaxFacts.GetPartsOfMemberAccessExpression(parent, out var expression, out _); return node == expression; } public static bool IsNameOfAttribute(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) { if (!syntaxFacts.IsAttribute(node?.Parent)) return false; syntaxFacts.GetPartsOfAttribute(node.Parent, out var name, out _); return name == node; } public static bool IsRightOfQualifiedName(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) { var parent = node?.Parent; if (!syntaxFacts.IsQualifiedName(parent)) return false; syntaxFacts.GetPartsOfQualifiedName(parent, out _, out _, out var right); return node == right; } public static bool IsRightOfAliasQualifiedName(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) { var parent = node?.Parent; if (!syntaxFacts.IsAliasQualifiedName(parent)) return false; syntaxFacts.GetPartsOfAliasQualifiedName(parent, out _, out _, out var right); return node == right; } public static bool IsTypeOfObjectCreationExpression(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) { var parent = node?.Parent; if (!syntaxFacts.IsObjectCreationExpression(parent)) return false; syntaxFacts.GetPartsOfObjectCreationExpression(parent, out _, out var type, out _, out _); return type == node; } #endregion #region ISyntaxKinds forwarding methods #region trivia public static bool IsEndOfLineTrivia(this ISyntaxFacts syntaxFacts, SyntaxTrivia trivia) => trivia.RawKind == syntaxFacts.SyntaxKinds.EndOfLineTrivia; public static bool IsMultiLineCommentTrivia(this ISyntaxFacts syntaxFacts, SyntaxTrivia trivia) => trivia.RawKind == syntaxFacts.SyntaxKinds.MultiLineCommentTrivia; public static bool IsMultiLineDocCommentTrivia(this ISyntaxFacts syntaxFacts, SyntaxTrivia trivia) => trivia.RawKind == syntaxFacts.SyntaxKinds.MultiLineDocCommentTrivia; public static bool IsShebangDirectiveTrivia(this ISyntaxFacts syntaxFacts, SyntaxTrivia trivia) => trivia.RawKind == syntaxFacts.SyntaxKinds.ShebangDirectiveTrivia; public static bool IsSingleLineCommentTrivia(this ISyntaxFacts syntaxFacts, SyntaxTrivia trivia) => trivia.RawKind == syntaxFacts.SyntaxKinds.SingleLineCommentTrivia; public static bool IsSingleLineDocCommentTrivia(this ISyntaxFacts syntaxFacts, SyntaxTrivia trivia) => trivia.RawKind == syntaxFacts.SyntaxKinds.SingleLineDocCommentTrivia; public static bool IsWhitespaceTrivia(this ISyntaxFacts syntaxFacts, SyntaxTrivia trivia) => trivia.RawKind == syntaxFacts.SyntaxKinds.WhitespaceTrivia; public static bool IsSkippedTokensTrivia(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.SkippedTokensTrivia; #endregion #region keywords public static bool IsAwaitKeyword(this ISyntaxFacts syntaxFacts, SyntaxToken token) => token.RawKind == syntaxFacts.SyntaxKinds.AwaitKeyword; public static bool IsGlobalNamespaceKeyword(this ISyntaxFacts syntaxFacts, SyntaxToken token) => token.RawKind == syntaxFacts.SyntaxKinds.GlobalKeyword; #endregion #region literal tokens public static bool IsCharacterLiteral(this ISyntaxFacts syntaxFacts, SyntaxToken token) => token.RawKind == syntaxFacts.SyntaxKinds.CharacterLiteralToken; public static bool IsStringLiteral(this ISyntaxFacts syntaxFacts, SyntaxToken token) => token.RawKind == syntaxFacts.SyntaxKinds.StringLiteralToken; #endregion #region tokens public static bool IsIdentifier(this ISyntaxFacts syntaxFacts, SyntaxToken token) => token.RawKind == syntaxFacts.SyntaxKinds.IdentifierToken; public static bool IsHashToken(this ISyntaxFacts syntaxFacts, SyntaxToken token) => token.RawKind == syntaxFacts.SyntaxKinds.HashToken; public static bool IsInterpolatedStringTextToken(this ISyntaxFacts syntaxFacts, SyntaxToken token) => token.RawKind == syntaxFacts.SyntaxKinds.InterpolatedStringTextToken; #endregion #region names public static bool IsAliasQualifiedName(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.AliasQualifiedName; public static bool IsGenericName(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.GenericName; public static bool IsIdentifierName(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.IdentifierName; public static bool IsQualifiedName(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.QualifiedName; #endregion #region types public static bool IsTupleType(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.TupleType; #endregion #region literal expressions public static bool IsCharacterLiteralExpression(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.CharacterLiteralExpression; public static bool IsDefaultLiteralExpression(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.DefaultLiteralExpression; public static bool IsFalseLiteralExpression(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.FalseLiteralExpression; public static bool IsNumericLiteralExpression(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.NumericLiteralExpression; public static bool IsNullLiteralExpression(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.NullLiteralExpression; public static bool IsStringLiteralExpression(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.StringLiteralExpression; public static bool IsTrueLiteralExpression(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.TrueLiteralExpression; #endregion #region expressions public static bool IsArrayCreationExpression(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.ArrayCreationExpression; public static bool IsAwaitExpression(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.AwaitExpression; public static bool IsBaseExpression(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.BaseExpression; public static bool IsConditionalExpression(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.ConditionalExpression; public static bool IsConditionalAccessExpression(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.ConditionalAccessExpression; public static bool IsFieldExpression(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.FieldExpression; public static bool IsImplicitArrayCreationExpression(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.ImplicitArrayCreationExpression; public static bool IsImplicitObjectCreationExpression(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node != null && node.RawKind == syntaxFacts.SyntaxKinds.ImplicitObjectCreationExpression; public static bool IsIndexExpression(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.IndexExpression; public static bool IsInterpolatedStringExpression(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.InterpolatedStringExpression; public static bool IsInterpolation(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.Interpolation; public static bool IsInterpolatedStringText(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.InterpolatedStringText; public static bool IsInvocationExpression(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.InvocationExpression; public static bool IsIsTypeExpression(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.IsTypeExpression; public static bool IsIsNotTypeExpression(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.IsNotTypeExpression; public static bool IsIsPatternExpression(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.IsPatternExpression; public static bool IsLogicalAndExpression(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.LogicalAndExpression; public static bool IsLogicalOrExpression(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.LogicalOrExpression; public static bool IsLogicalNotExpression(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.LogicalNotExpression; public static bool IsObjectCreationExpression(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.ObjectCreationExpression; public static bool IsParenthesizedExpression(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.ParenthesizedExpression; public static bool IsQueryExpression(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.QueryExpression; public static bool IsRangeExpression(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.RangeExpression; public static bool IsRefExpression(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.RefExpression; public static bool IsSimpleMemberAccessExpression(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.SimpleMemberAccessExpression; public static bool IsThisExpression(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.ThisExpression; public static bool IsThrowExpression(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node != null && node.RawKind == syntaxFacts.SyntaxKinds.ThrowExpression; public static bool IsTupleExpression(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.TupleExpression; public static bool ContainsGlobalStatement(this ISyntaxFacts syntaxFacts, SyntaxNode node) => node.ChildNodes().Any(c => c.RawKind == syntaxFacts.SyntaxKinds.GlobalStatement); #endregion #region pattern public static bool IsAndPattern(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.AndPattern; public static bool IsConstantPattern(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.ConstantPattern; public static bool IsDeclarationPattern(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.DeclarationPattern; public static bool IsListPattern(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.ListPattern; public static bool IsNotPattern(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.NotPattern; public static bool IsOrPattern(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.OrPattern; public static bool IsParenthesizedPattern(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.ParenthesizedPattern; public static bool IsRecursivePattern(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.RecursivePattern; public static bool IsRelationalPattern(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.RelationalPattern; public static bool IsTypePattern(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.TypePattern; public static bool IsVarPattern(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.VarPattern; #endregion #region statements public static bool IsExpressionStatement(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.ExpressionStatement; public static bool IsForEachStatement(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.ForEachStatement; public static bool IsForStatement(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.ForStatement; public static bool IsIfStatement(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.IfStatement; public static bool IsLocalDeclarationStatement(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.LocalDeclarationStatement; public static bool IsLocalFunctionStatement(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node != null && node.RawKind == syntaxFacts.SyntaxKinds.LocalFunctionStatement; public static bool IsLockStatement(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.LockStatement; public static bool IsReturnStatement(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.ReturnStatement; public static bool IsThrowStatement(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.ThrowStatement; public static bool IsUsingStatement(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.UsingStatement; public static bool IsWhileStatement(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.WhileStatement; public static bool IsYieldReturnStatement(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.YieldReturnStatement; #endregion #region members/declarations public static bool IsAttribute(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.Attribute; public static bool IsClassDeclaration(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.ClassDeclaration; public static bool IsConstructorDeclaration(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.ConstructorDeclaration; public static bool IsEnumDeclaration(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.EnumDeclaration; public static bool IsGlobalAttribute(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => syntaxFacts.IsGlobalAssemblyAttribute(node) || syntaxFacts.IsGlobalModuleAttribute(node); public static bool IsInterfaceDeclaration(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.InterfaceDeclaration; public static bool IsParameter(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.Parameter; public static bool IsTypeConstraint(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.TypeConstraint; public static bool IsVariableDeclarator(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.VariableDeclarator; public static bool IsFieldDeclaration(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.FieldDeclaration; public static bool IsPropertyDeclaration(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.PropertyDeclaration; public static bool IsStructDeclaration(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.StructDeclaration; public static bool IsTypeArgumentList(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.TypeArgumentList; #endregion #region clauses public static bool IsElseClause(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.ElseClause; public static bool IsEqualsValueClause(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.EqualsValueClause; #endregion #region other public static bool IsImplicitElementAccess(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.ImplicitElementAccess; public static bool IsIndexerMemberCref(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.IndexerMemberCref; public static bool IsPrimaryConstructorBaseType(this ISyntaxFacts syntaxFacts, [NotNullWhen(true)] SyntaxNode? node) => node?.RawKind == syntaxFacts.SyntaxKinds.PrimaryConstructorBaseType; #endregion #endregion } |