Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 40 additions & 21 deletions called.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,37 +57,56 @@ func run(pass *analysis.Pass) (interface{}, error) {
func restrictedFuncs(pass *analysis.Pass, names string) []*types.Func {
var fs []*types.Func
for _, fn := range strings.Split(names, ",") {
ss := strings.Split(strings.TrimSpace(fn), ".")

// package function: pkgname.Func
if len(ss) < 2 {
continue
}
f, _ := analysisutil.ObjectOf(pass, ss[0], ss[1]).(*types.Func)
if f != nil {
fs = append(fs, f)
fn = strings.TrimSpace(fn)
if fn == "" {
continue
}

// method: (*pkgname.Type).Method
if len(ss) < 3 {
// split function/method name from the end
last := strings.LastIndex(fn, ".")
if last == -1 {
continue
}
pkgname := strings.TrimLeft(ss[0], "(")
typename := strings.TrimRight(ss[1], ")")
if pkgname != "" && pkgname[0] == '*' {
pkgname = pkgname[1:]
typename = "*" + typename
prefix := fn[:last]
name := fn[last+1:]

// drop surrounding parentheses and detect pointer receiver
recv := strings.TrimPrefix(prefix, "(")
recv = strings.TrimSuffix(recv, ")")
ptr := false
if strings.HasPrefix(recv, "*") {
ptr = true
recv = recv[1:]
}

typ := analysisutil.TypeOf(pass, pkgname, typename)
if typ == nil {
// determine whether it is a method or a package function
dot := strings.LastIndex(recv, ".")
slash := strings.LastIndex(recv, "/")
if dot != -1 && dot > slash {
// method: pkgpath.Type.Method or (*pkgpath.Type).Method
pkgpath := recv[:dot]
typename := recv[dot+1:]
if ptr {
typename = "*" + typename
}
typ := analysisutil.TypeOf(pass, pkgpath, typename)
if typ == nil {
continue
}
if m := analysisutil.MethodOf(typ, name); m != nil {
fs = append(fs, m)
}
continue
}

m := analysisutil.MethodOf(typ, ss[2])
if m != nil {
fs = append(fs, m)
// package function: pkgpath.Func
if ptr {
// invalid pattern
continue
}
f, _ := analysisutil.ObjectOf(pass, recv, name).(*types.Func)
if f != nil {
fs = append(fs, f)
}
}

Expand Down
4 changes: 2 additions & 2 deletions called_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ import (

func Test(t *testing.T) {
testdata := analysistest.TestData()
defer called.ExportSetFlagFuncs("b.Func,(*b.Type).Method, b/bsub.Type.Method")()
analysistest.Run(t, testdata, called.Analyzer, "a")
defer called.ExportSetFlagFuncs("b.Func,(*b.Type).Method,b/bsub.Type.Method,example.com/foo.Func,(example.com/foo.Type).Method")()
analysistest.Run(t, testdata, called.Analyzer, "a", "c")
}
8 changes: 8 additions & 0 deletions testdata/src/c/c.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package c

import "example.com/foo"

func main() {
foo.Func() // want `example.com/foo.Func must not be called`
foo.Type{}.Method() // want `(example.com/foo.Type).Method must not be called`
}
7 changes: 7 additions & 0 deletions testdata/src/c/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module c

go 1.13

require example.com/foo v0.0.0

replace example.com/foo => ../example.com/foo
7 changes: 7 additions & 0 deletions testdata/src/example.com/foo/foo.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package foo

func Func() {}

type Type struct{}

func (Type) Method() {}
3 changes: 3 additions & 0 deletions testdata/src/example.com/foo/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module example.com/foo

go 1.13
Loading