package main import ( "go/types" "sort" "strings" "golang.org/x/tools/go/packages" "go.mau.fi/mautrix-telegram/pkg/gotd/telegram/query/internal/genutil" ) func isHashField(field *types.Var) bool { basic, ok := field.Type().(*types.Basic) if !ok { return false } return basic.Kind() == types.Int64 && field.Name() == "Hash" } func hasHashField(st *types.Struct) bool { for i := 0; i < st.NumFields(); i++ { if isHashField(st.Field(i)) { return true } } return false } type request struct { name string params []Param } func isCachedQuery(args *types.Tuple) (request, bool) { arg := args.At(1) switch req := arg.Type().(type) { case *types.Pointer: named, ok := req.Elem().(*types.Named) if !ok { return request{}, false } st, ok := named.Underlying().(*types.Struct) if !ok { return request{}, false } var r []Param for i := 0; i < st.NumFields(); i++ { field := st.Field(i) if strings.Contains(field.Name(), "Offset") { return request{}, false } if isHashField(field) || field.Name() == "Flags" { continue } r = append(r, varToParam(field)) } return request{ name: named.Obj().Name(), params: sortParams(r), }, hasHashField(st) case *types.Basic: if req.Kind() != types.Int64 || arg.Name() != "hash" { return request{}, false } return request{}, true default: return request{}, false } } func collect(pkg *packages.Package) []CachedQuery { var r []CachedQuery for _, def := range genutil.Funcs(pkg, func(f genutil.Func) bool { return f.Args().Len() == 2 && f.Results().Len() == 2 }) { args := def.Args() req, ok := isCachedQuery(args) if !ok { continue } resultNamed, ok := def.Results().At(0).Type().(*types.Named) if !ok { continue } result, ok := resultNamed.Underlying().(*types.Interface) if !ok { continue } impls := genutil.Implementations(pkg, result) if len(impls) != 2 { continue } var ( notModified *types.Named pure *types.Named ) for _, impl := range impls { if notModified == nil && strings.Contains(impl.Obj().Name(), "NotModified") { notModified = impl continue } if pure == nil { pure = impl } } if pure == nil || notModified == nil { continue } pureStruct, ok := pure.Underlying().(*types.Struct) if !ok { continue } r = append(r, CachedQuery{ Name: def.Decl.Name(), MethodName: def.Decl.Name(), RequestName: req.name, ManualHash: !hasHashField(pureStruct), RequestParams: req.params, ResultName: pure.Obj().Name(), NotModifiedName: notModified.Obj().Name(), }) } sort.SliceStable(r, func(i, j int) bool { return r[i].Name < r[j].Name }) return r }