Skip to content

Commit f1f4626

Browse files
committed
go/analysis/passes/modernize: reflecttypefor: simplify .Elem()
The reflecttypefor modernizer already detects patterns involving pointers like: reflect.TypeOf((*io.Reader)(nil)).Elem() which are used to extract the type of an interface (since passing the interface directly to TypeOf produces a nil result) and simplifies them to remove the pointer and the call to Elem() when transformed to reflect.TypeFor. This CL also detects patterns using slices which have the same goal of extracting the interface type: reflect.TypeOf([]io.Reader(nil)).Elem() both become: reflect.TypeFor[io.Reader]() Fixes golang/go#77724 Change-Id: I1d5b4bdbaa812224a9e6f30687cadde01f99ed75 Reviewed-on: https://go-review.googlesource.com/c/tools/+/749500 Reviewed-by: Alan Donovan <adonovan@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
1 parent 0c3890d commit f1f4626

File tree

6 files changed

+51
-31
lines changed

6 files changed

+51
-31
lines changed

go/analysis/passes/modernize/doc.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,11 +263,15 @@ is known at compile time, for example:
263263
reflect.TypeOf(uint32(0)) -> reflect.TypeFor[uint32]()
264264
reflect.TypeOf((*ast.File)(nil)) -> reflect.TypeFor[*ast.File]()
265265
266-
It also offers a fix to simplify the construction below, which uses
266+
It also offers a fix to simplify the constructions below, which use
267267
reflect.TypeOf to return the runtime type for an interface type,
268268
269269
reflect.TypeOf((*io.Reader)(nil)).Elem()
270270
271+
or:
272+
273+
reflect.TypeOf([]io.Reader(nil)).Elem()
274+
271275
to:
272276
273277
reflect.TypeFor[io.Reader]()

