Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions python/ql/src/semmle/python/Function.qll
Original file line number Diff line number Diff line change
Expand Up @@ -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__" }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -498,10 +498,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. */
Expand Down Expand Up @@ -544,6 +546,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;
Expand Down
3 changes: 3 additions & 0 deletions python/ql/src/semmle/python/objects/ObjectAPI.qll
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
7 changes: 7 additions & 0 deletions python/ql/test/experimental/dataflow/consistency/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -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