From 9400442bea84f90e44e359443f32ddea1ad29fac Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Tue, 21 Jan 2020 16:33:13 +0000 Subject: [PATCH] Add call graph test. This test uses annotations to encode the expected output directly into the source, hence the `.expected` files are trivial. --- .../go/dataflow/CallGraph/getACall.expected | 2 ++ .../semmle/go/dataflow/CallGraph/getACall.ql | 11 ++++++ .../go/dataflow/CallGraph/getACallee.expected | 2 ++ .../go/dataflow/CallGraph/getACallee.ql | 25 +++++++++++++ .../semmle/go/dataflow/CallGraph/main.go | 35 +++++++++++++++++++ 5 files changed, 75 insertions(+) create mode 100644 ql/test/library-tests/semmle/go/dataflow/CallGraph/getACall.expected create mode 100644 ql/test/library-tests/semmle/go/dataflow/CallGraph/getACall.ql create mode 100644 ql/test/library-tests/semmle/go/dataflow/CallGraph/getACallee.expected create mode 100644 ql/test/library-tests/semmle/go/dataflow/CallGraph/getACallee.ql create mode 100644 ql/test/library-tests/semmle/go/dataflow/CallGraph/main.go diff --git a/ql/test/library-tests/semmle/go/dataflow/CallGraph/getACall.expected b/ql/test/library-tests/semmle/go/dataflow/CallGraph/getACall.expected new file mode 100644 index 00000000000..553fdf373eb --- /dev/null +++ b/ql/test/library-tests/semmle/go/dataflow/CallGraph/getACall.expected @@ -0,0 +1,2 @@ +missingCall +spuriousCall diff --git a/ql/test/library-tests/semmle/go/dataflow/CallGraph/getACall.ql b/ql/test/library-tests/semmle/go/dataflow/CallGraph/getACall.ql new file mode 100644 index 00000000000..82e50120d5e --- /dev/null +++ b/ql/test/library-tests/semmle/go/dataflow/CallGraph/getACall.ql @@ -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) +} diff --git a/ql/test/library-tests/semmle/go/dataflow/CallGraph/getACallee.expected b/ql/test/library-tests/semmle/go/dataflow/CallGraph/getACallee.expected new file mode 100644 index 00000000000..381d576a20b --- /dev/null +++ b/ql/test/library-tests/semmle/go/dataflow/CallGraph/getACallee.expected @@ -0,0 +1,2 @@ +missingCallee +spuriousCallee diff --git a/ql/test/library-tests/semmle/go/dataflow/CallGraph/getACallee.ql b/ql/test/library-tests/semmle/go/dataflow/CallGraph/getACallee.ql new file mode 100644 index 00000000000..99e85587d55 --- /dev/null +++ b/ql/test/library-tests/semmle/go/dataflow/CallGraph/getACallee.ql @@ -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") +} diff --git a/ql/test/library-tests/semmle/go/dataflow/CallGraph/main.go b/ql/test/library-tests/semmle/go/dataflow/CallGraph/main.go new file mode 100644 index 00000000000..b9bc5e7ada3 --- /dev/null +++ b/ql/test/library-tests/semmle/go/dataflow/CallGraph/main.go @@ -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 +}