/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/CSharp/Portable/Syntax/SyntaxExtensions.cs
490 строк
22 KB
Sam Harwell
Fix all IDE0240 (Nullable directive is redundant)
05 окт 2023, 18:59
05 окт 2023, 18:59
a190246
Код
Авторство
О чём код?
// 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; using System.Diagnostics.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp { public static class SyntaxExtensions { /// <summary> /// Gets the expression-body syntax from an expression-bodied member. The /// given syntax must be for a member which could contain an expression-body. /// </summary> internal static ArrowExpressionClauseSyntax? GetExpressionBodySyntax(this CSharpSyntaxNode node) { ArrowExpressionClauseSyntax? arrowExpr = null; switch (node.Kind()) { // The ArrowExpressionClause is the declaring syntax for the // 'get' SourcePropertyAccessorSymbol of properties and indexers. case SyntaxKind.ArrowExpressionClause: arrowExpr = (ArrowExpressionClauseSyntax)node; break; case SyntaxKind.MethodDeclaration: case SyntaxKind.OperatorDeclaration: case SyntaxKind.ConversionOperatorDeclaration: case SyntaxKind.ConstructorDeclaration: case SyntaxKind.DestructorDeclaration: arrowExpr = ((BaseMethodDeclarationSyntax)node).ExpressionBody; break; case SyntaxKind.GetAccessorDeclaration: case SyntaxKind.SetAccessorDeclaration: case SyntaxKind.InitAccessorDeclaration: case SyntaxKind.AddAccessorDeclaration: case SyntaxKind.RemoveAccessorDeclaration: case SyntaxKind.UnknownAccessorDeclaration: arrowExpr = ((AccessorDeclarationSyntax)node).ExpressionBody; break; case SyntaxKind.PropertyDeclaration: arrowExpr = ((PropertyDeclarationSyntax)node).ExpressionBody; break; case SyntaxKind.IndexerDeclaration: arrowExpr = ((IndexerDeclarationSyntax)node).ExpressionBody; break; default: // Don't throw, just use for the assert in case this is used in the semantic model ExceptionUtilities.UnexpectedValue(node.Kind()); break; } return arrowExpr; } /// <summary> /// Creates a new syntax token with all whitespace and end of line trivia replaced with /// regularly formatted trivia. /// </summary> /// <param name="token">The token to normalize.</param> /// <param name="indentation">A sequence of whitespace characters that defines a single level of indentation.</param> /// <param name="elasticTrivia">If true the replaced trivia is elastic trivia.</param> public static SyntaxToken NormalizeWhitespace(this SyntaxToken token, string indentation, bool elasticTrivia) { return SyntaxNormalizer.Normalize(token, indentation, CodeAnalysis.SyntaxNodeExtensions.DefaultEOL, elasticTrivia); } /// <summary> /// Return the identifier of an out declaration argument expression. /// </summary> internal static SyntaxToken Identifier(this DeclarationExpressionSyntax self) { return ((SingleVariableDesignationSyntax)self.Designation).Identifier; } /// <summary> /// Creates a new syntax token with all whitespace and end of line trivia replaced with /// regularly formatted trivia. /// </summary> /// <param name="token">The token to normalize.</param> /// <param name="indentation">An optional sequence of whitespace characters that defines a /// single level of indentation.</param> /// <param name="eol">An optional sequence of whitespace characters used for end of line.</param> /// <param name="elasticTrivia">If true the replaced trivia is elastic trivia.</param> public static SyntaxToken NormalizeWhitespace(this SyntaxToken token, string indentation = CodeAnalysis.SyntaxNodeExtensions.DefaultIndentation, string eol = CodeAnalysis.SyntaxNodeExtensions.DefaultEOL, bool elasticTrivia = false) { return SyntaxNormalizer.Normalize(token, indentation, eol, elasticTrivia); } /// <summary> /// Creates a new syntax trivia list with all whitespace and end of line trivia replaced with /// regularly formatted trivia. /// </summary> /// <param name="list">The trivia list to normalize.</param> /// <param name="indentation">A sequence of whitespace characters that defines a single level of indentation.</param> /// <param name="elasticTrivia">If true the replaced trivia is elastic trivia.</param> public static SyntaxTriviaList NormalizeWhitespace(this SyntaxTriviaList list, string indentation, bool elasticTrivia) { return SyntaxNormalizer.Normalize(list, indentation, CodeAnalysis.SyntaxNodeExtensions.DefaultEOL, elasticTrivia); } /// <summary> /// Creates a new syntax trivia list with all whitespace and end of line trivia replaced with /// regularly formatted trivia. /// </summary> /// <param name="list">The trivia list to normalize.</param> /// <param name="indentation">An optional sequence of whitespace characters that defines a /// single level of indentation.</param> /// <param name="eol">An optional sequence of whitespace characters used for end of line.</param> /// <param name="elasticTrivia">If true the replaced trivia is elastic trivia.</param> public static SyntaxTriviaList NormalizeWhitespace(this SyntaxTriviaList list, string indentation = CodeAnalysis.SyntaxNodeExtensions.DefaultIndentation, string eol = CodeAnalysis.SyntaxNodeExtensions.DefaultEOL, bool elasticTrivia = false) { return SyntaxNormalizer.Normalize(list, indentation, eol, elasticTrivia); } public static SyntaxTriviaList ToSyntaxTriviaList(this IEnumerable<SyntaxTrivia> sequence) { return SyntaxFactory.TriviaList(sequence); } internal static XmlNameAttributeElementKind GetElementKind(this XmlNameAttributeSyntax attributeSyntax) { Debug.Assert(attributeSyntax.Parent is object); CSharpSyntaxNode parentSyntax = attributeSyntax.Parent; SyntaxKind parentKind = parentSyntax.Kind(); string parentName; if (parentKind == SyntaxKind.XmlEmptyElement) { var parent = (XmlEmptyElementSyntax)parentSyntax; parentName = parent.Name.LocalName.ValueText; Debug.Assert(parent.Name.Prefix is null); } else if (parentKind == SyntaxKind.XmlElementStartTag) { var parent = (XmlElementStartTagSyntax)parentSyntax; parentName = parent.Name.LocalName.ValueText; Debug.Assert(parent.Name.Prefix is null); } else { throw ExceptionUtilities.UnexpectedValue(parentKind); } if (DocumentationCommentXmlNames.ElementEquals(parentName, DocumentationCommentXmlNames.ParameterElementName)) { return XmlNameAttributeElementKind.Parameter; } else if (DocumentationCommentXmlNames.ElementEquals(parentName, DocumentationCommentXmlNames.ParameterReferenceElementName)) { return XmlNameAttributeElementKind.ParameterReference; } else if (DocumentationCommentXmlNames.ElementEquals(parentName, DocumentationCommentXmlNames.TypeParameterElementName)) { return XmlNameAttributeElementKind.TypeParameter; } else if (DocumentationCommentXmlNames.ElementEquals(parentName, DocumentationCommentXmlNames.TypeParameterReferenceElementName)) { return XmlNameAttributeElementKind.TypeParameterReference; } else { throw ExceptionUtilities.UnexpectedValue(parentName); } } internal static bool ReportDocumentationCommentDiagnostics(this SyntaxTree tree) { return tree.Options.DocumentationMode >= DocumentationMode.Diagnose; } /// <summary> /// Updates the given SimpleNameSyntax node with the given identifier token. /// This function is a wrapper that calls WithIdentifier on derived syntax nodes. /// </summary> /// <param name="simpleName"></param> /// <param name="identifier"></param> /// <returns>The given simple name updated with the given identifier.</returns> public static SimpleNameSyntax WithIdentifier(this SimpleNameSyntax simpleName, SyntaxToken identifier) { return simpleName.Kind() == SyntaxKind.IdentifierName ? (SimpleNameSyntax)((IdentifierNameSyntax)simpleName).WithIdentifier(identifier) : (SimpleNameSyntax)((GenericNameSyntax)simpleName).WithIdentifier(identifier); } internal static bool IsTypeInContextWhichNeedsDynamicAttribute(this IdentifierNameSyntax typeNode) { Debug.Assert(typeNode != null); return SyntaxFacts.IsInTypeOnlyContext(typeNode) && IsInContextWhichNeedsDynamicAttribute(typeNode); } internal static ExpressionSyntax SkipParens(this ExpressionSyntax expression) { while (expression.Kind() == SyntaxKind.ParenthesizedExpression) { expression = ((ParenthesizedExpressionSyntax)expression).Expression; } return expression; } /// <summary> /// Returns true if the expression on the left-hand-side of an assignment causes the assignment to be a deconstruction. /// </summary> internal static bool IsDeconstructionLeft(this ExpressionSyntax node) { switch (node.Kind()) { case SyntaxKind.TupleExpression: return true; case SyntaxKind.DeclarationExpression: return ((DeclarationExpressionSyntax)node).Designation.Kind() == SyntaxKind.ParenthesizedVariableDesignation; default: return false; } } internal static bool IsDeconstruction(this AssignmentExpressionSyntax self) { return self.Left.IsDeconstructionLeft(); } private static bool IsInContextWhichNeedsDynamicAttribute(CSharpSyntaxNode node) { Debug.Assert(node != null); switch (node.Kind()) { case SyntaxKind.Parameter: case SyntaxKind.FieldDeclaration: case SyntaxKind.MethodDeclaration: case SyntaxKind.IndexerDeclaration: case SyntaxKind.OperatorDeclaration: case SyntaxKind.ConversionOperatorDeclaration: case SyntaxKind.PropertyDeclaration: case SyntaxKind.DelegateDeclaration: case SyntaxKind.EventDeclaration: case SyntaxKind.EventFieldDeclaration: case SyntaxKind.BaseList: case SyntaxKind.SimpleBaseType: case SyntaxKind.PrimaryConstructorBaseType: return true; case SyntaxKind.Block: case SyntaxKind.VariableDeclarator: case SyntaxKind.TypeParameterConstraintClause: case SyntaxKind.Attribute: case SyntaxKind.EqualsValueClause: return false; default: return node.Parent != null && IsInContextWhichNeedsDynamicAttribute(node.Parent); } } public static IndexerDeclarationSyntax Update( this IndexerDeclarationSyntax syntax, SyntaxList<AttributeListSyntax> attributeLists, SyntaxTokenList modifiers, TypeSyntax type, ExplicitInterfaceSpecifierSyntax explicitInterfaceSpecifier, SyntaxToken thisKeyword, BracketedParameterListSyntax parameterList, AccessorListSyntax accessorList) { return syntax.Update( attributeLists, modifiers, type, explicitInterfaceSpecifier, thisKeyword, parameterList, accessorList, expressionBody: null, semicolonToken: default); } public static OperatorDeclarationSyntax Update( this OperatorDeclarationSyntax syntax, SyntaxList<AttributeListSyntax> attributeLists, SyntaxTokenList modifiers, TypeSyntax returnType, SyntaxToken operatorKeyword, SyntaxToken operatorToken, ParameterListSyntax parameterList, BlockSyntax block, SyntaxToken semicolonToken) { return syntax.Update( attributeLists, modifiers, returnType, operatorKeyword, operatorToken, parameterList, block, expressionBody: null, semicolonToken); } public static MethodDeclarationSyntax Update( this MethodDeclarationSyntax syntax, SyntaxList<AttributeListSyntax> attributeLists, SyntaxTokenList modifiers, TypeSyntax returnType, ExplicitInterfaceSpecifierSyntax explicitInterfaceSpecifier, SyntaxToken identifier, TypeParameterListSyntax typeParameterList, ParameterListSyntax parameterList, SyntaxList<TypeParameterConstraintClauseSyntax> constraintClauses, BlockSyntax block, SyntaxToken semicolonToken) { return syntax.Update( attributeLists, modifiers, returnType, explicitInterfaceSpecifier, identifier, typeParameterList, parameterList, constraintClauses, block, expressionBody: null, semicolonToken); } /// <summary> /// If this declaration or identifier is part of a deconstruction, find the deconstruction. /// If found, returns either an assignment expression or a foreach variable statement. /// Returns null otherwise. /// </summary> internal static CSharpSyntaxNode? GetContainingDeconstruction(this ExpressionSyntax expr) { var kind = expr.Kind(); if (kind != SyntaxKind.TupleExpression && kind != SyntaxKind.DeclarationExpression && kind != SyntaxKind.IdentifierName) { return null; } while (true) { Debug.Assert(expr.Kind() == SyntaxKind.TupleExpression || expr.Kind() == SyntaxKind.DeclarationExpression || expr.Kind() == SyntaxKind.IdentifierName); var parent = expr.Parent; if (parent == null) { return null; } switch (parent.Kind()) { case SyntaxKind.Argument: if (parent.Parent?.Kind() == SyntaxKind.TupleExpression) { expr = (TupleExpressionSyntax)parent.Parent; continue; } return null; case SyntaxKind.SimpleAssignmentExpression: if ((object)((AssignmentExpressionSyntax)parent).Left == expr) { return parent; } return null; case SyntaxKind.ForEachVariableStatement: if ((object)((ForEachVariableStatementSyntax)parent).Variable == expr) { return parent; } return null; default: return null; } } } internal static bool IsOutDeclaration(this DeclarationExpressionSyntax p) { return p.Parent?.Kind() == SyntaxKind.Argument && ((ArgumentSyntax)p.Parent).RefOrOutKeyword.Kind() == SyntaxKind.OutKeyword; } internal static bool IsOutVarDeclaration(this DeclarationExpressionSyntax p) { return p.Designation.Kind() == SyntaxKind.SingleVariableDesignation && p.IsOutDeclaration(); } /// <summary> /// Visits all the ArrayRankSpecifiers of a typeSyntax, invoking an action on each one in turn. /// </summary> /// <param name="type"></param> /// <param name="action"></param> /// <param name="argument">The argument that is passed to the action whenever it is invoked</param> internal static void VisitRankSpecifiers<TArg>(this TypeSyntax type, Action<ArrayRankSpecifierSyntax, TArg> action, in TArg argument) { // Use a manual stack here to avoid deeply nested recursion which can blow the real stack var stack = ArrayBuilder<SyntaxNode>.GetInstance(); stack.Push(type); while (stack.Count > 0) { var current = stack.Pop(); if (current is ArrayRankSpecifierSyntax rankSpecifier) { action(rankSpecifier, argument); continue; } else { type = (TypeSyntax)current; } switch (type.Kind()) { case SyntaxKind.ArrayType: var arrayTypeSyntax = (ArrayTypeSyntax)type; for (int i = arrayTypeSyntax.RankSpecifiers.Count - 1; i >= 0; i--) { stack.Push(arrayTypeSyntax.RankSpecifiers[i]); } stack.Push(arrayTypeSyntax.ElementType); break; case SyntaxKind.NullableType: var nullableTypeSyntax = (NullableTypeSyntax)type; stack.Push(nullableTypeSyntax.ElementType); break; case SyntaxKind.PointerType: var pointerTypeSyntax = (PointerTypeSyntax)type; stack.Push(pointerTypeSyntax.ElementType); break; case SyntaxKind.FunctionPointerType: var functionPointerTypeSyntax = (FunctionPointerTypeSyntax)type; for (int i = functionPointerTypeSyntax.ParameterList.Parameters.Count - 1; i >= 0; i--) { TypeSyntax? paramType = functionPointerTypeSyntax.ParameterList.Parameters[i].Type; Debug.Assert(paramType is object); stack.Push(paramType); } break; case SyntaxKind.TupleType: var tupleTypeSyntax = (TupleTypeSyntax)type; for (int i = tupleTypeSyntax.Elements.Count - 1; i >= 0; i--) { stack.Push(tupleTypeSyntax.Elements[i].Type); } break; case SyntaxKind.RefType: var refTypeSyntax = (RefTypeSyntax)type; stack.Push(refTypeSyntax.Type); break; case SyntaxKind.ScopedType: var scopedTypeSyntax = (ScopedTypeSyntax)type; stack.Push(scopedTypeSyntax.Type); break; case SyntaxKind.GenericName: var genericNameSyntax = (GenericNameSyntax)type; for (int i = genericNameSyntax.TypeArgumentList.Arguments.Count - 1; i >= 0; i--) { stack.Push(genericNameSyntax.TypeArgumentList.Arguments[i]); } break; case SyntaxKind.QualifiedName: var qualifiedNameSyntax = (QualifiedNameSyntax)type; stack.Push(qualifiedNameSyntax.Right); stack.Push(qualifiedNameSyntax.Left); break; case SyntaxKind.AliasQualifiedName: var aliasQualifiedNameSyntax = (AliasQualifiedNameSyntax)type; stack.Push(aliasQualifiedNameSyntax.Name); break; case SyntaxKind.IdentifierName: case SyntaxKind.OmittedTypeArgument: case SyntaxKind.PredefinedType: break; default: throw ExceptionUtilities.UnexpectedValue(type.Kind()); } } stack.Free(); } } }