@@ -13,20 +13,38 @@ private int varargs_length_objectapi(Call call) {
13
13
result = count ( call .getStarargs ( ) .( List ) .getAnElt ( ) )
14
14
}
15
15
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
+
16
27
/** Gets a keyword argument that is not a keyword-only parameter. */
17
28
private Keyword not_keyword_only_arg_objectapi ( Call call , FunctionObject func ) {
18
29
func .getACall ( ) .getNode ( ) = call and
19
30
result = call .getAKeyword ( ) and
20
31
not func .getFunction ( ) .getAKeywordOnlyArg ( ) .getId ( ) = result .getArg ( )
21
32
}
22
33
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
+
23
41
/** Gets the count of arguments that are passed as positional parameters even if they
24
42
* are named in the call.
25
43
* This is the sum of the number of positional arguments, the number of elements in any explicit tuple passed as *arg
26
44
* plus the number of keyword arguments that do not match keyword-only arguments (if the function does not take **kwargs).
27
45
*/
28
46
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 ) {
30
48
call = get_a_call_objectapi ( callable ) .getNode ( ) and
31
49
exists ( int positional_keywords |
32
50
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
40
58
)
41
59
}
42
60
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
+
43
81
int arg_count_objectapi ( Call call ) {
44
82
result = count ( call .getAnArg ( ) ) + varargs_length_objectapi ( call ) + count ( call .getAKeyword ( ) )
45
83
}
46
84
85
+ int arg_count ( Call call ) {
86
+ result = count ( call .getAnArg ( ) ) + varargs_length ( call ) + count ( call .getAKeyword ( ) )
87
+ }
88
+
47
89
/* Gets a call corresponding to the given class or function*/
48
90
private ControlFlowNode get_a_call_objectapi ( Object callable ) {
49
91
result = callable .( ClassObject ) .getACall ( )
50
92
or
51
93
result = callable .( FunctionObject ) .getACall ( )
52
94
}
53
95
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
+
54
103
/* Gets the function object corresponding to the given class or function*/
55
104
FunctionObject get_function_or_initializer_objectapi ( Object func_or_cls ) {
56
105
result = func_or_cls .( FunctionObject )
57
106
or
58
107
result = func_or_cls .( ClassObject ) .declaredAttribute ( "__init__" )
59
108
}
60
109
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
+
61
117
62
118
/**Whether there is an illegally named parameter called `name` in the `call` to `func` */
63
119
predicate 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
67
123
not get_function_or_initializer_objectapi ( func ) .isLegalArgumentName ( name )
68
124
}
69
125
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
+
70
134
/**Whether there are too few arguments in the `call` to `callable` where `limit` is the lowest number of legal arguments */
71
135
predicate too_few_args_objectapi ( Call call , Object callable , int limit ) {
72
136
// 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) {
88
152
)
89
153
}
90
154
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
+
91
176
/**Whether there are too many arguments in the `call` to `func` where `limit` is the highest number of legal arguments */
92
177
predicate too_many_args_objectapi ( Call call , Object callable , int limit ) {
93
178
// 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) {
103
188
callable instanceof ClassObject and
104
189
call .getAFlowNode ( ) = get_a_call_objectapi ( callable ) and limit = func .maxParameters ( ) - 1
105
190
) 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
107
210
}
108
211
109
212
/** 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
113
216
too_many_args_objectapi ( call , func , limit ) and too = "too many"
114
217
}
115
218
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
+
116
226
/** Holds if `call` has correct number of arguments for `func`.
117
227
* Implies nothing about whether `call` could call `func`.
118
228
*/
@@ -123,8 +233,25 @@ predicate correct_args_if_called_as_method_objectapi(Call call, FunctionObject f
123
233
arg_count_objectapi ( call ) < func .maxParameters ( )
124
234
}
125
235
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
+
126
246
/** Holds if `call` is a call to `overriding`, which overrides `func`. */
127
247
predicate overridden_call_objectapi ( FunctionObject func , FunctionObject overriding , Call call ) {
128
248
overriding .overrides ( func ) and
129
249
overriding .getACall ( ) .getNode ( ) = call
130
250
}
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