/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Features/VisualBasic/Portable/Completion/CompletionProviders/CrefCompletionProvider.vb
292 строки
13 KB
Joey Robichaud
Reapply "Move to .NET 10 Preview 5 (#78906)"
08 июл 2025, 07:36
08 июл 2025, 07:36
1e5af11
Код
Авторство
О чём код?
' 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.Composition Imports System.Text Imports System.Threading Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.Collections Imports Microsoft.CodeAnalysis.Completion Imports Microsoft.CodeAnalysis.Completion.Providers Imports Microsoft.CodeAnalysis.ErrorReporting Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Extensions.ContextQuery Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.Providers <ExportCompletionProvider(NameOf(CrefCompletionProvider), LanguageNames.VisualBasic)> <ExtensionOrder(After:=NameOf(PartialTypeCompletionProvider))> <[Shared]> Partial Friend Class CrefCompletionProvider Inherits AbstractCrefCompletionProvider Private Shared ReadOnly s_crefFormat As SymbolDisplayFormat = New SymbolDisplayFormat( globalNamespaceStyle:=SymbolDisplayGlobalNamespaceStyle.Omitted, typeQualificationStyle:=SymbolDisplayTypeQualificationStyle.NameOnly, propertyStyle:=SymbolDisplayPropertyStyle.NameOnly, genericsOptions:=SymbolDisplayGenericsOptions.IncludeTypeParameters, miscellaneousOptions:=SymbolDisplayMiscellaneousOptions.UseSpecialTypes) Private Shared ReadOnly s_minimalParameterTypeFormat As SymbolDisplayFormat = SymbolDisplayFormat.MinimallyQualifiedFormat.AddMiscellaneousOptions(SymbolDisplayMiscellaneousOptions.ExpandValueTuple) Private _testSpeculativeNodeCallbackOpt As Action(Of SyntaxNode) Public Overrides Function IsInsertionTrigger(text As SourceText, characterPosition As Integer, options As CompletionOptions) As Boolean Return CompletionUtilities.IsDefaultTriggerCharacter(text, characterPosition, options) End Function Friend Overrides ReadOnly Property Language As String Get Return LanguageNames.VisualBasic End Get End Property Public Overrides ReadOnly Property TriggerCharacters As ImmutableHashSet(Of Char) = CompletionUtilities.CommonTriggerChars <ImportingConstructor> <Obsolete(MefConstruction.ImportingConstructorMessage, True)> Public Sub New() End Sub Public Overrides Async Function ProvideCompletionsAsync(context As CompletionContext) As Task Try Dim document = context.Document Dim position = context.Position Dim cancellationToken = context.CancellationToken Dim tree = Await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(False) Dim token = tree.GetTargetToken(position, cancellationToken) If IsCrefTypeParameterContext(token) Then Return End If ' To get a Speculative SemanticModel (which is much faster), we need to ' walk up to the node the DocumentationTrivia is attached to. Dim parentNode = token.Parent?.FirstAncestorOrSelf(Of DocumentationCommentTriviaSyntax)()?.ParentTrivia.Token.Parent _testSpeculativeNodeCallbackOpt?.Invoke(parentNode) If parentNode Is Nothing Then Return End If Dim semanticModel = Await document.ReuseExistingSpeculativeModelAsync(parentNode, cancellationToken).ConfigureAwait(False) Dim symbols = GetSymbols(token, semanticModel, cancellationToken) If Not symbols.Any() Then Return End If Dim text = Await document.GetValueTextAsync(cancellationToken).ConfigureAwait(False) Dim items = CreateCompletionItems(semanticModel, symbols, position) context.AddItems(items) If IsFirstCrefParameterContext(token) Then ' Include Of in case they're typing a type parameter context.AddItem(CreateOfCompletionItem()) End If context.IsExclusive = True Catch e As Exception When FatalError.ReportAndCatchUnlessCanceled(e) ' nop End Try End Function Protected Overrides Async Function GetSymbolsAsync(document As Document, position As Integer, options As CompletionOptions, cancellationToken As CancellationToken) As Task(Of (SyntaxToken, SemanticModel, ImmutableArray(Of ISymbol))) Dim tree = Await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(False) Dim token = tree.GetTargetToken(position, cancellationToken) If IsCrefTypeParameterContext(token) Then Return Nothing End If ' To get a Speculative SemanticModel (which is much faster), we need to ' walk up to the node the DocumentationTrivia is attached to. Dim parentNode = token.Parent?.FirstAncestorOrSelf(Of DocumentationCommentTriviaSyntax)()?.ParentTrivia.Token.Parent _testSpeculativeNodeCallbackOpt?.Invoke(parentNode) If parentNode Is Nothing Then Return Nothing End If Dim semanticModel = Await document.ReuseExistingSpeculativeModelAsync(parentNode, cancellationToken).ConfigureAwait(False) Dim symbols = GetSymbols(token, semanticModel, cancellationToken) Return (token, semanticModel, symbols.ToImmutableArray()) End Function Private Shared Function IsCrefTypeParameterContext(token As SyntaxToken) As Boolean Return (token.IsChildToken(Function(t As TypeArgumentListSyntax) t.OfKeyword) OrElse token.IsChildSeparatorToken(Function(t As TypeArgumentListSyntax) t.Arguments)) AndAlso token.Parent?.FirstAncestorOrSelf(Of XmlCrefAttributeSyntax)() IsNot Nothing End Function Private Shared Function IsCrefStartContext(token As SyntaxToken) As Boolean ' cases: ' <see cref="x| ' <see cref='x| If token.IsChildToken(Function(x As XmlCrefAttributeSyntax) x.StartQuoteToken) Then Return True End If ' cases: ' <see cref="| ' <see cref='| If token.Parent.IsKind(SyntaxKind.XmlString) AndAlso token.Parent.IsParentKind(SyntaxKind.XmlAttribute) Then Dim xmlAttribute = DirectCast(token.Parent.Parent, XmlAttributeSyntax) Dim xmlName = TryCast(xmlAttribute.Name, XmlNameSyntax) Dim xmlValue = TryCast(xmlAttribute.Value, XmlStringSyntax) If xmlName?.LocalName.ValueText = "cref" AndAlso xmlValue?.StartQuoteToken = token Then Return True End If End If Return False End Function Private Shared Function IsCrefParameterListContext(token As SyntaxToken) As Boolean ' cases: ' <see cref="M(| ' <see cref="M(x, | Return IsFirstCrefParameterContext(token) OrElse token.IsChildSeparatorToken(Function(x As CrefSignatureSyntax) x.ArgumentTypes) End Function Private Shared Function IsFirstCrefParameterContext(ByRef token As SyntaxToken) As Boolean Return token.IsChildToken(Function(x As CrefSignatureSyntax) x.OpenParenToken) End Function Private Overloads Shared Function GetSymbols(token As SyntaxToken, semanticModel As SemanticModel, cancellationToken As CancellationToken) As IEnumerable(Of ISymbol) If IsCrefStartContext(token) Then Return semanticModel.LookupSymbols(token.SpanStart) ElseIf IsCrefParameterListContext(token) Then Return semanticModel.LookupNamespacesAndTypes(token.SpanStart) ElseIf token.IsChildToken(Function(x As QualifiedNameSyntax) x.DotToken) Then Return GetQualifiedSymbols(DirectCast(token.Parent, QualifiedNameSyntax), token, semanticModel, cancellationToken) End If Return SpecializedCollections.EmptyEnumerable(Of ISymbol) End Function Private Shared Iterator Function GetQualifiedSymbols(qualifiedName As QualifiedNameSyntax, token As SyntaxToken, semanticModel As SemanticModel, cancellationToken As CancellationToken) As IEnumerable(Of ISymbol) Dim leftSymbol = semanticModel.GetSymbolInfo(qualifiedName.Left, cancellationToken).Symbol Dim leftType = semanticModel.GetTypeInfo(qualifiedName.Left, cancellationToken).Type Dim container = TryCast(If(leftSymbol, leftType), INamespaceOrTypeSymbol) For Each symbol In semanticModel.LookupSymbols(token.SpanStart, container) Yield symbol Next Dim namedTypeContainer = TryCast(container, INamedTypeSymbol) If namedTypeContainer IsNot Nothing Then For Each constructor In namedTypeContainer.Constructors If Not constructor.IsStatic Then Yield constructor End If Next End If End Function Private Shared Iterator Function CreateCompletionItems( semanticModel As SemanticModel, symbols As IEnumerable(Of ISymbol), position As Integer) As IEnumerable(Of CompletionItem) Dim builder = SharedPools.Default(Of StringBuilder).Allocate() Try For Each symbol In symbols builder.Clear() Yield CreateCompletionItem(semanticModel, symbol, position, builder) Next Finally SharedPools.Default(Of StringBuilder).ClearAndFree(builder) End Try End Function Private Shared Function CreateCompletionItem( semanticModel As SemanticModel, symbol As ISymbol, position As Integer, builder As StringBuilder) As CompletionItem If symbol.IsUserDefinedOperator() Then builder.Append("Operator ") End If builder.Append(symbol.ToDisplayString(s_crefFormat)) Dim parameters = symbol.GetParameters() If Not parameters.IsDefaultOrEmpty Then builder.Append("("c) For i = 0 To parameters.Length - 1 If i > 0 Then builder.Append(", ") End If Dim parameter = parameters(i) If parameter.RefKind = RefKind.Ref Then builder.Append("ByRef ") End If builder.Append(parameter.Type.ToMinimalDisplayString(semanticModel, position, s_minimalParameterTypeFormat)) Next builder.Append(")"c) ElseIf symbol.Kind = SymbolKind.Method Then builder.Append("()") End If Dim displayString = builder.ToString() Return SymbolCompletionItem.CreateWithNameAndKind( displayText:=displayString, displayTextSuffix:="", insertionText:=Nothing, symbols:=ImmutableArray.Create(symbol), contextPosition:=position, rules:=GetRules(displayString)) End Function Private Shared Function CreateOfCompletionItem() As CompletionItem Return CommonCompletionItem.Create( "Of", displayTextSuffix:="", CompletionItemRules.Default, Glyph.Keyword, description:=RecommendedKeyword.CreateDisplayParts("Of", VBFeaturesResources.Identifies_a_type_parameter_on_a_generic_class_structure_interface_delegate_or_procedure)) End Function Private Shared ReadOnly s_WithoutOpenParen As CharacterSetModificationRule = CharacterSetModificationRule.Create(CharacterSetModificationKind.Remove, "("c) Private Shared ReadOnly s_defaultRules As CompletionItemRules = CompletionItemRules.Default Private Shared Function GetRules(displayText As String) As CompletionItemRules Dim commitRules = s_defaultRules.CommitCharacterRules If displayText.Contains("(") Then commitRules = commitRules.Add(s_WithoutOpenParen) End If Return s_defaultRules.WithCommitCharacterRules(commitRules) End Function Friend Function GetTestAccessor() As TestAccessor Return New TestAccessor(Me) End Function Friend Structure TestAccessor Private ReadOnly _crefCompletionProvider As CrefCompletionProvider Public Sub New(crefCompletionProvider As CrefCompletionProvider) _crefCompletionProvider = crefCompletionProvider End Sub Public Sub SetSpeculativeNodeCallback(value As Action(Of SyntaxNode)) _crefCompletionProvider._testSpeculativeNodeCallbackOpt = value End Sub End Structure End Class End Namespace