mirror of
https://github.com/github/codeql.git
synced 2025-12-23 20:26:32 +01:00
Python: Modernise Statements/ queries
Almost. Left out a few things marked with TODO
This commit is contained in:
@@ -27,8 +27,8 @@ predicate needs_docstring(Scope s) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
predicate function_needs_docstring(Function f) {
|
predicate function_needs_docstring(Function f) {
|
||||||
not exists(FunctionObject fo, FunctionObject base | fo.overrides(base) and fo.getFunction() = f |
|
not exists(FunctionValue fo, FunctionValue base | fo.overrides(base) and fo.getScope() = f |
|
||||||
not function_needs_docstring(base.getFunction())
|
not function_needs_docstring(base.getScope())
|
||||||
) and
|
) and
|
||||||
f.getName() != "lambda" and
|
f.getName() != "lambda" and
|
||||||
(f.getMetrics().getNumberOfLinesOfCode() - count(f.getADecorator())) > 2 and
|
(f.getMetrics().getNumberOfLinesOfCode() - count(f.getADecorator())) > 2 and
|
||||||
|
|||||||
@@ -13,21 +13,15 @@
|
|||||||
|
|
||||||
import python
|
import python
|
||||||
|
|
||||||
predicate is_a_string_type(ClassObject seqtype) {
|
|
||||||
seqtype = theBytesType() and major_version() = 2
|
|
||||||
or
|
|
||||||
seqtype = theUnicodeType()
|
|
||||||
}
|
|
||||||
|
|
||||||
from
|
from
|
||||||
For loop, ControlFlowNode iter, Object str, Object seq, ControlFlowNode seq_origin,
|
For loop, ControlFlowNode iter, Value str, Value seq, ControlFlowNode seq_origin, ControlFlowNode str_origin
|
||||||
ClassObject strtype, ClassObject seqtype, ControlFlowNode str_origin
|
|
||||||
where
|
where
|
||||||
loop.getIter().getAFlowNode() = iter and
|
loop.getIter().getAFlowNode() = iter and
|
||||||
iter.refersTo(str, strtype, str_origin) and
|
iter.pointsTo(str, str_origin) and
|
||||||
iter.refersTo(seq, seqtype, seq_origin) and
|
iter.pointsTo(seq, seq_origin) and
|
||||||
is_a_string_type(strtype) and
|
str.getClass() = ClassValue::str() and
|
||||||
seqtype.isIterable() and
|
seq.getClass().isIterable() and
|
||||||
not is_a_string_type(seqtype)
|
not seq.getClass() = ClassValue::str()
|
||||||
select loop, "Iteration over $@, of class " + seqtype.getName() + ", may also iterate over $@.",
|
select loop, "Iteration over $@, of class " + seq.getClass().getName() + ", may also iterate over $@.",
|
||||||
seq_origin, "sequence", str_origin, "string"
|
seq_origin, "sequence", str_origin, "string"
|
||||||
|
|||||||
@@ -36,15 +36,15 @@ predicate mismatched(Assign a, int lcount, int rcount, Location loc, string sequ
|
|||||||
}
|
}
|
||||||
|
|
||||||
predicate mismatched_tuple_rhs(Assign a, int lcount, int rcount, Location loc) {
|
predicate mismatched_tuple_rhs(Assign a, int lcount, int rcount, Location loc) {
|
||||||
exists(ExprList l, TupleObject r, AstNode origin |
|
exists(ExprList l, TupleValue r, AstNode origin |
|
||||||
(
|
(
|
||||||
a.getATarget().(Tuple).getElts() = l or
|
a.getATarget().(Tuple).getElts() = l or
|
||||||
a.getATarget().(List).getElts() = l
|
a.getATarget().(List).getElts() = l
|
||||||
) and
|
) and
|
||||||
a.getValue().refersTo(r, origin) and
|
a.getValue().pointsTo(r, origin) and
|
||||||
loc = origin.getLocation() and
|
loc = origin.getLocation() and
|
||||||
lcount = len(l) and
|
lcount = len(l) and
|
||||||
rcount = r.getLength() and
|
rcount = r.length() and
|
||||||
lcount != rcount and
|
lcount != rcount and
|
||||||
not exists(Starred s | l.getAnItem() = s)
|
not exists(Starred s | l.getAnItem() = s)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -12,23 +12,17 @@
|
|||||||
|
|
||||||
import python
|
import python
|
||||||
|
|
||||||
Object aFunctionLocalsObject() {
|
predicate originIsLocals(ControlFlowNode n) {
|
||||||
exists(Call c, Name n, GlobalVariable v |
|
n.pointsTo(_, _, Value::named("locals").getACall())
|
||||||
c = result.getOrigin() and
|
|
||||||
n = c.getFunc() and
|
|
||||||
n.getVariable() = v and
|
|
||||||
v.getId() = "locals" and
|
|
||||||
c.getScope() instanceof FastLocalsFunction
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate modification_of_locals(ControlFlowNode f) {
|
predicate modification_of_locals(ControlFlowNode f) {
|
||||||
f.(SubscriptNode).getObject().refersTo(aFunctionLocalsObject()) and
|
originIsLocals(f.(SubscriptNode).getObject()) and
|
||||||
(f.isStore() or f.isDelete())
|
(f.isStore() or f.isDelete())
|
||||||
or
|
or
|
||||||
exists(string mname, AttrNode attr |
|
exists(string mname, AttrNode attr |
|
||||||
attr = f.(CallNode).getFunction() and
|
attr = f.(CallNode).getFunction() and
|
||||||
attr.getObject(mname).refersTo(aFunctionLocalsObject(), _)
|
originIsLocals(attr.getObject(mname))
|
||||||
|
|
|
|
||||||
mname = "pop" or
|
mname = "pop" or
|
||||||
mname = "popitem" or
|
mname = "popitem" or
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ for addressing the defect. </p>
|
|||||||
</recommendation>
|
</recommendation>
|
||||||
<example>
|
<example>
|
||||||
<p>
|
<p>
|
||||||
In this example, the loop may attempt to iterate over <code>None</code>, which is not an iterator.
|
In this example, the loop may attempt to iterate over <code>None</code>, which is not an iterable.
|
||||||
It is likely that the programmer forgot to test for <code>None</code> before the loop.
|
It is likely that the programmer forgot to test for <code>None</code> before the loop.
|
||||||
</p>
|
</p>
|
||||||
<sample src="NonIteratorInForLoop.py" />
|
<sample src="NonIteratorInForLoop.py" />
|
||||||
|
|||||||
@@ -22,4 +22,4 @@ where
|
|||||||
not t.failedInference(_) and
|
not t.failedInference(_) and
|
||||||
not v = Value::named("None") and
|
not v = Value::named("None") and
|
||||||
not t.isDescriptorType()
|
not t.isDescriptorType()
|
||||||
select loop, "$@ of class '$@' may be used in for-loop.", origin, "Non-iterator", t, t.getName()
|
select loop, "$@ of class '$@' may be used in for-loop.", origin, "Non-iterable", t, t.getName()
|
||||||
|
|||||||
@@ -37,21 +37,30 @@ predicate maybe_defined_in_outer_scope(Name n) {
|
|||||||
exists(SsaVariable v | v.getAUse().getNode() = n | v.maybeUndefined())
|
exists(SsaVariable v | v.getAUse().getNode() = n | v.maybeUndefined())
|
||||||
}
|
}
|
||||||
|
|
||||||
Variable relevant_var(Name n) {
|
/* Protection against FPs in projects that offer compatibility between Python 2 and 3,
|
||||||
n.getVariable() = result and
|
* since many of them make assignments such as
|
||||||
(corresponding(n, _) or corresponding(_, n))
|
*
|
||||||
|
* if PY2:
|
||||||
|
* bytes = str
|
||||||
|
* else:
|
||||||
|
* bytes = bytes
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
predicate isBuiltin(string name) {
|
||||||
|
exists(Value v | v = Value::named(name) and v.isBuiltin())
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate same_name(Name n1, Name n2) {
|
predicate same_name(Name n1, Name n2) {
|
||||||
corresponding(n1, n2) and
|
corresponding(n1, n2) and
|
||||||
relevant_var(n1) = relevant_var(n2) and
|
n1.getVariable() = n2.getVariable() and
|
||||||
not exists(Object::builtin(n1.getId())) and
|
not isBuiltin(n1.getId()) and
|
||||||
not maybe_defined_in_outer_scope(n2)
|
not maybe_defined_in_outer_scope(n2)
|
||||||
}
|
}
|
||||||
|
|
||||||
ClassObject value_type(Attribute a) { a.getObject().refersTo(_, result, _) }
|
ClassObject value_type(Attribute a) { a.getObject().refersTo(_, result, _) }
|
||||||
|
|
||||||
predicate is_property_access(Attribute a) {
|
predicate is_property_access(Attribute a) {
|
||||||
|
// TODO: We need something to model PropertyObject in the Value API
|
||||||
value_type(a).lookupAttribute(a.getName()) instanceof PropertyObject
|
value_type(a).lookupAttribute(a.getName()) instanceof PropertyObject
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,9 +86,9 @@ predicate pyflakes_commented(AssignStmt assignment) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
predicate side_effecting_lhs(Attribute lhs) {
|
predicate side_effecting_lhs(Attribute lhs) {
|
||||||
exists(ClassObject cls, ClassObject decl |
|
exists(ClassValue cls, ClassValue decl |
|
||||||
lhs.getObject().refersTo(_, cls, _) and
|
lhs.getObject().pointsTo().getClass() = cls and
|
||||||
decl = cls.getAnImproperSuperType() and
|
decl = cls.getASuperType() and
|
||||||
not decl.isBuiltin()
|
not decl.isBuiltin()
|
||||||
|
|
|
|
||||||
decl.declaresAttribute("__setattr__")
|
decl.declaresAttribute("__setattr__")
|
||||||
@@ -90,6 +99,7 @@ from AssignStmt a, Expr left, Expr right
|
|||||||
where
|
where
|
||||||
assignment(a, left, right) and
|
assignment(a, left, right) and
|
||||||
same_value(left, right) and
|
same_value(left, right) and
|
||||||
|
// some people use self-assignment to shut Pyflakes up, such as `ok = ok # Pyflakes`
|
||||||
not pyflakes_commented(a) and
|
not pyflakes_commented(a) and
|
||||||
not side_effecting_lhs(left)
|
not side_effecting_lhs(left)
|
||||||
select a, "This assignment assigns a variable to itself."
|
select a, "This assignment assigns a variable to itself."
|
||||||
|
|||||||
@@ -22,12 +22,12 @@ predicate only_stmt_in_finally(Try t, Call c) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate points_to_context_manager(ControlFlowNode f, ClassObject cls) {
|
predicate points_to_context_manager(ControlFlowNode f, ClassValue cls) {
|
||||||
cls.isContextManager() and
|
forex(Value v | f.pointsTo(v) | v.getClass() = cls) and
|
||||||
forex(Object obj | f.refersTo(obj) | f.refersTo(obj, cls, _))
|
cls.isContextManager()
|
||||||
}
|
}
|
||||||
|
|
||||||
from Call close, Try t, ClassObject cls
|
from Call close, Try t, ClassValue cls
|
||||||
where
|
where
|
||||||
only_stmt_in_finally(t, close) and
|
only_stmt_in_finally(t, close) and
|
||||||
calls_close(close) and
|
calls_close(close) and
|
||||||
|
|||||||
@@ -13,28 +13,28 @@
|
|||||||
|
|
||||||
import python
|
import python
|
||||||
|
|
||||||
predicate understood_attribute(Attribute attr, ClassObject cls, ClassObject attr_cls) {
|
predicate understood_attribute(Attribute attr, ClassValue cls, ClassValue attr_cls) {
|
||||||
exists(string name | attr.getName() = name |
|
exists(string name | attr.getName() = name |
|
||||||
attr.getObject().refersTo(_, cls, _) and
|
attr.getObject().pointsTo().getClass() = cls and
|
||||||
cls.attributeRefersTo(name, _, attr_cls, _)
|
cls.attr(name).getClass() = attr_cls
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Conservative estimate of whether attribute lookup has a side effect */
|
/* Conservative estimate of whether attribute lookup has a side effect */
|
||||||
predicate side_effecting_attribute(Attribute attr) {
|
predicate side_effecting_attribute(Attribute attr) {
|
||||||
exists(ClassObject cls, ClassObject attr_cls |
|
exists(ClassValue cls, ClassValue attr_cls |
|
||||||
understood_attribute(attr, cls, attr_cls) and
|
understood_attribute(attr, cls, attr_cls) and
|
||||||
side_effecting_descriptor_type(attr_cls)
|
side_effecting_descriptor_type(attr_cls)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate maybe_side_effecting_attribute(Attribute attr) {
|
predicate maybe_side_effecting_attribute(Attribute attr) {
|
||||||
not understood_attribute(attr, _, _) and not attr.refersTo(_)
|
not understood_attribute(attr, _, _) and not attr.pointsTo(_)
|
||||||
or
|
or
|
||||||
side_effecting_attribute(attr)
|
side_effecting_attribute(attr)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate side_effecting_descriptor_type(ClassObject descriptor) {
|
predicate side_effecting_descriptor_type(ClassValue descriptor) {
|
||||||
descriptor.isDescriptorType() and
|
descriptor.isDescriptorType() and
|
||||||
/*
|
/*
|
||||||
* Technically all descriptor gets have side effects,
|
* Technically all descriptor gets have side effects,
|
||||||
@@ -42,9 +42,9 @@ predicate side_effecting_descriptor_type(ClassObject descriptor) {
|
|||||||
* we want to treat them as having no effect.
|
* we want to treat them as having no effect.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
not descriptor = thePyFunctionType() and
|
not descriptor = ClassValue::function() and
|
||||||
not descriptor = theStaticMethodType() and
|
not descriptor = ClassValue::staticmethod() and
|
||||||
not descriptor = theClassMethodType()
|
not descriptor = ClassValue::classmethod()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -52,39 +52,39 @@ predicate side_effecting_descriptor_type(ClassObject descriptor) {
|
|||||||
* side-effecting unless we know otherwise.
|
* side-effecting unless we know otherwise.
|
||||||
*/
|
*/
|
||||||
predicate side_effecting_binary(Expr b) {
|
predicate side_effecting_binary(Expr b) {
|
||||||
exists(Expr sub, ClassObject cls, string method_name |
|
exists(Expr sub, ClassValue cls, string method_name |
|
||||||
binary_operator_special_method(b, sub, cls, method_name)
|
binary_operator_special_method(b, sub, cls, method_name)
|
||||||
or
|
or
|
||||||
comparison_special_method(b, sub, cls, method_name)
|
comparison_special_method(b, sub, cls, method_name)
|
||||||
|
|
|
|
||||||
method_name = special_method() and
|
method_name = special_method() and
|
||||||
cls.hasAttribute(method_name) and
|
cls.hasAttribute(method_name) and
|
||||||
not exists(ClassObject declaring |
|
not exists(ClassValue declaring |
|
||||||
declaring.declaresAttribute(method_name) and
|
declaring.declaresAttribute(method_name) and
|
||||||
declaring = cls.getAnImproperSuperType() and
|
declaring = cls.getASuperType() and
|
||||||
declaring.isBuiltin() and
|
declaring.isBuiltin() and
|
||||||
not declaring = theObjectType()
|
not declaring = ClassValue::object()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate binary_operator_special_method(
|
private predicate binary_operator_special_method(
|
||||||
BinaryExpr b, Expr sub, ClassObject cls, string method_name
|
BinaryExpr b, Expr sub, ClassValue cls, string method_name
|
||||||
) {
|
) {
|
||||||
method_name = special_method() and
|
method_name = special_method() and
|
||||||
sub = b.getLeft() and
|
sub = b.getLeft() and
|
||||||
method_name = b.getOp().getSpecialMethodName() and
|
method_name = b.getOp().getSpecialMethodName() and
|
||||||
sub.refersTo(_, cls, _)
|
sub.pointsTo().getClass() = cls
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate comparison_special_method(Compare b, Expr sub, ClassObject cls, string method_name) {
|
private predicate comparison_special_method(Compare b, Expr sub, ClassValue cls, string method_name) {
|
||||||
exists(Cmpop op |
|
exists(Cmpop op |
|
||||||
b.compares(sub, op, _) and
|
b.compares(sub, op, _) and
|
||||||
method_name = op.getSpecialMethodName()
|
method_name = op.getSpecialMethodName()
|
||||||
) and
|
) and
|
||||||
sub.refersTo(_, cls, _)
|
sub.pointsTo().getClass() = cls
|
||||||
}
|
}
|
||||||
|
|
||||||
private string special_method() {
|
private string special_method() {
|
||||||
@@ -102,9 +102,8 @@ predicate is_notebook(File f) {
|
|||||||
/** Expression (statement) in a jupyter/ipython notebook */
|
/** Expression (statement) in a jupyter/ipython notebook */
|
||||||
predicate in_notebook(Expr e) { is_notebook(e.getScope().(Module).getFile()) }
|
predicate in_notebook(Expr e) { is_notebook(e.getScope().(Module).getFile()) }
|
||||||
|
|
||||||
FunctionObject assertRaises() {
|
FunctionValue assertRaises() {
|
||||||
result =
|
result = Value::named("unittest.TestCase").(ClassValue).lookup("assertRaises")
|
||||||
ModuleObject::named("unittest").attr("TestCase").(ClassObject).lookupAttribute("assertRaises")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if expression `e` is in a `with` block that tests for exceptions being raised. */
|
/** Holds if expression `e` is in a `with` block that tests for exceptions being raised. */
|
||||||
@@ -124,6 +123,7 @@ predicate python2_print(Expr e) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
predicate no_effect(Expr e) {
|
predicate no_effect(Expr e) {
|
||||||
|
// strings can be used as comments
|
||||||
not e instanceof StrConst and
|
not e instanceof StrConst and
|
||||||
not e.hasSideEffects() and
|
not e.hasSideEffects() and
|
||||||
forall(Expr sub | sub = e.getASubExpression*() |
|
forall(Expr sub | sub = e.getASubExpression*() |
|
||||||
|
|||||||
@@ -3,13 +3,13 @@
|
|||||||
"qhelp.dtd">
|
"qhelp.dtd">
|
||||||
<qhelp>
|
<qhelp>
|
||||||
<overview>
|
<overview>
|
||||||
<p>If you concatenate strings in a loop then the time taken by the loop is quadratic in the number
|
<p>If you concatenate strings in a loop then the time taken by the loop is quadratic in the number
|
||||||
of iterations.</p>
|
of iterations.</p>
|
||||||
|
|
||||||
</overview>
|
</overview>
|
||||||
<recommendation>
|
<recommendation>
|
||||||
|
|
||||||
<p>Initialize an empty list before the start of the list.
|
<p>Initialize an empty list before the start of the loop.
|
||||||
During the loop append the substrings to the list.
|
During the loop append the substrings to the list.
|
||||||
At the end of the loop, convert the list to a string by using <code>''.join(list)</code>.</p>
|
At the end of the loop, convert the list to a string by using <code>''.join(list)</code>.</p>
|
||||||
|
|
||||||
|
|||||||
@@ -14,13 +14,12 @@ import python
|
|||||||
|
|
||||||
predicate string_concat_in_loop(BinaryExpr b) {
|
predicate string_concat_in_loop(BinaryExpr b) {
|
||||||
b.getOp() instanceof Add and
|
b.getOp() instanceof Add and
|
||||||
exists(SsaVariable d, SsaVariable u, BinaryExprNode add, ClassObject str_type |
|
exists(SsaVariable d, SsaVariable u, BinaryExprNode add |
|
||||||
add.getNode() = b and d = u.getAnUltimateDefinition()
|
add.getNode() = b and d = u.getAnUltimateDefinition()
|
||||||
|
|
|
|
||||||
d.getDefinition().(DefinitionNode).getValue() = add and
|
d.getDefinition().(DefinitionNode).getValue() = add and
|
||||||
u.getAUse() = add.getAnOperand() and
|
u.getAUse() = add.getAnOperand() and
|
||||||
add.getAnOperand().refersTo(_, str_type, _) and
|
add.getAnOperand().pointsTo().getClass() = ClassValue::str()
|
||||||
(str_type = theBytesType() or str_type = theUnicodeType())
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ predicate is_print_stmt(Stmt s) {
|
|||||||
from Stmt p
|
from Stmt p
|
||||||
where
|
where
|
||||||
is_print_stmt(p) and
|
is_print_stmt(p) and
|
||||||
|
// TODO: Need to discuss how we would like to handle ModuleObject.getKind in the glorious future
|
||||||
exists(ModuleObject m | m.getModule() = p.getScope() and m.getKind() = "module") and
|
exists(ModuleObject m | m.getModule() = p.getScope() and m.getKind() = "module") and
|
||||||
not exists(If i | main_eq_name(i) and i.getASubStatement().getASubStatement*() = p)
|
not exists(If i | main_eq_name(i) and i.getASubStatement().getASubStatement*() = p)
|
||||||
select p, "Print statement may execute during import."
|
select p, "Print statement may execute during import."
|
||||||
|
|||||||
@@ -27,8 +27,8 @@ where
|
|||||||
* reference cycle, and an explicit call to `del` helps break this cycle.
|
* reference cycle, and an explicit call to `del` helps break this cycle.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
not exists(FunctionObject ex |
|
not exists(FunctionValue ex |
|
||||||
ex.hasLongName("sys.exc_info") and
|
ex = Value::named("sys.exc_info") and
|
||||||
ex.getACall().getScope() = f
|
ex.getACall().getScope() = f
|
||||||
)
|
)
|
||||||
select del, "Unnecessary deletion of local variable $@ in function $@.", e.getLocation(),
|
select del, "Unnecessary deletion of local variable $@ in function $@.", e.getLocation(),
|
||||||
|
|||||||
@@ -12,9 +12,9 @@
|
|||||||
|
|
||||||
import python
|
import python
|
||||||
|
|
||||||
from Call call, ClassObject ex
|
from Call call, ClassValue ex
|
||||||
where
|
where
|
||||||
call.getFunc().refersTo(ex) and
|
call.getFunc().pointsTo(ex) and
|
||||||
ex.getAnImproperSuperType() = theExceptionType() and
|
ex.getASuperType() = ClassValue::exception() and
|
||||||
exists(ExprStmt s | s.getValue() = call)
|
exists(ExprStmt s | s.getValue() = call)
|
||||||
select call, "Instantiating an exception, but not raising it, has no effect"
|
select call, "Instantiating an exception, but not raising it, has no effect"
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
import python
|
import python
|
||||||
|
|
||||||
from CallNode call, string name
|
from CallNode call, string name
|
||||||
where call.getFunction().refersTo(Object::quitter(name))
|
where call.getFunction().pointsTo(Value::siteQuitter(name))
|
||||||
select call,
|
select call,
|
||||||
"The '" + name +
|
"The '" + name +
|
||||||
"' site.Quitter object may not exist if the 'site' module is not loaded or is modified."
|
"' site.Quitter object may not exist if the 'site' module is not loaded or is modified."
|
||||||
|
|||||||
@@ -301,6 +301,19 @@ module Value {
|
|||||||
result = ObjectInternal::none_()
|
result = ObjectInternal::none_()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shorcuts added by the `site` module to exit your interactive session.
|
||||||
|
*
|
||||||
|
* see https://docs.python.org/3/library/constants.html#constants-added-by-the-site-module
|
||||||
|
*/
|
||||||
|
Value siteQuitter(string name) {
|
||||||
|
(
|
||||||
|
name = "exit"
|
||||||
|
or
|
||||||
|
name = "quit"
|
||||||
|
) and
|
||||||
|
result = Value::named(name)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Class representing callables in the Python program
|
/** Class representing callables in the Python program
|
||||||
@@ -418,6 +431,12 @@ class ClassValue extends Value {
|
|||||||
this.hasAttribute("__get__")
|
this.hasAttribute("__get__")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Holds if this class is a context manager. */
|
||||||
|
predicate isContextManager() {
|
||||||
|
this.hasAttribute("__enter__") and
|
||||||
|
this.hasAttribute("__exit__")
|
||||||
|
}
|
||||||
|
|
||||||
/** Gets the qualified name for this class.
|
/** Gets the qualified name for this class.
|
||||||
* Should return the same name as the `__qualname__` attribute on classes in Python 3.
|
* Should return the same name as the `__qualname__` attribute on classes in Python 3.
|
||||||
*/
|
*/
|
||||||
@@ -698,34 +717,34 @@ module ClassValue {
|
|||||||
ClassValue bool() {
|
ClassValue bool() {
|
||||||
result = TBuiltinClassObject(Builtin::special("bool"))
|
result = TBuiltinClassObject(Builtin::special("bool"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get the `ClassValue` for the `tuple` class. */
|
/** Get the `ClassValue` for the `tuple` class. */
|
||||||
ClassValue tuple() {
|
ClassValue tuple() {
|
||||||
result = TBuiltinClassObject(Builtin::special("tuple"))
|
result = TBuiltinClassObject(Builtin::special("tuple"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get the `ClassValue` for the `list` class. */
|
/** Get the `ClassValue` for the `list` class. */
|
||||||
ClassValue list() {
|
ClassValue list() {
|
||||||
result = TBuiltinClassObject(Builtin::special("list"))
|
result = TBuiltinClassObject(Builtin::special("list"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get the `ClassValue` for `xrange` (Python 2), or `range` (only Python 3) */
|
/** Get the `ClassValue` for `xrange` (Python 2), or `range` (only Python 3) */
|
||||||
ClassValue range() {
|
ClassValue range() {
|
||||||
major_version() = 2 and result = TBuiltinClassObject(Builtin::special("xrange"))
|
major_version() = 2 and result = TBuiltinClassObject(Builtin::special("xrange"))
|
||||||
or
|
or
|
||||||
major_version() = 3 and result = TBuiltinClassObject(Builtin::special("range"))
|
major_version() = 3 and result = TBuiltinClassObject(Builtin::special("range"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get the `ClassValue` for the `dict` class. */
|
/** Get the `ClassValue` for the `dict` class. */
|
||||||
ClassValue dict() {
|
ClassValue dict() {
|
||||||
result = TBuiltinClassObject(Builtin::special("dict"))
|
result = TBuiltinClassObject(Builtin::special("dict"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get the `ClassValue` for the `set` class. */
|
/** Get the `ClassValue` for the `set` class. */
|
||||||
ClassValue set() {
|
ClassValue set() {
|
||||||
result = TBuiltinClassObject(Builtin::special("set"))
|
result = TBuiltinClassObject(Builtin::special("set"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get the `ClassValue` for the `object` class. */
|
/** Get the `ClassValue` for the `object` class. */
|
||||||
ClassValue object() {
|
ClassValue object() {
|
||||||
result = TBuiltinClassObject(Builtin::special("object"))
|
result = TBuiltinClassObject(Builtin::special("object"))
|
||||||
@@ -735,7 +754,7 @@ module ClassValue {
|
|||||||
ClassValue int_() {
|
ClassValue int_() {
|
||||||
result = TBuiltinClassObject(Builtin::special("int"))
|
result = TBuiltinClassObject(Builtin::special("int"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get the `ClassValue` for the `long` class. */
|
/** Get the `ClassValue` for the `long` class. */
|
||||||
ClassValue long() {
|
ClassValue long() {
|
||||||
result = TBuiltinClassObject(Builtin::special("long"))
|
result = TBuiltinClassObject(Builtin::special("long"))
|
||||||
@@ -745,7 +764,7 @@ module ClassValue {
|
|||||||
ClassValue float_() {
|
ClassValue float_() {
|
||||||
result = TBuiltinClassObject(Builtin::special("float"))
|
result = TBuiltinClassObject(Builtin::special("float"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get the `ClassValue` for the `complex` class. */
|
/** Get the `ClassValue` for the `complex` class. */
|
||||||
ClassValue complex() {
|
ClassValue complex() {
|
||||||
result = TBuiltinClassObject(Builtin::special("complex"))
|
result = TBuiltinClassObject(Builtin::special("complex"))
|
||||||
@@ -770,12 +789,12 @@ module ClassValue {
|
|||||||
else
|
else
|
||||||
result = unicode()
|
result = unicode()
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get the `ClassValue` for the `property` class. */
|
/** Get the `ClassValue` for the `property` class. */
|
||||||
ClassValue property() {
|
ClassValue property() {
|
||||||
result = TBuiltinClassObject(Builtin::special("property"))
|
result = TBuiltinClassObject(Builtin::special("property"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get the `ClassValue` for the class of Python functions. */
|
/** Get the `ClassValue` for the class of Python functions. */
|
||||||
ClassValue functionType() {
|
ClassValue functionType() {
|
||||||
result = TBuiltinClassObject(Builtin::special("FunctionType"))
|
result = TBuiltinClassObject(Builtin::special("FunctionType"))
|
||||||
@@ -785,32 +804,32 @@ module ClassValue {
|
|||||||
ClassValue builtinFunction() {
|
ClassValue builtinFunction() {
|
||||||
result = Value::named("len").getClass()
|
result = Value::named("len").getClass()
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get the `ClassValue` for the `generatorType` class. */
|
/** Get the `ClassValue` for the `generatorType` class. */
|
||||||
ClassValue generator() {
|
ClassValue generator() {
|
||||||
result = TBuiltinClassObject(Builtin::special("generator"))
|
result = TBuiltinClassObject(Builtin::special("generator"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get the `ClassValue` for the `type` class. */
|
/** Get the `ClassValue` for the `type` class. */
|
||||||
ClassValue type() {
|
ClassValue type() {
|
||||||
result = TType()
|
result = TType()
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get the `ClassValue` for `ClassType`. */
|
/** Get the `ClassValue` for `ClassType`. */
|
||||||
ClassValue classType() {
|
ClassValue classType() {
|
||||||
result = TBuiltinClassObject(Builtin::special("ClassType"))
|
result = TBuiltinClassObject(Builtin::special("ClassType"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get the `ClassValue` for `InstanceType`. */
|
/** Get the `ClassValue` for `InstanceType`. */
|
||||||
ClassValue instanceType() {
|
ClassValue instanceType() {
|
||||||
result = TBuiltinClassObject(Builtin::special("InstanceType"))
|
result = TBuiltinClassObject(Builtin::special("InstanceType"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get the `ClassValue` for `super`. */
|
/** Get the `ClassValue` for `super`. */
|
||||||
ClassValue super_() {
|
ClassValue super_() {
|
||||||
result = TBuiltinClassObject(Builtin::special("super"))
|
result = TBuiltinClassObject(Builtin::special("super"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get the `ClassValue` for the `classmethod` class. */
|
/** Get the `ClassValue` for the `classmethod` class. */
|
||||||
ClassValue classmethod() {
|
ClassValue classmethod() {
|
||||||
result = TBuiltinClassObject(Builtin::special("ClassMethod"))
|
result = TBuiltinClassObject(Builtin::special("ClassMethod"))
|
||||||
@@ -820,23 +839,23 @@ module ClassValue {
|
|||||||
ClassValue staticmethod() {
|
ClassValue staticmethod() {
|
||||||
result = TBuiltinClassObject(Builtin::special("StaticMethod"))
|
result = TBuiltinClassObject(Builtin::special("StaticMethod"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get the `ClassValue` for the `MethodType` class. */
|
/** Get the `ClassValue` for the `MethodType` class. */
|
||||||
pragma [noinline]
|
pragma [noinline]
|
||||||
ClassValue methodType() {
|
ClassValue methodType() {
|
||||||
result = TBuiltinClassObject(Builtin::special("MethodType"))
|
result = TBuiltinClassObject(Builtin::special("MethodType"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get the `ClassValue` for the `MethodDescriptorType` class. */
|
/** Get the `ClassValue` for the `MethodDescriptorType` class. */
|
||||||
ClassValue methodDescriptorType() {
|
ClassValue methodDescriptorType() {
|
||||||
result = TBuiltinClassObject(Builtin::special("MethodDescriptorType"))
|
result = TBuiltinClassObject(Builtin::special("MethodDescriptorType"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get the `ClassValue` for the `GetSetDescriptorType` class. */
|
/** Get the `ClassValue` for the `GetSetDescriptorType` class. */
|
||||||
ClassValue getSetDescriptorType() {
|
ClassValue getSetDescriptorType() {
|
||||||
result = TBuiltinClassObject(Builtin::special("GetSetDescriptorType"))
|
result = TBuiltinClassObject(Builtin::special("GetSetDescriptorType"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get the `ClassValue` for the `StopIteration` class. */
|
/** Get the `ClassValue` for the `StopIteration` class. */
|
||||||
ClassValue stopIteration() {
|
ClassValue stopIteration() {
|
||||||
result = TBuiltinClassObject(Builtin::special("StopIteration"))
|
result = TBuiltinClassObject(Builtin::special("StopIteration"))
|
||||||
@@ -851,17 +870,17 @@ module ClassValue {
|
|||||||
ClassValue exception() {
|
ClassValue exception() {
|
||||||
result = TBuiltinClassObject(Builtin::special("Exception"))
|
result = TBuiltinClassObject(Builtin::special("Exception"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get the `ClassValue` for the `BaseException` class. */
|
/** Get the `ClassValue` for the `BaseException` class. */
|
||||||
ClassValue baseException() {
|
ClassValue baseException() {
|
||||||
result = TBuiltinClassObject(Builtin::special("BaseException"))
|
result = TBuiltinClassObject(Builtin::special("BaseException"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get the `ClassValue` for the `NoneType` class. */
|
/** Get the `ClassValue` for the `NoneType` class. */
|
||||||
ClassValue nonetype() {
|
ClassValue nonetype() {
|
||||||
result = TBuiltinClassObject(Builtin::special("NoneType"))
|
result = TBuiltinClassObject(Builtin::special("NoneType"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get the `ClassValue` for the `TypeError` class */
|
/** Get the `ClassValue` for the `TypeError` class */
|
||||||
ClassValue typeError() {
|
ClassValue typeError() {
|
||||||
result = TBuiltinClassObject(Builtin::special("TypeError"))
|
result = TBuiltinClassObject(Builtin::special("TypeError"))
|
||||||
@@ -871,22 +890,22 @@ module ClassValue {
|
|||||||
ClassValue nameError() {
|
ClassValue nameError() {
|
||||||
result = TBuiltinClassObject(Builtin::builtin("NameError"))
|
result = TBuiltinClassObject(Builtin::builtin("NameError"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get the `ClassValue` for the `AttributeError` class. */
|
/** Get the `ClassValue` for the `AttributeError` class. */
|
||||||
ClassValue attributeError() {
|
ClassValue attributeError() {
|
||||||
result = TBuiltinClassObject(Builtin::builtin("AttributeError"))
|
result = TBuiltinClassObject(Builtin::builtin("AttributeError"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get the `ClassValue` for the `KeyError` class. */
|
/** Get the `ClassValue` for the `KeyError` class. */
|
||||||
ClassValue keyError() {
|
ClassValue keyError() {
|
||||||
result = TBuiltinClassObject(Builtin::builtin("KeyError"))
|
result = TBuiltinClassObject(Builtin::builtin("KeyError"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get the `ClassValue` for the `IOError` class. */
|
/** Get the `ClassValue` for the `IOError` class. */
|
||||||
ClassValue ioError() {
|
ClassValue ioError() {
|
||||||
result = TBuiltinClassObject(Builtin::builtin("IOError"))
|
result = TBuiltinClassObject(Builtin::builtin("IOError"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get the `ClassValue` for the `NotImplementedError` class. */
|
/** Get the `ClassValue` for the `NotImplementedError` class. */
|
||||||
ClassValue notImplementedError() {
|
ClassValue notImplementedError() {
|
||||||
result = TBuiltinClassObject(Builtin::builtin("NotImplementedError"))
|
result = TBuiltinClassObject(Builtin::builtin("NotImplementedError"))
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
| statements_test.py:19:5:19:18 | AssignStmt | Left hand side of assignment contains 3 variables, but right hand side is a $@ of length 2. | statements_test.py:19:15:19:18 | statements_test.py:19 | tuple |
|
| statements_test.py:19:5:19:18 | AssignStmt | Left hand side of assignment contains 3 variables, but right hand side is a $@ of length 2. | statements_test.py:19:15:19:18 | statements_test.py:19 | tuple |
|
||||||
| statements_test.py:167:5:167:23 | AssignStmt | Left hand side of assignment contains 3 variables, but right hand side is a $@ of length 5. | statements_test.py:167:13:167:23 | statements_test.py:167 | list |
|
| statements_test.py:169:5:169:23 | AssignStmt | Left hand side of assignment contains 3 variables, but right hand side is a $@ of length 5. | statements_test.py:169:13:169:23 | statements_test.py:169 | list |
|
||||||
| statements_test.py:176:5:176:48 | AssignStmt | Left hand side of assignment contains 3 variables, but right hand side is a $@ of length 5. | statements_test.py:171:16:171:24 | statements_test.py:171 | tuple |
|
| statements_test.py:178:5:178:48 | AssignStmt | Left hand side of assignment contains 3 variables, but right hand side is a $@ of length 5. | statements_test.py:173:16:173:24 | statements_test.py:173 | tuple |
|
||||||
| statements_test.py:176:5:176:48 | AssignStmt | Left hand side of assignment contains 3 variables, but right hand side is a $@ of length 6. | statements_test.py:173:16:173:26 | statements_test.py:173 | tuple |
|
| statements_test.py:178:5:178:48 | AssignStmt | Left hand side of assignment contains 3 variables, but right hand side is a $@ of length 6. | statements_test.py:175:16:175:26 | statements_test.py:175 | tuple |
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
| test.py:50:1:50:23 | For | $@ of class '$@' may be used in for-loop. | test.py:50:10:50:22 | ControlFlowNode for NonIterator() | Non-iterator | test.py:45:1:45:26 | class NonIterator | NonIterator |
|
| test.py:50:1:50:23 | For | $@ of class '$@' may be used in for-loop. | test.py:50:10:50:22 | ControlFlowNode for NonIterator() | Non-iterable | test.py:45:1:45:26 | class NonIterator | NonIterator |
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
| statements_test.py:54:5:54:9 | AssignStmt | This assignment assigns a variable to itself. |
|
| statements_test.py:54:5:54:9 | AssignStmt | This assignment assigns a variable to itself. |
|
||||||
| statements_test.py:57:9:57:19 | AssignStmt | This assignment assigns a variable to itself. |
|
| statements_test.py:57:9:57:19 | AssignStmt | This assignment assigns a variable to itself. |
|
||||||
| statements_test.py:117:9:117:23 | AssignStmt | This assignment assigns a variable to itself. |
|
| statements_test.py:119:9:119:23 | AssignStmt | This assignment assigns a variable to itself. |
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
| statements_test.py:185:5:185:9 | Delete | Unnecessary deletion of local variable $@ in function $@. | statements_test.py:185:9:185:9 | statements_test.py:185 | x | statements_test.py:183:1:183:31 | statements_test.py:183 | error_unnecessary_delete |
|
| statements_test.py:187:5:187:9 | Delete | Unnecessary deletion of local variable $@ in function $@. | statements_test.py:187:9:187:9 | statements_test.py:187 | x | statements_test.py:185:1:185:31 | statements_test.py:185 | error_unnecessary_delete |
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
| statements_test.py:63:1:63:19 | For | This 'for' statement has a redundant 'else' as no 'break' is present in the body. |
|
| statements_test.py:65:1:65:19 | For | This 'for' statement has a redundant 'else' as no 'break' is present in the body. |
|
||||||
| statements_test.py:68:1:68:13 | While | This 'while' statement has a redundant 'else' as no 'break' is present in the body. |
|
| statements_test.py:70:1:70:13 | While | This 'while' statement has a redundant 'else' as no 'break' is present in the body. |
|
||||||
|
|||||||
@@ -56,8 +56,10 @@ class Redundant(object):
|
|||||||
def __init__(self, args):
|
def __init__(self, args):
|
||||||
args = args # violation
|
args = args # violation
|
||||||
|
|
||||||
#Non redundant assignment
|
if sys.version_info < (3,):
|
||||||
len = len
|
bytes = str
|
||||||
|
else:
|
||||||
|
bytes = bytes # Should not be flagged
|
||||||
|
|
||||||
#Pointless else clauses
|
#Pointless else clauses
|
||||||
for x in range(10):
|
for x in range(10):
|
||||||
|
|||||||
Reference in New Issue
Block a user