Bug fixes and clean up how methods are added to an interface from

superclasses and protocols. Ensure that "Unavailable" attributes are
handled properly.
This commit is contained in:
Greg 2019-06-11 16:41:21 -04:00
parent 9a4fabda24
commit b0139b9aa8
4 changed files with 106 additions and 92 deletions

View File

@ -55,6 +55,8 @@ func discoverServices(p ns.CBPeripheral, e ns.NSError) {
case serv.UUID().IsEqualTo(ns.CBUUIDWithGoString("180A")): case serv.UUID().IsEqualTo(ns.CBUUIDWithGoString("180A")):
fmt.Printf("--device information service\n") fmt.Printf("--device information service\n")
p.DiscoverCharacteristics(ns.NSArray{}, serv) p.DiscoverCharacteristics(ns.NSArray{}, serv)
default:
fmt.Printf("--unknown service\n")
} }
return true return true
}) })

View File

@ -38,4 +38,4 @@ delegates:
- peripheralDidUpdateValueForCharacteristic - peripheralDidUpdateValueForCharacteristic
pragma: [ clang diagnostic ignored "-Wformat-security" ] pragma: [ clang diagnostic ignored "-Wformat-security" ]
autorelease: true gogc: true

View File

@ -50,7 +50,7 @@ func memtest2() {
o2 := ns.NSStringWithGoString("two string") // does not leak o2 := ns.NSStringWithGoString("two string") // does not leak
arr := ns.NSArrayWithObjects(o1,o2) arr := ns.NSArrayAlloc().InitWithObjects(o1,o2)
_ = arr _ = arr
runtime.GC() runtime.GC()

View File

@ -147,6 +147,7 @@ type Method struct {
Type *types.Type Type *types.Type
ClassMethod bool ClassMethod bool
Parameters []*Parameter Parameters []*Parameter
Unavailable bool
} }
//Fully disambiguated method name (m.GoName + all parameter names) //Fully disambiguated method name (m.GoName + all parameter names)
@ -360,6 +361,7 @@ func (w *Wrapper) AddInterface(n *ast.ObjCInterfaceDecl) {
if Debug { if Debug {
fmt.Printf("ast.ObjCInterfaceDecl: %s\n", n.Name) fmt.Printf("ast.ObjCInterfaceDecl: %s\n", n.Name)
} }
//fmt.Printf("AddInterface(%s)\n",n.Name)
w.addIntCat(n.Name, n.Children()) w.addIntCat(n.Name, n.Children())
} }
@ -371,6 +373,7 @@ func (w *Wrapper) AddCategory(n *ast.ObjCCategoryDecl) {
if len(ns) > 0 { if len(ns) > 0 {
switch x := ns[0].(type) { switch x := ns[0].(type) {
case *ast.ObjCInterface: case *ast.ObjCInterface:
//fmt.Printf("AddCategory(%s) -> %s\n",n.Name, x.Name)
w.addIntCat(x.Name, ns[1:]) w.addIntCat(x.Name, ns[1:])
return return
} }
@ -466,12 +469,13 @@ func (w *Wrapper) AddMethod(p *MethodCollection, x *ast.ObjCMethodDecl) {
Class: p.Class, Class: p.Class,
GoClass: strings.Title(p.Class), GoClass: strings.Title(p.Class),
ClassMethod: x.ClassMethod, ClassMethod: x.ClassMethod,
Unavailable: false,
} }
if Debug { if Debug {
fmt.Printf(" -- Method %s\n", m.Name) fmt.Printf(" -- Method %s\n", m.Name)
} }
var avail bool var avail bool
m.Parameters, avail = w.GetParms(x, p.Class) m.Parameters, avail, m.Unavailable = w.GetParms(x, p.Class)
if avail { if avail {
if Debug { if Debug {
fmt.Printf("%s: Adding %s (%d)\n", p.Class, m.Name, len(m.Parameters)) fmt.Printf("%s: Adding %s (%d)\n", p.Class, m.Name, len(m.Parameters))
@ -556,18 +560,6 @@ func (w *Wrapper) addIntCat(name string, ns []ast.Node) {
i.ClassMethods = NewMethodCollection(name) i.ClassMethods = NewMethodCollection(name)
i.Protocols = []string{} i.Protocols = []string{}
i.ProcessedInstanceMethods = map[string]bool{} i.ProcessedInstanceMethods = map[string]bool{}
/*
m := &Method{
Name: "class",
GoName: "Class",
Class: i.Name,
GoClass: i.Name,
Type: types.NewTypeFromString("Class",i.Name),
ClassMethod: true,
Parameters: []*Parameter{},
}
i.ClassMethods.Methods = []*Method{m}
*/
} }
avail := (*Avail)(&[]AvailAttr{}) avail := (*Avail)(&[]AvailAttr{})
mcc := NewMethodCollection(name) mcc := NewMethodCollection(name)
@ -641,52 +633,13 @@ func (w *Wrapper) addIntCat(name string, ns []ast.Node) {
i.InstanceMethods.Methods = append(i.InstanceMethods.Methods, mci.Methods...) i.InstanceMethods.Methods = append(i.InstanceMethods.Methods, mci.Methods...)
i.Protocols = append(i.Protocols, prots...) i.Protocols = append(i.Protocols, prots...)
//Add class methods from super class
var supmethods func(*Interface, string)
supmethods = func(i *Interface, s string) {
if sup, ok := w.Interfaces[s]; !ok {
return
} else {
//depth first
supmethods(i, types.Super(s))
for _, m := range sup.ClassMethods.Methods {
m2 := &Method{
Name: m.Name,
GoName: m.GoName,
Class: i.Name,
GoClass: i.GoName,
Type: m.Type.CloneToClass(i.Name),
ClassMethod: true,
Parameters: []*Parameter{},
}
for _, p := range m.Parameters {
p2 := &Parameter{
Pname: p.Pname,
Vname: p.Vname,
Type: p.Type.CloneToClass(i.Name),
}
m2.Parameters = append(m2.Parameters, p2)
}
found := false
longname := m2.LongName()
for n, x := range i.ClassMethods.Methods {
if x.LongName() == longname {
i.ClassMethods.Methods[n] = m2
found = true
}
}
if !found {
i.ClassMethods.Methods = append(i.ClassMethods.Methods, m2)
}
}
}
}
supmethods(i, types.Super(i.Name))
if Debug { if Debug {
fmt.Println("Add interface ", i.Name) fmt.Println("Add interface ", i.Name)
} }
//fmt.Printf("Interface = %s %d class methods, %d instance methods\n", i.Name, len(i.ClassMethods.Methods), len(i.InstanceMethods.Methods))
Disambiguate(i.ClassMethods) Disambiguate(i.ClassMethods)
Disambiguate(i.InstanceMethods) Disambiguate(i.InstanceMethods)
//fmt.Printf("Interface = %s (disambiguated) %d class methods, %d instance methods\n", i.Name, len(i.ClassMethods.Methods), len(i.InstanceMethods.Methods))
w.Interfaces[i.Name] = i w.Interfaces[i.Name] = i
} }
@ -735,8 +688,9 @@ func (a *Avail) Available() bool {
//GetParms returns the parameters of a method declaration and a bool //GetParms returns the parameters of a method declaration and a bool
//indicating whether the given method is available on MacOS and not //indicating whether the given method is available on MacOS and not
//deprecated. //deprecated.
func (w *Wrapper) GetParms(n ast.Node, class string) ([]*Parameter, bool) { func (w *Wrapper) GetParms(n ast.Node, class string) ([]*Parameter, bool, bool) {
ret := make([]*Parameter, 0) ret := make([]*Parameter, 0)
unavail := false
avail := (*Avail)(&[]AvailAttr{}) avail := (*Avail)(&[]AvailAttr{})
var parms []string var parms []string
switch x := n.(type) { switch x := n.(type) {
@ -768,7 +722,9 @@ func (w *Wrapper) GetParms(n ast.Node, class string) ([]*Parameter, bool) {
p.Type.Variadic = true p.Type.Variadic = true
ret = append(ret, p) ret = append(ret, p)
j++ j++
case *ast.AvailabilityAttr, *ast.UnavailableAttr, *ast.DeprecatedAttr: case *ast.UnavailableAttr:
unavail = true
case *ast.AvailabilityAttr, *ast.DeprecatedAttr:
avail.Add(x) avail.Add(x)
case *ast.Unknown: case *ast.Unknown:
if Debug { if Debug {
@ -778,9 +734,9 @@ func (w *Wrapper) GetParms(n ast.Node, class string) ([]*Parameter, bool) {
} }
// check that the method is available for this OS and not deprecated // check that the method is available for this OS and not deprecated
if !avail.Available() { if !avail.Available() {
return nil, false return nil, false, unavail
} }
return ret, true return ret, true, unavail
} }
func (w *Wrapper) AddTypedef(n, t string) { func (w *Wrapper) AddTypedef(n, t string) {
@ -888,20 +844,7 @@ func (e NSEnumerator) ForIn(f func(Id) bool) {
} }
func (w *Wrapper) AutoreleaseHelpers() { func (w *Wrapper) AutoreleaseHelpers() {
//not sure why this is not coming up automatically...
w.cCode.WriteString(`
void* _Nonnull
NSAutoreleasePool_init(void* o) {
return [(NSAutoreleasePool*)o init];
}
`)
w.goHelpers.WriteString(` w.goHelpers.WriteString(`
func (o NSAutoreleasePool) Init() NSAutoreleasePool {
ret := NSAutoreleasePool{}
ret.ptr = C.NSAutoreleasePool_init(o.Ptr())
return ret
}
func Autoreleasepool(f func()) { func Autoreleasepool(f func()) {
pool := NSAutoreleasePoolAlloc().Init() pool := NSAutoreleasePoolAlloc().Init()
f() f()
@ -960,6 +903,9 @@ func (w *Wrapper) _processMethod(m *Method, fun bool) {
if m.HasUnsupportedType() { if m.HasUnsupportedType() {
return return
} }
if m.Unavailable {
return
}
w.processType(m.Type) w.processType(m.Type)
gname := m.GoName gname := m.GoName
gname = strings.ReplaceAll(gname, "_", " ") gname = strings.ReplaceAll(gname, "_", " ")
@ -1809,6 +1755,74 @@ func (o %s) Super%s(%s) %s {
w.goExports.WriteString(goexports.String()) w.goExports.WriteString(goexports.String())
} }
//Add class and instance methods from super class
func (w *Wrapper) AddSupermethods(i *Interface) {
var supmethods func(string)
procsups := func(mc, smc *MethodCollection) {
for _, m := range smc.Methods {
m2 := &Method{
Name: m.Name,
GoName: m.GoName,
Class: i.Name,
GoClass: i.GoName,
Type: m.Type.CloneToClass(i.Name),
ClassMethod: m.ClassMethod,
Parameters: []*Parameter{},
Unavailable: m.Unavailable,
}
for _, p := range m.Parameters {
p2 := &Parameter{
Pname: p.Pname,
Vname: p.Vname,
Type: p.Type.CloneToClass(i.Name),
}
m2.Parameters = append(m2.Parameters, p2)
}
mc.Methods = append(mc.Methods, m2)
}
}
supmethods = func(s string) {
if sup, ok := w.Interfaces[s]; !ok {
return
} else {
procsups(i.ClassMethods, sup.ClassMethods)
procsups(i.InstanceMethods, sup.InstanceMethods)
// depth last
supmethods(types.Super(s))
}
}
supmethods(types.Super(i.Name))
}
//Add methods from a Protocol
func (w *Wrapper) AddProtocolMethods(i *Interface, p *Protocol) {
procmeths := func(mc, pmc *MethodCollection) {
for _, m := range pmc.Methods {
m2 := &Method{
Name: m.Name,
GoName: m.GoName,
Class: i.Name,
GoClass: i.GoName,
Type: m.Type.CloneToClass(i.Name),
ClassMethod: m.ClassMethod,
Parameters: []*Parameter{},
Unavailable: m.Unavailable,
}
for _, p := range m.Parameters {
p2 := &Parameter{
Pname: p.Pname,
Vname: p.Vname,
Type: p.Type.CloneToClass(i.Name),
}
m2.Parameters = append(m2.Parameters,p2)
}
mc.Methods = append(mc.Methods, m2)
}
}
procmeths(i.ClassMethods, p.ClassMethods)
procmeths(i.InstanceMethods, p.InstanceMethods)
}
func (w *Wrapper) Wrap(toproc []string) { func (w *Wrapper) Wrap(toproc []string) {
if w.Package == "" { if w.Package == "" {
w.Package = "ns" w.Package = "ns"
@ -1847,13 +1861,7 @@ func (w *Wrapper) Wrap(toproc []string) {
if i.Name == "NSEnumerator" { if i.Name == "NSEnumerator" {
w.EnumeratorHelpers() w.EnumeratorHelpers()
} }
/*gname := i.GoName w.AddSupermethods(i)
if types.IsGoInterface(i.GoName) {
gname = "Id"
}
*/
fmt.Printf("Interface %s: %d properties, %d class methods, %d instance methods\n",
i.Name, len(i.Properties), len(i.ClassMethods.Methods), len(i.InstanceMethods.Methods))
//FIXME: sort properties //FIXME: sort properties
for _, p := range i.Properties { for _, p := range i.Properties {
@ -1863,12 +1871,6 @@ func (w *Wrapper) Wrap(toproc []string) {
fmt.Printf(" property: %s (%s)\n", p.Name, p.Type.CType()) fmt.Printf(" property: %s (%s)\n", p.Name, p.Type.CType())
} }
} }
for _, m := range i.ClassMethods.Methods {
w.ProcessMethod(m)
}
for _, m := range i.InstanceMethods.Methods {
w.ProcessMethod(m)
}
// add methods for Protocols that this interface implements // add methods for Protocols that this interface implements
for _, p := range i.Protocols { for _, p := range i.Protocols {
prot, ok := w.Protocols[p] prot, ok := w.Protocols[p]
@ -1876,12 +1878,22 @@ func (w *Wrapper) Wrap(toproc []string) {
fmt.Printf("Failed to find protocol %s for interface %s\n", p, i.Name) fmt.Printf("Failed to find protocol %s for interface %s\n", p, i.Name)
os.Exit(-1) os.Exit(-1)
} }
for _, m := range prot.ClassMethods.Methods { w.AddProtocolMethods(i,prot)
w.ProcessMethodForClass(m, i.Name) // for _, m := range prot.ClassMethods.Methods {
// w.ProcessMethodForClass(m, i.Name)
// }
// for _, m := range prot.InstanceMethods.Methods {
// w.ProcessMethodForClass(m, i.Name)
// }
} }
for _, m := range prot.InstanceMethods.Methods { Disambiguate(i.ClassMethods)
w.ProcessMethodForClass(m, i.Name) Disambiguate(i.InstanceMethods)
fmt.Printf("Interface %s: %d properties, %d class methods, %d instance methods\n", i.Name, len(i.Properties), len(i.ClassMethods.Methods), len(i.InstanceMethods.Methods))
for _, m := range i.ClassMethods.Methods {
w.ProcessMethod(m)
} }
for _, m := range i.InstanceMethods.Methods {
w.ProcessMethod(m)
} }
} }
for _, m := range w.Functions { for _, m := range w.Functions {