public static (ClassDeclarationSyntax, GeneratedProxyDescription) Generate( LibraryTypes libraryTypes, InvokableInterfaceDescription interfaceDescription, MetadataModel metadataModel) { var generatedClassName = GetSimpleClassName(interfaceDescription); var ctors = GenerateConstructors(generatedClassName, interfaceDescription.ProxyBaseType).ToArray(); var proxyMethods = CreateProxyMethods(libraryTypes, interfaceDescription, metadataModel).ToArray(); var classDeclaration = ClassDeclaration(generatedClassName) .AddBaseListTypes( SimpleBaseType(interfaceDescription.ProxyBaseType.ToTypeSyntax()), SimpleBaseType(interfaceDescription.InterfaceType.ToTypeSyntax())) .AddModifiers(Token(SyntaxKind.InternalKeyword), Token(SyntaxKind.SealedKeyword)) .AddAttributeLists( AttributeList(SingletonSeparatedList(CodeGenerator.GetGeneratedCodeAttributeSyntax()))) .AddMembers(ctors) .AddMembers(proxyMethods); var typeParameters = interfaceDescription.TypeParameters; if (typeParameters.Count > 0) { classDeclaration = SyntaxFactoryUtility.AddGenericTypeParameters(classDeclaration, typeParameters); } return(classDeclaration, new GeneratedProxyDescription(interfaceDescription)); }
private static List <GeneratedFieldDescription> GetFieldDescriptions( InvokableInterfaceDescription interfaceDescription, MetadataModel metadataModel, LibraryTypes libraryTypes) { var fields = new List <GeneratedFieldDescription>(); // Add a codec field for any method parameter which does not have a static codec. var allTypes = interfaceDescription.Methods .Where(method => method.MethodTypeParameters.Count == 0) .SelectMany(method => metadataModel.GeneratedInvokables[method].Members); fields.AddRange(GetCopierFieldDescriptions(allTypes, libraryTypes)); return(fields); }
private static IEnumerable <MemberDeclarationSyntax> CreateProxyMethods( LibraryTypes libraryTypes, InvokableInterfaceDescription interfaceDescription, MetadataModel metadataModel) { foreach (var methodDescription in interfaceDescription.Methods) { yield return(CreateProxyMethod(methodDescription)); } MethodDeclarationSyntax CreateProxyMethod(MethodDescription methodDescription) { var method = methodDescription.Method; var declaration = MethodDeclaration(method.ReturnType.ToTypeSyntax(methodDescription.TypeParameterSubstitutions), method.Name.EscapeIdentifier()) .AddParameterListParameters(method.Parameters.Select((p, i) => GetParameterSyntax(i, p, methodDescription.TypeParameterSubstitutions)).ToArray()) .WithBody( CreateAsyncProxyMethodBody(libraryTypes, metadataModel, methodDescription)); if (methodDescription.HasCollision) { declaration = declaration.WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword))); // Type parameter constrains are not valid on explicit interface definitions var typeParameters = SyntaxFactoryUtility.GetTypeParameterConstraints(methodDescription.MethodTypeParameters); foreach (var(name, constraints) in typeParameters) { if (constraints.Count > 0) { declaration = declaration.AddConstraintClauses( TypeParameterConstraintClause(name).AddConstraints(constraints.ToArray())); } } } else { var explicitInterfaceSpecifier = ExplicitInterfaceSpecifier(methodDescription.Method.ContainingType.ToNameSyntax()); declaration = declaration.WithExplicitInterfaceSpecifier(explicitInterfaceSpecifier); } if (methodDescription.MethodTypeParameters.Count > 0) { declaration = declaration.WithTypeParameterList( TypeParameterList(SeparatedList(methodDescription.MethodTypeParameters.Select(tp => TypeParameter(tp.Name))))); } return(declaration); } }
public static ClassDeclarationSyntax GenerateMetadata(Compilation compilation, MetadataModel metadataModel, LibraryTypes libraryTypes) { var configParam = "config".ToIdentifierName(); var addSerializerMethod = configParam.Member("Serializers").Member("Add"); var addCopierMethod = configParam.Member("Copiers").Member("Add"); var body = new List <StatementSyntax>(); body.AddRange( metadataModel.SerializableTypes.Select( type => (StatementSyntax)ExpressionStatement( InvocationExpression( addSerializerMethod, ArgumentList( SingletonSeparatedList( Argument(TypeOfExpression(GetCodecTypeName(type))))))) )); body.AddRange( metadataModel.SerializableTypes.Select( type => (StatementSyntax)ExpressionStatement( InvocationExpression( addCopierMethod, ArgumentList( SingletonSeparatedList( Argument(TypeOfExpression(GetCopierTypeName(type))))))) )); body.AddRange( metadataModel.DetectedCopiers.Select( type => (StatementSyntax)ExpressionStatement( InvocationExpression( addCopierMethod, ArgumentList( SingletonSeparatedList( Argument(TypeOfExpression(type.ToOpenTypeSyntax())))))) )); body.AddRange( metadataModel.DetectedSerializers.Select( type => (StatementSyntax)ExpressionStatement( InvocationExpression( addSerializerMethod, ArgumentList( SingletonSeparatedList( Argument(TypeOfExpression(type.ToOpenTypeSyntax())))))) )); var addProxyMethod = configParam.Member("InterfaceProxies").Member("Add"); body.AddRange( metadataModel.GeneratedProxies.Select( type => (StatementSyntax)ExpressionStatement( InvocationExpression( addProxyMethod, ArgumentList( SingletonSeparatedList( Argument(TypeOfExpression(type.TypeSyntax)))))) )); var addInvokableInterfaceMethod = configParam.Member("Interfaces").Member("Add"); body.AddRange( metadataModel.InvokableInterfaces.Select( type => (StatementSyntax)ExpressionStatement( InvocationExpression( addInvokableInterfaceMethod, ArgumentList( SingletonSeparatedList( Argument(TypeOfExpression(type.InterfaceType.ToOpenTypeSyntax())))))) )); var addInvokableInterfaceImplementationMethod = configParam.Member("InterfaceImplementations").Member("Add"); body.AddRange( metadataModel.InvokableInterfaceImplementations.Select( type => (StatementSyntax)ExpressionStatement( InvocationExpression( addInvokableInterfaceImplementationMethod, ArgumentList( SingletonSeparatedList( Argument(TypeOfExpression(type.ToOpenTypeSyntax())))))) )); var addActivatorMethod = configParam.Member("Activators").Member("Add"); body.AddRange( metadataModel.ActivatableTypes.Select( type => (StatementSyntax)ExpressionStatement( InvocationExpression( addActivatorMethod, ArgumentList( SingletonSeparatedList( Argument(TypeOfExpression(GetActivatorTypeName(type))))))) )); body.AddRange( metadataModel.DetectedActivators.Select( type => (StatementSyntax)ExpressionStatement( InvocationExpression( addActivatorMethod, ArgumentList( SingletonSeparatedList( Argument(TypeOfExpression(type.ToOpenTypeSyntax())))))) )); var addWellKnownTypeIdMethod = configParam.Member("WellKnownTypeIds").Member("Add"); body.AddRange( metadataModel.WellKnownTypeIds.Select( type => (StatementSyntax)ExpressionStatement( InvocationExpression( addWellKnownTypeIdMethod, ArgumentList(SeparatedList( new[] { Argument(LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(type.Id))), Argument(TypeOfExpression(type.Type)) })))) )); var addTypeAliasMethod = configParam.Member("WellKnownTypeAliases").Member("Add"); body.AddRange( metadataModel.TypeAliases.Select( type => (StatementSyntax)ExpressionStatement( InvocationExpression( addTypeAliasMethod, ArgumentList(SeparatedList( new[] { Argument(LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(type.Alias))), Argument(TypeOfExpression(type.Type)) })))) )); var configType = libraryTypes.TypeManifestOptions; var configureMethod = MethodDeclaration(PredefinedType(Token(SyntaxKind.VoidKeyword)), "Configure") .AddModifiers(Token(SyntaxKind.PublicKeyword)) .AddParameterListParameters( Parameter(configParam.Identifier).WithType(configType.ToTypeSyntax())) .AddBodyStatements(body.ToArray()); var interfaceType = libraryTypes.ITypeManifestProvider; return(ClassDeclaration("Metadata_" + SyntaxGeneration.Identifier.SanitizeIdentifierName(compilation.AssemblyName)) .AddBaseListTypes(SimpleBaseType(interfaceType.ToTypeSyntax())) .AddModifiers(Token(SyntaxKind.InternalKeyword), Token(SyntaxKind.SealedKeyword)) .AddAttributeLists(AttributeList(SingletonSeparatedList(CodeGenerator.GetGeneratedCodeAttributeSyntax()))) .AddMembers(configureMethod)); }
public static List <AttributeListSyntax> GenerateSyntax(LibraryTypes wellKnownTypes, MetadataModel model) { var attributes = new List <AttributeListSyntax>(); foreach (var assemblyName in model.ApplicationParts) { // Generate an assembly-level attribute with an instance of that class. var attribute = AttributeList( AttributeTargetSpecifier(Token(SyntaxKind.AssemblyKeyword)), SingletonSeparatedList( Attribute(wellKnownTypes.ApplicationPartAttribute.ToNameSyntax()) .AddArgumentListArguments(AttributeArgument(assemblyName.GetLiteralExpression())))); attributes.Add(attribute); } return(attributes); }
private static BlockSyntax CreateAsyncProxyMethodBody( LibraryTypes libraryTypes, MetadataModel metadataModel, MethodDescription methodDescription) { var statements = new List <StatementSyntax>(); var requestVar = IdentifierName("request"); var requestDescription = metadataModel.GeneratedInvokables[methodDescription]; var createRequestExpr = InvocationExpression(ThisExpression().Member("GetInvokable", requestDescription.TypeSyntax)) .WithArgumentList(ArgumentList(SeparatedList <ArgumentSyntax>())); statements.Add( LocalDeclarationStatement( VariableDeclaration( ParseTypeName("var"), SingletonSeparatedList( VariableDeclarator( Identifier("request")) .WithInitializer( EqualsValueClause(createRequestExpr)))))); // Set request object fields from method parameters. var parameterIndex = 0; foreach (var parameter in methodDescription.Method.Parameters) { statements.Add( ExpressionStatement( AssignmentExpression( SyntaxKind.SimpleAssignmentExpression, requestVar.Member($"arg{parameterIndex}"), IdentifierName(SyntaxFactoryUtility.GetSanitizedName(parameter, parameterIndex))))); parameterIndex++; } var invokeMethodName = "InvokeAsync"; foreach (var attr in methodDescription.Method.GetAttributes()) { if (attr.AttributeClass.GetAttributes(libraryTypes.InvokeMethodNameAttribute, out var attrs)) { foreach (var methodAttr in attrs) { invokeMethodName = (string)methodAttr.ConstructorArguments.First().Value; } } } ITypeSymbol resultType; var methodReturnType = (INamedTypeSymbol)methodDescription.Method.ReturnType; if (methodReturnType.TypeArguments.Length == 1) { // Task<T> / ValueTask<T> resultType = methodReturnType.TypeArguments[0]; } else if (SymbolEqualityComparer.Default.Equals(methodReturnType, libraryTypes.Void)) { // void resultType = libraryTypes.Object; } else { // Task / ValueTask resultType = libraryTypes.Object; } // C#: base.InvokeAsync<TReturn>(request); var invocationExpression = InvocationExpression( BaseExpression().Member(invokeMethodName, resultType.ToTypeSyntax(methodDescription.TypeParameterSubstitutions)), ArgumentList(SeparatedList(new[] { Argument(requestVar) }))); var rt = methodReturnType.ConstructedFrom; if (SymbolEqualityComparer.Default.Equals(rt, libraryTypes.Task_1) || SymbolEqualityComparer.Default.Equals(methodReturnType, libraryTypes.Task)) { // C#: return <invocation>.AsTask() statements.Add(ReturnStatement(InvocationExpression(invocationExpression.Member("AsTask"), ArgumentList()))); } else if (SymbolEqualityComparer.Default.Equals(rt, libraryTypes.ValueTask_1)) { // C#: return <invocation> statements.Add(ReturnStatement(invocationExpression)); } else if (SymbolEqualityComparer.Default.Equals(methodReturnType, libraryTypes.ValueTask)) { // C#: return new ValueTask(<invocation>) statements.Add(ReturnStatement(ObjectCreationExpression(libraryTypes.ValueTask.ToTypeSyntax()).WithArgumentList(ArgumentList(SeparatedList(new[] { Argument(InvocationExpression(invocationExpression.Member("AsTask"), ArgumentList())) }))))); } else { // C#: _ = <invocation> statements.Add(ExpressionStatement(AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, IdentifierName("_"), invocationExpression))); } return(Block(statements)); }
private static BlockSyntax CreateProxyMethodBody( LibraryTypes libraryTypes, MetadataModel metadataModel, MethodDescription methodDescription) { var statements = new List <StatementSyntax>(); var completionVar = IdentifierName("completion"); var requestVar = IdentifierName("request"); var requestDescription = metadataModel.GeneratedInvokables[methodDescription]; var createRequestExpr = InvocationExpression(libraryTypes.InvokablePool.ToTypeSyntax().Member("Get", requestDescription.TypeSyntax)) .WithArgumentList(ArgumentList(SeparatedList <ArgumentSyntax>())); statements.Add( LocalDeclarationStatement( VariableDeclaration( ParseTypeName("var"), SingletonSeparatedList( VariableDeclarator( Identifier("request")) .WithInitializer( EqualsValueClause(createRequestExpr)))))); // Set request object fields from method parameters. var parameterIndex = 0; foreach (var parameter in methodDescription.Method.Parameters) { statements.Add( ExpressionStatement( AssignmentExpression( SyntaxKind.SimpleAssignmentExpression, requestVar.Member($"arg{parameterIndex}"), IdentifierName(SyntaxFactoryUtility.GetSanitizedName(parameter, parameterIndex))))); parameterIndex++; } ITypeSymbol returnType; var methodReturnType = (INamedTypeSymbol)methodDescription.Method.ReturnType; if (methodReturnType.TypeParameters.Length == 1) { returnType = methodReturnType.TypeArguments[0]; } else { returnType = libraryTypes.Object; } var createCompletionExpr = InvocationExpression(libraryTypes.ResponseCompletionSourcePool.ToTypeSyntax().Member("Get", returnType.ToTypeSyntax(methodDescription.TypeParameterSubstitutions))) .WithArgumentList(ArgumentList(SeparatedList <ArgumentSyntax>())); statements.Add( LocalDeclarationStatement( VariableDeclaration( ParseTypeName("var"), SingletonSeparatedList( VariableDeclarator( Identifier("completion")) .WithInitializer( EqualsValueClause(createCompletionExpr)))))); var sendRequestMethodName = "SendRequest"; foreach (var attr in methodDescription.Method.GetAttributes()) { if (attr.AttributeClass.GetAttributes(libraryTypes.InvokeMethodNameAttribute, out var attrs)) { foreach (var methodAttr in attrs) { sendRequestMethodName = (string)methodAttr.ConstructorArguments.First().Value; } } } // Issue request statements.Add( ExpressionStatement( InvocationExpression( BaseExpression().Member(sendRequestMethodName), ArgumentList(SeparatedList(new[] { Argument(completionVar), Argument(requestVar) }))))); // Return result string valueTaskMethodName; if (methodReturnType.TypeArguments.Length == 1) { valueTaskMethodName = "AsValueTask"; } else if (SymbolEqualityComparer.Default.Equals(methodReturnType, libraryTypes.Void)) { valueTaskMethodName = null; } else { valueTaskMethodName = "AsVoidValueTask"; } if (valueTaskMethodName is not null) { var returnVal = InvocationExpression(completionVar.Member(valueTaskMethodName)); if (SymbolEqualityComparer.Default.Equals(methodReturnType.ConstructedFrom, libraryTypes.Task_1) || SymbolEqualityComparer.Default.Equals(methodReturnType, libraryTypes.Task)) { returnVal = InvocationExpression(returnVal.Member("AsTask")); } statements.Add(ReturnStatement(returnVal)); } return(Block(statements)); }