@@ -2,18 +2,20 @@ private import go
22private import DataFlowPrivate
33
44/**
5- * Holds if `call` is an interface call to method `m`, meaning that its receiver `recv` has an
6- * interface type.
5+ * Holds if `call` is an interface call to method `m`, meaning that its receiver `recv` has
6+ * interface type `tp` .
77 */
8- private predicate isInterfaceCallReceiver ( DataFlow:: CallNode call , DataFlow:: Node recv , string m ) {
8+ private predicate isInterfaceCallReceiver (
9+ DataFlow:: CallNode call , DataFlow:: Node recv , InterfaceType tp , string m
10+ ) {
911 call .getReceiver ( ) = recv and
10- recv .getType ( ) .getUnderlyingType ( ) instanceof InterfaceType and
12+ recv .getType ( ) .getUnderlyingType ( ) = tp and
1113 m = call .getCalleeName ( )
1214}
1315
1416/** Gets a data-flow node that may flow into the receiver value of `call`, which is an interface value. */
1517private DataFlow:: Node getInterfaceCallReceiverSource ( DataFlow:: CallNode call ) {
16- isInterfaceCallReceiver ( call , result .getASuccessor * ( ) , _)
18+ isInterfaceCallReceiver ( call , result .getASuccessor * ( ) , _, _ )
1719}
1820
1921/** Gets the type of `nd`, which must be a valid type and not an interface type. */
@@ -44,7 +46,7 @@ private predicate isConcreteValue(DataFlow::Node nd) {
4446 * types of `recv` can be established by local reasoning.
4547 */
4648private predicate isConcreteInterfaceCall ( DataFlow:: Node call , DataFlow:: Node recv , string m ) {
47- isInterfaceCallReceiver ( call , recv , m ) and isConcreteValue ( recv )
49+ isInterfaceCallReceiver ( call , recv , _ , m ) and isConcreteValue ( recv )
4850}
4951
5052/**
@@ -61,14 +63,36 @@ private FuncDecl getConcreteTarget(DataFlow::CallNode call) {
6163 )
6264}
6365
66+ /**
67+ * Holds if `call` is a method call whose receiver has an interface type.
68+ */
69+ private predicate isInterfaceMethodCall ( DataFlow:: CallNode call ) {
70+ isInterfaceCallReceiver ( call , _, _, _)
71+ }
72+
73+ /**
74+ * Gets a method that might be called by `call`, where we restrict the result to
75+ * implement the interface type of the receiver of `call`.
76+ */
77+ private MethodDecl getRestrictedInterfaceTarget ( DataFlow:: CallNode call ) {
78+ exists ( InterfaceType tp , Type recvtp , string m |
79+ isInterfaceCallReceiver ( call , _, tp , m ) and
80+ result = recvtp .getMethod ( m ) .( DeclaredFunction ) .getFuncDecl ( ) and
81+ recvtp .implements ( tp )
82+ )
83+ }
84+
6485/**
6586 * Gets a function that might be called by `call`.
6687 */
6788DataFlowCallable viableCallable ( CallExpr ma ) {
6889 exists ( DataFlow:: CallNode call | call .asExpr ( ) = ma |
6990 if isConcreteInterfaceCall ( call , _, _)
7091 then result = getConcreteTarget ( call )
71- else result = call .getACallee ( )
92+ else
93+ if isInterfaceMethodCall ( call )
94+ then result = getRestrictedInterfaceTarget ( call )
95+ else result = call .getACallee ( )
7296 )
7397}
7498
0 commit comments