1
0
mirror of https://github.com/golang/go synced 2024-11-18 11:04:42 -07:00

go/gcimporter15: support export/import of invalid aliases

+ test

Tested on 1.6, 1.7, and 1.8.

Fixes golang/go#17731.

Change-Id: I06dff4a72ff08ed5e8ae1d23a1e65fe719c03180
Reviewed-on: https://go-review.googlesource.com/32581
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Alan Donovan <adonovan@google.com>
This commit is contained in:
Robert Griesemer 2016-11-02 15:03:14 -07:00
parent c3ce94f8a8
commit f08d70c2ed
5 changed files with 99 additions and 29 deletions

View File

@ -177,24 +177,6 @@ func (p *exporter) pkg(pkg *types.Package, emptypath bool) {
}
func (p *exporter) obj(obj types.Object) {
if orig := original(obj); orig != obj {
if orig == nil {
// invalid alias - don't export for now (issue 17731)
return
}
if !p.reexported[orig] {
p.obj(orig)
p.reexported[orig] = true
}
p.tag(aliasTag)
p.pos(obj)
p.string(obj.Name())
p.qualifiedName(orig)
return
}
switch obj := obj.(type) {
case *types.Const:
p.tag(constTag)
@ -221,6 +203,20 @@ func (p *exporter) obj(obj types.Object) {
p.paramList(sig.Params(), sig.Variadic())
p.paramList(sig.Results(), false)
case *types_Alias:
// make sure the original is exported before the alias
// (if the alias declaration was invalid, orig will be nil)
orig := original(obj)
if orig != nil && !p.reexported[orig] {
p.obj(orig)
p.reexported[orig] = true
}
p.tag(aliasTag)
p.pos(obj)
p.string(obj.Name())
p.qualifiedName(orig)
default:
log.Fatalf("gcimporter: unexpected object %v (%T)", obj, obj)
}
@ -280,6 +276,10 @@ func commonPrefixLen(a, b string) int {
}
func (p *exporter) qualifiedName(obj types.Object) {
if obj == nil {
p.string("")
return
}
p.string(obj.Name())
p.pkg(obj.Pkg(), false)
}

View File

@ -0,0 +1,59 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build go1.8
package gcimporter_test
import (
"go/ast"
"go/parser"
"go/token"
"go/types"
"testing"
gcimporter "golang.org/x/tools/go/gcimporter15"
)
func TestInvalidAlias(t *testing.T) {
// parse and typecheck
const src = "package p; func InvalidAlias => foo.f"
fset1 := token.NewFileSet()
f, err := parser.ParseFile(fset1, "p.go", src, 0)
if err != nil {
t.Fatal(err)
}
var conf types.Config
pkg, err := conf.Check("p", fset1, []*ast.File{f}, nil)
if err == nil {
t.Fatal("invalid source type-checked without error")
}
if pkg == nil {
t.Fatal("nil package returned")
}
// export
exportdata := gcimporter.BExportData(fset1, pkg)
// import
imports := make(map[string]*types.Package)
fset2 := token.NewFileSet()
_, pkg2, err := gcimporter.BImportData(fset2, imports, exportdata, pkg.Path())
if err != nil {
t.Fatalf("BImportData(%s): %v", pkg.Path(), err)
}
// pkg2 must contain InvalidAlias as an invalid Alias
obj := pkg2.Scope().Lookup("InvalidAlias")
if obj == nil {
t.Fatal("InvalidAlias not found")
}
alias, ok := obj.(*types.Alias)
if !ok {
t.Fatalf("got %v; want alias", alias)
}
if alias.Type() != types.Typ[types.Invalid] || alias.Orig() != nil {
t.Fatalf("got %v (orig = %v); want invalid alias", alias, alias.Orig())
}
}

View File

@ -282,11 +282,13 @@ func (p *importer) obj(tag int) {
p.declare(types.NewFunc(pos, pkg, name, sig))
case aliasTag:
aliasPos := p.pos()
aliasName := p.string()
pkg, name := p.qualifiedName()
obj := pkg.Scope().Lookup(name)
p.declare(newAlias(aliasPos, p.pkgList[0], aliasName,obj))
pos := p.pos()
name := p.string()
var orig types.Object
if pkg, name := p.qualifiedName(); pkg != nil {
orig = pkg.Scope().Lookup(name)
}
p.declare(types_NewAlias(pos, p.pkgList[0], name, orig))
default:
errorf("unexpected object tag %d", tag)
@ -347,7 +349,9 @@ var (
func (p *importer) qualifiedName() (pkg *types.Package, name string) {
name = p.string()
pkg = p.pkg()
if name != "" {
pkg = p.pkg()
}
return
}

View File

@ -11,13 +11,18 @@ import (
"go/types"
)
func newAlias(pos token.Pos, pkg *types.Package, name string, orig types.Object) types.Object {
errorf("unexpected alias in non-Go1.8 export data: %s.%s => %v", pkg.Name(), name, orig)
type types_Alias struct {
types.Object
dummy int
} // satisfies types.Object but will never be encountered
func types_NewAlias(pos token.Pos, pkg *types.Package, name string, orig types.Object) types.Object {
errorf("unexpected alias in non-Go1.8 export data: %s.%s => %v", pkg.Name(), name, orig) // panics
panic("unreachable")
}
func original(obj types.Object) types.Object {
return obj // don't know about aliases
func original(types.Object) types.Object {
panic("unreachable")
}
const testfile = "exports17.go"

View File

@ -8,7 +8,9 @@ package gcimporter
import "go/types"
func newAlias => types.NewAlias
type types_Alias => types.Alias
func types_NewAlias => types.NewAlias
// TODO(gri) Consider exporting this functionality from go/types (issue 17730).
func original(obj types.Object) types.Object {