private static IEnumerable <MemberDeclarationSyntax> PaginatedPartialClasses(SourceFileContext ctx, ServiceDetails svc, HashSet <Typ> seenPaginatedResponseTyps) { var paginatedMethods = svc.Methods.OfType <MethodDetails.Paginated>(); foreach (var representingMethod in paginatedMethods .GroupBy(m => m.RequestTyp) .Select(typMethodGrp => typMethodGrp.First())) { yield return(PaginatedPartialInterfaceClass(ctx, representingMethod.RequestTyp, representingMethod.RequestMessageDesc)); } foreach (var method in paginatedMethods) { if (seenPaginatedResponseTyps.Add(method.ResponseTyp)) { var cls = Class(Public | Partial, method.ResponseTyp, baseTypes: ctx.Type(Typ.Generic(typeof(IPageResponse <>), method.ResourceTyp))); using (ctx.InClass(cls)) { var propertyName = method.ResourcesFieldName; var genericGetEnumerator = Method(Public, ctx.Type(Typ.Generic(typeof(IEnumerator <>), method.ResourceTyp)), "GetEnumerator")() .WithBody(Property(Public, ctx.TypeDontCare, propertyName).Call(nameof(IEnumerable <int> .GetEnumerator))()) .WithXmlDoc(XmlDoc.Summary("Returns an enumerator that iterates through the resources in this response.")); var getEnumerator = Method(None, ctx.Type <IEnumerator>(), "GetEnumerator")() .WithExplicitInterfaceSpecifier(ctx.Type <IEnumerable>()) .WithBody(This.Call(genericGetEnumerator)()); cls = cls.AddMembers(genericGetEnumerator, getEnumerator); } yield return(cls); } } }
private MethodDeclarationSyntax AbstractRequestMethod(bool sync, bool callSettings, IEnumerable <ParameterInfo> parameters, DocumentationCommentTriviaSyntax returnsXmlDoc = null) { var returnTyp = sync ? MethodDetails.SyncReturnTyp : MethodDetails.AsyncReturnTyp; var methodName = sync ? MethodDetails.SyncMethodName : MethodDetails.AsyncMethodName; var finalParam = callSettings ? _def.CallSettingsParam : _def.CancellationTokenParam; var finalParamXmlDoc = callSettings ? _def.CallSettingsXmlDoc : _def.CancellationTokenXmlDoc; returnsXmlDoc = returnsXmlDoc ?? (sync ? MethodDetails is MethodDetails.Paginated ? _def.ReturnsSyncPaginatedXmlDoc : _def.ReturnsSyncXmlDoc : MethodDetails is MethodDetails.Paginated ? _def.ReturnsAsyncPaginatedXmlDoc : _def.ReturnsAsyncXmlDoc); if (callSettings) { return(Method(Public | Virtual, Ctx.Type(returnTyp), methodName)(parameters.Select(x => x.Parameter).Append(finalParam).ToArray()) .MaybeWithAttribute(MethodDetails.IsDeprecated || _sig.HasDeprecatedField, () => Ctx.Type <ObsoleteAttribute>())() .WithBody(This.Call(methodName)(New(Ctx.Type(MethodDetails.RequestTyp))() .WithInitializer(NestInit(parameters, 0).ToArray()), finalParam)) .WithXmlDoc(parameters.Select(x => x.XmlDoc).Prepend(_def.SummaryXmlDoc).Append(finalParamXmlDoc).Append(returnsXmlDoc).ToArray())); IEnumerable <ObjectInitExpr> NestInit(IEnumerable <ParameterInfo> ps, int ofs) { var byField = ps.GroupBy(x => (x.FieldDescs ?? Enumerable.Empty <FieldDescriptor>()).Skip(ofs).SkipLast(1).FirstOrDefault()) .OrderBy(x => x.Key?.Index); foreach (var f in byField) { if (f.Key == null) { // No more nesting, these are the actual fields that need filling. foreach (var param in f.OrderBy(x => x.FieldDescs?.Last().Index ?? int.MaxValue)) { // Note: even if the signature includes a deprecated field, we don't indicate that in the // ObjectInitExpr, as we don't want or need the pragma when the method we're generating is obsolete. yield return((param.InitExpr as ObjectInitExpr) ?? new ObjectInitExpr(param.ResourcePropertyName ?? param.FieldDescs.Last().CSharpPropertyName(), param.InitExpr)); } } else { // Nested field. var code = New(Ctx.Type(ProtoTyp.Of(f.Key)))().WithInitializer(NestInit(f, ofs + 1).ToArray()); yield return(new ObjectInitExpr(f.Key.CSharpPropertyName(), code)); } } } } else { return(Method(Public | Virtual, Ctx.Type(returnTyp), methodName)(parameters.Select(x => x.Parameter).Append(finalParam).ToArray()) .MaybeWithAttribute(MethodDetails.IsDeprecated || _sig.HasDeprecatedField, () => Ctx.Type <ObsoleteAttribute>())() .WithBody(This.Call(methodName)(parameters.Select(x => (object)x.Parameter).Append( Ctx.Type <CallSettings>().Call(nameof(CallSettings.FromCancellationToken))(finalParam)))) .WithXmlDoc(parameters.Select(x => x.XmlDoc).Prepend(_def.SummaryXmlDoc).Append(finalParamXmlDoc).Append(returnsXmlDoc).ToArray())); } }
private IEnumerable <MethodDeclarationSyntax> FormatMethods() { bool first = true; foreach (var pattern in PatternDetails) { var xmlDoc = pattern.PathElements.Select(x => x.ParameterXmlDoc) .Prepend(XmlDoc.Summary("Formats the IDs into the string representation of this ", _ctx.Type(_def.ResourceNameTyp), " with pattern ", XmlDoc.C(pattern.PatternString), ".")) .Append(XmlDoc.Returns("The string representation of this ", _ctx.Type(_def.ResourceNameTyp), " with pattern ", XmlDoc.C(pattern.PatternString), ".")) .ToArray(); var expandArgs = pattern.PathSegments.Where(x => x.Segment.ParameterCount > 0).Select(x => { if (x.Segment.IsComplex) { var dollarItems = x.Elements.Zip(x.Segment.Separators.Select(x => x.ToString()).Append(""), (element, sep) => (FormattableString) $"{Parens(_ctx.Type(typeof(GaxPreconditions)).Call(nameof(GaxPreconditions.CheckNotNullOrEmpty))(element.Parameter, Nameof(element.Parameter)))}{sep:raw}"); return((object)Dollar(dollarItems.ToArray())); } else { return(_ctx.Type(typeof(GaxPreconditions)).Call(nameof(GaxPreconditions.CheckNotNullOrEmpty))(x.Elements[0].Parameter, Nameof(x.Elements[0].Parameter))); } }); var method = Method(Public | Static, _ctx.Type <string>(), $"Format{pattern.UpperName}")(pattern.PathElements.Select(x => x.Parameter).ToArray()) .WithBody(Return(pattern.PathTemplateField.Call(nameof(PathTemplate.Expand))(expandArgs))) .WithXmlDoc(xmlDoc); if (first) { yield return(Method(Public | Static, _ctx.Type <string>(), "Format")(pattern.PathElements.Select(x => x.Parameter).ToArray()) .WithBody(Return(This.Call(method)(pattern.PathElements.Select(x => x.Parameter)))) .WithXmlDoc(xmlDoc)); first = false; } yield return(method); } }
private IEnumerable <MethodDeclarationSyntax> ParseMethods() { var paramName = _def.ResourceNameTyp.Name.ToLowerCamelCase(); var name = Parameter(_ctx.Type <string>(), paramName); var allowUnparsed = Parameter(_ctx.Type <bool>(), "allowUnparsed"); var result = Parameter(_ctx.Type(_def.ResourceNameTyp), "result").Out(); var resultLocal = Local(_ctx.Type(_def.ResourceNameTyp), "result"); var resourceName = Local(_ctx.Type <TemplatedResourceName>(), paramName == "resourceName" ? "resourceName2" : "resourceName"); var unparsedResourceName = Local(_ctx.Type <UnparsedResourceName>(), "unparsedResourceName"); MethodDeclarationSyntax parseSplitHelper; if (PatternDetails.SelectMany(x => x.PathSegments).Any(x => x.Segment.IsComplex)) { var s = Parameter(_ctx.Type <string>(), "s"); var separators = Parameter(_ctx.ArrayType <char[]>(), "separators"); var i0 = Local(_ctx.Type <int>(), "i0"); var i1 = Local(_ctx.Type <int>(), "i1"); var i = Local(_ctx.Type <int>(), "i"); var pshResult = Local(_ctx.ArrayType <string[]>(), "result"); parseSplitHelper = Method(Private | Static, _ctx.ArrayType <string[]>(), "ParseSplitHelper")(s, separators) .WithBody( pshResult.WithInitializer(NewArray(_ctx.ArrayType <string[]>(), separators.Access(nameof(Array.Length)).Plus(1))), i0.WithInitializer(0), For(i.WithInitializer(0), i.LessThanOrEqual(separators.Access(nameof(Array.Length))), i.PlusPlus())( i1.WithInitializer(i.LessThan(separators.Access(nameof(Array.Length))).ConditionalOperator( s.Call(nameof(string.IndexOf))(separators.ElementAccess(i), i0), s.Access(nameof(string.Length)))), If(i1.LessThan(0).Or(i1.Equality(i0))).Then(Return(Null)), pshResult.ElementAccess(i).Assign(s.Call(nameof(string.Substring))(i0, i1.Minus(i0))), i0.Assign(i1.Plus(1))), Return(pshResult)); } else { parseSplitHelper = null; } var tryParse2 = Method(Public | Static, _ctx.Type <bool>(), "TryParse")(name, allowUnparsed, result) .WithBody( _ctx.Type(typeof(GaxPreconditions)).Call(nameof(GaxPreconditions.CheckNotNull))(name, Nameof(name)), resourceName, PatternDetails.Zip(FromMethods(), (pattern, create) => { IEnumerable <(object code, IEnumerable <ExpressionSyntax> args)> codeAndArgs = pattern.PathSegments .Where(x => x.Segment.ParameterCount > 0) .Select((seg, segmentIndex) => { if (seg.Segment.IsComplex) { var splitResult = Local(_ctx.ArrayType <string[]>(), $"split{segmentIndex}") .WithInitializer(This.Call(parseSplitHelper)( resourceName.ElementAccess(segmentIndex), NewArray(_ctx.ArrayType <char[]>())(seg.Segment.Separators.ToArray()))); var splitIf = If(splitResult.Equality(Null)).Then( result.Assign(Null), Return(false)); var args = Enumerable.Range(0, seg.Segment.ParameterCount).Select(i => splitResult.ElementAccess(i)); return((object)new object[] { splitResult, splitIf }, args); } else { return((object)null, new[] { resourceName.ElementAccess(segmentIndex) }); } }); var elements = codeAndArgs.SelectMany(x => x.args); return(If(pattern.PathTemplateField.Call(nameof(PathTemplate.TryParseName))(name, Out(resourceName))).Then( codeAndArgs.Select(x => x.code), result.Assign(This.Call(create)(elements.ToArray())), Return(true))); }),