diff --git a/called.go b/called.go index 1a93579..0f5f2f4 100644 --- a/called.go +++ b/called.go @@ -57,39 +57,71 @@ 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 len(fn) == 0 { continue } - // method: (*pkgname.Type).Method - if len(ss) < 3 { - continue - } - pkgname := strings.TrimLeft(ss[0], "(") - typename := strings.TrimRight(ss[1], ")") - if pkgname != "" && pkgname[0] == '*' { - pkgname = pkgname[1:] - typename = "*" + typename + if fn[0] == '(' { + // method: (*pkgname.Type).Method + ss := splitLastN(fn, ".", 3) + if len(ss) < 3 { + continue + } + pkgname := strings.TrimLeft(ss[0], "(") + typename := strings.TrimRight(ss[1], ")") + if pkgname != "" && pkgname[0] == '*' { + pkgname = pkgname[1:] + typename = "*" + typename + } + + typ := analysisutil.TypeOf(pass, pkgname, typename) + if typ == nil { + continue + } + + m := analysisutil.MethodOf(typ, ss[2]) + if m != nil { + fs = append(fs, m) + } + } else { + // package function: pkgname.Func + ss := splitLastN(fn, ".", 2) + if len(ss) < 2 { + continue + } + f, _ := analysisutil.ObjectOf(pass, ss[0], ss[1]).(*types.Func) + if f != nil { + fs = append(fs, f) + continue + } } + } - typ := analysisutil.TypeOf(pass, pkgname, typename) - if typ == nil { - continue + return fs +} + +func splitLastN(s, sep string, n int) []string { + ret := make([]string, 0) + for i := 0; i < n-1; i++ { + li := strings.LastIndex(s, sep) + if li < 0 { + break } - m := analysisutil.MethodOf(typ, ss[2]) - if m != nil { - fs = append(fs, m) + if li+1 < len(s) { + ret = append(ret, s[li+1:]) + } else { + ret = append(ret, "") } + s = s[:li] } + ret = append(ret, s) - return fs + // reverse + for i, j := 0, len(ret)-1; i < j; i, j = i+1, j-1 { + ret[i], ret[j] = ret[j], ret[i] + } + + return ret } diff --git a/called_test.go b/called_test.go index 8ec3672..25a23c3 100644 --- a/called_test.go +++ b/called_test.go @@ -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")() + defer called.ExportSetFlagFuncs("b.Func,(*b.Type).Method, (b/bsub.Type).Method,github.com/gostaticanalysis/c.Func,(*github.com/gostaticanalysis/c.Type).Method,(github.com/gostaticanalysis/c/csub.Type).Method")() analysistest.Run(t, testdata, called.Analyzer, "a") } diff --git a/testdata/src/a/a.go b/testdata/src/a/a.go index e589d1b..f7d3192 100644 --- a/testdata/src/a/a.go +++ b/testdata/src/a/a.go @@ -3,6 +3,9 @@ package a import ( "b" "b/bsub" + + "github.com/gostaticanalysis/c" + "github.com/gostaticanalysis/c/csub" ) func afunc() { @@ -53,5 +56,26 @@ func main() { //lint:ignore called OK m4(bsub.Type{}) // OK + c.Func() // want `github\.com/gostaticanalysis/c\.Func must not be called` + _ = c.Func // OK + g := c.Func // OK + g() // want `github\.com/gostaticanalysis/c\.Func must not be called` + + new(c.Type).Method() // want `\(\*github\.com/gostaticanalysis/c\.Type\)\.Method must not be called` + _ = new(c.Type).Method // OK + m5 := new(c.Type).Method // OK + m5() // want `\(\*github\.com/gostaticanalysis/c\.Type\)\.Method must not be called` + (*c.Type).Method(new(c.Type)) // want `\(\*github\.com/gostaticanalysis/c\.Type\)\.Method must not be called` + m6 := (*c.Type).Method // OK + m6(new(c.Type)) // want `\(\*github\.com/gostaticanalysis/c\.Type\)\.Method must not be called` + + csub.Type{}.Method() // want `\(github\.com/gostaticanalysis/c/csub\.Type\)\.Method must not be called` + _ = csub.Type{}.Method // OK + m7 := csub.Type{}.Method // OK + m7() // want `\(github\.com/gostaticanalysis/c/csub\.Type\)\.Method must not be called` + (csub.Type).Method(csub.Type{}) // want `\(github\.com/gostaticanalysis/c/csub\.Type\)\.Method must not be called` + m8 := (csub.Type).Method // OK + m8(csub.Type{}) // want `\(github\.com/gostaticanalysis/c/csub\.Type\)\.Method must not be called` + afunc() // OK } diff --git a/testdata/src/github.com/gostaticanalysis/c/c.go b/testdata/src/github.com/gostaticanalysis/c/c.go new file mode 100644 index 0000000..8fccc0e --- /dev/null +++ b/testdata/src/github.com/gostaticanalysis/c/c.go @@ -0,0 +1,7 @@ +package c + +func Func() {} + +type Type struct{} + +func (*Type) Method() {} diff --git a/testdata/src/github.com/gostaticanalysis/c/csub/csub.go b/testdata/src/github.com/gostaticanalysis/c/csub/csub.go new file mode 100644 index 0000000..a56e5f7 --- /dev/null +++ b/testdata/src/github.com/gostaticanalysis/c/csub/csub.go @@ -0,0 +1,5 @@ +package csub + +type Type struct{} + +func (Type) Method() {}