func (cache *MethodSetCache) lookupNamed(named *types.Named) struct{ value, pointer *types.MethodSet } { if cache.named == nil { cache.named = make(map[*types.Named]struct{ value, pointer *types.MethodSet }) } // Avoid recomputing mset(*T) for each distinct Pointer // instance whose underlying type is a named type. msets, ok := cache.named[named] if !ok { msets.value = types.NewMethodSet(named) msets.pointer = types.NewMethodSet(types.NewPointer(named)) cache.named[named] = msets } return msets }
// Type = // BasicType | TypeName | ArrayType | SliceType | StructType | // PointerType | FuncType | InterfaceType | MapType | ChanType | // "(" Type ")" . // // BasicType = ident . // TypeName = ExportedName . // SliceType = "[" "]" Type . // PointerType = "*" Type . // FuncType = "func" Signature . // func (p *parser) parseType() types.Type { switch p.tok { case scanner.Ident: switch p.lit { default: return p.parseBasicType() case "struct": return p.parseStructType() case "func": // FuncType p.next() return p.parseSignature(nil) case "interface": return p.parseInterfaceType() case "map": return p.parseMapType() case "chan": return p.parseChanType() } case '@': // TypeName pkg, name := p.parseExportedName() return declTypeName(pkg, name).Type() case '[': p.next() // look ahead if p.tok == ']' { // SliceType p.next() return types.NewSlice(p.parseType()) } return p.parseArrayType() case '*': // PointerType p.next() return types.NewPointer(p.parseType()) case '<': return p.parseChanType() case '(': // "(" Type ")" p.next() typ := p.parseType() p.expect(')') return typ } p.errorf("expected type, got %s (%q)", scanner.TokenString(p.tok), p.lit) return nil }
// IntuitiveMethodSet returns the intuitive method set of a type, T. // // The result contains MethodSet(T) and additionally, if T is a // concrete type, methods belonging to *T if there is no identically // named method on T itself. This corresponds to user intuition about // method sets; this function is intended only for user interfaces. // // The order of the result is as for types.MethodSet(T). // func IntuitiveMethodSet(T types.Type, msets *MethodSetCache) []*types.Selection { var result []*types.Selection mset := msets.MethodSet(T) if _, ok := T.Underlying().(*types.Interface); ok { for i, n := 0, mset.Len(); i < n; i++ { result = append(result, mset.At(i)) } } else { pmset := msets.MethodSet(types.NewPointer(T)) for i, n := 0, pmset.Len(); i < n; i++ { meth := pmset.At(i) if m := mset.Lookup(meth.Obj().Pkg(), meth.Obj().Name()); m != nil { meth = m } result = append(result, meth) } } return result }
// Smoke test to ensure that imported methods get the correct package. func TestCorrectMethodPackage(t *testing.T) { skipSpecialPlatforms(t) // This package only handles gc export data. if runtime.Compiler != "gc" { t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler) return } imports := make(map[string]*types.Package) _, err := Import(imports, "net/http") if err != nil { t.Fatal(err) } mutex := imports["sync"].Scope().Lookup("Mutex").(*types.TypeName).Type() mset := types.NewMethodSet(types.NewPointer(mutex)) // methods of *sync.Mutex sel := mset.Lookup(nil, "Lock") lock := sel.Obj().(*types.Func) if got, want := lock.Pkg().Path(), "sync"; got != want { t.Errorf("got package path %q; want %q", got, want) } }
// TODO(adonovan): // - test use of explicit hasher across two maps. // - test hashcodes are consistent with equals for a range of types // (e.g. all types generated by type-checking some body of real code). import ( "testing" "github.com/square/inspect/Godeps/_workspace/src/golang.org/x/tools/go/types" "github.com/square/inspect/Godeps/_workspace/src/golang.org/x/tools/go/types/typeutil" ) var ( tStr = types.Typ[types.String] // string tPStr1 = types.NewPointer(tStr) // *string tPStr2 = types.NewPointer(tStr) // *string, again tInt = types.Typ[types.Int] // int tChanInt1 = types.NewChan(types.RecvOnly, tInt) // <-chan int tChanInt2 = types.NewChan(types.RecvOnly, tInt) // <-chan int, again ) func checkEqualButNotIdentical(t *testing.T, x, y types.Type, comment string) { if !types.Identical(x, y) { t.Errorf("%s: not equal: %s, %s", comment, x, y) } if x == y { t.Errorf("%s: identical: %v, %v", comment, x, y) } }