--- /dev/null
+package main
+
+import (
+ "fmt"
+)
+
+// Tests of call-graph queries.
+// See go.tools/guru/guru_test.go for explanation.
+// See calls.golden for expected query results.
+
+func A(x *int) { // @pointsto pointsto-A-x "x"
+ // @callers callers-A "^"
+ // @callstack callstack-A "^"
+}
+
+func B(x *int) { // @pointsto pointsto-B-x "x"
+ // @callers callers-B "^"
+}
+
+func foo() {
+}
+
+// apply is not (yet) treated context-sensitively.
+func apply(f func(x *int), x *int) {
+ f(x) // @callees callees-apply "f"
+ // @callers callers-apply "^"
+}
+
+// store *is* treated context-sensitively,
+// so the points-to sets for pc, pd are precise.
+func store(ptr **int, value *int) {
+ *ptr = value
+ // @callers callers-store "^"
+}
+
+func call(f func() *int) {
+ // Result points to anon function.
+ f() // @pointsto pointsto-result-f "f"
+
+ // Target of call is anon function.
+ f() // @callees callees-main.call-f "f"
+
+ // @callers callers-main.call "^"
+}
+
+func main() {
+ var a, b int
+ go apply(A, &a) // @callees callees-main-apply1 "app"
+ defer apply(B, &b)
+
+ var c, d int
+ var pc, pd *int // @pointsto pointsto-pc "pc"
+ store(&pc, &c)
+ store(&pd, &d)
+ _ = pd // @pointsto pointsto-pd "pd"
+
+ call(func() *int {
+ // We are called twice from main.call
+ // @callers callers-main.anon "^"
+ return &a
+ })
+
+ // Errors
+ _ = "no function call here" // @callees callees-err-no-call "no"
+ print("builtin") // @callees callees-err-builtin "builtin"
+ _ = string("type conversion") // @callees callees-err-conversion "str"
+ call(nil) // @callees callees-err-bad-selection "call\\(nil"
+ if false {
+ main() // @callees callees-err-deadcode1 "main"
+ }
+ var nilFunc func()
+ nilFunc() // @callees callees-err-nil-func "nilFunc"
+ var i interface {
+ f()
+ }
+ i.f() // @callees callees-err-nil-interface "i.f"
+
+ i = new(myint)
+ i.f() // @callees callees-not-a-wrapper "f"
+
+ // statically dispatched calls. Handled specially by callees, so test that they work.
+ foo() // @callees callees-static-call "foo"
+ fmt.Println() // @callees callees-qualified-call "Println"
+ m := new(method)
+ m.f() // @callees callees-static-method-call "f"
+ g := new(embeddedIface)
+ g.iface = m
+ g.f() // @callees callees-implicit-selection-method-call "f"
+}
+
+type myint int
+
+func (myint) f() {
+ // @callers callers-not-a-wrapper "^"
+}
+
+type method int
+
+func (method) f() {
+}
+
+type embeddedIface struct {
+ iface
+}
+
+type iface interface {
+ f()
+}
+
+var dynamic = func() {}
+
+func deadcode() {
+ main() // @callees callees-err-deadcode2 "main"
+ // @callers callers-err-deadcode "^"
+ // @callstack callstack-err-deadcode "^"
+
+ // Within dead code, dynamic calls have no callees.
+ dynamic() // @callees callees-err-deadcode3 "dynamic"
+}
+
+// This code belongs to init.
+var global = 123 // @callers callers-global "global"
+
+// The package initializer may be called by other packages' inits, or
+// in this case, the root of the callgraph. The source-level init functions
+// are in turn called by it.
+func init() {
+ // @callstack callstack-init "^"
+}