@@ -5,11 +5,14 @@ import semmle.python.ApiGraphs
55import semmle.python.dataflow.new.internal.DataFlowDispatch
66import codeql.util.Option
77
8- predicate multipleCallsToSuperclassMethod ( Function meth , Function calledMulti , string name ) {
9- exists ( DataFlow:: MethodCallNode call1 , DataFlow:: MethodCallNode call2 , Class cls |
8+ predicate multipleCallsToSuperclassMethod (
9+ Function meth , Function calledMulti , DataFlow:: MethodCallNode call1 ,
10+ DataFlow:: MethodCallNode call2 , string name
11+ ) {
12+ exists ( Class cls |
1013 meth .getName ( ) = name and
1114 meth .getScope ( ) = cls and
12- call1 .asExpr ( ) != call2 .asExpr ( ) and
15+ call1 .getLocation ( ) . toString ( ) < call2 .getLocation ( ) . toString ( ) and
1316 calledMulti = getASuperCallTargetFromCall ( cls , meth , call1 , name ) and
1417 calledMulti = getASuperCallTargetFromCall ( cls , meth , call2 , name ) and
1518 nonTrivial ( calledMulti )
@@ -18,23 +21,44 @@ predicate multipleCallsToSuperclassMethod(Function meth, Function calledMulti, s
1821
1922Function getASuperCallTargetFromCall (
2023 Class mroBase , Function meth , DataFlow:: MethodCallNode call , string name
24+ ) {
25+ exists ( Function target | target = getDirectSuperCallTargetFromCall ( mroBase , meth , call , name ) |
26+ result = target
27+ or
28+ result = getASuperCallTargetFromCall ( mroBase , target , _, name )
29+ )
30+ }
31+
32+ Function getDirectSuperCallTargetFromCall (
33+ Class mroBase , Function meth , DataFlow:: MethodCallNode call , string name
2134) {
2235 meth = call .getScope ( ) and
2336 getADirectSuperclass * ( mroBase ) = meth .getScope ( ) and
2437 meth .getName ( ) = name and
2538 call .calls ( _, name ) and
26- exists ( Class targetCls | result = getASuperCallTargetFromClass ( mroBase , targetCls , name ) |
39+ mroBase = getADirectSubclass * ( meth .getScope ( ) ) and
40+ exists ( Class targetCls |
41+ // the differences between 0-arg and 2-arg super is not considered; we assume each super uses the mro of the instance `self`
2742 superCall ( call , _) and
28- targetCls = getNextClassInMroKnownStartingClass ( meth .getScope ( ) , mroBase )
43+ targetCls = getNextClassInMroKnownStartingClass ( meth .getScope ( ) , mroBase ) and
44+ result = findFunctionAccordingToMroKnownStartingClass ( targetCls , mroBase , name )
2945 or
30- callsMethodOnClassWithSelf ( meth , call , targetCls , _)
46+ // targetCls is the mro base for this lookup.
47+ // note however that if the call we find uses super(), that still uses the mro of the instance `self` will sill be used
48+ // assuming it's 0-arg or is 2-arg with `self` as second arg.
49+ callsMethodOnClassWithSelf ( meth , call , targetCls , _) and
50+ result = findFunctionAccordingToMroKnownStartingClass ( targetCls , targetCls , name )
3151 )
3252}
3353
3454Function getASuperCallTargetFromClass ( Class mroBase , Class cls , string name ) {
3555 exists ( Function target |
3656 target = findFunctionAccordingToMroKnownStartingClass ( cls , mroBase , name ) and
37- ( result = target or result = getASuperCallTargetFromCall ( mroBase , target , _, name ) )
57+ (
58+ result = target
59+ or
60+ result = getASuperCallTargetFromCall ( mroBase , target , _, name )
61+ )
3862 )
3963}
4064
0 commit comments