|
|
|
|
@@ -2,7 +2,7 @@ import python
|
|
|
|
|
|
|
|
|
|
import Testing.Mox
|
|
|
|
|
|
|
|
|
|
private int varargs_length(Call call) {
|
|
|
|
|
private int varargs_length_objectapi(Call call) {
|
|
|
|
|
not exists(call.getStarargs()) and result = 0
|
|
|
|
|
or
|
|
|
|
|
exists(TupleObject t |
|
|
|
|
|
@@ -14,7 +14,7 @@ private int varargs_length(Call call) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Gets a keyword argument that is not a keyword-only parameter. */
|
|
|
|
|
private Keyword not_keyword_only_arg(Call call, FunctionObject func) {
|
|
|
|
|
private Keyword not_keyword_only_arg_objectapi(Call call, FunctionObject func) {
|
|
|
|
|
func.getACall().getNode() = call and
|
|
|
|
|
result = call.getAKeyword() and
|
|
|
|
|
not func.getFunction().getAKeywordOnlyArg().getId() = result.getArg()
|
|
|
|
|
@@ -26,33 +26,33 @@ private Keyword not_keyword_only_arg(Call call, FunctionObject func) {
|
|
|
|
|
* plus the number of keyword arguments that do not match keyword-only arguments (if the function does not take **kwargs).
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
private int positional_arg_count_for_call(Call call, Object callable) {
|
|
|
|
|
call = get_a_call(callable).getNode() and
|
|
|
|
|
private int positional_arg_count_objectapi_for_call_objectapi(Call call, Object callable) {
|
|
|
|
|
call = get_a_call_objectapi(callable).getNode() and
|
|
|
|
|
exists(int positional_keywords |
|
|
|
|
|
exists(FunctionObject func | func = get_function_or_initializer(callable) |
|
|
|
|
|
exists(FunctionObject func | func = get_function_or_initializer_objectapi(callable) |
|
|
|
|
|
not func.getFunction().hasKwArg() and
|
|
|
|
|
positional_keywords = count(not_keyword_only_arg(call, func))
|
|
|
|
|
positional_keywords = count(not_keyword_only_arg_objectapi(call, func))
|
|
|
|
|
or
|
|
|
|
|
func.getFunction().hasKwArg() and positional_keywords = 0
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
result = count(call.getAnArg()) + varargs_length(call) + positional_keywords
|
|
|
|
|
result = count(call.getAnArg()) + varargs_length_objectapi(call) + positional_keywords
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int arg_count(Call call) {
|
|
|
|
|
result = count(call.getAnArg()) + varargs_length(call) + count(call.getAKeyword())
|
|
|
|
|
int arg_count_objectapi(Call call) {
|
|
|
|
|
result = count(call.getAnArg()) + varargs_length_objectapi(call) + count(call.getAKeyword())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Gets a call corresponding to the given class or function*/
|
|
|
|
|
private ControlFlowNode get_a_call(Object callable) {
|
|
|
|
|
private ControlFlowNode get_a_call_objectapi(Object callable) {
|
|
|
|
|
result = callable.(ClassObject).getACall()
|
|
|
|
|
or
|
|
|
|
|
result = callable.(FunctionObject).getACall()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Gets the function object corresponding to the given class or function*/
|
|
|
|
|
FunctionObject get_function_or_initializer(Object func_or_cls) {
|
|
|
|
|
FunctionObject get_function_or_initializer_objectapi(Object func_or_cls) {
|
|
|
|
|
result = func_or_cls.(FunctionObject)
|
|
|
|
|
or
|
|
|
|
|
result = func_or_cls.(ClassObject).declaredAttribute("__init__")
|
|
|
|
|
@@ -60,20 +60,20 @@ FunctionObject get_function_or_initializer(Object func_or_cls) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**Whether there is an illegally named parameter called `name` in the `call` to `func` */
|
|
|
|
|
predicate illegally_named_parameter(Call call, Object func, string name) {
|
|
|
|
|
predicate illegally_named_parameter_objectapi(Call call, Object func, string name) {
|
|
|
|
|
not func.isC() and
|
|
|
|
|
name = call.getANamedArgumentName() and
|
|
|
|
|
call.getAFlowNode() = get_a_call(func) and
|
|
|
|
|
not get_function_or_initializer(func).isLegalArgumentName(name)
|
|
|
|
|
call.getAFlowNode() = get_a_call_objectapi(func) and
|
|
|
|
|
not get_function_or_initializer_objectapi(func).isLegalArgumentName(name)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**Whether there are too few arguments in the `call` to `callable` where `limit` is the lowest number of legal arguments */
|
|
|
|
|
predicate too_few_args(Call call, Object callable, int limit) {
|
|
|
|
|
predicate too_few_args_objectapi(Call call, Object callable, int limit) {
|
|
|
|
|
// Exclude cases where an incorrect name is used as that is covered by 'Wrong name for an argument in a call'
|
|
|
|
|
not illegally_named_parameter(call, callable, _) and
|
|
|
|
|
not illegally_named_parameter_objectapi(call, callable, _) and
|
|
|
|
|
not exists(call.getStarargs()) and not exists(call.getKwargs()) and
|
|
|
|
|
arg_count(call) < limit and
|
|
|
|
|
exists(FunctionObject func | func = get_function_or_initializer(callable) |
|
|
|
|
|
arg_count_objectapi(call) < limit and
|
|
|
|
|
exists(FunctionObject func | func = get_function_or_initializer_objectapi(callable) |
|
|
|
|
|
call = func.getAFunctionCall().getNode() and limit = func.minParameters() and
|
|
|
|
|
/* The combination of misuse of `mox.Mox().StubOutWithMock()`
|
|
|
|
|
* and a bug in mox's implementation of methods results in having to
|
|
|
|
|
@@ -84,16 +84,16 @@ predicate too_few_args(Call call, Object callable, int limit) {
|
|
|
|
|
call = func.getAMethodCall().getNode() and limit = func.minParameters() - 1
|
|
|
|
|
or
|
|
|
|
|
callable instanceof ClassObject and
|
|
|
|
|
call.getAFlowNode() = get_a_call(callable) and limit = func.minParameters() - 1
|
|
|
|
|
call.getAFlowNode() = get_a_call_objectapi(callable) and limit = func.minParameters() - 1
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**Whether there are too many arguments in the `call` to `func` where `limit` is the highest number of legal arguments */
|
|
|
|
|
predicate too_many_args(Call call, Object callable, int limit) {
|
|
|
|
|
predicate too_many_args_objectapi(Call call, Object callable, int limit) {
|
|
|
|
|
// Exclude cases where an incorrect name is used as that is covered by 'Wrong name for an argument in a call'
|
|
|
|
|
not illegally_named_parameter(call, callable, _) and
|
|
|
|
|
not illegally_named_parameter_objectapi(call, callable, _) and
|
|
|
|
|
exists(FunctionObject func |
|
|
|
|
|
func = get_function_or_initializer(callable) and
|
|
|
|
|
func = get_function_or_initializer_objectapi(callable) and
|
|
|
|
|
not func.getFunction().hasVarArg() and limit >= 0
|
|
|
|
|
|
|
|
|
|
|
call = func.getAFunctionCall().getNode() and limit = func.maxParameters()
|
|
|
|
|
@@ -101,30 +101,30 @@ predicate too_many_args(Call call, Object callable, int limit) {
|
|
|
|
|
call = func.getAMethodCall().getNode() and limit = func.maxParameters() - 1
|
|
|
|
|
or
|
|
|
|
|
callable instanceof ClassObject and
|
|
|
|
|
call.getAFlowNode() = get_a_call(callable) and limit = func.maxParameters() - 1
|
|
|
|
|
call.getAFlowNode() = get_a_call_objectapi(callable) and limit = func.maxParameters() - 1
|
|
|
|
|
) and
|
|
|
|
|
positional_arg_count_for_call(call, callable) > limit
|
|
|
|
|
positional_arg_count_objectapi_for_call_objectapi(call, callable) > limit
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Holds if `call` has too many or too few arguments for `func` */
|
|
|
|
|
predicate wrong_args(Call call, FunctionObject func, int limit, string too) {
|
|
|
|
|
too_few_args(call, func, limit) and too = "too few"
|
|
|
|
|
predicate wrong_args_objectapi(Call call, FunctionObject func, int limit, string too) {
|
|
|
|
|
too_few_args_objectapi(call, func, limit) and too = "too few"
|
|
|
|
|
or
|
|
|
|
|
too_many_args(call, func, limit) and too = "too many"
|
|
|
|
|
too_many_args_objectapi(call, func, limit) and too = "too many"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Holds if `call` has correct number of arguments for `func`.
|
|
|
|
|
* Implies nothing about whether `call` could call `func`.
|
|
|
|
|
*/
|
|
|
|
|
bindingset[call, func]
|
|
|
|
|
predicate correct_args_if_called_as_method(Call call, FunctionObject func) {
|
|
|
|
|
arg_count(call)+1 >= func.minParameters()
|
|
|
|
|
predicate correct_args_if_called_as_method_objectapi(Call call, FunctionObject func) {
|
|
|
|
|
arg_count_objectapi(call)+1 >= func.minParameters()
|
|
|
|
|
and
|
|
|
|
|
arg_count(call) < func.maxParameters()
|
|
|
|
|
arg_count_objectapi(call) < func.maxParameters()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Holds if `call` is a call to `overriding`, which overrides `func`. */
|
|
|
|
|
predicate overridden_call(FunctionObject func, FunctionObject overriding, Call call) {
|
|
|
|
|
predicate overridden_call_objectapi(FunctionObject func, FunctionObject overriding, Call call) {
|
|
|
|
|
overriding.overrides(func) and
|
|
|
|
|
overriding.getACall().getNode() = call
|
|
|
|
|
}
|
|
|
|
|
|