@@ -13,20 +13,38 @@ private int varargs_length_objectapi(Call call) {
1313 result = count ( call .getStarargs ( ) .( List ) .getAnElt ( ) )
1414}
1515
16+ private int varargs_length ( Call call ) {
17+ not exists ( call .getStarargs ( ) ) and result = 0
18+ or
19+ exists ( TupleValue t |
20+ call .getStarargs ( ) .pointsTo ( t ) |
21+ result = t .length ( )
22+ )
23+ or
24+ result = count ( call .getStarargs ( ) .( List ) .getAnElt ( ) )
25+ }
26+
1627/** Gets a keyword argument that is not a keyword-only parameter. */
1728private Keyword not_keyword_only_arg_objectapi ( Call call , FunctionObject func ) {
1829 func .getACall ( ) .getNode ( ) = call and
1930 result = call .getAKeyword ( ) and
2031 not func .getFunction ( ) .getAKeywordOnlyArg ( ) .getId ( ) = result .getArg ( )
2132}
2233
34+ /** Gets a keyword argument that is not a keyword-only parameter. */
35+ private Keyword not_keyword_only_arg ( Call call , FunctionValue func ) {
36+ func .getACall ( ) .getNode ( ) = call and
37+ result = call .getAKeyword ( ) and
38+ not func .getScope ( ) .getAKeywordOnlyArg ( ) .getId ( ) = result .getArg ( )
39+ }
40+
2341/** Gets the count of arguments that are passed as positional parameters even if they
2442 * are named in the call.
2543 * This is the sum of the number of positional arguments, the number of elements in any explicit tuple passed as *arg
2644 * plus the number of keyword arguments that do not match keyword-only arguments (if the function does not take **kwargs).
2745 */
2846
29- private int positional_arg_count_objectapi_for_call_objectapi ( Call call , Object callable ) {
47+ private int positional_arg_count_for_call_objectapi ( Call call , Object callable ) {
3048 call = get_a_call_objectapi ( callable ) .getNode ( ) and
3149 exists ( int positional_keywords |
3250 exists ( FunctionObject func | func = get_function_or_initializer_objectapi ( callable ) |
@@ -40,24 +58,62 @@ private int positional_arg_count_objectapi_for_call_objectapi(Call call, Object
4058 )
4159}
4260
61+ /** Gets the count of arguments that are passed as positional parameters even if they
62+ * are named in the call.
63+ * This is the sum of the number of positional arguments, the number of elements in any explicit tuple passed as *arg
64+ * plus the number of keyword arguments that do not match keyword-only arguments (if the function does not take **kwargs).
65+ */
66+
67+ private int positional_arg_count_for_call ( Call call , Value callable ) {
68+ call = get_a_call ( callable ) .getNode ( ) and
69+ exists ( int positional_keywords |
70+ exists ( FunctionValue func | func = get_function_or_initializer ( callable ) |
71+ not func .getScope ( ) .hasKwArg ( ) and
72+ positional_keywords = count ( not_keyword_only_arg ( call , func ) )
73+ or
74+ func .getScope ( ) .hasKwArg ( ) and positional_keywords = 0
75+ )
76+ |
77+ result = count ( call .getAnArg ( ) ) + varargs_length_objectapi ( call ) + positional_keywords
78+ )
79+ }
80+
4381int arg_count_objectapi ( Call call ) {
4482 result = count ( call .getAnArg ( ) ) + varargs_length_objectapi ( call ) + count ( call .getAKeyword ( ) )
4583}
4684
85+ int arg_count ( Call call ) {
86+ result = count ( call .getAnArg ( ) ) + varargs_length ( call ) + count ( call .getAKeyword ( ) )
87+ }
88+
4789/* Gets a call corresponding to the given class or function*/
4890private ControlFlowNode get_a_call_objectapi ( Object callable ) {
4991 result = callable .( ClassObject ) .getACall ( )
5092 or
5193 result = callable .( FunctionObject ) .getACall ( )
5294}
5395
96+ /* Gets a call corresponding to the given class or function*/
97+ private ControlFlowNode get_a_call ( Value callable ) {
98+ result = callable .( ClassValue ) .getACall ( )
99+ or
100+ result = callable .( FunctionValue ) .getACall ( )
101+ }
102+
54103/* Gets the function object corresponding to the given class or function*/
55104FunctionObject get_function_or_initializer_objectapi ( Object func_or_cls ) {
56105 result = func_or_cls .( FunctionObject )
57106 or
58107 result = func_or_cls .( ClassObject ) .declaredAttribute ( "__init__" )
59108}
60109
110+ /* Gets the function object corresponding to the given class or function*/
111+ FunctionValue get_function_or_initializer ( Value func_or_cls ) {
112+ result = func_or_cls .( FunctionValue )
113+ or
114+ result = func_or_cls .( ClassValue ) .declaredAttribute ( "__init__" )
115+ }
116+
61117
62118/**Whether there is an illegally named parameter called `name` in the `call` to `func` */
63119predicate illegally_named_parameter_objectapi ( Call call , Object func , string name ) {
@@ -67,6 +123,14 @@ predicate illegally_named_parameter_objectapi(Call call, Object func, string nam
67123 not get_function_or_initializer_objectapi ( func ) .isLegalArgumentName ( name )
68124}
69125
126+ /**Whether there is an illegally named parameter called `name` in the `call` to `func` */
127+ predicate illegally_named_parameter ( Call call , Value func , string name ) {
128+ not func .isBuiltin ( ) and
129+ name = call .getANamedArgumentName ( ) and
130+ call .getAFlowNode ( ) = get_a_call ( func ) and
131+ not get_function_or_initializer ( func ) .isLegalArgumentName ( name )
132+ }
133+
70134/**Whether there are too few arguments in the `call` to `callable` where `limit` is the lowest number of legal arguments */
71135predicate too_few_args_objectapi ( Call call , Object callable , int limit ) {
72136 // Exclude cases where an incorrect name is used as that is covered by 'Wrong name for an argument in a call'
@@ -88,6 +152,27 @@ predicate too_few_args_objectapi(Call call, Object callable, int limit) {
88152 )
89153}
90154
155+ /**Whether there are too few arguments in the `call` to `callable` where `limit` is the lowest number of legal arguments */
156+ predicate too_few_args ( Call call , Value callable , int limit ) {
157+ // Exclude cases where an incorrect name is used as that is covered by 'Wrong name for an argument in a call'
158+ not illegally_named_parameter ( call , callable , _) and
159+ not exists ( call .getStarargs ( ) ) and not exists ( call .getKwargs ( ) ) and
160+ arg_count ( call ) < limit and
161+ exists ( FunctionValue func | func = get_function_or_initializer ( callable ) |
162+ call = func .getACall ( ) .getNode ( ) and limit = func .minParameters ( ) and
163+ /* The combination of misuse of `mox.Mox().StubOutWithMock()`
164+ * and a bug in mox's implementation of methods results in having to
165+ * pass 1 too few arguments to the mocked function.
166+ */
167+ not ( useOfMoxInModule ( call .getEnclosingModule ( ) ) and func .isNormalMethod ( ) )
168+ or
169+ call = func .getACall ( ) .getNode ( ) and limit = func .minParameters ( ) - 1
170+ or
171+ callable instanceof ClassValue and
172+ call .getAFlowNode ( ) = get_a_call ( callable ) and limit = func .minParameters ( ) - 1
173+ )
174+ }
175+
91176/**Whether there are too many arguments in the `call` to `func` where `limit` is the highest number of legal arguments */
92177predicate too_many_args_objectapi ( Call call , Object callable , int limit ) {
93178 // Exclude cases where an incorrect name is used as that is covered by 'Wrong name for an argument in a call'
@@ -103,7 +188,25 @@ predicate too_many_args_objectapi(Call call, Object callable, int limit) {
103188 callable instanceof ClassObject and
104189 call .getAFlowNode ( ) = get_a_call_objectapi ( callable ) and limit = func .maxParameters ( ) - 1
105190 ) and
106- positional_arg_count_objectapi_for_call_objectapi ( call , callable ) > limit
191+ positional_arg_count_for_call_objectapi ( call , callable ) > limit
192+ }
193+
194+ /**Whether there are too many arguments in the `call` to `func` where `limit` is the highest number of legal arguments */
195+ predicate too_many_args ( Call call , Value callable , int limit ) {
196+ // Exclude cases where an incorrect name is used as that is covered by 'Wrong name for an argument in a call'
197+ not illegally_named_parameter ( call , callable , _) and
198+ exists ( FunctionValue func |
199+ func = get_function_or_initializer ( callable ) and
200+ not func .getScope ( ) .hasVarArg ( ) and limit >= 0
201+ |
202+ call = func .getACall ( ) .getNode ( ) and limit = func .maxParameters ( )
203+ or
204+ call = func .getACall ( ) .getNode ( ) and limit = func .maxParameters ( ) - 1
205+ or
206+ callable instanceof ClassValue and
207+ call .getAFlowNode ( ) = get_a_call ( callable ) and limit = func .maxParameters ( ) - 1
208+ ) and
209+ positional_arg_count_for_call ( call , callable ) > limit
107210}
108211
109212/** Holds if `call` has too many or too few arguments for `func` */
@@ -113,6 +216,13 @@ predicate wrong_args_objectapi(Call call, FunctionObject func, int limit, string
113216 too_many_args_objectapi ( call , func , limit ) and too = "too many"
114217}
115218
219+ /** Holds if `call` has too many or too few arguments for `func` */
220+ predicate wrong_args ( Call call , FunctionValue func , int limit , string too ) {
221+ too_few_args ( call , func , limit ) and too = "too few"
222+ or
223+ too_many_args ( call , func , limit ) and too = "too many"
224+ }
225+
116226/** Holds if `call` has correct number of arguments for `func`.
117227 * Implies nothing about whether `call` could call `func`.
118228 */
@@ -123,8 +233,25 @@ predicate correct_args_if_called_as_method_objectapi(Call call, FunctionObject f
123233 arg_count_objectapi ( call ) < func .maxParameters ( )
124234}
125235
236+ /** Holds if `call` has correct number of arguments for `func`.
237+ * Implies nothing about whether `call` could call `func`.
238+ */
239+ bindingset [ call, func]
240+ predicate correct_args_if_called_as_method ( Call call , FunctionValue func ) {
241+ arg_count ( call ) + 1 >= func .minParameters ( )
242+ and
243+ arg_count ( call ) < func .maxParameters ( )
244+ }
245+
126246/** Holds if `call` is a call to `overriding`, which overrides `func`. */
127247predicate overridden_call_objectapi ( FunctionObject func , FunctionObject overriding , Call call ) {
128248 overriding .overrides ( func ) and
129249 overriding .getACall ( ) .getNode ( ) = call
130250}
251+
252+ /** Holds if `call` is a call to `overriding`, which overrides `func`. */
253+ predicate overridden_call ( FunctionValue func , FunctionValue overriding , Call call ) {
254+ overriding .overrides ( func ) and
255+ overriding .getACall ( ) .getNode ( ) = call
256+ }
257+
0 commit comments