func (u *Unexporter) usedObjects() map[types.Object]bool { objs := make(map[types.Object]bool) for _, pkgInfo := range u.packages { // easy path for id, obj := range pkgInfo.Uses { // ignore builtin value if obj.Pkg() == nil { continue } // if it's a type from different package, store it if obj.Pkg() != pkgInfo.Pkg { objs[obj] = true } // embedded fields are marked as used, no much which package the original type belongs to, // so that they won't show up in the renaming list #16 if field := pkgInfo.Defs[id]; field != nil { // embdded field identifier is the same as it's type objs[field] = true } } } // Check assignability for key := range u.satisfy() { var ( lhs, rhs *types.Named ok bool ) if lhs, ok = key.LHS.(*types.Named); !ok { continue } switch r := key.RHS.(type) { case *types.Named: rhs = r case *types.Pointer: // the receiver could be a pointer, see #14 rhs = r.Elem().(*types.Named) default: continue } lset := u.msets.MethodSet(key.LHS) rset := u.msets.MethodSet(key.RHS) for i := 0; i < lset.Len(); i++ { obj := lset.At(i).Obj() // LHS are the abstract methods, they are only exported if there are other packages using it if lhs.Obj().Pkg() != rhs.Obj().Pkg() { objs[obj] = true } // if satisfied by type within the same package only, it should be unexported // however, we should not rename from the concret method side, but from the // interface side, carefully exclude concret methods that don't implement an abstract method (see #14, #17) rsel := rset.Lookup(rhs.Obj().Pkg(), obj.Name()) objs[rsel.Obj()] = true } } return objs }
func getConsts(named *types.Named) string { pkg := named.Obj().Pkg() var s []string for _, name := range pkg.Scope().Names() { obj := pkg.Scope().Lookup(name) if konst, ok := obj.(*types.Const); ok { if konst.Type() == named { s = append(s, strings.Replace(konst.Val().String(), "\"", "", -1)) } } } sort.Strings(s) return strings.Trim(strings.Join(s, " | "), " ") }
func (w *PkgWalker) lookupNamedField(named *types.Named, name string) *types.Named { if istruct, ok := named.Underlying().(*types.Struct); ok { for i := 0; i < istruct.NumFields(); i++ { field := istruct.Field(i) if field.Anonymous() { fieldType := orgType(field.Type()) if typ, ok := fieldType.(*types.Named); ok { if na := w.lookupNamedField(typ, name); na != nil { return na } } } else { if field.Name() == name { return named } } } } return nil }
func (g *Grapher) assignMethodPaths(named *types.Named, prefix []string, pkgscope bool) { for i := 0; i < named.NumMethods(); i++ { m := named.Method(i) path := append(append([]string{}, prefix...), m.Name()) g.paths[m] = path g.exported[m] = ast.IsExported(m.Name()) g.pkgscope[m] = pkgscope if s := m.Scope(); s != nil { g.assignPaths(s, path, false) } } if iface, ok := named.Underlying().(*types.Interface); ok { for i := 0; i < iface.NumExplicitMethods(); i++ { m := iface.Method(i) path := append(append([]string{}, prefix...), m.Name()) g.paths[m] = path g.exported[m] = ast.IsExported(m.Name()) g.pkgscope[m] = pkgscope if s := m.Scope(); s != nil { g.assignPaths(s, path, false) } } } }
func (d *DIBuilder) descriptorNamed(t *types.Named) llvm.Value { // Create a placeholder for the named type, to terminate cycles. placeholder := llvm.MDNode(nil) d.types.Set(t, placeholder) var diFile llvm.Value var line int if file := d.fset.File(t.Obj().Pos()); file != nil { line = file.Line(t.Obj().Pos()) diFile = d.getFile(file) } typedef := d.builder.CreateTypedef(llvm.DITypedef{ Type: d.DIType(t.Underlying()), Name: t.Obj().Name(), File: diFile, Line: line, }) placeholder.ReplaceAllUsesWith(typedef) return typedef }
func (w *PkgWalker) lookupNamedMethod(named *types.Named, name string) (types.Object, *types.Named) { if iface, ok := named.Underlying().(*types.Interface); ok { for i := 0; i < iface.NumMethods(); i++ { fn := iface.Method(i) if fn.Name() == name { return fn, named } } for i := 0; i < iface.NumEmbeddeds(); i++ { if obj, na := w.lookupNamedMethod(iface.Embedded(i), name); obj != nil { return obj, na } } return nil, nil } if istruct, ok := named.Underlying().(*types.Struct); ok { for i := 0; i < named.NumMethods(); i++ { fn := named.Method(i) if fn.Name() == name { return fn, named } } for i := 0; i < istruct.NumFields(); i++ { field := istruct.Field(i) if !field.Anonymous() { continue } if typ, ok := field.Type().(*types.Named); ok { if obj, na := w.lookupNamedMethod(typ, name); obj != nil { return obj, na } } } } return nil, nil }
// Type definitions are only carried through to Haxe to allow access to objects as if they were native Haxe classes. // TODO consider renaming func (l langType) TypeStart(nt *types.Named, err string) string { typName := "GoType" + l.LangName("", nt.String()) hxTyp := l.LangType(nt.Obj().Type(), false, nt.String()) ret := "" switch hxTyp { case "Object": ret += "class " + typName ret += " extends " + hxTyp + " {\n" default: ret += "abstract " + typName + "(" + hxTyp + ") from " + hxTyp + " to " + hxTyp + " {\n" } switch nt.Underlying().(type) { case *types.Struct: str := nt.Underlying().(*types.Struct) ret += "inline public function new(){ super new(" + strconv.Itoa(int(haxeStdSizes.Sizeof(nt.Obj().Type()))) + "); }\n" flds := []string{} for f := 0; f < str.NumFields(); f++ { fName := str.Field(f).Name() if len(fName) > 0 { if unicode.IsUpper(rune(fName[0])) { flds = append(flds, fName) } } } sort.Strings(flds) // make sure the fields are always in the same order in the file for _, fName := range flds { for f := 0; f < str.NumFields(); f++ { if fName == str.Field(f).Name() { haxeTyp := l.LangType(str.Field(f).Type(), false, nt.String()) fOff := fieldOffset(str, f) sfx := loadStoreSuffix(str.Field(f).Type(), true) ret += fmt.Sprintf("public var _%s(get,set):%s;\n", fName, haxeTyp) ret += fmt.Sprintf("function get__%s():%s { return get%s%d); }\n", fName, haxeTyp, sfx, fOff) ret += fmt.Sprintf("function set__%s(v:%s):%s { return set%s%d,v); }\n", fName, haxeTyp, haxeTyp, sfx, fOff) break } } } case *types.Array: ret += "inline public function new(){ super new(" + strconv.Itoa(int(haxeStdSizes.Sizeof(nt.Obj().Type()))) + "); }\n" default: // TODO not yet sure how to handle named types that are not structs ret += "inline public function new(v:" + hxTyp + ") { this = v; }\n" } meths := []string{} for m := 0; m < nt.NumMethods(); m++ { mName := nt.Method(m).Name() if len(mName) > 0 { if unicode.IsUpper(rune(mName[0])) { meths = append(meths, mName) } } } sort.Strings(meths) // make sure the methods always appear in the same order in the file for _, mName := range meths { for m := 0; m < nt.NumMethods(); m++ { meth := nt.Method(m) if mName == meth.Name() { sig := meth.Type().(*types.Signature) ret += "// " + mName + " " + sig.String() + "\n" ret += "public function _" + mName + "(" for p := 0; p < sig.Params().Len(); p++ { if p > 0 { ret += "," } ret += "_" + sig.Params().At(p).Name() + ":" + l.LangType(sig.Params().At(p).Type(), false, nt.String()) } ret += ")" switch sig.Results().Len() { case 0: ret += ":Void " case 1: ret += ":" + l.LangType(sig.Results().At(0).Type(), false, nt.String()) default: ret += ":{" for r := 0; r < sig.Results().Len(); r++ { if r > 0 { ret += "," } ret += fmt.Sprintf("r%d:%s", r, l.LangType(sig.Results().At(r).Type(), false, nt.String())) } ret += "}" } ret += "{\n\t" if sig.Results().Len() > 0 { ret += "return " } fnToCall := l.LangName( nt.Obj().Pkg().Name()+":"+sig.Recv().Type().String(), meth.Name()) ret += `Go_` + fnToCall + `.hx(this` for p := 0; p < sig.Params().Len(); p++ { ret += ", _" + sig.Params().At(p).Name() } ret += ");\n}\n" } } } l.PogoComp().WriteAsClass(typName, ret+"}\n") return "" //ret }
// addRuntimeType is called for each concrete type that can be the // dynamic type of some interface or reflect.Value. // Adapted from needMethods in go/ssa/builder.go // func (r *rta) addRuntimeType(T types.Type, skip bool) { if prev, ok := r.result.RuntimeTypes.At(T).(bool); ok { if skip && !prev { r.result.RuntimeTypes.Set(T, skip) } return } r.result.RuntimeTypes.Set(T, skip) mset := r.prog.MethodSets.MethodSet(T) if _, ok := T.Underlying().(*types.Interface); !ok { // T is a new concrete type. for i, n := 0, mset.Len(); i < n; i++ { sel := mset.At(i) m := sel.Obj() if m.Exported() { // Exported methods are always potentially callable via reflection. r.addReachable(r.prog.MethodValue(sel), true) } } // Add callgraph edge for each existing dynamic // "invoke"-mode call via that interface. for _, I := range r.interfaces(T) { sites, _ := r.invokeSites.At(I).([]ssa.CallInstruction) for _, site := range sites { r.addInvokeEdge(site, T) } } } // Precondition: T is not a method signature (*Signature with Recv()!=nil). // Recursive case: skip => don't call makeMethods(T). // Each package maintains its own set of types it has visited. var n *types.Named switch T := T.(type) { case *types.Named: n = T case *types.Pointer: n, _ = T.Elem().(*types.Named) } if n != nil { owner := n.Obj().Pkg() if owner == nil { return // built-in error type } } // Recursion over signatures of each exported method. for i := 0; i < mset.Len(); i++ { if mset.At(i).Obj().Exported() { sig := mset.At(i).Type().(*types.Signature) r.addRuntimeType(sig.Params(), true) // skip the Tuple itself r.addRuntimeType(sig.Results(), true) // skip the Tuple itself } } switch t := T.(type) { case *types.Basic: // nop case *types.Interface: // nop---handled by recursion over method set. case *types.Pointer: r.addRuntimeType(t.Elem(), false) case *types.Slice: r.addRuntimeType(t.Elem(), false) case *types.Chan: r.addRuntimeType(t.Elem(), false) case *types.Map: r.addRuntimeType(t.Key(), false) r.addRuntimeType(t.Elem(), false) case *types.Signature: if t.Recv() != nil { panic(fmt.Sprintf("Signature %s has Recv %s", t, t.Recv())) } r.addRuntimeType(t.Params(), true) // skip the Tuple itself r.addRuntimeType(t.Results(), true) // skip the Tuple itself case *types.Named: // A pointer-to-named type can be derived from a named // type via reflection. It may have methods too. r.addRuntimeType(types.NewPointer(T), false) // Consider 'type T struct{S}' where S has methods. // Reflection provides no way to get from T to struct{S}, // only to S, so the method set of struct{S} is unwanted, // so set 'skip' flag during recursion. r.addRuntimeType(t.Underlying(), true) case *types.Array: r.addRuntimeType(t.Elem(), false) case *types.Struct: for i, n := 0, t.NumFields(); i < n; i++ { r.addRuntimeType(t.Field(i).Type(), false) } case *types.Tuple: for i, n := 0, t.Len(); i < n; i++ { r.addRuntimeType(t.At(i).Type(), false) } default: panic(T) } }