Skip to content

Commit e1d6482

Browse files
dominikhadonovan
andcommitted
QF1012: support implicit address-taking
Co-authored-by: Alan Donovan <[email protected]> Closes: gh-1097
1 parent 883987a commit e1d6482

File tree

3 files changed

+29
-3
lines changed

3 files changed

+29
-3
lines changed

quickfix/qf1012/qf1012.go

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package qf1012
33
import (
44
"fmt"
55
"go/ast"
6+
"go/token"
67
"go/types"
78
"strings"
89

@@ -57,9 +58,25 @@ var (
5758

5859
func run(pass *analysis.Pass) (any, error) {
5960
fn := func(node ast.Node) {
60-
if m, ok := code.Match(pass, checkWriteBytesSprintfQ, node); ok {
61+
getRecv := func(m *pattern.Matcher) (ast.Expr, types.Type) {
6162
recv := m.State["recv"].(ast.Expr)
6263
recvT := pass.TypesInfo.TypeOf(recv)
64+
65+
// Use *N, not N, for the interface check if N
66+
// is a named non-interface type, since the pointer
67+
// has a larger method set (https://staticcheck.dev/issues/1097).
68+
// We assume the receiver expression is addressable
69+
// since otherwise thre code wouldn't compile.
70+
if _, ok := types.Unalias(recvT).(*types.Named); ok && !types.IsInterface(recvT) {
71+
recvT = types.NewPointer(recvT)
72+
recv = &ast.UnaryExpr{Op: token.AND, X: recv}
73+
74+
}
75+
return recv, recvT
76+
}
77+
78+
if m, ok := code.Match(pass, checkWriteBytesSprintfQ, node); ok {
79+
recv, recvT := getRecv(m)
6380
if !types.Implements(recvT, knowledge.Interfaces["io.Writer"]) {
6481
return
6582
}
@@ -78,8 +95,7 @@ func run(pass *analysis.Pass) (any, error) {
7895
}))
7996
report.Report(pass, node, msg, report.Fixes(fix))
8097
} else if m, ok := code.Match(pass, checkWriteStringSprintfQ, node); ok {
81-
recv := m.State["recv"].(ast.Expr)
82-
recvT := pass.TypesInfo.TypeOf(recv)
98+
recv, recvT := getRecv(m)
8399
if !types.Implements(recvT, knowledge.Interfaces["io.StringWriter"]) {
84100
return
85101
}

quickfix/qf1012/testdata/go1.0/CheckWriteBytesSprintf/CheckWriteBytesSprintf.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,8 @@ func fn2() {
3434
sw.WriteString(fmt.Sprintf("%T", 0))
3535
sw.WriteString(fmt.Sprintln("abc", "de"))
3636
}
37+
38+
func fn3() {
39+
var buf bytes.Buffer
40+
buf.WriteString(fmt.Sprint("abc", "de")) //@ diag(`Use fmt.Fprint`)
41+
}

quickfix/qf1012/testdata/go1.0/CheckWriteBytesSprintf/CheckWriteBytesSprintf.go.golden

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,8 @@ func fn2() {
3434
sw.WriteString(fmt.Sprintf("%T", 0))
3535
sw.WriteString(fmt.Sprintln("abc", "de"))
3636
}
37+
38+
func fn3() {
39+
var buf bytes.Buffer
40+
fmt.Fprint(&buf, "abc", "de") //@ diag(`Use fmt.Fprint`)
41+
}

0 commit comments

Comments
 (0)