From d89860af3b4b35dddb65f14716b60fbece556678 Mon Sep 17 00:00:00 2001 From: Matts966 Date: Fri, 4 Oct 2019 16:59:51 +0000 Subject: [PATCH] go/analysis/analysistest: fix nil pointer dereference when sorting facts Without this change, we can't use `ExportPackageFact` function with analysistest package. PackageFacts are keyed by nil and analysistest.check crashed while sorting, due to a nil object dereference. Change-Id: Ic94c71acc9c74012bf150e1d72e937da8dfdff75 GitHub-Last-Rev: 51c91008a6756e66c630bfeabc9b8da08c12bfdd GitHub-Pull-Request: golang/tools#163 Reviewed-on: https://go-review.googlesource.com/c/tools/+/196758 Run-TryBot: Rebecca Stambler Reviewed-by: Alan Donovan --- go/analysis/analysistest/analysistest.go | 5 +++++ go/analysis/analysistest/analysistest_test.go | 2 +- go/analysis/passes/findcall/findcall.go | 9 ++++++++- go/analysis/passes/findcall/findcall_test.go | 6 ++++-- go/analysis/passes/findcall/testdata/src/a/a.go | 4 +++- 5 files changed, 21 insertions(+), 5 deletions(-) diff --git a/go/analysis/analysistest/analysistest.go b/go/analysis/analysistest/analysistest.go index 0d323dc583..fc06c32269 100644 --- a/go/analysis/analysistest/analysistest.go +++ b/go/analysis/analysistest/analysistest.go @@ -277,6 +277,11 @@ func check(t Testing, gopath string, pass *analysis.Pass, diagnostics []analysis objects = append(objects, obj) } sort.Slice(objects, func(i, j int) bool { + // Package facts compare less than object facts. + ip, jp := objects[i] == nil, objects[j] == nil // whether i, j is a package fact + if ip != jp { + return ip && !jp + } return objects[i].Pos() < objects[j].Pos() }) for _, obj := range objects { diff --git a/go/analysis/analysistest/analysistest_test.go b/go/analysis/analysistest/analysistest_test.go index 2b08542865..c16e5079e2 100644 --- a/go/analysis/analysistest/analysistest_test.go +++ b/go/analysis/analysistest/analysistest_test.go @@ -33,7 +33,7 @@ func TestTheTest(t *testing.T) { // which (by default) reports calls to functions named 'println'. findcall.Analyzer.Flags.Set("name", "println") - filemap := map[string]string{"a/b.go": `package main + filemap := map[string]string{"a/b.go": `package main // want package:"found" func main() { // The expectation is ill-formed: diff --git a/go/analysis/passes/findcall/findcall.go b/go/analysis/passes/findcall/findcall.go index 2a4e3a4744..cd31ab416f 100644 --- a/go/analysis/passes/findcall/findcall.go +++ b/go/analysis/passes/findcall/findcall.go @@ -5,7 +5,10 @@ // The findcall package defines an Analyzer that serves as a trivial // example and test of the Analysis API. It reports a diagnostic for // every call to a function or method of the name specified by its -// -name flag. +// -name flag. It also exports a fact for each declaration that +// matches the name, plus a package-level fact if the package contained +// one or more such declarations. + package findcall import ( @@ -69,6 +72,10 @@ func run(pass *analysis.Pass) (interface{}, error) { } } + if len(pass.AllObjectFacts()) > 0 { + pass.ExportPackageFact(new(foundFact)) + } + return nil, nil } diff --git a/go/analysis/passes/findcall/findcall_test.go b/go/analysis/passes/findcall/findcall_test.go index e5292df885..7710d524aa 100644 --- a/go/analysis/passes/findcall/findcall_test.go +++ b/go/analysis/passes/findcall/findcall_test.go @@ -29,12 +29,14 @@ func TestFromStringLiterals(t *testing.T) { { desc: "SimpleTest", pkgpath: "main", - files: map[string]string{"main/main.go": `package main + files: map[string]string{"main/main.go": `package main // want package:"found" func main() { println("hello") // want "call of println" print("goodbye") // not a call of println -}`, +} + +func println(s string) {} // want println:"found"`, }, }, } { diff --git a/go/analysis/passes/findcall/testdata/src/a/a.go b/go/analysis/passes/findcall/testdata/src/a/a.go index f2c205330e..d9321cceb0 100644 --- a/go/analysis/passes/findcall/testdata/src/a/a.go +++ b/go/analysis/passes/findcall/testdata/src/a/a.go @@ -1,6 +1,8 @@ -package main +package main // want package:"found" func main() { println("hi") // want "call of println" print("hi") // not a call of println } + +func println(s string) {} // want println:"found"