go/analysis/passes/modernize/reflect.go

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -62,24 +62,30 @@ func reflecttypefor(pass *analysis.Pass) (any, error) {
6262
t := info.TypeOf(expr)
6363
var edits []analysis.TextEdit
6464

65-
// Special case for TypeOf((*T)(nil)).Elem(),
66-
// needed when T is an interface type.
65+
// Special cases for TypeOf((*T)(nil)).Elem(), and
66+
// TypeOf([]T(nil)).Elem(), needed when T is an interface type.
6767
if curCall.ParentEdgeKind() == edge.SelectorExpr_X {
6868
curSel := unparenEnclosing(curCall).Parent()
6969
if curSel.ParentEdgeKind() == edge.CallExpr_Fun {
70-
call2 := unparenEnclosing(curSel).Parent().Node().(*ast.CallExpr)
70+
call2 := unparenEnclosing(curSel).Parent().Node().(*ast.CallExpr) // potentially .Elem()
7171
obj := typeutil.Callee(info, call2)
7272
if typesinternal.IsMethodNamed(obj, "reflect", "Type", "Elem") {
73-
if ptr, ok := t.(*types.Pointer); ok {
73+
// reflect.TypeOf(expr).Elem()
74+
// -------
75+
// reflect.TypeOf(expr)
76+
removeElem := []analysis.TextEdit{{
77+
Pos: call.End(),
78+
End: call2.End(),
79+
}}
80+
switch typ := t.(type) {
81+
case *types.Pointer:
7482
// Have: TypeOf(expr).Elem() where expr : *T
75-
t = ptr.Elem()
76-
// reflect.TypeOf(expr).Elem()
77-
// -------
78-
// reflect.TypeOf(expr)
79-
edits = []analysis.TextEdit{{
80-
Pos: call.End(),
81-
End: call2.End(),
82-
}}
83+
t = typ.Elem()
84+
edits = removeElem
85+
case *types.Slice:
86+
// Have: TypeOf(expr).Elem() where expr : []T
87+
t = typ.Elem()
88+
edits = removeElem
8389
}
8490
}
8591
}

go/analysis/passes/modernize/testdata/src/reflecttypefor/reflecttypefor.go

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,22 @@ var (
1414
x any
1515
a A
1616
b B[int]
17-
_ = reflect.TypeOf(x) // nope (dynamic)
18-
_ = reflect.TypeOf(0) // want "reflect.TypeOf call can be simplified using TypeFor"
19-
_ = reflect.TypeOf(nil) // nope (likely a mistake)
20-
_ = reflect.TypeOf(uint(0)) // want "reflect.TypeOf call can be simplified using TypeFor"
21-
_ = reflect.TypeOf(error(nil)) // nope (likely a mistake)
22-
_ = reflect.TypeOf((*error)(nil)) // want "reflect.TypeOf call can be simplified using TypeFor"
23-
_ = reflect.TypeOf(io.Reader(nil)) // nope (likely a mistake)
24-
_ = reflect.TypeOf((*io.Reader)(nil)) // want "reflect.TypeOf call can be simplified using TypeFor"
25-
_ = reflect.TypeOf(*new(time.Time)) // want "reflect.TypeOf call can be simplified using TypeFor"
26-
_ = reflect.TypeOf(time.Time{}) // want "reflect.TypeOf call can be simplified using TypeFor"
27-
_ = reflect.TypeOf(time.Duration(0)) // want "reflect.TypeOf call can be simplified using TypeFor"
28-
_ = reflect.TypeOf(&a) // want "reflect.TypeOf call can be simplified using TypeFor"
29-
_ = reflect.TypeOf(&b) // want "reflect.TypeOf call can be simplified using TypeFor"
17+
_ = reflect.TypeOf(x) // nope (dynamic)
18+
_ = reflect.TypeOf(0) // want "reflect.TypeOf call can be simplified using TypeFor"
19+
_ = reflect.TypeOf(nil) // nope (likely a mistake)
20+
_ = reflect.TypeOf(uint(0)) // want "reflect.TypeOf call can be simplified using TypeFor"
21+
_ = reflect.TypeOf(error(nil)) // nope (likely a mistake)
22+
_ = reflect.TypeOf((*error)(nil)) // want "reflect.TypeOf call can be simplified using TypeFor"
23+
_ = reflect.TypeOf(io.Reader(nil)) // nope (likely a mistake)
24+
_ = reflect.TypeOf((*io.Reader)(nil)) // want "reflect.TypeOf call can be simplified using TypeFor"
25+
_ = reflect.TypeOf(*new(time.Time)) // want "reflect.TypeOf call can be simplified using TypeFor"
26+
_ = reflect.TypeOf(time.Time{}) // want "reflect.TypeOf call can be simplified using TypeFor"
27+
_ = reflect.TypeOf(time.Duration(0)) // want "reflect.TypeOf call can be simplified using TypeFor"
28+
_ = reflect.TypeOf(&a) // want "reflect.TypeOf call can be simplified using TypeFor"
29+
_ = reflect.TypeOf(&b) // want "reflect.TypeOf call can be simplified using TypeFor"
30+
_ = reflect.TypeOf([]io.Reader(nil)).Elem() // want "reflect.TypeOf call can be simplified using TypeFor"
31+
_ = reflect.TypeOf([]*io.Reader(nil)).Elem() // want "reflect.TypeOf call can be simplified using TypeFor"
32+
_ = reflect.TypeOf((*io.Reader)(nil)).Elem() // want "reflect.TypeOf call can be simplified using TypeFor"
3033
)
3134

3235
// Eliminate local var if we deleted its last use.

go/analysis/passes/modernize/testdata/src/reflecttypefor/reflecttypefor.go.golden

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,11 @@ var (
2525
_ = reflect.TypeFor[time.Time]() // want "reflect.TypeOf call can be simplified using TypeFor"
2626
_ = reflect.TypeFor[time.Time]() // want "reflect.TypeOf call can be simplified using TypeFor"
2727
_ = reflect.TypeFor[time.Duration]() // want "reflect.TypeOf call can be simplified using TypeFor"
28-
_ = reflect.TypeFor[*A]() // want "reflect.TypeOf call can be simplified using TypeFor"
29-
_ = reflect.TypeFor[*B[int]]() // want "reflect.TypeOf call can be simplified using TypeFor"
28+
_ = reflect.TypeFor[*A]() // want "reflect.TypeOf call can be simplified using TypeFor"
29+
_ = reflect.TypeFor[*B[int]]() // want "reflect.TypeOf call can be simplified using TypeFor"
30+
_ = reflect.TypeFor[io.Reader]() // want "reflect.TypeOf call can be simplified using TypeFor"
31+
_ = reflect.TypeFor[*io.Reader]() // want "reflect.TypeOf call can be simplified using TypeFor"
32+
_ = reflect.TypeFor[io.Reader]() // want "reflect.TypeOf call can be simplified using TypeFor"
3033
)
3134

3235
// Eliminate local var if we deleted its last use.

gopls/doc/analyzers.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3732,10 +3732,14 @@ This analyzer suggests fixes to replace uses of reflect.TypeOf(x) with reflect.T
37323732
reflect.TypeOf(uint32(0)) -> reflect.TypeFor[uint32]()
37333733
reflect.TypeOf((*ast.File)(nil)) -> reflect.TypeFor[*ast.File]()
37343734

3735-
It also offers a fix to simplify the construction below, which uses reflect.TypeOf to return the runtime type for an interface type,
3735+
It also offers a fix to simplify the constructions below, which use reflect.TypeOf to return the runtime type for an interface type,
37363736

37373737
reflect.TypeOf((*io.Reader)(nil)).Elem()
37383738

3739+
or:
3740+
3741+
reflect.TypeOf([]io.Reader(nil)).Elem()
3742+
37393743
to:
37403744

37413745
reflect.TypeFor[io.Reader]()

gopls/internal/doc/api.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1606,7 +1606,7 @@
16061606
},
16071607
{
16081608
"Name": "\"reflecttypefor\"",
1609-
"Doc": "replace reflect.TypeOf(x) with TypeFor[T]()\n\nThis analyzer suggests fixes to replace uses of reflect.TypeOf(x) with\nreflect.TypeFor, introduced in go1.22, when the desired runtime type\nis known at compile time, for example:\n\n\treflect.TypeOf(uint32(0)) -\u003e reflect.TypeFor[uint32]()\n\treflect.TypeOf((*ast.File)(nil)) -\u003e reflect.TypeFor[*ast.File]()\n\nIt also offers a fix to simplify the construction below, which uses\nreflect.TypeOf to return the runtime type for an interface type,\n\n\treflect.TypeOf((*io.Reader)(nil)).Elem()\n\nto:\n\n\treflect.TypeFor[io.Reader]()\n\nNo fix is offered in cases when the runtime type is dynamic, such as:\n\n\tvar r io.Reader = ...\n\treflect.TypeOf(r)\n\nor when the operand has potential side effects.",
1609+
"Doc": "replace reflect.TypeOf(x) with TypeFor[T]()\n\nThis analyzer suggests fixes to replace uses of reflect.TypeOf(x) with\nreflect.TypeFor, introduced in go1.22, when the desired runtime type\nis known at compile time, for example:\n\n\treflect.TypeOf(uint32(0)) -\u003e reflect.TypeFor[uint32]()\n\treflect.TypeOf((*ast.File)(nil)) -\u003e reflect.TypeFor[*ast.File]()\n\nIt also offers a fix to simplify the constructions below, which use\nreflect.TypeOf to return the runtime type for an interface type,\n\n\treflect.TypeOf((*io.Reader)(nil)).Elem()\n\nor:\n\n\treflect.TypeOf([]io.Reader(nil)).Elem()\n\nto:\n\n\treflect.TypeFor[io.Reader]()\n\nNo fix is offered in cases when the runtime type is dynamic, such as:\n\n\tvar r io.Reader = ...\n\treflect.TypeOf(r)\n\nor when the operand has potential side effects.",
16101610
"Default": "true",
16111611
"Status": ""
16121612
},
@@ -3535,7 +3535,7 @@
35353535
},
35363536
{
35373537
"Name": "reflecttypefor",
3538-
"Doc": "replace reflect.TypeOf(x) with TypeFor[T]()\n\nThis analyzer suggests fixes to replace uses of reflect.TypeOf(x) with\nreflect.TypeFor, introduced in go1.22, when the desired runtime type\nis known at compile time, for example:\n\n\treflect.TypeOf(uint32(0)) -\u003e reflect.TypeFor[uint32]()\n\treflect.TypeOf((*ast.File)(nil)) -\u003e reflect.TypeFor[*ast.File]()\n\nIt also offers a fix to simplify the construction below, which uses\nreflect.TypeOf to return the runtime type for an interface type,\n\n\treflect.TypeOf((*io.Reader)(nil)).Elem()\n\nto:\n\n\treflect.TypeFor[io.Reader]()\n\nNo fix is offered in cases when the runtime type is dynamic, such as:\n\n\tvar r io.Reader = ...\n\treflect.TypeOf(r)\n\nor when the operand has potential side effects.",
3538+
"Doc": "replace reflect.TypeOf(x) with TypeFor[T]()\n\nThis analyzer suggests fixes to replace uses of reflect.TypeOf(x) with\nreflect.TypeFor, introduced in go1.22, when the desired runtime type\nis known at compile time, for example:\n\n\treflect.TypeOf(uint32(0)) -\u003e reflect.TypeFor[uint32]()\n\treflect.TypeOf((*ast.File)(nil)) -\u003e reflect.TypeFor[*ast.File]()\n\nIt also offers a fix to simplify the constructions below, which use\nreflect.TypeOf to return the runtime type for an interface type,\n\n\treflect.TypeOf((*io.Reader)(nil)).Elem()\n\nor:\n\n\treflect.TypeOf([]io.Reader(nil)).Elem()\n\nto:\n\n\treflect.TypeFor[io.Reader]()\n\nNo fix is offered in cases when the runtime type is dynamic, such as:\n\n\tvar r io.Reader = ...\n\treflect.TypeOf(r)\n\nor when the operand has potential side effects.",
35393539
"URL": "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/modernize#reflecttypefor",
35403540
"Default": true
35413541
},

0 commit comments

Comments
 (0)