diff --git a/unused/testdata/src/alias/alias.go b/unused/testdata/src/alias/alias.go index 5d05524db..af296600e 100644 --- a/unused/testdata/src/alias/alias.go +++ b/unused/testdata/src/alias/alias.go @@ -1,5 +1,7 @@ package main +import "net/http" + type t1 struct{} // used type t2 struct{} // unused type t3 struct{} // used @@ -13,3 +15,20 @@ func main() { // used var _ alias1 var _ t3 } + +type t4 struct { // used + x int // used +} + +func (t4) foo() {} // used + +//lint:ignore U1000 alias5 is ignored, which also ignores t4 +type alias5 = t4 // used + +//lint:ignore U1000 alias6 is ignored, and we don't incorrectly try to include http.Server's fields and methods in the graph +type alias6 = http.Server // used + +//lint:ignore U1000 aliases don't have to be to named types +type alias7 = struct { // used + x int // used +} diff --git a/unused/unused.go b/unused/unused.go index 3b1ed1702..fd51d381d 100644 --- a/unused/unused.go +++ b/unused/unused.go @@ -1206,6 +1206,17 @@ func (g *graph) entry(pkg *pkg) { // use methods and fields of ignored types if obj, ok := obj.(*types.TypeName); ok { + if obj.IsAlias() { + if typ, ok := obj.Type().(*types.Named); ok && typ.Obj().Pkg() != obj.Pkg() { + // This is an alias of a named type in another package. + // Don't walk its fields or methods; we don't have to, + // and it breaks an assertion in graph.use because we're using an object that we haven't seen before. + // + // For aliases to types in the same package, we do want to ignore the fields and methods, + // because ignoring the alias should ignore the aliased type. + continue + } + } if typ, ok := obj.Type().(*types.Named); ok { for i := 0; i < typ.NumMethods(); i++ { g.use(typ.Method(i), nil, edgeIgnored)