/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/Extensions/ExpressionSyntaxExtensions.vb
307 строк
14 KB
Cyrus Najmabadi
Unskip tests
02 ноя 2022, 21:19
02 ноя 2022, 21:19
d65b6d2
Код
Авторство
О чём код?
' 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. Imports System.Runtime.CompilerServices Imports System.Runtime.InteropServices Imports System.Threading Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.Simplification Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Microsoft.CodeAnalysis.VisualBasic.Utilities Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions Friend Module ExpressionSyntaxExtensions Public ReadOnly typeNameFormatWithGenerics As New SymbolDisplayFormat( globalNamespaceStyle:=SymbolDisplayGlobalNamespaceStyle.Included, genericsOptions:=SymbolDisplayGenericsOptions.IncludeTypeParameters, memberOptions:=SymbolDisplayMemberOptions.IncludeContainingType, localOptions:=SymbolDisplayLocalOptions.IncludeType, miscellaneousOptions:=SymbolDisplayMiscellaneousOptions.EscapeKeywordIdentifiers, typeQualificationStyle:=SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces) Public ReadOnly typeNameFormatWithoutGenerics As New SymbolDisplayFormat( globalNamespaceStyle:=SymbolDisplayGlobalNamespaceStyle.Included, genericsOptions:=SymbolDisplayGenericsOptions.None, memberOptions:=SymbolDisplayMemberOptions.IncludeContainingType, localOptions:=SymbolDisplayLocalOptions.IncludeType, miscellaneousOptions:=SymbolDisplayMiscellaneousOptions.EscapeKeywordIdentifiers, typeQualificationStyle:=SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces) <Extension()> Public Function Parenthesize(expression As ExpressionSyntax, Optional addSimplifierAnnotation As Boolean = True) As ParenthesizedExpressionSyntax Dim result = SyntaxFactory.ParenthesizedExpression(expression.WithoutTrivia()) _ .WithTriviaFrom(expression) Return If(addSimplifierAnnotation, result.WithAdditionalAnnotations(Simplifier.Annotation), result) End Function <Extension()> Public Function TryGetNameParts(expression As ExpressionSyntax, ByRef parts As IList(Of String)) As Boolean Dim partsList = New List(Of String) If Not expression.TryGetNameParts(partsList) Then parts = Nothing Return False End If parts = partsList Return True End Function <Extension()> Public Function TryGetNameParts(expression As ExpressionSyntax, parts As List(Of String)) As Boolean If expression.IsKind(SyntaxKind.SimpleMemberAccessExpression) Then Dim memberAccess = DirectCast(expression, MemberAccessExpressionSyntax) If Not memberAccess.Name.TryGetNameParts(parts) Then Return False End If Return AddSimpleName(memberAccess.Name, parts) ElseIf expression.IsKind(SyntaxKind.QualifiedName) Then Dim qualifiedName = DirectCast(expression, QualifiedNameSyntax) If Not qualifiedName.Left.TryGetNameParts(parts) Then Return False End If Return AddSimpleName(qualifiedName.Right, parts) ElseIf TypeOf expression Is SimpleNameSyntax Then Return AddSimpleName(DirectCast(expression, SimpleNameSyntax), parts) Else Return False End If End Function Private Function AddSimpleName(simpleName As SimpleNameSyntax, parts As List(Of String)) As Boolean If Not simpleName.IsKind(SyntaxKind.IdentifierName) Then Return False End If parts.Add(simpleName.Identifier.ValueText) Return True End Function <Extension> Public Function Cast( expression As ExpressionSyntax, targetType As ITypeSymbol, <Out> ByRef isResultPredefinedCast As Boolean) As ExpressionSyntax ' Parenthesize the expression, except for collection initializers and interpolated strings, ' where parenthesizing changes semantics. Dim newExpression = expression If Not expression.IsKind(SyntaxKind.CollectionInitializer, SyntaxKind.InterpolatedStringExpression) Then newExpression = expression.Parenthesize() End If Dim leadingTrivia = newExpression.GetLeadingTrivia() Dim trailingTrivia = newExpression.GetTrailingTrivia() Dim stripped = newExpression.WithoutLeadingTrivia().WithoutTrailingTrivia() Dim castKeyword = targetType.SpecialType.GetPredefinedCastKeyword() If castKeyword = SyntaxKind.None Then isResultPredefinedCast = False Return SyntaxFactory.CTypeExpression( expression:=stripped, type:=targetType.GenerateTypeSyntax()) _ .WithLeadingTrivia(leadingTrivia) _ .WithTrailingTrivia(trailingTrivia) _ .WithAdditionalAnnotations(Simplifier.Annotation) Else isResultPredefinedCast = True Return SyntaxFactory.PredefinedCastExpression( keyword:=SyntaxFactory.Token(castKeyword), expression:=stripped) _ .WithLeadingTrivia(leadingTrivia) _ .WithTrailingTrivia(trailingTrivia) _ .WithAdditionalAnnotations(Simplifier.Annotation) End If End Function <Extension()> Public Function CastIfPossible( expression As ExpressionSyntax, targetType As ITypeSymbol, position As Integer, semanticModel As SemanticModel, <Out> ByRef wasCastAdded As Boolean, cancellationToken As CancellationToken) As ExpressionSyntax wasCastAdded = False If targetType.ContainsAnonymousType() OrElse expression.IsParentKind(SyntaxKind.AsNewClause) Then Return expression End If Dim typeSyntax = targetType.GenerateTypeSyntax() Dim type = semanticModel.GetSpeculativeTypeInfo( position, typeSyntax, SpeculativeBindingOption.BindAsTypeOrNamespace).Type If Not targetType.Equals(type) Then Return expression End If Dim isResultPredefinedCast As Boolean = False Dim castExpression = expression.Cast(targetType, isResultPredefinedCast) ' Ensure that inserting the cast doesn't change the semantics. Dim specAnalyzer = New SpeculationAnalyzer(expression, castExpression, semanticModel, cancellationToken) Dim speculativeSemanticModel = specAnalyzer.SpeculativeSemanticModel If speculativeSemanticModel Is Nothing Then Return expression End If Dim speculatedCastExpression = specAnalyzer.ReplacedExpression Dim speculatedCastInnerExpression = If(isResultPredefinedCast, DirectCast(speculatedCastExpression, PredefinedCastExpressionSyntax).Expression, DirectCast(speculatedCastExpression, CastExpressionSyntax).Expression) If Not CastAnalyzer.IsUnnecessary(speculatedCastExpression, speculatedCastInnerExpression, speculativeSemanticModel, True, cancellationToken) Then Return expression End If wasCastAdded = True Return castExpression End Function <Extension()> Public Function IsObjectCreationWithoutArgumentList(expression As ExpressionSyntax) As Boolean Return _ TypeOf expression Is ObjectCreationExpressionSyntax AndAlso DirectCast(expression, ObjectCreationExpressionSyntax).ArgumentList Is Nothing End Function <Extension()> Public Function IsMeMyBaseOrMyClass(expression As ExpressionSyntax) As Boolean If expression Is Nothing Then Return False End If Return expression.Kind = SyntaxKind.MeExpression OrElse expression.Kind = SyntaxKind.MyBaseExpression OrElse expression.Kind = SyntaxKind.MyClassExpression End Function <Extension()> Public Function IsFirstStatementInCtor(expression As ExpressionSyntax) As Boolean Dim statement = expression.FirstAncestorOrSelf(Of StatementSyntax)() If statement Is Nothing Then Return False End If If Not statement.IsParentKind(SyntaxKind.ConstructorBlock) Then Return False End If Return DirectCast(statement.Parent, ConstructorBlockSyntax).Statements(0) Is statement End Function <Extension()> Public Function IsNamedArgumentIdentifier(expression As ExpressionSyntax) As Boolean Dim simpleArgument = TryCast(expression.Parent, SimpleArgumentSyntax) Return simpleArgument IsNot Nothing AndAlso simpleArgument.NameColonEquals.Name Is expression End Function <Extension> Public Function ContainsImplicitMemberAccess(expression As ExpressionSyntax) As Boolean Return ContainsImplicitMemberAccessWorker(expression) End Function <Extension> Public Function ContainsImplicitMemberAccess(statement As StatementSyntax) As Boolean Return ContainsImplicitMemberAccessWorker(statement) End Function <Extension> Public Function GetImplicitMemberAccessExpressions(expression As SyntaxNode, span As TextSpan) As IEnumerable(Of ExpressionSyntax) ' We don't want to allow a variable to be introduced if the expression contains an ' implicit member access. i.e. ".Blah.ToString()" as that .Blah refers to the containing ' object creation or anonymous type and we can't make a local for it. So we get all the ' descendants and we suppress ourselves. ' Note: if we hit a with block or an anonymous type, then we do not look deeper. Any ' implicit member accesses will refer to that thing and we *can* introduce a variable Dim descendentExpressions = expression.DescendantNodesAndSelf().OfType(Of ExpressionSyntax).Where(Function(e) span.Contains(e.Span)).ToSet() Return descendentExpressions.OfType(Of MemberAccessExpressionSyntax). Select(Function(m) m.GetExpressionOfMemberAccessExpression(allowImplicitTarget:=True)). Where(Function(e) Not descendentExpressions.Contains(e)) End Function <Extension> Public Function GetImplicitMemberAccessExpressions(expression As SyntaxNode) As IEnumerable(Of ExpressionSyntax) Return GetImplicitMemberAccessExpressions(expression, expression.FullSpan) End Function Private Function ContainsImplicitMemberAccessWorker(expression As SyntaxNode) As Boolean Return GetImplicitMemberAccessExpressions(expression).Any() End Function <Extension> Public Function InsideCrefReference(expression As ExpressionSyntax) As Boolean Dim crefAttribute = expression.FirstAncestorOrSelf(Of XmlCrefAttributeSyntax)() Return crefAttribute IsNot Nothing End Function <Extension> Public Function IsDirectChildOfMemberAccessExpression(expression As ExpressionSyntax) As Boolean Return TypeOf expression?.Parent Is MemberAccessExpressionSyntax End Function <Extension> Public Function GetRightmostName(node As ExpressionSyntax) As SimpleNameSyntax Dim memberAccess = TryCast(node, MemberAccessExpressionSyntax) If memberAccess IsNot Nothing AndAlso memberAccess.Name IsNot Nothing Then Return memberAccess.Name End If Dim qualified = TryCast(node, QualifiedNameSyntax) If qualified IsNot Nothing AndAlso qualified.Right IsNot Nothing Then Return qualified.Right End If Return TryCast(node, SimpleNameSyntax) End Function <Extension> Public Function IsNameOfArgumentExpression(expression As ExpressionSyntax) As Boolean Return expression.IsParentKind(SyntaxKind.NameOfExpression) End Function Public Function IsReservedNameInAttribute(originalName As NameSyntax, simplifiedNode As ExpressionSyntax) As Boolean Dim attribute = originalName.GetAncestorOrThis(Of AttributeSyntax)() If attribute Is Nothing Then Return False End If Dim identifier As SimpleNameSyntax If simplifiedNode.Kind = SyntaxKind.IdentifierName Then identifier = DirectCast(simplifiedNode, SimpleNameSyntax) ElseIf simplifiedNode.Kind = SyntaxKind.QualifiedName Then identifier = DirectCast(DirectCast(simplifiedNode, QualifiedNameSyntax).Left, SimpleNameSyntax) Else Return False End If If identifier.Identifier.IsBracketed Then Return False End If If attribute.Target Is Nothing Then Dim identifierValue = SyntaxFacts.MakeHalfWidthIdentifier(identifier.Identifier.ValueText) If CaseInsensitiveComparison.Equals(identifierValue, "Assembly") OrElse CaseInsensitiveComparison.Equals(identifierValue, "Module") Then Return True End If End If Return False End Function End Module End Namespace