public static (ClassDeclarationSyntax, IGeneratedProxyDescription) Generate( LibraryTypes libraryTypes, IInvokableInterfaceDescription interfaceDescription, MetadataModel metadataModel) { var generatedClassName = GetSimpleClassName(interfaceDescription.InterfaceType); var ctors = GenerateConstructors(generatedClassName, interfaceDescription).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); if (interfaceDescription.InterfaceType.TypeParameters.Length > 0) { classDeclaration = AddGenericTypeConstraints(classDeclaration, interfaceDescription.InterfaceType); } return(classDeclaration, new GeneratedProxyDescription(interfaceDescription)); }
private static MemberDeclarationSyntax GenerateSetTargetMethod( LibraryTypes libraryTypes, IInvokableInterfaceDescription interfaceDescription, TargetFieldDescription targetField) { var type = IdentifierName("TTargetHolder"); var typeToken = Identifier("TTargetHolder"); var holderParameter = Identifier("holder"); var holder = IdentifierName("holder"); var getTarget = InvocationExpression( MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, holder, GenericName(interfaceDescription.IsExtension ? "GetExtension" : "GetTarget") .WithTypeArgumentList( TypeArgumentList( SingletonSeparatedList(interfaceDescription.InterfaceType.ToTypeSyntax()))))) .WithArgumentList(ArgumentList()); var body = AssignmentExpression( SyntaxKind.SimpleAssignmentExpression, ThisExpression().Member(targetField.FieldName), getTarget); return(MethodDeclaration(libraryTypes.Void.ToTypeSyntax(), "SetTarget") .WithTypeParameterList(TypeParameterList(SingletonSeparatedList(TypeParameter(typeToken)))) .WithParameterList(ParameterList(SingletonSeparatedList(Parameter(holderParameter).WithType(type)))) .WithExpressionBody(ArrowExpressionClause(body)) .WithSemicolonToken(Token(SyntaxKind.SemicolonToken)) .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.OverrideKeyword)))); }
private static BlockSyntax CreateProxyMethodBody( LibraryTypes libraryTypes, MetadataModel metadataModel, IInvokableInterfaceDescription interfaceDescription, MethodDescription methodDescription) { var statements = new List <StatementSyntax>(); // Create request object var requestVar = IdentifierName("request"); var requestDescription = metadataModel.GeneratedInvokables[methodDescription]; var createRequestExpr = ObjectCreationExpression(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(parameter.Name)))); parameterIndex++; } // Issue request statements.Add( ExpressionStatement( AwaitExpression( InvocationExpression( BaseExpression().Member("Invoke"), ArgumentList(SingletonSeparatedList(Argument(requestVar))))))); // Return result if (methodDescription.Method.ReturnType is INamedTypeSymbol named && named.TypeParameters.Length == 1) { statements.Add(ReturnStatement(requestVar.Member("result"))); } return(Block(statements)); }
public static (ClassDeclarationSyntax, IGeneratedInvokerDescription) Generate( Compilation compilation, LibraryTypes libraryTypes, IInvokableInterfaceDescription interfaceDescription, MethodDescription methodDescription) { var method = methodDescription.Method; var generatedClassName = GetSimpleClassName(method); var fieldDescriptions = GetFieldDescriptions(methodDescription.Method, interfaceDescription); var fields = GetFieldDeclarations(fieldDescriptions, libraryTypes); var ctor = GenerateConstructor(generatedClassName, fieldDescriptions); var targetField = fieldDescriptions.OfType <TargetFieldDescription>().Single(); var resultField = fieldDescriptions.OfType <ResultFieldDescription>().FirstOrDefault(); var classDeclaration = ClassDeclaration(generatedClassName) .AddBaseListTypes(SimpleBaseType(libraryTypes.Invokable.ToTypeSyntax())) .AddModifiers(Token(SyntaxKind.InternalKeyword), Token(SyntaxKind.SealedKeyword)) .AddAttributeLists( AttributeList(SingletonSeparatedList(CodeGenerator.GetGeneratedCodeAttributeSyntax()))) .AddMembers(fields) .AddMembers(ctor) .AddMembers( GenerateGetArgumentCount(libraryTypes, methodDescription), GenerateSetTargetMethod(libraryTypes, interfaceDescription, targetField), GenerateGetTargetMethod(libraryTypes, targetField), GenerateResetMethod(libraryTypes, fieldDescriptions), GenerateGetArgumentMethod(libraryTypes, methodDescription, fieldDescriptions), GenerateSetArgumentMethod(libraryTypes, methodDescription, fieldDescriptions), GenerateInvokeMethod(libraryTypes, methodDescription, fieldDescriptions, targetField, resultField), GenerateSetResultProperty(libraryTypes, resultField), GenerateGetResultProperty(libraryTypes, resultField)); var typeParameters = interfaceDescription.InterfaceType.TypeParameters.Select(tp => (tp, tp.Name)) .Concat(method.TypeParameters.Select(tp => (tp, tp.Name))) .ToList(); if (typeParameters.Count > 0) { classDeclaration = AddGenericTypeConstraints(classDeclaration, typeParameters); } return(classDeclaration, new GeneratedInvokerDescription( interfaceDescription, methodDescription, generatedClassName, fieldDescriptions.OfType <IMemberDescription>().ToList())); }
public GeneratedInvokerDescription( IInvokableInterfaceDescription interfaceDescription, MethodDescription methodDescription, string generatedClassName, List <IMemberDescription> members) { this.InterfaceDescription = interfaceDescription; this.methodDescription = methodDescription; this.Name = generatedClassName; this.Members = members; this.TypeParameters = interfaceDescription.InterfaceType.TypeParameters .Concat(this.methodDescription.Method.TypeParameters) .ToImmutableArray(); }
private static IEnumerable <MemberDeclarationSyntax> CreateProxyMethods( LibraryTypes libraryTypes, IInvokableInterfaceDescription 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(), method.Name) .AddModifiers(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.AsyncKeyword)) .AddParameterListParameters(method.Parameters.Select(GetParameterSyntax).ToArray()) .WithBody( CreateProxyMethodBody(libraryTypes, metadataModel, interfaceDescription, methodDescription)); var typeParameters = GetTypeParametersWithConstraints(method.TypeParameters); foreach (var(name, constraints) in typeParameters) { if (constraints.Count > 0) { declaration = declaration.AddConstraintClauses( TypeParameterConstraintClause(name).AddConstraints(constraints.ToArray())); } } if (typeParameters.Count > 0) { declaration = declaration.WithTypeParameterList( TypeParameterList(SeparatedList(typeParameters.Select(tp => TypeParameter(tp.Item1))))); } return(declaration); } }
private static IEnumerable <MemberDeclarationSyntax> GenerateConstructors( string simpleClassName, IInvokableInterfaceDescription interfaceDescription) { var baseType = interfaceDescription.ProxyBaseType; foreach (var member in baseType.GetMembers()) { if (member is not IMethodSymbol method) { continue; } if (method.MethodKind != MethodKind.Constructor) { continue; } if (method.DeclaredAccessibility == Accessibility.Private) { continue; } yield return(CreateConstructor(method)); } ConstructorDeclarationSyntax CreateConstructor(IMethodSymbol baseConstructor) { return(ConstructorDeclaration(simpleClassName) .AddParameterListParameters(baseConstructor.Parameters.Select(GetParameterSyntax).ToArray()) .WithModifiers(TokenList(GetModifiers(baseConstructor))) .WithInitializer( ConstructorInitializer( SyntaxKind.BaseConstructorInitializer, ArgumentList( SeparatedList(baseConstructor.Parameters.Select(GetBaseInitializerArgument))))) .WithBody(Block())); }
public GeneratedProxyDescription(IInvokableInterfaceDescription interfaceDescription) { InterfaceDescription = interfaceDescription; }
public static (ClassDeclarationSyntax, IGeneratedInvokerDescription) Generate( Compilation compilation, LibraryTypes libraryTypes, IInvokableInterfaceDescription interfaceDescription, MethodDescription methodDescription) { var method = methodDescription.Method; var generatedClassName = GetSimpleClassName(method); var fieldDescriptions = GetFieldDescriptions(methodDescription.Method, interfaceDescription); var fields = GetFieldDeclarations(fieldDescriptions, libraryTypes); var ctor = GenerateConstructor(generatedClassName, fieldDescriptions); var targetField = fieldDescriptions.OfType <TargetFieldDescription>().Single(); var methodReturnType = (INamedTypeSymbol)method.ReturnType; ITypeSymbol baseClassType; if (methodReturnType.TypeArguments.Length == 1) { if (methodReturnType.ConstructedFrom.Equals(libraryTypes.ValueTask_1)) { baseClassType = libraryTypes.Request_1.Construct(methodReturnType.TypeArguments[0]); } else if (methodReturnType.ConstructedFrom.Equals(libraryTypes.Task_1)) { baseClassType = libraryTypes.TaskRequest_1.Construct(methodReturnType.TypeArguments[0]); } else { throw new InvalidOperationException($"Unsupported return type {methodReturnType}. Constructed from: {methodReturnType.ConstructedFrom}"); } } else { if (methodReturnType.Equals(libraryTypes.ValueTask)) { baseClassType = libraryTypes.Request; } else if (methodReturnType.Equals(libraryTypes.Task)) { baseClassType = libraryTypes.TaskRequest; } else { throw new InvalidOperationException($"Unsupported return type {methodReturnType}"); } } var classDeclaration = ClassDeclaration(generatedClassName) .AddBaseListTypes(SimpleBaseType(baseClassType.ToTypeSyntax())) .AddModifiers(Token(SyntaxKind.InternalKeyword), Token(SyntaxKind.SealedKeyword)) .AddAttributeLists( AttributeList(SingletonSeparatedList(CodeGenerator.GetGeneratedCodeAttributeSyntax()))) .AddMembers(fields) .AddMembers(ctor) .AddMembers( GenerateGetArgumentCount(libraryTypes, methodDescription), GenerateSetTargetMethod(libraryTypes, interfaceDescription, targetField), GenerateGetTargetMethod(libraryTypes, targetField), GenerateDisposeMethod(libraryTypes, fieldDescriptions), GenerateGetArgumentMethod(libraryTypes, methodDescription, fieldDescriptions), GenerateSetArgumentMethod(libraryTypes, methodDescription, fieldDescriptions), GenerateInvokeInnerMethod(libraryTypes, methodDescription, fieldDescriptions, targetField)); var typeParameters = interfaceDescription.InterfaceType.TypeParameters.Select(tp => (tp, tp.Name)) .Concat(method.TypeParameters.Select(tp => (tp, tp.Name))) .ToList(); if (typeParameters.Count > 0) { classDeclaration = AddGenericTypeConstraints(classDeclaration, typeParameters); } return(classDeclaration, new GeneratedInvokerDescription( interfaceDescription, methodDescription, generatedClassName, fieldDescriptions.OfType <IMemberDescription>().ToList())); }
private static IEnumerable <MemberDeclarationSyntax> GenerateConstructors( string simpleClassName, LibraryTypes libraryTypes, IInvokableInterfaceDescription interfaceDescription) { var baseType = interfaceDescription.ProxyBaseType; foreach (var member in baseType.GetMembers()) { if (!(member is IMethodSymbol method)) { continue; } if (method.MethodKind != MethodKind.Constructor) { continue; } if (method.DeclaredAccessibility == Accessibility.Private) { continue; } yield return(CreateConstructor(method)); } ConstructorDeclarationSyntax CreateConstructor(IMethodSymbol baseConstructor) { return(ConstructorDeclaration(simpleClassName) .AddParameterListParameters(baseConstructor.Parameters.Select(GetParameterSyntax).ToArray()) .WithModifiers(TokenList(GetModifiers(baseConstructor))) .WithInitializer( ConstructorInitializer( SyntaxKind.BaseConstructorInitializer, ArgumentList( SeparatedList(baseConstructor.Parameters.Select(GetBaseInitializerArgument))))) .WithBody(Block())); } IEnumerable <SyntaxToken> GetModifiers(IMethodSymbol method) { switch (method.DeclaredAccessibility) { case Accessibility.Public: case Accessibility.Protected: yield return(Token(SyntaxKind.PublicKeyword)); break; case Accessibility.Internal: case Accessibility.ProtectedOrInternal: case Accessibility.ProtectedAndInternal: yield return(Token(SyntaxKind.InternalKeyword)); break; default: break; } } ArgumentSyntax GetBaseInitializerArgument(IParameterSymbol parameter) { var result = Argument(IdentifierName(parameter.Name)); switch (parameter.RefKind) { case RefKind.None: break; case RefKind.Ref: result = result.WithRefOrOutKeyword(Token(SyntaxKind.RefKeyword)); break; case RefKind.Out: result = result.WithRefOrOutKeyword(Token(SyntaxKind.OutKeyword)); break; default: break; } return(result); } }
private static BlockSyntax CreateProxyMethodBody( LibraryTypes libraryTypes, MetadataModel metadataModel, IInvokableInterfaceDescription interfaceDescription, 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(parameter.Name)))); 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())) .WithArgumentList(ArgumentList(SeparatedList <ArgumentSyntax>())); statements.Add( LocalDeclarationStatement( VariableDeclaration( ParseTypeName("var"), SingletonSeparatedList( VariableDeclarator( Identifier("completion")) .WithInitializer( EqualsValueClause(createCompletionExpr)))))); // Issue request statements.Add( ExpressionStatement( InvocationExpression( BaseExpression().Member("SendRequest"), ArgumentList(SeparatedList(new[] { Argument(completionVar), Argument(requestVar) }))))); // Return result string valueTaskMethodName; if (methodReturnType.TypeArguments.Length == 1) { valueTaskMethodName = "AsValueTask"; } else { valueTaskMethodName = "AsVoidValueTask"; } var returnVal = InvocationExpression(completionVar.Member(valueTaskMethodName)); if (methodReturnType.ConstructedFrom.Equals(libraryTypes.Task_1) || methodReturnType.Equals(libraryTypes.Task)) { returnVal = InvocationExpression(returnVal.Member("AsTask")); } statements.Add(ReturnStatement(returnVal)); return(Block(statements)); }