예제 #1
0
        private void GenerateExtensionMethod(ClassDeclaration extensionClass, Method method, MethodParameter methodParameter)
        {
            foreach (var parameterEntityRef in methodParameter.Type.ParameterEntity.Refs.Where(r => r.ModelRef.IsModel))
            {
                var m = GenerateMethod(extensionClass, method);
                m.Modifiers |= Modifiers.Static;
                var extensionArgument = new MethodArgumentDeclaration(parameterEntityRef.ModelRef, ToArgumentName(parameterEntityRef.ModelRef.Model.Name))
                {
                    IsExtension = true
                };

                m.Statements.Clear();

                var invoke = new MethodInvokeExpression(new CastExpression(extensionArgument, new TypeReference("IGitLabObject")).CreateMemberReferenceExpression("GitLabClient", m.Name));

                foreach (var arg in m.Arguments.ToList())
                {
                    if (arg.Data.TryGetValue("Parameter", out var parameter) && methodParameter == parameter)
                    {
                        m.Arguments.Remove(arg);
                        invoke.Arguments.Add(extensionArgument);
                    }
                    else
                    {
                        invoke.Arguments.Add(arg);
                    }
                }

                m.Statements.Add(new ReturnStatement(invoke));

                m.Name = m.Name.Replace(extensionClass.Name, "", StringComparison.OrdinalIgnoreCase);
                m.Arguments.Insert(0, extensionArgument);
            }
        }
예제 #2
0
        private void GenerateFileExtensionMethod(ClassDeclaration classDeclaration, ClassDeclaration extensionClass)
        {
            var methods = classDeclaration.Members
                          .OfType <MethodDeclaration>()
                          .Where(ContainsFileArgument)
                          .ToList();

            foreach (var methodDeclaration in methods)
            {
                var method = methodDeclaration.Data["Method"] as Method;
                if (method == null)
                {
                    continue;
                }

                var m = GenerateMethod(extensionClass, method);
                m.Modifiers |= Modifiers.Static;
                m.Statements.Clear();

                var extensionArgument = new MethodArgumentDeclaration(new TypeReference("IGitLabClient"), "client")
                {
                    IsExtension = true
                };

                var invoke = new MethodInvokeExpression(extensionArgument.CreateMemberReferenceExpression(methodDeclaration.Name));

                foreach (var arg in m.Arguments.ToList())
                {
                    if (arg.Name == "encoding")
                    {
                        invoke.Arguments.Add(new LiteralExpression("base64"));
                        m.Arguments.Remove(arg);
                    }
                    else if (arg.Name == "content")
                    {
                        invoke.Arguments.Add(new TypeReference(typeof(Convert)).CreateInvokeMethodExpression(nameof(Convert.ToBase64String), arg));
                        arg.Type = typeof(byte[]);
                    }
                    else
                    {
                        invoke.Arguments.Add(arg);
                    }
                }

                m.Statements.Add(new ReturnStatement(invoke));

                m.Name = m.Name.Replace(extensionClass.Name, "", StringComparison.OrdinalIgnoreCase);
                m.Arguments.Insert(0, extensionArgument);
            }

            bool ContainsFileArgument(MethodDeclaration m)
            {
                return(m.Arguments.Any(a => a.Name == "content" && a.Type.ClrFullTypeName == typeof(string).FullName) &&
                       m.Arguments.Any(a => a.Name == "encoding" && a.Type.ClrFullTypeName == typeof(string).FullName));
            }
        }
예제 #3
0
        private string PrintExpression(MethodInvokeExpression expression)
        {
            var prefix = "";

            if (expression.TargetObject != null)
            {
                prefix = PrintExpression((dynamic)expression.TargetObject) + ".";
            }
            return(string.Concat(prefix, expression.MethodName, "(", string.Join(", ", expression.Arguments.Select(a => (string)PrintExpression((dynamic)a))), ")"));
        }
        private static void GenerateParameterEntityEqualTypedMethod(StructDeclaration type, PropertyDeclaration valueProperty)
        {
            var equal = type.AddMember(new MethodDeclaration(nameof(object.Equals)));

            equal.Modifiers  = Modifiers.Public;
            equal.ReturnType = typeof(bool);
            var objArg = equal.AddArgument("other", new TypeReference(type));

            Expression returnExpression = new MethodInvokeExpression(
                new MemberReferenceExpression(typeof(object), "Equals"),
                valueProperty,
                new MemberReferenceExpression(objArg, valueProperty));

            equal.Statements = new ReturnStatement(returnExpression);
        }
