From 90aa993096adbf375b520ab66536805df1e293b6 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Mon, 29 Jul 2013 13:22:46 -0700 Subject: [PATCH] go.tools/go/types: provide package for imported methods Fixes golang/go#5815. R=adonovan CC=golang-dev https://golang.org/cl/12048043 --- go/types/gcimporter.go | 25 ++++++++++--------------- go/types/issues_test.go | 22 ++++++++++++++++++++++ 2 files changed, 32 insertions(+), 15 deletions(-) diff --git a/go/types/gcimporter.go b/go/types/gcimporter.go index 31dd824a..99ab146d 100644 --- a/go/types/gcimporter.go +++ b/go/types/gcimporter.go @@ -425,20 +425,23 @@ func (p *gcParser) parseMapType() Type { // Name = identifier | "?" | QualifiedName . // -// If materializePkg is set, a package is returned for fully qualified names. -// That package may be a fake package (without name, scope, and not in the -// p.imports map), created for the sole purpose of providing a package path -// for QualifiedNames. Fake packages are created when the package id is not -// found in the p.imports map; we cannot create a real package in that case -// because we don't have a package name. +// If materializePkg is set, the returned package is guaranteed to be set. +// For fully qualified names, the returned package may be a fake package +// (without name, scope, and not in the p.imports map), created for the +// sole purpose of providing a package path. Fake packages are created +// when the package id is not found in the p.imports map; in that case +// we cannot create a real package because we don't have a package name. +// For non-qualified names, the returned package is the imported package. // func (p *gcParser) parseName(materializePkg bool) (pkg *Package, name string) { switch p.tok { case scanner.Ident: + pkg = p.imports[p.id] name = p.lit p.next() case '?': // anonymous + pkg = p.imports[p.id] p.next() case '@': // exported name prefixed with package path @@ -611,10 +614,6 @@ func (p *gcParser) parseInterfaceType() Type { // TODO(gri) Ideally, we should use a named type here instead of // typ, for less verbose printing of interface method signatures. sig.recv = NewVar(token.NoPos, pkg, "", typ) - // TODO(gri): fix: pkg may be nil! - if pkg == nil { - pkg = p.imports[p.id] - } m := NewFunc(token.NoPos, pkg, name, sig) if alt := mset.insert(m); alt != nil { p.errorf("multiple methods named %s.%s", alt.Pkg().name, alt.Name()) @@ -902,7 +901,7 @@ func (p *gcParser) parseMethodDecl() { base := typ.(*Named) // parse method name, signature, and possibly inlined body - pkg, name := p.parseName(true) // unexported method names in imports are qualified with their package. + pkg, name := p.parseName(true) sig := p.parseFunc() sig.recv = recv @@ -910,10 +909,6 @@ func (p *gcParser) parseMethodDecl() { // and method exists already // TODO(gri) This is a quadratic algorithm - ok for now because method counts are small. if _, m := lookupMethod(base.methods, pkg, name); m == nil { - // TODO(gri): fix: pkg may be nil. - if pkg == nil { - pkg = p.imports[p.id] - } base.methods = append(base.methods, NewFunc(token.NoPos, pkg, name, sig)) } } diff --git a/go/types/issues_test.go b/go/types/issues_test.go index e55c300e..52fa48eb 100644 --- a/go/types/issues_test.go +++ b/go/types/issues_test.go @@ -79,3 +79,25 @@ var ( } } } + +func TestIssue5815(t *testing.T) { + pkg, err := GcImport(make(map[string]*Package), "strings") + if err != nil { + t.Fatal(err) + } + + for _, obj := range pkg.scope.elems { + if obj.Pkg() == nil { + t.Errorf("no pkg for %s", obj) + } + if tname, _ := obj.(*TypeName); tname != nil { + if named, _ := tname.typ.(*Named); named != nil { + for _, m := range named.methods { + if m.pkg == nil { + t.Errorf("no pkg for %s", m) + } + } + } + } + } +}