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); } }
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)); } }
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); }
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); }