예제 #5
0
            public override void Transform(IEReference reference, IEClass scope, Method output, ITransformationContext context)
            {
                output.Name       = "get_" + reference.Name;
                output.ReturnType = new TypeReference {
                    BaseName = reference.EType.Name
                };

                var resolve = new MethodInvokeExpression
                {
                    MethodName = "resolve"
                };

                resolve.Arguments.Add(new ThisReferenceExpression());
                resolve.Arguments.Add(new StringLiteralExpression {
                    Value = reference.Name
                });
                output.BodyExpression = resolve;

                var cl = context.Trace.ResolveIn(Rule <Class2Class>(), scope);

                cl.Members.Add(output);
            }
        public void MethodInvocationsOnClassBody()
        {
            String contents =
                "class MyClass \r\n" +
                "  attr_accessor (:name) \r\n" +
                "end \r\n";

            CompilationUnitNode unit = RookParser.ParseContents(contents);

            Assert.IsNotNull(unit);
            Assert.AreEqual(0, unit.Namespaces.Count);
            Assert.AreEqual(1, unit.ClassesTypes.Count);

            ClassDefinitionStatement ClassDefinitionStatement = unit.ClassesTypes[0] as ClassDefinitionStatement;

            Assert.IsNotNull(ClassDefinitionStatement);
            Assert.AreEqual("MyClass", ClassDefinitionStatement.Name);
            Assert.AreEqual(0, ClassDefinitionStatement.BaseTypes.Count);
            Assert.AreEqual(1, ClassDefinitionStatement.Statements.Count);

            ExpressionStatement stmt = ClassDefinitionStatement.Statements[0] as ExpressionStatement;

            Assert.IsNotNull(stmt);
            Assert.IsNotNull(stmt.Expression);

            MethodInvokeExpression minv = stmt.Expression as MethodInvokeExpression;

            Assert.IsNotNull(minv);
            Assert.IsNotNull(minv.Target);
            Assert.IsNotNull(minv.Arguments);
            Assert.AreEqual(1, minv.Arguments.Count);
            Assert.AreEqual("attr_accessor", (minv.Target as IdentifierReferenceExpression).Name);

            SymbolExpression se = minv.Arguments[0] as SymbolExpression;

            Assert.IsNotNull(se);
            Assert.AreEqual(":name", se.Name);
        }
        private static MethodDeclaration GenerateMethod(ClassDeclaration clientClass, Method method, TypeReference requestType)
        {
            var m = clientClass.AddMember(new MethodDeclaration(method.MethodGroup.Name + '_' + GetMethodName(method)));

            m.SetData("Method", method);
            var buildUrlMethod = GenerateBuildUrlMethod(clientClass, method, requestType);

            GenerateMethodSignature(method, m, requestType, out var requestArgument, out var requestOptionsArgument, out var cancellationTokenArgument);
            m.Modifiers = Modifiers.Private;
            if (method.MethodType != MethodType.GetPaged)
            {
                m.Modifiers |= Modifiers.Async;
            }

            // Method body
            m.Statements = new StatementCollection();

            // 1. Create url from parameters
            var buildUrlExpression = new MethodInvokeExpression(new MemberReferenceExpression(new TypeReference(clientClass), buildUrlMethod));

            if (buildUrlMethod.Arguments.Count > 0)
            {
                buildUrlExpression.Arguments.Add(requestArgument);
            }

            var urlVariable = new VariableDeclarationStatement(typeof(string), "url", buildUrlExpression);

            m.Statements.Add(urlVariable);

            if (method.MethodType == MethodType.GetPaged)
            {
                // return new Meziantou.GitLab.PagedResponse<MergeRequest>(this, url, requestOptions);
                m.Statements.Add(new ReturnStatement(new NewObjectExpression(m.ReturnType !.Clone(), new ThisExpression(), urlVariable, requestOptionsArgument)));
            }
            else
            {
                // 2. Create HttpRequestMessage object
                var requestVariable = new VariableDeclarationStatement(typeof(HttpRequestMessage), "requestMessage", new NewObjectExpression(typeof(HttpRequestMessage)));
                var usingStatement  = new UsingStatement()
                {
                    Statement = requestVariable, Body = new StatementCollection()
                };
                m.Statements.Add(usingStatement);
                var statements = usingStatement.Body;

                statements.Add(new AssignStatement(new MemberReferenceExpression(requestVariable, nameof(HttpRequestMessage.Method)), GetHttpMethod(method.MethodType)));
                statements.Add(new AssignStatement(new MemberReferenceExpression(requestVariable, nameof(HttpRequestMessage.RequestUri)), new NewObjectExpression(typeof(Uri), urlVariable, new MemberReferenceExpression(typeof(UriKind), nameof(UriKind.RelativeOrAbsolute)))));

                CreateBodyArgument(method, statements, requestArgument, requestVariable);

                // 3. Send request
                // var response = await SendAsync(request, options, cancellationToken).ConfigureAwait(false);
                var responseVariable = new VariableDeclarationStatement(WellKnownTypes.HttpResponseTypeReference.MakeNullable(), "response", LiteralExpression.Null());
                statements.Add(responseVariable);
                var responseTry = new TryCatchFinallyStatement()
                {
                    Try = new StatementCollection()
                };
                statements.Add(responseTry);
                responseTry.Try.Add(new AssignStatement(responseVariable, new AwaitExpression(new MethodInvokeExpression(new MemberReferenceExpression(new ThisExpression(), "SendAsync"), requestVariable, requestOptionsArgument, cancellationTokenArgument)).ConfigureAwait(false)));

                // Dispose reponse in catch if Stream or in finally if not stream
                var disposeReponseStatements = new ConditionStatement()
                {
                    Condition      = new BinaryExpression(BinaryOperator.NotEquals, responseVariable, LiteralExpression.Null()),
                    TrueStatements = responseVariable.CreateInvokeMethodExpression("Dispose"),
                };

                if (method.ReturnType == ModelRef.File)
                {
                    responseTry.Catch = new CatchClauseCollection
                    {
                        new CatchClause()
                        {
                            Body = disposeReponseStatements,
                        },
                    };

                    responseTry.Catch[0].Body.Add(new ThrowStatement());
                }
                else
                {
                    responseTry.Finally = disposeReponseStatements;
                }

                // 4. Convert and return response object
                //    if (response.StatusCode == HttpStatusCode.NotFound) return default;
                if (method.MethodType == MethodType.Get)
                {
                    responseTry.Try.Add(new ConditionStatement()
                    {
                        Condition      = new BinaryExpression(BinaryOperator.Equals, responseVariable.CreateMemberReferenceExpression("StatusCode"), new MemberReferenceExpression(typeof(HttpStatusCode), "NotFound")),
                        TrueStatements = new ReturnStatement(new DefaultValueExpression()),
                    });
                }

                // await response.EnsureStatusCodeAsync(cancellationToken).ConfigureAwait(false);
                responseTry.Try.Add(new AwaitExpression(new MethodInvokeExpression(new MemberReferenceExpression(responseVariable, "EnsureStatusCodeAsync"), cancellationTokenArgument)).ConfigureAwait(false));

                if (method.ReturnType != null)
                {
                    // var result = await response.ToObjectAsync<T>(cancellationToken).ConfigureAwait(false);
                    var resultVariable = new VariableDeclarationStatement(m.ReturnType.Parameters[0].MakeNullable(), "result");
                    responseTry.Try.Add(resultVariable);
                    if (method.MethodType == MethodType.Get && method.ReturnType == ModelRef.File)
                    {
                        resultVariable.InitExpression = new AwaitExpression(responseVariable.CreateInvokeMethodExpression("ToStreamAsync", cancellationTokenArgument)).ConfigureAwait(false);
                    }
                    else if (method.MethodType == MethodType.GetCollection)
                    {
                        resultVariable.InitExpression = new AwaitExpression(responseVariable.CreateInvokeMethodExpression("ToCollectionAsync", new TypeReference[] { method.ReturnType.ToPropertyTypeReference() }, cancellationTokenArgument)).ConfigureAwait(false);
                    }
                    else
                    {
                        resultVariable.InitExpression = new AwaitExpression(responseVariable.CreateInvokeMethodExpression("ToObjectAsync", new TypeReference[] { method.ReturnType.ToPropertyTypeReference() }, cancellationTokenArgument)).ConfigureAwait(false);
                    }

                    // if (result is null)
                    //   throw new GitLabException(response.RequestMethod, response.RequestUri, response.StatusCode, $"The response cannot be converted to '{typeof(T)}' because the body is null or empty");
                    if (method.MethodType != MethodType.Get)
                    {
                        responseTry.Try.Add(new ConditionStatement()
                        {
                            Condition      = new BinaryExpression(BinaryOperator.Equals, resultVariable, LiteralExpression.Null()),
                            TrueStatements = new ThrowStatement(new NewObjectExpression(WellKnownTypes.GitLabExceptionTypeReference,
                                                                                        responseVariable.CreateMemberReferenceExpression("RequestMethod"),
                                                                                        responseVariable.CreateMemberReferenceExpression("RequestUri"),
                                                                                        responseVariable.CreateMemberReferenceExpression("StatusCode"),
                                                                                        new LiteralExpression($"The response cannot be converted to '{method.ReturnType.ToPropertyTypeReference().ClrFullTypeName}' because the body is null or empty"))),
                        });
                    }

                    responseTry.Try.Add(new ReturnStatement(resultVariable));
                }
            }

            return(m);
        private static MethodDeclaration GenerateBuildUrlMethod(ClassDeclaration clientClass, Method method, TypeReference requestType)
        {
            var m = clientClass.AddMember(new MethodDeclaration(method.MethodGroup.Name + '_' + GetMethodName(method) + "_BuildUrl"));

            m.Modifiers  = Modifiers.Private | Modifiers.Static;
            m.ReturnType = typeof(string);

            // Method body
            m.Statements = new StatementCollection();

            var urlVariable = new VariableDeclarationStatement(typeof(string), "url");

            m.Statements.Add(urlVariable);

            // 1. Create url from parameters
            var parameters = method.Parameters.Where(p => GetParameterLocation(method, p) == ParameterLocation.Url).ToList();

            if (parameters.Any())
            {
                var requestArgument = m.AddArgument("request", requestType);

                // [System.Diagnostics.CodeAnalysis.SuppressMessage("Reliability", "CA2000:Dispose objects before losing scope", Justification = "<Pending>")]
                m.CustomAttributes.Add(new CustomAttribute(typeof(SuppressMessageAttribute))
                {
                    Arguments =
                    {
                        new CustomAttributeArgument(new LiteralExpression("Reliability")),
                        new CustomAttributeArgument(new LiteralExpression("CA2000:Dispose objects before losing scope")),
                        new CustomAttributeArgument("Justification",                                                     new LiteralExpression("The rule doesn't understand ref struct")),
                    },
                });

                var segments   = GetSegments(method.UrlTemplate);
                var urlBuilder = new VariableDeclarationStatement(
                    WellKnownTypes.UrlBuilderTypeReference, "urlBuilder",
                    new NewObjectExpression(WellKnownTypes.UrlBuilderTypeReference));
                var urlUsingStatement = new UsingStatement()
                {
                    Statement = urlBuilder,
                    Body      = new StatementCollection(),
                };
                var usingStatements = urlUsingStatement.Body;
                m.Statements.Add(urlUsingStatement);

                foreach (var segment in segments)
                {
                    if (segment[0] == ':')
                    {
                        var param = parameters.SingleOrDefault(p => p.Name == segment[1..]);
                        if (param == null)
                        {
                            throw new InvalidOperationException($"Parameter '{segment}' is not mapped for method '{method.UrlTemplate}'");
                        }

                        AddParameter(param, parameterDelimiterVariable: null, encoded: true);
                        parameters.Remove(param);
                    }
                    else if (segment[0] == '*')
                    {
                        var param = parameters.SingleOrDefault(p => p.Name == segment[1..]);
                        if (param == null)
                        {
                            throw new InvalidOperationException($"Parameter '{segment}' is not mapped for method '{method.UrlTemplate}'");
                        }

                        AddParameter(param, parameterDelimiterVariable: null, encoded: false);
                        parameters.Remove(param);
                    }
                    else if (segment.StartsWith("[.", StringComparison.Ordinal))
                    {
                        var param = parameters.SingleOrDefault(p => p.Name == segment[2..^ 1]);
                        if (param == null)
                        {
                            throw new InvalidOperationException($"Parameter '{segment}' is not mapped for method '{method.UrlTemplate}'");
                        }

                        AddParameter(param, parameterDelimiterVariable: null, encoded: false, prefix: ".");
                        parameters.Remove(param);
                    }
                    else
                    {
                        usingStatements.Add(urlBuilder.CreateInvokeMethodExpression("Append", new LiteralExpression(segment)));
                    }
                }

                if (parameters.Any())
                {
                    var separator = new VariableDeclarationStatement(typeof(char), "separator", new LiteralExpression('?'));
                    usingStatements.Add(separator);

                    foreach (var param in parameters)
                    {
                        AddParameter(param, separator, encoded: true);
                    }
                }

                usingStatements.Add(new AssignStatement(urlVariable, urlBuilder.CreateInvokeMethodExpression("ToString")));

                void AddParameter(MethodParameter param, VariableDeclarationStatement parameterDelimiterVariable, bool encoded, string prefix = null)
                {
                    var appendParameterMethodName = encoded ? "AppendParameter" : "AppendRawParameter";

                    void AddSeparator(StatementCollection statements)
                    {
                        if (parameterDelimiterVariable != null)
                        {
                            statements.Add(urlBuilder.CreateInvokeMethodExpression("Append", parameterDelimiterVariable));
                            statements.Add(new AssignStatement(parameterDelimiterVariable, new LiteralExpression('&')));

                            if (!param.Options.HasFlag(MethodParameterOptions.CustomMapping))
                            {
                                statements.Add(urlBuilder.CreateInvokeMethodExpression("Append", new LiteralExpression(param.Name + '=')));
                            }
                        }
                    }

                    void AppendPrefix(StatementCollection statements)
                    {
                        if (!string.IsNullOrEmpty(prefix))
                        {
                            statements.Add(urlBuilder.CreateInvokeMethodExpression("Append", prefix));
                        }
                    }

                    if (param.Type.IsParameterEntity)
                    {
                        var propertyName      = param.Type.ParameterEntity.FinalType == ModelRef.Object ? "ValueAsString" : "Value";
                        var hasValueCondition = new ConditionStatement
                        {
                            Condition      = CreatePropertyReference().CreateMemberReferenceExpression(nameof(Nullable <int> .HasValue)),
                            TrueStatements = new StatementCollection(),
                        };

                        AddSeparator(hasValueCondition.TrueStatements);
                        AppendPrefix(hasValueCondition.TrueStatements);
                        var parameterValue = FormatValue(param.Type, CreatePropertyReference().CreateInvokeMethodExpression("GetValueOrDefault").CreateMemberReferenceExpression(propertyName));

                        if (param.Options.HasFlag(MethodParameterOptions.CustomMapping))
                        {
                            hasValueCondition.TrueStatements.Add(urlBuilder
                                                                 .CreateInvokeMethodExpression(
                                                                     "AppendParameter",
                                                                     param.Name,
                                                                     parameterValue));
                        }
                        else
                        {
                            hasValueCondition.TrueStatements.Add(urlBuilder
                                                                 .CreateInvokeMethodExpression(
                                                                     appendParameterMethodName,
                                                                     parameterValue));
                        }

                        urlUsingStatement.Body.Add(hasValueCondition);
                    }
                    else
                    {
                        var isValueType = param.Type.IsValueType && !param.Type.IsCollection;

                        var hasValueCondition = new ConditionStatement
                        {
                            Condition = isValueType ? CreatePropertyReference().CreateMemberReferenceExpression("HasValue") :
                                        new UnaryExpression(UnaryOperator.Not,
                                                            new MethodInvokeExpression(
                                                                new MemberReferenceExpression(new TypeReference(typeof(object)), "ReferenceEquals"),
                                                                CreatePropertyReference(), LiteralExpression.Null())),
                            TrueStatements = new StatementCollection(),
                        };

                        AddSeparator(hasValueCondition.TrueStatements);
                        AppendPrefix(hasValueCondition.TrueStatements);

                        Expression parameterValue = isValueType ? CreatePropertyReference().CreateInvokeMethodExpression("GetValueOrDefault") : CreatePropertyReference();

                        if (param.Options.HasFlag(MethodParameterOptions.CustomMapping))
                        {
                            hasValueCondition.TrueStatements.Add(urlBuilder
                                                                 .CreateInvokeMethodExpression(
                                                                     "AppendParameter",
                                                                     param.Name,
                                                                     parameterValue));
                        }
                        else
                        {
                            var appendMethod = new MethodInvokeExpression(
                                new MemberReferenceExpression(urlBuilder, appendParameterMethodName),
                                FormatValue(param.Type, parameterValue));

                            hasValueCondition.TrueStatements.Add(appendMethod);
                        }

                        urlUsingStatement.Body.Add(hasValueCondition);
                    }

                    MemberReferenceExpression CreatePropertyReference()
                    {
                        return(requestArgument.CreateMemberReferenceExpression(ToPropertyName(param.Name)));
                    }
                }
            }
            else
            {
                m.Statements.Add(new AssignStatement(urlVariable, new LiteralExpression(method.UrlTemplate)));
            }

            m.Statements.Add(new ReturnStatement(urlVariable));
            return(m);
        }