Skip to content

Commit 3cd466f

Browse files
committed
unused: handle embedded aliases
Closes: gh-1361 Closes: gh-1365 (cherry picked from commit d717045)
1 parent 2eef176 commit 3cd466f

File tree

2 files changed

+85
-10
lines changed

2 files changed

+85
-10
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package pkg
2+
3+
type s1 struct{} //@ used("s1", true)
4+
5+
// Make sure the alias is used, and not just the type it points to.
6+
type a1 = s1 //@ used("a1", true)
7+
8+
type E1 struct { //@ used("E1", true)
9+
a1 //@ used("a1", true)
10+
}
11+
12+
func F1(e E1) { //@ used("F1", true), used("e", true)
13+
_ = e.a1
14+
}
15+
16+
// Make sure fields get used correctly when embedded multiple times
17+
type s2 struct { //@ used("s2", true)
18+
a int //@ used("a", true)
19+
b int //@ used("b", true)
20+
c int //@ used("c", false)
21+
}
22+
23+
type a2 = s2 //@ used("a2", true)
24+
25+
type E2 struct { //@ used("E2", true)
26+
a2 //@ used("a2", true)
27+
}
28+
29+
type E3 struct { //@ used("E3", true)
30+
a2 //@ used("a2", true)
31+
}
32+
33+
func F2(e E2) { //@ used("F2", true), used("e", true)
34+
_ = e.a
35+
}
36+
37+
func F3(e E3) { //@ used("F3", true), used("e", true)
38+
_ = e.b
39+
}
40+
41+
// Make sure embedding aliases to unnamed types works
42+
type a4 = struct { //@ used("a4", true)
43+
a int //@ used("a", true)
44+
b int //@ used("b", true)
45+
c int //@ used("c", false)
46+
}
47+
48+
type E4 struct { //@ used("E4", true)
49+
a4 //@ used("a4", true)
50+
}
51+
52+
type E5 struct { //@ used("E5", true)
53+
a4 //@ used("a4", true)
54+
}
55+
56+
func F4(e E4) { //@ used("F4", true), used("e", true)
57+
_ = e.a
58+
}
59+
60+
func F5(e E5) { //@ used("F5", true), used("e", true)
61+
_ = e.b
62+
}

unused/unused.go

+23-10
Original file line numberDiff line numberDiff line change
@@ -1394,28 +1394,38 @@ func (g *graph) stmt(stmt ast.Stmt, by types.Object) {
13941394
// embeddedField sees the field declared by the embedded field node, and marks the type as used by the field.
13951395
//
13961396
// Embedded fields are special in two ways: they don't have names, so we don't have immediate access to an ast.Ident to
1397-
// resolve to the field's types.Var, and we cannot use g.read on the type because eventually we do get to an ast.Ident,
1398-
// and ObjectOf resolves embedded fields to the field they declare, not the type. That's why we have code specially for
1399-
// handling embedded fields.
1397+
// resolve to the field's types.Var and need to instead walk the AST, and we cannot use g.read on the type because
1398+
// eventually we do get to an ast.Ident, and ObjectOf resolves embedded fields to the field they declare, not the type.
1399+
// That's why we have code specially for handling embedded fields.
14001400
func (g *graph) embeddedField(node ast.Node, by types.Object) *types.Var {
14011401
// We need to traverse the tree to find the ast.Ident, but all the nodes we traverse should be used by the object we
14021402
// get once we resolve the ident. Collect the nodes and process them once we've found the ident.
14031403
nodes := make([]ast.Node, 0, 4)
14041404
for {
14051405
switch node_ := node.(type) {
14061406
case *ast.Ident:
1407+
// obj is the field
14071408
obj := g.info.ObjectOf(node_).(*types.Var)
1409+
// the field is declared by the enclosing type
14081410
g.see(obj, by)
14091411
for _, n := range nodes {
14101412
g.read(n, obj)
14111413
}
1412-
switch typ := typeutil.Dereference(g.info.TypeOf(node_)).(type) {
1413-
case *types.Named:
1414-
g.use(typ.Obj(), obj)
1415-
case *types.Basic:
1416-
// Nothing to do
1417-
default:
1418-
lint.ExhaustiveTypeSwitch(typ)
1414+
1415+
if tname, ok := g.info.Uses[node_].(*types.TypeName); ok && tname.IsAlias() {
1416+
// When embedding an alias we want to use the alias, not what the alias points to.
1417+
g.use(tname, obj)
1418+
} else {
1419+
switch typ := typeutil.Dereference(g.info.TypeOf(node_)).(type) {
1420+
case *types.Named:
1421+
// (7.2) fields use their types
1422+
g.use(typ.Obj(), obj)
1423+
case *types.Basic:
1424+
// Nothing to do
1425+
default:
1426+
// Other types are only possible for aliases, which we've already handled
1427+
lint.ExhaustiveTypeSwitch(typ)
1428+
}
14191429
}
14201430
return obj
14211431
case *ast.StarExpr:
@@ -1518,6 +1528,9 @@ func (g *graph) namedType(typ *types.TypeName, spec ast.Expr) {
15181528
obj := g.info.ObjectOf(name)
15191529
g.see(obj, typ)
15201530
// (7.2) fields use their types
1531+
//
1532+
// This handles aliases correctly because ObjectOf(alias) returns the TypeName of the alias, not
1533+
// what the alias points to.
15211534
g.read(field.Type, obj)
15221535
if name.Name == "_" {
15231536
// (9.9) objects named the blank identifier are used

0 commit comments

Comments
 (0)