Merge pull request #5022 from yoff/python-split-lambdas

Python: Callable for lambdas
This commit is contained in:
Taus
2021-01-29 14:12:26 +01:00
committed by GitHub
4 changed files with 44 additions and 1 deletions

View File

@@ -39,6 +39,16 @@ class Function extends Function_, Scope, AstNode {
exists(YieldFrom y | y.getScope() = this)
}
/**
* Holds if this function represents a lambda.
*
* The extractor reifies each lambda expression as a (local) function with the name
* "lambda". As `lambda` is a keyword in Python, it's impossible to create a function with this
* name otherwise, and so it's impossible to get a non-lambda function accidentally
* classified as a lambda.
*/
predicate isLambda() { this.getName() = "lambda" }
/** Whether this function is declared in a class and is named `__init__` */
predicate isInitMethod() { this.isMethod() and this.getName() = "__init__" }

View File

@@ -519,10 +519,12 @@ import ArgumentPassing
*/
newtype TDataFlowCallable =
TCallableValue(CallableValue callable) {
callable instanceof FunctionValue
callable instanceof FunctionValue and
not callable.(FunctionValue).isLambda()
or
callable instanceof ClassValue
} or
TLambda(Function lambda) { lambda.isLambda() } or
TModule(Module m)
/** Represents a callable. */
@@ -565,6 +567,27 @@ class DataFlowCallableValue extends DataFlowCallable, TCallableValue {
override CallableValue getCallableValue() { result = callable }
}
/** A class representing a callable lambda. */
class DataFlowLambda extends DataFlowCallable, TLambda {
Function lambda;
DataFlowLambda() { this = TLambda(lambda) }
override string toString() { result = lambda.toString() }
override CallNode getACall() { result = getCallableValue().getACall() }
override Scope getScope() { result = lambda.getEvaluatingScope() }
override NameNode getParameter(int n) { result = getParameter(getCallableValue(), n) }
override string getName() { result = "Lambda callable" }
override FunctionValue getCallableValue() {
result.getOrigin().getNode() = lambda.getDefinition()
}
}
/** A class representing the scope in which a `ModuleVariableNode` appears. */
class DataFlowModuleScope extends DataFlowCallable, TModule {
Module mod;

View File

@@ -720,6 +720,9 @@ abstract class FunctionValue extends CallableValue {
/** Gets a class that this function may return */
abstract ClassValue getAnInferredReturnType();
/** Holds if this function represents a lambda. */
predicate isLambda() { this.getOrigin().getNode() instanceof Lambda }
}
/** Class representing Python functions */

View File

@@ -249,3 +249,10 @@ def synth_arg_kwOverflow():
def synth_arg_kwUnpacked():
overflowCallee(**{"p": "42"})
def split_lambda(cond):
if cond:
pass
foo = lambda x: False
if cond:
pass