/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Workspaces/VisualBasic/Portable/Classification/SyntaxClassification/NameSyntaxClassifier.vb
295 строк
14 KB
Cyrus Najmabadi
Remove
17 май 2024, 10:18
17 май 2024, 10:18
6a613c7
Код
Авторство
О чём код?
' 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.Collections.Immutable Imports System.Threading Imports Microsoft.CodeAnalysis.Classification Imports Microsoft.CodeAnalysis.Classification.Classifiers Imports Microsoft.CodeAnalysis.Collections Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Extensions.ContextQuery Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.Classification.Classifiers Friend Class NameSyntaxClassifier Inherits AbstractNameSyntaxClassifier Public Overrides ReadOnly Property SyntaxNodeTypes As ImmutableArray(Of Type) = ImmutableArray.Create( GetType(CrefOperatorReferenceSyntax), GetType(GenericNameSyntax), GetType(GlobalNameSyntax), GetType(IdentifierNameSyntax), GetType(LabelSyntax), GetType(MethodStatementSyntax), GetType(ModifiedIdentifierSyntax), GetType(QualifiedCrefOperatorReferenceSyntax), GetType(QualifiedNameSyntax), GetType(SimpleNameSyntax)) Public Overrides Sub AddClassifications( syntax As SyntaxNode, textSpan As TextSpan, semanticModel As SemanticModel, options As ClassificationOptions, result As SegmentedList(Of ClassifiedSpan), cancellationToken As CancellationToken) Dim nameSyntax = TryCast(syntax, NameSyntax) If nameSyntax IsNot Nothing Then ClassifyNameSyntax(nameSyntax, semanticModel, result, cancellationToken) Return End If Dim modifiedIdentifier = TryCast(syntax, ModifiedIdentifierSyntax) If modifiedIdentifier IsNot Nothing Then ClassifyModifiedIdentifier(modifiedIdentifier, result) Return End If Dim methodStatement = TryCast(syntax, MethodStatementSyntax) If methodStatement IsNot Nothing Then ClassifyMethodStatement(methodStatement, semanticModel, result) Return End If Dim labelSyntax = TryCast(syntax, LabelSyntax) If labelSyntax IsNot Nothing Then ClassifyLabelSyntax(labelSyntax, result) Return End If End Sub Protected Overrides Function IsParentAnAttribute(node As SyntaxNode) As Boolean Return node.IsParentKind(SyntaxKind.Attribute) End Function Private Sub ClassifyNameSyntax( node As NameSyntax, semanticModel As SemanticModel, result As SegmentedList(Of ClassifiedSpan), cancellationToken As CancellationToken) Dim classifiedSpan As ClassifiedSpan Dim symbolInfo = semanticModel.GetSymbolInfo(node, cancellationToken) Dim symbol = TryGetSymbol(node, symbolInfo) If symbol Is Nothing Then If TryClassifyIdentifier(node, semanticModel, cancellationToken, classifiedSpan) Then result.Add(classifiedSpan) End If Return End If If TryClassifyMyNamespace(node, symbol, semanticModel, classifiedSpan) Then result.Add(classifiedSpan) ElseIf TryClassifySymbol(node, symbol, classifiedSpan) Then result.Add(classifiedSpan) ' Additionally classify static symbols TryClassifyStaticSymbol(symbol, classifiedSpan.TextSpan, result) End If End Sub Private Shared Function TryClassifySymbol( node As NameSyntax, symbol As ISymbol, ByRef classifiedSpan As ClassifiedSpan) As Boolean Select Case symbol.Kind Case SymbolKind.Namespace ' Do not classify the Global namespace. It is already syntactically classified as a keyword. ' Also, we ignore QualifiedNameSyntax nodes since we want to classify individual name parts. If Not node.IsKind(SyntaxKind.GlobalName) AndAlso TypeOf node Is IdentifierNameSyntax Then classifiedSpan = New ClassifiedSpan(GetNameToken(node).Span, ClassificationTypeNames.NamespaceName) Return True End If Case SymbolKind.Method Dim classification = GetClassificationForMethod(node, DirectCast(symbol, IMethodSymbol)) If classification IsNot Nothing Then classifiedSpan = New ClassifiedSpan(GetNameToken(node).Span, classification) Return True End If Case SymbolKind.Event classifiedSpan = New ClassifiedSpan(GetNameToken(node).Span, ClassificationTypeNames.EventName) Return True Case SymbolKind.Property classifiedSpan = New ClassifiedSpan(GetNameToken(node).Span, ClassificationTypeNames.PropertyName) Return True Case SymbolKind.Field Dim classification = GetClassificationForField(DirectCast(symbol, IFieldSymbol)) If classification IsNot Nothing Then classifiedSpan = New ClassifiedSpan(GetNameToken(node).Span, classification) Return True End If Case SymbolKind.Parameter classifiedSpan = New ClassifiedSpan(GetNameToken(node).Span, ClassificationTypeNames.ParameterName) Return True Case SymbolKind.Local Dim classification = GetClassificationForLocal(DirectCast(symbol, ILocalSymbol)) If classification IsNot Nothing Then classifiedSpan = New ClassifiedSpan(GetNameToken(node).Span, classification) Return True End If End Select Dim type = TryCast(symbol, ITypeSymbol) If type IsNot Nothing Then Dim classification = GetClassificationForType(type) If classification IsNot Nothing Then Dim token = GetNameToken(node) classifiedSpan = New ClassifiedSpan(token.Span, classification) Return True End If End If Return False End Function Private Shared Function TryClassifyMyNamespace( node As NameSyntax, symbol As ISymbol, semanticModel As SemanticModel, ByRef classifiedSpan As ClassifiedSpan) As Boolean If symbol.IsMyNamespace(semanticModel.Compilation) Then classifiedSpan = New ClassifiedSpan(GetNameToken(node).Span, ClassificationTypeNames.Keyword) Return True End If Return False End Function Private Shared Function TryClassifyIdentifier( node As NameSyntax, semanticModel As SemanticModel, cancellationToken As CancellationToken, ByRef classifiedSpan As ClassifiedSpan) As Boolean ' Okay, it doesn't bind to anything. Dim identifierName = TryCast(node, IdentifierNameSyntax) If identifierName IsNot Nothing Then Dim token = identifierName.Identifier If token.HasMatchingText(SyntaxKind.FromKeyword) AndAlso semanticModel.SyntaxTree.IsExpressionContext(token.SpanStart, cancellationToken, semanticModel) Then ' Optimistically classify "From" as a keyword in expression contexts classifiedSpan = New ClassifiedSpan(token.Span, ClassificationTypeNames.Keyword) Return True ElseIf token.HasMatchingText(SyntaxKind.AsyncKeyword) OrElse token.HasMatchingText(SyntaxKind.IteratorKeyword) Then ' Optimistically classify "Async" or "Iterator" as a keyword in expression contexts If semanticModel.SyntaxTree.IsExpressionContext(token.SpanStart, cancellationToken, semanticModel) Then classifiedSpan = New ClassifiedSpan(token.Span, ClassificationTypeNames.Keyword) Return True End If End If End If Return False End Function Private Shared Function GetClassificationForField(fieldSymbol As IFieldSymbol) As String If fieldSymbol.IsConst Then Return If(fieldSymbol.ContainingType.IsEnumType(), ClassificationTypeNames.EnumMemberName, ClassificationTypeNames.ConstantName) End If Return ClassificationTypeNames.FieldName End Function Private Shared Function GetClassificationForLocal(localSymbol As ILocalSymbol) As String Return If(localSymbol.IsConst, ClassificationTypeNames.ConstantName, ClassificationTypeNames.LocalName) End Function Private Shared Function GetClassificationForMethod(node As NameSyntax, methodSymbol As IMethodSymbol) As String Select Case methodSymbol.MethodKind Case MethodKind.Constructor ' If node is member access or qualified name with explicit New on the right side, we should classify New as a keyword. If node.IsNewOnRightSideOfDotOrBang() Then Return ClassificationTypeNames.Keyword Else ' We bound to a constructor, but we weren't something like the 'New' in 'X.New'. ' This can happen when we're actually just binding the full node 'X.New'. In this ' case, don't return anything for this full node. We'll end up hitting the ' 'New' node as the worker walks down, and we'll classify it then. Return Nothing End If Case MethodKind.BuiltinOperator, MethodKind.UserDefinedOperator ' Operators are already classified syntactically. Return Nothing End Select Return If(methodSymbol.IsReducedExtension(), ClassificationTypeNames.ExtensionMethodName, ClassificationTypeNames.MethodName) End Function Private Shared Sub ClassifyModifiedIdentifier( modifiedIdentifier As ModifiedIdentifierSyntax, result As SegmentedList(Of ClassifiedSpan)) If modifiedIdentifier.ArrayBounds IsNot Nothing OrElse modifiedIdentifier.ArrayRankSpecifiers.Count > 0 OrElse modifiedIdentifier.Nullable.Kind <> SyntaxKind.None Then Return End If If modifiedIdentifier.IsParentKind(SyntaxKind.VariableDeclarator) AndAlso modifiedIdentifier.Parent.IsParentKind(SyntaxKind.FieldDeclaration) Then If DirectCast(modifiedIdentifier.Parent, VariableDeclaratorSyntax).AsClause Is Nothing AndAlso DirectCast(modifiedIdentifier.Parent, VariableDeclaratorSyntax).Initializer Is Nothing Then Dim token = modifiedIdentifier.Identifier If token.HasMatchingText(SyntaxKind.AsyncKeyword) OrElse token.HasMatchingText(SyntaxKind.IteratorKeyword) Then ' Optimistically classify "Async" or "Iterator" as a keyword result.Add(New ClassifiedSpan(token.Span, ClassificationTypeNames.Keyword)) Return End If End If End If End Sub Private Shared Function GetNameToken(node As NameSyntax) As SyntaxToken Select Case node.Kind Case SyntaxKind.IdentifierName Return DirectCast(node, IdentifierNameSyntax).Identifier Case SyntaxKind.GenericName Return DirectCast(node, GenericNameSyntax).Identifier Case SyntaxKind.QualifiedName Return DirectCast(node, QualifiedNameSyntax).Right.Identifier Case Else Throw New NotSupportedException() End Select End Function Private Shared Sub ClassifyMethodStatement(methodStatement As MethodStatementSyntax, semanticModel As SemanticModel, result As SegmentedList(Of ClassifiedSpan)) ' Ensure that extension method declarations are classified properly. ' Note that the method statement name is likely already classified as a method name ' by the syntactic classifier. However, there isn't away to determine whether a VB ' method declaration is an extension method syntactically. Dim methodSymbol = semanticModel.GetDeclaredSymbol(methodStatement) If methodSymbol IsNot Nothing AndAlso methodSymbol.IsExtensionMethod Then result.Add(New ClassifiedSpan(methodStatement.Identifier.Span, ClassificationTypeNames.ExtensionMethodName)) End If End Sub Private Shared Sub ClassifyLabelSyntax( node As LabelSyntax, result As SegmentedList(Of ClassifiedSpan)) result.Add(New ClassifiedSpan(node.LabelToken.Span, ClassificationTypeNames.LabelName)) End Sub End Class End Namespace