Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,21 @@
using System.Composition;
using System.Diagnostics.CodeAnalysis;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Editor.Implementation.EndConstructGeneration;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.Editor.CSharp.EndConstructGeneration;

[ExportLanguageService(typeof(IEndConstructGenerationService), LanguageNames.CSharp), Shared]
[ExcludeFromCodeCoverage]
internal class CSharpEndConstructGenerationService : IEndConstructGenerationService
[method: ImportingConstructor]
[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
internal sealed class CSharpEndConstructGenerationService() : IEndConstructGenerationService
{
[ImportingConstructor]
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
public CSharpEndConstructGenerationService()
{
}

public bool TryDo(
ITextView textView,
ITextBuffer subjectBuffer,
char typedChar,
CancellationToken cancellationToken)
{
return false;
}
public Task<bool> TryDoAsync(ITextView textView, ITextBuffer subjectBuffer, char typedChar, CancellationToken cancellationToken)
=> SpecializedTasks.False;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

#nullable disable

using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Host;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
Expand All @@ -13,5 +12,5 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.EndConstructGeneration;

internal interface IEndConstructGenerationService : ILanguageService
{
bool TryDo(ITextView textView, ITextBuffer subjectBuffer, char typedChar, CancellationToken cancellationToken);
Task<bool> TryDoAsync(ITextView textView, ITextBuffer subjectBuffer, char typedChar, CancellationToken cancellationToken);
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,21 +66,25 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.EndConstructGeneration
End Function

Public Sub ExecuteCommand_TypeCharCommandHandler(args As TypeCharCommandArgs, nextHandler As Action, context As CommandExecutionContext) Implements IChainedCommandHandler(Of TypeCharCommandArgs).ExecuteCommand
nextHandler()
_threadingContext.JoinableTaskFactory.Run(
Async Function()
nextHandler()

If Not _editorOptionsService.GlobalOptions.GetOption(EndConstructGenerationOptionsStorage.EndConstruct, LanguageNames.VisualBasic) Then
Return
End If
If Not _editorOptionsService.GlobalOptions.GetOption(EndConstructGenerationOptionsStorage.EndConstruct, LanguageNames.VisualBasic) Then
Return
End If

Dim textSnapshot = args.SubjectBuffer.CurrentSnapshot
Dim document = textSnapshot.GetOpenDocumentInCurrentContextWithChanges()
If document Is Nothing Then
Return
End If
Dim textSnapshot = args.SubjectBuffer.CurrentSnapshot
Dim document = textSnapshot.GetOpenDocumentInCurrentContextWithChanges()
If document Is Nothing Then
Return
End If

' End construct is not cancellable.
Dim endConstructService = document.GetLanguageService(Of IEndConstructGenerationService)()
endConstructService.TryDo(args.TextView, args.SubjectBuffer, args.TypedChar, context.OperationContext.UserCancellationToken)
' End construct is not cancellable.
Dim endConstructService = document.GetLanguageService(Of IEndConstructGenerationService)()
Await endConstructService.TryDoAsync(
args.TextView, args.SubjectBuffer, args.TypedChar, context.OperationContext.UserCancellationToken).ConfigureAwait(True)
End Function)
End Sub

Public Function GetCommandState_AutomaticLineEnderCommandHandler(args As AutomaticLineEnderCommandArgs, nextHandler As Func(Of CommandState)) As CommandState Implements IChainedCommandHandler(Of AutomaticLineEnderCommandArgs).GetCommandState
Expand Down Expand Up @@ -123,7 +127,8 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.EndConstructGeneration
textView, subjectBuffer, document, cancellationToken).ConfigureAwait(True)

Dim endConstructService = document.GetLanguageService(Of IEndConstructGenerationService)()
Dim result = endConstructService.TryDo(textView, subjectBuffer, vbLf(0), cancellationToken)
Dim result = Await endConstructService.TryDoAsync(
textView, subjectBuffer, vbLf(0), cancellationToken).ConfigureAwait(True)

If Not result Then
nextHandler()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,17 @@
' 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

Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.EndConstructGeneration
Friend Class EndConstructState
Friend NotInheritable Class EndConstructState
Private ReadOnly _caretPosition As Integer
Private ReadOnly _semanticModel As Lazy(Of SemanticModel)
Private ReadOnly _semanticModel As AsyncLazy(Of SemanticModel)
Private ReadOnly _tree As SyntaxTree
Private ReadOnly _tokenToLeft As SyntaxToken
Private ReadOnly _newLineCharacter As String

Public Sub New(caretPosition As Integer, semanticModel As Lazy(Of SemanticModel), syntaxTree As SyntaxTree, tokenToLeft As SyntaxToken, newLineCharacter As String)
Public Sub New(caretPosition As Integer, semanticModel As AsyncLazy(Of SemanticModel), syntaxTree As SyntaxTree, tokenToLeft As SyntaxToken, newLineCharacter As String)
ThrowIfNull(syntaxTree)

_caretPosition = caretPosition
Expand All @@ -26,11 +28,9 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.EndConstructGeneration
End Get
End Property

Public ReadOnly Property SemanticModel As SemanticModel
Get
Return _semanticModel.Value
End Get
End Property
Public Function GetSemanticModelAsync(cancellationToken As CancellationToken) As Task(Of SemanticModel)
Return _semanticModel.GetValueAsync(cancellationToken)
End Function

Public ReadOnly Property SyntaxTree As SyntaxTree
Get
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,51 @@ Imports Microsoft.VisualStudio.Text.Editor
Imports Microsoft.VisualStudio.Text.Editor.OptionsExtensionMethods

Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.EndConstructGeneration
Partial Friend Class EndConstructStatementVisitor
Partial Friend NotInheritable Class EndConstructStatementVisitor
Inherits VisualBasicSyntaxVisitor(Of AbstractEndConstructResult)

Private ReadOnly _textView As ITextView
Private ReadOnly _subjectBuffer As ITextBuffer
Private ReadOnly _cancellationToken As CancellationToken
Private ReadOnly _state As EndConstructState
Private ReadOnly _cancellationToken As CancellationToken

''' <summary>
''' Note: this is only passed in when <see cref="NeedsSemanticModel"/> return true. Any functions that require
''' a semantic model must declare their need up front so we do not pay the cost for semantics for all the cases
''' that do not need it.
''' </summary>
Private ReadOnly _semanticModel As SemanticModel

Public Sub New(textView As ITextView,
subjectBuffer As ITextBuffer,
state As EndConstructState,
cancellationToken As CancellationToken)
Public Sub New(
textView As ITextView,
subjectBuffer As ITextBuffer,
state As EndConstructState,
semanticModel As SemanticModel,
cancellationToken As CancellationToken)

_textView = textView
_subjectBuffer = subjectBuffer
_state = state
_semanticModel = semanticModel
_cancellationToken = cancellationToken
End Sub

Public Shared Function NeedsSemanticModel(node As SyntaxNode) As Boolean
' All of these call HandleMethodBlockSyntax, which needs semantics
If TypeOf node Is MethodStatementSyntax OrElse
TypeOf node Is SubNewStatementSyntax OrElse
TypeOf node Is OperatorStatementSyntax Then
Return True
End If

' Calls GenerateAddOrRemoveHandler and GenerateRaiseEventHandler, both which needs semantics
If TypeOf node Is EventStatementSyntax Then
Return True
End If

Return False
End Function

Public Overrides Function VisitDoStatement(node As DoStatementSyntax) As AbstractEndConstructResult
Dim needsEnd = node.GetAncestorsOrThis(Of DoLoopBlockSyntax)().Any(Function(block) block.LoopStatement.IsMissing)

Expand Down Expand Up @@ -100,11 +126,12 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.EndConstructGeneration
End If
End Function

Private Function TryGenerateResultForConstructorSpitWithInitializeComponent(methodBlock As MethodBlockBaseSyntax) As AbstractEndConstructResult
Private Function TryGenerateResultForConstructorSpitWithInitializeComponent(
methodBlock As MethodBlockBaseSyntax) As AbstractEndConstructResult
If methodBlock.BlockStatement.Kind = SyntaxKind.SubNewStatement Then
Dim boundConstructor = _state.SemanticModel.GetDeclaredSymbol(DirectCast(methodBlock.BlockStatement, SubNewStatementSyntax))
Dim boundConstructor = _semanticModel.GetDeclaredSymbol(DirectCast(methodBlock.BlockStatement, SubNewStatementSyntax))
If boundConstructor IsNot Nothing Then
If boundConstructor.ContainingType.IsDesignerGeneratedTypeWithInitializeComponent(_state.SemanticModel.Compilation) Then
If boundConstructor.ContainingType.IsDesignerGeneratedTypeWithInitializeComponent(_semanticModel.Compilation) Then
Dim aligningWhitespace = _subjectBuffer.CurrentSnapshot.GetAligningWhitespace(methodBlock.BlockStatement.SpanStart)
Dim innerAligningWhitespace = aligningWhitespace & " "

Expand Down Expand Up @@ -161,10 +188,10 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.EndConstructGeneration
Dim aligningWhitespace = _subjectBuffer.CurrentSnapshot.GetAligningWhitespace(node.SpanStart)
Dim stringBuilder As New StringBuilder
stringBuilder.Append(_textView.Options.GetNewLineCharacter())
StringBuilder.Append(aligningWhitespace & " Case ")
stringBuilder.Append(aligningWhitespace & " Case ")
Dim finalCaretPoint = stringBuilder.Length
stringBuilder.AppendLine()
StringBuilder.Append(aligningWhitespace & "End Select")
stringBuilder.Append(aligningWhitespace & "End Select")

Return New ReplaceSpanResult(New SnapshotSpan(_subjectBuffer.CurrentSnapshot, _state.CaretPosition, 0),
stringBuilder.ToString(), newCaretPosition:=finalCaretPoint)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,21 +37,21 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.EndConstructGeneration
End Function

Private Function GenerateAddOrRemoveHandler(eventStatement As EventStatementSyntax, kind As SyntaxKind) As String()
Dim type = _state.SemanticModel.GetTypeInfo(DirectCast(eventStatement.AsClause, SimpleAsClauseSyntax).Type, Me._cancellationToken)
Dim type = _semanticModel.GetTypeInfo(DirectCast(eventStatement.AsClause, SimpleAsClauseSyntax).Type, Me._cancellationToken)
Dim position As Integer = eventStatement.SpanStart
Dim aligningWhitespace = _subjectBuffer.CurrentSnapshot.GetAligningWhitespace(position) & " "
Return {aligningWhitespace & SyntaxFacts.GetText(kind) & "(value As " & type.Type.ToMinimalDisplayString(_state.SemanticModel, position, SymbolDisplayFormats.NameFormat) & ")",
Return {aligningWhitespace & SyntaxFacts.GetText(kind) & "(value As " & type.Type.ToMinimalDisplayString(_semanticModel, position, SymbolDisplayFormats.NameFormat) & ")",
"",
aligningWhitespace & "End " & SyntaxFacts.GetText(kind)}
End Function

Private Function GenerateRaiseEventHandler(eventStatement As EventStatementSyntax) As String()
Dim type = TryCast(_state.SemanticModel.GetTypeInfo(DirectCast(eventStatement.AsClause, SimpleAsClauseSyntax).Type, Me._cancellationToken).Type, INamedTypeSymbol)
Dim type = TryCast(_semanticModel.GetTypeInfo(DirectCast(eventStatement.AsClause, SimpleAsClauseSyntax).Type, Me._cancellationToken).Type, INamedTypeSymbol)
Dim signature = ""

If type IsNot Nothing AndAlso type.DelegateInvokeMethod IsNot Nothing Then
Dim parameterStrings = type.DelegateInvokeMethod.Parameters.Select(
Function(p) p.ToMinimalDisplayString(_state.SemanticModel, eventStatement.SpanStart))
Function(p) p.ToMinimalDisplayString(_semanticModel, eventStatement.SpanStart))
signature = String.Join(", ", parameterStrings)
End If

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Syntax

Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.EndConstructGeneration
Partial Friend Class EndConstructStatementVisitor

Public Overrides Function VisitIfStatement(node As IfStatementSyntax) As AbstractEndConstructResult
Dim needsEnd = node.GetAncestorsOrThis(Of MultiLineIfBlockSyntax)().Any(Function(block) block.EndIfStatement.IsMissing)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,12 +161,13 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.EndConstructGeneration
Dim bufferOptions = _editorOptionsFactoryService.GetOptions(subjectBuffer)

Return New EndConstructState(
caretPosition.Value, New Lazy(Of SemanticModel)(Function() document.GetSemanticModelAsync(cancellationToken).WaitAndGetResult(cancellationToken)), tree, tokenToLeft, bufferOptions.GetNewLineCharacter())
caretPosition.Value, AsyncLazy.Create(Function(c) document.GetSemanticModelAsync(c)), tree, tokenToLeft, bufferOptions.GetNewLineCharacter())
End Function

Friend Overridable Function TryDoEndConstructForEnterKey(textView As ITextView,
subjectBuffer As ITextBuffer,
cancellationToken As CancellationToken) As Boolean
Friend Overridable Async Function TryDoEndConstructForEnterKeyAsync(
textView As ITextView,
subjectBuffer As ITextBuffer,
cancellationToken As CancellationToken) As Task(Of Boolean)
Using Logger.LogBlock(FunctionId.EndConstruct_DoStatement, cancellationToken)
Using transaction = New CaretPreservingEditTransaction(VBEditorResources.End_Construct, textView, _undoHistoryRegistry, _editorOperationsFactoryService)
transaction.MergePolicy = AutomaticCodeChangeMergePolicy.Instance
Expand Down Expand Up @@ -285,7 +286,10 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.EndConstructGeneration
Return False
End If

Dim visitor = New EndConstructStatementVisitor(textView, subjectBuffer, state, cancellationToken)
Dim semanticModel = If(EndConstructStatementVisitor.NeedsSemanticModel(statement),
Await state.GetSemanticModelAsync(cancellationToken).ConfigureAwait(True),
Nothing)
Dim visitor = New EndConstructStatementVisitor(textView, subjectBuffer, state, semanticModel, cancellationToken)
Dim result = visitor.Visit(statement)

If result Is Nothing Then
Expand Down Expand Up @@ -480,10 +484,10 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.EndConstructGeneration
End Using
End Function

Public Function TryDo(textView As ITextView, subjectBuffer As ITextBuffer, typedChar As Char, cancellationToken As CancellationToken) As Boolean Implements IEndConstructGenerationService.TryDo
Public Async Function TryDoAsync(textView As ITextView, subjectBuffer As ITextBuffer, typedChar As Char, cancellationToken As CancellationToken) As Task(Of Boolean) Implements IEndConstructGenerationService.TryDoAsync
Select Case typedChar
Case vbLf(0)
Return Me.TryDoEndConstructForEnterKey(textView, subjectBuffer, cancellationToken)
Return Await Me.TryDoEndConstructForEnterKeyAsync(textView, subjectBuffer, cancellationToken).ConfigureAwait(True)
Case ">"c
Return Me.TryDoXmlElementEndConstruct(textView, subjectBuffer, cancellationToken)
Case "-"c
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.Utilities.CommandHandlers

' It's possible that there may be an end construct to generate at this position.
' We'll go ahead and generate it before determining whether we need to move the caret
TryGenerateEndConstruct(args, _cancellationToken)
Await TryGenerateEndConstructAsync(args, _cancellationToken).ConfigureAwait(True)

Dim snapshot = args.SubjectBuffer.CurrentSnapshot
Dim caretPosition = args.TextView.GetCaretPoint(args.SubjectBuffer).Value
Expand All @@ -92,7 +92,9 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.Utilities.CommandHandlers
Return True
End Function

Private Shared Function TryGenerateEndConstruct(args As ReturnKeyCommandArgs, cancellationToken As CancellationToken) As Boolean
Private Shared Async Function TryGenerateEndConstructAsync(
args As ReturnKeyCommandArgs,
cancellationToken As CancellationToken) As Task(Of Boolean)
Dim textSnapshot = args.SubjectBuffer.CurrentSnapshot

Dim document = textSnapshot.GetOpenDocumentInCurrentContextWithChanges()
Expand All @@ -112,7 +114,8 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.Utilities.CommandHandlers

Dim endConstructGenerationService = document.GetLanguageService(Of IEndConstructGenerationService)()

Return endConstructGenerationService.TryDo(args.TextView, args.SubjectBuffer, vbLf(0), cancellationToken)
Return Await endConstructGenerationService.TryDoAsync(
args.TextView, args.SubjectBuffer, vbLf(0), cancellationToken).ConfigureAwait(True)
End Function

Private Overloads Async Function TryExecuteAsync(
Expand Down
Loading
Loading