-
Notifications
You must be signed in to change notification settings - Fork 2k
Expand file tree
/
Copy pathUnnecessaryLambda.ql
More file actions
57 lines (53 loc) · 2.2 KB
/
UnnecessaryLambda.ql
File metadata and controls
57 lines (53 loc) · 2.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
/**
* @name Unnecessary lambda
* @description A lambda is used that calls through to a function without modifying any parameters
* @kind problem
* @tags maintainability
* useless-code
* @problem.severity recommendation
* @sub-severity high
* @precision high
* @id py/unnecessary-lambda
*/
import python
/* f consists of a single return statement, whose value is a call. The arguments of the call are exactly the parameters of f */
predicate simple_wrapper(Lambda l, Expr wrapped) {
exists(Function f, Call c | f = l.getInnerScope() and c = l.getExpression() |
wrapped = c.getFunc() and
count(f.getAnArg()) = count(c.getAnArg()) and
forall(int arg | exists(f.getArg(arg)) |
f.getArgName(arg) = ((Name)c.getArg(arg)).getId()) and
/* Either no **kwargs or they must match */
(not exists(f.getKwarg()) and not exists(c.getKwargs()) or
((Name)f.getKwarg()).getId() = ((Name)c.getKwargs()).getId()) and
/* Either no *args or they must match */
(not exists(f.getVararg()) and not exists(c.getStarargs()) or
((Name)f.getVararg()).getId() = ((Name)c.getStarargs()).getId()) and
/* No named parameters in call */
not exists(c.getAKeyword())
)
and
// f is not necessarily a drop-in replacement for the lambda if there are default argument values
not exists(l.getArgs().getADefault())
}
/* The expression called will refer to the same object if evaluated when the lambda is created or when the lambda is executed. */
predicate unnecessary_lambda(Lambda l, Expr e) {
simple_wrapper(l, e) and
(
/* plain class */
exists(ClassObject c | e.refersTo(c))
or
/* plain function */
exists(FunctionObject f | e.refersTo(f))
or
/* bound-method of enclosing instance */
exists(ClassObject cls, Attribute a |
cls.getPyClass() = l.getScope().getScope() and a = e |
((Name)a.getObject()).getId() = "self" and
cls.hasAttribute(a.getName())
)
)
}
from Lambda l, Expr e
where unnecessary_lambda(l, e)
select l, "This 'lambda' is just a simple wrapper around a callable object. Use that object directly."