mirror of
https://github.com/github/codeql.git
synced 2025-12-18 01:33:15 +01:00
Merge pull request #3088 from tausbn/python-prepare-autoformatting
Python: Prepare for autoformatting.
This commit is contained in:
@@ -22,8 +22,8 @@ predicate multiple_calls_to_superclass_method(ClassObject self, FunctionObject m
|
|||||||
multiple_invocation_paths(top, i1, i2, multi) and
|
multiple_invocation_paths(top, i1, i2, multi) and
|
||||||
top.runtime(self.declaredAttribute(name)) and
|
top.runtime(self.declaredAttribute(name)) and
|
||||||
self.getASuperType().declaredAttribute(name) = multi |
|
self.getASuperType().declaredAttribute(name) = multi |
|
||||||
/* Only called twice if called from different functions,
|
// Only called twice if called from different functions,
|
||||||
* or if one call-site can reach the other */
|
// or if one call-site can reach the other.
|
||||||
i1.getCall().getScope() != i2.getCall().getScope()
|
i1.getCall().getScope() != i2.getCall().getScope()
|
||||||
or
|
or
|
||||||
i1.getCall().strictlyReaches(i2.getCall())
|
i1.getCall().strictlyReaches(i2.getCall())
|
||||||
|
|||||||
@@ -39,9 +39,9 @@ private Keyword not_keyword_only_arg(Call call, FunctionValue func) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the count of arguments that are passed as positional parameters even if they
|
/** Gets the count of arguments that are passed as positional parameters even if they
|
||||||
* are named in the call.
|
* are named in the call.
|
||||||
* This is the sum of the number of positional arguments, the number of elements in any explicit tuple passed as *arg
|
* This is the sum of the number of positional arguments, the number of elements in any explicit tuple passed as *arg
|
||||||
* plus the number of keyword arguments that do not match keyword-only arguments (if the function does not take **kwargs).
|
* 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_objectapi(Call call, Object callable) {
|
private int positional_arg_count_for_call_objectapi(Call call, Object callable) {
|
||||||
@@ -59,9 +59,9 @@ private int positional_arg_count_for_call_objectapi(Call call, Object callable)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the count of arguments that are passed as positional parameters even if they
|
/** Gets the count of arguments that are passed as positional parameters even if they
|
||||||
* are named in the call.
|
* are named in the call.
|
||||||
* This is the sum of the number of positional arguments, the number of elements in any explicit tuple passed as *arg
|
* This is the sum of the number of positional arguments, the number of elements in any explicit tuple passed as *arg
|
||||||
* plus the number of keyword arguments that do not match keyword-only arguments (if the function does not take **kwargs).
|
* 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, Value callable) {
|
private int positional_arg_count_for_call(Call call, Value callable) {
|
||||||
@@ -139,10 +139,9 @@ predicate too_few_args_objectapi(Call call, Object callable, int limit) {
|
|||||||
arg_count_objectapi(call) < limit and
|
arg_count_objectapi(call) < limit and
|
||||||
exists(FunctionObject func | func = get_function_or_initializer_objectapi(callable) |
|
exists(FunctionObject func | func = get_function_or_initializer_objectapi(callable) |
|
||||||
call = func.getAFunctionCall().getNode() and limit = func.minParameters() and
|
call = func.getAFunctionCall().getNode() and limit = func.minParameters() and
|
||||||
/* The combination of misuse of `mox.Mox().StubOutWithMock()`
|
// The combination of misuse of `mox.Mox().StubOutWithMock()`
|
||||||
* and a bug in mox's implementation of methods results in having to
|
// and a bug in mox's implementation of methods results in having to
|
||||||
* pass 1 too few arguments to the mocked function.
|
// pass 1 too few arguments to the mocked function.
|
||||||
*/
|
|
||||||
not (useOfMoxInModule(call.getEnclosingModule()) and func.isNormalMethod())
|
not (useOfMoxInModule(call.getEnclosingModule()) and func.isNormalMethod())
|
||||||
or
|
or
|
||||||
call = func.getAMethodCall().getNode() and limit = func.minParameters() - 1
|
call = func.getAMethodCall().getNode() and limit = func.minParameters() - 1
|
||||||
@@ -160,10 +159,9 @@ predicate too_few_args(Call call, Value callable, int limit) {
|
|||||||
arg_count(call) < limit and
|
arg_count(call) < limit and
|
||||||
exists(FunctionValue func | func = get_function_or_initializer(callable) |
|
exists(FunctionValue func | func = get_function_or_initializer(callable) |
|
||||||
call = func.getACall().getNode() and limit = func.minParameters() and
|
call = func.getACall().getNode() and limit = func.minParameters() and
|
||||||
/* The combination of misuse of `mox.Mox().StubOutWithMock()`
|
// The combination of misuse of `mox.Mox().StubOutWithMock()`
|
||||||
* and a bug in mox's implementation of methods results in having to
|
// and a bug in mox's implementation of methods results in having to
|
||||||
* pass 1 too few arguments to the mocked function.
|
// pass 1 too few arguments to the mocked function.
|
||||||
*/
|
|
||||||
not (useOfMoxInModule(call.getEnclosingModule()) and func.isNormalMethod())
|
not (useOfMoxInModule(call.getEnclosingModule()) and func.isNormalMethod())
|
||||||
or
|
or
|
||||||
call = func.getACall().getNode() and limit = func.minParameters() - 1
|
call = func.getACall().getNode() and limit = func.minParameters() - 1
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import python
|
import python
|
||||||
|
|
||||||
/** Whether `mox` or `.StubOutWithMock()` is used in thin module `m`.
|
/** Whether `mox` or `.StubOutWithMock()` is used in thin module `m`. */
|
||||||
*/
|
|
||||||
predicate useOfMoxInModule(Module m) {
|
predicate useOfMoxInModule(Module m) {
|
||||||
exists(ModuleObject mox |
|
exists(ModuleObject mox |
|
||||||
mox.getName() = "mox" or mox.getName() = "mox3.mox" |
|
mox.getName() = "mox" or mox.getName() = "mox3.mox" |
|
||||||
|
|||||||
@@ -48,8 +48,7 @@ class Symbol extends TSymbol {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Finds the `AstNode` that this `Symbol` refers to.
|
/** Finds the `AstNode` that this `Symbol` refers to. */
|
||||||
*/
|
|
||||||
AstNode find() {
|
AstNode find() {
|
||||||
this = TModule(result)
|
this = TModule(result)
|
||||||
or
|
or
|
||||||
@@ -91,8 +90,7 @@ class Symbol extends TSymbol {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the `Symbol` that is the named member of this `Symbol`.
|
/** Gets the `Symbol` that is the named member of this `Symbol`. */
|
||||||
*/
|
|
||||||
Symbol getMember(string name) {
|
Symbol getMember(string name) {
|
||||||
result = TMember(this, name)
|
result = TMember(this, name)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,8 +10,7 @@ private newtype TDefinition =
|
|||||||
a instanceof Expr or a instanceof Stmt or a instanceof Module
|
a instanceof Expr or a instanceof Stmt or a instanceof Module
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A definition for the purposes of jump-to-definition.
|
/** A definition for the purposes of jump-to-definition. */
|
||||||
*/
|
|
||||||
class Definition extends TLocalDefinition {
|
class Definition extends TLocalDefinition {
|
||||||
|
|
||||||
|
|
||||||
@@ -159,8 +158,7 @@ private predicate delete_defn(DeletionDefinition def, Definition defn) {
|
|||||||
none()
|
none()
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Implicit "defn" of the names of submodules at the start of an `__init__.py` file.
|
/* Implicit "defn" of the names of submodules at the start of an `__init__.py` file. */
|
||||||
*/
|
|
||||||
private predicate implicit_submodule_defn(ImplicitSubModuleDefinition def, Definition defn) {
|
private predicate implicit_submodule_defn(ImplicitSubModuleDefinition def, Definition defn) {
|
||||||
exists(PackageObject package, ModuleObject mod |
|
exists(PackageObject package, ModuleObject mod |
|
||||||
package.getInitModule().getModule() = def.getDefiningNode().getScope() and
|
package.getInitModule().getModule() = def.getDefiningNode().getScope() and
|
||||||
@@ -170,7 +168,9 @@ private predicate implicit_submodule_defn(ImplicitSubModuleDefinition def, Defin
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Helper for scope_entry_value_transfer(...). Transfer of values from the callsite to the callee, for enclosing variables, but not arguments/parameters */
|
/* Helper for scope_entry_value_transfer(...).
|
||||||
|
* Transfer of values from the callsite to the callee, for enclosing variables, but not arguments/parameters
|
||||||
|
*/
|
||||||
private predicate scope_entry_value_transfer_at_callsite(EssaVariable pred_var, ScopeEntryDefinition succ_def) {
|
private predicate scope_entry_value_transfer_at_callsite(EssaVariable pred_var, ScopeEntryDefinition succ_def) {
|
||||||
exists(CallNode callsite, FunctionObject f |
|
exists(CallNode callsite, FunctionObject f |
|
||||||
f.getACall() = callsite and
|
f.getACall() = callsite and
|
||||||
@@ -469,8 +469,8 @@ class NiceLocationExpr extends @py_expr {
|
|||||||
or
|
or
|
||||||
this.(Name).getLocation().hasLocationInfo(f, bl, bc, el, ec)
|
this.(Name).getLocation().hasLocationInfo(f, bl, bc, el, ec)
|
||||||
or
|
or
|
||||||
/* Show xxx for `xxx` in `from xxx import y` or
|
// Show xxx for `xxx` in `from xxx import y` or
|
||||||
* for `import xxx` or for `import xxx as yyy`. */
|
// for `import xxx` or for `import xxx as yyy`.
|
||||||
this.(ImportExpr).getLocation().hasLocationInfo(f, bl, bc, el, ec)
|
this.(ImportExpr).getLocation().hasLocationInfo(f, bl, bc, el, ec)
|
||||||
or
|
or
|
||||||
/* Show y for `y` in `from xxx import y` */
|
/* Show y for `y` in `from xxx import y` */
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ abstract class AstNode extends AstNode_ {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Whether this syntactic element is artificial, that is it is generated
|
/** Whether this syntactic element is artificial, that is it is generated
|
||||||
* by the compiler and is not present in the source */
|
* by the compiler and is not present in the source */
|
||||||
predicate isArtificial() {
|
predicate isArtificial() {
|
||||||
none()
|
none()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ class ClassDef extends Assign {
|
|||||||
class Class extends Class_, Scope, AstNode {
|
class Class extends Class_, Scope, AstNode {
|
||||||
|
|
||||||
/** Use getADecorator() instead of getDefinition().getADecorator()
|
/** Use getADecorator() instead of getDefinition().getADecorator()
|
||||||
* Use getMetaClass() instead of getDefinition().getMetaClass()
|
* Use getMetaClass() instead of getDefinition().getMetaClass()
|
||||||
*/
|
*/
|
||||||
deprecated ClassExpr getDefinition() {
|
deprecated ClassExpr getDefinition() {
|
||||||
result = this.getParent()
|
result = this.getParent()
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
|
|
||||||
import python
|
import python
|
||||||
|
|
||||||
/* A class representing the six comparison operators, ==, !=, <, <=, > and >=.
|
/** A class representing the six comparison operators, ==, !=, <, <=, > and >=. */
|
||||||
* */
|
|
||||||
class CompareOp extends int {
|
class CompareOp extends int {
|
||||||
|
|
||||||
CompareOp() {
|
CompareOp() {
|
||||||
|
|||||||
@@ -356,7 +356,7 @@ class Repr extends Repr_ {
|
|||||||
/* Constants */
|
/* Constants */
|
||||||
|
|
||||||
/** A bytes constant, such as `b'ascii'`. Note that unadorned string constants such as
|
/** A bytes constant, such as `b'ascii'`. Note that unadorned string constants such as
|
||||||
`"hello"` are treated as Bytes for Python2, but Unicode for Python3. */
|
* `"hello"` are treated as Bytes for Python2, but Unicode for Python3. */
|
||||||
class Bytes extends StrConst {
|
class Bytes extends StrConst {
|
||||||
|
|
||||||
/* syntax: b"hello" */
|
/* syntax: b"hello" */
|
||||||
@@ -395,8 +395,7 @@ class Ellipsis extends Ellipsis_ {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Immutable literal expressions (except tuples).
|
/** Immutable literal expressions (except tuples).
|
||||||
* Consists of string (both unicode and byte) literals
|
* Consists of string (both unicode and byte) literals and numeric literals.
|
||||||
* and numeric literals.
|
|
||||||
*/
|
*/
|
||||||
abstract class ImmutableLiteral extends Expr {
|
abstract class ImmutableLiteral extends Expr {
|
||||||
|
|
||||||
@@ -433,8 +432,10 @@ class IntegerLiteral extends Num {
|
|||||||
not this instanceof FloatLiteral and not this instanceof ImaginaryLiteral
|
not this instanceof FloatLiteral and not this instanceof ImaginaryLiteral
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the (integer) value of this constant. Will not return a result if the value does not fit into
|
/**
|
||||||
a 32 bit signed value */
|
* Gets the (integer) value of this constant. Will not return a result if the value does not fit into
|
||||||
|
* a 32 bit signed value
|
||||||
|
*/
|
||||||
int getValue() {
|
int getValue() {
|
||||||
result = this.getN().toInt()
|
result = this.getN().toInt()
|
||||||
}
|
}
|
||||||
@@ -540,8 +541,10 @@ class NegativeIntegerLiteral extends ImmutableLiteral, UnaryExpr {
|
|||||||
py_cobjectnames(result, "-" + this.getOperand().(IntegerLiteral).getN())
|
py_cobjectnames(result, "-" + this.getOperand().(IntegerLiteral).getN())
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the (integer) value of this constant. Will not return a result if the value does not fit into
|
/**
|
||||||
a 32 bit signed value */
|
* Gets the (integer) value of this constant. Will not return a result if the value does not fit into
|
||||||
|
* a 32 bit signed value
|
||||||
|
*/
|
||||||
int getValue() {
|
int getValue() {
|
||||||
result = -(this.getOperand().(IntegerLiteral).getValue())
|
result = -(this.getOperand().(IntegerLiteral).getValue())
|
||||||
}
|
}
|
||||||
@@ -549,7 +552,8 @@ class NegativeIntegerLiteral extends ImmutableLiteral, UnaryExpr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** A unicode string expression, such as `u"\u20ac"`. Note that unadorned string constants such as
|
/** A unicode string expression, such as `u"\u20ac"`. Note that unadorned string constants such as
|
||||||
"hello" are treated as Bytes for Python2, but Unicode for Python3. */
|
* "hello" are treated as Bytes for Python2, but Unicode for Python3.
|
||||||
|
*/
|
||||||
class Unicode extends StrConst {
|
class Unicode extends StrConst {
|
||||||
|
|
||||||
/* syntax: "hello" */
|
/* syntax: "hello" */
|
||||||
|
|||||||
@@ -129,8 +129,10 @@ class Folder extends Container {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A container is an abstract representation of a file system object that can
|
/**
|
||||||
hold elements of interest. */
|
* A container is an abstract representation of a file system object that can
|
||||||
|
* hold elements of interest.
|
||||||
|
*/
|
||||||
abstract class Container extends @container {
|
abstract class Container extends @container {
|
||||||
|
|
||||||
Container getParent() {
|
Container getParent() {
|
||||||
@@ -473,8 +475,10 @@ class Line extends @py_line {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A syntax error. Note that if there is a syntax error in a module,
|
/**
|
||||||
much information about that module will be lost */
|
* A syntax error. Note that if there is a syntax error in a module,
|
||||||
|
* much information about that module will be lost
|
||||||
|
*/
|
||||||
class SyntaxError extends Location {
|
class SyntaxError extends Location {
|
||||||
|
|
||||||
SyntaxError() {
|
SyntaxError() {
|
||||||
@@ -492,8 +496,10 @@ class SyntaxError extends Location {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** An encoding error. Note that if there is an encoding error in a module,
|
/**
|
||||||
much information about that module will be lost */
|
* An encoding error. Note that if there is an encoding error in a module,
|
||||||
|
* much information about that module will be lost
|
||||||
|
*/
|
||||||
class EncodingError extends SyntaxError {
|
class EncodingError extends SyntaxError {
|
||||||
|
|
||||||
EncodingError() {
|
EncodingError() {
|
||||||
|
|||||||
@@ -27,8 +27,8 @@ private AstNode toAst(ControlFlowNode n) {
|
|||||||
|
|
||||||
/** A control flow node. Control flow nodes have a many-to-one relation with syntactic nodes,
|
/** A control flow node. Control flow nodes have a many-to-one relation with syntactic nodes,
|
||||||
* although most syntactic nodes have only one corresponding control flow node.
|
* although most syntactic nodes have only one corresponding control flow node.
|
||||||
* Edges between control flow nodes include exceptional as well as normal control flow.
|
* Edges between control flow nodes include exceptional as well as normal control flow.
|
||||||
*/
|
*/
|
||||||
class ControlFlowNode extends @py_flow_node {
|
class ControlFlowNode extends @py_flow_node {
|
||||||
|
|
||||||
/** Whether this control flow node is a load (including those in augmented assignments) */
|
/** Whether this control flow node is a load (including those in augmented assignments) */
|
||||||
@@ -235,18 +235,18 @@ class ControlFlowNode extends @py_flow_node {
|
|||||||
PointsTo::pointsTo(this, context, value, origin)
|
PointsTo::pointsTo(this, context, value, origin)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets what this flow node might "refer-to". Performs a combination of localized (intra-procedural) points-to
|
/**
|
||||||
* analysis and global module-level analysis. This points-to analysis favours precision over recall. It is highly
|
* Gets what this flow node might "refer-to". Performs a combination of localized (intra-procedural) points-to
|
||||||
* precise, but may not provide information for a significant number of flow-nodes.
|
* analysis and global module-level analysis. This points-to analysis favours precision over recall. It is highly
|
||||||
* If the class is unimportant then use `refersTo(value)` or `refersTo(value, origin)` instead.
|
* precise, but may not provide information for a significant number of flow-nodes.
|
||||||
|
* If the class is unimportant then use `refersTo(value)` or `refersTo(value, origin)` instead.
|
||||||
*/
|
*/
|
||||||
pragma [nomagic]
|
pragma [nomagic]
|
||||||
predicate refersTo(Object obj, ClassObject cls, ControlFlowNode origin) {
|
predicate refersTo(Object obj, ClassObject cls, ControlFlowNode origin) {
|
||||||
this.refersTo(_, obj, cls, origin)
|
this.refersTo(_, obj, cls, origin)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets what this expression might "refer-to" in the given `context`.
|
/** Gets what this expression might "refer-to" in the given `context`. */
|
||||||
*/
|
|
||||||
pragma [nomagic]
|
pragma [nomagic]
|
||||||
predicate refersTo(Context context, Object obj, ClassObject cls, ControlFlowNode origin) {
|
predicate refersTo(Context context, Object obj, ClassObject cls, ControlFlowNode origin) {
|
||||||
not obj = unknownValue() and
|
not obj = unknownValue() and
|
||||||
@@ -329,8 +329,8 @@ class ControlFlowNode extends @py_flow_node {
|
|||||||
exists(BasicBlock b |
|
exists(BasicBlock b |
|
||||||
start_bb_likely_reachable(b) and
|
start_bb_likely_reachable(b) and
|
||||||
not end_bb_likely_reachable(b) and
|
not end_bb_likely_reachable(b) and
|
||||||
/* If there is an unlikely successor edge earlier in the BB
|
// If there is an unlikely successor edge earlier in the BB
|
||||||
* than this node, then this node must be unreachable */
|
// than this node, then this node must be unreachable.
|
||||||
exists(ControlFlowNode p, int i, int j |
|
exists(ControlFlowNode p, int i, int j |
|
||||||
p.(RaisingNode).unlikelySuccessor(_) and
|
p.(RaisingNode).unlikelySuccessor(_) and
|
||||||
p = b.getNode(i) and
|
p = b.getNode(i) and
|
||||||
@@ -531,7 +531,7 @@ class AttrNode extends ControlFlowNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the flow node corresponding to the object of the attribute expression corresponding to this flow node,
|
/** Gets the flow node corresponding to the object of the attribute expression corresponding to this flow node,
|
||||||
with the matching name */
|
* with the matching name */
|
||||||
ControlFlowNode getObject(string name) {
|
ControlFlowNode getObject(string name) {
|
||||||
exists(Attribute a |
|
exists(Attribute a |
|
||||||
this.getNode() = a and a.getObject() = result.getNode() and
|
this.getNode() = a and a.getObject() = result.getNode() and
|
||||||
@@ -555,7 +555,7 @@ class ImportMemberNode extends ControlFlowNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the flow node corresponding to the module in the import-member expression corresponding to this flow node,
|
/** Gets the flow node corresponding to the module in the import-member expression corresponding to this flow node,
|
||||||
with the matching name*/
|
* with the matching name */
|
||||||
ControlFlowNode getModule(string name) {
|
ControlFlowNode getModule(string name) {
|
||||||
exists(ImportMember i |
|
exists(ImportMember i |
|
||||||
this.getNode() = i and i.getModule() = result.getNode() |
|
this.getNode() = i and i.getModule() = result.getNode() |
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import python
|
import python
|
||||||
|
|
||||||
/** A function, independent of defaults and binding.
|
/**
|
||||||
It is the syntactic entity that is compiled to a code object. */
|
* A function, independent of defaults and binding.
|
||||||
|
* It is the syntactic entity that is compiled to a code object.
|
||||||
|
*/
|
||||||
class Function extends Function_, Scope, AstNode {
|
class Function extends Function_, Scope, AstNode {
|
||||||
|
|
||||||
/** The expression defining this function */
|
/** The expression defining this function */
|
||||||
@@ -10,7 +12,7 @@ class Function extends Function_, Scope, AstNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** The scope in which this function occurs, will be a class for a method,
|
/** The scope in which this function occurs, will be a class for a method,
|
||||||
* another function for nested functions, generator expressions or comprehensions,
|
* another function for nested functions, generator expressions or comprehensions,
|
||||||
* or a module for a plain function. */
|
* or a module for a plain function. */
|
||||||
override Scope getEnclosingScope() {
|
override Scope getEnclosingScope() {
|
||||||
result = this.getParent().(Expr).getScope()
|
result = this.getParent().(Expr).getScope()
|
||||||
@@ -33,8 +35,10 @@ class Function extends Function_, Scope, AstNode {
|
|||||||
name != "__init__")
|
name != "__init__")
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Whether this function is a generator function,
|
/**
|
||||||
that is whether it contains a yield or yield-from expression */
|
* Whether this function is a generator function,
|
||||||
|
* that is whether it contains a yield or yield-from expression
|
||||||
|
*/
|
||||||
predicate isGenerator() {
|
predicate isGenerator() {
|
||||||
exists(Yield y | y.getScope() = this)
|
exists(Yield y | y.getScope() = this)
|
||||||
or
|
or
|
||||||
@@ -323,7 +327,7 @@ class Parameter extends Parameter_ {
|
|||||||
abstract class CallableExpr extends Expr {
|
abstract class CallableExpr extends Expr {
|
||||||
|
|
||||||
/** Gets the parameters of this callable.
|
/** Gets the parameters of this callable.
|
||||||
* This predicate is called getArgs(), rather than getParameters() for compatibility with Python's AST module. */
|
* This predicate is called getArgs(), rather than getParameters() for compatibility with Python's AST module. */
|
||||||
abstract Arguments getArgs();
|
abstract Arguments getArgs();
|
||||||
|
|
||||||
/** Gets the function scope of this code expression. */
|
/** Gets the function scope of this code expression. */
|
||||||
|
|||||||
@@ -9,38 +9,39 @@ class ConditionBlock extends BasicBlock {
|
|||||||
|
|
||||||
/** Basic blocks controlled by this condition, i.e. those BBs for which the condition is testIsTrue */
|
/** Basic blocks controlled by this condition, i.e. those BBs for which the condition is testIsTrue */
|
||||||
predicate controls(BasicBlock controlled, boolean testIsTrue) {
|
predicate controls(BasicBlock controlled, boolean testIsTrue) {
|
||||||
/* For this block to control the block 'controlled' with 'testIsTrue' the following must be true:
|
/*
|
||||||
Execution must have passed through the test i.e. 'this' must strictly dominate 'controlled'.
|
* For this block to control the block 'controlled' with 'testIsTrue' the following must be true:
|
||||||
Execution must have passed through the 'testIsTrue' edge leaving 'this'.
|
* Execution must have passed through the test i.e. 'this' must strictly dominate 'controlled'.
|
||||||
|
* Execution must have passed through the 'testIsTrue' edge leaving 'this'.
|
||||||
Although "passed through the true edge" implies that this.getATrueSuccessor() dominates 'controlled',
|
*
|
||||||
the reverse is not true, as flow may have passed through another edge to get to this.getATrueSuccessor()
|
* Although "passed through the true edge" implies that this.getATrueSuccessor() dominates 'controlled',
|
||||||
so we need to assert that this.getATrueSuccessor() dominates 'controlled' *and* that
|
* the reverse is not true, as flow may have passed through another edge to get to this.getATrueSuccessor()
|
||||||
all predecessors of this.getATrueSuccessor() are either this or dominated by this.getATrueSuccessor().
|
* so we need to assert that this.getATrueSuccessor() dominates 'controlled' *and* that
|
||||||
|
* all predecessors of this.getATrueSuccessor() are either this or dominated by this.getATrueSuccessor().
|
||||||
For example, in the following python snippet:
|
*
|
||||||
<code>
|
* For example, in the following python snippet:
|
||||||
if x:
|
* <code>
|
||||||
controlled
|
* if x:
|
||||||
false_successor
|
* controlled
|
||||||
uncontrolled
|
* false_successor
|
||||||
</code>
|
* uncontrolled
|
||||||
false_successor dominates uncontrolled, but not all of its predecessors are this (if x)
|
* </code>
|
||||||
or dominated by itself. Whereas in the following code:
|
* false_successor dominates uncontrolled, but not all of its predecessors are this (if x)
|
||||||
<code>
|
* or dominated by itself. Whereas in the following code:
|
||||||
if x:
|
* <code>
|
||||||
while controlled:
|
* if x:
|
||||||
also_controlled
|
* while controlled:
|
||||||
false_successor
|
* also_controlled
|
||||||
uncontrolled
|
* false_successor
|
||||||
</code>
|
* uncontrolled
|
||||||
the block 'while controlled' is controlled because all of its predecessors are this (if x)
|
* </code>
|
||||||
or (in the case of 'also_controlled') dominated by itself.
|
* the block 'while controlled' is controlled because all of its predecessors are this (if x)
|
||||||
|
* or (in the case of 'also_controlled') dominated by itself.
|
||||||
The additional constraint on the predecessors of the test successor implies
|
*
|
||||||
that `this` strictly dominates `controlled` so that isn't necessary to check
|
* The additional constraint on the predecessors of the test successor implies
|
||||||
directly.
|
* that `this` strictly dominates `controlled` so that isn't necessary to check
|
||||||
*/
|
* directly.
|
||||||
|
*/
|
||||||
exists(BasicBlock succ |
|
exists(BasicBlock succ |
|
||||||
testIsTrue = true and succ = this.getATrueSuccessor()
|
testIsTrue = true and succ = this.getATrueSuccessor()
|
||||||
or
|
or
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import python
|
|||||||
private import semmle.python.types.Builtins
|
private import semmle.python.types.Builtins
|
||||||
|
|
||||||
/** An alias in an import statement, the `mod as name` part of `import mod as name`. May be artificial;
|
/** An alias in an import statement, the `mod as name` part of `import mod as name`. May be artificial;
|
||||||
`import x` is transformed into `import x as x` */
|
* `import x` is transformed into `import x as x` */
|
||||||
class Alias extends Alias_ {
|
class Alias extends Alias_ {
|
||||||
|
|
||||||
Location getLocation() {
|
Location getLocation() {
|
||||||
@@ -38,7 +38,7 @@ class ImportExpr extends ImportExpr_ {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** The language specifies level as -1 if relative imports are to be tried first, 0 for absolute imports,
|
/** The language specifies level as -1 if relative imports are to be tried first, 0 for absolute imports,
|
||||||
and level > 0 for explicit relative imports. */
|
* and level > 0 for explicit relative imports. */
|
||||||
override int getLevel() {
|
override int getLevel() {
|
||||||
exists(int l | l = super.getLevel() |
|
exists(int l | l = super.getLevel() |
|
||||||
l > 0 and result = l
|
l > 0 and result = l
|
||||||
@@ -73,8 +73,8 @@ class ImportExpr extends ImportExpr_ {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the name by which the lowest level module or package is imported.
|
/** Gets the name by which the lowest level module or package is imported.
|
||||||
* NOTE: This is the name that used to import the module,
|
* NOTE: This is the name that used to import the module,
|
||||||
* which may not be the name of the module. */
|
* which may not be the name of the module. */
|
||||||
string bottomModuleName() {
|
string bottomModuleName() {
|
||||||
result = relativeTopName() + this.remainderOfName()
|
result = relativeTopName() + this.remainderOfName()
|
||||||
or
|
or
|
||||||
@@ -95,8 +95,8 @@ class ImportExpr extends ImportExpr_ {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the full name of the module resulting from evaluating this import.
|
/** Gets the full name of the module resulting from evaluating this import.
|
||||||
* NOTE: This is the name that used to import the module,
|
* NOTE: This is the name that used to import the module,
|
||||||
* which may not be the name of the module. */
|
* which may not be the name of the module. */
|
||||||
string getImportedModuleName() {
|
string getImportedModuleName() {
|
||||||
exists(string bottomName | bottomName = this.bottomModuleName() |
|
exists(string bottomName | bottomName = this.bottomModuleName() |
|
||||||
if this.isTop() then
|
if this.isTop() then
|
||||||
@@ -158,8 +158,8 @@ class ImportMember extends ImportMember_ {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the full name of the module resulting from evaluating this import.
|
/** Gets the full name of the module resulting from evaluating this import.
|
||||||
* NOTE: This is the name that used to import the module,
|
* NOTE: This is the name that used to import the module,
|
||||||
* which may not be the name of the module. */
|
* which may not be the name of the module. */
|
||||||
string getImportedModuleName() {
|
string getImportedModuleName() {
|
||||||
result = this.getModule().(ImportExpr).getImportedModuleName() + "." + this.getName()
|
result = this.getModule().(ImportExpr).getImportedModuleName() + "." + this.getName()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import python
|
|||||||
class FunctionMetrics extends Function {
|
class FunctionMetrics extends Function {
|
||||||
|
|
||||||
/** Gets the total number of lines (including blank lines)
|
/** Gets the total number of lines (including blank lines)
|
||||||
from the definition to the end of the function */
|
* from the definition to the end of the function */
|
||||||
int getNumberOfLines() {
|
int getNumberOfLines() {
|
||||||
py_alllines(this, result)
|
py_alllines(this, result)
|
||||||
}
|
}
|
||||||
@@ -53,8 +53,8 @@ class FunctionMetrics extends Function {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Dependency of Callables
|
/** Dependency of Callables
|
||||||
One callable "this" depends on another callable "result"
|
* One callable "this" depends on another callable "result"
|
||||||
if "this" makes some call to a method that may end up being "result".
|
* if "this" makes some call to a method that may end up being "result".
|
||||||
*/
|
*/
|
||||||
FunctionMetrics getADependency() {
|
FunctionMetrics getADependency() {
|
||||||
result != this and
|
result != this and
|
||||||
@@ -78,17 +78,17 @@ class FunctionMetrics extends Function {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Afferent Coupling
|
/** Afferent Coupling
|
||||||
the number of callables that depend on this method.
|
* the number of callables that depend on this method.
|
||||||
This is sometimes called the "fan-in" of a method.
|
* This is sometimes called the "fan-in" of a method.
|
||||||
*/
|
*/
|
||||||
int getAfferentCoupling() {
|
int getAfferentCoupling() {
|
||||||
result = count(FunctionMetrics m | m.getADependency() = this )
|
result = count(FunctionMetrics m | m.getADependency() = this )
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Efferent Coupling
|
/** Efferent Coupling
|
||||||
the number of methods that this method depends on
|
* the number of methods that this method depends on
|
||||||
This is sometimes called the "fan-out" of a method.
|
* This is sometimes called the "fan-out" of a method.
|
||||||
*/
|
*/
|
||||||
int getEfferentCoupling() {
|
int getEfferentCoupling() {
|
||||||
result = count(FunctionMetrics m | this.getADependency() = m)
|
result = count(FunctionMetrics m | this.getADependency() = m)
|
||||||
}
|
}
|
||||||
@@ -112,7 +112,7 @@ class FunctionMetrics extends Function {
|
|||||||
class ClassMetrics extends Class {
|
class ClassMetrics extends Class {
|
||||||
|
|
||||||
/** Gets the total number of lines (including blank lines)
|
/** Gets the total number of lines (including blank lines)
|
||||||
from the definition to the end of the class */
|
* from the definition to the end of the class */
|
||||||
int getNumberOfLines() {
|
int getNumberOfLines() {
|
||||||
py_alllines(this, result)
|
py_alllines(this, result)
|
||||||
}
|
}
|
||||||
@@ -149,14 +149,14 @@ class ClassMetrics extends Class {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** The afferent coupling of a class is the number of classes that
|
/** The afferent coupling of a class is the number of classes that
|
||||||
* directly depend on it.
|
* directly depend on it.
|
||||||
*/
|
*/
|
||||||
int getAfferentCoupling() {
|
int getAfferentCoupling() {
|
||||||
result = count(ClassMetrics t | t.dependsOn(this))
|
result = count(ClassMetrics t | t.dependsOn(this))
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The efferent coupling of a class is the number of classes that
|
/** The efferent coupling of a class is the number of classes that
|
||||||
* it directly depends on.
|
* it directly depends on.
|
||||||
*/
|
*/
|
||||||
int getEfferentCoupling() {
|
int getEfferentCoupling() {
|
||||||
result = count(ClassMetrics t | this.dependsOn(t))
|
result = count(ClassMetrics t | this.dependsOn(t))
|
||||||
@@ -172,20 +172,19 @@ class ClassMetrics extends Class {
|
|||||||
/* -------- CHIDAMBER AND KEMERER LACK OF COHESION IN METHODS ------------ */
|
/* -------- CHIDAMBER AND KEMERER LACK OF COHESION IN METHODS ------------ */
|
||||||
|
|
||||||
/* The aim of this metric is to try and determine whether a class
|
/* The aim of this metric is to try and determine whether a class
|
||||||
represents one abstraction (good) or multiple abstractions (bad).
|
* represents one abstraction (good) or multiple abstractions (bad).
|
||||||
If a class represents multiple abstractions, it should be split
|
* If a class represents multiple abstractions, it should be split
|
||||||
up into multiple classes.
|
* up into multiple classes.
|
||||||
|
*
|
||||||
In the Chidamber and Kemerer method, this is measured as follows:
|
* In the Chidamber and Kemerer method, this is measured as follows:
|
||||||
n1 = number of pairs of distinct methods in a class that do *not*
|
* n1 = number of pairs of distinct methods in a class that do *not*
|
||||||
have at least one commonly accessed field
|
* have at least one commonly accessed field
|
||||||
n2 = number of pairs of distinct methods in a class that do
|
* n2 = number of pairs of distinct methods in a class that do
|
||||||
have at least one commonly accessed field
|
* have at least one commonly accessed field
|
||||||
lcom = ((n1 - n2)/2 max 0)
|
* lcom = ((n1 - n2)/2 max 0)
|
||||||
|
*
|
||||||
We divide by 2 because each pair (m1,m2) is counted twice in n1 and n2.
|
* We divide by 2 because each pair (m1,m2) is counted twice in n1 and n2.
|
||||||
|
*/
|
||||||
*/
|
|
||||||
|
|
||||||
/** should function f be excluded from the cohesion computation? */
|
/** should function f be excluded from the cohesion computation? */
|
||||||
predicate ignoreLackOfCohesion(Function f) {
|
predicate ignoreLackOfCohesion(Function f) {
|
||||||
|
|||||||
@@ -170,7 +170,7 @@ class Compare extends Compare_ {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Whether as part of this comparison 'left' is compared with 'right' using the operator 'op'.
|
/** Whether as part of this comparison 'left' is compared with 'right' using the operator 'op'.
|
||||||
* For example, the comparison `a<b<c` compares(`a`, `b`, `<`) and compares(`b`, `c`, `<`). */
|
* For example, the comparison `a<b<c` compares(`a`, `b`, `<`) and compares(`b`, `c`, `<`). */
|
||||||
predicate compares(Expr left, Cmpop op, Expr right)
|
predicate compares(Expr left, Cmpop op, Expr right)
|
||||||
{
|
{
|
||||||
this.getLeft() = left and this.getComparator(0) = right and op = this.getOp(0)
|
this.getLeft() = left and this.getComparator(0) = right and op = this.getOp(0)
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import python
|
import python
|
||||||
|
|
||||||
/** A Scope. A scope is the lexical extent over which all identifiers with the same name refer to the same variable.
|
/** A Scope. A scope is the lexical extent over which all identifiers with the same name refer to the same variable.
|
||||||
* Modules, Classes and Functions are all Scopes. There are no other scopes.
|
* Modules, Classes and Functions are all Scopes. There are no other scopes.
|
||||||
* The scopes for expressions that create new scopes, lambdas and comprehensions, are handled by creating an anonymous Function. */
|
* The scopes for expressions that create new scopes, lambdas and comprehensions, are handled by creating an anonymous Function. */
|
||||||
class Scope extends Scope_ {
|
class Scope extends Scope_ {
|
||||||
|
|
||||||
Module getEnclosingModule() {
|
Module getEnclosingModule() {
|
||||||
@@ -74,7 +74,7 @@ class Scope extends Scope_ {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Gets an exit from this Scope's control flow graph,
|
/** Gets an exit from this Scope's control flow graph,
|
||||||
* that does not result from an exception */
|
* that does not result from an exception */
|
||||||
ControlFlowNode getANormalExit() {
|
ControlFlowNode getANormalExit() {
|
||||||
result = this.getFallthroughNode()
|
result = this.getFallthroughNode()
|
||||||
or
|
or
|
||||||
|
|||||||
@@ -41,10 +41,9 @@ class SelfAttributeRead extends SelfAttribute {
|
|||||||
|
|
||||||
SelfAttributeRead() {
|
SelfAttributeRead() {
|
||||||
this.getCtx() instanceof Load and
|
this.getCtx() instanceof Load and
|
||||||
/* Be stricter for loads.
|
// Be stricter for loads.
|
||||||
* We want to generous as to what is defined (ie stores),
|
// We want to generous as to what is defined (i.e. stores),
|
||||||
* but strict as to what needs to be defined (ie loads).
|
// but strict as to what needs to be defined (i.e. loads).
|
||||||
*/
|
|
||||||
exists(ClassObject cls, FunctionObject func |
|
exists(ClassObject cls, FunctionObject func |
|
||||||
cls.declaredAttribute(_) = func |
|
cls.declaredAttribute(_) = func |
|
||||||
func.getFunction() = this.getScope() and
|
func.getFunction() = this.getScope() and
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ string remove_prefix_before_substring(string str, string sub) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Removes the part of the `resources/lib` Python library path that may vary
|
/** Removes the part of the `resources/lib` Python library path that may vary
|
||||||
* from machine to machine. */
|
* from machine to machine. */
|
||||||
|
|
||||||
string remove_library_prefix(Location loc) {
|
string remove_library_prefix(Location loc) {
|
||||||
result = remove_prefix_before_substring(loc.toString(), "resources/lib")
|
result = remove_prefix_before_substring(loc.toString(), "resources/lib")
|
||||||
|
|||||||
@@ -81,8 +81,8 @@ class PythonUse extends DependencyKind {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Whether there is a more specific dependency source than this one.
|
/** Whether there is a more specific dependency source than this one.
|
||||||
* E.g. if the expression pack.mod.func is a dependency on the function 'func' in 'pack.mod'
|
* E.g. if the expression pack.mod.func is a dependency on the function 'func' in 'pack.mod'
|
||||||
* don't make pack.mod depend on the module 'pack.mod'
|
* don't make pack.mod depend on the module 'pack.mod'
|
||||||
*/
|
*/
|
||||||
private predicate has_more_specific_dependency_source(Expr e) {
|
private predicate has_more_specific_dependency_source(Expr e) {
|
||||||
exists(Attribute member |
|
exists(Attribute member |
|
||||||
|
|||||||
@@ -142,8 +142,8 @@ private cached newtype TEssaDefinition =
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Definition of an extended-SSA (ESSA) variable.
|
/** Definition of an extended-SSA (ESSA) variable.
|
||||||
* There is exactly one definition for each variable,
|
* There is exactly one definition for each variable,
|
||||||
* and exactly one variable for each definition.
|
* and exactly one variable for each definition.
|
||||||
*/
|
*/
|
||||||
abstract class EssaDefinition extends TEssaDefinition {
|
abstract class EssaDefinition extends TEssaDefinition {
|
||||||
|
|
||||||
@@ -471,8 +471,7 @@ class EssaNodeDefinition extends EssaDefinition, TEssaNodeDefinition {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A definition of an ESSA variable that takes another ESSA variable as an input.
|
/** A definition of an ESSA variable that takes another ESSA variable as an input. */
|
||||||
*/
|
|
||||||
class EssaNodeRefinement extends EssaDefinition, TEssaNodeRefinement {
|
class EssaNodeRefinement extends EssaDefinition, TEssaNodeRefinement {
|
||||||
|
|
||||||
override string toString() {
|
override string toString() {
|
||||||
|
|||||||
@@ -232,8 +232,7 @@ class BuiltinFunctionObjectInternal extends CallableObjectInternal, TBuiltinFunc
|
|||||||
Builtin getReturnType() {
|
Builtin getReturnType() {
|
||||||
exists(Builtin func |
|
exists(Builtin func |
|
||||||
func = this.getBuiltin() |
|
func = this.getBuiltin() |
|
||||||
/* Enumerate the types of a few builtin functions, that the CPython analysis misses.
|
/* Enumerate the types of a few builtin functions, that the CPython analysis misses. */
|
||||||
*/
|
|
||||||
func = Builtin::builtin("hex") and result = Builtin::special("str")
|
func = Builtin::builtin("hex") and result = Builtin::special("str")
|
||||||
or
|
or
|
||||||
func = Builtin::builtin("oct") and result = Builtin::special("str")
|
func = Builtin::builtin("oct") and result = Builtin::special("str")
|
||||||
@@ -294,8 +293,7 @@ class BuiltinFunctionObjectInternal extends CallableObjectInternal, TBuiltinFunc
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Class representing methods of built-in classes (otherwise known as method-descriptors) such as `list.append`.
|
/** Class representing methods of built-in classes (otherwise known as method-descriptors) such as `list.append`. */
|
||||||
*/
|
|
||||||
class BuiltinMethodObjectInternal extends CallableObjectInternal, TBuiltinMethodObject {
|
class BuiltinMethodObjectInternal extends CallableObjectInternal, TBuiltinMethodObject {
|
||||||
|
|
||||||
override Builtin getBuiltin() {
|
override Builtin getBuiltin() {
|
||||||
|
|||||||
@@ -113,8 +113,8 @@ class Value extends TObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Whether this overrides v. In this context, "overrides" means that this object
|
/** Whether this overrides v. In this context, "overrides" means that this object
|
||||||
* is a named attribute of a some class C and `v` is a named attribute of another
|
* is a named attribute of a some class C and `v` is a named attribute of another
|
||||||
* class S, both attributes having the same name, and S is a super class of C.
|
* class S, both attributes having the same name, and S is a super class of C.
|
||||||
*/
|
*/
|
||||||
predicate overrides(Value v) {
|
predicate overrides(Value v) {
|
||||||
exists(ClassValue my_class, ClassValue other_class, string name |
|
exists(ClassValue my_class, ClassValue other_class, string name |
|
||||||
@@ -542,13 +542,13 @@ class ClassValue extends Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if this class is a new style class.
|
/** Holds if this class is a new style class.
|
||||||
A new style class is one that implicitly or explicitly inherits from `object`. */
|
* A new style class is one that implicitly or explicitly inherits from `object`. */
|
||||||
predicate isNewStyle() {
|
predicate isNewStyle() {
|
||||||
Types::isNewStyle(this)
|
Types::isNewStyle(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if this class is an old style class.
|
/** Holds if this class is an old style class.
|
||||||
An old style class is one that does not inherit from `object`. */
|
* An old style class is one that does not inherit from `object`. */
|
||||||
predicate isOldStyle() {
|
predicate isOldStyle() {
|
||||||
Types::isOldStyle(this)
|
Types::isOldStyle(this)
|
||||||
}
|
}
|
||||||
@@ -578,7 +578,7 @@ class ClassValue extends Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Whether this class is a legal exception class.
|
/** Whether this class is a legal exception class.
|
||||||
* What constitutes a legal exception class differs between major versions */
|
* What constitutes a legal exception class differs between major versions */
|
||||||
predicate isLegalExceptionType() {
|
predicate isLegalExceptionType() {
|
||||||
not this.isNewStyle()
|
not this.isNewStyle()
|
||||||
or
|
or
|
||||||
@@ -622,7 +622,7 @@ abstract class FunctionValue extends CallableValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Whether this is a "normal" method, that is, it is exists as a class attribute
|
/** Whether this is a "normal" method, that is, it is exists as a class attribute
|
||||||
* which is not a lambda and not the __new__ method. */
|
* which is not a lambda and not the __new__ method. */
|
||||||
predicate isNormalMethod() {
|
predicate isNormalMethod() {
|
||||||
exists(ClassValue cls, string name |
|
exists(ClassValue cls, string name |
|
||||||
cls.declaredAttribute(name) = this and
|
cls.declaredAttribute(name) = this and
|
||||||
@@ -742,7 +742,7 @@ class TupleValue extends SequenceValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** A class representing strings, either present in the source as a literal, or
|
/** A class representing strings, either present in the source as a literal, or
|
||||||
in a builtin as a value. */
|
* in a builtin as a value. */
|
||||||
|
|
||||||
class StringValue extends Value {
|
class StringValue extends Value {
|
||||||
StringValue() {
|
StringValue() {
|
||||||
@@ -758,7 +758,7 @@ class StringValue extends Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** A class representing numbers (ints and floats), either present in the source as a literal,
|
/** A class representing numbers (ints and floats), either present in the source as a literal,
|
||||||
* or in a builtin as a value.
|
* or in a builtin as a value.
|
||||||
*/
|
*/
|
||||||
class NumericValue extends Value {
|
class NumericValue extends Value {
|
||||||
NumericValue() {
|
NumericValue() {
|
||||||
@@ -918,7 +918,7 @@ module ClassValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Get the `ClassValue` for the `str` class. This is `bytes` in Python 2,
|
/** Get the `ClassValue` for the `str` class. This is `bytes` in Python 2,
|
||||||
and `str` in Python 3. */
|
* and `str` in Python 3. */
|
||||||
ClassValue str() {
|
ClassValue str() {
|
||||||
if major_version() = 2 then
|
if major_version() = 2 then
|
||||||
result = bytes()
|
result = bytes()
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/**
|
/*
|
||||||
*
|
*
|
||||||
* ## Points-to analysis for Python
|
* ## Points-to analysis for Python
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1176,7 +1176,7 @@ module InterProceduralPointsTo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** INTERNAL -- Use `FunctionObject.neverReturns()` instead.
|
/** INTERNAL -- Use `FunctionObject.neverReturns()` instead.
|
||||||
* Whether function `func` never returns. Slightly conservative approximation, this predicate may be false
|
* Whether function `func` never returns. Slightly conservative approximation, this predicate may be false
|
||||||
* for a function that can never return. */
|
* for a function that can never return. */
|
||||||
cached predicate neverReturns(Function f) {
|
cached predicate neverReturns(Function f) {
|
||||||
/* A Python function never returns if it has no normal exits that are not dominated by a
|
/* A Python function never returns if it has no normal exits that are not dominated by a
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ private int syntactic_call_count(Scope s) {
|
|||||||
|
|
||||||
private int incoming_call_cost(Scope s) {
|
private int incoming_call_cost(Scope s) {
|
||||||
/* Syntactic call count will often be a considerable overestimate
|
/* Syntactic call count will often be a considerable overestimate
|
||||||
* of the actual number of calls, so we use the square root.
|
* of the actual number of calls, so we use the square root.
|
||||||
* Cost = log(sqrt(call-count))
|
* Cost = log(sqrt(call-count))
|
||||||
*/
|
*/
|
||||||
result = ((syntactic_call_count(s)+1).log(2)*0.5).floor()
|
result = ((syntactic_call_count(s)+1).log(2)*0.5).floor()
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ class FirstElementFlow extends DataFlowExtension::DataFlowNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** A taint sink that is potentially vulnerable to malicious shell commands.
|
/** A taint sink that is potentially vulnerable to malicious shell commands.
|
||||||
* The `vuln` in `subprocess.call(shell=vuln)` and similar calls.
|
* The `vuln` in `subprocess.call(shell=vuln)` and similar calls.
|
||||||
*/
|
*/
|
||||||
class ShellCommand extends TaintSink {
|
class ShellCommand extends TaintSink {
|
||||||
|
|
||||||
@@ -98,7 +98,7 @@ class ShellCommand extends TaintSink {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** A taint sink that is potentially vulnerable to malicious shell commands.
|
/** A taint sink that is potentially vulnerable to malicious shell commands.
|
||||||
* The `vuln` in `subprocess.call(vuln, ...)` and similar calls.
|
* The `vuln` in `subprocess.call(vuln, ...)` and similar calls.
|
||||||
*/
|
*/
|
||||||
class OsCommandFirstArgument extends TaintSink {
|
class OsCommandFirstArgument extends TaintSink {
|
||||||
|
|
||||||
|
|||||||
@@ -3,8 +3,7 @@ private import Common
|
|||||||
|
|
||||||
import semmle.python.security.TaintTracking
|
import semmle.python.security.TaintTracking
|
||||||
|
|
||||||
/** An extensible kind of taint representing any kind of string.
|
/** An extensible kind of taint representing any kind of string. */
|
||||||
*/
|
|
||||||
abstract class StringKind extends TaintKind {
|
abstract class StringKind extends TaintKind {
|
||||||
|
|
||||||
bindingset[this]
|
bindingset[this]
|
||||||
|
|||||||
@@ -73,13 +73,13 @@ class ClassObject extends Object {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Whether this class is a new style class.
|
/** Whether this class is a new style class.
|
||||||
A new style class is one that implicitly or explicitly inherits from `object`. */
|
* A new style class is one that implicitly or explicitly inherits from `object`. */
|
||||||
predicate isNewStyle() {
|
predicate isNewStyle() {
|
||||||
Types::isNewStyle(theClass())
|
Types::isNewStyle(theClass())
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Whether this class is an old style class.
|
/** Whether this class is an old style class.
|
||||||
An old style class is one that does not inherit from `object`. */
|
* An old style class is one that does not inherit from `object`. */
|
||||||
predicate isOldStyle() {
|
predicate isOldStyle() {
|
||||||
Types::isOldStyle(theClass())
|
Types::isOldStyle(theClass())
|
||||||
}
|
}
|
||||||
@@ -112,7 +112,7 @@ class ClassObject extends Object {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Returns an attribute as it would be when looked up at runtime on this class.
|
/** Returns an attribute as it would be when looked up at runtime on this class.
|
||||||
Will include attributes of super-classes */
|
* Will include attributes of super-classes */
|
||||||
Object lookupAttribute(string name) {
|
Object lookupAttribute(string name) {
|
||||||
exists(ObjectInternal val |
|
exists(ObjectInternal val |
|
||||||
theClass().lookup(name, val, _) and
|
theClass().lookup(name, val, _) and
|
||||||
@@ -155,7 +155,7 @@ class ClassObject extends Object {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Whether it is impossible to know all the attributes of this class. Usually because it is
|
/** Whether it is impossible to know all the attributes of this class. Usually because it is
|
||||||
impossible to calculate the full class hierarchy or because some attribute is too dynamic. */
|
* impossible to calculate the full class hierarchy or because some attribute is too dynamic. */
|
||||||
predicate unknowableAttributes() {
|
predicate unknowableAttributes() {
|
||||||
/* True for a class with undeterminable superclasses, unanalysable metaclasses, or other confusions */
|
/* True for a class with undeterminable superclasses, unanalysable metaclasses, or other confusions */
|
||||||
this.failedInference()
|
this.failedInference()
|
||||||
@@ -204,8 +204,8 @@ class ClassObject extends Object {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Gets an object which is the sole instance of this class, if this class is probably a singleton.
|
/** Gets an object which is the sole instance of this class, if this class is probably a singleton.
|
||||||
* Note the 'probable' in the name; there is no guarantee that this class is in fact a singleton.
|
* Note the 'probable' in the name; there is no guarantee that this class is in fact a singleton.
|
||||||
* It is guaranteed that getProbableSingletonInstance() returns at most one Object for each ClassObject. */
|
* It is guaranteed that getProbableSingletonInstance() returns at most one Object for each ClassObject. */
|
||||||
Object getProbableSingletonInstance() {
|
Object getProbableSingletonInstance() {
|
||||||
exists(ControlFlowNode use, Expr origin |
|
exists(ControlFlowNode use, Expr origin |
|
||||||
use.refersTo(result, this, origin.getAFlowNode())
|
use.refersTo(result, this, origin.getAFlowNode())
|
||||||
@@ -284,9 +284,9 @@ class ClassObject extends Object {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if this class is an improper subclass of the other class.
|
/** Holds if this class is an improper subclass of the other class.
|
||||||
* True if this is a sub-class of other or this is the same class as other.
|
* True if this is a sub-class of other or this is the same class as other.
|
||||||
*
|
*
|
||||||
* Equivalent to the Python builtin function issubclass().
|
* Equivalent to the Python builtin function issubclass().
|
||||||
*/
|
*/
|
||||||
predicate isSubclassOf(ClassObject other) {
|
predicate isSubclassOf(ClassObject other) {
|
||||||
this = other or this.getASuperType() = other
|
this = other or this.getASuperType() = other
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ class RaisingNode extends ControlFlowNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the type of an exception that may be raised
|
/** Gets the type of an exception that may be raised
|
||||||
at this control flow node */
|
* at this control flow node */
|
||||||
ClassObject getARaisedType() {
|
ClassObject getARaisedType() {
|
||||||
result = this.localRaisedType()
|
result = this.localRaisedType()
|
||||||
or
|
or
|
||||||
@@ -118,8 +118,7 @@ class RaisingNode extends ControlFlowNode {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Whether (as inferred by type inference) it is highly unlikely (or impossible) for control to flow from this to succ.
|
/** Whether (as inferred by type inference) it is highly unlikely (or impossible) for control to flow from this to succ. */
|
||||||
*/
|
|
||||||
predicate unlikelySuccessor(ControlFlowNode succ) {
|
predicate unlikelySuccessor(ControlFlowNode succ) {
|
||||||
succ = this.getAnExceptionalSuccessor() and
|
succ = this.getAnExceptionalSuccessor() and
|
||||||
not this.viableExceptionEdge(succ, _) and
|
not this.viableExceptionEdge(succ, _) and
|
||||||
|
|||||||
@@ -70,27 +70,26 @@ abstract class FunctionObject extends Object {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the `ControlFlowNode` that will be passed as the nth argument to `this` when called at `call`.
|
/** Gets the `ControlFlowNode` that will be passed as the nth argument to `this` when called at `call`.
|
||||||
This predicate will correctly handle `x.y()`, treating `x` as the zeroth argument.
|
* This predicate will correctly handle `x.y()`, treating `x` as the zeroth argument.
|
||||||
*/
|
*/
|
||||||
ControlFlowNode getArgumentForCall(CallNode call, int n) {
|
ControlFlowNode getArgumentForCall(CallNode call, int n) {
|
||||||
result = theCallable().getArgumentForCall(call, n)
|
result = theCallable().getArgumentForCall(call, n)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the `ControlFlowNode` that will be passed as the named argument to `this` when called at `call`.
|
/** Gets the `ControlFlowNode` that will be passed as the named argument to `this` when called at `call`.
|
||||||
This predicate will correctly handle `x.y()`, treating `x` as the self argument.
|
* This predicate will correctly handle `x.y()`, treating `x` as the self argument.
|
||||||
*/
|
*/
|
||||||
ControlFlowNode getNamedArgumentForCall(CallNode call, string name) {
|
ControlFlowNode getNamedArgumentForCall(CallNode call, string name) {
|
||||||
result = theCallable().getNamedArgumentForCall(call, name)
|
result = theCallable().getNamedArgumentForCall(call, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Whether this function never returns. This is an approximation.
|
/** Whether this function never returns. This is an approximation. */
|
||||||
*/
|
|
||||||
predicate neverReturns() {
|
predicate neverReturns() {
|
||||||
theCallable().neverReturns()
|
theCallable().neverReturns()
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Whether this is a "normal" method, that is, it is exists as a class attribute
|
/** Whether this is a "normal" method, that is, it is exists as a class attribute
|
||||||
* which is not wrapped and not the __new__ method. */
|
* which is not wrapped and not the __new__ method. */
|
||||||
predicate isNormalMethod() {
|
predicate isNormalMethod() {
|
||||||
exists(ClassObject cls, string name |
|
exists(ClassObject cls, string name |
|
||||||
cls.declaredAttribute(name) = this and
|
cls.declaredAttribute(name) = this and
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ abstract class ModuleObject extends Object {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Whether this module "exports" `name`. That is, whether using `import *` on this module
|
/** Whether this module "exports" `name`. That is, whether using `import *` on this module
|
||||||
will result in `name` being added to the namespace. */
|
* will result in `name` being added to the namespace. */
|
||||||
predicate exports(string name) {
|
predicate exports(string name) {
|
||||||
theModule().exports(name)
|
theModule().exports(name)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,8 +44,8 @@ class Object extends @py_object {
|
|||||||
this = unknownValue() and result = theUnknownType()
|
this = unknownValue() and result = theUnknownType()
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Whether this a builtin object. A builtin object is one defined by the implementation,
|
/** Whether this is a builtin object. A builtin object is one defined by the implementation,
|
||||||
such as the integer 4 or by a native extension, such as a NumPy array class. */
|
* such as the integer 4 or by a native extension, such as a NumPy array class. */
|
||||||
predicate isBuiltin() {
|
predicate isBuiltin() {
|
||||||
exists(this.asBuiltin())
|
exists(this.asBuiltin())
|
||||||
}
|
}
|
||||||
@@ -57,7 +57,7 @@ class Object extends @py_object {
|
|||||||
|
|
||||||
/** Gets the point in the source code from which this object "originates".
|
/** Gets the point in the source code from which this object "originates".
|
||||||
*
|
*
|
||||||
* WARNING: The lack of context makes this less accurate than f.refersTo(this, _, result)
|
* WARNING: The lack of context makes this less accurate than f.refersTo(this, _, result)
|
||||||
* for a control flow node 'f'.
|
* for a control flow node 'f'.
|
||||||
*/
|
*/
|
||||||
AstNode getOrigin() {
|
AstNode getOrigin() {
|
||||||
@@ -114,8 +114,8 @@ class Object extends @py_object {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Whether this overrides o. In this context, "overrides" means that this object
|
/** Whether this overrides o. In this context, "overrides" means that this object
|
||||||
* is a named attribute of a some class C and `o` is a named attribute of another
|
* is a named attribute of a some class C and `o` is a named attribute of another
|
||||||
* class S, both attributes having the same name, and S is a super class of C.
|
* class S, both attributes having the same name, and S is a super class of C.
|
||||||
*/
|
*/
|
||||||
predicate overrides(Object o) {
|
predicate overrides(Object o) {
|
||||||
exists(string name |
|
exists(string name |
|
||||||
@@ -216,8 +216,8 @@ private Object findByName3(string longName) {
|
|||||||
|
|
||||||
|
|
||||||
/** Numeric objects (ints and floats).
|
/** Numeric objects (ints and floats).
|
||||||
* Includes those occurring in the source as a literal
|
* Includes those occurring in the source as a literal
|
||||||
* or in a builtin module as a value.
|
* or in a builtin module as a value.
|
||||||
*/
|
*/
|
||||||
class NumericObject extends Object {
|
class NumericObject extends Object {
|
||||||
|
|
||||||
@@ -228,7 +228,7 @@ class NumericObject extends Object {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the Boolean value that this object
|
/** Gets the Boolean value that this object
|
||||||
* would evaluate to in a Boolean context,
|
* would evaluate to in a Boolean context,
|
||||||
* such as `bool(x)` or `if x: ...`
|
* such as `bool(x)` or `if x: ...`
|
||||||
*/
|
*/
|
||||||
override boolean booleanValue() {
|
override boolean booleanValue() {
|
||||||
@@ -272,8 +272,8 @@ class NumericObject extends Object {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** String objects (unicode or bytes).
|
/** String objects (unicode or bytes).
|
||||||
* Includes those occurring in the source as a literal
|
* Includes those occurring in the source as a literal
|
||||||
* or in a builtin module as a value.
|
* or in a builtin module as a value.
|
||||||
*/
|
*/
|
||||||
class StringObject extends Object {
|
class StringObject extends Object {
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user