func (v *typeVisitor) parseMethods(iface *Interface, fields *ast.FieldList) { for _, field := range fields.List { switch typeNode := field.Type.(type) { case *ast.FuncType: if len(field.Names) != 1 { panic(fmt.Errorf("unexpected named fields in interface type %#v", field)) } method := &Method{ Name: field.Names[0].String(), Arguments: make([]DeclPair, 0, 10), Results: make([]DeclPair, 0, 10), } method.Public = ast.IsExported(method.Name) parseFuncType(method, typeNode) iface.Methods = append(iface.Methods, method) case *ast.Ident: if len(field.Names) != 0 { panic(fmt.Errorf("unexpected named fields in interface type %#v", field)) } elementType := v.elementType(typeNode) rel := &Relation{Target: elementType, RelType: Extension} iface.Relations = append(iface.Relations, rel) case *ast.SelectorExpr: if len(field.Names) != 0 { panic(fmt.Errorf("unexpected named fields in interface type %#v", field)) } elementType := v.elementType(typeNode) rel := &Relation{Target: elementType, RelType: Extension} iface.Relations = append(iface.Relations, rel) default: panic(fmt.Errorf("unexpected field type in interface type %#v on %+v", field, iface)) } } }
func (v *methodVisitor) visitFuncDecl(node *ast.FuncDecl) { if node.Recv == nil { return } recv := node.Recv.List[0] typeName := elementType(recv.Type) class, ok := v.name2class[typeName] if !ok { // unknown method receiver return } method := &Method{ Name: node.Name.String(), Arguments: make([]DeclPair, 0, 10), Results: make([]DeclPair, 0, 10), } method.Public = ast.IsExported(method.Name) parseFuncType(method, node.Type) class.Methods = append(class.Methods, method) }
func (v *typeVisitor) parseFields(cl *Class, prefix string, fields *ast.FieldList) { for _, field := range fields.List { multiplicity := "" switch fType := field.Type.(type) { case *ast.ArrayType: multiplicity = "*" // TODO: we should nested array struct in runtime.Memstats like: // type A struct { X []struct{ bool }; Y []*struct{ *A }; Z *[]struct{ []*A } } case *ast.StarExpr: if fType, ok := fType.X.(*ast.StructType); ok { // case: type A struct { X *struct{ bool } } if len(field.Names) == 0 { // anonymous field panic("anonymous struct is prohibited in go spec") } for _, name := range field.Names { v.parseFields(cl, prefix+name.String()+".", fType.Fields) } continue } case *ast.StructType: if len(field.Names) == 0 { // anonymous field panic("anonymous struct is prohibited in go spec") } for _, name := range field.Names { v.parseFields(cl, prefix+name.String()+".", fType.Fields) } continue } elementType := v.elementType(field.Type) switch { case isPrimitive(elementType) || isField(v.fieldPackages, elementType): f := &Field{Type: typeGoString(field.Type), Multiplicity: multiplicity} if len(field.Names) == 0 { // anonymous field f.Name = prefix + elementType cl.Fields = append(cl.Fields, f) } for _, name := range field.Names { f2 := *f f2.Name = prefix + name.String() f2.Public = ast.IsExported(f2.Name) cl.Fields = append(cl.Fields, &f2) } default: rel := &Relation{Target: elementType, Multiplicity: multiplicity} if len(field.Names) == 0 { // anonymous field if prefix == "" { rel.RelType = Composition } else { rel.Label = prefix + path.Ext(elementType)[1:] rel.RelType = Association } cl.Relations = append(cl.Relations, rel) } for _, name := range field.Names { rel2 := *rel rel2.Label = prefix + name.String() rel2.RelType = Association cl.Relations = append(cl.Relations, &rel2) } } } }