/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Workspaces/VisualBasic/Portable/Classification/ClassificationHelpers.vb
333 строки
16 KB
Cyrus Najmabadi
Organize VB imports
27 июн 2025, 21:53
27 июн 2025, 21:53
e9c47fd
Код
Авторство
О чём код?
' 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.Threading Imports Microsoft.CodeAnalysis.Classification Imports Microsoft.CodeAnalysis.Collections Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Microsoft.CodeAnalysis.VisualBasic.Utilities Namespace Microsoft.CodeAnalysis.VisualBasic.Classification Friend Module ClassificationHelpers ''' <summary> ''' Return the classification type associated with this token. ''' </summary> ''' <param name="token">The token to be classified.</param> ''' <returns>The classification type for the token</returns> ''' <remarks></remarks> Public Function GetClassification(token As SyntaxToken) As String If IsControlKeyword(token) Then Return ClassificationTypeNames.ControlKeyword ElseIf SyntaxFacts.IsKeywordKind(token.Kind) Then Return ClassificationTypeNames.Keyword ElseIf IsStringToken(token) Then Return ClassificationTypeNames.StringLiteral ElseIf SyntaxFacts.IsPunctuation(token.Kind) Then Return ClassifyPunctuation(token) ElseIf token.Kind = SyntaxKind.IdentifierToken Then Return GetSyntacticClassificationForIdentifier(token) ElseIf token.IsNumericLiteral() Then Return ClassificationTypeNames.NumericLiteral ElseIf token.Kind = SyntaxKind.XmlNameToken Then Return ClassificationTypeNames.XmlLiteralName ElseIf token.Kind = SyntaxKind.XmlTextLiteralToken Then Select Case token.Parent.Kind Case SyntaxKind.XmlString Return ClassificationTypeNames.XmlLiteralAttributeValue Case SyntaxKind.XmlProcessingInstruction Return ClassificationTypeNames.XmlLiteralProcessingInstruction Case SyntaxKind.XmlComment Return ClassificationTypeNames.XmlLiteralComment Case SyntaxKind.XmlCDataSection Return ClassificationTypeNames.XmlLiteralCDataSection Case Else Return ClassificationTypeNames.XmlLiteralText End Select ElseIf token.Kind = SyntaxKind.XmlEntityLiteralToken Then Return ClassificationTypeNames.XmlLiteralEntityReference ElseIf token.IsKind(SyntaxKind.None, SyntaxKind.BadToken) Then Return Nothing Else Throw ExceptionUtilities.UnexpectedValue(token.Kind()) End If End Function Private Function IsControlKeyword(token As SyntaxToken) As Boolean If token.Parent Is Nothing Then Return False End If ' For Exit Statments classify everything as a control keyword If token.Parent.IsKind( SyntaxKind.ExitFunctionStatement, SyntaxKind.ExitOperatorStatement, SyntaxKind.ExitPropertyStatement, SyntaxKind.ExitSubStatement) Then Return True End If ' Control keywords are used in other contexts so check that it is ' being used in a supported context. Return IsControlKeywordKind(token.Kind) AndAlso IsControlStatementKind(token.Parent.Kind) End Function ''' <summary> ''' Determine if the kind represents a control keyword ''' </summary> Public Function IsControlKeywordKind(kind As SyntaxKind) As Boolean Select Case kind Case _ SyntaxKind.CaseKeyword, SyntaxKind.CatchKeyword, SyntaxKind.ContinueKeyword, SyntaxKind.DoKeyword, SyntaxKind.EachKeyword, SyntaxKind.ElseKeyword, SyntaxKind.ElseIfKeyword, SyntaxKind.EndKeyword, SyntaxKind.ExitKeyword, SyntaxKind.FinallyKeyword, SyntaxKind.ForKeyword, SyntaxKind.GoToKeyword, SyntaxKind.IfKeyword, SyntaxKind.InKeyword, SyntaxKind.LoopKeyword, SyntaxKind.NextKeyword, SyntaxKind.ResumeKeyword, SyntaxKind.ReturnKeyword, SyntaxKind.SelectKeyword, SyntaxKind.ThenKeyword, SyntaxKind.TryKeyword, SyntaxKind.WhileKeyword, SyntaxKind.WendKeyword, SyntaxKind.UntilKeyword, SyntaxKind.EndIfKeyword, SyntaxKind.GosubKeyword, SyntaxKind.YieldKeyword, SyntaxKind.ThrowKeyword, SyntaxKind.ToKeyword Return True Case Else Return False End Select End Function ''' <summary> ''' Determine if the kind represents a control statement ''' </summary> Public Function IsControlStatementKind(kind As SyntaxKind) As Boolean Select Case kind Case _ SyntaxKind.CallStatement, SyntaxKind.CaseElseStatement, SyntaxKind.CaseStatement, SyntaxKind.CatchStatement, SyntaxKind.ContinueDoStatement, SyntaxKind.ContinueForStatement, SyntaxKind.ContinueWhileStatement, SyntaxKind.DoUntilStatement, SyntaxKind.DoWhileStatement, SyntaxKind.ElseIfStatement, SyntaxKind.ElseStatement, SyntaxKind.EndIfStatement, SyntaxKind.EndSelectStatement, SyntaxKind.EndTryStatement, SyntaxKind.EndWhileStatement, SyntaxKind.ExitDoStatement, SyntaxKind.ExitForStatement, SyntaxKind.ExitSelectStatement, SyntaxKind.ExitTryStatement, SyntaxKind.ExitWhileStatement, SyntaxKind.FinallyStatement, SyntaxKind.ForEachStatement, SyntaxKind.ForStatement, SyntaxKind.GoToStatement, SyntaxKind.IfStatement, SyntaxKind.LoopUntilStatement, SyntaxKind.LoopWhileStatement, SyntaxKind.NextStatement, SyntaxKind.ResumeLabelStatement, SyntaxKind.ResumeNextStatement, SyntaxKind.ReturnStatement, SyntaxKind.SelectStatement, SyntaxKind.SimpleDoStatement, SyntaxKind.SimpleLoopStatement, SyntaxKind.SingleLineIfStatement, SyntaxKind.ThrowStatement, SyntaxKind.TryStatement, SyntaxKind.UntilClause, SyntaxKind.WhileClause, SyntaxKind.WhileStatement, SyntaxKind.YieldStatement, SyntaxKind.TernaryConditionalExpression Return True Case Else Return False End Select End Function Private Function ClassifyPunctuation(token As SyntaxToken) As String If AllOperators.Contains(token.Kind) Then ' special cases... Select Case token.Kind Case SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken If TypeOf token.Parent Is AttributeListSyntax Then Return ClassificationTypeNames.Punctuation End If End Select Return ClassificationTypeNames.Operator Else Return ClassificationTypeNames.Punctuation End If End Function Public Function GetSyntacticClassificationForIdentifier(identifier As SyntaxToken) As String 'Note: parent might be Nothing, if we are classifying raw tokens. Dim parent = identifier.Parent Dim classification As String = Nothing If TypeOf parent Is IdentifierNameSyntax AndAlso IsNamespaceName(DirectCast(parent, IdentifierNameSyntax)) Then Return ClassificationTypeNames.NamespaceName ElseIf TypeOf parent Is TypeStatementSyntax AndAlso DirectCast(parent, TypeStatementSyntax).Identifier = identifier Then Return ClassifyTypeDeclarationIdentifier(identifier) ElseIf TypeOf parent Is EnumStatementSyntax AndAlso DirectCast(parent, EnumStatementSyntax).Identifier = identifier Then Return ClassificationTypeNames.EnumName ElseIf TypeOf parent Is DelegateStatementSyntax AndAlso DirectCast(parent, DelegateStatementSyntax).Identifier = identifier AndAlso (parent.Kind = SyntaxKind.DelegateSubStatement OrElse parent.Kind = SyntaxKind.DelegateFunctionStatement) Then Return ClassificationTypeNames.DelegateName ElseIf TypeOf parent Is TypeParameterSyntax AndAlso DirectCast(parent, TypeParameterSyntax).Identifier = identifier Then Return ClassificationTypeNames.TypeParameterName ElseIf TypeOf parent Is MethodStatementSyntax AndAlso DirectCast(parent, MethodStatementSyntax).Identifier = identifier Then Return ClassificationTypeNames.MethodName ElseIf TypeOf parent Is DeclareStatementSyntax AndAlso DirectCast(parent, DeclareStatementSyntax).Identifier = identifier Then Return ClassificationTypeNames.MethodName ElseIf TypeOf parent Is PropertyStatementSyntax AndAlso DirectCast(parent, PropertyStatementSyntax).Identifier = identifier Then Return ClassificationTypeNames.PropertyName ElseIf TypeOf parent Is EventStatementSyntax AndAlso DirectCast(parent, EventStatementSyntax).Identifier = identifier Then Return ClassificationTypeNames.EventName ElseIf TypeOf parent Is EnumMemberDeclarationSyntax AndAlso DirectCast(parent, EnumMemberDeclarationSyntax).Identifier = identifier Then Return ClassificationTypeNames.EnumMemberName ElseIf TypeOf parent Is LabelStatementSyntax AndAlso DirectCast(parent, LabelStatementSyntax).LabelToken = identifier Then Return ClassificationTypeNames.LabelName ElseIf TypeOf parent?.Parent Is CatchStatementSyntax AndAlso DirectCast(parent.Parent, CatchStatementSyntax).IdentifierName.Identifier = identifier Then Return ClassificationTypeNames.LocalName ElseIf TryClassifyModifiedIdentifer(parent, identifier, classification) Then Return classification ElseIf (identifier.ToString() = "IsTrue" OrElse identifier.ToString() = "IsFalse") AndAlso TypeOf parent Is OperatorStatementSyntax AndAlso DirectCast(parent, OperatorStatementSyntax).OperatorToken = identifier Then Return ClassificationTypeNames.Keyword End If Return ClassificationTypeNames.Identifier End Function Private Function IsNamespaceName(identifierSyntax As IdentifierNameSyntax) As Boolean Dim parent = identifierSyntax.Parent While TypeOf parent Is QualifiedNameSyntax parent = parent.Parent End While Return TypeOf parent Is NamespaceStatementSyntax End Function Public Function IsStaticallyDeclared(identifier As SyntaxToken) As Boolean 'Note: parent might be Nothing, if we are classifying raw tokens. Dim parent = identifier.Parent If parent.IsKind(SyntaxKind.EnumMemberDeclaration) Then ' EnumMembers are not classified as static since there is no ' instance equivalent of the concept and they have their own ' classification type. Return False ElseIf parent.IsKind(SyntaxKind.ModifiedIdentifier) Then parent = parent.Parent?.Parent ' We are specifically looking for field declarations or constants. If Not parent.IsKind(SyntaxKind.FieldDeclaration) Then Return False End If If parent.GetModifiers().Any(SyntaxKind.ConstKeyword) Then Return True End If End If Return parent.GetModifiers().Any(SyntaxKind.SharedKeyword) End Function Private Function IsStringToken(token As SyntaxToken) As Boolean If token.IsKind(SyntaxKind.StringLiteralToken, SyntaxKind.CharacterLiteralToken, SyntaxKind.InterpolatedStringTextToken) Then Return True End If Return token.IsKind(SyntaxKind.DollarSignDoubleQuoteToken, SyntaxKind.DoubleQuoteToken) AndAlso token.Parent.IsKind(SyntaxKind.InterpolatedStringExpression) End Function Private Function TryClassifyModifiedIdentifer(node As SyntaxNode, identifier As SyntaxToken, ByRef classification As String) As Boolean classification = Nothing If TypeOf node IsNot ModifiedIdentifierSyntax OrElse DirectCast(node, ModifiedIdentifierSyntax).Identifier <> identifier Then Return False End If If TypeOf node.Parent Is ParameterSyntax Then classification = ClassificationTypeNames.ParameterName Return True End If If TypeOf node.Parent IsNot VariableDeclaratorSyntax Then Return False End If If TypeOf node.Parent.Parent Is LocalDeclarationStatementSyntax Then Dim localDeclaration = DirectCast(node.Parent.Parent, LocalDeclarationStatementSyntax) classification = If(localDeclaration.Modifiers.Any(SyntaxKind.ConstKeyword), ClassificationTypeNames.ConstantName, ClassificationTypeNames.LocalName) Return True End If If TypeOf node.Parent.Parent Is FieldDeclarationSyntax Then Dim localDeclaration = DirectCast(node.Parent.Parent, FieldDeclarationSyntax) classification = If(localDeclaration.Modifiers.Any(SyntaxKind.ConstKeyword), ClassificationTypeNames.ConstantName, ClassificationTypeNames.FieldName) Return True End If Return False End Function Private Function ClassifyTypeDeclarationIdentifier(identifier As SyntaxToken) As String Select Case identifier.Parent.Kind Case SyntaxKind.ClassStatement Return ClassificationTypeNames.ClassName Case SyntaxKind.ModuleStatement Return ClassificationTypeNames.ModuleName Case SyntaxKind.InterfaceStatement Return ClassificationTypeNames.InterfaceName Case SyntaxKind.StructureStatement Return ClassificationTypeNames.StructName Case Else Throw ExceptionUtilities.UnexpectedValue(identifier.Parent.Kind) End Select End Function Friend Sub AddLexicalClassifications(text As SourceText, textSpan As TextSpan, result As SegmentedList(Of ClassifiedSpan), cancellationToken As CancellationToken) Dim text2 = text.ToString(textSpan) Dim tokens = SyntaxFactory.ParseTokens(text2, initialTokenPosition:=textSpan.Start) Worker.CollectClassifiedSpans(tokens, textSpan, result, cancellationToken) End Sub #Disable Warning IDE0060 ' Remove unused parameter - TODO: Do we need to do the same work here that we do in C#? Friend Function AdjustStaleClassification(text As SourceText, classifiedSpan As ClassifiedSpan) As ClassifiedSpan #Enable Warning IDE0060 ' Remove unused parameter Return classifiedSpan End Function End Module End Namespace