/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/EditorFeatures/VisualBasic/NavigationBar/VisualBasicEditorNavigationBarItemService_CodeGeneration.vb
280 строк
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.Collections.Immutable Imports System.Threading Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.CodeGeneration Imports Microsoft.CodeAnalysis.Editing Imports Microsoft.CodeAnalysis.Editor.Shared.Utilities Imports Microsoft.CodeAnalysis.Editor.VisualBasic.Utilities Imports Microsoft.CodeAnalysis.Formatting Imports Microsoft.CodeAnalysis.Formatting.Rules Imports Microsoft.CodeAnalysis.NavigationBar Imports Microsoft.CodeAnalysis.NavigationBar.RoslynNavigationBarItem Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Simplification Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Microsoft.VisualStudio.Text.Editor Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.NavigationBar Partial Friend Class VisualBasicEditorNavigationBarItemService Private Async Function GenerateCodeForItemAsync(document As Document, generateCodeItem As AbstractGenerateCodeItem, textView As ITextView, cancellationToken As CancellationToken) As Task ' We'll compute everything up front before we go mutate state Dim text = Await document.GetValueTextAsync(cancellationToken).ConfigureAwait(False) Dim newDocument = Await GetGeneratedDocumentAsync(document, generateCodeItem, cancellationToken).ConfigureAwait(False) Dim generatedTree = Await newDocument.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False) Dim generatedNode = generatedTree.GetAnnotatedNodes(GeneratedSymbolAnnotation).Single().FirstAncestorOrSelf(Of MethodBlockBaseSyntax) Dim formattingOptions = Await document.GetLineFormattingOptionsAsync(cancellationToken).ConfigureAwait(False) Dim indentSize = formattingOptions.IndentationSize Dim generatedText = Await newDocument.GetValueTextAsync(cancellationToken).ConfigureAwait(False) Dim navigationPoint = NavigationPointHelpers.GetNavigationPoint(generatedText, indentSize, generatedNode) ' switch back to ui thread to actually perform the application and navigation Await ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken) Using transaction = New CaretPreservingEditTransaction(VBEditorResources.Generate_Member, textView, _textUndoHistoryRegistry, _editorOperationsFactoryService) Dim solution = newDocument.Project.Solution Await solution.Workspace.ApplyDocumentChangesAsync( ThreadingContext, newDocument, cancellationToken).ConfigureAwait(True) Await NavigateToPositionAsync( solution.Workspace, solution.GetRequiredDocument(navigationPoint.Tree).Id, navigationPoint.Position, navigationPoint.VirtualSpaces, cancellationToken).ConfigureAwait(True) transaction.Complete() End Using End Function Public Shared Async Function GetGeneratedDocumentAsync(document As Document, generateCodeItem As RoslynNavigationBarItem, cancellationToken As CancellationToken) As Task(Of Document) Dim syntaxTree = Await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(False) Dim contextLocation = syntaxTree.GetLocation(New TextSpan(0, 0)) Dim codeGenerationContext = New CodeGenerationContext(contextLocation, generateMethodBodies:=True) Dim newDocument = Await GetGeneratedDocumentCoreAsync(document, generateCodeItem, codeGenerationContext, cancellationToken).ConfigureAwait(False) If newDocument Is Nothing Then Return document End If Dim simplifierOptions = Await newDocument.GetSimplifierOptionsAsync(cancellationToken).ConfigureAwait(False) Dim formattingOptions = Await newDocument.GetSyntaxFormattingOptionsAsync(cancellationToken).ConfigureAwait(False) newDocument = Await Simplifier.ReduceAsync(newDocument, Simplifier.Annotation, simplifierOptions, cancellationToken).ConfigureAwait(False) Dim formatterRules = Formatter.GetDefaultFormattingRules(newDocument) If ShouldApplyLineAdjustmentFormattingRule(generateCodeItem) Then formatterRules = ImmutableArray.Create(Of AbstractFormattingRule)(LineAdjustmentFormattingRule.Instance).AddRange(formatterRules) End If Return Await Formatter.FormatAsync( newDocument, Formatter.Annotation, options:=formattingOptions, cancellationToken:=cancellationToken, rules:=formatterRules).ConfigureAwait(False) End Function Private Shared Function ShouldApplyLineAdjustmentFormattingRule(generateCodeItem As RoslynNavigationBarItem) As Boolean Return generateCodeItem.Kind <> RoslynNavigationBarItemKind.GenerateFinalizer End Function Private Shared Function GetGeneratedDocumentCoreAsync( document As Document, generateCodeItem As RoslynNavigationBarItem, codeGenerationContext As CodeGenerationContext, cancellationToken As CancellationToken) As Task(Of Document) Select Case generateCodeItem.Kind Case RoslynNavigationBarItemKind.GenerateDefaultConstructor Return GenerateDefaultConstructorAsync(document, DirectCast(generateCodeItem, GenerateDefaultConstructor), codeGenerationContext, cancellationToken) Case RoslynNavigationBarItemKind.GenerateEventHandler Return GenerateEventHandlerAsync(document, DirectCast(generateCodeItem, GenerateEventHandler), codeGenerationContext, cancellationToken) Case RoslynNavigationBarItemKind.GenerateFinalizer Return GenerateFinalizerAsync(document, DirectCast(generateCodeItem, GenerateFinalizer), codeGenerationContext, cancellationToken) Case RoslynNavigationBarItemKind.GenerateMethod Return GenerateMethodAsync(document, DirectCast(generateCodeItem, GenerateMethod), codeGenerationContext, cancellationToken) Case Else Throw ExceptionUtilities.UnexpectedValue(generateCodeItem.Kind) End Select End Function Private Shared Async Function GenerateDefaultConstructorAsync( document As Document, generateCodeItem As GenerateDefaultConstructor, codeGenerationContext As CodeGenerationContext, cancellationToken As CancellationToken) As Task(Of Document) Dim compilation = Await document.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(False) Dim destinationType = TryCast(generateCodeItem.DestinationTypeSymbolKey.Resolve(compilation, cancellationToken:=cancellationToken).Symbol, INamedTypeSymbol) If destinationType Is Nothing Then Return Nothing End If Dim statements As New ArrayBuilder(Of SyntaxNode) If destinationType.IsDesignerGeneratedTypeWithInitializeComponent(compilation) Then Dim statement = SyntaxFactory.ExpressionStatement(SyntaxFactory.InvocationExpression(SyntaxFactory.IdentifierName("InitializeComponent"), SyntaxFactory.ArgumentList())) Dim endOfLineTrivia = SyntaxFactory.EndOfLineTrivia(vbCrLf) ' When sticking on the comments, we don't want the ' in the localized string ' lest we try localizing the comment character itself statement = statement.WithLeadingTrivia(endOfLineTrivia, SyntaxFactory.CommentTrivia("' " & VBEditorResources.This_call_is_required_by_the_designer), endOfLineTrivia) statement = statement.WithTrailingTrivia(endOfLineTrivia, endOfLineTrivia, SyntaxFactory.CommentTrivia("' " & VBEditorResources.Add_any_initialization_after_the_InitializeComponent_call), endOfLineTrivia, endOfLineTrivia) statements.Add(statement) End If Dim methodSymbol = CodeGenerationSymbolFactory.CreateConstructorSymbol( attributes:=Nothing, accessibility:=Accessibility.Public, modifiers:=New DeclarationModifiers(), typeName:=destinationType.Name, parameters:=ImmutableArray(Of IParameterSymbol).Empty, statements:=statements.ToImmutableAndFree()) methodSymbol = GeneratedSymbolAnnotation.AddAnnotationToSymbol(methodSymbol) Return Await CodeGenerator.AddMethodDeclarationAsync( New CodeGenerationSolutionContext( document.Project.Solution, codeGenerationContext), destinationType, methodSymbol, cancellationToken).ConfigureAwait(False) End Function Private Shared Async Function GenerateEventHandlerAsync( document As Document, generateCodeItem As GenerateEventHandler, codeGenerationContext As CodeGenerationContext, cancellationToken As CancellationToken) As Task(Of Document) Dim compilation = Await document.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(False) Dim eventSymbol = TryCast(generateCodeItem.EventSymbolKey.Resolve(compilation, cancellationToken:=cancellationToken).GetAnySymbol(), IEventSymbol) Dim destinationType = TryCast(generateCodeItem.DestinationTypeSymbolKey.Resolve(compilation, cancellationToken:=cancellationToken).GetAnySymbol(), INamedTypeSymbol) If eventSymbol Is Nothing OrElse destinationType Is Nothing Then Return Nothing End If Dim delegateInvokeMethod = DirectCast(eventSymbol.Type, INamedTypeSymbol).DelegateInvokeMethod If delegateInvokeMethod Is Nothing Then Return Nothing End If Dim containerSyntax As ExpressionSyntax Dim methodName As String If generateCodeItem.ContainerName IsNot Nothing Then containerSyntax = SyntaxFactory.IdentifierName(generateCodeItem.ContainerName) methodName = generateCodeItem.ContainerName + "_" + eventSymbol.Name Else containerSyntax = SyntaxFactory.KeywordEventContainer(SyntaxFactory.Token(SyntaxKind.MeKeyword)) methodName = destinationType.Name + "_" + eventSymbol.Name End If Dim handlesSyntax = SyntaxFactory.SimpleMemberAccessExpression(containerSyntax, SyntaxFactory.Token(SyntaxKind.DotToken), eventSymbol.Name.ToIdentifierName()) Dim methodSymbol = CodeGenerationSymbolFactory.CreateMethodSymbol( attributes:=Nothing, accessibility:=Accessibility.Private, modifiers:=New DeclarationModifiers(), returnType:=delegateInvokeMethod.ReturnType, refKind:=delegateInvokeMethod.RefKind, explicitInterfaceImplementations:=Nothing, name:=methodName, typeParameters:=Nothing, parameters:=delegateInvokeMethod.RemoveInaccessibleAttributesAndAttributesOfTypes(destinationType).Parameters, handlesExpressions:=ImmutableArray.Create(Of SyntaxNode)(handlesSyntax)) methodSymbol = GeneratedSymbolAnnotation.AddAnnotationToSymbol(methodSymbol) Return Await CodeGenerator.AddMethodDeclarationAsync( New CodeGenerationSolutionContext( document.Project.Solution, codeGenerationContext), destinationType, methodSymbol, cancellationToken).ConfigureAwait(False) End Function Private Shared Async Function GenerateFinalizerAsync( document As Document, generateCodeItem As GenerateFinalizer, codeGenerationContext As CodeGenerationContext, cancellationToken As CancellationToken) As Task(Of Document) Dim compilation = Await document.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(False) Dim destinationType = TryCast(generateCodeItem.DestinationTypeSymbolKey.Resolve(compilation, cancellationToken:=cancellationToken).Symbol, INamedTypeSymbol) If destinationType Is Nothing Then Return Nothing End If Dim syntaxFactory = document.GetLanguageService(Of SyntaxGenerator)() Dim finalizeCall = syntaxFactory.ExpressionStatement( syntaxFactory.InvocationExpression( syntaxFactory.MemberAccessExpression( syntaxFactory.BaseExpression(), syntaxFactory.IdentifierName(WellKnownMemberNames.DestructorName)))) Dim finalizerMethodSymbol = CodeGenerationSymbolFactory.CreateMethodSymbol( attributes:=Nothing, accessibility:=Accessibility.Protected, modifiers:=New DeclarationModifiers(isOverride:=True), returnType:=compilation.GetSpecialType(SpecialType.System_Void), refKind:=RefKind.None, explicitInterfaceImplementations:=Nothing, name:=WellKnownMemberNames.DestructorName, typeParameters:=Nothing, parameters:=ImmutableArray(Of IParameterSymbol).Empty, statements:=ImmutableArray.Create(finalizeCall)) finalizerMethodSymbol = GeneratedSymbolAnnotation.AddAnnotationToSymbol(finalizerMethodSymbol) Return Await CodeGenerator.AddMethodDeclarationAsync( New CodeGenerationSolutionContext( document.Project.Solution, codeGenerationContext), destinationType, finalizerMethodSymbol, cancellationToken).ConfigureAwait(False) End Function Private Shared Async Function GenerateMethodAsync( document As Document, generateCodeItem As GenerateMethod, codeGenerationContext As CodeGenerationContext, cancellationToken As CancellationToken) As Task(Of Document) Dim compilation = Await document.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(False) Dim destinationType = TryCast(generateCodeItem.DestinationTypeSymbolKey.Resolve(compilation, cancellationToken:=cancellationToken).Symbol, INamedTypeSymbol) Dim methodToReplicate = TryCast(generateCodeItem.MethodToReplicateSymbolKey.Resolve(compilation, cancellationToken:=cancellationToken).Symbol, IMethodSymbol) If destinationType Is Nothing OrElse methodToReplicate Is Nothing Then Return Nothing End If Dim codeGenerationSymbol = GeneratedSymbolAnnotation.AddAnnotationToSymbol( CodeGenerationSymbolFactory.CreateMethodSymbol( methodToReplicate.RemoveInaccessibleAttributesAndAttributesOfTypes(destinationType))) Return Await CodeGenerator.AddMethodDeclarationAsync( New CodeGenerationSolutionContext( document.Project.Solution, codeGenerationContext), destinationType, codeGenerationSymbol, cancellationToken).ConfigureAwait(False) End Function End Class End Namespace