Python: Modernise Statements/ queries

Almost. Left out a few things marked with TODO
This commit is contained in:
Rasmus Wriedt Larsen
2020-02-12 13:01:05 +01:00
parent 83d40f167b
commit 13568b7b9f
22 changed files with 129 additions and 110 deletions

View File

@@ -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

View File

@@ -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"

View File

@@ -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)
) )

View File

@@ -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

View File

@@ -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" />

View File

@@ -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()

View File

@@ -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."

View File

@@ -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

View File

@@ -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*() |

View File

@@ -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>

View File

@@ -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())
) )
} }

View File

@@ -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."

View File

@@ -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(),

View File

@@ -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"

View File

@@ -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."

View File

@@ -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"))

View File

@@ -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 |

View File

@@ -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 |

View File

@@ -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. |

View File

@@ -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 |

View File

@@ -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. |

View File

@@ -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):