public void CSharpCodeGenerator_FieldDeclaration() { var type = new ClassDeclaration("Sample"); type.AddMember(new FieldDeclaration("_a", typeof(int))); type.AddMember(new FieldDeclaration("_b", typeof(Type), Modifiers.Private)); type.AddMember(new FieldDeclaration("_c", typeof(int), Modifiers.Protected, 10)); var generator = new CSharpCodeGenerator(); var result = generator.Write(type); Assert.That.StringEquals(@"class Sample { int _a; private System.Type _b; protected int _c = 10; } ", result); }
public void CSharpCodeGenerator_EventDeclaration() { var type = new ClassDeclaration("Sample"); type.AddMember(new EventFieldDeclaration("A", typeof(EventHandler), Modifiers.Public)); var generator = new CSharpCodeGenerator(); var result = generator.Write(type); Assert.That.StringEquals(@"class Sample { public event System.EventHandler A; } ", result); }
private static MethodDeclaration GenerateExplicitImplementationMethod(ClassDeclaration clientClass, InterfaceDeclaration clientInterface, Method method, TypeReference requestType) { var m = clientClass.AddMember(new MethodDeclaration(GetMethodName(method))); m.PrivateImplementationType = clientInterface; GenerateMethodSignature(method, m, requestType, out _, out _, out _); foreach (var arg in m.Arguments) { arg.DefaultValue = null; } m.Statements = new ReturnStatement( new MethodInvokeExpression( new MemberReferenceExpression(new ThisExpression(), method.MethodGroup.Name + '_' + m.Name), m.Arguments.Select(arg => new ArgumentReferenceExpression(arg)).ToArray())); return(m); }
public void CSharpCodeGenerator_Constructor() { var type = new ClassDeclaration("Sample"); var ctor = type.AddMember(new ConstructorDeclaration()); ctor.Modifiers = Modifiers.Internal; var generator = new CSharpCodeGenerator(); var result = generator.Write(type); Assert.That.StringEquals(@"class Sample { internal Sample() { } } ", result); }
public void CSharpCodeGenerator_Constructor_ThisWithArgs() { var type = new ClassDeclaration("Sample"); var ctor = type.AddMember(new ConstructorDeclaration()); ctor.Initializer = new ConstructorThisInitializer(new LiteralExpression("arg")); ctor.Modifiers = Modifiers.Public; var generator = new CSharpCodeGenerator(); var result = generator.Write(type); Assert.That.StringEquals(@"class Sample { public Sample() : this(""arg"") { } } ", result); }
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); }
private MethodDeclaration GenerateMethod(ClassDeclaration clientClass, Method method) { var m = clientClass.AddMember(new MethodDeclaration(method.Name + "Async")); m.SetData("Method", method); GenerateMethodSignature(method, m, out var arguments, out var pageArgument, out var requestOptionsArgument, out var cancellationTokenArgument); m.Modifiers = Modifiers.Public; // Method body m.Statements = new StatementCollection(); var urlBuilder = new VariableDeclarationStatement( typeof(UrlBuilder), "urlBuilder", new TypeReference(typeof(UrlBuilder)) .CreateInvokeMethodExpression("Get", method.UrlTemplate)); m.Statements.Add(urlBuilder); foreach (var param in method.Parameters.Where(p => GetParameterLocation(method, p) == ParameterLocation.Url)) { if (param.Type.IsParameterEntity) { if (param.Type.IsNullable) { var hasValueCondition = new ConditionStatement { Condition = arguments[param].CreateMemberReferenceExpression(nameof(Nullable <int> .HasValue)), TrueStatements = urlBuilder.CreateInvokeMethodExpression(nameof(UrlBuilder.WithValue), param.Name, arguments[param].CreateMemberReferenceExpression(nameof(Nullable <int> .Value), "Value")) }; m.Statements.Add(hasValueCondition); } else { m.Statements.Add(urlBuilder.CreateInvokeMethodExpression(nameof(UrlBuilder.WithValue), param.Name, arguments[param].CreateMemberReferenceExpression("Value"))); } } else { m.Statements.Add(urlBuilder.CreateInvokeMethodExpression(nameof(UrlBuilder.WithValue), param.Name, arguments[param])); } } if (pageArgument != null) { var pageCondition = new ConditionStatement() { Condition = new BinaryExpression(BinaryOperator.NotEquals, pageArgument, new LiteralExpression(null)), TrueStatements = new StatementCollection { new ConditionStatement() { Condition = new BinaryExpression(BinaryOperator.GreaterThan, pageArgument.CreateMemberReferenceExpression(nameof(PageOptions.PageIndex)), new LiteralExpression(0)), TrueStatements = new StatementCollection { urlBuilder.CreateInvokeMethodExpression(nameof(UrlBuilder.WithValue), "page", pageArgument.CreateMemberReferenceExpression(nameof(PageOptions.PageIndex))) } }, new ConditionStatement() { Condition = new BinaryExpression(BinaryOperator.GreaterThan, pageArgument.CreateMemberReferenceExpression(nameof(PageOptions.PageSize)), new LiteralExpression(0)), TrueStatements = new StatementCollection { urlBuilder.CreateInvokeMethodExpression(nameof(UrlBuilder.WithValue), "per_page", pageArgument.CreateMemberReferenceExpression(nameof(PageOptions.PageSize))) } }, new ConditionStatement() { Condition = new BinaryExpression(BinaryOperator.Equals, pageArgument.CreateMemberReferenceExpression(nameof(PageOptions.OrderBy), nameof(OrderBy.Name)).CreateIsNullOrEmptyExpression(), new LiteralExpression(false)), TrueStatements = new StatementCollection { urlBuilder.CreateInvokeMethodExpression(nameof(UrlBuilder.WithValue), "order_by", pageArgument.CreateMemberReferenceExpression(nameof(PageOptions.OrderBy), nameof(OrderBy.Name))), urlBuilder.CreateInvokeMethodExpression(nameof(UrlBuilder.WithValue), "sort", pageArgument.CreateMemberReferenceExpression(nameof(PageOptions.OrderBy), nameof(OrderBy.Direction))) } } } }; m.Statements.Add(pageCondition); } var url = new VariableDeclarationStatement(typeof(string), "url", urlBuilder.CreateInvokeMethodExpression(nameof(UrlBuilder.Build))); m.Statements.Add(url); var bodyArgument = CreateBodyArgument(method, m); switch (method.MethodType) { case MethodType.Get: if (method.ReturnType.IsCollection) { m.Statements.Add(new ReturnStatement(new ThisExpression().CreateInvokeMethodExpression("GetCollectionAsync", new TypeReference[] { method.ReturnType }, url, requestOptionsArgument, cancellationTokenArgument))); } else { m.Statements.Add(new ReturnStatement(new ThisExpression().CreateInvokeMethodExpression("GetAsync", new TypeReference[] { method.ReturnType }, url, requestOptionsArgument, cancellationTokenArgument))); } break; case MethodType.GetPaged: m.Statements.Add(new ReturnStatement(new ThisExpression().CreateInvokeMethodExpression("GetPagedAsync", new TypeReference[] { method.ReturnType }, url, requestOptionsArgument, cancellationTokenArgument))); break; case MethodType.Put: var putArgs = new List <Expression>(); putArgs.Add(url); putArgs.Add((Expression)bodyArgument ?? new LiteralExpression(null)); putArgs.Add(requestOptionsArgument); putArgs.Add(cancellationTokenArgument); m.Statements.Add(new ReturnStatement(new ThisExpression().CreateInvokeMethodExpression("PutJsonAsync", new TypeReference[] { method.ReturnType }, putArgs.ToArray()))); break; case MethodType.Post: var postArgs = new List <Expression>(); postArgs.Add(url); postArgs.Add((Expression)bodyArgument ?? new LiteralExpression(null)); postArgs.Add(requestOptionsArgument); postArgs.Add(cancellationTokenArgument); if (method.ReturnType != null) { m.Statements.Add(new ReturnStatement(new ThisExpression().CreateInvokeMethodExpression("PostJsonAsync", new TypeReference[] { method.ReturnType }, postArgs.ToArray()))); } else { m.Statements.Add(new ReturnStatement(new ThisExpression().CreateInvokeMethodExpression("PostJsonAsync", postArgs.ToArray()))); } break; case MethodType.Delete: m.Statements.Add(new ReturnStatement(new ThisExpression().CreateInvokeMethodExpression("DeleteAsync", url, requestOptionsArgument, cancellationTokenArgument))); break; default: throw new NotSupportedException($"Method {method.MethodType} is not supported"); } return(m); }
private void AddCopyToMethod(ClassDeclaration classDecl, TableSchema table) { var method = new CodeMemberMethod(); method.Attributes = MemberAttributes.Public | MemberAttributes.Final; method.Name = "CopyTo"; string argName = this.NameProvider.GetArgumentName(table.Name); var parameter = new CodeParameterDeclarationExpression(this.NameProvider.GetClassName(table), argName); method.Parameters.Add(parameter); foreach (ColumnSchema column in table.NonKeyColumns) { var lhs = new CodePropertyReferenceExpression(new CodeArgumentReferenceExpression(argName), this.NameProvider.GetPropertyName(column)); var rhs = new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), this.NameProvider.GetPropertyName(column)); method.Statements.Add(new CodeAssignStatement(lhs, rhs)); } foreach (ColumnSchema column in table.ForeignKeys) { string propertyName = this.NameProvider.GetPropertyName(column.Name.Replace("ID", "").Replace("_id", "")); var lhs = new CodePropertyReferenceExpression(new CodeArgumentReferenceExpression(argName), propertyName); var rhs = new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), propertyName); method.Statements.Add(new CodeAssignStatement(lhs, rhs)); } classDecl.AddMember(method); }