func (r *reader) obj(x ast.Expr) types.Object { switch x := x.(type) { case *ast.Ident: if obj := r.scope.LookupParent(x.Name); obj != nil { if v, ok := obj.(*types.Var); ok && v.Pkg == nil { // ignore local vars return nil } return obj } return unknownObject{pkg: r.pkg, name: x.Name} case *ast.SelectorExpr: // TODO: Type.Method and pkg.Type.Method n1 := name(x.X) n2 := x.Sel.Name switch obj := r.scope.LookupParent(n1).(type) { case *types.PkgName: if obj := obj.Pkg.Scope().Lookup(n2); obj != nil { return obj } return unknownObject{pkg: obj.Pkg, name: n2} case *types.Var: t := obj.Type fm, _, addr := types.LookupFieldOrMethod(t, r.pkg, n2) switch fm := fm.(type) { case *types.Func: sig := fm.Type.(*types.Signature) return types.NewFunc(0, r.pkg, n2, types.NewSignature(nil, newVar("", t), sig.Params, sig.Results, sig.IsVariadic)) case *types.Var: return field{fm, t, addr} } return unknownObject{pkg: obj.Pkg, recv: t, name: n2} } } panic("unreachable") }
func (r *reader) value(b *block, x, y ast.Expr, set bool, s ast.Stmt) { if x2, ok := x.(*ast.UnaryExpr); ok { x = x2.X } var obj types.Object if _, ok := x.(*ast.StarExpr); !ok { // StarExpr indicates an assignment (*x = y), for which obj must be nil obj = r.obj(x) if u, ok := obj.(unknownObject); ok { if _, ok := s.(*ast.DeclStmt); ok { obj = types.NewConst(0, u.pkg, u.name, nil, nil) } else { var t types.Type if set { t = r.scope.Lookup(name(y)).(*types.Var).Type } addr := false if s, ok := s.(*ast.AssignStmt); ok { if s.Tok == token.DEFINE { _, addr = s.Rhs[0].(*ast.UnaryExpr) } } if u.recv != nil { obj = field{types.NewVar(0, u.pkg, u.name, t), u.recv, addr} // it may be a method val, but a non-addressable field is close enough } else { if addr { obj = types.NewVar(0, u.pkg, u.name, t) } else { obj = types.NewFunc(0, u.pkg, u.name, types.NewSignature(nil, newVar("", u.recv), nil, nil, false)) } } } //unknown(obj) == true } } n := newValueNode(obj, r.pkg, set) b.addNode(n) switch x := x.(type) { case *ast.SelectorExpr: r.in(x.X, n.x) case *ast.StarExpr: r.in(x.X, n.x) } if set { r.in(y, n.y) } else { r.out(y, n.y) } r.seq(n, s) }
func (r *reader) typ(x ast.Expr) types.Type { switch x := x.(type) { case *ast.Ident: if t, ok := r.scope.LookupParent(x.Name).(*types.TypeName); ok { return t.Type } return types.NewNamed(types.NewTypeName(0, r.pkg, x.Name, nil), types.Typ[types.Invalid], nil) //unknown(t.Obj) == true case *ast.SelectorExpr: pkg := r.scope.LookupParent(name(x.X)).(*types.PkgName).Pkg if t, ok := pkg.Scope().Lookup(x.Sel.Name).(*types.TypeName); ok { return t.Type } return types.NewNamed(types.NewTypeName(0, r.pkg, x.Sel.Name, nil), types.Typ[types.Invalid], nil) //unknown(t.Obj) == true case *ast.StarExpr: return types.NewPointer(r.typ(x.X)) case *ast.ArrayType: elem := r.typ(x.Elt) if x.Len != nil { // TODO: x.Len return types.NewArray(elem, 0) } return types.NewSlice(elem) case *ast.Ellipsis: return types.NewSlice(r.typ(x.Elt)) case *ast.MapType: return types.NewMap(r.typ(x.Key), r.typ(x.Value)) case *ast.ChanType: dir := types.SendRecv if x.Dir&ast.SEND == 0 { dir = types.RecvOnly } if x.Dir&ast.RECV == 0 { dir = types.SendOnly } return types.NewChan(dir, r.typ(x.Value)) case *ast.FuncType: var params, results []*types.Var for _, f := range x.Params.List { t := r.typ(f.Type) if f.Names == nil { params = append(params, types.NewParam(0, r.pkg, "", t)) } for _, n := range f.Names { params = append(params, types.NewParam(0, r.pkg, n.Name, t)) } } variadic := false if x.Results != nil { for _, f := range x.Results.List { t := r.typ(f.Type) if f.Names == nil { results = append(results, types.NewParam(0, r.pkg, "", t)) } for _, n := range f.Names { results = append(results, types.NewParam(0, r.pkg, n.Name, t)) } _, variadic = f.Type.(*ast.Ellipsis) } } return types.NewSignature(nil, nil, params, results, variadic) case *ast.StructType: var fields []*types.Var if x.Fields != nil { for _, f := range x.Fields.List { t := r.typ(f.Type) if f.Names == nil { fields = append(fields, types.NewField(0, r.pkg, "", t, true)) } for _, n := range f.Names { fields = append(fields, types.NewField(0, r.pkg, n.Name, t, false)) } } } return types.NewStruct(fields, nil) case *ast.InterfaceType: var methods []*types.Func var embeddeds []*types.Named if x.Methods != nil { for _, f := range x.Methods.List { switch t := r.typ(f.Type).(type) { case *types.Signature: methods = append(methods, types.NewFunc(0, r.pkg, f.Names[0].Name, t)) case *types.Named: embeddeds = append(embeddeds, t) } } } return types.NewInterface(methods, embeddeds) } panic("unreachable") }