Skip to content

Commit

Permalink
cmd/cue: find packages by canonical path in get go
Browse files Browse the repository at this point in the history
Most Go APIs like go/types.Package.Path and go/packages.Package.PkgPath
use full canonical package paths, whereas go/packages.Package.Imports
uses source import paths as they appear in the import declarations.

We mixed the two, using paths from go/types to index into Imports,
resulting in nil packages in the edge cases when they are different.
One such instance is vendored packages, whose full path may be
"vendor/foo/bar" when they are simply imported as "foo/bar".

This also fixes a similar panic with some type aliases,
in particular when an alias points to an indirectly imported package,
as such a package would be missing from the Imports map.

The two added testscripts reproduced both panics without the fix,
and now work as expected with the fix.

Fixes #1607.
Fixes #2046.

Change-Id: I51df3465da76b39f031855982b48552604817f80
Signed-off-by: Thomas Way <[email protected]>
Co-authored-by: Daniel Martí <[email protected]>
Signed-off-by: Daniel Martí <[email protected]>
Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1173100
Reviewed-by: Paul Jolly <[email protected]>
Unity-Result: CUE porcuepine <[email protected]>
TryBot-Result: CUEcueckoo <[email protected]>
  • Loading branch information
uhthomas and mvdan committed Mar 18, 2024
1 parent 5489392 commit b648cf4
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 9 deletions.
33 changes: 24 additions & 9 deletions cmd/cue/cmd/get_go.go
Original file line number Diff line number Diff line change
Expand Up @@ -246,9 +246,10 @@ func (e *extractor) filter(name string) bool {
type extractor struct {
cmd *Command

stderr io.Writer
pkgs []*packages.Package
done map[string]bool
stderr io.Writer
pkgs []*packages.Package
allPkgs map[string]*packages.Package
done map[string]bool

// per package
orig map[types.Type]*ast.StructType
Expand Down Expand Up @@ -395,10 +396,11 @@ func extract(cmd *Command, args []string) error {
}

e := extractor{
cmd: cmd,
stderr: cmd.Stderr(),
pkgs: pkgs,
orig: map[types.Type]*ast.StructType{},
cmd: cmd,
stderr: cmd.Stderr(),
pkgs: pkgs,
allPkgs: map[string]*packages.Package{},
orig: map[types.Type]*ast.StructType{},
}

e.initExclusions(flagExclude.String(cmd))
Expand All @@ -407,6 +409,7 @@ func extract(cmd *Command, args []string) error {

for _, p := range pkgs {
e.done[p.PkgPath] = true
e.addPackage(p)
}

for _, p := range pkgs {
Expand All @@ -417,6 +420,19 @@ func extract(cmd *Command, args []string) error {
return nil
}

func (e *extractor) addPackage(p *packages.Package) {
if pkg, ok := e.allPkgs[p.PkgPath]; ok {
if p != pkg {
panic(fmt.Sprintf("duplicate package %s", p.PkgPath))
}
return
}
e.allPkgs[p.PkgPath] = p
for _, pkg := range p.Imports {
e.addPackage(pkg)
}
}

func (e *extractor) recordTypeInfo(p *packages.Package) {
for _, f := range p.Syntax {
ast.Inspect(f, func(n ast.Node) bool {
Expand Down Expand Up @@ -546,8 +562,7 @@ func (e *extractor) extractPkg(root string, p *packages.Package) error {
for path := range e.usedPkgs {
if !e.done[path] {
e.done[path] = true
p := p.Imports[path]
if err := e.extractPkg(root, p); err != nil {
if err := e.extractPkg(root, e.allPkgs[p.PkgPath]); err != nil {
return err
}
}
Expand Down
38 changes: 38 additions & 0 deletions cmd/cue/cmd/testdata/script/get_go_type_alias.txtar
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Issue 1607

exec cue get go --local ./x
cmp x/x_go_gen.cue x_go_gen.cue.golden

-- go.mod --
module mod.test

go 1.21
-- x/x.go --
package x

import "mod.test/y"

type X = y.Y

-- y/y.go --
package y

import "mod.test/z"

type Y = z.Z

-- z/z.go --
package z

type Z int

-- x_go_gen.cue.golden --
// Code generated by cue get go. DO NOT EDIT.

//cue:generate cue get go mod.test/x

package x

import "mod.test/z"

#X: z.#Z
38 changes: 38 additions & 0 deletions cmd/cue/cmd/testdata/script/get_go_vendor.txtar
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Issue 1607

exec cue get go --local ./x
cmp x/x_go_gen.cue x_go_gen.cue.golden

-- go.mod --
module mod.test

go 1.21
-- x/x.go --
package x

import "mod.test/y"

type X = y.Y

-- y/y.go --
package y

import "mod.test/z"

type Y = z.Z

-- z/z.go --
package z

type Z int

-- x_go_gen.cue.golden --
// Code generated by cue get go. DO NOT EDIT.

//cue:generate cue get go mod.test/x

package x

import "mod.test/z"

#X: z.#Z

0 comments on commit b648cf4

Please sign in to comment.