mirror of
https://github.com/github/codeql.git
synced 2026-03-28 10:18:17 +01:00
Will need subsequent PRs fixing up test failures (due to deprecated methods moving around), but other than that everything should be straight-forward.
62 lines
2.1 KiB
Plaintext
62 lines
2.1 KiB
Plaintext
/**
|
|
* @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) = c.getArg(arg).(Name).getId()) and
|
|
/* Either no **kwargs or they must match */
|
|
(
|
|
not exists(f.getKwarg()) and not exists(c.getKwargs())
|
|
or
|
|
f.getKwarg().(Name).getId() = c.getKwargs().(Name).getId()
|
|
) and
|
|
/* Either no *args or they must match */
|
|
(
|
|
not exists(f.getVararg()) and not exists(c.getStarargs())
|
|
or
|
|
f.getVararg().(Name).getId() = c.getStarargs().(Name).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(ClassValue c | e.pointsTo(c))
|
|
or
|
|
/* plain function */
|
|
exists(FunctionValue f | e.pointsTo(f))
|
|
or
|
|
/* bound-method of enclosing instance */
|
|
exists(ClassValue cls, Attribute a | cls.getScope() = l.getScope().getScope() and a = e |
|
|
a.getObject().(Name).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."
|