Add call graph test.

This test uses annotations to encode the expected output directly into the source, hence the `.expected` files are trivial.
This commit is contained in:
Max Schaefer
2020-01-21 16:33:13 +00:00
parent 3c88eab84c
commit 9400442bea
5 changed files with 75 additions and 0 deletions

View File

@@ -0,0 +1,2 @@
missingCall
spuriousCall

View File

@@ -0,0 +1,11 @@
import go
query predicate missingCall(DeclaredFunction f, DataFlow::CallNode call) {
call.getACallee() = f.getFuncDecl() and
not call = f.getACall()
}
query predicate spuriousCall(DeclaredFunction f, DataFlow::CallNode call) {
call = f.getACall() and
exists(FuncDecl fd | fd = f.getFuncDecl() | not call.getACallee() = fd)
}

View File

@@ -0,0 +1,2 @@
missingCallee
spuriousCallee

View File

@@ -0,0 +1,25 @@
import go
/**
* Gets a string `val` such that there is a comment on the same line as `l`
* that contains the substring `key: val`.
*/
string metadata(Locatable l, string key) {
exists(string f, int line, Comment c, string kv |
l.hasLocationInfo(f, line, _, _, _) and
c.hasLocationInfo(f, line, _, _, _) and
kv = c.getText().regexpFind("\\b(\\w+: \\S+)", _, _) and
key = kv.regexpCapture("(\\w+): (\\S+)", 1) and
result = kv.regexpCapture("(\\w+): (\\S+)", 2)
)
}
query predicate missingCallee(DataFlow::CallNode call, FuncDef callee) {
metadata(call.asExpr(), "callee") = metadata(callee, "name") and
not call.getACallee() = callee
}
query predicate spuriousCallee(DataFlow::CallNode call, FuncDef callee) {
call.getACallee() = callee and
not metadata(call.asExpr(), "callee") = metadata(callee, "name")
}

View File

@@ -0,0 +1,35 @@
package main
type I interface {
m() // name: I.m
}
type s1 struct{}
type s2 struct{}
type s3 struct{}
type mybool bool
func (s1) m() {} // name: s1.m
func (*s2) m() {} // name: s2.m
func (s3) m(int) {} // name: s3.m
func (mybool) m() {} // name: mybool.m
func test(x *s1, y s2, z s3, b mybool, i I) {
x.m() // callee: s1.m
y.m() // callee: s2.m
z.m(0) // callee: s3.m
b.m() // callee: mybool.m
i.m() // callee: s1.m callee: s2.m callee: mybool.m
s1.m(*x) // callee: s1.m
s3.m(z, 0) // callee: s3.m
mybool.m(b) // callee: mybool.m
(func() {})() // name: func(){} callee: func(){}
id := func(x int) int { return x } // name: id
id(1) // callee: id
}