|
' 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.Threading
Imports Microsoft.CodeAnalysis.CodeGeneration
Imports Microsoft.CodeAnalysis.CodeGeneration.CodeGenerationHelpers
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration
Friend Module NamedTypeGenerator
Public Function AddNamedTypeTo(service As ICodeGenerationService,
destination As TypeBlockSyntax,
namedType As INamedTypeSymbol,
options As CodeGenerationContextInfo,
availableIndices As IList(Of Boolean),
cancellationToken As CancellationToken) As TypeBlockSyntax
Dim declaration = GenerateNamedTypeDeclaration(service, namedType, options, cancellationToken)
Dim members = Insert(destination.Members, declaration, options, availableIndices)
Return FixTerminators(destination.WithMembers(members))
End Function
Public Function AddNamedTypeTo(service As ICodeGenerationService,
destination As NamespaceBlockSyntax,
namedType As INamedTypeSymbol,
options As CodeGenerationContextInfo,
availableIndices As IList(Of Boolean),
cancellationToken As CancellationToken) As NamespaceBlockSyntax
Dim declaration = GenerateNamedTypeDeclaration(service, namedType, options, cancellationToken)
Dim members = Insert(destination.Members, declaration, options, availableIndices)
Return destination.WithMembers(members)
End Function
Public Function AddNamedTypeTo(service As ICodeGenerationService,
destination As CompilationUnitSyntax,
namedType As INamedTypeSymbol,
options As CodeGenerationContextInfo,
availableIndices As IList(Of Boolean),
cancellationToken As CancellationToken) As CompilationUnitSyntax
Dim declaration = GenerateNamedTypeDeclaration(service, namedType, options, cancellationToken)
Dim members = Insert(destination.Members, declaration, options, availableIndices)
Return destination.WithMembers(members)
End Function
Public Function GenerateNamedTypeDeclaration(service As ICodeGenerationService,
namedType As INamedTypeSymbol,
options As CodeGenerationContextInfo,
cancellationToken As CancellationToken) As StatementSyntax
Dim declaration = GetDeclarationSyntaxWithoutMembers(namedType, options)
declaration = If(options.Context.GenerateMembers AndAlso namedType.TypeKind <> TypeKind.Delegate,
service.AddMembers(declaration, GetMembers(namedType), options, cancellationToken),
declaration)
Return AddFormatterAndCodeGeneratorAnnotationsTo(ConditionallyAddDocumentationCommentTo(declaration, namedType, options, cancellationToken))
End Function
Public Function UpdateNamedTypeDeclaration(service As ICodeGenerationService,
declaration As StatementSyntax,
newMembers As IList(Of ISymbol),
options As CodeGenerationContextInfo,
cancellationToken As CancellationToken) As StatementSyntax
declaration = RemoveAllMembers(declaration)
declaration = service.AddMembers(declaration, newMembers, options, cancellationToken)
Return AddFormatterAndCodeGeneratorAnnotationsTo(declaration)
End Function
Private Function GetDeclarationSyntaxWithoutMembers(namedType As INamedTypeSymbol, options As CodeGenerationContextInfo) As StatementSyntax
Dim reusableDeclarationSyntax = GetReuseableSyntaxNodeForSymbol(Of StatementSyntax)(namedType, options)
If reusableDeclarationSyntax Is Nothing Then
Return GenerateNamedTypeDeclarationWorker(namedType, options)
End If
Return RemoveAllMembers(reusableDeclarationSyntax)
End Function
Private Function RemoveAllMembers(declaration As StatementSyntax) As StatementSyntax
Select Case declaration.Kind
Case SyntaxKind.EnumBlock
Return DirectCast(declaration, EnumBlockSyntax).WithMembers(Nothing)
Case SyntaxKind.StructureBlock, SyntaxKind.InterfaceBlock, SyntaxKind.ClassBlock
Return DirectCast(declaration, TypeBlockSyntax).WithMembers(Nothing)
Case Else
Return declaration
End Select
End Function
Private Function GenerateNamedTypeDeclarationWorker(namedType As INamedTypeSymbol, options As CodeGenerationContextInfo) As StatementSyntax
' TODO(cyrusn): Support enums/delegates.
If namedType.TypeKind = TypeKind.Enum Then
Return GenerateEnumDeclaration(namedType, options)
ElseIf namedType.TypeKind = TypeKind.Delegate Then
Return GenerateDelegateDeclaration(namedType, options)
End If
Dim isInterface = namedType.TypeKind = TypeKind.Interface
Dim isStruct = namedType.TypeKind = TypeKind.Struct
Dim isModule = namedType.TypeKind = TypeKind.Module
Dim blockKind =
If(isInterface, SyntaxKind.InterfaceBlock, If(isStruct, SyntaxKind.StructureBlock, If(isModule, SyntaxKind.ModuleBlock, SyntaxKind.ClassBlock)))
Dim statementKind =
If(isInterface, SyntaxKind.InterfaceStatement, If(isStruct, SyntaxKind.StructureStatement, If(isModule, SyntaxKind.ModuleStatement, SyntaxKind.ClassStatement)))
Dim keywordKind =
If(isInterface, SyntaxKind.InterfaceKeyword, If(isStruct, SyntaxKind.StructureKeyword, If(isModule, SyntaxKind.ModuleKeyword, SyntaxKind.ClassKeyword)))
Dim endStatement =
If(isInterface, SyntaxFactory.EndInterfaceStatement(), If(isStruct, SyntaxFactory.EndStructureStatement(), If(isModule, SyntaxFactory.EndModuleStatement, SyntaxFactory.EndClassStatement)))
Dim typeDeclaration =
SyntaxFactory.TypeBlock(
blockKind,
SyntaxFactory.TypeStatement(
statementKind,
attributes:=GenerateAttributes(namedType, options),
modifiers:=GenerateModifiers(namedType),
keyword:=SyntaxFactory.Token(keywordKind),
identifier:=namedType.Name.ToIdentifierToken(),
typeParameterList:=GenerateTypeParameterList(namedType)),
[inherits]:=GenerateInheritsStatements(namedType),
implements:=GenerateImplementsStatements(namedType),
end:=endStatement)
Return typeDeclaration
End Function
Private Function GenerateDelegateDeclaration(namedType As INamedTypeSymbol, options As CodeGenerationContextInfo) As StatementSyntax
Dim invokeMethod = namedType.DelegateInvokeMethod
Return SyntaxFactory.DelegateStatement(
kind:=If(invokeMethod.ReturnsVoid, SyntaxKind.DelegateSubStatement, SyntaxKind.DelegateFunctionStatement),
attributeLists:=GenerateAttributes(namedType, options),
modifiers:=GenerateModifiers(namedType),
subOrFunctionKeyword:=If(invokeMethod.ReturnsVoid, SyntaxFactory.Token(SyntaxKind.SubKeyword), SyntaxFactory.Token(SyntaxKind.FunctionKeyword)),
identifier:=namedType.Name.ToIdentifierToken(),
typeParameterList:=GenerateTypeParameterList(namedType),
parameterList:=ParameterGenerator.GenerateParameterList(invokeMethod.Parameters, options),
asClause:=If(invokeMethod.ReturnsVoid, Nothing,
SyntaxFactory.SimpleAsClause(invokeMethod.ReturnType.GenerateTypeSyntax())))
End Function
Private Function GenerateEnumDeclaration(namedType As INamedTypeSymbol, options As CodeGenerationContextInfo) As StatementSyntax
Dim underlyingType =
If(namedType.EnumUnderlyingType IsNot Nothing AndAlso namedType.EnumUnderlyingType.SpecialType <> SpecialType.System_Int32,
SyntaxFactory.SimpleAsClause(namedType.EnumUnderlyingType.GenerateTypeSyntax()),
Nothing)
Return SyntaxFactory.EnumBlock(
SyntaxFactory.EnumStatement(
GenerateAttributes(namedType, options),
GenerateModifiers(namedType),
namedType.Name.ToIdentifierToken,
underlyingType))
End Function
Private Function GenerateAttributes(namedType As INamedTypeSymbol, options As CodeGenerationContextInfo) As SyntaxList(Of AttributeListSyntax)
Return AttributeGenerator.GenerateAttributeBlocks(namedType.GetAttributes(), options)
End Function
Private Function GenerateModifiers(namedType As INamedTypeSymbol) As SyntaxTokenList
Dim tokens = New List(Of SyntaxToken)
Select Case namedType.DeclaredAccessibility
Case Accessibility.Public
tokens.Add(SyntaxFactory.Token(SyntaxKind.PublicKeyword))
Case Accessibility.Protected
tokens.Add(SyntaxFactory.Token(SyntaxKind.ProtectedKeyword))
Case Accessibility.Private
tokens.Add(SyntaxFactory.Token(SyntaxKind.PrivateKeyword))
Case Accessibility.Internal
tokens.Add(SyntaxFactory.Token(SyntaxKind.FriendKeyword))
Case Accessibility.ProtectedAndInternal
tokens.Add(SyntaxFactory.Token(SyntaxKind.PrivateKeyword))
tokens.Add(SyntaxFactory.Token(SyntaxKind.ProtectedKeyword))
Case Accessibility.ProtectedOrInternal
tokens.Add(SyntaxFactory.Token(SyntaxKind.ProtectedKeyword))
tokens.Add(SyntaxFactory.Token(SyntaxKind.FriendKeyword))
Case Accessibility.Internal
tokens.Add(SyntaxFactory.Token(SyntaxKind.FriendKeyword))
Case Else
End Select
If namedType.TypeKind = TypeKind.Class Then
If namedType.IsSealed Then
tokens.Add(SyntaxFactory.Token(SyntaxKind.NotInheritableKeyword))
End If
If namedType.IsAbstract Then
tokens.Add(SyntaxFactory.Token(SyntaxKind.MustInheritKeyword))
End If
End If
Return SyntaxFactory.TokenList(tokens)
End Function
Private Function GenerateTypeParameterList(namedType As INamedTypeSymbol) As TypeParameterListSyntax
Return TypeParameterGenerator.GenerateTypeParameterList(namedType.TypeParameters)
End Function
Private Function GenerateInheritsStatements(namedType As INamedTypeSymbol) As SyntaxList(Of InheritsStatementSyntax)
If namedType.TypeKind = TypeKind.Struct OrElse
namedType.BaseType Is Nothing OrElse
namedType.BaseType.SpecialType = SpecialType.System_Object Then
Return Nothing
End If
Return SyntaxFactory.SingletonList(
SyntaxFactory.InheritsStatement(types:=SyntaxFactory.SingletonSeparatedList(namedType.BaseType.GenerateTypeSyntax())))
End Function
Private Function GenerateImplementsStatements(namedType As INamedTypeSymbol) As SyntaxList(Of ImplementsStatementSyntax)
If namedType.Interfaces.Length = 0 Then
Return Nothing
End If
Dim types = namedType.Interfaces.Select(Function(t) t.GenerateTypeSyntax())
Dim typeNodes = SyntaxFactory.SeparatedList(types)
Return SyntaxFactory.SingletonList(SyntaxFactory.ImplementsStatement(types:=typeNodes))
End Function
End Module
End Namespace
|