|
' 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.Composition
Imports System.Threading
Imports Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.GenerateMember.GenerateParameterizedMember
Imports Microsoft.CodeAnalysis.Host.Mef
Imports Microsoft.CodeAnalysis.LanguageService
Imports Microsoft.CodeAnalysis.VisualBasic.Extensions.ContextQuery
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Namespace Microsoft.CodeAnalysis.VisualBasic.GenerateMember.GenerateMethod
<ExportLanguageService(GetType(IGenerateParameterizedMemberService), LanguageNames.VisualBasic), [Shared]>
Partial Friend NotInheritable Class VisualBasicGenerateMethodService
Inherits AbstractGenerateMethodService(Of VisualBasicGenerateMethodService, SimpleNameSyntax, ExpressionSyntax, InvocationExpressionSyntax)
<ImportingConstructor>
<Obsolete(MefConstruction.ImportingConstructorMessage, True)>
Public Sub New()
End Sub
Protected Overrides Function IsExplicitInterfaceGeneration(node As SyntaxNode) As Boolean
Return TypeOf node Is QualifiedNameSyntax
End Function
Protected Overrides Function IsSimpleNameGeneration(node As SyntaxNode) As Boolean
Return TypeOf node Is SimpleNameSyntax
End Function
Protected Overrides Function AreSpecialOptionsActive(semanticModel As SemanticModel) As Boolean
Return VisualBasicCommonGenerationServiceMethods.AreSpecialOptionsActive(semanticModel)
End Function
Protected Overrides Function IsValidSymbol(symbol As ISymbol, semanticModel As SemanticModel) As Boolean
Return VisualBasicCommonGenerationServiceMethods.IsValidSymbol(symbol, semanticModel)
End Function
Protected Overrides Function TryInitializeExplicitInterfaceState(
document As SemanticDocument,
node As SyntaxNode,
cancellationToken As CancellationToken,
ByRef identifierToken As SyntaxToken,
ByRef methodSymbol As IMethodSymbol,
ByRef typeToGenerateIn As INamedTypeSymbol) As Boolean
Dim qualifiedName = DirectCast(node, QualifiedNameSyntax)
identifierToken = qualifiedName.Right.Identifier
If qualifiedName.IsParentKind(SyntaxKind.ImplementsClause) Then
Dim implementsClause = DirectCast(qualifiedName.Parent, ImplementsClauseSyntax)
If implementsClause.IsParentKind(SyntaxKind.SubStatement) OrElse
implementsClause.IsParentKind(SyntaxKind.FunctionStatement) Then
Dim methodStatement = DirectCast(implementsClause.Parent, MethodStatementSyntax)
Dim semanticModel = document.SemanticModel
methodSymbol = DirectCast(semanticModel.GetDeclaredSymbol(methodStatement, cancellationToken), IMethodSymbol)
If methodSymbol IsNot Nothing AndAlso Not methodSymbol.ExplicitInterfaceImplementations.Any() Then
Dim semanticInfo = semanticModel.GetTypeInfo(qualifiedName.Left, cancellationToken)
typeToGenerateIn = TryCast(semanticInfo.Type, INamedTypeSymbol)
Return typeToGenerateIn IsNot Nothing
End If
End If
End If
identifierToken = Nothing
methodSymbol = Nothing
typeToGenerateIn = Nothing
Return False
End Function
Protected Overrides Function TryInitializeSimpleNameState(
document As SemanticDocument,
simpleName As SimpleNameSyntax,
cancellationToken As CancellationToken,
ByRef identifierToken As SyntaxToken,
ByRef simpleNameOrMemberAccessExpression As ExpressionSyntax,
ByRef invocationExpressionOpt As InvocationExpressionSyntax,
ByRef isInConditionalAccessExpression As Boolean) As Boolean
identifierToken = simpleName.Identifier
Dim memberAccess = TryCast(simpleName?.Parent, MemberAccessExpressionSyntax)
Dim conditionalMemberAccessInvocationExpression = TryCast(simpleName?.Parent?.Parent?.Parent, ConditionalAccessExpressionSyntax)
Dim conditionalMemberAccessSimpleMemberAccess = TryCast(simpleName?.Parent?.Parent, ConditionalAccessExpressionSyntax)
If memberAccess?.Name Is simpleName AndAlso memberAccess.Expression IsNot Nothing Then
simpleNameOrMemberAccessExpression = memberAccess
ElseIf TryCast(TryCast(conditionalMemberAccessInvocationExpression?.WhenNotNull, InvocationExpressionSyntax)?.Expression, MemberAccessExpressionSyntax)?.Name Is simpleName Then
simpleNameOrMemberAccessExpression = conditionalMemberAccessInvocationExpression
ElseIf TryCast(conditionalMemberAccessSimpleMemberAccess?.WhenNotNull, MemberAccessExpressionSyntax)?.Name Is simpleName Then
simpleNameOrMemberAccessExpression = conditionalMemberAccessSimpleMemberAccess
Else
simpleNameOrMemberAccessExpression = simpleName
End If
If memberAccess Is Nothing OrElse memberAccess.Name Is simpleName Then
' VB is ambiguous. Something that looks like a method call might
' actually just be an array access. Check for that here.
Dim semanticModel = document.SemanticModel
Dim nameSemanticInfo = semanticModel.GetTypeInfo(simpleNameOrMemberAccessExpression, cancellationToken)
If TypeOf nameSemanticInfo.Type IsNot IArrayTypeSymbol Then
' Don't offer generate method if it's a call to another constructor inside a
' constructor.
If Not memberAccess.IsConstructorInitializer() Then
If cancellationToken.IsCancellationRequested Then
isInConditionalAccessExpression = False
Return False
End If
isInConditionalAccessExpression = conditionalMemberAccessInvocationExpression IsNot Nothing Or conditionalMemberAccessSimpleMemberAccess IsNot Nothing
If simpleNameOrMemberAccessExpression.IsParentKind(SyntaxKind.InvocationExpression) Then
invocationExpressionOpt = DirectCast(simpleNameOrMemberAccessExpression.Parent, InvocationExpressionSyntax)
Return invocationExpressionOpt.ArgumentList Is Nothing OrElse
Not invocationExpressionOpt.ArgumentList.CloseParenToken.IsMissing
ElseIf TryCast(TryCast(TryCast(simpleNameOrMemberAccessExpression, ConditionalAccessExpressionSyntax)?.WhenNotNull, InvocationExpressionSyntax)?.Expression, MemberAccessExpressionSyntax)?.Name Is simpleName Then
invocationExpressionOpt = DirectCast(DirectCast(simpleNameOrMemberAccessExpression, ConditionalAccessExpressionSyntax).WhenNotNull, InvocationExpressionSyntax)
Return invocationExpressionOpt.ArgumentList Is Nothing OrElse
Not invocationExpressionOpt.ArgumentList.CloseParenToken.IsMissing
ElseIf TryCast(conditionalMemberAccessSimpleMemberAccess?.WhenNotNull, MemberAccessExpressionSyntax)?.Name Is simpleName AndAlso
IsLegal(semanticModel, simpleNameOrMemberAccessExpression, cancellationToken) Then
Return True
ElseIf simpleNameOrMemberAccessExpression?.Parent?.IsKind(SyntaxKind.AddressOfExpression, SyntaxKind.NameOfExpression) Then
Return True
ElseIf IsLegal(semanticModel, simpleNameOrMemberAccessExpression, cancellationToken) Then
simpleNameOrMemberAccessExpression =
If(memberAccess IsNot Nothing AndAlso memberAccess.Name Is simpleName,
DirectCast(memberAccess, ExpressionSyntax),
simpleName)
Return True
End If
End If
End If
End If
identifierToken = Nothing
simpleNameOrMemberAccessExpression = Nothing
invocationExpressionOpt = Nothing
isInConditionalAccessExpression = False
Return False
End Function
Private Shared Function IsLegal(semanticModel As SemanticModel, expression As ExpressionSyntax, cancellationToken As CancellationToken) As Boolean
Dim tree = semanticModel.SyntaxTree
Dim position = expression.SpanStart
If Not tree.IsExpressionContext(position, cancellationToken) AndAlso
Not tree.IsSingleLineStatementContext(position, cancellationToken) Then
Return False
End If
Return expression.CanReplaceWithLValue(semanticModel, cancellationToken)
End Function
Protected Overrides Function CreateInvocationMethodInfo(document As SemanticDocument, state As AbstractGenerateParameterizedMemberService(Of VisualBasicGenerateMethodService, SimpleNameSyntax, ExpressionSyntax, InvocationExpressionSyntax).State) As AbstractInvocationInfo
Return New VisualBasicGenerateParameterizedMemberService(Of VisualBasicGenerateMethodService).InvocationExpressionInfo(document, state)
End Function
Protected Overrides Function DetermineReturnTypeForSimpleNameOrMemberAccessExpression(typeInferenceService As ITypeInferenceService, semanticModel As SemanticModel, expression As ExpressionSyntax, cancellationToken As CancellationToken) As ITypeSymbol
Return typeInferenceService.InferType(semanticModel, expression, True, cancellationToken)
End Function
End Class
End Namespace
|