diff --git a/python/ql/test/library-tests/ControlFlow/PointsToSupport/UseFromDefinition.expected b/python/ql/test/library-tests/ControlFlow/PointsToSupport/UseFromDefinition.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/library-tests/ControlFlow/PointsToSupport/UseFromDefinition.ql b/python/ql/test/library-tests/ControlFlow/PointsToSupport/UseFromDefinition.ql new file mode 100644 index 00000000000..8e3d1457572 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/PointsToSupport/UseFromDefinition.ql @@ -0,0 +1,23 @@ +/** + * @name UseFromDefinition + * @description Insert description here... + * @kind problem + * @problem.severity warning + */ + +import python + +/*Find any Definition, assigned value pairs that 'valueForDefinition' misses */ + +Expr assignedValue(Name n) { + exists(Assign a | a.getATarget() = n and result = a.getValue()) + or + exists(Alias a | a.getAsname() = n and result = a.getValue()) +} + +from Name def, DefinitionNode d +where d = def.getAFlowNode() and + exists(assignedValue(def)) and + not d.getValue().getNode() = assignedValue(def) + +select def.toString(), assignedValue(def) \ No newline at end of file diff --git a/python/ql/test/library-tests/ControlFlow/augassign/AugAssignFlow.expected b/python/ql/test/library-tests/ControlFlow/augassign/AugAssignFlow.expected new file mode 100644 index 00000000000..f5ab8c8a6f1 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/augassign/AugAssignFlow.expected @@ -0,0 +1,7 @@ +| ControlFlowNode for Attribute | ControlFlowNode for Attribute | 8 | +| ControlFlowNode for Attribute | ControlFlowNode for Attribute | 22 | +| ControlFlowNode for Subscript | ControlFlowNode for Subscript | 9 | +| ControlFlowNode for Subscript | ControlFlowNode for Subscript | 23 | +| ControlFlowNode for v | ControlFlowNode for v | 28 | +| ControlFlowNode for x | ControlFlowNode for x | 7 | +| ControlFlowNode for x | ControlFlowNode for x | 21 | \ No newline at end of file diff --git a/python/ql/test/library-tests/ControlFlow/augassign/AugAssignFlow.ql b/python/ql/test/library-tests/ControlFlow/augassign/AugAssignFlow.ql new file mode 100644 index 00000000000..d356ea5de43 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/augassign/AugAssignFlow.ql @@ -0,0 +1,10 @@ +import python + +int lineof(ControlFlowNode f) { + result = f.getNode().getLocation().getStartLine() +} + +from ControlFlowNode defn, ControlFlowNode use +where defn.getNode() = use.getNode() +and defn.isStore() and use.isLoad() +select defn.toString(), use.toString(), lineof(defn) diff --git a/python/ql/test/library-tests/ControlFlow/augassign/Kind.expected b/python/ql/test/library-tests/ControlFlow/augassign/Kind.expected new file mode 100644 index 00000000000..be8d11d0adb --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/augassign/Kind.expected @@ -0,0 +1,61 @@ +| 4 | test.py:4:5:4:9 | ControlFlowNode for func1 | store | +| 7 | test.py:7:5:7:5 | ControlFlowNode for x | aug load | +| 7 | test.py:7:5:7:5 | ControlFlowNode for x | aug store | +| 7 | test.py:7:10:7:10 | ControlFlowNode for f | load | +| 7 | test.py:7:12:7:12 | ControlFlowNode for y | load | +| 7 | test.py:7:16:7:20 | ControlFlowNode for Tuple | load | +| 8 | test.py:8:5:8:5 | ControlFlowNode for o | load | +| 8 | test.py:8:5:8:9 | ControlFlowNode for Attribute | load | +| 8 | test.py:8:5:8:14 | ControlFlowNode for Attribute | aug load | +| 8 | test.py:8:5:8:14 | ControlFlowNode for Attribute | aug store | +| 8 | test.py:8:19:8:19 | ControlFlowNode for f | load | +| 8 | test.py:8:21:8:21 | ControlFlowNode for y | load | +| 8 | test.py:8:25:8:29 | ControlFlowNode for Tuple | load | +| 9 | test.py:9:5:9:5 | ControlFlowNode for s | load | +| 9 | test.py:9:5:9:17 | ControlFlowNode for Subscript | aug load | +| 9 | test.py:9:5:9:17 | ControlFlowNode for Subscript | aug store | +| 9 | test.py:9:7:9:7 | ControlFlowNode for z | load | +| 9 | test.py:9:7:9:16 | ControlFlowNode for Tuple | load | +| 9 | test.py:9:22:9:22 | ControlFlowNode for f | load | +| 9 | test.py:9:24:9:24 | ControlFlowNode for y | load | +| 9 | test.py:9:28:9:32 | ControlFlowNode for Tuple | load | +| 10 | test.py:10:12:10:12 | ControlFlowNode for x | load | +| 13 | test.py:13:5:13:9 | ControlFlowNode for func2 | store | +| 14 | test.py:14:5:14:5 | ControlFlowNode for s | store | +| 14 | test.py:14:9:14:12 | ControlFlowNode for None | load | +| 15 | test.py:15:5:15:5 | ControlFlowNode for o | store | +| 15 | test.py:15:9:15:12 | ControlFlowNode for None | load | +| 16 | test.py:16:5:16:5 | ControlFlowNode for x | store | +| 16 | test.py:16:9:16:12 | ControlFlowNode for None | load | +| 17 | test.py:17:5:17:5 | ControlFlowNode for y | store | +| 17 | test.py:17:9:17:12 | ControlFlowNode for None | load | +| 18 | test.py:18:5:18:5 | ControlFlowNode for z | store | +| 18 | test.py:18:9:18:12 | ControlFlowNode for None | load | +| 21 | test.py:21:5:21:5 | ControlFlowNode for x | aug load | +| 21 | test.py:21:5:21:5 | ControlFlowNode for x | aug store | +| 21 | test.py:21:10:21:10 | ControlFlowNode for f | load | +| 21 | test.py:21:12:21:12 | ControlFlowNode for y | load | +| 21 | test.py:21:16:21:20 | ControlFlowNode for Tuple | load | +| 22 | test.py:22:5:22:5 | ControlFlowNode for o | load | +| 22 | test.py:22:5:22:9 | ControlFlowNode for Attribute | load | +| 22 | test.py:22:5:22:14 | ControlFlowNode for Attribute | aug load | +| 22 | test.py:22:5:22:14 | ControlFlowNode for Attribute | aug store | +| 22 | test.py:22:19:22:19 | ControlFlowNode for f | load | +| 22 | test.py:22:21:22:21 | ControlFlowNode for y | load | +| 22 | test.py:22:25:22:29 | ControlFlowNode for Tuple | load | +| 23 | test.py:23:5:23:5 | ControlFlowNode for s | load | +| 23 | test.py:23:5:23:17 | ControlFlowNode for Subscript | aug load | +| 23 | test.py:23:5:23:17 | ControlFlowNode for Subscript | aug store | +| 23 | test.py:23:7:23:7 | ControlFlowNode for z | load | +| 23 | test.py:23:7:23:16 | ControlFlowNode for Tuple | load | +| 23 | test.py:23:22:23:22 | ControlFlowNode for f | load | +| 23 | test.py:23:24:23:24 | ControlFlowNode for y | load | +| 23 | test.py:23:28:23:32 | ControlFlowNode for Tuple | load | +| 24 | test.py:24:12:24:12 | ControlFlowNode for x | load | +| 27 | test.py:27:5:27:8 | ControlFlowNode for comp | store | +| 28 | test.py:28:5:28:5 | ControlFlowNode for v | aug load | +| 28 | test.py:28:5:28:5 | ControlFlowNode for v | aug store | +| 28 | test.py:28:10:28:10 | ControlFlowNode for a | load | +| 28 | test.py:28:15:28:18 | ControlFlowNode for cond | load | +| 28 | test.py:28:25:28:25 | ControlFlowNode for b | load | +| 29 | test.py:29:12:29:12 | ControlFlowNode for v | load | diff --git a/python/ql/test/library-tests/ControlFlow/augassign/Kind.ql b/python/ql/test/library-tests/ControlFlow/augassign/Kind.ql new file mode 100644 index 00000000000..8ac3a4de0c1 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/augassign/Kind.ql @@ -0,0 +1,21 @@ + +import python + +string kind(ControlFlowNode f) { + if f.isAugLoad() then + result = "aug load" + else ( + if f.isAugStore() then + result = "aug store" + else ( + if f.isLoad() then + result = "load" + else ( + f.isStore() and result = "store" + ) + ) + ) +} + +from ControlFlowNode cfg +select cfg.getLocation().getStartLine(), cfg, kind(cfg) \ No newline at end of file diff --git a/python/ql/test/library-tests/ControlFlow/augassign/SSA.expected b/python/ql/test/library-tests/ControlFlow/augassign/SSA.expected new file mode 100644 index 00000000000..f5c89ccdfc4 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/augassign/SSA.expected @@ -0,0 +1,3 @@ +| ControlFlowNode for v | 28 | +| ControlFlowNode for x | 7 | +| ControlFlowNode for x | 21 | \ No newline at end of file diff --git a/python/ql/test/library-tests/ControlFlow/augassign/SSA.ql b/python/ql/test/library-tests/ControlFlow/augassign/SSA.ql new file mode 100644 index 00000000000..3738aa1f255 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/augassign/SSA.ql @@ -0,0 +1,13 @@ +/** + * @name SSA + * @description Insert description here... + * @kind problem + * @problem.severity warning + */ + +import python + + +from ControlFlowNode defn, SsaVariable v, AugAssign a, BinaryExpr b +where v.getDefinition() = defn and a.getOperation() = b and b.contains((Expr)defn.getNode()) +select defn.toString(), defn.getNode().getLocation().getStartLine() \ No newline at end of file diff --git a/python/ql/test/library-tests/ControlFlow/augassign/test.py b/python/ql/test/library-tests/ControlFlow/augassign/test.py new file mode 100644 index 00000000000..0a3cbe30ae3 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/augassign/test.py @@ -0,0 +1,29 @@ +#Test flow control for augmented assignment statements: + +#Parameters +def func1(s, o, x, y, z): + #Note that the right hand sides should be sufficiently complex + #to make the parts of the statement sufficiently separated + x += f(y, (1,2,3)) + o.val.item += f(y, (1,2,3)) + s[z, 10, 1:3] += f(y, (1,2,3)) + return x + +#Local variables +def func2(): + s = None + o = None + x = None + y = None + z = None + #Note that the right hand sides should be sufficiently complex + #to make the parts of the statement sufficiently separated + x += f(y, (1,2,3)) + o.val.item += f(y, (1,2,3)) + s[z, 10, 1:3] += f(y, (1,2,3)) + return x + +#Complex flow +def comp(v, cond): + v += a if cond else b + return v diff --git a/python/ql/test/library-tests/ControlFlow/comparison/Compare.expected b/python/ql/test/library-tests/ControlFlow/comparison/Compare.expected new file mode 100644 index 00000000000..34cb8350342 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/comparison/Compare.expected @@ -0,0 +1,6 @@ +| 1 | ControlFlowNode for Compare | a | b | == | +| 2 | ControlFlowNode for Compare | c | d | > | +| 3 | ControlFlowNode for Compare | e | f | < | +| 4 | ControlFlowNode for Compare | g | h | >= | +| 5 | ControlFlowNode for Compare | i | j | <= | +| 6 | ControlFlowNode for Compare | k | l | != | \ No newline at end of file diff --git a/python/ql/test/library-tests/ControlFlow/comparison/Compare.ql b/python/ql/test/library-tests/ControlFlow/comparison/Compare.ql new file mode 100644 index 00000000000..162b02b1f61 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/comparison/Compare.ql @@ -0,0 +1,17 @@ +/** + * @name CompareTest + * @description CompareTest + * @kind problem + * @problem.severity warning + */ + +import python + +from CompareNode c, NameNode l, NameNode r, Cmpop op, int line, Variable vl, Variable vr +where c.operands(l, op, r) and +line = c.getLocation().getStartLine() and +line = l.getLocation().getStartLine() and +line = r.getLocation().getStartLine() and +l.uses(vl) and r.uses(vr) +select line, c.toString(), vl.getId(), vr.getId(), op.getSymbol() + diff --git a/python/ql/test/library-tests/ControlFlow/comparison/compare.py b/python/ql/test/library-tests/ControlFlow/comparison/compare.py new file mode 100644 index 00000000000..e40411d931f --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/comparison/compare.py @@ -0,0 +1,6 @@ +a == b +c > d +e < f +g >= h +i <= j +k != l diff --git a/python/ql/test/library-tests/ControlFlow/delete/test.expected b/python/ql/test/library-tests/ControlFlow/delete/test.expected new file mode 100644 index 00000000000..ccbfba0b2a8 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/delete/test.expected @@ -0,0 +1,16 @@ +| 0 | Entry node for Module test | 1 | ControlFlowNode for FunctionExpr | +| 1 | ControlFlowNode for FunctionExpr | 1 | ControlFlowNode for foo | +| 1 | ControlFlowNode for a | 1 | ControlFlowNode for b | +| 1 | ControlFlowNode for b | 1 | ControlFlowNode for c | +| 1 | ControlFlowNode for c | 2 | ControlFlowNode for a | +| 1 | ControlFlowNode for foo | 0 | Exit node for Module test | +| 1 | Entry node for Function foo | 1 | ControlFlowNode for a | +| 2 | ControlFlowNode for Attribute | 2 | ControlFlowNode for Delete | +| 2 | ControlFlowNode for Delete | 3 | ControlFlowNode for a | +| 2 | ControlFlowNode for a | 2 | ControlFlowNode for Attribute | +| 3 | ControlFlowNode for Delete | 3 | ControlFlowNode for b | +| 3 | ControlFlowNode for Delete | 4 | ControlFlowNode for c | +| 3 | ControlFlowNode for a | 3 | ControlFlowNode for Delete | +| 3 | ControlFlowNode for b | 3 | ControlFlowNode for Delete | +| 4 | ControlFlowNode for Delete | 1 | Exit node for Function foo | +| 4 | ControlFlowNode for c | 4 | ControlFlowNode for Delete | diff --git a/python/ql/test/library-tests/ControlFlow/delete/test.py b/python/ql/test/library-tests/ControlFlow/delete/test.py new file mode 100644 index 00000000000..820bc3392d3 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/delete/test.py @@ -0,0 +1,4 @@ +def foo(a, b, c): + del a.x + del a, b + del c diff --git a/python/ql/test/library-tests/ControlFlow/delete/test.ql b/python/ql/test/library-tests/ControlFlow/delete/test.ql new file mode 100644 index 00000000000..517733b70d6 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/delete/test.ql @@ -0,0 +1,5 @@ +import python + +from ControlFlowNode p, ControlFlowNode s +where p.getASuccessor() = s +select p.getLocation().getStartLine().toString(), p.toString(), s.getLocation().getStartLine(), s.toString() \ No newline at end of file diff --git a/python/ql/test/library-tests/ControlFlow/dominators/DominatesSanity.expected b/python/ql/test/library-tests/ControlFlow/dominators/DominatesSanity.expected new file mode 100644 index 00000000000..fe98b155587 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/dominators/DominatesSanity.expected @@ -0,0 +1 @@ +| 0 | 0 | \ No newline at end of file diff --git a/python/ql/test/library-tests/ControlFlow/dominators/DominatesSanity.ql b/python/ql/test/library-tests/ControlFlow/dominators/DominatesSanity.ql new file mode 100644 index 00000000000..cb53879e63b --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/dominators/DominatesSanity.ql @@ -0,0 +1,9 @@ + +import python + +select count(BasicBlock b1, BasicBlock b2 +| b1 = b2.getImmediateDominator+() and not b1.strictlyDominates(b2) +), +count(BasicBlock b1, BasicBlock b2 +| not b1 = b2.getImmediateDominator+() and b1.strictlyDominates(b2) +) diff --git a/python/ql/test/library-tests/ControlFlow/dominators/idom.expected b/python/ql/test/library-tests/ControlFlow/dominators/idom.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/library-tests/ControlFlow/dominators/idom.ql b/python/ql/test/library-tests/ControlFlow/dominators/idom.ql new file mode 100644 index 00000000000..37739501bd9 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/dominators/idom.ql @@ -0,0 +1,16 @@ +/** + * @name Check all non-scope nodes have an immediate dominator + * @description Check all non-scope nodes have an immediate dominator + * @kind problem + * @problem.severity warning + */ + +import python + +/* This query should *never* produce a result */ + +from ControlFlowNode f +where not exists(f.getImmediateDominator()) +and not f.getNode() instanceof Scope +select f + diff --git a/python/ql/test/library-tests/ControlFlow/dominators/test.py b/python/ql/test/library-tests/ControlFlow/dominators/test.py new file mode 100644 index 00000000000..fe9db8fad0a --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/dominators/test.py @@ -0,0 +1,37 @@ + + +def f(): + while 0: + pass + return 1 + +def g(): + while 1: + pass + return unreachable + +def h(x): + if x: + return x + else: + return None + + + + +def k(a, b): + for x in a or b: + pass + return 0 + +def l(a, b, c): + if a or b or c: + return a or b or c + else: + return None + +def m(a, b, c): + if a and b and c: + return a and b and c + else: + return None \ No newline at end of file diff --git a/python/ql/test/library-tests/ControlFlow/except/test.expected b/python/ql/test/library-tests/ControlFlow/except/test.expected new file mode 100644 index 00000000000..da4b21d23df --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/except/test.expected @@ -0,0 +1,9 @@ +| e2 | +| e3 | +| e5 | +| e6 | +| e8 | +| ec | +| ed | +| ee | +| ef | \ No newline at end of file diff --git a/python/ql/test/library-tests/ControlFlow/except/test.py b/python/ql/test/library-tests/ControlFlow/except/test.py new file mode 100644 index 00000000000..e66082c4b88 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/except/test.py @@ -0,0 +1,106 @@ +#Ensure there is an exceptional edge from the following case + + + + + + +def f2(): + b, d = Base, Derived + try: + class MyNewClass(b, d): + pass + except: + e2 + +def f3(): + sequence_of_four = a_global + try: + a, b, c = sequence_of_four + except: + e3 + +#Always treat locals as non-raising to keep DB size down. +def f4(): + if cond: + local = 1 + try: + local + except: + e4 + +def f5(): + try: + a_global + except: + e5 + +def f6(): + local = a_global + try: + local() + except: + e6 + +#Literals can't raise +def f7(): + try: + 4 + except: + e7 + +def f8(): + try: + a + b + except: + e8 + + +#OK assignments +def f9(): + try: + a, b = 1, 2 + except: + e9 + +def fa(): + seq = a_global + try: + a = seq + except: + ea + +def fb(): + a, b, c = a_global + try: + seq = a, b, c + except: + eb + +#Ensure that a.b and c[d] can raise + +def fc(): + a, b = a_global + try: + return a[b] + except: + ec + +def fd(): + a = a_global + try: + return a.b + except: + ed + + +def fe(): + try: + call() + except: + ee + else: + ef + + + diff --git a/python/ql/test/library-tests/ControlFlow/except/test.ql b/python/ql/test/library-tests/ControlFlow/except/test.ql new file mode 100644 index 00000000000..a81459377af --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/except/test.ql @@ -0,0 +1,5 @@ +import python + +from GlobalVariable v, Name n, ControlFlowNode f +where v.getId().charAt(0) = "e" and n.uses(v) and f.getNode() = n +select v.getId() diff --git a/python/ql/test/library-tests/ControlFlow/general/Comments.expected b/python/ql/test/library-tests/ControlFlow/general/Comments.expected new file mode 100644 index 00000000000..f55daf3bc72 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/general/Comments.expected @@ -0,0 +1 @@ +| Module flowtest | 5 | diff --git a/python/ql/test/library-tests/ControlFlow/general/Comments.ql b/python/ql/test/library-tests/ControlFlow/general/Comments.ql new file mode 100644 index 00000000000..e93c8aae330 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/general/Comments.ql @@ -0,0 +1,6 @@ +import python + +from Module m, int n +where n = m.getMetrics().getNumberOfLinesOfComments() +select m.toString(), n + diff --git a/python/ql/test/library-tests/ControlFlow/general/Cyclo.expected b/python/ql/test/library-tests/ControlFlow/general/Cyclo.expected new file mode 100644 index 00000000000..e814047bf80 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/general/Cyclo.expected @@ -0,0 +1,9 @@ +| Function definitions | 2 | +| Function deletion | 1 | +| Function gloop | 2 | +| Function if_else | 2 | +| Function lloop | 2 | +| Function normal_args | 1 | +| Function special_args | 1 | +| Function try_except | 4 | +| Function try_finally | 2 | \ No newline at end of file diff --git a/python/ql/test/library-tests/ControlFlow/general/Cyclo.ql b/python/ql/test/library-tests/ControlFlow/general/Cyclo.ql new file mode 100644 index 00000000000..6ca0327ab0b --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/general/Cyclo.ql @@ -0,0 +1,6 @@ +import python + +from Function func +select func.toString(), func.getMetrics().getCyclomaticComplexity() + + diff --git a/python/ql/test/library-tests/ControlFlow/general/ImmediateDominatorCheck.expected b/python/ql/test/library-tests/ControlFlow/general/ImmediateDominatorCheck.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/library-tests/ControlFlow/general/ImmediateDominatorCheck.ql b/python/ql/test/library-tests/ControlFlow/general/ImmediateDominatorCheck.ql new file mode 100644 index 00000000000..f038fd8d77a --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/general/ImmediateDominatorCheck.ql @@ -0,0 +1,16 @@ + + +import python + +predicate +can_reach_from_entry_without_passing(ControlFlowNode target, ControlFlowNode pass) { + target != pass and target.getScope() = pass.getScope() and + (target.isEntryNode() or + exists(ControlFlowNode pre | target.getAPredecessor() = pre and can_reach_from_entry_without_passing(pre, pass))) +} + +from ControlFlowNode node, ControlFlowNode dom +where dom = node.getImmediateDominator() +and +can_reach_from_entry_without_passing(node, dom) +select node.toString(), dom.toString() diff --git a/python/ql/test/library-tests/ControlFlow/general/Lines.expected b/python/ql/test/library-tests/ControlFlow/general/Lines.expected new file mode 100644 index 00000000000..b7c1e0393fe --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/general/Lines.expected @@ -0,0 +1,10 @@ +| Function definitions | 13 | +| Function deletion | 7 | +| Function gloop | 6 | +| Function if_else | 6 | +| Function lloop | 4 | +| Function normal_args | 3 | +| Function special_args | 4 | +| Function try_except | 7 | +| Function try_finally | 7 | +| Module flowtest | 70 | diff --git a/python/ql/test/library-tests/ControlFlow/general/Lines.ql b/python/ql/test/library-tests/ControlFlow/general/Lines.ql new file mode 100644 index 00000000000..60046ef3242 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/general/Lines.ql @@ -0,0 +1,7 @@ +import python + +from Scope s, int n +where exists(Function f | f = s | n = f.getMetrics().getNumberOfLines()) or +exists(Module m | m = s | n = m.getMetrics().getNumberOfLines()) +select s.toString(), n + diff --git a/python/ql/test/library-tests/ControlFlow/general/Reaches.expected b/python/ql/test/library-tests/ControlFlow/general/Reaches.expected new file mode 100644 index 00000000000..4fc0324ad13 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/general/Reaches.expected @@ -0,0 +1,19 @@ +| ExceptionL | +| ExceptionR | +| cond1 | +| cond2 | +| except_handler | +| fall_through1 | +| fall_through2 | +| final_body | +| g1 | +| g2 | +| g3 | +| g5 | +| left | +| merged | +| right | +| try_body1 | +| try_body2 | +| try_body3 | +| try_body4 | \ No newline at end of file diff --git a/python/ql/test/library-tests/ControlFlow/general/Reaches.ql b/python/ql/test/library-tests/ControlFlow/general/Reaches.ql new file mode 100644 index 00000000000..548be578a76 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/general/Reaches.ql @@ -0,0 +1,13 @@ +import python + +predicate reaches_exit(Name u) { + u.uses(_) and + exists(ControlFlowNode f, BasicBlock b | + f.getNode() = u and f.getBasicBlock() = b | + b.reachesExit() + ) +} + +from Name u +where reaches_exit(u) and u.getVariable() instanceof GlobalVariable +select u.toString() diff --git a/python/ql/test/library-tests/ControlFlow/general/flowtest.py b/python/ql/test/library-tests/ControlFlow/general/flowtest.py new file mode 100644 index 00000000000..98589557409 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/general/flowtest.py @@ -0,0 +1,73 @@ +def definitions(p1): # Multiple defns of same variable + v1 = 0 + v1 + v1 = 1 + v1 + v2 = 2 + if p1: + v1 = 1 + v2 = 2 + else: + v2 = 2 + v1 + v2 + +def lloop(): #Loop + v3 = 0 + while 1: + v3 + +def gloop(): #Loop and global + global d1 + d1 = 0 + g1 + while g2: + g3 + +def deletion(): + global g4 + del g4 + g5 + v4 = 0 + del v4 + v4 + +def if_else(): + if cond1: + left + else: + right + merged + +def try_except(): + try: + try_body1() + try_body2() + except ExceptionL if cond2 else ExceptionR: + except_handler + fall_through1 + +def try_finally(): + try: + try_body3() + try_body4() + finally: + final_body + fall_through2 + +def normal_args(arg0, arg1): + arg0 + arg1 + +def special_args(*vararg, **kwarg): + vararg + + kwarg + + + +#A comment +#at the end of the file + + + diff --git a/python/ql/test/library-tests/ControlFlow/pruning/test.expected b/python/ql/test/library-tests/ControlFlow/pruning/test.expected new file mode 100644 index 00000000000..b8cd5b6b98d --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/pruning/test.expected @@ -0,0 +1,45 @@ +| 5 | 0 | +| 11 | 0 | +| 18 | 1 | +| 24 | 0 | +| 25 | 1 | +| 29 | 1 | +| 30 | 0 | +| 32 | 1 | +| 33 | 1 | +| 34 | 1 | +| 35 | 1 | +| 37 | 0 | +| 38 | 1 | +| 39 | 0 | +| 40 | 1 | +| 48 | 0 | +| 49 | 1 | +| 51 | 1 | +| 52 | 1 | +| 61 | 1 | +| 64 | 1 | +| 72 | 1 | +| 75 | 1 | +| 82 | 1 | +| 94 | 0 | +| 96 | 0 | +| 103 | 0 | +| 112 | 1 | +| 114 | 1 | +| 120 | 0 | +| 127 | 1 | +| 131 | 0 | +| 133 | 1 | +| 135 | 0 | +| 137 | 1 | +| 139 | 1 | +| 141 | 0 | +| 143 | 0 | +| 145 | 1 | +| 147 | 1 | +| 149 | 0 | +| 152 | 0 | +| 154 | 1 | +| 161 | 1 | +| 163 | 1 | diff --git a/python/ql/test/library-tests/ControlFlow/pruning/test.py b/python/ql/test/library-tests/ControlFlow/pruning/test.py new file mode 100644 index 00000000000..bdc43c414ad --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/pruning/test.py @@ -0,0 +1,164 @@ +#Test number of CFG nodes for each use of 'count' + +def dead(): + return 0 + count + +def conditional_dead(test): + if test: + return + if test: + count + +def made_true(seq): + if seq: + return + seq.append(1) + if seq: + count + +def boolop(t1, t2, t3, t4, t5, t6): + if not t1: + return + #bool(t1) must be True + t1 or count + t1 and count + if t2: + return + #bool(t2) must be False + t2 or count + t2 and count + if t3 or t4: + t3 or count + t3 and count + t3 or count + t4 and count + if t5 and t6: + t5 or count + t5 and count + t6 or count + t6 and count + +def with_splitting(t1, t2): + if t1: + if not t2: + return + #Cannot have bool(t1) be True and bool(t2) be False + if t1: + t2 or count #Unreachable + t2 and count + else: + t2 or count + t2 and count + +def loops(seq1, seq2, seq3, seq4, seq5): + if seq1: + return + if not seq2: + return + #bool(seq1) is False; bool(seq2) is True + while seq1: + count #This is unreachable, but the pop below forces us to be conservative. + seq1.pop() + while seq2: + count + seq2.pop() + if seq3: + return + if not seq4: + return + #bool(seq3) is False; bool(seq4) is True + for var in seq3: + count #This is unreachable, but we cannot infer this yet. + print(var) + for var in seq4: + count + print(var) + #seq5 false then made true + if seq5: + return + seq5.append(1) + for var in seq5: + count + print(var) + +#Logic does not apply to global variables in calls, +#as they may be changed from true to false externally. +from some_module import x, y +if not x: + raise Exception() +if y: + raise Exception() +make_a_call() +if not x: + count +if y: + count + +# However, modules are always true -- Which is important. +import another_module + +make_a_call() +if not another_module: + count + + +def negated_conditional_live(t1, t2): + if not t1: + return + if t2: + return + if t1: + count + if not t2: + count + +def negated_conditional_dead(test): + if not test: + return + if not test: + count + +def made_true2(m): + if m: + return + del m['a'] + if m: + count + +def prune_const_branches(): + if None: + count + if not None: + count + if False: + count + else: + count + if True: + count + else: + count + if 0: + count + else: + count + if -4: + count + else: + count + #Muliptle nots + if not not False: + count + if not not not False: + count + +#ODASA-6794 +def attribute_lookup_cannot_effect_comparisons_with_immutable_constants(ps): + if ps is not None: + ps_clamped = ps.clamp() + if ps is None: + count + else: + count + diff --git a/python/ql/test/library-tests/ControlFlow/pruning/test.ql b/python/ql/test/library-tests/ControlFlow/pruning/test.ql new file mode 100644 index 00000000000..837228fcd2a --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/pruning/test.ql @@ -0,0 +1,5 @@ +import python + +from Name n +where n.getId() = "count" +select n.getLocation().getStartLine(), count(n.getAFlowNode()) diff --git a/python/ql/test/library-tests/ControlFlow/raising_stmts/RaisingFlow.expected b/python/ql/test/library-tests/ControlFlow/raising_stmts/RaisingFlow.expected new file mode 100644 index 00000000000..ed831c69967 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/raising_stmts/RaisingFlow.expected @@ -0,0 +1,99 @@ +| 5 | ControlFlowNode for ImportExpr | normal | 5 | test.py:5:1:5:16 | ControlFlowNode for from _s import * | +| 5 | ControlFlowNode for from _s import * | normal | 7 | test.py:7:1:7:8 | ControlFlowNode for FunctionExpr | +| 7 | ControlFlowNode for FunctionExpr | normal | 7 | test.py:7:5:7:5 | ControlFlowNode for f | +| 7 | ControlFlowNode for f | normal | 15 | test.py:15:1:15:8 | ControlFlowNode for FunctionExpr | +| 8 | ControlFlowNode for ImportExpr | normal | 8 | test.py:8:12:8:12 | ControlFlowNode for x | +| 8 | ControlFlowNode for x | normal | 9 | test.py:9:10:9:10 | ControlFlowNode for ImportExpr | +| 9 | ControlFlowNode for ImportExpr | normal | 9 | test.py:9:19:9:19 | ControlFlowNode for ImportMember | +| 9 | ControlFlowNode for ImportMember | normal | 9 | test.py:9:19:9:19 | ControlFlowNode for b | +| 9 | ControlFlowNode for b | normal | 10 | test.py:10:9:10:12 | ControlFlowNode for AA_s | +| 10 | ControlFlowNode for AA_s | normal | 10 | test.py:10:14:10:14 | ControlFlowNode for IntegerLiteral | +| 10 | ControlFlowNode for Delete | normal | 12 | test.py:12:18:12:21 | ControlFlowNode for AA_p | +| 10 | ControlFlowNode for IntegerLiteral | normal | 10 | test.py:10:9:10:15 | ControlFlowNode for Subscript | +| 10 | ControlFlowNode for Subscript | normal | 10 | test.py:10:5:10:15 | ControlFlowNode for Delete | +| 12 | ControlFlowNode for AA_p | normal | 12 | test.py:12:5:12:14 | ControlFlowNode for Tuple | +| 12 | ControlFlowNode for AA_q | normal | 12 | test.py:12:11:12:14 | ControlFlowNode for AA_r | +| 12 | ControlFlowNode for AA_r | normal | 13 | test.py:13:12:13:15 | ControlFlowNode for AA_c | +| 12 | ControlFlowNode for Tuple | normal | 12 | test.py:12:5:12:8 | ControlFlowNode for AA_q | +| 13 | ControlFlowNode for AA_c | normal | 13 | test.py:13:20:13:23 | ControlFlowNode for AA_d | +| 13 | ControlFlowNode for AA_d | normal | 13 | test.py:13:12:13:23 | ControlFlowNode for Compare | +| 13 | ControlFlowNode for Compare | normal | 13 | test.py:13:5:13:23 | ControlFlowNode for Assert | +| 13 | ControlFlowNode for Compare | normal | 13 | test.py:13:5:13:23 | ControlFlowNode for Assert | +| 15 | ControlFlowNode for FunctionExpr | normal | 15 | test.py:15:5:15:5 | ControlFlowNode for g | +| 15 | ControlFlowNode for g | normal | 26 | test.py:26:1:26:8 | ControlFlowNode for FunctionExpr | +| 16 | ControlFlowNode for Try | normal | 17 | test.py:17:16:17:16 | ControlFlowNode for ImportExpr | +| 17 | ControlFlowNode for ImportExpr | normal | 17 | test.py:17:16:17:16 | ControlFlowNode for x | +| 17 | ControlFlowNode for ImportExpr | exception | 23 | test.py:23:5:23:11 | ControlFlowNode for ExceptStmt | +| 17 | ControlFlowNode for x | normal | 18 | test.py:18:14:18:14 | ControlFlowNode for ImportExpr | +| 18 | ControlFlowNode for ImportExpr | normal | 18 | test.py:18:23:18:23 | ControlFlowNode for ImportMember | +| 18 | ControlFlowNode for ImportExpr | exception | 23 | test.py:23:5:23:11 | ControlFlowNode for ExceptStmt | +| 18 | ControlFlowNode for ImportMember | normal | 18 | test.py:18:23:18:23 | ControlFlowNode for b | +| 18 | ControlFlowNode for ImportMember | exception | 23 | test.py:23:5:23:11 | ControlFlowNode for ExceptStmt | +| 18 | ControlFlowNode for b | normal | 19 | test.py:19:13:19:16 | ControlFlowNode for AA_s | +| 19 | ControlFlowNode for AA_s | normal | 19 | test.py:19:18:19:18 | ControlFlowNode for IntegerLiteral | +| 19 | ControlFlowNode for AA_s | exception | 23 | test.py:23:5:23:11 | ControlFlowNode for ExceptStmt | +| 19 | ControlFlowNode for Delete | normal | 21 | test.py:21:22:21:25 | ControlFlowNode for AA_p | +| 19 | ControlFlowNode for IntegerLiteral | normal | 19 | test.py:19:13:19:19 | ControlFlowNode for Subscript | +| 19 | ControlFlowNode for Subscript | normal | 19 | test.py:19:9:19:19 | ControlFlowNode for Delete | +| 19 | ControlFlowNode for Subscript | exception | 23 | test.py:23:5:23:11 | ControlFlowNode for ExceptStmt | +| 21 | ControlFlowNode for AA_p | normal | 21 | test.py:21:9:21:18 | ControlFlowNode for Tuple | +| 21 | ControlFlowNode for AA_p | exception | 23 | test.py:23:5:23:11 | ControlFlowNode for ExceptStmt | +| 21 | ControlFlowNode for AA_q | normal | 21 | test.py:21:15:21:18 | ControlFlowNode for AA_r | +| 21 | ControlFlowNode for AA_r | normal | 22 | test.py:22:16:22:19 | ControlFlowNode for AA_c | +| 21 | ControlFlowNode for Tuple | normal | 21 | test.py:21:9:21:12 | ControlFlowNode for AA_q | +| 21 | ControlFlowNode for Tuple | exception | 23 | test.py:23:5:23:11 | ControlFlowNode for ExceptStmt | +| 22 | ControlFlowNode for AA_c | normal | 22 | test.py:22:24:22:27 | ControlFlowNode for AA_d | +| 22 | ControlFlowNode for AA_c | exception | 23 | test.py:23:5:23:11 | ControlFlowNode for ExceptStmt | +| 22 | ControlFlowNode for AA_d | normal | 22 | test.py:22:16:22:27 | ControlFlowNode for Compare | +| 22 | ControlFlowNode for AA_d | exception | 23 | test.py:23:5:23:11 | ControlFlowNode for ExceptStmt | +| 22 | ControlFlowNode for Assert | exception | 23 | test.py:23:5:23:11 | ControlFlowNode for ExceptStmt | +| 22 | ControlFlowNode for Compare | normal | 22 | test.py:22:9:22:27 | ControlFlowNode for Assert | +| 22 | ControlFlowNode for Compare | normal | 22 | test.py:22:9:22:27 | ControlFlowNode for Assert | +| 23 | ControlFlowNode for ExceptStmt | normal | 24 | test.py:24:9:24:12 | ControlFlowNode for Pass | +| 26 | ControlFlowNode for FunctionExpr | normal | 26 | test.py:26:5:26:5 | ControlFlowNode for h | +| 26 | ControlFlowNode for h | normal | 34 | test.py:34:1:34:8 | ControlFlowNode for FunctionExpr | +| 27 | ControlFlowNode for Try | normal | 28 | test.py:28:9:28:14 | ControlFlowNode for a_call | +| 28 | ControlFlowNode for a_call | normal | 28 | test.py:28:9:28:16 | ControlFlowNode for a_call() | +| 28 | ControlFlowNode for a_call | exception | 29 | test.py:29:5:29:11 | ControlFlowNode for ExceptStmt | +| 28 | ControlFlowNode for a_call() | normal | 32 | test.py:32:9:32:12 | ControlFlowNode for Pass | +| 28 | ControlFlowNode for a_call() | exception | 29 | test.py:29:5:29:11 | ControlFlowNode for ExceptStmt | +| 29 | ControlFlowNode for ExceptStmt | normal | 30 | test.py:30:16:30:19 | ControlFlowNode for AA_c | +| 30 | ControlFlowNode for AA_c | normal | 30 | test.py:30:24:30:27 | ControlFlowNode for AA_d | +| 30 | ControlFlowNode for AA_c | exception | 32 | test.py:32:9:32:12 | ControlFlowNode for Pass | +| 30 | ControlFlowNode for AA_d | normal | 30 | test.py:30:16:30:27 | ControlFlowNode for Compare | +| 30 | ControlFlowNode for AA_d | exception | 32 | test.py:32:9:32:12 | ControlFlowNode for Pass | +| 30 | ControlFlowNode for Assert | normal | 32 | test.py:32:9:32:12 | ControlFlowNode for Pass | +| 30 | ControlFlowNode for Assert | exception | 32 | test.py:32:9:32:12 | ControlFlowNode for Pass | +| 30 | ControlFlowNode for Compare | normal | 30 | test.py:30:9:30:27 | ControlFlowNode for Assert | +| 30 | ControlFlowNode for Compare | normal | 30 | test.py:30:9:30:27 | ControlFlowNode for Assert | +| 34 | ControlFlowNode for FunctionExpr | normal | 34 | test.py:34:5:34:5 | ControlFlowNode for k | +| 34 | ControlFlowNode for k | normal | 45 | test.py:45:1:45:19 | ControlFlowNode for FunctionExpr | +| 35 | ControlFlowNode for Try | normal | 37 | test.py:37:13:37:13 | ControlFlowNode for y | +| 37 | ControlFlowNode for x | normal | 38 | test.py:38:16:38:16 | ControlFlowNode for a | +| 37 | ControlFlowNode for y | normal | 37 | test.py:37:9:37:9 | ControlFlowNode for x | +| 37 | ControlFlowNode for y | exception | 41 | test.py:41:5:41:11 | ControlFlowNode for ExceptStmt | +| 38 | ControlFlowNode for Tuple | normal | 38 | test.py:38:9:38:9 | ControlFlowNode for c | +| 38 | ControlFlowNode for Tuple | normal | 38 | test.py:38:9:38:12 | ControlFlowNode for Tuple | +| 38 | ControlFlowNode for a | normal | 38 | test.py:38:19:38:19 | ControlFlowNode for b | +| 38 | ControlFlowNode for a | exception | 41 | test.py:41:5:41:11 | ControlFlowNode for ExceptStmt | +| 38 | ControlFlowNode for b | normal | 38 | test.py:38:16:38:19 | ControlFlowNode for Tuple | +| 38 | ControlFlowNode for b | exception | 41 | test.py:41:5:41:11 | ControlFlowNode for ExceptStmt | +| 38 | ControlFlowNode for c | normal | 38 | test.py:38:12:38:12 | ControlFlowNode for d | +| 38 | ControlFlowNode for d | normal | 40 | test.py:40:16:40:16 | ControlFlowNode for p | +| 40 | ControlFlowNode for Tuple | normal | 40 | test.py:40:9:40:9 | ControlFlowNode for q | +| 40 | ControlFlowNode for Tuple | exception | 41 | test.py:41:5:41:11 | ControlFlowNode for ExceptStmt | +| 40 | ControlFlowNode for p | normal | 40 | test.py:40:9:40:12 | ControlFlowNode for Tuple | +| 40 | ControlFlowNode for p | exception | 41 | test.py:41:5:41:11 | ControlFlowNode for ExceptStmt | +| 40 | ControlFlowNode for q | normal | 40 | test.py:40:12:40:12 | ControlFlowNode for r | +| 41 | ControlFlowNode for ExceptStmt | normal | 42 | test.py:42:9:42:12 | ControlFlowNode for Pass | +| 45 | ControlFlowNode for FunctionExpr | normal | 45 | test.py:45:5:45:13 | ControlFlowNode for odasa3686 | +| 45 | ControlFlowNode for obj | normal | 47 | test.py:47:9:47:12 | ControlFlowNode for Try | +| 47 | ControlFlowNode for Try | normal | 48 | test.py:48:13:48:16 | ControlFlowNode for None | +| 48 | ControlFlowNode for Compare | normal | 49 | test.py:49:20:49:23 | ControlFlowNode for True | +| 48 | ControlFlowNode for Compare | exception | 50 | test.py:50:9:50:25 | ControlFlowNode for ExceptStmt | +| 48 | ControlFlowNode for None | normal | 48 | test.py:48:21:48:23 | ControlFlowNode for obj | +| 48 | ControlFlowNode for obj | normal | 48 | test.py:48:13:48:23 | ControlFlowNode for Compare | +| 49 | ControlFlowNode for True | normal | 49 | test.py:49:13:49:23 | ControlFlowNode for Return | +| 50 | ControlFlowNode for ExceptStmt | normal | 50 | test.py:50:16:50:24 | ControlFlowNode for TypeError | +| 50 | ControlFlowNode for TypeError | normal | 51 | test.py:51:20:51:24 | ControlFlowNode for False | +| 51 | ControlFlowNode for False | normal | 51 | test.py:51:13:51:24 | ControlFlowNode for Return | diff --git a/python/ql/test/library-tests/ControlFlow/raising_stmts/RaisingFlow.ql b/python/ql/test/library-tests/ControlFlow/raising_stmts/RaisingFlow.ql new file mode 100644 index 00000000000..bfc884f7bac --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/raising_stmts/RaisingFlow.ql @@ -0,0 +1,17 @@ +/** + * @name Raising Flow + * @description Test + */ + +import python + +from ControlFlowNode p, ControlFlowNode s, string kind +where p.getASuccessor() = s and +(if s = p.getAnExceptionalSuccessor() then + kind = "exception" + else + kind = " normal " +) and +not p.getNode() instanceof Scope and +not s.getNode() instanceof Scope +select p.getNode().getLocation().getStartLine(), p.toString(), kind, s.getNode().getLocation().getStartLine(), s diff --git a/python/ql/test/library-tests/ControlFlow/raising_stmts/test.py b/python/ql/test/library-tests/ControlFlow/raising_stmts/test.py new file mode 100644 index 00000000000..42e8baa47cb --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/raising_stmts/test.py @@ -0,0 +1,51 @@ +#All variables that will evaluate before statements start with "AA_" +#so that the test output better reflects the execution order and makes +#it easier to manually verify. + +from _s import * + +def f(): + import x + from a import b + del AA_s[0] + + AA_q, AA_r = AA_p + assert AA_c == AA_d + +def g(): + try: + import x + from a import b + del AA_s[0] + + AA_q, AA_r = AA_p + assert AA_c == AA_d + except: + pass + +def h(): + try: + a_call() + except: + assert AA_c == AA_d + finally: + pass + +def k(): + try: + #Safe + x = y + c, d = a, b + #Unsafe + q, r = p + except: + pass + + +def odasa3686(obj): + #Test for iterability + try: + None in obj + return True + except TypeError: + return False diff --git a/python/ql/test/library-tests/ControlFlow/splitting/NodeCount.expected b/python/ql/test/library-tests/ControlFlow/splitting/NodeCount.expected new file mode 100644 index 00000000000..c1ce91c2e8d --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/splitting/NodeCount.expected @@ -0,0 +1,565 @@ +| 2 | split1 | test.py:2:12:2:15 | cond | 1 | +| 3 | split1 | test.py:3:8:3:11 | cond | 1 | +| 4 | split1 | test.py:4:9:4:12 | Pass | 1 | +| 5 | split1 | test.py:5:8:5:11 | cond | 2 | +| 6 | split1 | test.py:6:9:6:12 | Pass | 1 | +| 8 | dont_split1 | test.py:8:17:8:20 | cond | 1 | +| 9 | dont_split1 | test.py:9:8:9:11 | cond | 1 | +| 10 | dont_split1 | test.py:10:9:10:12 | Pass | 1 | +| 11 | dont_split1 | test.py:11:5:11:8 | cond | 1 | +| 11 | dont_split1 | test.py:11:12:11:12 | f | 1 | +| 11 | dont_split1 | test.py:11:12:11:14 | f() | 1 | +| 12 | dont_split1 | test.py:12:8:12:11 | cond | 1 | +| 13 | dont_split1 | test.py:13:9:13:12 | Pass | 1 | +| 15 | dont_split2 | test.py:15:17:15:20 | cond | 1 | +| 16 | dont_split2 | test.py:16:8:16:11 | cond | 1 | +| 17 | dont_split2 | test.py:17:9:17:12 | Pass | 1 | +| 18 | dont_split2 | test.py:18:5:18:20 | For | 1 | +| 18 | dont_split2 | test.py:18:9:18:12 | cond | 1 | +| 18 | dont_split2 | test.py:18:17:18:19 | seq | 1 | +| 18 | dont_split2 | test.py:18:22:18:25 | Pass | 1 | +| 19 | dont_split2 | test.py:19:8:19:11 | cond | 1 | +| 20 | dont_split2 | test.py:20:9:20:12 | Pass | 1 | +| 24 | split2 | test.py:24:5:24:8 | Try | 1 | +| 25 | split2 | test.py:25:9:25:12 | call | 1 | +| 25 | split2 | test.py:25:9:25:14 | call() | 1 | +| 26 | split2 | test.py:26:9:26:9 | x | 1 | +| 26 | split2 | test.py:26:13:26:16 | True | 1 | +| 27 | split2 | test.py:27:5:27:11 | ExceptStmt | 1 | +| 28 | split2 | test.py:28:9:28:9 | x | 1 | +| 28 | split2 | test.py:28:13:28:17 | False | 1 | +| 29 | split2 | test.py:29:8:29:8 | x | 2 | +| 30 | split2 | test.py:30:9:30:12 | Pass | 1 | +| 33 | unclear_split3 | test.py:33:5:33:8 | Try | 1 | +| 34 | unclear_split3 | test.py:34:9:34:12 | call | 1 | +| 34 | unclear_split3 | test.py:34:9:34:14 | call() | 1 | +| 35 | unclear_split3 | test.py:35:9:35:9 | x | 1 | +| 35 | unclear_split3 | test.py:35:13:35:16 | True | 1 | +| 36 | unclear_split3 | test.py:36:5:36:11 | ExceptStmt | 1 | +| 37 | unclear_split3 | test.py:37:9:37:9 | x | 1 | +| 37 | unclear_split3 | test.py:37:13:37:17 | False | 1 | +| 38 | unclear_split3 | test.py:38:8:38:11 | cond | 1 | +| 39 | unclear_split3 | test.py:39:9:39:9 | x | 1 | +| 39 | unclear_split3 | test.py:39:13:39:17 | False | 1 | +| 40 | unclear_split3 | test.py:40:8:40:8 | x | 2 | +| 41 | unclear_split3 | test.py:41:9:41:12 | Pass | 1 | +| 43 | split4 | test.py:43:12:43:12 | x | 1 | +| 44 | split4 | test.py:44:8:44:8 | x | 1 | +| 44 | split4 | test.py:44:8:44:16 | Compare | 1 | +| 44 | split4 | test.py:44:13:44:16 | None | 1 | +| 45 | split4 | test.py:45:9:45:9 | x | 1 | +| 45 | split4 | test.py:45:13:45:20 | not_none | 1 | +| 45 | split4 | test.py:45:13:45:22 | not_none() | 1 | +| 46 | split4 | test.py:46:5:46:5 | c | 1 | +| 46 | split4 | test.py:46:5:46:17 | IfExp | 1 | +| 46 | split4 | test.py:46:10:46:10 | b | 1 | +| 46 | split4 | test.py:46:17:46:17 | c | 1 | +| 47 | split4 | test.py:47:5:47:12 | Return | 1 | +| 47 | split4 | test.py:47:12:47:12 | x | 1 | +| 49 | split_carefully_5 | test.py:49:23:49:23 | x | 1 | +| 50 | split_carefully_5 | test.py:50:8:50:8 | x | 1 | +| 50 | split_carefully_5 | test.py:50:8:50:16 | Compare | 1 | +| 50 | split_carefully_5 | test.py:50:13:50:16 | None | 1 | +| 51 | split_carefully_5 | test.py:51:9:51:9 | x | 1 | +| 51 | split_carefully_5 | test.py:51:13:51:20 | not_none | 1 | +| 51 | split_carefully_5 | test.py:51:13:51:22 | not_none() | 1 | +| 52 | split_carefully_5 | test.py:52:8:52:8 | x | 1 | +| 53 | split_carefully_5 | test.py:53:9:53:12 | Pass | 1 | +| 54 | split_carefully_5 | test.py:54:5:54:12 | Return | 1 | +| 54 | split_carefully_5 | test.py:54:12:54:12 | x | 1 | +| 58 | dont_split_globals | test.py:58:8:58:11 | cond | 1 | +| 59 | dont_split_globals | test.py:59:9:59:12 | Pass | 1 | +| 60 | dont_split_globals | test.py:60:5:60:31 | call_could_alter_any_global | 2 | +| 60 | dont_split_globals | test.py:60:5:60:33 | call_could_alter_any_global() | 2 | +| 61 | dont_split_globals | test.py:61:8:61:11 | cond | 2 | +| 62 | dont_split_globals | test.py:62:9:62:12 | Pass | 2 | +| 64 | limit_splitting1 | test.py:64:22:64:22 | a | 1 | +| 64 | limit_splitting1 | test.py:64:24:64:24 | b | 1 | +| 64 | limit_splitting1 | test.py:64:26:64:26 | c | 1 | +| 64 | limit_splitting1 | test.py:64:28:64:28 | d | 1 | +| 65 | limit_splitting1 | test.py:65:8:65:8 | a | 1 | +| 65 | limit_splitting1 | test.py:65:8:65:16 | Compare | 1 | +| 65 | limit_splitting1 | test.py:65:13:65:16 | None | 1 | +| 65 | limit_splitting1 | test.py:65:19:65:19 | a | 1 | +| 65 | limit_splitting1 | test.py:65:23:65:25 | Str | 1 | +| 66 | limit_splitting1 | test.py:66:8:66:8 | b | 1 | +| 66 | limit_splitting1 | test.py:66:8:66:16 | Compare | 1 | +| 66 | limit_splitting1 | test.py:66:13:66:16 | None | 1 | +| 66 | limit_splitting1 | test.py:66:19:66:19 | b | 1 | +| 66 | limit_splitting1 | test.py:66:23:66:25 | Str | 1 | +| 67 | limit_splitting1 | test.py:67:8:67:8 | c | 1 | +| 67 | limit_splitting1 | test.py:67:8:67:16 | Compare | 1 | +| 67 | limit_splitting1 | test.py:67:13:67:16 | None | 1 | +| 67 | limit_splitting1 | test.py:67:19:67:19 | c | 1 | +| 67 | limit_splitting1 | test.py:67:23:67:25 | Str | 1 | +| 68 | limit_splitting1 | test.py:68:8:68:8 | d | 1 | +| 68 | limit_splitting1 | test.py:68:8:68:16 | Compare | 1 | +| 68 | limit_splitting1 | test.py:68:13:68:16 | None | 1 | +| 68 | limit_splitting1 | test.py:68:19:68:19 | d | 1 | +| 68 | limit_splitting1 | test.py:68:23:68:25 | Str | 1 | +| 69 | limit_splitting1 | test.py:69:5:69:8 | Pass | 1 | +| 77 | limit_splitting2 | test.py:77:22:77:22 | a | 1 | +| 77 | limit_splitting2 | test.py:77:24:77:24 | b | 1 | +| 77 | limit_splitting2 | test.py:77:26:77:26 | c | 1 | +| 77 | limit_splitting2 | test.py:77:28:77:28 | d | 1 | +| 78 | limit_splitting2 | test.py:78:8:78:8 | a | 1 | +| 79 | limit_splitting2 | test.py:79:9:79:12 | Pass | 1 | +| 80 | limit_splitting2 | test.py:80:8:80:8 | b | 2 | +| 81 | limit_splitting2 | test.py:81:9:81:12 | Pass | 2 | +| 82 | limit_splitting2 | test.py:82:8:82:8 | c | 4 | +| 83 | limit_splitting2 | test.py:83:9:83:12 | Pass | 4 | +| 84 | limit_splitting2 | test.py:84:8:84:8 | d | 4 | +| 85 | limit_splitting2 | test.py:85:9:85:12 | Pass | 4 | +| 87 | limit_splitting2 | test.py:87:8:87:8 | a | 4 | +| 88 | limit_splitting2 | test.py:88:9:88:10 | a1 | 2 | +| 89 | limit_splitting2 | test.py:89:8:89:8 | b | 4 | +| 90 | limit_splitting2 | test.py:90:9:90:10 | b1 | 2 | +| 92 | limit_splitting2 | test.py:92:8:92:8 | c | 4 | +| 93 | limit_splitting2 | test.py:93:9:93:10 | c1 | 4 | +| 94 | limit_splitting2 | test.py:94:8:94:8 | d | 4 | +| 95 | limit_splitting2 | test.py:95:9:95:10 | d1 | 4 | +| 98 | split_on_numbers | test.py:98:5:98:8 | Try | 1 | +| 99 | split_on_numbers | test.py:99:9:99:12 | call | 1 | +| 99 | split_on_numbers | test.py:99:9:99:14 | call() | 1 | +| 100 | split_on_numbers | test.py:100:9:100:9 | x | 1 | +| 100 | split_on_numbers | test.py:100:13:100:14 | UnaryExpr | 1 | +| 100 | split_on_numbers | test.py:100:14:100:14 | IntegerLiteral | 1 | +| 101 | split_on_numbers | test.py:101:5:101:11 | ExceptStmt | 1 | +| 102 | split_on_numbers | test.py:102:9:102:9 | x | 1 | +| 102 | split_on_numbers | test.py:102:13:102:13 | IntegerLiteral | 1 | +| 103 | split_on_numbers | test.py:103:8:103:8 | x | 2 | +| 104 | split_on_numbers | test.py:104:9:104:12 | Pass | 1 | +| 107 | split_try_except_else | test.py:107:5:107:8 | Try | 1 | +| 108 | split_try_except_else | test.py:108:9:108:12 | call | 1 | +| 108 | split_try_except_else | test.py:108:9:108:14 | call() | 1 | +| 109 | split_try_except_else | test.py:109:5:109:11 | ExceptStmt | 1 | +| 110 | split_try_except_else | test.py:110:9:110:9 | x | 1 | +| 110 | split_try_except_else | test.py:110:13:110:13 | IntegerLiteral | 1 | +| 112 | split_try_except_else | test.py:112:9:112:9 | x | 1 | +| 112 | split_try_except_else | test.py:112:13:112:13 | IntegerLiteral | 1 | +| 113 | split_try_except_else | test.py:113:8:113:8 | x | 2 | +| 114 | split_try_except_else | test.py:114:9:114:12 | Pass | 1 | +| 119 | logging | test.py:119:5:119:8 | Try | 1 | +| 120 | logging | test.py:120:16:120:22 | ImportExpr | 1 | +| 120 | logging | test.py:120:16:120:22 | module1 | 1 | +| 121 | logging | test.py:121:16:121:22 | ImportExpr | 1 | +| 121 | logging | test.py:121:16:121:22 | module2 | 1 | +| 123 | logging | test.py:123:5:123:23 | ExceptStmt | 1 | +| 123 | logging | test.py:123:12:123:22 | ImportError | 1 | +| 124 | logging | test.py:124:9:124:15 | module1 | 1 | +| 124 | logging | test.py:124:19:124:22 | None | 1 | +| 126 | logging | test.py:126:8:126:14 | module1 | 2 | +| 127 | logging | test.py:127:9:127:12 | inst | 1 | +| 127 | logging | test.py:127:16:127:22 | module2 | 1 | +| 127 | logging | test.py:127:16:127:28 | Attribute | 1 | +| 127 | logging | test.py:127:16:127:30 | Attribute() | 1 | +| 131 | split5 | test.py:131:5:131:8 | Try | 1 | +| 132 | split5 | test.py:132:9:132:12 | call | 1 | +| 132 | split5 | test.py:132:9:132:14 | call() | 1 | +| 133 | split5 | test.py:133:9:133:9 | x | 1 | +| 133 | split5 | test.py:133:13:133:16 | True | 1 | +| 134 | split5 | test.py:134:5:134:11 | ExceptStmt | 1 | +| 135 | split5 | test.py:135:9:135:9 | x | 1 | +| 135 | split5 | test.py:135:13:135:17 | False | 1 | +| 136 | split5 | test.py:136:8:136:12 | UnaryExpr | 2 | +| 136 | split5 | test.py:136:12:136:12 | x | 2 | +| 137 | split5 | test.py:137:9:137:12 | Pass | 1 | +| 140 | split6 | test.py:140:5:140:8 | Try | 1 | +| 141 | split6 | test.py:141:9:141:12 | call | 1 | +| 141 | split6 | test.py:141:9:141:14 | call() | 1 | +| 142 | split6 | test.py:142:9:142:9 | x | 1 | +| 142 | split6 | test.py:142:13:142:16 | True | 1 | +| 143 | split6 | test.py:143:5:143:11 | ExceptStmt | 1 | +| 144 | split6 | test.py:144:9:144:9 | x | 1 | +| 144 | split6 | test.py:144:13:144:17 | False | 1 | +| 145 | split6 | test.py:145:8:145:16 | UnaryExpr | 2 | +| 145 | split6 | test.py:145:12:145:16 | UnaryExpr | 2 | +| 145 | split6 | test.py:145:16:145:16 | x | 2 | +| 146 | split6 | test.py:146:9:146:12 | Pass | 1 | +| 149 | split7 | test.py:149:5:149:8 | Try | 1 | +| 150 | split7 | test.py:150:9:150:12 | call | 1 | +| 150 | split7 | test.py:150:9:150:14 | call() | 1 | +| 151 | split7 | test.py:151:9:151:9 | x | 1 | +| 151 | split7 | test.py:151:13:151:20 | UnaryExpr | 1 | +| 151 | split7 | test.py:151:17:151:20 | True | 1 | +| 152 | split7 | test.py:152:5:152:11 | ExceptStmt | 1 | +| 153 | split7 | test.py:153:9:153:9 | x | 1 | +| 153 | split7 | test.py:153:13:153:21 | UnaryExpr | 1 | +| 153 | split7 | test.py:153:17:153:21 | False | 1 | +| 154 | split7 | test.py:154:8:154:8 | x | 2 | +| 155 | split7 | test.py:155:9:155:12 | Pass | 1 | +| 157 | split8 | test.py:157:12:157:15 | cond | 1 | +| 158 | split8 | test.py:158:8:158:11 | cond | 1 | +| 159 | split8 | test.py:159:9:159:9 | t | 1 | +| 159 | split8 | test.py:159:13:159:16 | True | 1 | +| 161 | split8 | test.py:161:9:161:9 | t | 1 | +| 161 | split8 | test.py:161:13:161:17 | False | 1 | +| 162 | split8 | test.py:162:8:162:15 | UnaryExpr | 2 | +| 162 | split8 | test.py:162:12:162:15 | cond | 2 | +| 163 | split8 | test.py:163:12:163:12 | t | 1 | +| 164 | split8 | test.py:164:13:164:16 | Pass | 0 | +| 167 | split9 | test.py:167:12:167:14 | var | 1 | +| 168 | split9 | test.py:168:8:168:10 | var | 1 | +| 168 | split9 | test.py:168:8:168:18 | Compare | 1 | +| 168 | split9 | test.py:168:15:168:18 | None | 1 | +| 169 | split9 | test.py:169:9:169:10 | a1 | 1 | +| 171 | split9 | test.py:171:9:171:10 | a2 | 1 | +| 172 | split9 | test.py:172:8:172:10 | var | 2 | +| 172 | split9 | test.py:172:8:172:22 | Compare | 2 | +| 172 | split9 | test.py:172:19:172:22 | None | 2 | +| 173 | split9 | test.py:173:9:173:10 | b1 | 1 | +| 175 | split9 | test.py:175:9:175:10 | b2 | 1 | +| 177 | split10 | test.py:177:13:177:15 | var | 1 | +| 178 | split10 | test.py:178:8:178:10 | var | 1 | +| 179 | split10 | test.py:179:9:179:10 | a1 | 1 | +| 181 | split10 | test.py:181:9:181:10 | a2 | 1 | +| 182 | split10 | test.py:182:8:182:10 | var | 2 | +| 182 | split10 | test.py:182:8:182:22 | Compare | 2 | +| 182 | split10 | test.py:182:19:182:22 | None | 2 | +| 183 | split10 | test.py:183:9:183:10 | b1 | 2 | +| 185 | split10 | test.py:185:9:185:10 | b2 | 1 | +| 187 | split11 | test.py:187:13:187:15 | var | 1 | +| 188 | split11 | test.py:188:8:188:10 | var | 1 | +| 188 | split11 | test.py:188:8:188:18 | Compare | 1 | +| 188 | split11 | test.py:188:15:188:18 | None | 1 | +| 189 | split11 | test.py:189:9:189:10 | a1 | 1 | +| 191 | split11 | test.py:191:9:191:10 | a2 | 1 | +| 192 | split11 | test.py:192:8:192:10 | var | 2 | +| 193 | split11 | test.py:193:9:193:10 | b1 | 1 | +| 195 | split11 | test.py:195:9:195:10 | b2 | 2 | +| 197 | dont_split_on_unrelated_variables | test.py:197:39:197:42 | var1 | 1 | +| 197 | dont_split_on_unrelated_variables | test.py:197:45:197:48 | var2 | 1 | +| 198 | dont_split_on_unrelated_variables | test.py:198:8:198:11 | var1 | 1 | +| 198 | dont_split_on_unrelated_variables | test.py:198:8:198:19 | Compare | 1 | +| 198 | dont_split_on_unrelated_variables | test.py:198:16:198:19 | None | 1 | +| 199 | dont_split_on_unrelated_variables | test.py:199:9:199:10 | a1 | 1 | +| 201 | dont_split_on_unrelated_variables | test.py:201:9:201:10 | a2 | 1 | +| 202 | dont_split_on_unrelated_variables | test.py:202:8:202:11 | var2 | 1 | +| 202 | dont_split_on_unrelated_variables | test.py:202:8:202:23 | Compare | 1 | +| 202 | dont_split_on_unrelated_variables | test.py:202:20:202:23 | None | 1 | +| 203 | dont_split_on_unrelated_variables | test.py:203:9:203:10 | b1 | 1 | +| 205 | dont_split_on_unrelated_variables | test.py:205:9:205:10 | b2 | 1 | +| 208 | split12 | test.py:208:5:208:8 | Try | 1 | +| 209 | split12 | test.py:209:9:209:12 | call | 1 | +| 209 | split12 | test.py:209:9:209:14 | call() | 1 | +| 210 | split12 | test.py:210:9:210:9 | x | 1 | +| 210 | split12 | test.py:210:13:210:16 | None | 1 | +| 211 | split12 | test.py:211:5:211:11 | ExceptStmt | 1 | +| 212 | split12 | test.py:212:16:212:16 | ImportExpr | 1 | +| 212 | split12 | test.py:212:16:212:16 | x | 1 | +| 213 | split12 | test.py:213:8:213:8 | x | 2 | +| 214 | split12 | test.py:214:9:214:12 | Pass | 1 | +| 217 | split13 | test.py:217:5:217:7 | var | 1 | +| 217 | split13 | test.py:217:11:217:14 | cond | 1 | +| 217 | split13 | test.py:217:11:217:16 | cond() | 1 | +| 218 | split13 | test.py:218:8:218:10 | var | 1 | +| 219 | split13 | test.py:219:9:219:10 | a1 | 1 | +| 221 | split13 | test.py:221:9:221:10 | a2 | 1 | +| 222 | split13 | test.py:222:5:222:8 | Try | 2 | +| 223 | split13 | test.py:223:9:223:10 | b1 | 2 | +| 225 | split13 | test.py:225:12:225:14 | var | 4 | +| 226 | split13 | test.py:226:13:226:14 | a3 | 2 | +| 230 | split14 | test.py:230:5:230:8 | flag | 1 | +| 230 | split14 | test.py:230:12:230:16 | False | 1 | +| 231 | split14 | test.py:231:5:231:8 | Try | 1 | +| 232 | split14 | test.py:232:9:232:9 | x | 1 | +| 232 | split14 | test.py:232:13:232:21 | something | 1 | +| 232 | split14 | test.py:232:13:232:23 | something() | 1 | +| 233 | split14 | test.py:233:5:233:21 | ExceptStmt | 1 | +| 233 | split14 | test.py:233:12:233:20 | Exception | 1 | +| 234 | split14 | test.py:234:9:234:10 | IntegerLiteral | 1 | +| 235 | split14 | test.py:235:9:235:12 | flag | 1 | +| 235 | split14 | test.py:235:16:235:19 | True | 1 | +| 236 | split14 | test.py:236:8:236:15 | UnaryExpr | 2 | +| 236 | split14 | test.py:236:12:236:15 | flag | 2 | +| 238 | split14 | test.py:238:9:238:12 | Pass | 1 | +| 240 | split15 | test.py:240:13:240:15 | var | 1 | +| 241 | split15 | test.py:241:8:241:10 | var | 1 | +| 242 | split15 | test.py:242:9:242:13 | other | 1 | +| 242 | split15 | test.py:242:17:242:17 | IntegerLiteral | 1 | +| 243 | split15 | test.py:243:8:243:14 | UnaryExpr | 2 | +| 243 | split15 | test.py:243:8:243:28 | BoolExpr | 2 | +| 243 | split15 | test.py:243:12:243:14 | var | 2 | +| 243 | split15 | test.py:243:19:243:23 | other | 1 | +| 243 | split15 | test.py:243:19:243:28 | Attribute | 1 | +| 244 | split15 | test.py:244:9:244:12 | Pass | 2 | +| 247 | split16 | test.py:247:5:247:5 | x | 1 | +| 247 | split16 | test.py:247:9:247:12 | True | 1 | +| 248 | split16 | test.py:248:8:248:11 | cond | 1 | +| 249 | split16 | test.py:249:9:249:9 | x | 1 | +| 249 | split16 | test.py:249:13:249:16 | None | 1 | +| 250 | split16 | test.py:250:8:250:8 | x | 2 | +| 251 | split16 | test.py:251:9:251:11 | use | 1 | +| 251 | split16 | test.py:251:9:251:14 | use() | 1 | +| 251 | split16 | test.py:251:13:251:13 | x | 1 | +| 253 | dont_split_on_different_ssa | test.py:253:33:253:35 | var | 1 | +| 254 | dont_split_on_different_ssa | test.py:254:8:254:10 | var | 1 | +| 255 | dont_split_on_different_ssa | test.py:255:9:255:10 | a1 | 1 | +| 257 | dont_split_on_different_ssa | test.py:257:9:257:10 | a2 | 1 | +| 258 | dont_split_on_different_ssa | test.py:258:5:258:7 | var | 1 | +| 258 | dont_split_on_different_ssa | test.py:258:11:258:14 | func | 1 | +| 258 | dont_split_on_different_ssa | test.py:258:11:258:16 | func() | 1 | +| 259 | dont_split_on_different_ssa | test.py:259:8:259:10 | var | 1 | +| 259 | dont_split_on_different_ssa | test.py:259:8:259:22 | Compare | 1 | +| 259 | dont_split_on_different_ssa | test.py:259:19:259:22 | None | 1 | +| 260 | dont_split_on_different_ssa | test.py:260:9:260:10 | b1 | 1 | +| 262 | dont_split_on_different_ssa | test.py:262:9:262:10 | b2 | 1 | +| 264 | split17 | test.py:264:13:264:15 | var | 1 | +| 266 | split17 | test.py:266:8:266:10 | var | 1 | +| 267 | split17 | test.py:267:9:267:10 | a1 | 1 | +| 269 | split17 | test.py:269:9:269:10 | a2 | 1 | +| 270 | split17 | test.py:270:8:270:14 | UnaryExpr | 2 | +| 270 | split17 | test.py:270:12:270:14 | var | 2 | +| 271 | split17 | test.py:271:9:271:10 | b1 | 1 | +| 273 | split17 | test.py:273:9:273:10 | b2 | 1 | +| 274 | split17 | test.py:274:8:274:10 | var | 2 | +| 275 | split17 | test.py:275:9:275:10 | c1 | 1 | +| 277 | split17 | test.py:277:9:277:10 | c2 | 1 | +| 278 | split17 | test.py:278:8:278:10 | var | 2 | +| 279 | split17 | test.py:279:9:279:10 | d1 | 1 | +| 281 | split17 | test.py:281:9:281:10 | d2 | 1 | +| 282 | split17 | test.py:282:8:282:10 | var | 2 | +| 283 | split17 | test.py:283:9:283:10 | e1 | 1 | +| 285 | split17 | test.py:285:9:285:10 | e2 | 1 | +| 287 | split18 | test.py:287:13:287:15 | var | 1 | +| 289 | split18 | test.py:289:8:289:10 | var | 1 | +| 290 | split18 | test.py:290:9:290:10 | a1 | 1 | +| 292 | split18 | test.py:292:9:292:10 | a2 | 1 | +| 293 | split18 | test.py:293:8:293:10 | var | 2 | +| 293 | split18 | test.py:293:8:293:22 | Compare | 2 | +| 293 | split18 | test.py:293:19:293:22 | None | 2 | +| 294 | split18 | test.py:294:9:294:10 | b1 | 2 | +| 296 | split18 | test.py:296:9:296:10 | b2 | 1 | +| 297 | split18 | test.py:297:8:297:10 | var | 3 | +| 297 | split18 | test.py:297:8:297:18 | Compare | 3 | +| 297 | split18 | test.py:297:15:297:18 | None | 3 | +| 298 | split18 | test.py:298:9:298:10 | c1 | 1 | +| 300 | split18 | test.py:300:9:300:10 | c2 | 2 | +| 301 | split18 | test.py:301:8:301:10 | var | 3 | +| 302 | split18 | test.py:302:9:302:10 | d1 | 1 | +| 304 | split18 | test.py:304:9:304:10 | d2 | 2 | +| 305 | split18 | test.py:305:8:305:10 | var | 3 | +| 306 | split18 | test.py:306:9:306:10 | e1 | 1 | +| 308 | split18 | test.py:308:9:308:10 | e2 | 2 | +| 310 | split_on_boolean_only | test.py:310:27:310:27 | x | 1 | +| 311 | split_on_boolean_only | test.py:311:8:311:8 | x | 1 | +| 312 | split_on_boolean_only | test.py:312:9:312:10 | a1 | 1 | +| 314 | split_on_boolean_only | test.py:314:9:314:10 | a2 | 1 | +| 315 | split_on_boolean_only | test.py:315:8:315:8 | x | 2 | +| 315 | split_on_boolean_only | test.py:315:8:315:20 | Compare | 2 | +| 315 | split_on_boolean_only | test.py:315:17:315:20 | None | 2 | +| 316 | split_on_boolean_only | test.py:316:9:316:10 | b1 | 2 | +| 318 | split_on_boolean_only | test.py:318:9:318:10 | b2 | 1 | +| 319 | split_on_boolean_only | test.py:319:8:319:8 | x | 3 | +| 320 | split_on_boolean_only | test.py:320:9:320:10 | c1 | 1 | +| 322 | split_on_boolean_only | test.py:322:9:322:10 | c2 | 2 | +| 324 | split_on_none_aswell | test.py:324:26:324:26 | x | 1 | +| 325 | split_on_none_aswell | test.py:325:8:325:8 | x | 1 | +| 326 | split_on_none_aswell | test.py:326:9:326:10 | a1 | 1 | +| 328 | split_on_none_aswell | test.py:328:9:328:10 | a2 | 1 | +| 329 | split_on_none_aswell | test.py:329:8:329:8 | x | 2 | +| 329 | split_on_none_aswell | test.py:329:8:329:20 | Compare | 2 | +| 329 | split_on_none_aswell | test.py:329:17:329:20 | None | 2 | +| 330 | split_on_none_aswell | test.py:330:9:330:10 | b1 | 2 | +| 332 | split_on_none_aswell | test.py:332:9:332:10 | b2 | 1 | +| 333 | split_on_none_aswell | test.py:333:8:333:8 | x | 3 | +| 333 | split_on_none_aswell | test.py:333:8:333:16 | Compare | 3 | +| 333 | split_on_none_aswell | test.py:333:13:333:16 | None | 3 | +| 334 | split_on_none_aswell | test.py:334:9:334:10 | c1 | 1 | +| 336 | split_on_none_aswell | test.py:336:9:336:10 | c2 | 2 | +| 338 | split_on_or_defn | test.py:338:22:338:24 | var | 1 | +| 339 | split_on_or_defn | test.py:339:8:339:10 | var | 1 | +| 340 | split_on_or_defn | test.py:340:9:340:11 | obj | 1 | +| 340 | split_on_or_defn | test.py:340:15:340:19 | thing | 1 | +| 340 | split_on_or_defn | test.py:340:15:340:21 | thing() | 1 | +| 341 | split_on_or_defn | test.py:341:8:341:14 | UnaryExpr | 2 | +| 341 | split_on_or_defn | test.py:341:8:341:26 | BoolExpr | 2 | +| 341 | split_on_or_defn | test.py:341:12:341:14 | var | 2 | +| 341 | split_on_or_defn | test.py:341:19:341:21 | obj | 1 | +| 341 | split_on_or_defn | test.py:341:19:341:26 | Attribute | 1 | +| 342 | split_on_or_defn | test.py:342:9:342:9 | x | 2 | +| 345 | split_on_exception | test.py:345:5:345:8 | flag | 1 | +| 345 | split_on_exception | test.py:345:12:345:16 | False | 1 | +| 346 | split_on_exception | test.py:346:5:346:8 | Try | 1 | +| 347 | split_on_exception | test.py:347:9:347:9 | x | 1 | +| 347 | split_on_exception | test.py:347:13:347:24 | do_something | 1 | +| 347 | split_on_exception | test.py:347:13:347:26 | do_something() | 1 | +| 348 | split_on_exception | test.py:348:5:348:21 | ExceptStmt | 1 | +| 348 | split_on_exception | test.py:348:12:348:20 | Exception | 1 | +| 349 | split_on_exception | test.py:349:9:349:12 | flag | 1 | +| 349 | split_on_exception | test.py:349:16:349:19 | True | 1 | +| 350 | split_on_exception | test.py:350:8:350:15 | UnaryExpr | 2 | +| 350 | split_on_exception | test.py:350:12:350:15 | flag | 2 | +| 351 | split_on_exception | test.py:351:9:351:9 | x | 1 | +| 353 | partially_useful_split | test.py:353:28:353:31 | cond | 1 | +| 354 | partially_useful_split | test.py:354:8:354:11 | cond | 1 | +| 355 | partially_useful_split | test.py:355:9:355:9 | x | 1 | +| 355 | partially_useful_split | test.py:355:13:355:16 | None | 1 | +| 357 | partially_useful_split | test.py:357:9:357:9 | x | 1 | +| 357 | partially_useful_split | test.py:357:13:357:29 | something_or_none | 1 | +| 357 | partially_useful_split | test.py:357:13:357:31 | something_or_none() | 1 | +| 358 | partially_useful_split | test.py:358:5:358:15 | other_stuff | 2 | +| 358 | partially_useful_split | test.py:358:5:358:17 | other_stuff() | 2 | +| 359 | partially_useful_split | test.py:359:8:359:8 | x | 2 | +| 360 | partially_useful_split | test.py:360:9:360:10 | a1 | 1 | +| 362 | partially_useful_split | test.py:362:9:362:10 | a2 | 2 | +| 364 | dont_split_not_useful | test.py:364:27:364:30 | cond | 1 | +| 364 | dont_split_not_useful | test.py:364:33:364:33 | y | 1 | +| 365 | dont_split_not_useful | test.py:365:8:365:11 | cond | 1 | +| 366 | dont_split_not_useful | test.py:366:9:366:9 | x | 1 | +| 366 | dont_split_not_useful | test.py:366:13:366:16 | None | 1 | +| 368 | dont_split_not_useful | test.py:368:9:368:9 | x | 1 | +| 368 | dont_split_not_useful | test.py:368:13:368:29 | something_or_none | 1 | +| 368 | dont_split_not_useful | test.py:368:13:368:31 | something_or_none() | 1 | +| 369 | dont_split_not_useful | test.py:369:5:369:15 | other_stuff | 1 | +| 369 | dont_split_not_useful | test.py:369:5:369:17 | other_stuff() | 1 | +| 370 | dont_split_not_useful | test.py:370:8:370:8 | y | 1 | +| 371 | dont_split_not_useful | test.py:371:9:371:10 | a1 | 1 | +| 373 | dont_split_not_useful | test.py:373:9:373:10 | a2 | 1 | +| 376 | f | test.py:376:7:376:7 | x | 1 | +| 376 | f | test.py:376:9:376:9 | y | 1 | +| 377 | f | test.py:377:8:377:8 | x | 1 | +| 377 | f | test.py:377:8:377:14 | BoolExpr | 1 | +| 377 | f | test.py:377:14:377:14 | y | 1 | +| 378 | f | test.py:378:9:378:13 | Raise | 1 | +| 379 | f | test.py:379:8:379:19 | UnaryExpr | 3 | +| 379 | f | test.py:379:13:379:13 | x | 2 | +| 379 | f | test.py:379:13:379:18 | BoolExpr | 2 | +| 379 | f | test.py:379:18:379:18 | y | 1 | +| 380 | f | test.py:380:9:380:13 | Raise | 1 | +| 381 | f | test.py:381:5:381:8 | Pass | 2 | +| 383 | g | test.py:383:7:383:7 | x | 1 | +| 383 | g | test.py:383:9:383:9 | y | 1 | +| 384 | g | test.py:384:8:384:8 | x | 1 | +| 384 | g | test.py:384:8:384:14 | BoolExpr | 1 | +| 384 | g | test.py:384:14:384:14 | y | 1 | +| 385 | g | test.py:385:9:385:13 | Raise | 1 | +| 386 | g | test.py:386:8:386:8 | x | 2 | +| 386 | g | test.py:386:8:386:13 | BoolExpr | 2 | +| 386 | g | test.py:386:13:386:13 | y | 1 | +| 388 | g | test.py:388:9:388:12 | here | 2 | +| 389 | g | test.py:389:5:389:7 | end | 2 | +| 391 | h | test.py:391:7:391:7 | x | 1 | +| 391 | h | test.py:391:10:391:10 | y | 1 | +| 393 | h | test.py:393:9:396:18 | BoolExpr | 1 | +| 393 | h | test.py:393:10:393:10 | x | 1 | +| 393 | h | test.py:393:10:394:14 | BoolExpr | 1 | +| 394 | h | test.py:394:10:394:14 | UnaryExpr | 1 | +| 394 | h | test.py:394:14:394:14 | y | 1 | +| 395 | h | test.py:395:10:395:10 | x | 2 | +| 395 | h | test.py:395:10:396:17 | BoolExpr | 2 | +| 396 | h | test.py:396:10:396:10 | y | 1 | +| 396 | h | test.py:396:10:396:15 | Attribute | 1 | +| 396 | h | test.py:396:10:396:17 | Attribute() | 1 | +| 398 | h | test.py:398:9:398:12 | Pass | 1 | +| 400 | j | test.py:400:7:400:7 | a | 1 | +| 400 | j | test.py:400:10:400:10 | b | 1 | +| 401 | j | test.py:401:8:401:8 | a | 1 | +| 401 | j | test.py:401:8:401:13 | BoolExpr | 1 | +| 401 | j | test.py:401:13:401:13 | b | 1 | +| 402 | j | test.py:402:12:402:12 | a | 2 | +| 403 | j | test.py:403:13:403:16 | here | 1 | +| 405 | j | test.py:405:13:405:17 | there | 1 | +| 408 | split_on_strings | test.py:408:5:408:8 | Try | 1 | +| 409 | split_on_strings | test.py:409:9:409:18 | might_fail | 1 | +| 409 | split_on_strings | test.py:409:9:409:20 | might_fail() | 1 | +| 410 | split_on_strings | test.py:410:9:410:9 | x | 1 | +| 410 | split_on_strings | test.py:410:13:410:18 | Str | 1 | +| 411 | split_on_strings | test.py:411:5:411:11 | ExceptStmt | 1 | +| 412 | split_on_strings | test.py:412:9:412:9 | x | 1 | +| 412 | split_on_strings | test.py:412:13:412:16 | Str | 1 | +| 414 | split_on_strings | test.py:414:8:414:8 | x | 2 | +| 414 | split_on_strings | test.py:414:8:414:16 | Compare | 2 | +| 414 | split_on_strings | test.py:414:13:414:16 | Str | 2 | +| 415 | split_on_strings | test.py:415:9:415:12 | Pass | 2 | +| 416 | split_on_strings | test.py:416:5:416:8 | Pass | 2 | +| 419 | scipy_stylee | test.py:419:18:419:18 | x | 1 | +| 420 | scipy_stylee | test.py:420:5:420:31 | Assert | 2 | +| 420 | scipy_stylee | test.py:420:12:420:12 | x | 1 | +| 420 | scipy_stylee | test.py:420:12:420:31 | Compare | 1 | +| 420 | scipy_stylee | test.py:420:18:420:20 | Str | 1 | +| 420 | scipy_stylee | test.py:420:18:420:30 | Tuple | 1 | +| 420 | scipy_stylee | test.py:420:23:420:25 | Str | 1 | +| 420 | scipy_stylee | test.py:420:28:420:30 | Str | 1 | +| 421 | scipy_stylee | test.py:421:8:421:8 | x | 1 | +| 421 | scipy_stylee | test.py:421:8:421:15 | Compare | 1 | +| 421 | scipy_stylee | test.py:421:13:421:15 | Str | 1 | +| 422 | scipy_stylee | test.py:422:9:422:12 | Pass | 1 | +| 423 | scipy_stylee | test.py:423:10:423:10 | x | 1 | +| 423 | scipy_stylee | test.py:423:10:423:17 | Compare | 1 | +| 423 | scipy_stylee | test.py:423:15:423:17 | Str | 1 | +| 424 | scipy_stylee | test.py:424:9:424:12 | Pass | 1 | +| 425 | scipy_stylee | test.py:425:10:425:10 | x | 1 | +| 425 | scipy_stylee | test.py:425:10:425:17 | Compare | 1 | +| 425 | scipy_stylee | test.py:425:15:425:17 | Str | 1 | +| 426 | scipy_stylee | test.py:426:9:426:12 | Pass | 1 | +| 429 | scipy_stylee | test.py:429:9:429:12 | Pass | 1 | +| 431 | odasa_6674 | test.py:431:16:431:16 | x | 1 | +| 432 | odasa_6674 | test.py:432:5:432:9 | valid | 1 | +| 432 | odasa_6674 | test.py:432:13:432:16 | True | 1 | +| 433 | odasa_6674 | test.py:433:8:433:27 | dont_understand_this | 1 | +| 433 | odasa_6674 | test.py:433:8:433:29 | dont_understand_this() | 1 | +| 434 | odasa_6674 | test.py:434:9:434:12 | Try | 1 | +| 435 | odasa_6674 | test.py:435:13:435:21 | may_raise | 1 | +| 435 | odasa_6674 | test.py:435:13:435:23 | may_raise() | 1 | +| 436 | odasa_6674 | test.py:436:13:436:17 | score | 1 | +| 436 | odasa_6674 | test.py:436:21:436:21 | IntegerLiteral | 1 | +| 437 | odasa_6674 | test.py:437:9:437:24 | ExceptStmt | 1 | +| 437 | odasa_6674 | test.py:437:16:437:23 | KeyError | 1 | +| 438 | odasa_6674 | test.py:438:13:438:17 | valid | 1 | +| 438 | odasa_6674 | test.py:438:21:438:25 | False | 1 | +| 439 | odasa_6674 | test.py:439:12:439:20 | UnaryExpr | 2 | +| 439 | odasa_6674 | test.py:439:16:439:20 | valid | 2 | +| 440 | odasa_6674 | test.py:440:13:440:30 | Raise | 1 | +| 440 | odasa_6674 | test.py:440:19:440:28 | ValueError | 1 | +| 440 | odasa_6674 | test.py:440:19:440:30 | ValueError() | 1 | +| 442 | odasa_6674 | test.py:442:9:442:13 | score | 1 | +| 442 | odasa_6674 | test.py:442:17:442:17 | IntegerLiteral | 1 | +| 443 | odasa_6674 | test.py:443:5:443:16 | Return | 1 | +| 443 | odasa_6674 | test.py:443:12:443:16 | score | 1 | +| 445 | odasa_6625 | test.py:445:16:445:16 | k | 1 | +| 446 | odasa_6625 | test.py:446:5:446:9 | value | 1 | +| 446 | odasa_6625 | test.py:446:13:446:16 | Str | 1 | +| 447 | odasa_6625 | test.py:447:8:447:8 | k | 1 | +| 447 | odasa_6625 | test.py:447:8:447:17 | Attribute | 1 | +| 447 | odasa_6625 | test.py:447:8:447:25 | Attribute() | 1 | +| 447 | odasa_6625 | test.py:447:8:447:47 | BoolExpr | 1 | +| 447 | odasa_6625 | test.py:447:19:447:24 | Str | 1 | +| 447 | odasa_6625 | test.py:447:30:447:30 | k | 1 | +| 447 | odasa_6625 | test.py:447:30:447:39 | Attribute | 1 | +| 447 | odasa_6625 | test.py:447:30:447:47 | Attribute() | 1 | +| 447 | odasa_6625 | test.py:447:41:447:46 | Str | 1 | +| 448 | odasa_6625 | test.py:448:9:448:13 | value | 1 | +| 448 | odasa_6625 | test.py:448:17:448:17 | IntegerLiteral | 1 | +| 449 | odasa_6625 | test.py:449:8:449:8 | k | 1 | +| 449 | odasa_6625 | test.py:449:8:449:18 | Compare | 1 | +| 449 | odasa_6625 | test.py:449:13:449:18 | Str | 1 | +| 450 | odasa_6625 | test.py:450:9:450:31 | Return | 1 | +| 450 | odasa_6625 | test.py:450:16:450:20 | value | 1 | +| 450 | odasa_6625 | test.py:450:16:450:31 | BinaryExpr | 1 | +| 450 | odasa_6625 | test.py:450:24:450:31 | Str | 1 | +| 453 | avoid_redundant_split | test.py:453:27:453:27 | a | 1 | +| 454 | avoid_redundant_split | test.py:454:8:454:8 | a | 1 | +| 455 | avoid_redundant_split | test.py:455:9:455:9 | x | 1 | +| 455 | avoid_redundant_split | test.py:455:13:455:25 | unknown_thing | 1 | +| 455 | avoid_redundant_split | test.py:455:13:455:27 | unknown_thing() | 1 | +| 457 | avoid_redundant_split | test.py:457:9:457:9 | x | 1 | +| 457 | avoid_redundant_split | test.py:457:13:457:16 | None | 1 | +| 458 | avoid_redundant_split | test.py:458:8:458:8 | x | 2 | +| 459 | avoid_redundant_split | test.py:459:9:459:12 | Pass | 1 | +| 460 | avoid_redundant_split | test.py:460:8:460:8 | x | 2 | +| 461 | avoid_redundant_split | test.py:461:9:461:12 | Pass | 1 | +| 462 | avoid_redundant_split | test.py:462:5:462:15 | other_stuff | 2 | +| 462 | avoid_redundant_split | test.py:462:5:462:17 | other_stuff() | 2 | +| 463 | avoid_redundant_split | test.py:463:5:463:8 | Try | 2 | +| 464 | avoid_redundant_split | test.py:464:16:464:18 | ImportExpr | 2 | +| 464 | avoid_redundant_split | test.py:464:16:464:18 | foo | 2 | +| 465 | avoid_redundant_split | test.py:465:9:465:11 | var | 2 | +| 465 | avoid_redundant_split | test.py:465:15:465:18 | True | 2 | +| 466 | avoid_redundant_split | test.py:466:5:466:11 | ExceptStmt | 2 | +| 467 | avoid_redundant_split | test.py:467:9:467:11 | var | 2 | +| 467 | avoid_redundant_split | test.py:467:15:467:19 | False | 2 | +| 468 | avoid_redundant_split | test.py:468:8:468:10 | var | 4 | +| 469 | avoid_redundant_split | test.py:469:9:469:11 | foo | 2 | +| 469 | avoid_redundant_split | test.py:469:9:469:15 | Attribute | 2 | +| 469 | avoid_redundant_split | test.py:469:9:469:17 | Attribute() | 2 | diff --git a/python/ql/test/library-tests/ControlFlow/splitting/NodeCount.ql b/python/ql/test/library-tests/ControlFlow/splitting/NodeCount.ql new file mode 100644 index 00000000000..d9d5efbb494 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/splitting/NodeCount.ql @@ -0,0 +1,8 @@ +import python + +from AstNode a, Scope s +where not a instanceof Import and not a instanceof If and not a instanceof AssignStmt and not a instanceof ExprStmt and +a.getScope() = s and +s instanceof Function +select +a.getLocation().getStartLine(), s.getName(), a, count(a.getAFlowNode()) diff --git a/python/ql/test/library-tests/ControlFlow/splitting/SuccessorCount.expected b/python/ql/test/library-tests/ControlFlow/splitting/SuccessorCount.expected new file mode 100644 index 00000000000..c65e6d1b64b --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/splitting/SuccessorCount.expected @@ -0,0 +1,181 @@ +| 3 | split1 | test.py:3:8:3:11 | ControlFlowNode for cond | 2 | +| 5 | split1 | test.py:5:8:5:11 | ControlFlowNode for cond | 1 | +| 5 | split1 | test.py:5:8:5:11 | ControlFlowNode for cond | 1 | +| 9 | dont_split1 | test.py:9:8:9:11 | ControlFlowNode for cond | 2 | +| 12 | dont_split1 | test.py:12:8:12:11 | ControlFlowNode for cond | 2 | +| 16 | dont_split2 | test.py:16:8:16:11 | ControlFlowNode for cond | 2 | +| 19 | dont_split2 | test.py:19:8:19:11 | ControlFlowNode for cond | 2 | +| 29 | split2 | test.py:29:8:29:8 | ControlFlowNode for x | 1 | +| 29 | split2 | test.py:29:8:29:8 | ControlFlowNode for x | 1 | +| 38 | unclear_split3 | test.py:38:8:38:11 | ControlFlowNode for cond | 2 | +| 40 | unclear_split3 | test.py:40:8:40:8 | ControlFlowNode for x | 1 | +| 40 | unclear_split3 | test.py:40:8:40:8 | ControlFlowNode for x | 2 | +| 44 | split4 | test.py:44:8:44:16 | ControlFlowNode for Compare | 2 | +| 46 | split4 | test.py:46:10:46:10 | ControlFlowNode for b | 2 | +| 50 | split_carefully_5 | test.py:50:8:50:16 | ControlFlowNode for Compare | 2 | +| 52 | split_carefully_5 | test.py:52:8:52:8 | ControlFlowNode for x | 2 | +| 58 | dont_split_globals | test.py:58:8:58:11 | ControlFlowNode for cond | 2 | +| 61 | dont_split_globals | test.py:61:8:61:11 | ControlFlowNode for cond | 2 | +| 61 | dont_split_globals | test.py:61:8:61:11 | ControlFlowNode for cond | 2 | +| 65 | limit_splitting1 | test.py:65:8:65:16 | ControlFlowNode for Compare | 2 | +| 66 | limit_splitting1 | test.py:66:8:66:16 | ControlFlowNode for Compare | 2 | +| 67 | limit_splitting1 | test.py:67:8:67:16 | ControlFlowNode for Compare | 2 | +| 68 | limit_splitting1 | test.py:68:8:68:16 | ControlFlowNode for Compare | 2 | +| 78 | limit_splitting2 | test.py:78:8:78:8 | ControlFlowNode for a | 2 | +| 80 | limit_splitting2 | test.py:80:8:80:8 | ControlFlowNode for b | 2 | +| 80 | limit_splitting2 | test.py:80:8:80:8 | ControlFlowNode for b | 2 | +| 82 | limit_splitting2 | test.py:82:8:82:8 | ControlFlowNode for c | 2 | +| 82 | limit_splitting2 | test.py:82:8:82:8 | ControlFlowNode for c | 2 | +| 82 | limit_splitting2 | test.py:82:8:82:8 | ControlFlowNode for c | 2 | +| 82 | limit_splitting2 | test.py:82:8:82:8 | ControlFlowNode for c | 2 | +| 84 | limit_splitting2 | test.py:84:8:84:8 | ControlFlowNode for d | 2 | +| 84 | limit_splitting2 | test.py:84:8:84:8 | ControlFlowNode for d | 2 | +| 84 | limit_splitting2 | test.py:84:8:84:8 | ControlFlowNode for d | 2 | +| 84 | limit_splitting2 | test.py:84:8:84:8 | ControlFlowNode for d | 2 | +| 87 | limit_splitting2 | test.py:87:8:87:8 | ControlFlowNode for a | 1 | +| 87 | limit_splitting2 | test.py:87:8:87:8 | ControlFlowNode for a | 1 | +| 87 | limit_splitting2 | test.py:87:8:87:8 | ControlFlowNode for a | 1 | +| 87 | limit_splitting2 | test.py:87:8:87:8 | ControlFlowNode for a | 1 | +| 89 | limit_splitting2 | test.py:89:8:89:8 | ControlFlowNode for b | 1 | +| 89 | limit_splitting2 | test.py:89:8:89:8 | ControlFlowNode for b | 1 | +| 89 | limit_splitting2 | test.py:89:8:89:8 | ControlFlowNode for b | 1 | +| 89 | limit_splitting2 | test.py:89:8:89:8 | ControlFlowNode for b | 1 | +| 92 | limit_splitting2 | test.py:92:8:92:8 | ControlFlowNode for c | 2 | +| 92 | limit_splitting2 | test.py:92:8:92:8 | ControlFlowNode for c | 2 | +| 92 | limit_splitting2 | test.py:92:8:92:8 | ControlFlowNode for c | 2 | +| 92 | limit_splitting2 | test.py:92:8:92:8 | ControlFlowNode for c | 2 | +| 94 | limit_splitting2 | test.py:94:8:94:8 | ControlFlowNode for d | 2 | +| 94 | limit_splitting2 | test.py:94:8:94:8 | ControlFlowNode for d | 2 | +| 94 | limit_splitting2 | test.py:94:8:94:8 | ControlFlowNode for d | 2 | +| 94 | limit_splitting2 | test.py:94:8:94:8 | ControlFlowNode for d | 2 | +| 103 | split_on_numbers | test.py:103:8:103:8 | ControlFlowNode for x | 1 | +| 103 | split_on_numbers | test.py:103:8:103:8 | ControlFlowNode for x | 1 | +| 113 | split_try_except_else | test.py:113:8:113:8 | ControlFlowNode for x | 1 | +| 113 | split_try_except_else | test.py:113:8:113:8 | ControlFlowNode for x | 1 | +| 126 | logging | test.py:126:8:126:14 | ControlFlowNode for module1 | 1 | +| 126 | logging | test.py:126:8:126:14 | ControlFlowNode for module1 | 1 | +| 136 | split5 | test.py:136:8:136:12 | ControlFlowNode for UnaryExpr | 1 | +| 136 | split5 | test.py:136:8:136:12 | ControlFlowNode for UnaryExpr | 1 | +| 145 | split6 | test.py:145:8:145:16 | ControlFlowNode for UnaryExpr | 1 | +| 145 | split6 | test.py:145:8:145:16 | ControlFlowNode for UnaryExpr | 1 | +| 154 | split7 | test.py:154:8:154:8 | ControlFlowNode for x | 1 | +| 154 | split7 | test.py:154:8:154:8 | ControlFlowNode for x | 1 | +| 158 | split8 | test.py:158:8:158:11 | ControlFlowNode for cond | 2 | +| 162 | split8 | test.py:162:8:162:15 | ControlFlowNode for UnaryExpr | 1 | +| 162 | split8 | test.py:162:8:162:15 | ControlFlowNode for UnaryExpr | 1 | +| 163 | split8 | test.py:163:12:163:12 | ControlFlowNode for t | 1 | +| 168 | split9 | test.py:168:8:168:18 | ControlFlowNode for Compare | 2 | +| 172 | split9 | test.py:172:8:172:22 | ControlFlowNode for Compare | 1 | +| 172 | split9 | test.py:172:8:172:22 | ControlFlowNode for Compare | 1 | +| 178 | split10 | test.py:178:8:178:10 | ControlFlowNode for var | 2 | +| 182 | split10 | test.py:182:8:182:22 | ControlFlowNode for Compare | 1 | +| 182 | split10 | test.py:182:8:182:22 | ControlFlowNode for Compare | 2 | +| 188 | split11 | test.py:188:8:188:18 | ControlFlowNode for Compare | 2 | +| 192 | split11 | test.py:192:8:192:10 | ControlFlowNode for var | 1 | +| 192 | split11 | test.py:192:8:192:10 | ControlFlowNode for var | 2 | +| 198 | dont_split_on_unrelated_variables | test.py:198:8:198:19 | ControlFlowNode for Compare | 2 | +| 202 | dont_split_on_unrelated_variables | test.py:202:8:202:23 | ControlFlowNode for Compare | 2 | +| 213 | split12 | test.py:213:8:213:8 | ControlFlowNode for x | 1 | +| 213 | split12 | test.py:213:8:213:8 | ControlFlowNode for x | 1 | +| 218 | split13 | test.py:218:8:218:10 | ControlFlowNode for var | 2 | +| 225 | split13 | test.py:225:12:225:14 | ControlFlowNode for var | 1 | +| 225 | split13 | test.py:225:12:225:14 | ControlFlowNode for var | 1 | +| 225 | split13 | test.py:225:12:225:14 | ControlFlowNode for var | 1 | +| 236 | split14 | test.py:236:8:236:15 | ControlFlowNode for UnaryExpr | 1 | +| 236 | split14 | test.py:236:8:236:15 | ControlFlowNode for UnaryExpr | 1 | +| 241 | split15 | test.py:241:8:241:10 | ControlFlowNode for var | 2 | +| 243 | split15 | test.py:243:8:243:14 | ControlFlowNode for UnaryExpr | 1 | +| 243 | split15 | test.py:243:8:243:14 | ControlFlowNode for UnaryExpr | 1 | +| 243 | split15 | test.py:243:19:243:28 | ControlFlowNode for Attribute | 2 | +| 248 | split16 | test.py:248:8:248:11 | ControlFlowNode for cond | 2 | +| 250 | split16 | test.py:250:8:250:8 | ControlFlowNode for x | 1 | +| 250 | split16 | test.py:250:8:250:8 | ControlFlowNode for x | 1 | +| 254 | dont_split_on_different_ssa | test.py:254:8:254:10 | ControlFlowNode for var | 2 | +| 259 | dont_split_on_different_ssa | test.py:259:8:259:22 | ControlFlowNode for Compare | 2 | +| 266 | split17 | test.py:266:8:266:10 | ControlFlowNode for var | 2 | +| 270 | split17 | test.py:270:8:270:14 | ControlFlowNode for UnaryExpr | 1 | +| 270 | split17 | test.py:270:8:270:14 | ControlFlowNode for UnaryExpr | 1 | +| 274 | split17 | test.py:274:8:274:10 | ControlFlowNode for var | 1 | +| 274 | split17 | test.py:274:8:274:10 | ControlFlowNode for var | 1 | +| 278 | split17 | test.py:278:8:278:10 | ControlFlowNode for var | 1 | +| 278 | split17 | test.py:278:8:278:10 | ControlFlowNode for var | 1 | +| 282 | split17 | test.py:282:8:282:10 | ControlFlowNode for var | 1 | +| 282 | split17 | test.py:282:8:282:10 | ControlFlowNode for var | 1 | +| 289 | split18 | test.py:289:8:289:10 | ControlFlowNode for var | 2 | +| 293 | split18 | test.py:293:8:293:22 | ControlFlowNode for Compare | 1 | +| 293 | split18 | test.py:293:8:293:22 | ControlFlowNode for Compare | 2 | +| 297 | split18 | test.py:297:8:297:18 | ControlFlowNode for Compare | 1 | +| 297 | split18 | test.py:297:8:297:18 | ControlFlowNode for Compare | 1 | +| 297 | split18 | test.py:297:8:297:18 | ControlFlowNode for Compare | 1 | +| 301 | split18 | test.py:301:8:301:10 | ControlFlowNode for var | 1 | +| 301 | split18 | test.py:301:8:301:10 | ControlFlowNode for var | 1 | +| 301 | split18 | test.py:301:8:301:10 | ControlFlowNode for var | 1 | +| 305 | split18 | test.py:305:8:305:10 | ControlFlowNode for var | 1 | +| 305 | split18 | test.py:305:8:305:10 | ControlFlowNode for var | 1 | +| 305 | split18 | test.py:305:8:305:10 | ControlFlowNode for var | 1 | +| 311 | split_on_boolean_only | test.py:311:8:311:8 | ControlFlowNode for x | 2 | +| 315 | split_on_boolean_only | test.py:315:8:315:20 | ControlFlowNode for Compare | 1 | +| 315 | split_on_boolean_only | test.py:315:8:315:20 | ControlFlowNode for Compare | 2 | +| 319 | split_on_boolean_only | test.py:319:8:319:8 | ControlFlowNode for x | 1 | +| 319 | split_on_boolean_only | test.py:319:8:319:8 | ControlFlowNode for x | 1 | +| 319 | split_on_boolean_only | test.py:319:8:319:8 | ControlFlowNode for x | 1 | +| 325 | split_on_none_aswell | test.py:325:8:325:8 | ControlFlowNode for x | 2 | +| 329 | split_on_none_aswell | test.py:329:8:329:20 | ControlFlowNode for Compare | 1 | +| 329 | split_on_none_aswell | test.py:329:8:329:20 | ControlFlowNode for Compare | 2 | +| 333 | split_on_none_aswell | test.py:333:8:333:16 | ControlFlowNode for Compare | 1 | +| 333 | split_on_none_aswell | test.py:333:8:333:16 | ControlFlowNode for Compare | 1 | +| 333 | split_on_none_aswell | test.py:333:8:333:16 | ControlFlowNode for Compare | 1 | +| 339 | split_on_or_defn | test.py:339:8:339:10 | ControlFlowNode for var | 2 | +| 341 | split_on_or_defn | test.py:341:8:341:14 | ControlFlowNode for UnaryExpr | 1 | +| 341 | split_on_or_defn | test.py:341:8:341:14 | ControlFlowNode for UnaryExpr | 1 | +| 341 | split_on_or_defn | test.py:341:19:341:26 | ControlFlowNode for Attribute | 2 | +| 350 | split_on_exception | test.py:350:8:350:15 | ControlFlowNode for UnaryExpr | 1 | +| 350 | split_on_exception | test.py:350:8:350:15 | ControlFlowNode for UnaryExpr | 1 | +| 354 | partially_useful_split | test.py:354:8:354:11 | ControlFlowNode for cond | 2 | +| 359 | partially_useful_split | test.py:359:8:359:8 | ControlFlowNode for x | 1 | +| 359 | partially_useful_split | test.py:359:8:359:8 | ControlFlowNode for x | 2 | +| 365 | dont_split_not_useful | test.py:365:8:365:11 | ControlFlowNode for cond | 2 | +| 370 | dont_split_not_useful | test.py:370:8:370:8 | ControlFlowNode for y | 2 | +| 377 | f | test.py:377:8:377:8 | ControlFlowNode for x | 2 | +| 377 | f | test.py:377:14:377:14 | ControlFlowNode for y | 2 | +| 379 | f | test.py:379:8:379:19 | ControlFlowNode for UnaryExpr | 1 | +| 379 | f | test.py:379:8:379:19 | ControlFlowNode for UnaryExpr | 1 | +| 379 | f | test.py:379:8:379:19 | ControlFlowNode for UnaryExpr | 1 | +| 379 | f | test.py:379:13:379:13 | ControlFlowNode for x | 1 | +| 379 | f | test.py:379:13:379:13 | ControlFlowNode for x | 1 | +| 379 | f | test.py:379:18:379:18 | ControlFlowNode for y | 2 | +| 384 | g | test.py:384:8:384:8 | ControlFlowNode for x | 2 | +| 384 | g | test.py:384:14:384:14 | ControlFlowNode for y | 2 | +| 386 | g | test.py:386:8:386:8 | ControlFlowNode for x | 1 | +| 386 | g | test.py:386:8:386:8 | ControlFlowNode for x | 1 | +| 386 | g | test.py:386:13:386:13 | ControlFlowNode for y | 2 | +| 393 | h | test.py:393:10:393:10 | ControlFlowNode for x | 2 | +| 394 | h | test.py:394:10:394:14 | ControlFlowNode for UnaryExpr | 2 | +| 395 | h | test.py:395:10:395:10 | ControlFlowNode for x | 1 | +| 395 | h | test.py:395:10:395:10 | ControlFlowNode for x | 1 | +| 396 | h | test.py:396:10:396:17 | ControlFlowNode for Attribute() | 2 | +| 401 | j | test.py:401:8:401:8 | ControlFlowNode for a | 2 | +| 401 | j | test.py:401:13:401:13 | ControlFlowNode for b | 2 | +| 402 | j | test.py:402:12:402:12 | ControlFlowNode for a | 1 | +| 402 | j | test.py:402:12:402:12 | ControlFlowNode for a | 1 | +| 414 | split_on_strings | test.py:414:8:414:16 | ControlFlowNode for Compare | 2 | +| 414 | split_on_strings | test.py:414:8:414:16 | ControlFlowNode for Compare | 2 | +| 420 | scipy_stylee | test.py:420:12:420:31 | ControlFlowNode for Compare | 2 | +| 421 | scipy_stylee | test.py:421:8:421:15 | ControlFlowNode for Compare | 2 | +| 423 | scipy_stylee | test.py:423:10:423:17 | ControlFlowNode for Compare | 2 | +| 425 | scipy_stylee | test.py:425:10:425:17 | ControlFlowNode for Compare | 2 | +| 433 | odasa_6674 | test.py:433:8:433:29 | ControlFlowNode for dont_understand_this() | 2 | +| 439 | odasa_6674 | test.py:439:12:439:20 | ControlFlowNode for UnaryExpr | 1 | +| 439 | odasa_6674 | test.py:439:12:439:20 | ControlFlowNode for UnaryExpr | 1 | +| 447 | odasa_6625 | test.py:447:8:447:25 | ControlFlowNode for Attribute() | 2 | +| 447 | odasa_6625 | test.py:447:30:447:47 | ControlFlowNode for Attribute() | 2 | +| 449 | odasa_6625 | test.py:449:8:449:18 | ControlFlowNode for Compare | 2 | +| 454 | avoid_redundant_split | test.py:454:8:454:8 | ControlFlowNode for a | 2 | +| 458 | avoid_redundant_split | test.py:458:8:458:8 | ControlFlowNode for x | 1 | +| 458 | avoid_redundant_split | test.py:458:8:458:8 | ControlFlowNode for x | 2 | +| 460 | avoid_redundant_split | test.py:460:8:460:8 | ControlFlowNode for x | 1 | +| 460 | avoid_redundant_split | test.py:460:8:460:8 | ControlFlowNode for x | 2 | +| 468 | avoid_redundant_split | test.py:468:8:468:10 | ControlFlowNode for var | 1 | +| 468 | avoid_redundant_split | test.py:468:8:468:10 | ControlFlowNode for var | 1 | +| 468 | avoid_redundant_split | test.py:468:8:468:10 | ControlFlowNode for var | 1 | +| 468 | avoid_redundant_split | test.py:468:8:468:10 | ControlFlowNode for var | 1 | diff --git a/python/ql/test/library-tests/ControlFlow/splitting/SuccessorCount.ql b/python/ql/test/library-tests/ControlFlow/splitting/SuccessorCount.ql new file mode 100644 index 00000000000..d865d9061c3 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/splitting/SuccessorCount.ql @@ -0,0 +1,9 @@ +import python + +from ControlFlowNode p, Scope s +where +p.getScope() = s and +(exists (p.getATrueSuccessor()) or exists(p.getAFalseSuccessor())) and +s instanceof Function +select +p.getLocation().getStartLine(), s.getName(), p, strictcount(p.getASuccessor()) diff --git a/python/ql/test/library-tests/ControlFlow/splitting/test.py b/python/ql/test/library-tests/ControlFlow/splitting/test.py new file mode 100644 index 00000000000..f01f83f4c5c --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/splitting/test.py @@ -0,0 +1,471 @@ + +def split1(cond): + if cond: + pass + if cond: + pass + +def dont_split1(cond): + if cond: + pass + cond = f() + if cond: + pass + +def dont_split2(cond): + if cond: + pass + for cond in seq: pass + if cond: + pass + + +def split2(): + try: + call() + x = True + except: + x = False + if x: + pass + +def unclear_split3(): + try: # May be arguably better to split here. + call() + x = True + except: + x = False + if cond: # Currently split here + x = False + if x: + pass + +def split4(x): + if x is None: + x = not_none() + c if b else c + return x + +def split_carefully_5(x): + if x is None: + x = not_none() + if x: + pass + return x + + +def dont_split_globals(): + if cond: + pass + call_could_alter_any_global() + if cond: + pass + +def limit_splitting1(a,b,c,d): + if a is None: a = "a" + if b is None: b = "b" + if c is None: c = "c" + if d is None: d = "d" + pass + + + + + + + +def limit_splitting2(a,b,c,d): + if a: + pass + if b: + pass + if c: + pass + if d: + pass + #These should be pruned + if a: + a1 + if b: + b1 + #But not these + if c: + c1 + if d: + d1 + +def split_on_numbers(): + try: + call() + x = -1 + except: + x = 0 + if x: + pass + +def split_try_except_else(): + try: + call() + except: + x = 0 + else: + x = 1 + if x: + pass + +#Example taken from logging module +#Splitting should allow us to deduce that module2 is defined at point of use +def logging(): + try: + import module1 + import module2 + + except ImportError: + module1 = None + + if module1: + inst = module2.Class() + +#Handle 'not' as well. +def split5(): + try: + call() + x = True + except: + x = False + if not x: + pass + +def split6(): + try: + call() + x = True + except: + x = False + if not not x: + pass + +def split7(): + try: + call() + x = not True + except: + x = not False + if x: + pass + +def split8(cond): + if cond: + t = True + else: + t = False + if not cond: + if t: + pass + + +def split9(var): + if var is None: + a1 + else: + a2 + if var is not None: + b1 + else: + b2 + +def split10(var): + if var: + a1 + else: + a2 + if var is not None: + b1 + else: + b2 + +def split11(var): + if var is None: + a1 + else: + a2 + if var: + b1 + else: + b2 + +def dont_split_on_unrelated_variables(var1, var2): + if var1 is None: + a1 + else: + a2 + if var2 is not None: + b1 + else: + b2 + +def split12(): + try: + call() + x = None + except: + import x + if x: + pass + +def split13(): + var = cond() + if var: + a1 + else: + a2 + try: + b1 + finally: + if var: + a3 + + +def split14(): + flag = False + try: + x = something() + except Exception: + 99 + flag = True + if not flag: + #Should be split here + pass + +def split15(var): + if var: + other = 0 + if not var or other.attr: #other looks like it might be undefined, but it is defined. + pass + +def split16(): + x = True + if cond: + x = None + if x: + use(x) + +def dont_split_on_different_ssa(var): + if var: + a1 + else: + a2 + var = func() + if var is not None: + b1 + else: + b2 + +def split17(var): + #Should only be split once + if var: + a1 + else: + a2 + if not var: + b1 + else: + b2 + if var: + c1 + else: + c2 + if var: + d1 + else: + d2 + if var: + e1 + else: + e2 + +def split18(var): + #Should only be split once + if var: + a1 + else: + a2 + if var is not None: #Distinguishes between False and None + b1 + else: + b2 + if var is None: + c1 + else: + c2 + if var: + d1 + else: + d2 + if var: + e1 + else: + e2 + +def split_on_boolean_only(x): + if x: + a1 + else: + a2 + if x is not None: + b1 + else: + b2 + if x: + c1 + else: + c2 + +def split_on_none_aswell(x): + if x: + a1 + else: + a2 + if x is not None: + b1 + else: + b2 + if x is None: + c1 + else: + c2 + +def split_on_or_defn(var): + if var: + obj = thing() + if not var or obj.attr: # obj is defined if reached + x + +def split_on_exception(): + flag = False + try: + x = do_something() + except Exception: + flag = True + if not flag: + x # x is defined here + +def partially_useful_split(cond): + if cond: + x = None + else: + x = something_or_none() + other_stuff() + if x: + a1 + else: + a2 + +def dont_split_not_useful(cond, y): + if cond: + x = None + else: + x = something_or_none() + other_stuff() + if y: + a1 + else: + a2 + +#Splittings with boolean expressions: +def f(x,y): + if x and y: + raise + if not (x or y): + raise + pass + +def g(x,y): + if x and y: + raise + if x or y: + # Either x or y is true here (exclusive). + here + end + +def h(x, y): + if ( + (x and + not y) or + (x and + y.meth()) + ): + pass + +def j(a, b): + if a or b: + if a: + here + else: + there + +def split_on_strings(): + try: + might_fail() + x = "yes+" + except: + x = "no" + #We want to split here, even though we can't (easily) prune + if x == "no": + pass + pass + + +def scipy_stylee(x): + assert x in ("a", "b", "c") + if x == "a": + pass + elif x == "b": + pass + elif x == "c": + pass + else: + #unreachable + pass + +def odasa_6674(x): + valid = True + if dont_understand_this(): + try: + may_raise() + score = 0 + except KeyError: + valid = False + if not valid: + raise ValueError() + else: + score = 1 + return score + +def odasa_6625(k): + value = "hi" + if k.endswith('_min') or k.endswith('_max'): + value = 0 + if k == 'tags': + return value + " there" + + +def avoid_redundant_split(a): + if a: # Should split here + x = unknown_thing() + else: + x = None + if x: # but not here, + pass + if x: # or here, because + pass + other_stuff() + try: # we want to split here + import foo + var = True + except: + var = False + if var: + foo.bar() + + diff --git a/python/ql/test/library-tests/ControlFlow/ssa/defns/test.expected b/python/ql/test/library-tests/ControlFlow/ssa/defns/test.expected new file mode 100644 index 00000000000..1860e4f280f --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/ssa/defns/test.expected @@ -0,0 +1,31 @@ +| test1.py | SSA Variable l0 | 6 | test1.py:6:5:6:6 | SSA Variable l0 | 6 | +| test1.py | SSA Variable l1 | 7 | test1.py:7:5:7:6 | SSA Variable l1 | 7 | +| test1.py | SSA Variable l2 | 8 | test1.py:8:5:8:6 | SSA Variable l2 | 8 | +| test1.py | SSA Variable no_phi | 5 | test1.py:5:5:5:10 | SSA Variable no_phi | 5 | +| test2.py | SSA Variable cond | 5 | test2.py:5:5:5:8 | SSA Variable cond | 5 | +| test2.py | SSA Variable l0 | 7 | test2.py:7:9:7:10 | SSA Variable l0 | 7 | +| test2.py | SSA Variable l0 | 9 | test2.py:9:9:9:10 | SSA Variable l0 | 9 | +| test2.py | SSA Variable l0 | 10 | test2.py:7:9:7:10 | SSA Variable l0 | 7 | +| test2.py | SSA Variable l0 | 10 | test2.py:9:9:9:10 | SSA Variable l0 | 9 | +| test2.py | SSA Variable with_phi | 4 | test2.py:4:5:4:12 | SSA Variable with_phi | 4 | +| test3.py | SSA Variable l0 | 9 | test3.py:9:13:9:14 | SSA Variable l0 | 9 | +| test3.py | SSA Variable l0 | 9 | test3.py:9:13:9:14 | SSA Variable l0 | 9 | +| test3.py | SSA Variable l0 | 11 | test3.py:9:13:9:14 | SSA Variable l0 | 9 | +| test3.py | SSA Variable l0 | 11 | test3.py:9:13:9:14 | SSA Variable l0 | 9 | +| test3.py | SSA Variable l0 | 13 | test3.py:9:13:9:14 | SSA Variable l0 | 9 | +| test3.py | SSA Variable l0 | 13 | test3.py:9:13:9:14 | SSA Variable l0 | 9 | +| test3.py | SSA Variable phi_in_try | 4 | test3.py:4:5:4:14 | SSA Variable phi_in_try | 4 | +| test4.py | SSA Variable del1 | 2 | test4.py:2:5:2:8 | SSA Variable del1 | 2 | +| test4.py | SSA Variable del2 | 8 | test4.py:8:5:8:8 | SSA Variable del2 | 8 | +| test4.py | SSA Variable x | 3 | test4.py:3:5:3:5 | SSA Variable x | 3 | +| test4.py | SSA Variable x | 5 | test4.py:5:5:5:5 | SSA Variable x | 5 | +| test4.py | SSA Variable x | 9 | test4.py:9:5:9:5 | SSA Variable x | 9 | +| test4.py | SSA Variable x | 11 | test4.py:11:13:11:13 | SSA Variable x | 11 | +| test4.py | SSA Variable x | 13 | test4.py:13:9:13:9 | SSA Variable x | 13 | +| test4.py | SSA Variable x | 14 | test4.py:11:13:11:13 | SSA Variable x | 11 | +| test4.py | SSA Variable x | 14 | test4.py:13:9:13:9 | SSA Variable x | 13 | +| test5.py | SSA Variable a | 0 | test5.py:4:9:4:9 | SSA Variable a | 4 | +| test5.py | SSA Variable a | 0 | test5.py:9:9:9:9 | SSA Variable a | 9 | +| test5.py | SSA Variable a | 4 | test5.py:4:9:4:9 | SSA Variable a | 4 | +| test5.py | SSA Variable a | 9 | test5.py:9:9:9:9 | SSA Variable a | 9 | +| test6.py | SSA Variable a | 4 | test6.py:4:9:4:9 | SSA Variable a | 4 | diff --git a/python/ql/test/library-tests/ControlFlow/ssa/defns/test.ql b/python/ql/test/library-tests/ControlFlow/ssa/defns/test.ql new file mode 100644 index 00000000000..c8ce2855455 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/ssa/defns/test.ql @@ -0,0 +1,6 @@ +import python + +from SsaVariable var, SsaVariable def +where def = var.getAnUltimateDefinition() +select var.getLocation().getFile().getShortName(), +var.toString(), var.getLocation().getStartLine(), def, def.getLocation().getStartLine() diff --git a/python/ql/test/library-tests/ControlFlow/ssa/defns/test1.py b/python/ql/test/library-tests/ControlFlow/ssa/defns/test1.py new file mode 100644 index 00000000000..d6fe26089b0 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/ssa/defns/test1.py @@ -0,0 +1,10 @@ +#Weird formatting is so that all uses and defn are on separate lines +#to assist checking test results. + + +def no_phi(cond): + l0 = 0 + l1 = 1 + l2 = l0 + l1 + return l2 + diff --git a/python/ql/test/library-tests/ControlFlow/ssa/defns/test2.py b/python/ql/test/library-tests/ControlFlow/ssa/defns/test2.py new file mode 100644 index 00000000000..d02c4c370bb --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/ssa/defns/test2.py @@ -0,0 +1,11 @@ +#Weird formatting is so that all uses and defn are on separate lines +#to assist checking test results. + +def with_phi( + cond): + if cond: + l0 = 0 + else: + l0 = 1 + return l0 + diff --git a/python/ql/test/library-tests/ControlFlow/ssa/defns/test3.py b/python/ql/test/library-tests/ControlFlow/ssa/defns/test3.py new file mode 100644 index 00000000000..ce2d9ac920e --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/ssa/defns/test3.py @@ -0,0 +1,14 @@ +#Weird formatting is so that all uses and defn are on separate lines +#to assist checking test results. + +def phi_in_try(): + try: + try: + a_call() + finally: + l0 = 0 + another_call() + except: + pass + return l0 + diff --git a/python/ql/test/library-tests/ControlFlow/ssa/defns/test4.py b/python/ql/test/library-tests/ControlFlow/ssa/defns/test4.py new file mode 100644 index 00000000000..1f4426514a2 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/ssa/defns/test4.py @@ -0,0 +1,15 @@ + +def del1(): + x = 0 + del x + x = 0 + return x + +def del2(): + x = 0 + if random(): + del x + else: + x = 1 + return x + diff --git a/python/ql/test/library-tests/ControlFlow/ssa/defns/test5.py b/python/ql/test/library-tests/ControlFlow/ssa/defns/test5.py new file mode 100644 index 00000000000..8f900254ec6 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/ssa/defns/test5.py @@ -0,0 +1,11 @@ + +if x: + + def a(): + pass + +else: + + def a(): + pass + diff --git a/python/ql/test/library-tests/ControlFlow/ssa/defns/test6.py b/python/ql/test/library-tests/ControlFlow/ssa/defns/test6.py new file mode 100644 index 00000000000..d148a5c745b --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/ssa/defns/test6.py @@ -0,0 +1,6 @@ + +if x: + + def a(): + pass + del a diff --git a/python/ql/test/library-tests/ControlFlow/ssa/deletions/test.expected b/python/ql/test/library-tests/ControlFlow/ssa/deletions/test.expected new file mode 100644 index 00000000000..a80d1fe8beb --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/ssa/deletions/test.expected @@ -0,0 +1,6 @@ +| 5 | ControlFlowNode for cond | cond | other | +| 7 | ControlFlowNode for u2 | u2 | delete | +| 10 | ControlFlowNode for u3 | u3 | delete | +| 10 | ControlFlowNode for use | use | other | +| 18 | ControlFlowNode for u2 | u2 | delete | +| 21 | ControlFlowNode for u3 | u3 | delete | \ No newline at end of file diff --git a/python/ql/test/library-tests/ControlFlow/ssa/deletions/test.py b/python/ql/test/library-tests/ControlFlow/ssa/deletions/test.py new file mode 100644 index 00000000000..16f19232643 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/ssa/deletions/test.py @@ -0,0 +1,21 @@ +from mod import cond + +del u1 + +if cond: + u2 = 0 +del u2 + +del u3 +use(u3) + + +def f(): + del u1 + + if cond: + u2 = 0 + del u2 + + del u3 + use(u3) \ No newline at end of file diff --git a/python/ql/test/library-tests/ControlFlow/ssa/deletions/test.ql b/python/ql/test/library-tests/ControlFlow/ssa/deletions/test.ql new file mode 100644 index 00000000000..b220553d07b --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/ssa/deletions/test.ql @@ -0,0 +1,14 @@ +import python + + +from SsaVariable v, string kind, ControlFlowNode use, int line +where use = v.getAUse() and +( + kind = "delete" and v.getDefinition().isDelete() + or + kind = "other " and not v.getDefinition().isDelete() +) +and line = use.getLocation().getStartLine() +and line != 0 + +select line, use.toString(), v.getId(), kind diff --git a/python/ql/test/library-tests/ControlFlow/ssa/phi-nodes/phi_input_test.expected b/python/ql/test/library-tests/ControlFlow/ssa/phi-nodes/phi_input_test.expected new file mode 100644 index 00000000000..ffdf9771e91 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/ssa/phi-nodes/phi_input_test.expected @@ -0,0 +1,12 @@ +| test2.py | SSA Variable l0 | 10 | test2.py:7:9:7:10 | SSA Variable l0 | 7 | 7 | +| test2.py | SSA Variable l0 | 10 | test2.py:9:9:9:10 | SSA Variable l0 | 9 | 9 | +| test2.py | SSA Variable l1 | 19 | test2.py:14:5:14:6 | SSA Variable l1 | 14 | 16 | +| test2.py | SSA Variable l1 | 19 | test2.py:18:9:18:10 | SSA Variable l1 | 18 | 18 | +| test3.py | SSA Variable l0 | 11 | test3.py:9:13:9:14 | SSA Variable l0 | 9 | 10 | +| test3.py | SSA Variable l0 | 11 | test3.py:9:13:9:14 | SSA Variable l0 | 9 | 10 | +| test3.py | SSA Variable l0 | 13 | test3.py:9:13:9:14 | SSA Variable l0 | 9 | 10 | +| test3.py | SSA Variable l0 | 13 | test3.py:11:5:11:11 | SSA Variable l0 | 11 | 12 | +| test4.py | SSA Variable x | 14 | test4.py:11:13:11:13 | SSA Variable x | 11 | 11 | +| test4.py | SSA Variable x | 14 | test4.py:13:9:13:9 | SSA Variable x | 13 | 13 | +| test5.py | SSA Variable a | 0 | test5.py:4:9:4:9 | SSA Variable a | 4 | 4 | +| test5.py | SSA Variable a | 0 | test5.py:9:9:9:9 | SSA Variable a | 9 | 9 | diff --git a/python/ql/test/library-tests/ControlFlow/ssa/phi-nodes/phi_input_test.ql b/python/ql/test/library-tests/ControlFlow/ssa/phi-nodes/phi_input_test.ql new file mode 100644 index 00000000000..5cfb210da24 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/ssa/phi-nodes/phi_input_test.ql @@ -0,0 +1,7 @@ +import python + +from SsaVariable var, SsaVariable arg, BasicBlock pred +where pred = var.getPredecessorBlockForPhiArgument(arg) +select var.getLocation().getFile().getShortName(), +var.toString(), var.getLocation().getStartLine(), arg, arg.getLocation().getStartLine(), pred.getLastNode().getLocation().getStartLine() + diff --git a/python/ql/test/library-tests/ControlFlow/ssa/phi-nodes/test.expected b/python/ql/test/library-tests/ControlFlow/ssa/phi-nodes/test.expected new file mode 100644 index 00000000000..53dd0482533 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/ssa/phi-nodes/test.expected @@ -0,0 +1,12 @@ +| test2.py | SSA Variable l0 | 10 | test2.py:7:9:7:10 | SSA Variable l0 | 7 | +| test2.py | SSA Variable l0 | 10 | test2.py:9:9:9:10 | SSA Variable l0 | 9 | +| test2.py | SSA Variable l1 | 19 | test2.py:14:5:14:6 | SSA Variable l1 | 14 | +| test2.py | SSA Variable l1 | 19 | test2.py:18:9:18:10 | SSA Variable l1 | 18 | +| test3.py | SSA Variable l0 | 11 | test3.py:9:13:9:14 | SSA Variable l0 | 9 | +| test3.py | SSA Variable l0 | 11 | test3.py:9:13:9:14 | SSA Variable l0 | 9 | +| test3.py | SSA Variable l0 | 13 | test3.py:9:13:9:14 | SSA Variable l0 | 9 | +| test3.py | SSA Variable l0 | 13 | test3.py:11:5:11:11 | SSA Variable l0 | 11 | +| test4.py | SSA Variable x | 14 | test4.py:11:13:11:13 | SSA Variable x | 11 | +| test4.py | SSA Variable x | 14 | test4.py:13:9:13:9 | SSA Variable x | 13 | +| test5.py | SSA Variable a | 0 | test5.py:4:9:4:9 | SSA Variable a | 4 | +| test5.py | SSA Variable a | 0 | test5.py:9:9:9:9 | SSA Variable a | 9 | diff --git a/python/ql/test/library-tests/ControlFlow/ssa/phi-nodes/test.ql b/python/ql/test/library-tests/ControlFlow/ssa/phi-nodes/test.ql new file mode 100644 index 00000000000..6c4f617e172 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/ssa/phi-nodes/test.ql @@ -0,0 +1,7 @@ +import python + +from SsaVariable var, SsaVariable arg +where arg = var.getAPhiInput() +select var.getLocation().getFile().getShortName(), +var.toString(), var.getLocation().getStartLine(), arg, arg.getLocation().getStartLine() + diff --git a/python/ql/test/library-tests/ControlFlow/ssa/phi-nodes/test1.py b/python/ql/test/library-tests/ControlFlow/ssa/phi-nodes/test1.py new file mode 100644 index 00000000000..d6fe26089b0 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/ssa/phi-nodes/test1.py @@ -0,0 +1,10 @@ +#Weird formatting is so that all uses and defn are on separate lines +#to assist checking test results. + + +def no_phi(cond): + l0 = 0 + l1 = 1 + l2 = l0 + l1 + return l2 + diff --git a/python/ql/test/library-tests/ControlFlow/ssa/phi-nodes/test2.py b/python/ql/test/library-tests/ControlFlow/ssa/phi-nodes/test2.py new file mode 100644 index 00000000000..de38a986cee --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/ssa/phi-nodes/test2.py @@ -0,0 +1,19 @@ +#Weird formatting is so that all uses and defn are on separate lines +#to assist checking test results. + +def with_phi( + cond): + if cond: + l0 = 0 + else: + l0 = 1 + return l0 + +def with_phi2( + cond): + l1 = 0 + if cond: + pass + else: + l1 = 1 + return l1 diff --git a/python/ql/test/library-tests/ControlFlow/ssa/phi-nodes/test3.py b/python/ql/test/library-tests/ControlFlow/ssa/phi-nodes/test3.py new file mode 100644 index 00000000000..ce2d9ac920e --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/ssa/phi-nodes/test3.py @@ -0,0 +1,14 @@ +#Weird formatting is so that all uses and defn are on separate lines +#to assist checking test results. + +def phi_in_try(): + try: + try: + a_call() + finally: + l0 = 0 + another_call() + except: + pass + return l0 + diff --git a/python/ql/test/library-tests/ControlFlow/ssa/phi-nodes/test4.py b/python/ql/test/library-tests/ControlFlow/ssa/phi-nodes/test4.py new file mode 100644 index 00000000000..1f4426514a2 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/ssa/phi-nodes/test4.py @@ -0,0 +1,15 @@ + +def del1(): + x = 0 + del x + x = 0 + return x + +def del2(): + x = 0 + if random(): + del x + else: + x = 1 + return x + diff --git a/python/ql/test/library-tests/ControlFlow/ssa/phi-nodes/test5.py b/python/ql/test/library-tests/ControlFlow/ssa/phi-nodes/test5.py new file mode 100644 index 00000000000..8f900254ec6 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/ssa/phi-nodes/test5.py @@ -0,0 +1,11 @@ + +if x: + + def a(): + pass + +else: + + def a(): + pass + diff --git a/python/ql/test/library-tests/ControlFlow/ssa/phi-nodes/test6.py b/python/ql/test/library-tests/ControlFlow/ssa/phi-nodes/test6.py new file mode 100644 index 00000000000..d148a5c745b --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/ssa/phi-nodes/test6.py @@ -0,0 +1,6 @@ + +if x: + + def a(): + pass + del a diff --git a/python/ql/test/library-tests/ControlFlow/ssa/undefined/test.expected b/python/ql/test/library-tests/ControlFlow/ssa/undefined/test.expected new file mode 100644 index 00000000000..8ca7c0a9309 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/ssa/undefined/test.expected @@ -0,0 +1,2 @@ +| 15 | SSA Variable module2 | +| 20 | SSA Variable x | diff --git a/python/ql/test/library-tests/ControlFlow/ssa/undefined/test.py b/python/ql/test/library-tests/ControlFlow/ssa/undefined/test.py new file mode 100644 index 00000000000..fb7420506dc --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/ssa/undefined/test.py @@ -0,0 +1,20 @@ +from outside import cond + +try: + import module1 +except ImportError: + quit() + +module1 + +try: + import module2 +except ImportError: + print("Error") + +module2 + +if cond(): + x = 0 + +x diff --git a/python/ql/test/library-tests/ControlFlow/ssa/undefined/test.ql b/python/ql/test/library-tests/ControlFlow/ssa/undefined/test.ql new file mode 100644 index 00000000000..df5df70d827 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/ssa/undefined/test.ql @@ -0,0 +1,7 @@ + +import python + +from SsaVariable var +where var.maybeUndefined() +select +var.getDefinition().getLocation().getStartLine(), var.toString() diff --git a/python/ql/test/library-tests/ControlFlow/ssa/uses/test.expected b/python/ql/test/library-tests/ControlFlow/ssa/uses/test.expected new file mode 100644 index 00000000000..6d7ad357cba --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/ssa/uses/test.expected @@ -0,0 +1,11 @@ +| test1.py | ControlFlowNode for l0 | 8 | SSA Variable l0 | 6 | +| test1.py | ControlFlowNode for l1 | 8 | SSA Variable l1 | 7 | +| test1.py | ControlFlowNode for l2 | 9 | SSA Variable l2 | 8 | +| test1.py | Exit node for Module test1 | 0 | SSA Variable no_phi | 5 | +| test2.py | ControlFlowNode for cond | 6 | SSA Variable cond | 5 | +| test2.py | ControlFlowNode for l0 | 10 | SSA Variable l0 | 10 | +| test2.py | Exit node for Module test2 | 0 | SSA Variable with_phi | 4 | +| test3.py | ControlFlowNode for l0 | 13 | SSA Variable l0 | 13 | +| test3.py | Exit node for Module test3 | 0 | SSA Variable phi_in_try | 4 | +| test5.py | Exit node for Module test5 | 0 | SSA Variable a | 0 | +| test6.py | ControlFlowNode for a | 6 | SSA Variable a | 4 | diff --git a/python/ql/test/library-tests/ControlFlow/ssa/uses/test.ql b/python/ql/test/library-tests/ControlFlow/ssa/uses/test.ql new file mode 100644 index 00000000000..9a3f4e92452 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/ssa/uses/test.ql @@ -0,0 +1,6 @@ +import python + +from ControlFlowNode use, SsaVariable def +where def.getAUse() = use +select use.getLocation().getFile().getShortName(), +use.toString(), use.getLocation().getStartLine(), def.toString(), def.getLocation().getStartLine() diff --git a/python/ql/test/library-tests/ControlFlow/ssa/uses/test1.py b/python/ql/test/library-tests/ControlFlow/ssa/uses/test1.py new file mode 100644 index 00000000000..d6fe26089b0 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/ssa/uses/test1.py @@ -0,0 +1,10 @@ +#Weird formatting is so that all uses and defn are on separate lines +#to assist checking test results. + + +def no_phi(cond): + l0 = 0 + l1 = 1 + l2 = l0 + l1 + return l2 + diff --git a/python/ql/test/library-tests/ControlFlow/ssa/uses/test2.py b/python/ql/test/library-tests/ControlFlow/ssa/uses/test2.py new file mode 100644 index 00000000000..d02c4c370bb --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/ssa/uses/test2.py @@ -0,0 +1,11 @@ +#Weird formatting is so that all uses and defn are on separate lines +#to assist checking test results. + +def with_phi( + cond): + if cond: + l0 = 0 + else: + l0 = 1 + return l0 + diff --git a/python/ql/test/library-tests/ControlFlow/ssa/uses/test3.py b/python/ql/test/library-tests/ControlFlow/ssa/uses/test3.py new file mode 100644 index 00000000000..ce2d9ac920e --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/ssa/uses/test3.py @@ -0,0 +1,14 @@ +#Weird formatting is so that all uses and defn are on separate lines +#to assist checking test results. + +def phi_in_try(): + try: + try: + a_call() + finally: + l0 = 0 + another_call() + except: + pass + return l0 + diff --git a/python/ql/test/library-tests/ControlFlow/ssa/uses/test5.py b/python/ql/test/library-tests/ControlFlow/ssa/uses/test5.py new file mode 100644 index 00000000000..8f900254ec6 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/ssa/uses/test5.py @@ -0,0 +1,11 @@ + +if x: + + def a(): + pass + +else: + + def a(): + pass + diff --git a/python/ql/test/library-tests/ControlFlow/ssa/uses/test6.py b/python/ql/test/library-tests/ControlFlow/ssa/uses/test6.py new file mode 100644 index 00000000000..d148a5c745b --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/ssa/uses/test6.py @@ -0,0 +1,6 @@ + +if x: + + def a(): + pass + del a diff --git a/python/ql/test/library-tests/ControlFlow/ssa/vars/test.expected b/python/ql/test/library-tests/ControlFlow/ssa/vars/test.expected new file mode 100644 index 00000000000..be7f90aea76 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/ssa/vars/test.expected @@ -0,0 +1,26 @@ +| test1.py | test1.py:5:5:5:10 | SSA Variable no_phi | 5 | +| test1.py | test1.py:6:5:6:6 | SSA Variable l0 | 6 | +| test1.py | test1.py:7:5:7:6 | SSA Variable l1 | 7 | +| test1.py | test1.py:8:5:8:6 | SSA Variable l2 | 8 | +| test2.py | test2.py:4:5:4:12 | SSA Variable with_phi | 4 | +| test2.py | test2.py:5:5:5:8 | SSA Variable cond | 5 | +| test2.py | test2.py:7:9:7:10 | SSA Variable l0 | 7 | +| test2.py | test2.py:9:9:9:10 | SSA Variable l0 | 9 | +| test2.py | test2.py:10:12:10:13 | SSA Variable l0 | 10 | +| test3.py | test3.py:4:5:4:14 | SSA Variable phi_in_try | 4 | +| test3.py | test3.py:9:13:9:14 | SSA Variable l0 | 9 | +| test3.py | test3.py:9:13:9:14 | SSA Variable l0 | 9 | +| test3.py | test3.py:11:5:11:11 | SSA Variable l0 | 11 | +| test3.py | test3.py:13:12:13:13 | SSA Variable l0 | 13 | +| test4.py | test4.py:2:5:2:8 | SSA Variable del1 | 2 | +| test4.py | test4.py:3:5:3:5 | SSA Variable x | 3 | +| test4.py | test4.py:5:5:5:5 | SSA Variable x | 5 | +| test4.py | test4.py:8:5:8:8 | SSA Variable del2 | 8 | +| test4.py | test4.py:9:5:9:5 | SSA Variable x | 9 | +| test4.py | test4.py:11:13:11:13 | SSA Variable x | 11 | +| test4.py | test4.py:13:9:13:9 | SSA Variable x | 13 | +| test4.py | test4.py:14:12:14:12 | SSA Variable x | 14 | +| test5.py | test5.py:0:0:0:0 | SSA Variable a | 0 | +| test5.py | test5.py:4:9:4:9 | SSA Variable a | 4 | +| test5.py | test5.py:9:9:9:9 | SSA Variable a | 9 | +| test6.py | test6.py:4:9:4:9 | SSA Variable a | 4 | diff --git a/python/ql/test/library-tests/ControlFlow/ssa/vars/test.ql b/python/ql/test/library-tests/ControlFlow/ssa/vars/test.ql new file mode 100644 index 00000000000..5e2dd530ad9 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/ssa/vars/test.ql @@ -0,0 +1,7 @@ +import python + +from SsaVariable var + +select var.getLocation().getFile().getShortName(), +var, var.getLocation().getStartLine() + diff --git a/python/ql/test/library-tests/ControlFlow/ssa/vars/test1.py b/python/ql/test/library-tests/ControlFlow/ssa/vars/test1.py new file mode 100644 index 00000000000..d6fe26089b0 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/ssa/vars/test1.py @@ -0,0 +1,10 @@ +#Weird formatting is so that all uses and defn are on separate lines +#to assist checking test results. + + +def no_phi(cond): + l0 = 0 + l1 = 1 + l2 = l0 + l1 + return l2 + diff --git a/python/ql/test/library-tests/ControlFlow/ssa/vars/test2.py b/python/ql/test/library-tests/ControlFlow/ssa/vars/test2.py new file mode 100644 index 00000000000..d02c4c370bb --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/ssa/vars/test2.py @@ -0,0 +1,11 @@ +#Weird formatting is so that all uses and defn are on separate lines +#to assist checking test results. + +def with_phi( + cond): + if cond: + l0 = 0 + else: + l0 = 1 + return l0 + diff --git a/python/ql/test/library-tests/ControlFlow/ssa/vars/test3.py b/python/ql/test/library-tests/ControlFlow/ssa/vars/test3.py new file mode 100644 index 00000000000..ce2d9ac920e --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/ssa/vars/test3.py @@ -0,0 +1,14 @@ +#Weird formatting is so that all uses and defn are on separate lines +#to assist checking test results. + +def phi_in_try(): + try: + try: + a_call() + finally: + l0 = 0 + another_call() + except: + pass + return l0 + diff --git a/python/ql/test/library-tests/ControlFlow/ssa/vars/test4.py b/python/ql/test/library-tests/ControlFlow/ssa/vars/test4.py new file mode 100644 index 00000000000..1f4426514a2 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/ssa/vars/test4.py @@ -0,0 +1,15 @@ + +def del1(): + x = 0 + del x + x = 0 + return x + +def del2(): + x = 0 + if random(): + del x + else: + x = 1 + return x + diff --git a/python/ql/test/library-tests/ControlFlow/ssa/vars/test5.py b/python/ql/test/library-tests/ControlFlow/ssa/vars/test5.py new file mode 100644 index 00000000000..8f900254ec6 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/ssa/vars/test5.py @@ -0,0 +1,11 @@ + +if x: + + def a(): + pass + +else: + + def a(): + pass + diff --git a/python/ql/test/library-tests/ControlFlow/ssa/vars/test6.py b/python/ql/test/library-tests/ControlFlow/ssa/vars/test6.py new file mode 100644 index 00000000000..d148a5c745b --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/ssa/vars/test6.py @@ -0,0 +1,6 @@ + +if x: + + def a(): + pass + del a diff --git a/python/ql/test/library-tests/ControlFlow/truefalse/Branch.expected b/python/ql/test/library-tests/ControlFlow/truefalse/Branch.expected new file mode 100644 index 00000000000..a5feb4fc4e8 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/truefalse/Branch.expected @@ -0,0 +1,14 @@ +| 2 | boolops.py:2:9:6:25 | ControlFlowNode for UnaryExpr | +| 2 | boolops.py:2:9:6:25 | ControlFlowNode for UnaryExpr | +| 3 | boolops.py:3:13:3:13 | ControlFlowNode for x | +| 4 | boolops.py:4:17:6:24 | ControlFlowNode for UnaryExpr | +| 4 | boolops.py:4:17:6:24 | ControlFlowNode for UnaryExpr | +| 5 | boolops.py:5:22:5:23 | ControlFlowNode for y1 | +| 6 | boolops.py:6:22:6:23 | ControlFlowNode for z1 | +| 7 | boolops.py:7:8:11:23 | ControlFlowNode for UnaryExpr | +| 7 | boolops.py:7:8:11:23 | ControlFlowNode for UnaryExpr | +| 8 | boolops.py:8:12:8:12 | ControlFlowNode for x | +| 9 | boolops.py:9:15:11:22 | ControlFlowNode for UnaryExpr | +| 9 | boolops.py:9:15:11:22 | ControlFlowNode for UnaryExpr | +| 10 | boolops.py:10:20:10:21 | ControlFlowNode for y2 | +| 11 | boolops.py:11:20:11:21 | ControlFlowNode for z2 | diff --git a/python/ql/test/library-tests/ControlFlow/truefalse/Branch.ql b/python/ql/test/library-tests/ControlFlow/truefalse/Branch.ql new file mode 100644 index 00000000000..76b235c8006 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/truefalse/Branch.ql @@ -0,0 +1,12 @@ +/** + * @name Branch + * @description Insert description here... + * @kind problem + * @problem.severity warning + */ + +import python + +from ControlFlowNode f +where f.isBranch() and f.getLocation().getFile().getShortName() = "boolops.py" +select f.getLocation().getStartLine(), f diff --git a/python/ql/test/library-tests/ControlFlow/truefalse/ExceptionalSuccessors.expected b/python/ql/test/library-tests/ControlFlow/truefalse/ExceptionalSuccessors.expected new file mode 100644 index 00000000000..b84e4f43f92 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/truefalse/ExceptionalSuccessors.expected @@ -0,0 +1,23 @@ +| true_false_test.py | 14 | true_false_test.py:14:12:14:16 | ControlFlowNode for cond4 | ControlFlowNode for Pass | +| true_false_test.py | 15 | true_false_test.py:15:13:15:17 | ControlFlowNode for true4 | ControlFlowNode for Pass | +| true_false_test.py | 15 | true_false_test.py:15:13:15:19 | ControlFlowNode for true4() | ControlFlowNode for Pass | +| true_false_test.py | 17 | true_false_test.py:17:13:17:18 | ControlFlowNode for false4 | ControlFlowNode for Pass | +| true_false_test.py | 17 | true_false_test.py:17:13:17:20 | ControlFlowNode for false4() | ControlFlowNode for Pass | +| true_false_test.py | 19 | true_false_test.py:19:9:19:12 | ControlFlowNode for Pass | Entry node for Function func | +| true_false_test.py | 22 | true_false_test.py:22:13:22:17 | ControlFlowNode for true5 | ControlFlowNode for ExceptStmt | +| true_false_test.py | 22 | true_false_test.py:22:13:22:19 | ControlFlowNode for true5() | ControlFlowNode for ExceptStmt | +| true_false_test.py | 35 | true_false_test.py:35:18:35:26 | ControlFlowNode for range() | Entry node for Function func | +| true_false_test.py | 48 | true_false_test.py:48:17:48:24 | ControlFlowNode for true12() | ControlFlowNode for ExceptStmt | +| true_false_test.py | 48 | true_false_test.py:48:17:48:24 | ControlFlowNode for true12() | Entry node for Function func | +| true_succ.py | 8 | true_succ.py:8:21:8:39 | ControlFlowNode for open() | ControlFlowNode for ExceptStmt | +| true_succ.py | 8 | true_succ.py:8:21:8:39 | ControlFlowNode for open() | ControlFlowNode for f | +| true_succ.py | 9 | true_succ.py:9:17:9:23 | ControlFlowNode for Attribute | ControlFlowNode for ExceptStmt | +| true_succ.py | 9 | true_succ.py:9:17:9:23 | ControlFlowNode for Attribute | ControlFlowNode for f | +| true_succ.py | 9 | true_succ.py:9:17:9:32 | ControlFlowNode for Attribute() | ControlFlowNode for ExceptStmt | +| true_succ.py | 9 | true_succ.py:9:17:9:32 | ControlFlowNode for Attribute() | ControlFlowNode for f | +| true_succ.py | 11 | true_succ.py:11:17:11:19 | ControlFlowNode for sys | ControlFlowNode for f | +| true_succ.py | 11 | true_succ.py:11:17:11:24 | ControlFlowNode for Attribute | ControlFlowNode for f | +| true_succ.py | 11 | true_succ.py:11:17:11:27 | ControlFlowNode for Attribute() | ControlFlowNode for f | +| true_succ.py | 13 | true_succ.py:13:16:13:28 | ControlFlowNode for Compare | Entry node for Function example | +| true_succ.py | 13 | true_succ.py:13:31:13:39 | ControlFlowNode for Attribute() | Entry node for Function example | +| true_succ.py | 13 | true_succ.py:13:31:13:39 | ControlFlowNode for Attribute() | Entry node for Function example | diff --git a/python/ql/test/library-tests/ControlFlow/truefalse/ExceptionalSuccessors.ql b/python/ql/test/library-tests/ControlFlow/truefalse/ExceptionalSuccessors.ql new file mode 100644 index 00000000000..f7bf00db01b --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/truefalse/ExceptionalSuccessors.ql @@ -0,0 +1,16 @@ +/** + * @name TrueFalseSuccessors Test + * @description Tests true/false successors + * @kind problem + * @problem.severity warning + */ + +import python + +from ControlFlowNode p, ControlFlowNode s +where +s = p.getAnExceptionalSuccessor() +or +// Add fake edges for node that raise out of scope +p.isExceptionalExit(_) and s = p.getScope().getEntryNode() +select p.getLocation().getFile().getShortName(), p.getLocation().getStartLine(), p, s.toString() diff --git a/python/ql/test/library-tests/ControlFlow/truefalse/TrueAndFalseSuccessor.expected b/python/ql/test/library-tests/ControlFlow/truefalse/TrueAndFalseSuccessor.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/library-tests/ControlFlow/truefalse/TrueAndFalseSuccessor.ql b/python/ql/test/library-tests/ControlFlow/truefalse/TrueAndFalseSuccessor.ql new file mode 100644 index 00000000000..d5d8323a3a2 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/truefalse/TrueAndFalseSuccessor.ql @@ -0,0 +1,7 @@ + + +import python + +from ControlFlowNode f +where f.getATrueSuccessor() = f.getAFalseSuccessor() +select f.toString() \ No newline at end of file diff --git a/python/ql/test/library-tests/ControlFlow/truefalse/TrueFalseSuccessors.expected b/python/ql/test/library-tests/ControlFlow/truefalse/TrueFalseSuccessors.expected new file mode 100644 index 00000000000..4590ee6f390 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/truefalse/TrueFalseSuccessors.expected @@ -0,0 +1,82 @@ +| boolops.py | 2 | boolops.py:2:9:6:25 | ControlFlowNode for UnaryExpr | ControlFlowNode for p | False | +| boolops.py | 2 | boolops.py:2:9:6:25 | ControlFlowNode for UnaryExpr | ControlFlowNode for p | True | +| boolops.py | 3 | boolops.py:3:13:3:13 | ControlFlowNode for x | ControlFlowNode for BoolExpr | True | +| boolops.py | 3 | boolops.py:3:13:3:13 | ControlFlowNode for x | ControlFlowNode for UnaryExpr | False | +| boolops.py | 4 | boolops.py:4:17:6:24 | ControlFlowNode for UnaryExpr | ControlFlowNode for UnaryExpr | False | +| boolops.py | 4 | boolops.py:4:17:6:24 | ControlFlowNode for UnaryExpr | ControlFlowNode for UnaryExpr | True | +| boolops.py | 5 | boolops.py:5:22:5:23 | ControlFlowNode for y1 | ControlFlowNode for UnaryExpr | True | +| boolops.py | 5 | boolops.py:5:22:5:23 | ControlFlowNode for y1 | ControlFlowNode for z1 | False | +| boolops.py | 6 | boolops.py:6:22:6:23 | ControlFlowNode for z1 | ControlFlowNode for UnaryExpr | False | +| boolops.py | 6 | boolops.py:6:22:6:23 | ControlFlowNode for z1 | ControlFlowNode for UnaryExpr | True | +| boolops.py | 7 | boolops.py:7:8:11:23 | ControlFlowNode for UnaryExpr | ControlFlowNode for Str | False | +| boolops.py | 7 | boolops.py:7:8:11:23 | ControlFlowNode for UnaryExpr | ControlFlowNode for Str | True | +| boolops.py | 8 | boolops.py:8:12:8:12 | ControlFlowNode for x | ControlFlowNode for BoolExpr | False | +| boolops.py | 8 | boolops.py:8:12:8:12 | ControlFlowNode for x | ControlFlowNode for UnaryExpr | True | +| boolops.py | 9 | boolops.py:9:15:11:22 | ControlFlowNode for UnaryExpr | ControlFlowNode for UnaryExpr | False | +| boolops.py | 9 | boolops.py:9:15:11:22 | ControlFlowNode for UnaryExpr | ControlFlowNode for UnaryExpr | True | +| boolops.py | 10 | boolops.py:10:20:10:21 | ControlFlowNode for y2 | ControlFlowNode for UnaryExpr | False | +| boolops.py | 10 | boolops.py:10:20:10:21 | ControlFlowNode for y2 | ControlFlowNode for z2 | True | +| boolops.py | 11 | boolops.py:11:20:11:21 | ControlFlowNode for z2 | ControlFlowNode for UnaryExpr | False | +| boolops.py | 11 | boolops.py:11:20:11:21 | ControlFlowNode for z2 | ControlFlowNode for UnaryExpr | True | +| true_false_test.py | 3 | true_false_test.py:3:8:3:12 | ControlFlowNode for cond1 | ControlFlowNode for cond2 | False | +| true_false_test.py | 3 | true_false_test.py:3:8:3:12 | ControlFlowNode for cond1 | ControlFlowNode for true1 | True | +| true_false_test.py | 5 | true_false_test.py:5:8:5:12 | ControlFlowNode for cond2 | ControlFlowNode for Pass | True | +| true_false_test.py | 5 | true_false_test.py:5:8:5:12 | ControlFlowNode for cond2 | ControlFlowNode for false2 | False | +| true_false_test.py | 9 | true_false_test.py:9:8:9:12 | ControlFlowNode for cond3 | ControlFlowNode for false3 | False | +| true_false_test.py | 9 | true_false_test.py:9:8:9:12 | ControlFlowNode for cond3 | ControlFlowNode for true3 | True | +| true_false_test.py | 14 | true_false_test.py:14:12:14:16 | ControlFlowNode for cond4 | ControlFlowNode for false4 | False | +| true_false_test.py | 14 | true_false_test.py:14:12:14:16 | ControlFlowNode for cond4 | ControlFlowNode for true4 | True | +| true_false_test.py | 20 | true_false_test.py:20:8:20:12 | ControlFlowNode for cond5 | ControlFlowNode for Try | True | +| true_false_test.py | 20 | true_false_test.py:20:8:20:12 | ControlFlowNode for cond5 | ControlFlowNode for false5 | False | +| true_false_test.py | 27 | true_false_test.py:27:8:27:12 | ControlFlowNode for cond6 | ControlFlowNode for cond7 | True | +| true_false_test.py | 27 | true_false_test.py:27:8:27:12 | ControlFlowNode for cond6 | ControlFlowNode for false6 | False | +| true_false_test.py | 28 | true_false_test.py:28:12:28:16 | ControlFlowNode for cond7 | ControlFlowNode for false7 | False | +| true_false_test.py | 28 | true_false_test.py:28:12:28:16 | ControlFlowNode for cond7 | ControlFlowNode for true7 | True | +| true_false_test.py | 34 | true_false_test.py:34:8:34:12 | ControlFlowNode for cond8 | ControlFlowNode for false8 | False | +| true_false_test.py | 34 | true_false_test.py:34:8:34:12 | ControlFlowNode for cond8 | ControlFlowNode for range | True | +| true_false_test.py | 39 | true_false_test.py:39:8:39:12 | ControlFlowNode for cond9 | ControlFlowNode for While | True | +| true_false_test.py | 39 | true_false_test.py:39:8:39:12 | ControlFlowNode for cond9 | ControlFlowNode for false9 | False | +| true_false_test.py | 40 | true_false_test.py:40:15:40:20 | ControlFlowNode for cond10 | ControlFlowNode for false10 | False | +| true_false_test.py | 40 | true_false_test.py:40:15:40:20 | ControlFlowNode for cond10 | ControlFlowNode for true10 | True | +| true_false_test.py | 45 | true_false_test.py:45:11:45:11 | ControlFlowNode for IntegerLiteral | ControlFlowNode for cond12 | True | +| true_false_test.py | 46 | true_false_test.py:46:12:46:17 | ControlFlowNode for cond12 | ControlFlowNode for Try | True | +| true_false_test.py | 46 | true_false_test.py:46:12:46:17 | ControlFlowNode for cond12 | ControlFlowNode for While | False | +| true_false_test.py | 55 | true_false_test.py:55:11:55:16 | ControlFlowNode for condw1 | ControlFlowNode for truew2 | True | +| true_false_test.py | 55 | true_false_test.py:55:11:55:16 | ControlFlowNode for condw1 | Exit node for Function func2 | False | +| true_false_test.py | 59 | true_false_test.py:59:8:59:13 | ControlFlowNode for condi1 | ControlFlowNode for truei1 | True | +| true_false_test.py | 59 | true_false_test.py:59:8:59:13 | ControlFlowNode for condi1 | Exit node for Function func3 | False | +| true_false_test.py | 63 | true_false_test.py:63:11:63:14 | ControlFlowNode for True | ControlFlowNode for no_branch | True | +| true_false_test.py | 69 | true_false_test.py:69:11:69:14 | ControlFlowNode for True | ControlFlowNode for Break | True | +| true_false_test.py | 71 | true_false_test.py:71:8:71:13 | ControlFlowNode for cond11 | ControlFlowNode for true11 | True | +| true_false_test.py | 71 | true_false_test.py:71:8:71:13 | ControlFlowNode for cond11 | Exit node for Function func5 | False | +| true_false_test.py | 75 | true_false_test.py:75:8:75:13 | ControlFlowNode for cond13 | ControlFlowNode for cond13a | False | +| true_false_test.py | 75 | true_false_test.py:75:8:75:13 | ControlFlowNode for cond13 | ControlFlowNode for true13 | True | +| true_false_test.py | 75 | true_false_test.py:75:18:75:24 | ControlFlowNode for cond13a | ControlFlowNode for BoolExpr | False | +| true_false_test.py | 75 | true_false_test.py:75:18:75:24 | ControlFlowNode for cond13a | ControlFlowNode for true13 | True | +| true_false_test.py | 77 | true_false_test.py:77:8:77:13 | ControlFlowNode for cond14 | ControlFlowNode for cond14a | True | +| true_false_test.py | 77 | true_false_test.py:77:8:77:13 | ControlFlowNode for cond14 | ControlFlowNode for cond15 | False | +| true_false_test.py | 77 | true_false_test.py:77:19:77:25 | ControlFlowNode for cond14a | ControlFlowNode for cond15 | False | +| true_false_test.py | 77 | true_false_test.py:77:19:77:25 | ControlFlowNode for cond14a | ControlFlowNode for true14 | True | +| true_false_test.py | 79 | true_false_test.py:79:15:79:20 | ControlFlowNode for cond15 | ControlFlowNode for false15 | False | +| true_false_test.py | 79 | true_false_test.py:79:15:79:20 | ControlFlowNode for cond15 | ControlFlowNode for true15 | True | +| true_false_test.py | 80 | true_false_test.py:80:15:80:20 | ControlFlowNode for cond16 | ControlFlowNode for cond17 | False | +| true_false_test.py | 80 | true_false_test.py:80:15:80:20 | ControlFlowNode for cond16 | ControlFlowNode for true16 | True | +| true_false_test.py | 80 | true_false_test.py:80:25:80:30 | ControlFlowNode for cond17 | ControlFlowNode for false16 | False | +| true_false_test.py | 80 | true_false_test.py:80:25:80:30 | ControlFlowNode for cond17 | ControlFlowNode for true16 | True | +| true_false_test.py | 81 | true_false_test.py:81:15:81:20 | ControlFlowNode for cond18 | ControlFlowNode for cond19 | True | +| true_false_test.py | 81 | true_false_test.py:81:15:81:20 | ControlFlowNode for cond18 | ControlFlowNode for false18 | False | +| true_false_test.py | 81 | true_false_test.py:81:26:81:31 | ControlFlowNode for cond19 | ControlFlowNode for false18 | False | +| true_false_test.py | 81 | true_false_test.py:81:26:81:31 | ControlFlowNode for cond19 | ControlFlowNode for true18 | True | +| true_false_test.py | 84 | true_false_test.py:84:11:84:16 | ControlFlowNode for cond20 | ControlFlowNode for Yield | True | +| true_false_test.py | 84 | true_false_test.py:84:11:84:16 | ControlFlowNode for cond20 | ControlFlowNode for cond21 | False | +| true_false_test.py | 84 | true_false_test.py:84:21:84:26 | ControlFlowNode for cond21 | ControlFlowNode for Yield | True | +| true_false_test.py | 84 | true_false_test.py:84:21:84:26 | ControlFlowNode for cond21 | ControlFlowNode for cond22 | False | +| true_false_test.py | 85 | true_false_test.py:85:11:85:16 | ControlFlowNode for cond23 | ControlFlowNode for Yield | False | +| true_false_test.py | 85 | true_false_test.py:85:11:85:16 | ControlFlowNode for cond23 | ControlFlowNode for cond24 | True | +| true_false_test.py | 85 | true_false_test.py:85:22:85:27 | ControlFlowNode for cond24 | ControlFlowNode for Yield | False | +| true_false_test.py | 85 | true_false_test.py:85:22:85:27 | ControlFlowNode for cond24 | ControlFlowNode for cond25 | True | +| true_succ.py | 4 | true_succ.py:4:8:4:15 | ControlFlowNode for filename | ControlFlowNode for Str | False | +| true_succ.py | 4 | true_succ.py:4:8:4:15 | ControlFlowNode for filename | ControlFlowNode for Try | True | +| true_succ.py | 13 | true_succ.py:13:16:13:28 | ControlFlowNode for Compare | ControlFlowNode for Str | False | +| true_succ.py | 13 | true_succ.py:13:16:13:28 | ControlFlowNode for Compare | ControlFlowNode for f | True | +| true_succ.py | 13 | true_succ.py:13:16:13:28 | ControlFlowNode for Compare | ControlFlowNode for f | True | diff --git a/python/ql/test/library-tests/ControlFlow/truefalse/TrueFalseSuccessors.ql b/python/ql/test/library-tests/ControlFlow/truefalse/TrueFalseSuccessors.ql new file mode 100644 index 00000000000..0f0e614523a --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/truefalse/TrueFalseSuccessors.ql @@ -0,0 +1,15 @@ +/** + * @name TrueFalseSuccessors Test + * @description Tests true/false successors + * @kind problem + * @problem.severity warning + */ + +import python + +from ControlFlowNode p, ControlFlowNode s, string which +where +s = p.getAFalseSuccessor() and which = "False" +or +s = p.getATrueSuccessor() and which = "True" +select p.getLocation().getFile().getShortName(), p.getLocation().getStartLine(), p, s.toString(), which diff --git a/python/ql/test/library-tests/ControlFlow/truefalse/boolops.py b/python/ql/test/library-tests/ControlFlow/truefalse/boolops.py new file mode 100644 index 00000000000..383b12a6a56 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/truefalse/boolops.py @@ -0,0 +1,14 @@ +def boolops(x, y1, z1, y2, z2): + p = not( + x + and not ( + y1 or + z1)) + if not( + x + or not ( + y2 and + z2)): + return b"true" + else: + return b"false" diff --git a/python/ql/test/library-tests/ControlFlow/truefalse/true_false_test.py b/python/ql/test/library-tests/ControlFlow/truefalse/true_false_test.py new file mode 100644 index 00000000000..031845551ae --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/truefalse/true_false_test.py @@ -0,0 +1,85 @@ + +def func(): + if cond1: + true1 + if cond2: + pass + else: + false2 + if cond3: + true3 + else: + false3 + try: + if cond4: + true4() + else: + false4() + finally: + pass + if cond5: + try: + true5() + except: + pass + else: + false5 + if cond6: + if cond7: + true7 + else: + false7 + else: + false6 + if cond8: + for i in range(10): + pass + else: + false8 + if cond9: + while cond10: + true10 + false10 + else: + false9 + while 1: + if cond12: + try: + true12() + except IOError: + true12 = 0 + + + +def func2(): + while condw1: + truew2 + +def func3(): + if condi1: + truei1 + +def func4(): + while True: + no_branch + if unreachable: + not reachable + +def func5(): + while True: + break + if cond11: + true11 + +def func6(): + if cond13 or cond13a: + true13 + if cond14 and cond14a: + true14 + true15 if cond15 else false15 + true16 if cond16 or cond17 else false16 + true18 if cond18 and cond19 else false18 + +def func7(): + yield cond20 or cond21 or cond22 + yield cond23 and cond24 and cond25 diff --git a/python/ql/test/library-tests/ControlFlow/truefalse/true_succ.py b/python/ql/test/library-tests/ControlFlow/truefalse/true_succ.py new file mode 100644 index 00000000000..1d879cd4b42 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/truefalse/true_succ.py @@ -0,0 +1,16 @@ +#https://semmle.com/jira/browse/ODASA-1222 + +def example(filename): + if filename: + try: + f = None + try: + f = open(filename, 'w') + f.write('Hello') + except IOError: + sys.exit(1) + finally: + if f is not None: f.close() + + assert u"This is a false successor to the comparison" + diff --git a/python/ql/test/library-tests/ControlFlow/try/test.py b/python/ql/test/library-tests/ControlFlow/try/test.py new file mode 100644 index 00000000000..7c543b2993e --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/try/test.py @@ -0,0 +1,42 @@ +#Test that the flow control through nested trys is handled correctly. + +def f1(): + try: + x = call() + finally: + try: + another_call() + except: + pass + return x + +def f2(): + try: + x = call() + except: + try: + another_call() + finally: + x = 0 + return x + +def f3(): + try: + x = call() + except: + try: + another_call() + except: + pass + return x + +def f4(): + try: + x = call() + finally: + try: + another_call() + finally: + x = 0 + return x + diff --git a/python/ql/test/library-tests/ControlFlow/try/test_ssa.expected b/python/ql/test/library-tests/ControlFlow/try/test_ssa.expected new file mode 100644 index 00000000000..73dd6613cec --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/try/test_ssa.expected @@ -0,0 +1,8 @@ +| test.py | SSA Variable f1 | 3 | Exit node for Module test | 0 | +| test.py | SSA Variable f2 | 13 | Exit node for Module test | 0 | +| test.py | SSA Variable f3 | 23 | Exit node for Module test | 0 | +| test.py | SSA Variable f4 | 33 | Exit node for Module test | 0 | +| test.py | SSA Variable x | 5 | ControlFlowNode for x | 11 | +| test.py | SSA Variable x | 21 | ControlFlowNode for x | 21 | +| test.py | SSA Variable x | 31 | ControlFlowNode for x | 31 | +| test.py | SSA Variable x | 40 | ControlFlowNode for x | 41 | diff --git a/python/ql/test/library-tests/ControlFlow/try/test_ssa.ql b/python/ql/test/library-tests/ControlFlow/try/test_ssa.ql new file mode 100644 index 00000000000..8df422495fb --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/try/test_ssa.ql @@ -0,0 +1,7 @@ +import python + +from SsaVariable var, ControlFlowNode use +where use = var.getAUse() +select var.getLocation().getFile().getShortName(), +var.toString(), var.getLocation().getStartLine(), use.toString(), use.getLocation().getStartLine() + diff --git a/python/ql/test/library-tests/DefUse/Definitions.expected b/python/ql/test/library-tests/DefUse/Definitions.expected new file mode 100644 index 00000000000..a4670930f96 --- /dev/null +++ b/python/ql/test/library-tests/DefUse/Definitions.expected @@ -0,0 +1,5 @@ +| a | 1 | +| b | 2 | +| c | 3 | +| ctx | 22 | +| ex | 16 | diff --git a/python/ql/test/library-tests/DefUse/Definitions.ql b/python/ql/test/library-tests/DefUse/Definitions.ql new file mode 100644 index 00000000000..927aee8f930 --- /dev/null +++ b/python/ql/test/library-tests/DefUse/Definitions.ql @@ -0,0 +1,12 @@ +/** + * @name Definitions + * @description Insert description here... + * @kind problem + * @problem.severity warning + */ + +import python + +from Name d +where d.defines(_) +select d.getId(), d.getLocation().getStartLine() \ No newline at end of file diff --git a/python/ql/test/library-tests/DefUse/Uses.expected b/python/ql/test/library-tests/DefUse/Uses.expected new file mode 100644 index 00000000000..d36da6087a5 --- /dev/null +++ b/python/ql/test/library-tests/DefUse/Uses.expected @@ -0,0 +1,9 @@ +| C1 | 19 | +| C2 | 22 | +| E1 | 11 | +| E2 | 16 | +| a | 4 | +| b | 5 | +| ctx | 23 | +| d | 7 | +| ex | 17 | diff --git a/python/ql/test/library-tests/DefUse/Uses.ql b/python/ql/test/library-tests/DefUse/Uses.ql new file mode 100644 index 00000000000..f19f08c126e --- /dev/null +++ b/python/ql/test/library-tests/DefUse/Uses.ql @@ -0,0 +1,12 @@ +/** + * @name Usages + * @description Insert description here... + * @kind problem + * @problem.severity warning + */ + +import python + +from Name u +where u.uses(_) +select u.getId(), u.getLocation().getStartLine() \ No newline at end of file diff --git a/python/ql/test/library-tests/DefUse/defuse.py b/python/ql/test/library-tests/DefUse/defuse.py new file mode 100644 index 00000000000..715a8d29007 --- /dev/null +++ b/python/ql/test/library-tests/DefUse/defuse.py @@ -0,0 +1,24 @@ +a = 1 +b = 2 +c = 3 +a +b +# c is not used +d # not defined + +try: + pass +except E1: + pass + +try: + pass +except E2 as ex: + ex + +with C1: + pass + +with C2 as ctx: + ctx + diff --git a/python/ql/test/library-tests/DuplicateCode/Duplicate.expected b/python/ql/test/library-tests/DuplicateCode/Duplicate.expected new file mode 100644 index 00000000000..5c7717546d6 --- /dev/null +++ b/python/ql/test/library-tests/DuplicateCode/Duplicate.expected @@ -0,0 +1,2 @@ +| Duplicate code: 34 duplicated lines. | Duplicate code: 34 duplicated lines. | duplicate_test.py | 9 | 42 | +| Duplicate code: 80 duplicated lines. | Duplicate code: 80 duplicated lines. | duplicate_test.py | 84 | 163 | diff --git a/python/ql/test/library-tests/DuplicateCode/Duplicate.ql b/python/ql/test/library-tests/DuplicateCode/Duplicate.ql new file mode 100644 index 00000000000..3368fef9d16 --- /dev/null +++ b/python/ql/test/library-tests/DuplicateCode/Duplicate.ql @@ -0,0 +1,21 @@ +/** + * @name Duplicate + * @description Insert description here... + * @kind problem + * @problem.severity warning + */ + +import python + +import external.CodeDuplication + +predicate lexically_sorted(DuplicateBlock dup1, DuplicateBlock dup2) { + dup1.sourceFile().getName() < dup2.sourceFile().getName() + or + dup1.sourceFile().getName() = dup2.sourceFile().getName() and dup1.sourceStartLine() < dup2.sourceStartLine() +} + +from DuplicateBlock dup1, DuplicateBlock dup2 +where dup1.getEquivalenceClass() = dup2.getEquivalenceClass() +and lexically_sorted(dup1, dup2) +select dup1.toString(), dup2.toString(), dup1.sourceFile().getShortName(), dup1.sourceStartLine(), dup1.sourceEndLine() \ No newline at end of file diff --git a/python/ql/test/library-tests/DuplicateCode/DuplicateStatements.expected b/python/ql/test/library-tests/DuplicateCode/DuplicateStatements.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/library-tests/DuplicateCode/DuplicateStatements.ql b/python/ql/test/library-tests/DuplicateCode/DuplicateStatements.ql new file mode 100644 index 00000000000..a4243bca968 --- /dev/null +++ b/python/ql/test/library-tests/DuplicateCode/DuplicateStatements.ql @@ -0,0 +1,25 @@ +/** + * @name DuplicateStatements + * @description Insert description here... + * @kind problem + * @problem.severity warning + */ + +import python +import external.CodeDuplication + +predicate mostlyDuplicateFunction(Function f) { + exists(int covered, int total, Function other, int percent | + duplicateStatements(f, other, covered, total) and + covered != total and + total > 5 and + covered * 100 / total = percent and + percent > 80 and + not exists(Scope s | s = f.getScope*() | duplicateScopes(s, _, _, _)) + ) +} + +from Stmt s +where mostlyDuplicateFunction(s.getScope()) and +not duplicateStatement(s.getScope(), _, s, _) +select s.toString(), s.getLocation().toString() \ No newline at end of file diff --git a/python/ql/test/library-tests/DuplicateCode/Similar.expected b/python/ql/test/library-tests/DuplicateCode/Similar.expected new file mode 100644 index 00000000000..34e0b8f745c --- /dev/null +++ b/python/ql/test/library-tests/DuplicateCode/Similar.expected @@ -0,0 +1,23 @@ +| duplicate_test.py:9:1:20:17 | Similar code: 12 almost duplicated lines. | duplicate_test.py:47:1:58:17 | Similar code: 12 almost duplicated lines. | duplicate_test.py | 9 | 20 | +| duplicate_test.py:9:1:20:17 | Similar code: 12 almost duplicated lines. | duplicate_test.py:249:1:260:17 | Similar code: 12 almost duplicated lines. | duplicate_test.py | 9 | 20 | +| duplicate_test.py:9:1:20:17 | Similar code: 12 almost duplicated lines. | duplicate_test.py:287:1:298:17 | Similar code: 12 almost duplicated lines. | duplicate_test.py | 9 | 20 | +| duplicate_test.py:14:8:25:13 | Similar code: 12 almost duplicated lines. | duplicate_test.py:52:8:63:13 | Similar code: 12 almost duplicated lines. | duplicate_test.py | 14 | 25 | +| duplicate_test.py:14:8:25:13 | Similar code: 12 almost duplicated lines. | duplicate_test.py:254:8:265:13 | Similar code: 12 almost duplicated lines. | duplicate_test.py | 14 | 25 | +| duplicate_test.py:20:28:42:31 | Similar code: 23 almost duplicated lines. | duplicate_test.py:58:28:80:31 | Similar code: 23 almost duplicated lines. | duplicate_test.py | 20 | 42 | +| duplicate_test.py:20:28:42:31 | Similar code: 23 almost duplicated lines. | duplicate_test.py:260:28:282:31 | Similar code: 23 almost duplicated lines. | duplicate_test.py | 20 | 42 | +| duplicate_test.py:20:28:42:31 | Similar code: 23 almost duplicated lines. | duplicate_test.py:296:40:318:31 | Similar code: 23 almost duplicated lines. | duplicate_test.py | 20 | 42 | +| duplicate_test.py:36:1:47:0 | Similar code: 12 almost duplicated lines. | duplicate_test.py:74:1:84:0 | Similar code: 11 almost duplicated lines. | duplicate_test.py | 36 | 47 | +| duplicate_test.py:36:1:47:0 | Similar code: 12 almost duplicated lines. | duplicate_test.py:276:1:287:0 | Similar code: 12 almost duplicated lines. | duplicate_test.py | 36 | 47 | +| duplicate_test.py:36:22:56:26 | Similar code: 21 almost duplicated lines. | duplicate_test.py:276:21:296:26 | Similar code: 21 almost duplicated lines. | duplicate_test.py | 36 | 56 | +| duplicate_test.py:42:22:57:9 | Similar code: 16 almost duplicated lines. | duplicate_test.py:245:20:259:9 | Similar code: 15 almost duplicated lines. | duplicate_test.py | 42 | 57 | +| duplicate_test.py:42:22:57:9 | Similar code: 16 almost duplicated lines. | duplicate_test.py:282:22:297:9 | Similar code: 16 almost duplicated lines. | duplicate_test.py | 42 | 57 | +| duplicate_test.py:47:1:58:17 | Similar code: 12 almost duplicated lines. | duplicate_test.py:249:1:260:17 | Similar code: 12 almost duplicated lines. | duplicate_test.py | 47 | 58 | +| duplicate_test.py:47:1:58:17 | Similar code: 12 almost duplicated lines. | duplicate_test.py:287:1:298:17 | Similar code: 12 almost duplicated lines. | duplicate_test.py | 47 | 58 | +| duplicate_test.py:52:8:63:13 | Similar code: 12 almost duplicated lines. | duplicate_test.py:254:8:265:13 | Similar code: 12 almost duplicated lines. | duplicate_test.py | 52 | 63 | +| duplicate_test.py:58:28:80:31 | Similar code: 23 almost duplicated lines. | duplicate_test.py:260:28:282:31 | Similar code: 23 almost duplicated lines. | duplicate_test.py | 58 | 80 | +| duplicate_test.py:58:28:80:31 | Similar code: 23 almost duplicated lines. | duplicate_test.py:296:40:318:31 | Similar code: 23 almost duplicated lines. | duplicate_test.py | 58 | 80 | +| duplicate_test.py:74:1:84:0 | Similar code: 11 almost duplicated lines. | duplicate_test.py:276:1:287:0 | Similar code: 12 almost duplicated lines. | duplicate_test.py | 74 | 84 | +| duplicate_test.py:82:25:163:24 | Similar code: 82 almost duplicated lines. | duplicate_test.py:163:24:245:24 | Similar code: 83 almost duplicated lines. | duplicate_test.py | 82 | 163 | +| duplicate_test.py:245:20:259:9 | Similar code: 15 almost duplicated lines. | duplicate_test.py:282:22:297:9 | Similar code: 16 almost duplicated lines. | duplicate_test.py | 245 | 259 | +| duplicate_test.py:249:1:260:17 | Similar code: 12 almost duplicated lines. | duplicate_test.py:287:1:298:17 | Similar code: 12 almost duplicated lines. | duplicate_test.py | 249 | 260 | +| duplicate_test.py:260:28:282:31 | Similar code: 23 almost duplicated lines. | duplicate_test.py:296:40:318:31 | Similar code: 23 almost duplicated lines. | duplicate_test.py | 260 | 282 | diff --git a/python/ql/test/library-tests/DuplicateCode/Similar.ql b/python/ql/test/library-tests/DuplicateCode/Similar.ql new file mode 100644 index 00000000000..c055551793e --- /dev/null +++ b/python/ql/test/library-tests/DuplicateCode/Similar.ql @@ -0,0 +1,21 @@ +/** + * @name Similar + * @description Insert description here... + * @kind problem + * @problem.severity warning + */ + +import python + +import external.CodeDuplication + +predicate lexically_sorted(SimilarBlock dup1, SimilarBlock dup2) { + dup1.sourceFile().getName() < dup2.sourceFile().getName() + or + dup1.sourceFile().getName() = dup2.sourceFile().getName() and dup1.sourceStartLine() < dup2.sourceStartLine() +} + +from SimilarBlock dup1, SimilarBlock dup2 +where dup1.getEquivalenceClass() = dup2.getEquivalenceClass() +and lexically_sorted(dup1, dup2) +select dup1, dup2, dup1.sourceFile().getShortName(), dup1.sourceStartLine(), dup1.sourceEndLine() \ No newline at end of file diff --git a/python/ql/test/library-tests/DuplicateCode/duplicate_test.py b/python/ql/test/library-tests/DuplicateCode/duplicate_test.py new file mode 100644 index 00000000000..a382fdefcef --- /dev/null +++ b/python/ql/test/library-tests/DuplicateCode/duplicate_test.py @@ -0,0 +1,321 @@ +#Code Duplication + + +#Exact duplication of function + +#Code copied from stdlib, copyright PSF. +#See http://www.python.org/download/releases/2.7/license/ + +def dis(x=None): + """Disassemble classes, methods, functions, or code. + + With no argument, disassemble the last traceback. + + """ + if x is None: + distb() + return + if isinstance(x, types.InstanceType): + x = x.__class__ + if hasattr(x, 'im_func'): + x = x.im_func + if hasattr(x, 'func_code'): + x = x.func_code + if hasattr(x, '__dict__'): + items = x.__dict__.items() + items.sort() + for name, x1 in items: + if isinstance(x1, _have_code): + print "Disassembly of %s:" % name + try: + dis(x1) + except TypeError, msg: + print "Sorry:", msg + print + elif hasattr(x, 'co_code'): + disassemble(x) + elif isinstance(x, str): + disassemble_string(x) + else: + raise TypeError, \ + "don't know how to disassemble %s objects" % \ + type(x).__name__ + + +#And duplicate version + +def dis2(x=None): + """Disassemble classes, methods, functions, or code. + + With no argument, disassemble the last traceback. + + """ + if x is None: + distb() + return + if isinstance(x, types.InstanceType): + x = x.__class__ + if hasattr(x, 'im_func'): + x = x.im_func + if hasattr(x, 'func_code'): + x = x.func_code + if hasattr(x, '__dict__'): + items = x.__dict__.items() + items.sort() + for name, x1 in items: + if isinstance(x1, _have_code): + print "Disassembly of %s:" % name + try: + dis(x1) + except TypeError, msg: + print "Sorry:", msg + print + elif hasattr(x, 'co_code'): + disassemble(x) + elif isinstance(x, str): + disassemble_string(x) + else: + raise TypeError, \ + "don't know how to disassemble %s objects" % \ + type(x).__name__ + +#Exactly duplicate class + +class Popen3: + """Class representing a child process. Normally, instances are created + internally by the functions popen2() and popen3().""" + + sts = -1 # Child not completed yet + + def __init__(self, cmd, capturestderr=False, bufsize=-1): + """The parameter 'cmd' is the shell command to execute in a + sub-process. On UNIX, 'cmd' may be a sequence, in which case arguments + will be passed directly to the program without shell intervention (as + with os.spawnv()). If 'cmd' is a string it will be passed to the shell + (as with os.system()). The 'capturestderr' flag, if true, specifies + that the object should capture standard error output of the child + process. The default is false. If the 'bufsize' parameter is + specified, it specifies the size of the I/O buffers to/from the child + process.""" + _cleanup() + self.cmd = cmd + p2cread, p2cwrite = os.pipe() + c2pread, c2pwrite = os.pipe() + if capturestderr: + errout, errin = os.pipe() + self.pid = os.fork() + if self.pid == 0: + # Child + os.dup2(p2cread, 0) + os.dup2(c2pwrite, 1) + if capturestderr: + os.dup2(errin, 2) + self._run_child(cmd) + os.close(p2cread) + self.tochild = os.fdopen(p2cwrite, 'w', bufsize) + os.close(c2pwrite) + self.fromchild = os.fdopen(c2pread, 'r', bufsize) + if capturestderr: + os.close(errin) + self.childerr = os.fdopen(errout, 'r', bufsize) + else: + self.childerr = None + + def __del__(self): + # In case the child hasn't been waited on, check if it's done. + self.poll(_deadstate=sys.maxint) + if self.sts < 0: + if _active is not None: + # Child is still running, keep us alive until we can wait on it. + _active.append(self) + + def _run_child(self, cmd): + if isinstance(cmd, basestring): + cmd = ['/bin/sh', '-c', cmd] + os.closerange(3, MAXFD) + try: + os.execvp(cmd[0], cmd) + finally: + os._exit(1) + + def poll(self, _deadstate=None): + """Return the exit status of the child process if it has finished, + or -1 if it hasn't finished yet.""" + if self.sts < 0: + try: + pid, sts = os.waitpid(self.pid, os.WNOHANG) + # pid will be 0 if self.pid hasn't terminated + if pid == self.pid: + self.sts = sts + except os.error: + if _deadstate is not None: + self.sts = _deadstate + return self.sts + + def wait(self): + """Wait for and return the exit status of the child process.""" + if self.sts < 0: + pid, sts = os.waitpid(self.pid, 0) + # This used to be a test, but it is believed to be + # always true, so I changed it to an assertion - mvl + assert pid == self.pid + self.sts = sts + return self.sts + + +class Popen3Again: + """Class representing a child process. Normally, instances are created + internally by the functions popen2() and popen3().""" + + sts = -1 # Child not completed yet + + def __init__(self, cmd, capturestderr=False, bufsize=-1): + """The parameter 'cmd' is the shell command to execute in a + sub-process. On UNIX, 'cmd' may be a sequence, in which case arguments + will be passed directly to the program without shell intervention (as + with os.spawnv()). If 'cmd' is a string it will be passed to the shell + (as with os.system()). The 'capturestderr' flag, if true, specifies + that the object should capture standard error output of the child + process. The default is false. If the 'bufsize' parameter is + specified, it specifies the size of the I/O buffers to/from the child + process.""" + _cleanup() + self.cmd = cmd + p2cread, p2cwrite = os.pipe() + c2pread, c2pwrite = os.pipe() + if capturestderr: + errout, errin = os.pipe() + self.pid = os.fork() + if self.pid == 0: + # Child + os.dup2(p2cread, 0) + os.dup2(c2pwrite, 1) + if capturestderr: + os.dup2(errin, 2) + self._run_child(cmd) + os.close(p2cread) + self.tochild = os.fdopen(p2cwrite, 'w', bufsize) + os.close(c2pwrite) + self.fromchild = os.fdopen(c2pread, 'r', bufsize) + if capturestderr: + os.close(errin) + self.childerr = os.fdopen(errout, 'r', bufsize) + else: + self.childerr = None + + def __del__(self): + # In case the child hasn't been waited on, check if it's done. + self.poll(_deadstate=sys.maxint) + if self.sts < 0: + if _active is not None: + # Child is still running, keep us alive until we can wait on it. + _active.append(self) + + def _run_child(self, cmd): + if isinstance(cmd, basestring): + cmd = ['/bin/sh', '-c', cmd] + os.closerange(3, MAXFD) + try: + os.execvp(cmd[0], cmd) + finally: + os._exit(1) + + def poll(self, _deadstate=None): + """Return the exit status of the child process if it has finished, + or -1 if it hasn't finished yet.""" + if self.sts < 0: + try: + pid, sts = os.waitpid(self.pid, os.WNOHANG) + # pid will be 0 if self.pid hasn't terminated + if pid == self.pid: + self.sts = sts + except os.error: + if _deadstate is not None: + self.sts = _deadstate + return self.sts + + def wait(self): + """Wait for and return the exit status of the child process.""" + if self.sts < 0: + pid, sts = os.waitpid(self.pid, 0) + # This used to be a test, but it is believed to be + # always true, so I changed it to an assertion - mvl + assert pid == self.pid + self.sts = sts + return self.sts + +#Duplicate function with identifiers changed + +def dis3(y=None): + """frobnicate classes, methods, functions, or code. + + With no argument, frobnicate the last traceback. + + """ + if y is None: + distb() + return + if isinstance(y, types.InstanceType): + y = y.__class__ + if hasattr(y, 'im_func'): + y = y.im_func + if hasattr(y, 'func_code'): + y = y.func_code + if hasattr(y, '__dict__'): + items = y.__dict__.items() + items.sort() + for name, y1 in items: + if isinstance(y1, _have_code): + print "Disassembly of %s:" % name + try: + dis(y1) + except TypeError, msg: + print "Sorry:", msg + print + elif hasattr(y, 'co_code'): + frobnicate(y) + elif isinstance(y, str): + frobnicate_string(y) + else: + raise TypeError, \ + "don't know how to frobnicate %s objects" % \ + type(y).__name__ + + +#Mostly similar function with changed identifiers + +def dis5(z=None): + """splat classes, methods, functions, or code. + + With no argument, splat the last traceback. + + """ + if z is None: + distb() + return + if isinstance(z, types.InstanceType): + z = z.__class__ + if hasattr(y, 'func_code'): + y = y.func_code + if hasattr(z, '__dict__'): + items = z.__dict__.items() + items.sort() + for name, z1 in items: + if isinstance(z1, _have_code): + print "Disassembly of %s:" % name + try: + dis(z1) + except TypeError, msg: + print "Sorry:", msg + print + elif hasattr(z, 'co_code'): + splat(z) + elif isinstance(z, str): + splat_string(z) + else: + raise TypeError, \ + "don't know how to splat %s objects" % \ + type(z).__name__ + + + diff --git a/python/ql/test/library-tests/PointsTo/calls/Argument.expected b/python/ql/test/library-tests/PointsTo/calls/Argument.expected new file mode 100644 index 00000000000..dbc7e586f47 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/calls/Argument.expected @@ -0,0 +1,15 @@ +| 19 | 0 | ControlFlowNode for w | Function f | +| 19 | 1 | ControlFlowNode for x | Function f | +| 19 | 2 | ControlFlowNode for y | Function f | +| 21 | 0 | ControlFlowNode for y | Function f | +| 21 | 1 | ControlFlowNode for w | Function f | +| 21 | 2 | ControlFlowNode for z | Function f | +| 23 | 0 | ControlFlowNode for c | Function f | +| 23 | 1 | ControlFlowNode for w | Function f | +| 23 | 2 | ControlFlowNode for z | Function f | +| 24 | 0 | ControlFlowNode for c | Function n | +| 24 | 1 | ControlFlowNode for x | Function n | +| 25 | 0 | ControlFlowNode for y | Function n | +| 25 | 1 | ControlFlowNode for z | Function n | +| 33 | 0 | ControlFlowNode for IntegerLiteral | Function foo | +| 34 | 0 | ControlFlowNode for IntegerLiteral | Function foo | diff --git a/python/ql/test/library-tests/PointsTo/calls/Argument.ql b/python/ql/test/library-tests/PointsTo/calls/Argument.ql new file mode 100644 index 00000000000..e88baf75791 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/calls/Argument.ql @@ -0,0 +1,5 @@ +import python + +from ControlFlowNode arg, FunctionObject func, int i +where arg = func.getArgumentForCall(_, i) +select arg.getLocation().getStartLine(), i, arg.toString(), func.toString() \ No newline at end of file diff --git a/python/ql/test/library-tests/PointsTo/calls/Call.expected b/python/ql/test/library-tests/PointsTo/calls/Call.expected new file mode 100644 index 00000000000..9e9c5646d89 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/calls/Call.expected @@ -0,0 +1,7 @@ +| 19 | ControlFlowNode for f() | Function f | +| 21 | ControlFlowNode for f() | Function f | +| 23 | ControlFlowNode for Attribute() | Function f | +| 24 | ControlFlowNode for Attribute() | Function n | +| 25 | ControlFlowNode for Attribute() | Function n | +| 33 | ControlFlowNode for Attribute() | Function foo | +| 34 | ControlFlowNode for Attribute() | Function foo | diff --git a/python/ql/test/library-tests/PointsTo/calls/Call.ql b/python/ql/test/library-tests/PointsTo/calls/Call.ql new file mode 100644 index 00000000000..d1cfbdad690 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/calls/Call.ql @@ -0,0 +1,7 @@ + +import python + +from ControlFlowNode call, FunctionObject func + +where call = func.getACall() +select call.getLocation().getStartLine(), call.toString(), func.toString() \ No newline at end of file diff --git a/python/ql/test/library-tests/PointsTo/calls/test.py b/python/ql/test/library-tests/PointsTo/calls/test.py new file mode 100644 index 00000000000..38667a4a6e1 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/calls/test.py @@ -0,0 +1,34 @@ + +def f(arg0, arg1, arg2): + pass + +class C(object): + + m = f + + def n(self, arg1): + pass + +w = 0 +x = 1 +y = 2 +z = 3 + +def calls(): + outer = False + f(w, x, y) + def inner(): + f(y, w, z) + c = C() + c.m(w, z) + c.n(x) + C.n(y, z) + +class D(object): + + @staticmethod + def foo(arg): + return arg + +D.foo(1) +D().foo(2) diff --git a/python/ql/test/library-tests/PointsTo/customise/test.expected b/python/ql/test/library-tests/PointsTo/customise/test.expected new file mode 100644 index 00000000000..739123d92c7 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/customise/test.expected @@ -0,0 +1,9 @@ +| 9 | ControlFlowNode for has_type_int | Function has_type_int | builtin-class function | +| 9 | ControlFlowNode for has_type_int() | has_type_int() | builtin-class int | +| 9 | ControlFlowNode for x | has_type_int() | builtin-class int | +| 10 | ControlFlowNode for has_type_float | Function has_type_float | builtin-class function | +| 10 | ControlFlowNode for has_type_float() | has_type_float() | builtin-class float | +| 10 | ControlFlowNode for y | has_type_float() | builtin-class float | +| 11 | ControlFlowNode for Tuple | Tuple | builtin-class tuple | +| 11 | ControlFlowNode for x | has_type_int() | builtin-class int | +| 11 | ControlFlowNode for y | has_type_float() | builtin-class float | diff --git a/python/ql/test/library-tests/PointsTo/customise/test.py b/python/ql/test/library-tests/PointsTo/customise/test.py new file mode 100644 index 00000000000..f6aef15a9ff --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/customise/test.py @@ -0,0 +1,11 @@ +def has_type_int(): + return untaceable() + +def has_type_float(): + return untaceable2() + +def test(): + #Ignore before this comment + x = has_type_int() + y = has_type_float() + return x, y \ No newline at end of file diff --git a/python/ql/test/library-tests/PointsTo/customise/test.ql b/python/ql/test/library-tests/PointsTo/customise/test.ql new file mode 100644 index 00000000000..dca091e2e4f --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/customise/test.ql @@ -0,0 +1,35 @@ + +import python +import semmle.python.types.Extensions + +/* Customise: Claim any function called has_type_XXX return any class + * whose name matches XXX + */ +class HasTypeFact extends CustomPointsToOriginFact { + + HasTypeFact() { + exists(FunctionObject func, string name | + func.getACall() = this and + name = func.getName() and + name.prefix("has_type_".length()) = "has_type_" + ) + } + + override predicate pointsTo(Object value, ClassObject cls) { + exists(FunctionObject func, string name | + func.getACall() = this and + name = func.getName() and + name.prefix("has_type_".length()) = "has_type_" | + cls.getName() = name.suffix("has_type_".length()) + ) and + value = this + } + +} + + +from int line, ControlFlowNode f, Object o, ClassObject c +where f.getLocation().getStartLine() = line and + exists(Comment ct | ct.getLocation().getStartLine() < line) and + f.refersTo(o, c, _) +select line, f.toString(), o.toString(), c.toString() diff --git a/python/ql/test/library-tests/PointsTo/decorators/Test.expected b/python/ql/test/library-tests/PointsTo/decorators/Test.expected new file mode 100644 index 00000000000..136adce143f --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/decorators/Test.expected @@ -0,0 +1,3 @@ +| 41 | ControlFlowNode for func1 | Function func1 | test.py:23 | +| 42 | ControlFlowNode for func2 | Function wrapper | test.py:10 | +| 43 | ControlFlowNode for func3 | Function wrapper | test.py:17 | diff --git a/python/ql/test/library-tests/PointsTo/decorators/Test.ql b/python/ql/test/library-tests/PointsTo/decorators/Test.ql new file mode 100644 index 00000000000..c873feb9b48 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/decorators/Test.ql @@ -0,0 +1,11 @@ +import python + +from ControlFlowNode f, Object o, ControlFlowNode x, int line + +where f.refersTo(o, x) and +f.getLocation().getFile().getBaseName() = "test.py" and +// We don't care about the internals of functools which vary from +// version to version, just the end result. +line = f.getLocation().getStartLine() and line > 40 + +select line, f.toString(), o.toString(), x.getLocation().toString() diff --git a/python/ql/test/library-tests/PointsTo/decorators/test.py b/python/ql/test/library-tests/PointsTo/decorators/test.py new file mode 100644 index 00000000000..1c83d17fef4 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/decorators/test.py @@ -0,0 +1,43 @@ +import functools + +def annotate(value): + def inner(func): + func.annotation = value + return func + return inner + +def wraps1(func): + def wrapper(*args): + res = func(*args) + return res + return wrapper + +def wraps2(func): + @functools.wraps(func) + def wrapper(*args): + res = func(*args) + return res + return wrapper + +@annotate(100) +def func1(): + pass + +@wraps1 +def func2(): + pass + +@wraps2 +def func3(): + pass + + + + + + + + +func1 +func2 +func3 \ No newline at end of file diff --git a/python/ql/test/library-tests/PointsTo/functions/Calls.expected b/python/ql/test/library-tests/PointsTo/functions/Calls.expected new file mode 100644 index 00000000000..23dc828d03f --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/functions/Calls.expected @@ -0,0 +1,5 @@ +| 7 | ControlFlowNode for fail() | Function fail | function | +| 11 | ControlFlowNode for print() | Builtin-function print | function | +| 12 | ControlFlowNode for Attribute() | Builtin-function exit | function | +| 15 | ControlFlowNode for bar() | Function bar | function | +| 19 | ControlFlowNode for bar() | Function bar | function | diff --git a/python/ql/test/library-tests/PointsTo/functions/Calls.ql b/python/ql/test/library-tests/PointsTo/functions/Calls.ql new file mode 100644 index 00000000000..6f1e8cf8bd3 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/functions/Calls.ql @@ -0,0 +1,12 @@ + +import python + +from CallNode call, FunctionObject func, string kind +where +(func.getAMethodCall() = call and kind = "method" + or + func.getAFunctionCall() = call and kind = "function" +) +and +call.getLocation().getFile().getShortName().matches("odasa%") +select call.getLocation().getStartLine(), call.toString(), func.toString(), kind diff --git a/python/ql/test/library-tests/PointsTo/functions/NeverReturns.expected b/python/ql/test/library-tests/PointsTo/functions/NeverReturns.expected new file mode 100644 index 00000000000..41ad8f89bc7 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/functions/NeverReturns.expected @@ -0,0 +1,2 @@ +| Builtin-function exit | +| Function fail | diff --git a/python/ql/test/library-tests/PointsTo/functions/NeverReturns.ql b/python/ql/test/library-tests/PointsTo/functions/NeverReturns.ql new file mode 100644 index 00000000000..ebb69fc7a0f --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/functions/NeverReturns.ql @@ -0,0 +1,6 @@ + +import python + +from FunctionObject f +where f.neverReturns() +select f.toString() diff --git a/python/ql/test/library-tests/PointsTo/functions/odasa6418.py b/python/ql/test/library-tests/PointsTo/functions/odasa6418.py new file mode 100644 index 00000000000..e396f2fd282 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/functions/odasa6418.py @@ -0,0 +1,24 @@ + +from __future__ import print_function +import sys + +def bar(cond): + if cond: + fail("cond true") + + +def fail(message, *args): + print('Error:', message % args, file=sys.stderr) + sys.exit(1) + +def foo(cond): + bar() + +# To get the FP result reported in ODASA-6418, +#bar must be called directly (not transitively) from the module scope +bar(unknown()) + +#The following do not trigger the bug +#foo(unknown()) +#pass + diff --git a/python/ql/test/library-tests/PointsTo/functions/test.expected b/python/ql/test/library-tests/PointsTo/functions/test.expected new file mode 100644 index 00000000000..e2959372536 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/functions/test.expected @@ -0,0 +1,2 @@ +| 9 | Function meth | +| 14 | Function meth | \ No newline at end of file diff --git a/python/ql/test/library-tests/PointsTo/functions/test.py b/python/ql/test/library-tests/PointsTo/functions/test.py new file mode 100644 index 00000000000..b72d1f3bcd8 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/functions/test.py @@ -0,0 +1,14 @@ +class Base(object): + + def meth(self): + pass + +class Derived1(Base): + + def uses_meth(self): + return self.meth() + +class Derived2(Derived1): + + def uses_meth(self): + return self.meth() diff --git a/python/ql/test/library-tests/PointsTo/functions/test.ql b/python/ql/test/library-tests/PointsTo/functions/test.ql new file mode 100644 index 00000000000..dd1a070d99f --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/functions/test.ql @@ -0,0 +1,9 @@ +import python + +from Call c, FunctionObject f + +where c.getFunc().(Attribute).getObject().(Name).getId() = "self" +and +f.getACall().getNode() = c + +select c.getLocation().getStartLine(), f.toString() diff --git a/python/ql/test/library-tests/PointsTo/general/GlobalPointsTo.expected b/python/ql/test/library-tests/PointsTo/general/GlobalPointsTo.expected new file mode 100644 index 00000000000..f4a26e6919b --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/general/GlobalPointsTo.expected @@ -0,0 +1,178 @@ +| Class Base | 147 | ControlFlowNode for FunctionExpr | Function __init__ | +| Class Base | 147 | ControlFlowNode for __init__ | Function __init__ | +| Class Base2 | 175 | ControlFlowNode for FunctionExpr | Function __init__ | +| Class Base2 | 175 | ControlFlowNode for __init__ | Function __init__ | +| Class Base2 | 178 | ControlFlowNode for IntegerLiteral | int 1 | +| Class Base2 | 178 | ControlFlowNode for x | int 1 | +| Class Derived4 | 182 | ControlFlowNode for FunctionExpr | Function __init__ | +| Class Derived4 | 182 | ControlFlowNode for __init__ | Function __init__ | +| Class E | 195 | ControlFlowNode for FunctionExpr | Function _internal | +| Class E | 195 | ControlFlowNode for _internal | Function _internal | +| Class E | 201 | ControlFlowNode for _internal | Function _internal | +| Class E | 201 | ControlFlowNode for _internal() | Function wrapper | +| Class E | 202 | ControlFlowNode for FunctionExpr | Function method | +| Class E | 202 | ControlFlowNode for method | Function wrapper | +| Class F | 250 | ControlFlowNode for g3 | NoneType None | +| Class F | 251 | ControlFlowNode for g3 | NoneType None | +| Class G | 256 | ControlFlowNode for IntegerLiteral | int 0 | +| Class G | 256 | ControlFlowNode for attr | int 0 | +| Class G | 258 | ControlFlowNode for FunctionExpr | Function __init__ | +| Class G | 258 | ControlFlowNode for __init__ | Function __init__ | +| Class G | 261 | ControlFlowNode for FunctionExpr | Function meth | +| Class G | 261 | ControlFlowNode for meth | Function meth | +| Class Ugly | 240 | ControlFlowNode for FunctionExpr | Function __init__ | +| Class Ugly | 240 | ControlFlowNode for __init__ | Function __init__ | +| Class Ugly | 244 | ControlFlowNode for FunctionExpr | Function meth | +| Class Ugly | 244 | ControlFlowNode for meth | Function meth | +| Class X | 36 | ControlFlowNode for classmethod | builtin-class classmethod | +| Class X | 36 | ControlFlowNode for classmethod() | classmethod() | +| Class X | 37 | ControlFlowNode for FunctionExpr | Function method1 | +| Class X | 37 | ControlFlowNode for method1 | classmethod() | +| Class X | 41 | ControlFlowNode for FunctionExpr | Function method2 | +| Module pointsto_test | 17 | ControlFlowNode for Attribute | list object | +| Module pointsto_test | 17 | ControlFlowNode for Compare | bool False | +| Module pointsto_test | 17 | ControlFlowNode for Compare | bool True | +| Module pointsto_test | 17 | ControlFlowNode for IntegerLiteral | int 2 | +| Module pointsto_test | 17 | ControlFlowNode for len | Builtin-function len | +| Module pointsto_test | 17 | ControlFlowNode for len() | len() | +| Module pointsto_test | 17 | ControlFlowNode for sys | Module sys | +| Module pointsto_test | 18 | ControlFlowNode for C | class C | +| Module pointsto_test | 18 | ControlFlowNode for v1 | class C | +| Module pointsto_test | 20 | ControlFlowNode for D | class D | +| Module pointsto_test | 20 | ControlFlowNode for v1 | class D | +| Module pointsto_test | 21 | ControlFlowNode for v1 | class C | +| Module pointsto_test | 21 | ControlFlowNode for v1 | class D | +| Module pointsto_test | 21 | ControlFlowNode for v1() | v1() | +| Module pointsto_test | 21 | ControlFlowNode for v2 | v1() | +| Module pointsto_test | 23 | ControlFlowNode for FunctionExpr | Function f | +| Module pointsto_test | 23 | ControlFlowNode for f | Function f | +| Module pointsto_test | 30 | ControlFlowNode for FunctionExpr | Function g | +| Module pointsto_test | 30 | ControlFlowNode for g | Function g | +| Module pointsto_test | 33 | ControlFlowNode for f | Function f | +| Module pointsto_test | 33 | ControlFlowNode for f() | C() | +| Module pointsto_test | 33 | ControlFlowNode for f() | D() | +| Module pointsto_test | 33 | ControlFlowNode for g | Function g | +| Module pointsto_test | 33 | ControlFlowNode for g() | C() | +| Module pointsto_test | 33 | ControlFlowNode for g() | D() | +| Module pointsto_test | 33 | ControlFlowNode for v4 | C() | +| Module pointsto_test | 33 | ControlFlowNode for v4 | D() | +| Module pointsto_test | 35 | ControlFlowNode for ClassExpr | class X | +| Module pointsto_test | 35 | ControlFlowNode for X | class X | +| Module pointsto_test | 35 | ControlFlowNode for object | builtin-class object | +| Module pointsto_test | 44 | ControlFlowNode for FunctionExpr | Function deco | +| Module pointsto_test | 44 | ControlFlowNode for deco | Function deco | +| Module pointsto_test | 47 | ControlFlowNode for v1 | class C | +| Module pointsto_test | 47 | ControlFlowNode for v1 | class D | +| Module pointsto_test | 48 | ControlFlowNode for v2 | v1() | +| Module pointsto_test | 50 | ControlFlowNode for v4 | C() | +| Module pointsto_test | 50 | ControlFlowNode for v4 | D() | +| Module pointsto_test | 51 | ControlFlowNode for list | builtin-class list | +| Module pointsto_test | 53 | ControlFlowNode for FunctionExpr | Function h | +| Module pointsto_test | 53 | ControlFlowNode for h | Function h | +| Module pointsto_test | 60 | ControlFlowNode for FunctionExpr | Function j | +| Module pointsto_test | 60 | ControlFlowNode for j | Function j | +| Module pointsto_test | 62 | ControlFlowNode for dict | builtin-class dict | +| Module pointsto_test | 63 | ControlFlowNode for IntegerLiteral | int 7 | +| Module pointsto_test | 63 | ControlFlowNode for dict | int 7 | +| Module pointsto_test | 64 | ControlFlowNode for dict | int 7 | +| Module pointsto_test | 65 | ControlFlowNode for tuple | builtin-class tuple | +| Module pointsto_test | 66 | ControlFlowNode for tuple | builtin-class tuple | +| Module pointsto_test | 69 | ControlFlowNode for X | class X | +| Module pointsto_test | 70 | ControlFlowNode for X | class X | +| Module pointsto_test | 72 | ControlFlowNode for ImportExpr | Module abc | +| Module pointsto_test | 72 | ControlFlowNode for ImportMember | Function abstractmethod | +| Module pointsto_test | 72 | ControlFlowNode for abstractmethod | Function abstractmethod | +| Module pointsto_test | 73 | ControlFlowNode for abstractmethod | Function abstractmethod | +| Module pointsto_test | 75 | ControlFlowNode for C | class C | +| Module pointsto_test | 75 | ControlFlowNode for C() | C() | +| Module pointsto_test | 75 | ControlFlowNode for type | builtin-class type | +| Module pointsto_test | 75 | ControlFlowNode for type() | class C | +| Module pointsto_test | 76 | ControlFlowNode for sys | Module sys | +| Module pointsto_test | 76 | ControlFlowNode for type | builtin-class type | +| Module pointsto_test | 76 | ControlFlowNode for type() | builtin-class module | +| Module pointsto_test | 78 | ControlFlowNode for type | builtin-class type | +| Module pointsto_test | 79 | ControlFlowNode for Dict | Dict | +| Module pointsto_test | 79 | ControlFlowNode for Tuple | Tuple | +| Module pointsto_test | 79 | ControlFlowNode for object | builtin-class object | +| Module pointsto_test | 79 | ControlFlowNode for type | builtin-class type | +| Module pointsto_test | 81 | ControlFlowNode for FunctionExpr | Function k | +| Module pointsto_test | 81 | ControlFlowNode for k | Function k | +| Module pointsto_test | 88 | ControlFlowNode for FunctionExpr | Function outer | +| Module pointsto_test | 88 | ControlFlowNode for outer | Function outer | +| Module pointsto_test | 95 | ControlFlowNode for FunctionExpr | Function never_none | +| Module pointsto_test | 95 | ControlFlowNode for never_none | Function never_none | +| Module pointsto_test | 104 | ControlFlowNode for FunctionExpr | Function outer_use_vars | +| Module pointsto_test | 104 | ControlFlowNode for outer_use_vars | Function outer_use_vars | +| Module pointsto_test | 112 | ControlFlowNode for FunctionExpr | Function literals_in_func | +| Module pointsto_test | 112 | ControlFlowNode for literals_in_func | Function literals_in_func | +| Module pointsto_test | 122 | ControlFlowNode for Lambda | Function lambda | +| Module pointsto_test | 122 | ControlFlowNode for y | Function lambda | +| Module pointsto_test | 124 | ControlFlowNode for FunctionExpr | Function following | +| Module pointsto_test | 124 | ControlFlowNode for following | Function following | +| Module pointsto_test | 127 | ControlFlowNode for Dict | Dict | +| Module pointsto_test | 127 | ControlFlowNode for FunctionExpr | Function params_and_defaults | +| Module pointsto_test | 127 | ControlFlowNode for IntegerLiteral | int 1 | +| Module pointsto_test | 127 | ControlFlowNode for params_and_defaults | Function params_and_defaults | +| Module pointsto_test | 132 | ControlFlowNode for FunctionExpr | Function inner_cls | +| Module pointsto_test | 132 | ControlFlowNode for inner_cls | Function inner_cls | +| Module pointsto_test | 138 | ControlFlowNode for ImportExpr | Module xyz | +| Module pointsto_test | 139 | ControlFlowNode for ImportExpr | Module xyz | +| Module pointsto_test | 139 | ControlFlowNode for xyz | Module xyz | +| Module pointsto_test | 140 | ControlFlowNode for Attribute | float 1.0 | +| Module pointsto_test | 140 | ControlFlowNode for xyz | Module xyz | +| Module pointsto_test | 141 | ControlFlowNode for z | float 3.0 | +| Module pointsto_test | 145 | ControlFlowNode for Base | class Base | +| Module pointsto_test | 145 | ControlFlowNode for ClassExpr | class Base | +| Module pointsto_test | 145 | ControlFlowNode for object | builtin-class object | +| Module pointsto_test | 155 | ControlFlowNode for Base | class Base | +| Module pointsto_test | 155 | ControlFlowNode for ClassExpr | class Derived1 | +| Module pointsto_test | 155 | ControlFlowNode for Derived1 | class Derived1 | +| Module pointsto_test | 158 | ControlFlowNode for Base | class Base | +| Module pointsto_test | 158 | ControlFlowNode for ClassExpr | class Derived2 | +| Module pointsto_test | 158 | ControlFlowNode for Derived2 | class Derived2 | +| Module pointsto_test | 161 | ControlFlowNode for Base | class Base | +| Module pointsto_test | 161 | ControlFlowNode for ClassExpr | class Derived3 | +| Module pointsto_test | 161 | ControlFlowNode for Derived3 | class Derived3 | +| Module pointsto_test | 164 | ControlFlowNode for Base | class Base | +| Module pointsto_test | 167 | ControlFlowNode for FunctionExpr | Function multiple_assignment | +| Module pointsto_test | 167 | ControlFlowNode for multiple_assignment | Function multiple_assignment | +| Module pointsto_test | 173 | ControlFlowNode for Base2 | class Base2 | +| Module pointsto_test | 173 | ControlFlowNode for ClassExpr | class Base2 | +| Module pointsto_test | 173 | ControlFlowNode for object | builtin-class object | +| Module pointsto_test | 180 | ControlFlowNode for Base2 | class Base2 | +| Module pointsto_test | 180 | ControlFlowNode for ClassExpr | class Derived4 | +| Module pointsto_test | 180 | ControlFlowNode for Derived4 | class Derived4 | +| Module pointsto_test | 187 | ControlFlowNode for FunctionExpr | Function vararg_kwarg | +| Module pointsto_test | 187 | ControlFlowNode for vararg_kwarg | Function vararg_kwarg | +| Module pointsto_test | 193 | ControlFlowNode for ClassExpr | class E | +| Module pointsto_test | 193 | ControlFlowNode for E | class E | +| Module pointsto_test | 193 | ControlFlowNode for object | builtin-class object | +| Module pointsto_test | 206 | ControlFlowNode for FunctionExpr | Function calls_next | +| Module pointsto_test | 206 | ControlFlowNode for calls_next | Function calls_next | +| Module pointsto_test | 213 | ControlFlowNode for ImportExpr | Module sys | +| Module pointsto_test | 213 | ControlFlowNode for ImportMember | Builtin-function exit | +| Module pointsto_test | 213 | ControlFlowNode for exit | Builtin-function exit | +| Module pointsto_test | 217 | ControlFlowNode for None | NoneType None | +| Module pointsto_test | 217 | ControlFlowNode for g1 | NoneType None | +| Module pointsto_test | 219 | ControlFlowNode for FunctionExpr | Function assign_global | +| Module pointsto_test | 219 | ControlFlowNode for assign_global | Function assign_global | +| Module pointsto_test | 226 | ControlFlowNode for None | NoneType None | +| Module pointsto_test | 226 | ControlFlowNode for g2 | NoneType None | +| Module pointsto_test | 228 | ControlFlowNode for FunctionExpr | Function init | +| Module pointsto_test | 228 | ControlFlowNode for init | Function init | +| Module pointsto_test | 232 | ControlFlowNode for init | Function init | +| Module pointsto_test | 232 | ControlFlowNode for init() | NoneType None | +| Module pointsto_test | 233 | ControlFlowNode for g2 | int 102 | +| Module pointsto_test | 236 | ControlFlowNode for None | NoneType None | +| Module pointsto_test | 236 | ControlFlowNode for g3 | NoneType None | +| Module pointsto_test | 238 | ControlFlowNode for ClassExpr | class Ugly | +| Module pointsto_test | 238 | ControlFlowNode for Ugly | class Ugly | +| Module pointsto_test | 238 | ControlFlowNode for object | builtin-class object | +| Module pointsto_test | 248 | ControlFlowNode for ClassExpr | class F | +| Module pointsto_test | 248 | ControlFlowNode for F | class F | +| Module pointsto_test | 248 | ControlFlowNode for object | builtin-class object | +| Module pointsto_test | 254 | ControlFlowNode for ClassExpr | class G | +| Module pointsto_test | 254 | ControlFlowNode for G | class G | +| Module pointsto_test | 254 | ControlFlowNode for object | builtin-class object | +| Module pointsto_test | 267 | ControlFlowNode for Derived4 | class Derived4 | +| Module pointsto_test | 267 | ControlFlowNode for Derived4() | Derived4() | diff --git a/python/ql/test/library-tests/PointsTo/general/GlobalPointsTo.ql b/python/ql/test/library-tests/PointsTo/general/GlobalPointsTo.ql new file mode 100644 index 00000000000..147b7835e24 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/general/GlobalPointsTo.ql @@ -0,0 +1,10 @@ + +import python +import interesting + +from int line, ControlFlowNode f, Object o, ImportTimeScope n +where +of_interest(f, line) and +f.refersTo(o) and +f.getScope() = n +select n.toString(), line, f.toString(), o.toString() diff --git a/python/ql/test/library-tests/PointsTo/general/LocalPointsTo.expected b/python/ql/test/library-tests/PointsTo/general/LocalPointsTo.expected new file mode 100644 index 00000000000..7f132556180 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/general/LocalPointsTo.expected @@ -0,0 +1,341 @@ +| 17 | ControlFlowNode for Attribute | list object | +| 17 | ControlFlowNode for Compare | bool False | +| 17 | ControlFlowNode for Compare | bool True | +| 17 | ControlFlowNode for IntegerLiteral | int 2 | +| 17 | ControlFlowNode for len | Builtin-function len | +| 17 | ControlFlowNode for len() | len() | +| 17 | ControlFlowNode for sys | Module sys | +| 18 | ControlFlowNode for C | class C | +| 18 | ControlFlowNode for v1 | class C | +| 20 | ControlFlowNode for D | class D | +| 20 | ControlFlowNode for v1 | class D | +| 21 | ControlFlowNode for v1 | class C | +| 21 | ControlFlowNode for v1 | class D | +| 21 | ControlFlowNode for v1() | v1() | +| 21 | ControlFlowNode for v2 | v1() | +| 23 | ControlFlowNode for FunctionExpr | Function f | +| 23 | ControlFlowNode for f | Function f | +| 24 | ControlFlowNode for Attribute | list object | +| 24 | ControlFlowNode for Compare | bool False | +| 24 | ControlFlowNode for Compare | bool True | +| 24 | ControlFlowNode for IntegerLiteral | int 3 | +| 24 | ControlFlowNode for len | Builtin-function len | +| 24 | ControlFlowNode for len() | len() | +| 24 | ControlFlowNode for sys | Module sys | +| 25 | ControlFlowNode for C | class C | +| 25 | ControlFlowNode for C() | C() | +| 25 | ControlFlowNode for v3 | C() | +| 27 | ControlFlowNode for D | class D | +| 27 | ControlFlowNode for D() | D() | +| 27 | ControlFlowNode for v3 | D() | +| 28 | ControlFlowNode for v3 | C() | +| 28 | ControlFlowNode for v3 | D() | +| 30 | ControlFlowNode for FunctionExpr | Function g | +| 30 | ControlFlowNode for g | Function g | +| 31 | ControlFlowNode for arg | C() | +| 31 | ControlFlowNode for arg | D() | +| 33 | ControlFlowNode for f | Function f | +| 33 | ControlFlowNode for f() | C() | +| 33 | ControlFlowNode for f() | D() | +| 33 | ControlFlowNode for g | Function g | +| 33 | ControlFlowNode for g() | C() | +| 33 | ControlFlowNode for g() | D() | +| 33 | ControlFlowNode for v4 | C() | +| 33 | ControlFlowNode for v4 | D() | +| 35 | ControlFlowNode for ClassExpr | class X | +| 35 | ControlFlowNode for X | class X | +| 35 | ControlFlowNode for object | builtin-class object | +| 36 | ControlFlowNode for classmethod | builtin-class classmethod | +| 36 | ControlFlowNode for classmethod() | classmethod() | +| 37 | ControlFlowNode for FunctionExpr | Function method1 | +| 37 | ControlFlowNode for method1 | classmethod() | +| 41 | ControlFlowNode for FunctionExpr | Function method2 | +| 44 | ControlFlowNode for FunctionExpr | Function deco | +| 44 | ControlFlowNode for deco | Function deco | +| 47 | ControlFlowNode for v1 | class C | +| 47 | ControlFlowNode for v1 | class D | +| 48 | ControlFlowNode for v2 | v1() | +| 50 | ControlFlowNode for v4 | C() | +| 50 | ControlFlowNode for v4 | D() | +| 51 | ControlFlowNode for list | builtin-class list | +| 53 | ControlFlowNode for FunctionExpr | Function h | +| 53 | ControlFlowNode for h | Function h | +| 54 | ControlFlowNode for Attribute | list object | +| 54 | ControlFlowNode for Compare | bool False | +| 54 | ControlFlowNode for Compare | bool True | +| 54 | ControlFlowNode for IntegerLiteral | int 4 | +| 54 | ControlFlowNode for len | Builtin-function len | +| 54 | ControlFlowNode for len() | len() | +| 54 | ControlFlowNode for sys | Module sys | +| 55 | ControlFlowNode for C | class C | +| 55 | ControlFlowNode for C() | C() | +| 55 | ControlFlowNode for v5 | C() | +| 57 | ControlFlowNode for D | class D | +| 57 | ControlFlowNode for D() | D() | +| 57 | ControlFlowNode for v5 | D() | +| 58 | ControlFlowNode for Tuple | Tuple | +| 58 | ControlFlowNode for list | builtin-class list | +| 58 | ControlFlowNode for list() | list() | +| 58 | ControlFlowNode for v5 | C() | +| 58 | ControlFlowNode for v5 | D() | +| 60 | ControlFlowNode for FunctionExpr | Function j | +| 60 | ControlFlowNode for j | Function j | +| 61 | ControlFlowNode for Tuple | Tuple | +| 61 | ControlFlowNode for dict | int 7 | +| 61 | ControlFlowNode for tuple | builtin-class tuple | +| 62 | ControlFlowNode for dict | builtin-class dict | +| 63 | ControlFlowNode for IntegerLiteral | int 7 | +| 63 | ControlFlowNode for dict | int 7 | +| 64 | ControlFlowNode for dict | int 7 | +| 65 | ControlFlowNode for tuple | builtin-class tuple | +| 66 | ControlFlowNode for tuple | builtin-class tuple | +| 69 | ControlFlowNode for X | class X | +| 70 | ControlFlowNode for X | class X | +| 72 | ControlFlowNode for ImportExpr | Module abc | +| 72 | ControlFlowNode for ImportMember | Function abstractmethod | +| 72 | ControlFlowNode for abstractmethod | Function abstractmethod | +| 73 | ControlFlowNode for abstractmethod | Function abstractmethod | +| 75 | ControlFlowNode for C | class C | +| 75 | ControlFlowNode for C() | C() | +| 75 | ControlFlowNode for type | builtin-class type | +| 75 | ControlFlowNode for type() | class C | +| 76 | ControlFlowNode for sys | Module sys | +| 76 | ControlFlowNode for type | builtin-class type | +| 76 | ControlFlowNode for type() | builtin-class module | +| 78 | ControlFlowNode for type | builtin-class type | +| 79 | ControlFlowNode for Dict | Dict | +| 79 | ControlFlowNode for Tuple | Tuple | +| 79 | ControlFlowNode for object | builtin-class object | +| 79 | ControlFlowNode for type | builtin-class type | +| 81 | ControlFlowNode for FunctionExpr | Function k | +| 81 | ControlFlowNode for k | Function k | +| 82 | ControlFlowNode for C | class C | +| 82 | ControlFlowNode for C() | C() | +| 82 | ControlFlowNode for type | builtin-class type | +| 82 | ControlFlowNode for type() | class C | +| 83 | ControlFlowNode for sys | Module sys | +| 83 | ControlFlowNode for type | builtin-class type | +| 83 | ControlFlowNode for type() | builtin-class module | +| 84 | ControlFlowNode for type | builtin-class type | +| 85 | ControlFlowNode for Dict | Dict | +| 85 | ControlFlowNode for Tuple | Tuple | +| 85 | ControlFlowNode for object | builtin-class object | +| 85 | ControlFlowNode for type | builtin-class type | +| 88 | ControlFlowNode for FunctionExpr | Function outer | +| 88 | ControlFlowNode for outer | Function outer | +| 89 | ControlFlowNode for IntegerLiteral | int 1 | +| 89 | ControlFlowNode for y | int 1 | +| 90 | ControlFlowNode for FunctionExpr | Function inner | +| 90 | ControlFlowNode for inner | Function inner | +| 92 | ControlFlowNode for IntegerLiteral | int 2 | +| 92 | ControlFlowNode for z | int 2 | +| 93 | ControlFlowNode for inner | Function inner | +| 95 | ControlFlowNode for FunctionExpr | Function never_none | +| 95 | ControlFlowNode for never_none | Function never_none | +| 97 | ControlFlowNode for FloatLiteral | float 1.0 | +| 97 | ControlFlowNode for y | float 1.0 | +| 99 | ControlFlowNode for None | NoneType None | +| 99 | ControlFlowNode for y | NoneType None | +| 100 | ControlFlowNode for Compare | bool False | +| 100 | ControlFlowNode for Compare | bool True | +| 100 | ControlFlowNode for None | NoneType None | +| 100 | ControlFlowNode for y | NoneType None | +| 100 | ControlFlowNode for y | float 1.0 | +| 101 | ControlFlowNode for FloatLiteral | float 0.0 | +| 101 | ControlFlowNode for y | float 0.0 | +| 102 | ControlFlowNode for y | float 0.0 | +| 102 | ControlFlowNode for y | float 1.0 | +| 104 | ControlFlowNode for FunctionExpr | Function outer_use_vars | +| 104 | ControlFlowNode for outer_use_vars | Function outer_use_vars | +| 105 | ControlFlowNode for IntegerLiteral | int 1 | +| 105 | ControlFlowNode for y | int 1 | +| 106 | ControlFlowNode for FunctionExpr | Function inner | +| 106 | ControlFlowNode for inner | Function inner | +| 108 | ControlFlowNode for IntegerLiteral | int 2 | +| 108 | ControlFlowNode for z | int 2 | +| 109 | ControlFlowNode for y | int 1 | +| 109 | ControlFlowNode for z | int 2 | +| 110 | ControlFlowNode for inner | Function inner | +| 112 | ControlFlowNode for FunctionExpr | Function literals_in_func | +| 112 | ControlFlowNode for literals_in_func | Function literals_in_func | +| 113 | ControlFlowNode for True | bool True | +| 114 | ControlFlowNode for None | NoneType None | +| 115 | ControlFlowNode for IntegerLiteral | int 1346 | +| 116 | ControlFlowNode for FloatLiteral | float 0.7 | +| 117 | ControlFlowNode for ClassExpr | class X | +| 117 | ControlFlowNode for X | class X | +| 117 | ControlFlowNode for object | builtin-class object | +| 118 | ControlFlowNode for FunctionExpr | Function f | +| 118 | ControlFlowNode for f | Function f | +| 119 | ControlFlowNode for Tuple | Tuple | +| 120 | ControlFlowNode for List | List | +| 122 | ControlFlowNode for Lambda | Function lambda | +| 122 | ControlFlowNode for following | Function following | +| 122 | ControlFlowNode for following() | NoneType None | +| 122 | ControlFlowNode for y | Function lambda | +| 124 | ControlFlowNode for FunctionExpr | Function following | +| 124 | ControlFlowNode for following | Function following | +| 127 | ControlFlowNode for Dict | Dict | +| 127 | ControlFlowNode for FunctionExpr | Function params_and_defaults | +| 127 | ControlFlowNode for IntegerLiteral | int 1 | +| 127 | ControlFlowNode for params_and_defaults | Function params_and_defaults | +| 129 | ControlFlowNode for b | Dict | +| 130 | ControlFlowNode for c | int 1 | +| 132 | ControlFlowNode for FunctionExpr | Function inner_cls | +| 132 | ControlFlowNode for inner_cls | Function inner_cls | +| 133 | ControlFlowNode for A | class A | +| 133 | ControlFlowNode for BaseException | builtin-class BaseException | +| 133 | ControlFlowNode for ClassExpr | class A | +| 135 | ControlFlowNode for A | class A | +| 135 | ControlFlowNode for A() | A() | +| 135 | ControlFlowNode for a | A() | +| 136 | ControlFlowNode for a | A() | +| 138 | ControlFlowNode for ImportExpr | Module xyz | +| 139 | ControlFlowNode for ImportExpr | Module xyz | +| 139 | ControlFlowNode for xyz | Module xyz | +| 140 | ControlFlowNode for Attribute | float 1.0 | +| 140 | ControlFlowNode for xyz | Module xyz | +| 141 | ControlFlowNode for z | float 3.0 | +| 145 | ControlFlowNode for Base | class Base | +| 145 | ControlFlowNode for ClassExpr | class Base | +| 145 | ControlFlowNode for object | builtin-class object | +| 147 | ControlFlowNode for FunctionExpr | Function __init__ | +| 147 | ControlFlowNode for __init__ | Function __init__ | +| 148 | ControlFlowNode for Compare | bool False | +| 148 | ControlFlowNode for Compare | bool True | +| 148 | ControlFlowNode for IntegerLiteral | int 1 | +| 149 | ControlFlowNode for Attribute | class Derived1 | +| 149 | ControlFlowNode for Derived1 | class Derived1 | +| 149 | ControlFlowNode for self | self | +| 150 | ControlFlowNode for Compare | bool False | +| 150 | ControlFlowNode for Compare | bool True | +| 150 | ControlFlowNode for IntegerLiteral | int 2 | +| 151 | ControlFlowNode for Attribute | class Derived2 | +| 151 | ControlFlowNode for Derived2 | class Derived2 | +| 151 | ControlFlowNode for self | self | +| 153 | ControlFlowNode for Attribute | class Derived3 | +| 153 | ControlFlowNode for Derived3 | class Derived3 | +| 153 | ControlFlowNode for self | self | +| 155 | ControlFlowNode for Base | class Base | +| 155 | ControlFlowNode for ClassExpr | class Derived1 | +| 155 | ControlFlowNode for Derived1 | class Derived1 | +| 158 | ControlFlowNode for Base | class Base | +| 158 | ControlFlowNode for ClassExpr | class Derived2 | +| 158 | ControlFlowNode for Derived2 | class Derived2 | +| 161 | ControlFlowNode for Base | class Base | +| 161 | ControlFlowNode for ClassExpr | class Derived3 | +| 161 | ControlFlowNode for Derived3 | class Derived3 | +| 164 | ControlFlowNode for Base | class Base | +| 167 | ControlFlowNode for FunctionExpr | Function multiple_assignment | +| 167 | ControlFlowNode for multiple_assignment | Function multiple_assignment | +| 168 | ControlFlowNode for Tuple | Tuple | +| 168 | ControlFlowNode for _list | builtin-class list | +| 168 | ControlFlowNode for _tuple | builtin-class tuple | +| 168 | ControlFlowNode for list | builtin-class list | +| 168 | ControlFlowNode for tuple | builtin-class tuple | +| 169 | ControlFlowNode for _tuple | builtin-class tuple | +| 170 | ControlFlowNode for _list | builtin-class list | +| 173 | ControlFlowNode for Base2 | class Base2 | +| 173 | ControlFlowNode for ClassExpr | class Base2 | +| 173 | ControlFlowNode for object | builtin-class object | +| 175 | ControlFlowNode for FunctionExpr | Function __init__ | +| 175 | ControlFlowNode for __init__ | Function __init__ | +| 178 | ControlFlowNode for IntegerLiteral | int 1 | +| 178 | ControlFlowNode for x | int 1 | +| 180 | ControlFlowNode for Base2 | class Base2 | +| 180 | ControlFlowNode for ClassExpr | class Derived4 | +| 180 | ControlFlowNode for Derived4 | class Derived4 | +| 182 | ControlFlowNode for FunctionExpr | Function __init__ | +| 182 | ControlFlowNode for __init__ | Function __init__ | +| 183 | ControlFlowNode for Attribute | super().x | +| 183 | ControlFlowNode for Derived4 | class Derived4 | +| 183 | ControlFlowNode for self | self | +| 183 | ControlFlowNode for super | builtin-class super | +| 183 | ControlFlowNode for super() | super() | +| 184 | ControlFlowNode for Attribute | super().__init__ | +| 184 | ControlFlowNode for Attribute() | NoneType None | +| 184 | ControlFlowNode for Derived4 | class Derived4 | +| 184 | ControlFlowNode for self | self | +| 184 | ControlFlowNode for super | builtin-class super | +| 184 | ControlFlowNode for super() | super() | +| 187 | ControlFlowNode for FunctionExpr | Function vararg_kwarg | +| 187 | ControlFlowNode for d | d | +| 187 | ControlFlowNode for t | t | +| 187 | ControlFlowNode for vararg_kwarg | Function vararg_kwarg | +| 188 | ControlFlowNode for t | t | +| 189 | ControlFlowNode for d | d | +| 193 | ControlFlowNode for ClassExpr | class E | +| 193 | ControlFlowNode for E | class E | +| 193 | ControlFlowNode for object | builtin-class object | +| 195 | ControlFlowNode for FunctionExpr | Function _internal | +| 195 | ControlFlowNode for _internal | Function _internal | +| 197 | ControlFlowNode for FunctionExpr | Function wrapper | +| 197 | ControlFlowNode for wrapper | Function wrapper | +| 199 | ControlFlowNode for wrapper | Function wrapper | +| 201 | ControlFlowNode for _internal | Function _internal | +| 201 | ControlFlowNode for _internal() | Function wrapper | +| 202 | ControlFlowNode for FunctionExpr | Function method | +| 202 | ControlFlowNode for args | args | +| 202 | ControlFlowNode for method | Function wrapper | +| 206 | ControlFlowNode for FunctionExpr | Function calls_next | +| 206 | ControlFlowNode for calls_next | Function calls_next | +| 207 | ControlFlowNode for iter | Builtin-function iter | +| 208 | ControlFlowNode for next | Builtin-function next | +| 213 | ControlFlowNode for ImportExpr | Module sys | +| 213 | ControlFlowNode for ImportMember | Builtin-function exit | +| 213 | ControlFlowNode for exit | Builtin-function exit | +| 217 | ControlFlowNode for None | NoneType None | +| 217 | ControlFlowNode for g1 | NoneType None | +| 219 | ControlFlowNode for FunctionExpr | Function assign_global | +| 219 | ControlFlowNode for assign_global | Function assign_global | +| 221 | ControlFlowNode for IntegerLiteral | int 101 | +| 221 | ControlFlowNode for g1 | int 101 | +| 222 | ControlFlowNode for g1 | int 101 | +| 226 | ControlFlowNode for None | NoneType None | +| 226 | ControlFlowNode for g2 | NoneType None | +| 228 | ControlFlowNode for FunctionExpr | Function init | +| 228 | ControlFlowNode for init | Function init | +| 230 | ControlFlowNode for IntegerLiteral | int 102 | +| 230 | ControlFlowNode for g2 | int 102 | +| 232 | ControlFlowNode for init | Function init | +| 232 | ControlFlowNode for init() | NoneType None | +| 233 | ControlFlowNode for g2 | int 102 | +| 236 | ControlFlowNode for None | NoneType None | +| 236 | ControlFlowNode for g3 | NoneType None | +| 238 | ControlFlowNode for ClassExpr | class Ugly | +| 238 | ControlFlowNode for Ugly | class Ugly | +| 238 | ControlFlowNode for object | builtin-class object | +| 240 | ControlFlowNode for FunctionExpr | Function __init__ | +| 240 | ControlFlowNode for __init__ | Function __init__ | +| 242 | ControlFlowNode for IntegerLiteral | int 103 | +| 242 | ControlFlowNode for g3 | int 103 | +| 244 | ControlFlowNode for FunctionExpr | Function meth | +| 244 | ControlFlowNode for meth | Function meth | +| 245 | ControlFlowNode for g3 | int 103 | +| 248 | ControlFlowNode for ClassExpr | class F | +| 248 | ControlFlowNode for F | class F | +| 248 | ControlFlowNode for object | builtin-class object | +| 250 | ControlFlowNode for g3 | NoneType None | +| 251 | ControlFlowNode for g3 | NoneType None | +| 254 | ControlFlowNode for ClassExpr | class G | +| 254 | ControlFlowNode for G | class G | +| 254 | ControlFlowNode for object | builtin-class object | +| 256 | ControlFlowNode for IntegerLiteral | int 0 | +| 256 | ControlFlowNode for attr | int 0 | +| 258 | ControlFlowNode for FunctionExpr | Function __init__ | +| 258 | ControlFlowNode for __init__ | Function __init__ | +| 259 | ControlFlowNode for Attribute | int 1 | +| 259 | ControlFlowNode for IntegerLiteral | int 1 | +| 259 | ControlFlowNode for self | self | +| 261 | ControlFlowNode for FunctionExpr | Function meth | +| 261 | ControlFlowNode for meth | Function meth | +| 262 | ControlFlowNode for Attribute | int 2 | +| 262 | ControlFlowNode for IntegerLiteral | int 2 | +| 262 | ControlFlowNode for self | self | +| 263 | ControlFlowNode for Attribute | int 3 | +| 263 | ControlFlowNode for IntegerLiteral | int 3 | +| 263 | ControlFlowNode for self | self | +| 264 | ControlFlowNode for Attribute | int 3 | +| 264 | ControlFlowNode for self | self | +| 267 | ControlFlowNode for Derived4 | class Derived4 | +| 267 | ControlFlowNode for Derived4() | Derived4() | diff --git a/python/ql/test/library-tests/PointsTo/general/LocalPointsTo.ql b/python/ql/test/library-tests/PointsTo/general/LocalPointsTo.ql new file mode 100644 index 00000000000..a3e5d40486d --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/general/LocalPointsTo.ql @@ -0,0 +1,16 @@ +/** + * @name LocalPointsTo + * @description Insert description here... + * @kind problem + * @problem.severity warning + */ + +import python +import interesting +import Util + +from int line, ControlFlowNode f, Object o +where + of_interest(f, line) and + f.refersTo(o) +select line, f.toString(), repr(o) diff --git a/python/ql/test/library-tests/PointsTo/general/LocalPointsToType.expected b/python/ql/test/library-tests/PointsTo/general/LocalPointsToType.expected new file mode 100644 index 00000000000..2f1d347892d --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/general/LocalPointsToType.expected @@ -0,0 +1,344 @@ +| 17 | ControlFlowNode for Attribute | list object | builtin-class list | +| 17 | ControlFlowNode for Compare | bool False | builtin-class bool | +| 17 | ControlFlowNode for Compare | bool True | builtin-class bool | +| 17 | ControlFlowNode for IntegerLiteral | int 2 | builtin-class int | +| 17 | ControlFlowNode for len | Builtin-function len | builtin-class builtin_function_or_method | +| 17 | ControlFlowNode for len() | len() | builtin-class int | +| 17 | ControlFlowNode for sys | Module sys | builtin-class module | +| 18 | ControlFlowNode for C | class C | builtin-class type | +| 18 | ControlFlowNode for v1 | class C | builtin-class type | +| 20 | ControlFlowNode for D | class D | builtin-class type | +| 20 | ControlFlowNode for v1 | class D | builtin-class type | +| 21 | ControlFlowNode for v1 | class C | builtin-class type | +| 21 | ControlFlowNode for v1 | class D | builtin-class type | +| 21 | ControlFlowNode for v1() | v1() | class C | +| 21 | ControlFlowNode for v1() | v1() | class D | +| 21 | ControlFlowNode for v2 | v1() | class C | +| 21 | ControlFlowNode for v2 | v1() | class D | +| 23 | ControlFlowNode for FunctionExpr | Function f | builtin-class function | +| 23 | ControlFlowNode for f | Function f | builtin-class function | +| 24 | ControlFlowNode for Attribute | list object | builtin-class list | +| 24 | ControlFlowNode for Compare | bool False | builtin-class bool | +| 24 | ControlFlowNode for Compare | bool True | builtin-class bool | +| 24 | ControlFlowNode for IntegerLiteral | int 3 | builtin-class int | +| 24 | ControlFlowNode for len | Builtin-function len | builtin-class builtin_function_or_method | +| 24 | ControlFlowNode for len() | len() | builtin-class int | +| 24 | ControlFlowNode for sys | Module sys | builtin-class module | +| 25 | ControlFlowNode for C | class C | builtin-class type | +| 25 | ControlFlowNode for C() | C() | class C | +| 25 | ControlFlowNode for v3 | C() | class C | +| 27 | ControlFlowNode for D | class D | builtin-class type | +| 27 | ControlFlowNode for D() | D() | class D | +| 27 | ControlFlowNode for v3 | D() | class D | +| 28 | ControlFlowNode for v3 | C() | class C | +| 28 | ControlFlowNode for v3 | D() | class D | +| 30 | ControlFlowNode for FunctionExpr | Function g | builtin-class function | +| 30 | ControlFlowNode for g | Function g | builtin-class function | +| 31 | ControlFlowNode for arg | C() | class C | +| 31 | ControlFlowNode for arg | D() | class D | +| 33 | ControlFlowNode for f | Function f | builtin-class function | +| 33 | ControlFlowNode for f() | C() | class C | +| 33 | ControlFlowNode for f() | D() | class D | +| 33 | ControlFlowNode for g | Function g | builtin-class function | +| 33 | ControlFlowNode for g() | C() | class C | +| 33 | ControlFlowNode for g() | D() | class D | +| 33 | ControlFlowNode for v4 | C() | class C | +| 33 | ControlFlowNode for v4 | D() | class D | +| 35 | ControlFlowNode for ClassExpr | class X | builtin-class type | +| 35 | ControlFlowNode for X | class X | builtin-class type | +| 35 | ControlFlowNode for object | builtin-class object | builtin-class type | +| 36 | ControlFlowNode for classmethod | builtin-class classmethod | builtin-class type | +| 36 | ControlFlowNode for classmethod() | classmethod() | builtin-class classmethod | +| 37 | ControlFlowNode for FunctionExpr | Function method1 | builtin-class function | +| 37 | ControlFlowNode for method1 | classmethod() | builtin-class classmethod | +| 41 | ControlFlowNode for FunctionExpr | Function method2 | builtin-class function | +| 44 | ControlFlowNode for FunctionExpr | Function deco | builtin-class function | +| 44 | ControlFlowNode for deco | Function deco | builtin-class function | +| 47 | ControlFlowNode for v1 | class C | builtin-class type | +| 47 | ControlFlowNode for v1 | class D | builtin-class type | +| 48 | ControlFlowNode for v2 | v1() | class C | +| 48 | ControlFlowNode for v2 | v1() | class D | +| 50 | ControlFlowNode for v4 | C() | class C | +| 50 | ControlFlowNode for v4 | D() | class D | +| 51 | ControlFlowNode for list | builtin-class list | builtin-class type | +| 53 | ControlFlowNode for FunctionExpr | Function h | builtin-class function | +| 53 | ControlFlowNode for h | Function h | builtin-class function | +| 54 | ControlFlowNode for Attribute | list object | builtin-class list | +| 54 | ControlFlowNode for Compare | bool False | builtin-class bool | +| 54 | ControlFlowNode for Compare | bool True | builtin-class bool | +| 54 | ControlFlowNode for IntegerLiteral | int 4 | builtin-class int | +| 54 | ControlFlowNode for len | Builtin-function len | builtin-class builtin_function_or_method | +| 54 | ControlFlowNode for len() | len() | builtin-class int | +| 54 | ControlFlowNode for sys | Module sys | builtin-class module | +| 55 | ControlFlowNode for C | class C | builtin-class type | +| 55 | ControlFlowNode for C() | C() | class C | +| 55 | ControlFlowNode for v5 | C() | class C | +| 57 | ControlFlowNode for D | class D | builtin-class type | +| 57 | ControlFlowNode for D() | D() | class D | +| 57 | ControlFlowNode for v5 | D() | class D | +| 58 | ControlFlowNode for Tuple | Tuple | builtin-class tuple | +| 58 | ControlFlowNode for list | builtin-class list | builtin-class type | +| 58 | ControlFlowNode for list() | list() | builtin-class list | +| 58 | ControlFlowNode for v5 | C() | class C | +| 58 | ControlFlowNode for v5 | D() | class D | +| 60 | ControlFlowNode for FunctionExpr | Function j | builtin-class function | +| 60 | ControlFlowNode for j | Function j | builtin-class function | +| 61 | ControlFlowNode for Tuple | Tuple | builtin-class tuple | +| 61 | ControlFlowNode for dict | int 7 | builtin-class int | +| 61 | ControlFlowNode for tuple | builtin-class tuple | builtin-class type | +| 62 | ControlFlowNode for dict | builtin-class dict | builtin-class type | +| 63 | ControlFlowNode for IntegerLiteral | int 7 | builtin-class int | +| 63 | ControlFlowNode for dict | int 7 | builtin-class int | +| 64 | ControlFlowNode for dict | int 7 | builtin-class int | +| 65 | ControlFlowNode for tuple | builtin-class tuple | builtin-class type | +| 66 | ControlFlowNode for tuple | builtin-class tuple | builtin-class type | +| 69 | ControlFlowNode for X | class X | builtin-class type | +| 70 | ControlFlowNode for X | class X | builtin-class type | +| 72 | ControlFlowNode for ImportExpr | Module abc | builtin-class module | +| 72 | ControlFlowNode for ImportMember | Function abstractmethod | builtin-class function | +| 72 | ControlFlowNode for abstractmethod | Function abstractmethod | builtin-class function | +| 73 | ControlFlowNode for abstractmethod | Function abstractmethod | builtin-class function | +| 75 | ControlFlowNode for C | class C | builtin-class type | +| 75 | ControlFlowNode for C() | C() | class C | +| 75 | ControlFlowNode for type | builtin-class type | builtin-class type | +| 75 | ControlFlowNode for type() | class C | builtin-class type | +| 76 | ControlFlowNode for sys | Module sys | builtin-class module | +| 76 | ControlFlowNode for type | builtin-class type | builtin-class type | +| 76 | ControlFlowNode for type() | builtin-class module | builtin-class type | +| 78 | ControlFlowNode for type | builtin-class type | builtin-class type | +| 79 | ControlFlowNode for Dict | Dict | builtin-class dict | +| 79 | ControlFlowNode for Tuple | Tuple | builtin-class tuple | +| 79 | ControlFlowNode for object | builtin-class object | builtin-class type | +| 79 | ControlFlowNode for type | builtin-class type | builtin-class type | +| 81 | ControlFlowNode for FunctionExpr | Function k | builtin-class function | +| 81 | ControlFlowNode for k | Function k | builtin-class function | +| 82 | ControlFlowNode for C | class C | builtin-class type | +| 82 | ControlFlowNode for C() | C() | class C | +| 82 | ControlFlowNode for type | builtin-class type | builtin-class type | +| 82 | ControlFlowNode for type() | class C | builtin-class type | +| 83 | ControlFlowNode for sys | Module sys | builtin-class module | +| 83 | ControlFlowNode for type | builtin-class type | builtin-class type | +| 83 | ControlFlowNode for type() | builtin-class module | builtin-class type | +| 84 | ControlFlowNode for type | builtin-class type | builtin-class type | +| 85 | ControlFlowNode for Dict | Dict | builtin-class dict | +| 85 | ControlFlowNode for Tuple | Tuple | builtin-class tuple | +| 85 | ControlFlowNode for object | builtin-class object | builtin-class type | +| 85 | ControlFlowNode for type | builtin-class type | builtin-class type | +| 88 | ControlFlowNode for FunctionExpr | Function outer | builtin-class function | +| 88 | ControlFlowNode for outer | Function outer | builtin-class function | +| 89 | ControlFlowNode for IntegerLiteral | int 1 | builtin-class int | +| 89 | ControlFlowNode for y | int 1 | builtin-class int | +| 90 | ControlFlowNode for FunctionExpr | Function inner | builtin-class function | +| 90 | ControlFlowNode for inner | Function inner | builtin-class function | +| 92 | ControlFlowNode for IntegerLiteral | int 2 | builtin-class int | +| 92 | ControlFlowNode for z | int 2 | builtin-class int | +| 93 | ControlFlowNode for inner | Function inner | builtin-class function | +| 95 | ControlFlowNode for FunctionExpr | Function never_none | builtin-class function | +| 95 | ControlFlowNode for never_none | Function never_none | builtin-class function | +| 97 | ControlFlowNode for FloatLiteral | float 1.0 | builtin-class float | +| 97 | ControlFlowNode for y | float 1.0 | builtin-class float | +| 99 | ControlFlowNode for None | NoneType None | builtin-class NoneType | +| 99 | ControlFlowNode for y | NoneType None | builtin-class NoneType | +| 100 | ControlFlowNode for Compare | bool False | builtin-class bool | +| 100 | ControlFlowNode for Compare | bool True | builtin-class bool | +| 100 | ControlFlowNode for None | NoneType None | builtin-class NoneType | +| 100 | ControlFlowNode for y | NoneType None | builtin-class NoneType | +| 100 | ControlFlowNode for y | float 1.0 | builtin-class float | +| 101 | ControlFlowNode for FloatLiteral | float 0.0 | builtin-class float | +| 101 | ControlFlowNode for y | float 0.0 | builtin-class float | +| 102 | ControlFlowNode for y | float 0.0 | builtin-class float | +| 102 | ControlFlowNode for y | float 1.0 | builtin-class float | +| 104 | ControlFlowNode for FunctionExpr | Function outer_use_vars | builtin-class function | +| 104 | ControlFlowNode for outer_use_vars | Function outer_use_vars | builtin-class function | +| 105 | ControlFlowNode for IntegerLiteral | int 1 | builtin-class int | +| 105 | ControlFlowNode for y | int 1 | builtin-class int | +| 106 | ControlFlowNode for FunctionExpr | Function inner | builtin-class function | +| 106 | ControlFlowNode for inner | Function inner | builtin-class function | +| 108 | ControlFlowNode for IntegerLiteral | int 2 | builtin-class int | +| 108 | ControlFlowNode for z | int 2 | builtin-class int | +| 109 | ControlFlowNode for y | int 1 | builtin-class int | +| 109 | ControlFlowNode for z | int 2 | builtin-class int | +| 110 | ControlFlowNode for inner | Function inner | builtin-class function | +| 112 | ControlFlowNode for FunctionExpr | Function literals_in_func | builtin-class function | +| 112 | ControlFlowNode for literals_in_func | Function literals_in_func | builtin-class function | +| 113 | ControlFlowNode for True | bool True | builtin-class bool | +| 114 | ControlFlowNode for None | NoneType None | builtin-class NoneType | +| 115 | ControlFlowNode for IntegerLiteral | int 1346 | builtin-class int | +| 116 | ControlFlowNode for FloatLiteral | float 0.7 | builtin-class float | +| 117 | ControlFlowNode for ClassExpr | class X | builtin-class type | +| 117 | ControlFlowNode for X | class X | builtin-class type | +| 117 | ControlFlowNode for object | builtin-class object | builtin-class type | +| 118 | ControlFlowNode for FunctionExpr | Function f | builtin-class function | +| 118 | ControlFlowNode for f | Function f | builtin-class function | +| 119 | ControlFlowNode for Tuple | Tuple | builtin-class tuple | +| 120 | ControlFlowNode for List | List | builtin-class list | +| 122 | ControlFlowNode for Lambda | Function lambda | builtin-class function | +| 122 | ControlFlowNode for following | Function following | builtin-class function | +| 122 | ControlFlowNode for following() | NoneType None | builtin-class NoneType | +| 122 | ControlFlowNode for y | Function lambda | builtin-class function | +| 124 | ControlFlowNode for FunctionExpr | Function following | builtin-class function | +| 124 | ControlFlowNode for following | Function following | builtin-class function | +| 127 | ControlFlowNode for Dict | Dict | builtin-class dict | +| 127 | ControlFlowNode for FunctionExpr | Function params_and_defaults | builtin-class function | +| 127 | ControlFlowNode for IntegerLiteral | int 1 | builtin-class int | +| 127 | ControlFlowNode for params_and_defaults | Function params_and_defaults | builtin-class function | +| 129 | ControlFlowNode for b | Dict | builtin-class dict | +| 130 | ControlFlowNode for c | int 1 | builtin-class int | +| 132 | ControlFlowNode for FunctionExpr | Function inner_cls | builtin-class function | +| 132 | ControlFlowNode for inner_cls | Function inner_cls | builtin-class function | +| 133 | ControlFlowNode for A | class A | builtin-class type | +| 133 | ControlFlowNode for BaseException | builtin-class BaseException | builtin-class type | +| 133 | ControlFlowNode for ClassExpr | class A | builtin-class type | +| 135 | ControlFlowNode for A | class A | builtin-class type | +| 135 | ControlFlowNode for A() | A() | class A | +| 135 | ControlFlowNode for a | A() | class A | +| 136 | ControlFlowNode for a | A() | class A | +| 138 | ControlFlowNode for ImportExpr | Module xyz | builtin-class module | +| 139 | ControlFlowNode for ImportExpr | Module xyz | builtin-class module | +| 139 | ControlFlowNode for xyz | Module xyz | builtin-class module | +| 140 | ControlFlowNode for Attribute | float 1.0 | builtin-class float | +| 140 | ControlFlowNode for xyz | Module xyz | builtin-class module | +| 141 | ControlFlowNode for z | float 3.0 | builtin-class float | +| 145 | ControlFlowNode for Base | class Base | builtin-class type | +| 145 | ControlFlowNode for ClassExpr | class Base | builtin-class type | +| 145 | ControlFlowNode for object | builtin-class object | builtin-class type | +| 147 | ControlFlowNode for FunctionExpr | Function __init__ | builtin-class function | +| 147 | ControlFlowNode for __init__ | Function __init__ | builtin-class function | +| 148 | ControlFlowNode for Compare | bool False | builtin-class bool | +| 148 | ControlFlowNode for Compare | bool True | builtin-class bool | +| 148 | ControlFlowNode for IntegerLiteral | int 1 | builtin-class int | +| 149 | ControlFlowNode for Attribute | class Derived1 | builtin-class type | +| 149 | ControlFlowNode for Derived1 | class Derived1 | builtin-class type | +| 149 | ControlFlowNode for self | self | class Base | +| 150 | ControlFlowNode for Compare | bool False | builtin-class bool | +| 150 | ControlFlowNode for Compare | bool True | builtin-class bool | +| 150 | ControlFlowNode for IntegerLiteral | int 2 | builtin-class int | +| 151 | ControlFlowNode for Attribute | class Derived2 | builtin-class type | +| 151 | ControlFlowNode for Derived2 | class Derived2 | builtin-class type | +| 151 | ControlFlowNode for self | self | class Base | +| 153 | ControlFlowNode for Attribute | class Derived3 | builtin-class type | +| 153 | ControlFlowNode for Derived3 | class Derived3 | builtin-class type | +| 153 | ControlFlowNode for self | self | class Base | +| 155 | ControlFlowNode for Base | class Base | builtin-class type | +| 155 | ControlFlowNode for ClassExpr | class Derived1 | builtin-class type | +| 155 | ControlFlowNode for Derived1 | class Derived1 | builtin-class type | +| 158 | ControlFlowNode for Base | class Base | builtin-class type | +| 158 | ControlFlowNode for ClassExpr | class Derived2 | builtin-class type | +| 158 | ControlFlowNode for Derived2 | class Derived2 | builtin-class type | +| 161 | ControlFlowNode for Base | class Base | builtin-class type | +| 161 | ControlFlowNode for ClassExpr | class Derived3 | builtin-class type | +| 161 | ControlFlowNode for Derived3 | class Derived3 | builtin-class type | +| 164 | ControlFlowNode for Base | class Base | builtin-class type | +| 167 | ControlFlowNode for FunctionExpr | Function multiple_assignment | builtin-class function | +| 167 | ControlFlowNode for multiple_assignment | Function multiple_assignment | builtin-class function | +| 168 | ControlFlowNode for Tuple | Tuple | builtin-class tuple | +| 168 | ControlFlowNode for _list | builtin-class list | builtin-class type | +| 168 | ControlFlowNode for _tuple | builtin-class tuple | builtin-class type | +| 168 | ControlFlowNode for list | builtin-class list | builtin-class type | +| 168 | ControlFlowNode for tuple | builtin-class tuple | builtin-class type | +| 169 | ControlFlowNode for _tuple | builtin-class tuple | builtin-class type | +| 170 | ControlFlowNode for _list | builtin-class list | builtin-class type | +| 173 | ControlFlowNode for Base2 | class Base2 | builtin-class type | +| 173 | ControlFlowNode for ClassExpr | class Base2 | builtin-class type | +| 173 | ControlFlowNode for object | builtin-class object | builtin-class type | +| 175 | ControlFlowNode for FunctionExpr | Function __init__ | builtin-class function | +| 175 | ControlFlowNode for __init__ | Function __init__ | builtin-class function | +| 178 | ControlFlowNode for IntegerLiteral | int 1 | builtin-class int | +| 178 | ControlFlowNode for x | int 1 | builtin-class int | +| 180 | ControlFlowNode for Base2 | class Base2 | builtin-class type | +| 180 | ControlFlowNode for ClassExpr | class Derived4 | builtin-class type | +| 180 | ControlFlowNode for Derived4 | class Derived4 | builtin-class type | +| 182 | ControlFlowNode for FunctionExpr | Function __init__ | builtin-class function | +| 182 | ControlFlowNode for __init__ | Function __init__ | builtin-class function | +| 183 | ControlFlowNode for Attribute | super().x | builtin-class method | +| 183 | ControlFlowNode for Derived4 | class Derived4 | builtin-class type | +| 183 | ControlFlowNode for self | self | class Derived4 | +| 183 | ControlFlowNode for super | builtin-class super | builtin-class type | +| 183 | ControlFlowNode for super() | super() | builtin-class super | +| 184 | ControlFlowNode for Attribute | super().__init__ | builtin-class method | +| 184 | ControlFlowNode for Attribute() | NoneType None | builtin-class NoneType | +| 184 | ControlFlowNode for Derived4 | class Derived4 | builtin-class type | +| 184 | ControlFlowNode for self | self | class Derived4 | +| 184 | ControlFlowNode for super | builtin-class super | builtin-class type | +| 184 | ControlFlowNode for super() | super() | builtin-class super | +| 187 | ControlFlowNode for FunctionExpr | Function vararg_kwarg | builtin-class function | +| 187 | ControlFlowNode for d | d | builtin-class dict | +| 187 | ControlFlowNode for t | t | builtin-class tuple | +| 187 | ControlFlowNode for vararg_kwarg | Function vararg_kwarg | builtin-class function | +| 188 | ControlFlowNode for t | t | builtin-class tuple | +| 189 | ControlFlowNode for d | d | builtin-class dict | +| 193 | ControlFlowNode for ClassExpr | class E | builtin-class type | +| 193 | ControlFlowNode for E | class E | builtin-class type | +| 193 | ControlFlowNode for object | builtin-class object | builtin-class type | +| 195 | ControlFlowNode for FunctionExpr | Function _internal | builtin-class function | +| 195 | ControlFlowNode for _internal | Function _internal | builtin-class function | +| 197 | ControlFlowNode for FunctionExpr | Function wrapper | builtin-class function | +| 197 | ControlFlowNode for wrapper | Function wrapper | builtin-class function | +| 199 | ControlFlowNode for wrapper | Function wrapper | builtin-class function | +| 201 | ControlFlowNode for _internal | Function _internal | builtin-class function | +| 201 | ControlFlowNode for _internal() | Function wrapper | builtin-class function | +| 202 | ControlFlowNode for FunctionExpr | Function method | builtin-class function | +| 202 | ControlFlowNode for args | args | builtin-class tuple | +| 202 | ControlFlowNode for method | Function wrapper | builtin-class function | +| 206 | ControlFlowNode for FunctionExpr | Function calls_next | builtin-class function | +| 206 | ControlFlowNode for calls_next | Function calls_next | builtin-class function | +| 207 | ControlFlowNode for iter | Builtin-function iter | builtin-class builtin_function_or_method | +| 208 | ControlFlowNode for next | Builtin-function next | builtin-class builtin_function_or_method | +| 213 | ControlFlowNode for ImportExpr | Module sys | builtin-class module | +| 213 | ControlFlowNode for ImportMember | Builtin-function exit | builtin-class builtin_function_or_method | +| 213 | ControlFlowNode for exit | Builtin-function exit | builtin-class builtin_function_or_method | +| 217 | ControlFlowNode for None | NoneType None | builtin-class NoneType | +| 217 | ControlFlowNode for g1 | NoneType None | builtin-class NoneType | +| 219 | ControlFlowNode for FunctionExpr | Function assign_global | builtin-class function | +| 219 | ControlFlowNode for assign_global | Function assign_global | builtin-class function | +| 221 | ControlFlowNode for IntegerLiteral | int 101 | builtin-class int | +| 221 | ControlFlowNode for g1 | int 101 | builtin-class int | +| 222 | ControlFlowNode for g1 | int 101 | builtin-class int | +| 226 | ControlFlowNode for None | NoneType None | builtin-class NoneType | +| 226 | ControlFlowNode for g2 | NoneType None | builtin-class NoneType | +| 228 | ControlFlowNode for FunctionExpr | Function init | builtin-class function | +| 228 | ControlFlowNode for init | Function init | builtin-class function | +| 230 | ControlFlowNode for IntegerLiteral | int 102 | builtin-class int | +| 230 | ControlFlowNode for g2 | int 102 | builtin-class int | +| 232 | ControlFlowNode for init | Function init | builtin-class function | +| 232 | ControlFlowNode for init() | NoneType None | builtin-class NoneType | +| 233 | ControlFlowNode for g2 | int 102 | builtin-class int | +| 236 | ControlFlowNode for None | NoneType None | builtin-class NoneType | +| 236 | ControlFlowNode for g3 | NoneType None | builtin-class NoneType | +| 238 | ControlFlowNode for ClassExpr | class Ugly | builtin-class type | +| 238 | ControlFlowNode for Ugly | class Ugly | builtin-class type | +| 238 | ControlFlowNode for object | builtin-class object | builtin-class type | +| 240 | ControlFlowNode for FunctionExpr | Function __init__ | builtin-class function | +| 240 | ControlFlowNode for __init__ | Function __init__ | builtin-class function | +| 242 | ControlFlowNode for IntegerLiteral | int 103 | builtin-class int | +| 242 | ControlFlowNode for g3 | int 103 | builtin-class int | +| 244 | ControlFlowNode for FunctionExpr | Function meth | builtin-class function | +| 244 | ControlFlowNode for meth | Function meth | builtin-class function | +| 245 | ControlFlowNode for g3 | int 103 | builtin-class int | +| 248 | ControlFlowNode for ClassExpr | class F | builtin-class type | +| 248 | ControlFlowNode for F | class F | builtin-class type | +| 248 | ControlFlowNode for object | builtin-class object | builtin-class type | +| 250 | ControlFlowNode for g3 | NoneType None | builtin-class NoneType | +| 251 | ControlFlowNode for g3 | NoneType None | builtin-class NoneType | +| 254 | ControlFlowNode for ClassExpr | class G | builtin-class type | +| 254 | ControlFlowNode for G | class G | builtin-class type | +| 254 | ControlFlowNode for object | builtin-class object | builtin-class type | +| 256 | ControlFlowNode for IntegerLiteral | int 0 | builtin-class int | +| 256 | ControlFlowNode for attr | int 0 | builtin-class int | +| 258 | ControlFlowNode for FunctionExpr | Function __init__ | builtin-class function | +| 258 | ControlFlowNode for __init__ | Function __init__ | builtin-class function | +| 259 | ControlFlowNode for Attribute | int 1 | builtin-class int | +| 259 | ControlFlowNode for IntegerLiteral | int 1 | builtin-class int | +| 259 | ControlFlowNode for self | self | class G | +| 261 | ControlFlowNode for FunctionExpr | Function meth | builtin-class function | +| 261 | ControlFlowNode for meth | Function meth | builtin-class function | +| 262 | ControlFlowNode for Attribute | int 2 | builtin-class int | +| 262 | ControlFlowNode for IntegerLiteral | int 2 | builtin-class int | +| 262 | ControlFlowNode for self | self | class G | +| 263 | ControlFlowNode for Attribute | int 3 | builtin-class int | +| 263 | ControlFlowNode for IntegerLiteral | int 3 | builtin-class int | +| 263 | ControlFlowNode for self | self | class G | +| 264 | ControlFlowNode for Attribute | int 3 | builtin-class int | +| 264 | ControlFlowNode for self | self | class G | +| 267 | ControlFlowNode for Derived4 | class Derived4 | builtin-class type | +| 267 | ControlFlowNode for Derived4() | Derived4() | class Derived4 | diff --git a/python/ql/test/library-tests/PointsTo/general/LocalPointsToType.ql b/python/ql/test/library-tests/PointsTo/general/LocalPointsToType.ql new file mode 100644 index 00000000000..693d0b2b84b --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/general/LocalPointsToType.ql @@ -0,0 +1,10 @@ + +import python +import interesting +import Util + +from int line, ControlFlowNode f, Object o, ClassObject cls +where + of_interest(f, line) and + f.refersTo(o, cls, _) +select line, f.toString(), repr(o), repr(cls) diff --git a/python/ql/test/library-tests/PointsTo/general/Util.qll b/python/ql/test/library-tests/PointsTo/general/Util.qll new file mode 100644 index 00000000000..f75ed24f4f0 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/general/Util.qll @@ -0,0 +1,10 @@ +import python + +string repr(Object o) { + not o instanceof StringObject and not o = theBoundMethodType() and result = o.toString() + or + /* Work around differing names in 2/3 */ + result = "'" + o.(StringObject).getText() + "'" + or + o = theBoundMethodType() and result = "builtin-class method" +} diff --git a/python/ql/test/library-tests/PointsTo/general/interesting.qll b/python/ql/test/library-tests/PointsTo/general/interesting.qll new file mode 100644 index 00000000000..2a5259dd176 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/general/interesting.qll @@ -0,0 +1,14 @@ + +import python + +predicate of_interest(ControlFlowNode n, int line) { + exists(Location l, File f | l = n.getLocation() | + line = l.getStartLine() and + f = l.getFile() and + f.getName().matches("%test.py%") and + exists(Comment c | + c.getLocation().getStartLine() < line and + c.getLocation().getFile() = f + ) + ) +} diff --git a/python/ql/test/library-tests/PointsTo/general/options b/python/ql/test/library-tests/PointsTo/general/options new file mode 100644 index 00000000000..b91afde0767 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/general/options @@ -0,0 +1 @@ +semmle-extractor-options: --max-import-depth=2 diff --git a/python/ql/test/library-tests/PointsTo/general/pointsto_test.py b/python/ql/test/library-tests/PointsTo/general/pointsto_test.py new file mode 100644 index 00000000000..26fcce71ef9 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/general/pointsto_test.py @@ -0,0 +1,267 @@ +from __future__ import unicode_literals +import sys +class C(object): + + x = 'C_x' + + def __init__(self): + self.y = 'c_y' + +class D(object): + + x = 'D_x' + + def __init__(self): + self.y = 'd_y' +#Comment here +if len(sys.argv) > 2: + v1 = C +else: + v1 = D +v2 = v1() + +def f(): + if len(sys.argv) > 3: + v3 = C() + else: + v3 = D() + return v3 + +def g(arg): + return arg + +v4 = g(f()) + +class X(object): + @classmethod + def method1(cls): + pass + + @deco + def method2(self): + pass + +def deco(f): + return f + +v1 +v2 +v3 +v4 +list + +def h(args): + if len(sys.argv) > 4: + v5 = C() + else: + v5 = D() + return v5, list(args) + +def j(): + return tuple, dict +dict +dict = 7 +dict +tuple = tuple +tuple + + +X.method1 +X.method2 + +from abc import abstractmethod +abstractmethod + +type(C()) +type(sys) +from module import unknown +type(unknown) +type(name, (object,), {}) + +def k(arg): + type(C()) + type(sys) + type(arg) + type(name, (object,), {}) + +#Value of variables in inner functions +def outer(x): + y = 1 + def inner(): + return y + z + z = 2; + return inner + +def never_none(x): + if test(x): + y = 1.0 + else: + y = None + if y is None: + y = 0.0 + return y + +def outer_use_vars(x): + y = 1 + def inner(): + return y + z + z = 2; + y + z + return inner + +def literals_in_func(): + True + None + 1346 + 0.7 + class X(object): pass + def f(): pass + (a, b) + [a, b] + +y = lambda x : following() + +def following(): + pass + +def params_and_defaults(a, b={}, c = 1): + a + b + c + +def inner_cls(): + class A(BaseException): + pass + a = A() + raise a + +from xyz import * +import xyz +xyz.x +z + +#ODASA-3263 +#Django does this +class Base(object): + + def __init__(self, choice): + if choice == 1: + self.__class__ = Derived1 + elif choice == 2: + self.__class__ = Derived2 + else: + self.__class__ = Derived3 + +class Derived1(Base): + pass + +class Derived2(Base): + pass + +class Derived3(Base): + pass + +thing = Base(unknown()) + + +def multiple_assignment(): + _tuple, _list = tuple, list + _tuple + _list + + +class Base2(object): + + def __init__(self): + pass + + x = 1 + +class Derived4(Base2): + + def __init__(self): + super(Derived4, self).x + return super(Derived4, self).__init__() + + +def vararg_kwarg(*t, **d): + t + d + + +#ODASA-4055 +class E(object): + + def _internal(arg): + # arg is not a C + def wrapper(args): + return arg(args) + return wrapper + + @_internal + def method(self, *args): + pass + +#Builtin function calls +def calls_next(seq): + it = iter(seq) + n = next(it) + return n + + +#Check imports from builtin modules +from sys import exit + + +#Global assignment in local scope +g1 = None + +def assign_global(): + global g1 + g1 = 101 + return g1 # Cannot be None + +#Assignment in local scope, but called from module level + +g2 = None + +def init(): + global g2 + g2 = 102 # Cannot be None + +init() +g2 # Cannot be None + +#Global set in init method +g3 = None + +class Ugly(object): + + def __init__(self): + global g3 + g3 = 103 + + def meth(self): + return g3 # Cannot be None + +#Global in class scope +class F(object): + + g3 = g3 + g3 + +#Locally redefined attribute +class G(object): + + attr = 0 + + def __init__(self): + self.attr = 1 + + def meth(self): + self.attr = 2 + self.attr = 3 + self.attr + +# Self can only be of a class that is instantiated. +Derived4() diff --git a/python/ql/test/library-tests/PointsTo/general/xyz.py b/python/ql/test/library-tests/PointsTo/general/xyz.py new file mode 100644 index 00000000000..392054917df --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/general/xyz.py @@ -0,0 +1,4 @@ + +x = 1.0 +y = 2.0 +z = 3.0 diff --git a/python/ql/test/library-tests/PointsTo/guarded/PointsTo.expected b/python/ql/test/library-tests/PointsTo/guarded/PointsTo.expected new file mode 100644 index 00000000000..780529a795d --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/guarded/PointsTo.expected @@ -0,0 +1,77 @@ +| test.py | 8 | ControlFlowNode for x | int 7 | 7 | +| test.py | 14 | ControlFlowNode for x | NoneType None | 10 | +| test.py | 14 | ControlFlowNode for x | int 7 | 13 | +| test.py | 20 | ControlFlowNode for x | NoneType None | 19 | +| test.py | 26 | ControlFlowNode for x | int 7 | 25 | +| test.py | 32 | ControlFlowNode for x | NoneType None | 28 | +| test.py | 32 | ControlFlowNode for x | int 7 | 31 | +| test.py | 38 | ControlFlowNode for x | NoneType None | 37 | +| test.py | 43 | ControlFlowNode for i | float 1.0 | 42 | +| test.py | 48 | ControlFlowNode for i | int 0 | 45 | +| test.py | 53 | ControlFlowNode for i | int 0 | 52 | +| test.py | 58 | ControlFlowNode for i | float 1.0 | 57 | +| test.py | 63 | ControlFlowNode for i | float 1.0 | 62 | +| test.py | 63 | ControlFlowNode for i | int 0 | 60 | +| test.py | 68 | ControlFlowNode for i | int 0 | 67 | +| test.py | 74 | ControlFlowNode for i | float 1.0 | 73 | +| test.py | 79 | ControlFlowNode for i | int 7 | 76 | +| test.py | 84 | ControlFlowNode for i | int 7 | 83 | +| test.py | 90 | ControlFlowNode for b | int 7 | 89 | +| test.py | 96 | ControlFlowNode for b | bool True | 92 | +| test.py | 96 | ControlFlowNode for b | int 7 | 95 | +| test.py | 103 | ControlFlowNode for b | bool False | 99 | +| test.py | 103 | ControlFlowNode for b | int 7 | 102 | +| test.py | 109 | ControlFlowNode for b | int 7 | 108 | +| test.py | 114 | ControlFlowNode for t | builtin-class type | 111 | +| test.py | 119 | ControlFlowNode for t | builtin-class object | 118 | +| test.py | 125 | ControlFlowNode for u | int 7 | 124 | +| test.py | 131 | ControlFlowNode for u | int 7 | 130 | +| test.py | 137 | ControlFlowNode for u | int 7 | 136 | +| test.py | 143 | ControlFlowNode for u | int 7 | 142 | +| test.py | 151 | ControlFlowNode for u | int 7 | 150 | +| test.py | 157 | ControlFlowNode for u | int 7 | 156 | +| test.py | 164 | ControlFlowNode for s | float 1.0 | 163 | +| test.py | 169 | ControlFlowNode for f | int 0 | 168 | +| test.py | 176 | ControlFlowNode for x | int 0 | 175 | +| test.py | 181 | ControlFlowNode for x | int 0 | 180 | +| test.py | 186 | ControlFlowNode for x | int 0 | 185 | +| test.py | 186 | ControlFlowNode for x | object() | 172 | +| test.py | 199 | ControlFlowNode for f | int 0 | 198 | +| test.py | 207 | ControlFlowNode for s | builtin-class type | 206 | +| test.py | 214 | ControlFlowNode for s | class C2 | 202 | +| test.py | 215 | ControlFlowNode for s | builtin-class type | 212 | +| test.py | 215 | ControlFlowNode for s | class C2 | 202 | +| test.py | 220 | ControlFlowNode for s | int 0 | 219 | +| test.py | 234 | ControlFlowNode for f | int 0 | 233 | +| test.py | 252 | ControlFlowNode for Attribute | int 1 | 242 | +| test.py | 254 | ControlFlowNode for Attribute | int 2 | 245 | +| test.py | 272 | ControlFlowNode for x | int 1 | 271 | +| test.py | 276 | ControlFlowNode for Attribute | int 1 | 271 | +| test.py | 286 | ControlFlowNode for y | NoneType None | 281 | +| test.py | 297 | ControlFlowNode for y | NoneType None | 291 | +| test.py | 301 | ControlFlowNode for x | NoneType None | 291 | +| test.py | 308 | ControlFlowNode for z | int 7 | 305 | +| test.py | 314 | ControlFlowNode for b | NoneType None | 311 | +| test.py | 332 | ControlFlowNode for Attribute | int 4 | 322 | +| test.py | 339 | ControlFlowNode for Attribute | int 4 | 322 | +| test.py | 347 | ControlFlowNode for Attribute | int 4 | 322 | +| test.py | 369 | ControlFlowNode for g2 | float 2.0 | 366 | +| test.py | 382 | ControlFlowNode for g3 | bool True | 379 | +| test.py | 389 | ControlFlowNode for g4 | int 7 | 396 | +| test.py | 408 | ControlFlowNode for x | int 1 | 404 | +| test.py | 420 | ControlFlowNode for Attribute | NoneType None | 418 | +| test.py | 427 | ControlFlowNode for Attribute | NoneType None | 418 | +| type_test.py | 5 | ControlFlowNode for d | Dict | 2 | +| type_test.py | 14 | ControlFlowNode for x | int 0 | 11 | +| type_test.py | 16 | ControlFlowNode for x | float 1.0 | 11 | +| type_test.py | 22 | ControlFlowNode for arg | builtin-class int | 20 | +| type_test.py | 35 | ControlFlowNode for arg | E() | 32 | +| type_test.py | 42 | ControlFlowNode for arg | E() | 39 | +| type_test.py | 49 | ControlFlowNode for arg | class E | 29 | +| type_test.py | 55 | ControlFlowNode for arg | class E | 29 | +| type_test.py | 67 | ControlFlowNode for x | float 1.0 | 62 | +| type_test.py | 67 | ControlFlowNode for x | int 0 | 62 | +| type_test.py | 77 | ControlFlowNode for IntegerLiteral | int 0 | 77 | +| type_test.py | 83 | ControlFlowNode for IntegerLiteral | int 0 | 83 | +| type_test.py | 89 | ControlFlowNode for IntegerLiteral | int 0 | 89 | +| type_test.py | 95 | ControlFlowNode for IntegerLiteral | int 0 | 95 | diff --git a/python/ql/test/library-tests/PointsTo/guarded/PointsTo.ql b/python/ql/test/library-tests/PointsTo/guarded/PointsTo.ql new file mode 100644 index 00000000000..98644b02e99 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/guarded/PointsTo.ql @@ -0,0 +1,7 @@ +import python + +from ControlFlowNode f, Object o, ControlFlowNode x + +where f.refersTo(o, x) and exists(CallNode call | call.getFunction().getNode().(Name).getId() = "use" and call.getArg(0) = f) + +select f.getLocation().getFile().getShortName(), f.getLocation().getStartLine(), f.toString(), o.toString(), x.getLocation().getStartLine() diff --git a/python/ql/test/library-tests/PointsTo/guarded/PointsToWithType.expected b/python/ql/test/library-tests/PointsTo/guarded/PointsToWithType.expected new file mode 100644 index 00000000000..bd9e52a7664 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/guarded/PointsToWithType.expected @@ -0,0 +1,77 @@ +| test.py | 8 | ControlFlowNode for x | int 7 | builtin-class int | 7 | +| test.py | 14 | ControlFlowNode for x | NoneType None | builtin-class NoneType | 10 | +| test.py | 14 | ControlFlowNode for x | int 7 | builtin-class int | 13 | +| test.py | 20 | ControlFlowNode for x | NoneType None | builtin-class NoneType | 19 | +| test.py | 26 | ControlFlowNode for x | int 7 | builtin-class int | 25 | +| test.py | 32 | ControlFlowNode for x | NoneType None | builtin-class NoneType | 28 | +| test.py | 32 | ControlFlowNode for x | int 7 | builtin-class int | 31 | +| test.py | 38 | ControlFlowNode for x | NoneType None | builtin-class NoneType | 37 | +| test.py | 43 | ControlFlowNode for i | float 1.0 | builtin-class float | 42 | +| test.py | 48 | ControlFlowNode for i | int 0 | builtin-class int | 45 | +| test.py | 53 | ControlFlowNode for i | int 0 | builtin-class int | 52 | +| test.py | 58 | ControlFlowNode for i | float 1.0 | builtin-class float | 57 | +| test.py | 63 | ControlFlowNode for i | float 1.0 | builtin-class float | 62 | +| test.py | 63 | ControlFlowNode for i | int 0 | builtin-class int | 60 | +| test.py | 68 | ControlFlowNode for i | int 0 | builtin-class int | 67 | +| test.py | 74 | ControlFlowNode for i | float 1.0 | builtin-class float | 73 | +| test.py | 79 | ControlFlowNode for i | int 7 | builtin-class int | 76 | +| test.py | 84 | ControlFlowNode for i | int 7 | builtin-class int | 83 | +| test.py | 90 | ControlFlowNode for b | int 7 | builtin-class int | 89 | +| test.py | 96 | ControlFlowNode for b | bool True | builtin-class bool | 92 | +| test.py | 96 | ControlFlowNode for b | int 7 | builtin-class int | 95 | +| test.py | 103 | ControlFlowNode for b | bool False | builtin-class bool | 99 | +| test.py | 103 | ControlFlowNode for b | int 7 | builtin-class int | 102 | +| test.py | 109 | ControlFlowNode for b | int 7 | builtin-class int | 108 | +| test.py | 114 | ControlFlowNode for t | builtin-class type | builtin-class type | 111 | +| test.py | 119 | ControlFlowNode for t | builtin-class object | builtin-class type | 118 | +| test.py | 125 | ControlFlowNode for u | int 7 | builtin-class int | 124 | +| test.py | 131 | ControlFlowNode for u | int 7 | builtin-class int | 130 | +| test.py | 137 | ControlFlowNode for u | int 7 | builtin-class int | 136 | +| test.py | 143 | ControlFlowNode for u | int 7 | builtin-class int | 142 | +| test.py | 151 | ControlFlowNode for u | int 7 | builtin-class int | 150 | +| test.py | 157 | ControlFlowNode for u | int 7 | builtin-class int | 156 | +| test.py | 164 | ControlFlowNode for s | float 1.0 | builtin-class float | 163 | +| test.py | 169 | ControlFlowNode for f | int 0 | builtin-class int | 168 | +| test.py | 176 | ControlFlowNode for x | int 0 | builtin-class int | 175 | +| test.py | 181 | ControlFlowNode for x | int 0 | builtin-class int | 180 | +| test.py | 186 | ControlFlowNode for x | int 0 | builtin-class int | 185 | +| test.py | 186 | ControlFlowNode for x | object() | builtin-class object | 172 | +| test.py | 199 | ControlFlowNode for f | int 0 | builtin-class int | 198 | +| test.py | 207 | ControlFlowNode for s | builtin-class type | builtin-class type | 206 | +| test.py | 214 | ControlFlowNode for s | class C2 | builtin-class type | 202 | +| test.py | 215 | ControlFlowNode for s | builtin-class type | builtin-class type | 212 | +| test.py | 215 | ControlFlowNode for s | class C2 | builtin-class type | 202 | +| test.py | 220 | ControlFlowNode for s | int 0 | builtin-class int | 219 | +| test.py | 234 | ControlFlowNode for f | int 0 | builtin-class int | 233 | +| test.py | 252 | ControlFlowNode for Attribute | int 1 | builtin-class int | 242 | +| test.py | 254 | ControlFlowNode for Attribute | int 2 | builtin-class int | 245 | +| test.py | 272 | ControlFlowNode for x | int 1 | builtin-class int | 271 | +| test.py | 276 | ControlFlowNode for Attribute | int 1 | builtin-class int | 271 | +| test.py | 286 | ControlFlowNode for y | NoneType None | builtin-class NoneType | 281 | +| test.py | 297 | ControlFlowNode for y | NoneType None | builtin-class NoneType | 291 | +| test.py | 301 | ControlFlowNode for x | NoneType None | builtin-class NoneType | 291 | +| test.py | 308 | ControlFlowNode for z | int 7 | builtin-class int | 305 | +| test.py | 314 | ControlFlowNode for b | NoneType None | builtin-class NoneType | 311 | +| test.py | 332 | ControlFlowNode for Attribute | int 4 | builtin-class int | 322 | +| test.py | 339 | ControlFlowNode for Attribute | int 4 | builtin-class int | 322 | +| test.py | 347 | ControlFlowNode for Attribute | int 4 | builtin-class int | 322 | +| test.py | 369 | ControlFlowNode for g2 | float 2.0 | builtin-class float | 366 | +| test.py | 382 | ControlFlowNode for g3 | bool True | builtin-class bool | 379 | +| test.py | 389 | ControlFlowNode for g4 | int 7 | builtin-class int | 396 | +| test.py | 408 | ControlFlowNode for x | int 1 | builtin-class int | 404 | +| test.py | 420 | ControlFlowNode for Attribute | NoneType None | builtin-class NoneType | 418 | +| test.py | 427 | ControlFlowNode for Attribute | NoneType None | builtin-class NoneType | 418 | +| type_test.py | 5 | ControlFlowNode for d | Dict | builtin-class dict | 2 | +| type_test.py | 14 | ControlFlowNode for x | int 0 | builtin-class int | 11 | +| type_test.py | 16 | ControlFlowNode for x | float 1.0 | builtin-class float | 11 | +| type_test.py | 22 | ControlFlowNode for arg | builtin-class int | builtin-class type | 20 | +| type_test.py | 35 | ControlFlowNode for arg | E() | class E | 32 | +| type_test.py | 42 | ControlFlowNode for arg | E() | class E | 39 | +| type_test.py | 49 | ControlFlowNode for arg | class E | builtin-class type | 29 | +| type_test.py | 55 | ControlFlowNode for arg | class E | builtin-class type | 29 | +| type_test.py | 67 | ControlFlowNode for x | float 1.0 | builtin-class float | 62 | +| type_test.py | 67 | ControlFlowNode for x | int 0 | builtin-class int | 62 | +| type_test.py | 77 | ControlFlowNode for IntegerLiteral | int 0 | builtin-class int | 77 | +| type_test.py | 83 | ControlFlowNode for IntegerLiteral | int 0 | builtin-class int | 83 | +| type_test.py | 89 | ControlFlowNode for IntegerLiteral | int 0 | builtin-class int | 89 | +| type_test.py | 95 | ControlFlowNode for IntegerLiteral | int 0 | builtin-class int | 95 | diff --git a/python/ql/test/library-tests/PointsTo/guarded/PointsToWithType.ql b/python/ql/test/library-tests/PointsTo/guarded/PointsToWithType.ql new file mode 100644 index 00000000000..83bbd5e42ba --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/guarded/PointsToWithType.ql @@ -0,0 +1,7 @@ +import python + +from ControlFlowNode f, Object o, ClassObject c, ControlFlowNode x + +where f.refersTo(o, c, x) and exists(CallNode call | call.getFunction().getNode().(Name).getId() = "use" and call.getArg(0) = f) + +select f.getLocation().getFile().getShortName(), f.getLocation().getStartLine(), f.toString(), o.toString(), c.toString(), x.getLocation().getStartLine() diff --git a/python/ql/test/library-tests/PointsTo/guarded/options b/python/ql/test/library-tests/PointsTo/guarded/options new file mode 100644 index 00000000000..be048160aeb --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/guarded/options @@ -0,0 +1,2 @@ +semmle-extractor-options: --max-import-depth=3 +optimize: true diff --git a/python/ql/test/library-tests/PointsTo/guarded/test.py b/python/ql/test/library-tests/PointsTo/guarded/test.py new file mode 100644 index 00000000000..ced4edc0b6c --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/guarded/test.py @@ -0,0 +1,428 @@ +#Edge guards. + +def f(): + x = None + + if x is None: + x = 7 + use(x) + + x = unknown() if cond else None + + if x is not None: + x = 7 + use(x) + + x = None + + if x is None: + x = None + use(x) + + x = None + + if not x: + x = 7 + use(x) + + x = unknown() if cond else None + + if x: + x = 7 + use(x) + + x = None + + if not x: + x = None + use(x) + + i = 0 + if i == 0: + i = 1.0 + use(i) + + i = 0 + if i != 0: + i = 1.0 + use(i) + + i = 0 + if i == 0: + i = 0 + use(i) + + i = 0 + if not i: + i = 1.0 + use(i) + + i = unknown() if cond else 0 + if i: + i = 1.0 + use(i) + + i = 0 + if not i: + i = 0 + use(i) + + + i = 7 + if i == 7: + i = 1.0 + use(i) + + i = 7 + if i != 7: + i = 1.0 + use(i) + + i = 7 + if i == 7: + i = 7 + use(i) + + b = True + + if b: + b = 7 + use(b) + + b = unknown() if cond else True + + if not b: + b = 7 + use(b) + + + b = unknown() if cond else False + + if b: + b = 7 + use(b) + + b = False + + if not b: + b = 7 + use(b) + + t = type + if t is object: + t = float + use(t) + + t = type + if t is not object: + t = object + use(t) + + u = unknown_thing() + + if u is None: + u = 7 + use(u) + + u = unknown_thing() + + if u is not None: + u = 7 + use(u) + + u = unknown_thing() + + if u: + u = 7 + use(u) + + u = unknown_thing() + + if not u: + u = 7 + use(u) + + K = unknown_thing() + + u = unknown_thing() + + if u is K: + u = 7 + use(u) + + u = unknown_thing() + + if u is not K: + u = 7 + use(u) + +#String and float consts. + + s = "not this" + if s == "not this": + s = 1.0 + use(s) + + f = 0.7 + if f == 0.7: + f = 0 + use(f) + +#Sentinel guards +SENTINEL = object() +def g(x = SENTINEL): + if x is SENTINEL: + x = 0 + use(x) + +def h(x = SENTINEL): + if x == SENTINEL: + x = 0 + use(x) + +def j(x = SENTINEL): + if x is not SENTINEL: + x = 0 + use(x) + +#ODASA-4056 +def format_string(s, formatter='minimal'): + """Format the given string using the given formatter.""" + if not callable(formatter): + formatter = get_formatter_for_name(formatter) + use(formatter) + +def guard_callable(s, f=j): + """Format the given string using the given formatter.""" + if callable(f): + f=0 + use(f) + +class C1(object):pass +class C2(C1):pass + +def guard_subclass(s = C2): + if issubclass(s, C1): + s = type + use(s) + +def guard_subclass2(s = C2): + if not issubclass(s, C1): + use(s) + s = type + else: + use(s) + use(s) + +def instance_guard(s, f=1.0): + if isinstance(s, float): + s = 0 + use(s) + + +#ODASA-4056 +def format_string(s, formatter='minimal'): + """Format the given string using the given formatter.""" + if not callable(formatter): + formatter = get_formatter_for_name(formatter) + use(formatter) + +func_type = type(j) +def guard_callable(s, f=j): + if isinstance(f, func_type): + f=0 + use(f) + + +#Attribute points-to +class C(object): + + def __init__(self): + self._init() + self.x = 1 + + def _init(self): + self.y = 2 + self._init2() + + def _init2(self): + self.z = 3 + + def method(self): + use(self.x) + if isinstance(self.y, int): + use(self.y) + if not isinstance(self.z, int): + use(self.z) + +#Guarded None in nested function +def f(x=None): + def inner(arg): + if x: + use(x) + + + +#Guards on whole scope... +class D(object): + + def __init__(self, x = None): + if x is None: + x = 1 + use(x) + self.x = x + + def f(self): + use(self.x) + +#Biased splitting & pruning +def f(cond): + if cond: + y = None + x = False + else: + y = something() + x = some_condition() + use(y) # y can be None here + if x: + use(y) # Should not infer that y is None here + +#Splittings with boolean expressions: +def split_bool1(x=None,y=None): + if x and y: + raise + if not (x or y): + raise + if x: + use(y) + else: + use(y) + if y: + use(x) + else: + use(x) + +def split_bool2(x,y=None,z=7): + if x and not y or x and use(y): + pass + if x and not z or x and use(z): + pass + +def split_bool3(a=None, b=None): + if a or b: + if a: + use(b) + else: + use(b) # Should not infer b to be None. + +#Guard on instance attribute +class E(object): + + def __init__(self): + self.y = None if rand() else 4 + + x = None if rand() else 3 + + def a(self): + e = E() + #Do not mutate + if e.x: + use(e.x) + if e.y: + use(e.y) + + def b(self): + possibly_mutate(self) + if self.x: + use(self.x) + if self.y: + use(self.y) + +def k(): + e = E() + possibly_mutate(e) + if e.x: + use(e.x) + if e.y: + use(e.y) + + +#Global assignment in local scope +g1 = None + +def assign_global(): + global g1 + if not g1: + g1 = 7.0 + use(g1) # Cannot be None + +#Assignment in local scope, but called from module level + +g2 = None + +def init(): + global g2 + if not g2: + g2 = 2.0 + +init() +use(g2) # Cannot be None + +#Global set in init method +g3 = None + +class Ugly(object): + + def __init__(self): + global g3 + if not g3: + g3 = True + + def meth(self): + use(g3) # Cannot be None + +g4 = None + +def get_g4(): + if not g4: + set_g4() + use(g4) # Cannot be None + +def set_g4(): + set_g4_indirect() + +def set_g4_indirect(): + global g4 + g4 = 7 + +#Assertions +def f(cond): + x = None if cond else thing() + assert x + use(x) + +def f(cond, x = 1): + if cond: + x = 1.0 + assert isinstance(x, int) + use(x) + +#ODASA-5018 +def f(x,y=None, z=0): + if (x and y) or (y and not z): + #y cannot be None here. + use(y) + +class C(object): + + def __init__(self, x=None): + self.x = x + use(self.x) + + def meth(self): + if self.x is not None: + use(self.x) + return lambda : use(self.x) + else: + use(self.x) + return lambda : use(self.x) diff --git a/python/ql/test/library-tests/PointsTo/guarded/type_test.py b/python/ql/test/library-tests/PointsTo/guarded/type_test.py new file mode 100644 index 00000000000..79597dee0ef --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/guarded/type_test.py @@ -0,0 +1,97 @@ + +def f(d = {}): + + if isinstance(d, dict): + use(d) + else: + use(d) + +def g(cond): + + x = 0 if cond else 1.0 + + if isinstance(x, int): + use(x) + elif isinstance(x, float): + use(x) + else: + use(x) + +def h(arg=int): + if issubclass(arg, int): + use(arg) + else: + use(arg) + +class D(object): + pass + +class E(D): + pass + +def j(arg=E()): + + if isinstance(arg, E): + use(arg) + else: + use(arg) + +def k(arg=E()): + + if isinstance(arg, D): + use(arg) + else: + use(arg) + + +def l(arg=E): + if issubclass(arg, E): + use(arg) + else: + use(arg) + +def m(arg=E): + if issubclass(arg, D): + use(arg) + else: + use(arg) + +number = int, float + +def n(cond): + x = 0 if cond else 1.0 + + if not isinstance(x, number): + use(x) + else: + use(x) + +import sys +if sys.version < "3": + from collections import Iterable, Sequence, Set +else: + from collections.abc import Iterable, Sequence, Set + +def p(): + if issubclass(list, Iterable): + use(0) + else: + use(1) + +def q(): + if issubclass(list, Sequence): + use(0) + else: + use(1) + +def p(): + if isinstance({0}, Iterable): + use(0) + else: + use(1) + +def q(): + if isinstance({0}, Set): + use(0) + else: + use(1) diff --git a/python/ql/test/library-tests/PointsTo/imports/Runtime.expected b/python/ql/test/library-tests/PointsTo/imports/Runtime.expected new file mode 100644 index 00000000000..b36ac923ad4 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/imports/Runtime.expected @@ -0,0 +1,55 @@ +| __init__.py | 1 | ControlFlowNode for ImportExpr | Module package.module | ControlFlowNode for ImportExpr | +| __init__.py | 2 | ControlFlowNode for ImportMember | Function module | ControlFlowNode for FunctionExpr | +| __init__.py | 2 | ControlFlowNode for module | Function module | ControlFlowNode for FunctionExpr | +| __init__.py | 4 | ControlFlowNode for ImportExpr | Module package | ControlFlowNode for ImportExpr | +| __init__.py | 4 | ControlFlowNode for ImportMember | Module package.module2 | Entry node for Module package.module2 | +| __init__.py | 4 | ControlFlowNode for module3 | Module package.module2 | Entry node for Module package.module2 | +| __init__.py | 5 | ControlFlowNode for IntegerLiteral | int 7 | ControlFlowNode for IntegerLiteral | +| __init__.py | 5 | ControlFlowNode for module2 | int 7 | ControlFlowNode for IntegerLiteral | +| __init__.py | 6 | ControlFlowNode for ImportExpr | Module package | ControlFlowNode for ImportExpr | +| __init__.py | 6 | ControlFlowNode for ImportMember | int 7 | ControlFlowNode for IntegerLiteral | +| __init__.py | 6 | ControlFlowNode for module4 | int 7 | ControlFlowNode for IntegerLiteral | +| __init__.py | 7 | ControlFlowNode for ImportExpr | Module package | ControlFlowNode for ImportExpr | +| __init__.py | 7 | ControlFlowNode for ImportMember | Module package.module2 | Entry node for Module package.module2 | +| __init__.py | 7 | ControlFlowNode for module5 | Module package.module2 | Entry node for Module package.module2 | +| __init__.py | 8 | ControlFlowNode for ImportExpr | Module package | ControlFlowNode for ImportExpr | +| __init__.py | 8 | ControlFlowNode for ImportMember | Module package.moduleX | Entry node for Module package.moduleX | +| __init__.py | 8 | ControlFlowNode for moduleX | Module package.moduleX | Entry node for Module package.moduleX | +| module2.py | 1 | ControlFlowNode for IntegerLiteral | int 0 | ControlFlowNode for IntegerLiteral | +| module2.py | 1 | ControlFlowNode for x | int 0 | ControlFlowNode for IntegerLiteral | +| module.py | 2 | ControlFlowNode for FunctionExpr | Function module | ControlFlowNode for FunctionExpr | +| module.py | 2 | ControlFlowNode for module | Function module | ControlFlowNode for FunctionExpr | +| moduleX.py | 1 | ControlFlowNode for ClassExpr | class Y | ControlFlowNode for ClassExpr | +| moduleX.py | 1 | ControlFlowNode for Y | class Y | ControlFlowNode for ClassExpr | +| moduleX.py | 1 | ControlFlowNode for object | builtin-class object | ControlFlowNode for object | +| test.py | 1 | ControlFlowNode for ImportExpr | Module package | ControlFlowNode for ImportExpr | +| test.py | 2 | ControlFlowNode for ImportMember | Function module | ControlFlowNode for FunctionExpr | +| test.py | 2 | ControlFlowNode for module | Function module | ControlFlowNode for FunctionExpr | +| test.py | 4 | ControlFlowNode for ImportExpr | Module package | ControlFlowNode for ImportExpr | +| test.py | 5 | ControlFlowNode for ImportMember | Module package.x | Entry node for Module package.x | +| test.py | 5 | ControlFlowNode for x | Module package.x | Entry node for Module package.x | +| test.py | 8 | ControlFlowNode for C | class C | ControlFlowNode for ClassExpr | +| test.py | 8 | ControlFlowNode for ClassExpr | class C | ControlFlowNode for ClassExpr | +| test.py | 8 | ControlFlowNode for object | builtin-class object | ControlFlowNode for object | +| test.py | 10 | ControlFlowNode for ImportExpr | Module package | ControlFlowNode for ImportExpr | +| test.py | 10 | ControlFlowNode for ImportMember | int 7 | ControlFlowNode for IntegerLiteral | +| test.py | 10 | ControlFlowNode for module2 | int 7 | ControlFlowNode for IntegerLiteral | +| test.py | 12 | ControlFlowNode for FunctionExpr | Function f | ControlFlowNode for FunctionExpr | +| test.py | 12 | ControlFlowNode for f | Function f | ControlFlowNode for FunctionExpr | +| test.py | 13 | ControlFlowNode for ImportExpr | Module package | ControlFlowNode for ImportExpr | +| test.py | 13 | ControlFlowNode for ImportMember | Module package.x | Entry node for Module package.x | +| test.py | 13 | ControlFlowNode for x | Module package.x | Entry node for Module package.x | +| test.py | 15 | ControlFlowNode for ImportExpr | Module package | ControlFlowNode for ImportExpr | +| test.py | 15 | ControlFlowNode for ImportMember | Module package.moduleX | Entry node for Module package.moduleX | +| test.py | 15 | ControlFlowNode for moduleX | Module package.moduleX | Entry node for Module package.moduleX | +| test.py | 16 | ControlFlowNode for Attribute | class Y | ControlFlowNode for ClassExpr | +| test.py | 16 | ControlFlowNode for moduleX | Module package.moduleX | Entry node for Module package.moduleX | +| test.py | 19 | ControlFlowNode for ImportExpr | Module tty | ControlFlowNode for ImportExpr | +| test.py | 19 | ControlFlowNode for tty | Module tty | ControlFlowNode for ImportExpr | +| test.py | 22 | ControlFlowNode for Attribute | Builtin-function exc_info | ControlFlowNode for from sys import * | +| test.py | 22 | ControlFlowNode for x | Module package.x | Entry node for Module package.x | +| test.py | 24 | ControlFlowNode for IntegerLiteral | int 0 | ControlFlowNode for IntegerLiteral | +| test.py | 24 | ControlFlowNode for argv | int 0 | ControlFlowNode for IntegerLiteral | +| test.py | 27 | ControlFlowNode for ImportExpr | Module sys | ControlFlowNode for ImportExpr | +| test.py | 31 | ControlFlowNode for argv | list object | ControlFlowNode for argv | +| x.py | 2 | ControlFlowNode for ImportExpr | Module sys | ControlFlowNode for ImportExpr | diff --git a/python/ql/test/library-tests/PointsTo/imports/Runtime.ql b/python/ql/test/library-tests/PointsTo/imports/Runtime.ql new file mode 100644 index 00000000000..4a25bff744a --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/imports/Runtime.ql @@ -0,0 +1,8 @@ + +import python + +from int line, ControlFlowNode f, Object o, ControlFlowNode orig +where + not f.getLocation().getFile().inStdlib() and + f.refersTo(o, orig) and line = f.getLocation().getStartLine() and line != 0 +select f.getLocation().getFile().getShortName(), line, f.toString(), o.toString(), orig.toString() diff --git a/python/ql/test/library-tests/PointsTo/imports/RuntimeWithType.expected b/python/ql/test/library-tests/PointsTo/imports/RuntimeWithType.expected new file mode 100644 index 00000000000..ebd971cc048 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/imports/RuntimeWithType.expected @@ -0,0 +1,55 @@ +| __init__.py | 1 | ControlFlowNode for ImportExpr | Module package.module | builtin-class module | ControlFlowNode for ImportExpr | +| __init__.py | 2 | ControlFlowNode for ImportMember | Function module | builtin-class function | ControlFlowNode for FunctionExpr | +| __init__.py | 2 | ControlFlowNode for module | Function module | builtin-class function | ControlFlowNode for FunctionExpr | +| __init__.py | 4 | ControlFlowNode for ImportExpr | Module package | builtin-class module | ControlFlowNode for ImportExpr | +| __init__.py | 4 | ControlFlowNode for ImportMember | Module package.module2 | builtin-class module | Entry node for Module package.module2 | +| __init__.py | 4 | ControlFlowNode for module3 | Module package.module2 | builtin-class module | Entry node for Module package.module2 | +| __init__.py | 5 | ControlFlowNode for IntegerLiteral | int 7 | builtin-class int | ControlFlowNode for IntegerLiteral | +| __init__.py | 5 | ControlFlowNode for module2 | int 7 | builtin-class int | ControlFlowNode for IntegerLiteral | +| __init__.py | 6 | ControlFlowNode for ImportExpr | Module package | builtin-class module | ControlFlowNode for ImportExpr | +| __init__.py | 6 | ControlFlowNode for ImportMember | int 7 | builtin-class int | ControlFlowNode for IntegerLiteral | +| __init__.py | 6 | ControlFlowNode for module4 | int 7 | builtin-class int | ControlFlowNode for IntegerLiteral | +| __init__.py | 7 | ControlFlowNode for ImportExpr | Module package | builtin-class module | ControlFlowNode for ImportExpr | +| __init__.py | 7 | ControlFlowNode for ImportMember | Module package.module2 | builtin-class module | Entry node for Module package.module2 | +| __init__.py | 7 | ControlFlowNode for module5 | Module package.module2 | builtin-class module | Entry node for Module package.module2 | +| __init__.py | 8 | ControlFlowNode for ImportExpr | Module package | builtin-class module | ControlFlowNode for ImportExpr | +| __init__.py | 8 | ControlFlowNode for ImportMember | Module package.moduleX | builtin-class module | Entry node for Module package.moduleX | +| __init__.py | 8 | ControlFlowNode for moduleX | Module package.moduleX | builtin-class module | Entry node for Module package.moduleX | +| module2.py | 1 | ControlFlowNode for IntegerLiteral | int 0 | builtin-class int | ControlFlowNode for IntegerLiteral | +| module2.py | 1 | ControlFlowNode for x | int 0 | builtin-class int | ControlFlowNode for IntegerLiteral | +| module.py | 2 | ControlFlowNode for FunctionExpr | Function module | builtin-class function | ControlFlowNode for FunctionExpr | +| module.py | 2 | ControlFlowNode for module | Function module | builtin-class function | ControlFlowNode for FunctionExpr | +| moduleX.py | 1 | ControlFlowNode for ClassExpr | class Y | builtin-class type | ControlFlowNode for ClassExpr | +| moduleX.py | 1 | ControlFlowNode for Y | class Y | builtin-class type | ControlFlowNode for ClassExpr | +| moduleX.py | 1 | ControlFlowNode for object | builtin-class object | builtin-class type | ControlFlowNode for object | +| test.py | 1 | ControlFlowNode for ImportExpr | Module package | builtin-class module | ControlFlowNode for ImportExpr | +| test.py | 2 | ControlFlowNode for ImportMember | Function module | builtin-class function | ControlFlowNode for FunctionExpr | +| test.py | 2 | ControlFlowNode for module | Function module | builtin-class function | ControlFlowNode for FunctionExpr | +| test.py | 4 | ControlFlowNode for ImportExpr | Module package | builtin-class module | ControlFlowNode for ImportExpr | +| test.py | 5 | ControlFlowNode for ImportMember | Module package.x | builtin-class module | Entry node for Module package.x | +| test.py | 5 | ControlFlowNode for x | Module package.x | builtin-class module | Entry node for Module package.x | +| test.py | 8 | ControlFlowNode for C | class C | builtin-class type | ControlFlowNode for ClassExpr | +| test.py | 8 | ControlFlowNode for ClassExpr | class C | builtin-class type | ControlFlowNode for ClassExpr | +| test.py | 8 | ControlFlowNode for object | builtin-class object | builtin-class type | ControlFlowNode for object | +| test.py | 10 | ControlFlowNode for ImportExpr | Module package | builtin-class module | ControlFlowNode for ImportExpr | +| test.py | 10 | ControlFlowNode for ImportMember | int 7 | builtin-class int | ControlFlowNode for IntegerLiteral | +| test.py | 10 | ControlFlowNode for module2 | int 7 | builtin-class int | ControlFlowNode for IntegerLiteral | +| test.py | 12 | ControlFlowNode for FunctionExpr | Function f | builtin-class function | ControlFlowNode for FunctionExpr | +| test.py | 12 | ControlFlowNode for f | Function f | builtin-class function | ControlFlowNode for FunctionExpr | +| test.py | 13 | ControlFlowNode for ImportExpr | Module package | builtin-class module | ControlFlowNode for ImportExpr | +| test.py | 13 | ControlFlowNode for ImportMember | Module package.x | builtin-class module | Entry node for Module package.x | +| test.py | 13 | ControlFlowNode for x | Module package.x | builtin-class module | Entry node for Module package.x | +| test.py | 15 | ControlFlowNode for ImportExpr | Module package | builtin-class module | ControlFlowNode for ImportExpr | +| test.py | 15 | ControlFlowNode for ImportMember | Module package.moduleX | builtin-class module | Entry node for Module package.moduleX | +| test.py | 15 | ControlFlowNode for moduleX | Module package.moduleX | builtin-class module | Entry node for Module package.moduleX | +| test.py | 16 | ControlFlowNode for Attribute | class Y | builtin-class type | ControlFlowNode for ClassExpr | +| test.py | 16 | ControlFlowNode for moduleX | Module package.moduleX | builtin-class module | Entry node for Module package.moduleX | +| test.py | 19 | ControlFlowNode for ImportExpr | Module tty | builtin-class module | ControlFlowNode for ImportExpr | +| test.py | 19 | ControlFlowNode for tty | Module tty | builtin-class module | ControlFlowNode for ImportExpr | +| test.py | 22 | ControlFlowNode for Attribute | Builtin-function exc_info | builtin-class builtin_function_or_method | ControlFlowNode for from sys import * | +| test.py | 22 | ControlFlowNode for x | Module package.x | builtin-class module | Entry node for Module package.x | +| test.py | 24 | ControlFlowNode for IntegerLiteral | int 0 | builtin-class int | ControlFlowNode for IntegerLiteral | +| test.py | 24 | ControlFlowNode for argv | int 0 | builtin-class int | ControlFlowNode for IntegerLiteral | +| test.py | 27 | ControlFlowNode for ImportExpr | Module sys | builtin-class module | ControlFlowNode for ImportExpr | +| test.py | 31 | ControlFlowNode for argv | list object | builtin-class list | ControlFlowNode for argv | +| x.py | 2 | ControlFlowNode for ImportExpr | Module sys | builtin-class module | ControlFlowNode for ImportExpr | diff --git a/python/ql/test/library-tests/PointsTo/imports/RuntimeWithType.ql b/python/ql/test/library-tests/PointsTo/imports/RuntimeWithType.ql new file mode 100644 index 00000000000..eca5e965ea8 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/imports/RuntimeWithType.ql @@ -0,0 +1,8 @@ + +import python + +from int line, ControlFlowNode f, Object o, ClassObject cls, ControlFlowNode orig +where + not f.getLocation().getFile().inStdlib() and + f.refersTo(o, cls, orig) and line = f.getLocation().getStartLine() and line != 0 +select f.getLocation().getFile().getShortName(), line, f.toString(), o.toString(), cls.toString(), orig.toString() diff --git a/python/ql/test/library-tests/PointsTo/imports/options b/python/ql/test/library-tests/PointsTo/imports/options new file mode 100644 index 00000000000..b6a59fe2746 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/imports/options @@ -0,0 +1 @@ +semmle-extractor-options: --max-import-depth=2 -r package diff --git a/python/ql/test/library-tests/PointsTo/imports/package/__init__.py b/python/ql/test/library-tests/PointsTo/imports/package/__init__.py new file mode 100644 index 00000000000..715f4fbef35 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/imports/package/__init__.py @@ -0,0 +1,15 @@ +from .module \ +import module + +from . import module2 as module3 +module2 = 7 +from . import module2 as module4 +from . import module3 as module5 +from package import moduleX + +#We should now have: +#module2 = 7 +#module3 = package.module2 +#module4 = 7 +#module5 = package.module2 +#moduleX = package.moduleX diff --git a/python/ql/test/library-tests/PointsTo/imports/package/module.py b/python/ql/test/library-tests/PointsTo/imports/package/module.py new file mode 100644 index 00000000000..008b713d67e --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/imports/package/module.py @@ -0,0 +1,3 @@ + +def module(args): + pass diff --git a/python/ql/test/library-tests/PointsTo/imports/package/module2.py b/python/ql/test/library-tests/PointsTo/imports/package/module2.py new file mode 100644 index 00000000000..3aea0c58ce5 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/imports/package/module2.py @@ -0,0 +1 @@ +x = 0 diff --git a/python/ql/test/library-tests/PointsTo/imports/package/moduleX.py b/python/ql/test/library-tests/PointsTo/imports/package/moduleX.py new file mode 100644 index 00000000000..3b39b8c0985 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/imports/package/moduleX.py @@ -0,0 +1,2 @@ +class Y(object): + pass \ No newline at end of file diff --git a/python/ql/test/library-tests/PointsTo/imports/package/x.py b/python/ql/test/library-tests/PointsTo/imports/package/x.py new file mode 100644 index 00000000000..51cf8f5a381 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/imports/package/x.py @@ -0,0 +1,2 @@ + +from sys import * diff --git a/python/ql/test/library-tests/PointsTo/imports/test.py b/python/ql/test/library-tests/PointsTo/imports/test.py new file mode 100644 index 00000000000..eb57051a8fa --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/imports/test.py @@ -0,0 +1,31 @@ +from package \ +import module + +from package \ +import x +#Should work correctly in nested scopes as well. + +class C(object): + + from package import module2 + + def f(self): + from package import x + +from package import moduleX +moduleX.Y + +#A small stdlib module to test version handling. +import tty + +#Check imports of builtin-objects using import * with no corresponding variable. +x.exc_info + +argv = 0 + +try: + from sys import * +except: + pass + +argv diff --git a/python/ql/test/library-tests/PointsTo/indexing/Test.expected b/python/ql/test/library-tests/PointsTo/indexing/Test.expected new file mode 100644 index 00000000000..bd53dcea841 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/indexing/Test.expected @@ -0,0 +1,27 @@ +| 1 | ControlFlowNode for ImportExpr | Module fake_collections | 1 | +| 1 | ControlFlowNode for ImportMember | class deque | 4 | +| 1 | ControlFlowNode for deque | class deque | 4 | +| 2 | ControlFlowNode for FunctionExpr | Function f | 2 | +| 2 | ControlFlowNode for f | Function f | 2 | +| 3 | ControlFlowNode for d | deque() | 3 | +| 3 | ControlFlowNode for deque | class deque | 4 | +| 3 | ControlFlowNode for deque() | deque() | 3 | +| 4 | ControlFlowNode for List | List | 4 | +| 4 | ControlFlowNode for l | List | 4 | +| 6 | ControlFlowNode for d | deque() | 3 | +| 7 | ControlFlowNode for l | List | 4 | +| 8 | ControlFlowNode for IntegerLiteral | int 1 | 8 | +| 8 | ControlFlowNode for t | int 1 | 8 | +| 9 | ControlFlowNode for IntegerLiteral | int 0 | 9 | +| 9 | ControlFlowNode for Subscript | int 1 | 8 | +| 9 | ControlFlowNode for d | deque() | 3 | +| 9 | ControlFlowNode for t | int 1 | 8 | +| 10 | ControlFlowNode for IntegerLiteral | int 0 | 10 | +| 10 | ControlFlowNode for Subscript | int 1 | 8 | +| 10 | ControlFlowNode for l | List | 4 | +| 10 | ControlFlowNode for t | int 1 | 8 | +| 11 | ControlFlowNode for d | deque() | 3 | +| 12 | ControlFlowNode for l | List | 4 | +| 13 | ControlFlowNode for d | deque() | 3 | +| 14 | ControlFlowNode for IntegerLiteral | int 0 | 14 | +| 14 | ControlFlowNode for d | deque() | 3 | diff --git a/python/ql/test/library-tests/PointsTo/indexing/Test.ql b/python/ql/test/library-tests/PointsTo/indexing/Test.ql new file mode 100644 index 00000000000..70b62e825f7 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/indexing/Test.ql @@ -0,0 +1,8 @@ +import python + +from ControlFlowNode f, Object o, ControlFlowNode x + +where f.refersTo(o, x) and +f.getLocation().getFile().getBaseName() = "test.py" + +select f.getLocation().getStartLine(), f.toString(), o.toString(), x.getLocation().getStartLine() diff --git a/python/ql/test/library-tests/PointsTo/indexing/TestWithType.expected b/python/ql/test/library-tests/PointsTo/indexing/TestWithType.expected new file mode 100644 index 00000000000..a542ba9fe86 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/indexing/TestWithType.expected @@ -0,0 +1,27 @@ +| 1 | ControlFlowNode for ImportExpr | Module fake_collections | builtin-class module | 1 | +| 1 | ControlFlowNode for ImportMember | class deque | builtin-class type | 4 | +| 1 | ControlFlowNode for deque | class deque | builtin-class type | 4 | +| 2 | ControlFlowNode for FunctionExpr | Function f | builtin-class function | 2 | +| 2 | ControlFlowNode for f | Function f | builtin-class function | 2 | +| 3 | ControlFlowNode for d | deque() | class deque | 3 | +| 3 | ControlFlowNode for deque | class deque | builtin-class type | 4 | +| 3 | ControlFlowNode for deque() | deque() | class deque | 3 | +| 4 | ControlFlowNode for List | List | builtin-class list | 4 | +| 4 | ControlFlowNode for l | List | builtin-class list | 4 | +| 6 | ControlFlowNode for d | deque() | class deque | 3 | +| 7 | ControlFlowNode for l | List | builtin-class list | 4 | +| 8 | ControlFlowNode for IntegerLiteral | int 1 | builtin-class int | 8 | +| 8 | ControlFlowNode for t | int 1 | builtin-class int | 8 | +| 9 | ControlFlowNode for IntegerLiteral | int 0 | builtin-class int | 9 | +| 9 | ControlFlowNode for Subscript | int 1 | builtin-class int | 8 | +| 9 | ControlFlowNode for d | deque() | class deque | 3 | +| 9 | ControlFlowNode for t | int 1 | builtin-class int | 8 | +| 10 | ControlFlowNode for IntegerLiteral | int 0 | builtin-class int | 10 | +| 10 | ControlFlowNode for Subscript | int 1 | builtin-class int | 8 | +| 10 | ControlFlowNode for l | List | builtin-class list | 4 | +| 10 | ControlFlowNode for t | int 1 | builtin-class int | 8 | +| 11 | ControlFlowNode for d | deque() | class deque | 3 | +| 12 | ControlFlowNode for l | List | builtin-class list | 4 | +| 13 | ControlFlowNode for d | deque() | class deque | 3 | +| 14 | ControlFlowNode for IntegerLiteral | int 0 | builtin-class int | 14 | +| 14 | ControlFlowNode for d | deque() | class deque | 3 | diff --git a/python/ql/test/library-tests/PointsTo/indexing/TestWithType.ql b/python/ql/test/library-tests/PointsTo/indexing/TestWithType.ql new file mode 100644 index 00000000000..6b0c8b8460d --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/indexing/TestWithType.ql @@ -0,0 +1,8 @@ +import python + +from ControlFlowNode f, Object o, ClassObject c, ControlFlowNode x + +where f.refersTo(o, c, x) and +f.getLocation().getFile().getBaseName() = "test.py" + +select f.getLocation().getStartLine(), f.toString(), o.toString(), c.toString(), x.getLocation().getStartLine() diff --git a/python/ql/test/library-tests/PointsTo/indexing/fake_collections.py b/python/ql/test/library-tests/PointsTo/indexing/fake_collections.py new file mode 100644 index 00000000000..6f0ee9bde2d --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/indexing/fake_collections.py @@ -0,0 +1,16 @@ +# Use a fake collection module, otherwise we need to set the import depth to 3 +# which makes the test run very slowly. + +class deque(object): + + def __getitem__(self, index): + pass + + def append(self, item): + pass + + def index(self, key): + pass + + def __reversed__(self): + pass diff --git a/python/ql/test/library-tests/PointsTo/indexing/options b/python/ql/test/library-tests/PointsTo/indexing/options new file mode 100644 index 00000000000..eb214fc2931 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/indexing/options @@ -0,0 +1 @@ +semmle-extractor-options: --max-import-depth=1 diff --git a/python/ql/test/library-tests/PointsTo/indexing/test.py b/python/ql/test/library-tests/PointsTo/indexing/test.py new file mode 100644 index 00000000000..fba7bd91141 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/indexing/test.py @@ -0,0 +1,14 @@ +from fake_collections import deque +def f(x, y, z): + d = deque() + l = [] + for i in seq: + d[x] = y + l[x] = z + t = 1 + d[0] = t + l[0] = t + d[i] + l[i] + d[x] + d[0] diff --git a/python/ql/test/library-tests/PointsTo/inheritance/BaseTypes.expected b/python/ql/test/library-tests/PointsTo/inheritance/BaseTypes.expected new file mode 100644 index 00000000000..24feada6fe1 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/inheritance/BaseTypes.expected @@ -0,0 +1,15 @@ +| class Base | 0 | builtin-class object | +| class Derived1 | 0 | class Base | +| class Derived2 | 0 | class Derived1 | +| class Derived3 | 0 | class Derived1 | +| class Derived4 | 0 | class Derived3 | +| class Derived4 | 1 | class Derived2 | +| class Derived5 | 0 | class Derived1 | +| class Derived6 | 0 | class Derived5 | +| class Derived6 | 1 | class Derived2 | +| class Missing2 | 0 | class Base | +| class Missing3 | 1 | class Base | +| class Wrong1 | 0 | class Derived5 | +| class Wrong1 | 1 | class Derived2 | +| class Wrong2 | 0 | class Derived3 | +| class Wrong2 | 1 | class Derived2 | diff --git a/python/ql/test/library-tests/PointsTo/inheritance/BaseTypes.ql b/python/ql/test/library-tests/PointsTo/inheritance/BaseTypes.ql new file mode 100644 index 00000000000..27b2ed4ce2f --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/inheritance/BaseTypes.ql @@ -0,0 +1,7 @@ + +import python + +from ClassObject cls, ClassObject base, int n +where not cls.isBuiltin() and +base = cls.getBaseType(n) +select cls.toString(), n, base.toString() diff --git a/python/ql/test/library-tests/PointsTo/inheritance/Calls.expected b/python/ql/test/library-tests/PointsTo/inheritance/Calls.expected new file mode 100644 index 00000000000..f044ce05f9d --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/inheritance/Calls.expected @@ -0,0 +1,8 @@ +| 9 | Function meth | 3 | +| 14 | Function meth | 8 | +| 22 | Function meth | 13 | +| 27 | Function meth | 8 | +| 27 | Function meth | 13 | +| 32 | Function meth | 26 | +| 38 | Function meth | 13 | +| 43 | Function meth | 13 | diff --git a/python/ql/test/library-tests/PointsTo/inheritance/Calls.ql b/python/ql/test/library-tests/PointsTo/inheritance/Calls.ql new file mode 100644 index 00000000000..d35ac04bb30 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/inheritance/Calls.ql @@ -0,0 +1,8 @@ + +import python + +from Call c, FunctionObject f + +where f.getACall().getNode() = c + +select c.getLocation().getStartLine(), f.toString(), f.getFunction().getLocation().getStartLine() diff --git a/python/ql/test/library-tests/PointsTo/inheritance/Declared.expected b/python/ql/test/library-tests/PointsTo/inheritance/Declared.expected new file mode 100644 index 00000000000..daf2d029e7f --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/inheritance/Declared.expected @@ -0,0 +1,11 @@ +| class Base | meth | Function meth | 3 | +| class Derived1 | meth | Function meth | 8 | +| class Derived2 | meth | Function meth | 13 | +| class Derived4 | meth | Function meth | 21 | +| class Derived5 | meth | Function meth | 26 | +| class Derived6 | meth | Function meth | 31 | +| class Missing1 | a | Function a | 49 | +| class Missing2 | b | Function b | 53 | +| class Missing3 | c | Function c | 57 | +| class Wrong1 | meth | Function meth | 37 | +| class Wrong2 | meth | Function meth | 42 | diff --git a/python/ql/test/library-tests/PointsTo/inheritance/Declared.ql b/python/ql/test/library-tests/PointsTo/inheritance/Declared.ql new file mode 100644 index 00000000000..890fe308ea4 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/inheritance/Declared.ql @@ -0,0 +1,7 @@ + +import python +import semmle.python.pointsto.PointsTo + +from ClassObject cls, string name, PyFunctionObject f +where PointsTo::Types::class_declared_attribute(cls, name, f, _, _) +select cls.toString(), name, f.toString(), f.getFunction().getLocation().getStartLine() diff --git a/python/ql/test/library-tests/PointsTo/inheritance/Declares.expected b/python/ql/test/library-tests/PointsTo/inheritance/Declares.expected new file mode 100644 index 00000000000..625172325b6 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/inheritance/Declares.expected @@ -0,0 +1,11 @@ +| Class Base | meth | +| Class Derived1 | meth | +| Class Derived2 | meth | +| Class Derived4 | meth | +| Class Derived5 | meth | +| Class Derived6 | meth | +| Class Missing1 | a | +| Class Missing2 | b | +| Class Missing3 | c | +| Class Wrong1 | meth | +| Class Wrong2 | meth | diff --git a/python/ql/test/library-tests/PointsTo/inheritance/Declares.ql b/python/ql/test/library-tests/PointsTo/inheritance/Declares.ql new file mode 100644 index 00000000000..ee837e66478 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/inheritance/Declares.ql @@ -0,0 +1,7 @@ + +import python +import semmle.python.pointsto.Base + +from ClassObject cls, string name +where class_declares_attribute(cls, name) +select cls.getPyClass().toString(), name diff --git a/python/ql/test/library-tests/PointsTo/inheritance/Lookup.expected b/python/ql/test/library-tests/PointsTo/inheritance/Lookup.expected new file mode 100644 index 00000000000..d64169b6551 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/inheritance/Lookup.expected @@ -0,0 +1,13 @@ +| class Base | meth | Function meth | 3 | +| class Derived1 | meth | Function meth | 8 | +| class Derived2 | meth | Function meth | 13 | +| class Derived3 | meth | Function meth | 8 | +| class Derived4 | meth | Function meth | 21 | +| class Derived5 | meth | Function meth | 26 | +| class Derived6 | meth | Function meth | 31 | +| class Missing1 | a | Function a | 49 | +| class Missing2 | b | Function b | 53 | +| class Missing2 | meth | Function meth | 3 | +| class Missing3 | c | Function c | 57 | +| class Wrong1 | meth | Function meth | 37 | +| class Wrong2 | meth | Function meth | 42 | diff --git a/python/ql/test/library-tests/PointsTo/inheritance/Lookup.ql b/python/ql/test/library-tests/PointsTo/inheritance/Lookup.ql new file mode 100644 index 00000000000..5f229b8d0d0 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/inheritance/Lookup.ql @@ -0,0 +1,7 @@ + +import python +import semmle.python.pointsto.PointsTo + +from ClassObject cls, string name, PyFunctionObject f +where PointsTo::Types::class_attribute_lookup(cls, name, f, _, _) +select cls.toString(), name, f.toString(), f.getFunction().getLocation().getStartLine() diff --git a/python/ql/test/library-tests/PointsTo/inheritance/MetaClass.expected b/python/ql/test/library-tests/PointsTo/inheritance/MetaClass.expected new file mode 100644 index 00000000000..0348b74c1fb --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/inheritance/MetaClass.expected @@ -0,0 +1,9 @@ +| class Base | builtin-class type | +| class Derived1 | builtin-class type | +| class Derived2 | builtin-class type | +| class Derived3 | builtin-class type | +| class Derived4 | builtin-class type | +| class Derived5 | builtin-class type | +| class Derived6 | builtin-class type | +| class Wrong1 | builtin-class type | +| class Wrong2 | builtin-class type | diff --git a/python/ql/test/library-tests/PointsTo/inheritance/MetaClass.ql b/python/ql/test/library-tests/PointsTo/inheritance/MetaClass.ql new file mode 100644 index 00000000000..064cc2ca688 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/inheritance/MetaClass.ql @@ -0,0 +1,8 @@ + +import python + +from ClassObject cls, ClassObject meta +where not cls.isBuiltin() and +meta = cls.getMetaClass() +select cls.toString(), meta.toString() + diff --git a/python/ql/test/library-tests/PointsTo/inheritance/Mro.expected b/python/ql/test/library-tests/PointsTo/inheritance/Mro.expected new file mode 100644 index 00000000000..b64915a38a3 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/inheritance/Mro.expected @@ -0,0 +1,12 @@ +| class Base | [Base, object] | +| class Derived1 | [Derived1, Base, object] | +| class Derived2 | [Derived2, Derived1, Base, object] | +| class Derived3 | [Derived3, Derived1, Base, object] | +| class Derived4 | [Derived4, Derived3, Derived2, Derived1, Base, object] | +| class Derived5 | [Derived5, Derived1, Base, object] | +| class Derived6 | [Derived6, Derived5, Derived2, Derived1, Base, object] | +| class Missing1 | [Missing1, UNKNOWN, object] | +| class Missing2 | [Missing2, Base, UNKNOWN, object] | +| class Missing3 | [Missing3, UNKNOWN, Base, object] | +| class Wrong1 | [Wrong1, Derived5, Derived2, Derived1, Base, object] | +| class Wrong2 | [Wrong2, Derived3, Derived2, Derived1, Base, object] | diff --git a/python/ql/test/library-tests/PointsTo/inheritance/Mro.ql b/python/ql/test/library-tests/PointsTo/inheritance/Mro.ql new file mode 100644 index 00000000000..d7373fc2b35 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/inheritance/Mro.ql @@ -0,0 +1,17 @@ + +import python + +/** Make unknown type visible */ +class UnknownType extends ClassObject { + + UnknownType() { this = theUnknownType() } + + override string toString() { result = "*UNKNOWN TYPE" } + + override string getName() { result = "UNKNOWN" } + +} + +from ClassObject c +where not c.isBuiltin() +select c.toString(), c.getMro() diff --git a/python/ql/test/library-tests/PointsTo/inheritance/Self.expected b/python/ql/test/library-tests/PointsTo/inheritance/Self.expected new file mode 100644 index 00000000000..ba9aee6dd7b --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/inheritance/Self.expected @@ -0,0 +1,18 @@ +| 9 | self | class Derived1 | +| 9 | self | class Derived2 | +| 9 | self | class Derived4 | +| 9 | self | class Derived5 | +| 9 | self | class Derived6 | +| 9 | self | class Wrong1 | +| 9 | self | class Wrong2 | +| 14 | self | class Derived2 | +| 14 | self | class Derived4 | +| 14 | self | class Derived6 | +| 14 | self | class Wrong1 | +| 14 | self | class Wrong2 | +| 22 | self | class Derived4 | +| 27 | self | class Derived5 | +| 27 | self | class Derived6 | +| 32 | self | class Derived6 | +| 38 | self | class Wrong1 | +| 43 | self | class Wrong2 | diff --git a/python/ql/test/library-tests/PointsTo/inheritance/Self.ql b/python/ql/test/library-tests/PointsTo/inheritance/Self.ql new file mode 100644 index 00000000000..a72da5f5248 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/inheritance/Self.ql @@ -0,0 +1,6 @@ + +import python + +from NameNode n, Object value, ClassObject cls +where n.getId() = "self" and n.refersTo(value, cls, _) +select n.getNode().getLocation().getStartLine(), value.toString(), cls.toString() diff --git a/python/ql/test/library-tests/PointsTo/inheritance/SuperTypes.expected b/python/ql/test/library-tests/PointsTo/inheritance/SuperTypes.expected new file mode 100644 index 00000000000..48ef4076ed2 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/inheritance/SuperTypes.expected @@ -0,0 +1,37 @@ +| class Base | builtin-class object | +| class Derived1 | builtin-class object | +| class Derived1 | class Base | +| class Derived2 | builtin-class object | +| class Derived2 | class Base | +| class Derived2 | class Derived1 | +| class Derived3 | builtin-class object | +| class Derived3 | class Base | +| class Derived3 | class Derived1 | +| class Derived4 | builtin-class object | +| class Derived4 | class Base | +| class Derived4 | class Derived1 | +| class Derived4 | class Derived2 | +| class Derived4 | class Derived3 | +| class Derived5 | builtin-class object | +| class Derived5 | class Base | +| class Derived5 | class Derived1 | +| class Derived6 | builtin-class object | +| class Derived6 | class Base | +| class Derived6 | class Derived1 | +| class Derived6 | class Derived2 | +| class Derived6 | class Derived5 | +| class Missing1 | builtin-class object | +| class Missing2 | builtin-class object | +| class Missing2 | class Base | +| class Missing3 | builtin-class object | +| class Missing3 | class Base | +| class Wrong1 | builtin-class object | +| class Wrong1 | class Base | +| class Wrong1 | class Derived1 | +| class Wrong1 | class Derived2 | +| class Wrong1 | class Derived5 | +| class Wrong2 | builtin-class object | +| class Wrong2 | class Base | +| class Wrong2 | class Derived1 | +| class Wrong2 | class Derived2 | +| class Wrong2 | class Derived3 | \ No newline at end of file diff --git a/python/ql/test/library-tests/PointsTo/inheritance/SuperTypes.ql b/python/ql/test/library-tests/PointsTo/inheritance/SuperTypes.ql new file mode 100644 index 00000000000..0793957f2e4 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/inheritance/SuperTypes.ql @@ -0,0 +1,7 @@ + +import python + +from ClassObject cls, ClassObject sup +where not cls.isBuiltin() and +sup = cls.getASuperType() +select cls.toString(), sup.toString() diff --git a/python/ql/test/library-tests/PointsTo/inheritance/test.py b/python/ql/test/library-tests/PointsTo/inheritance/test.py new file mode 100644 index 00000000000..58e84dac306 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/inheritance/test.py @@ -0,0 +1,59 @@ +class Base(object): + + def meth(self): + pass + +class Derived1(Base): + + def meth(self): + return super(Derived1, self).meth() + +class Derived2(Derived1): + + def meth(self): + return super(Derived2, self).meth() + +class Derived3(Derived1): + pass + +class Derived4(Derived3, Derived2): + + def meth(self): + return super(Derived4, self).meth() + +class Derived5(Derived1): + + def meth(self): + return super(Derived5, self).meth() + +class Derived6(Derived5, Derived2): + + def meth(self): + return super(Derived6, self).meth() + +#Incorrect use of super() +class Wrong1(Derived5, Derived2): + + def meth(self): + return super(Derived5, self).meth() + +class Wrong2(Derived3, Derived2): + + def meth(self): + return super(Derived3, self).meth() + +UT = type.__new__(no_name, no_args) +UV = UT() + +class Missing1(UT): + def a(self): + pass + +class Missing2(Base, UT): + def b(self): + pass + +class Missing3(UT, Base): + def c(self): + pass + diff --git a/python/ql/test/library-tests/PointsTo/lookup/Lookup.expected b/python/ql/test/library-tests/PointsTo/lookup/Lookup.expected new file mode 100644 index 00000000000..d01f9d843aa --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/lookup/Lookup.expected @@ -0,0 +1,79 @@ +| 3 | object | global | +| 8 | self | local | +| 10 | C | global | +| 13 | len | global | +| 13 | sys | global | +| 14 | C | global | +| 16 | D | global | +| 17 | v1 | global | +| 20 | len | global | +| 20 | sys | global | +| 21 | C | global | +| 23 | D | global | +| 24 | v3 | local | +| 27 | arg | local | +| 29 | object | global | +| 30 | classmethod | global | +| 34 | deco | global | +| 38 | f | global | +| 38 | g | global | +| 41 | f | local | +| 43 | object | global | +| 45 | deco | global | +| 49 | v1 | global | +| 50 | v2 | global | +| 51 | v3 | global | +| 52 | v4 | global | +| 53 | list | global | +| 56 | len | global | +| 56 | sys | global | +| 57 | C | global | +| 59 | D | global | +| 60 | args | local | +| 60 | list | global | +| 60 | v5 | local | +| 63 | dict | global | +| 63 | tuple | global | +| 64 | dict | global | +| 66 | dict | global | +| 67 | tuple | global | +| 68 | tuple | global | +| 71 | abstractmethod | global | +| 74 | unknown | global | +| 80 | list | global | +| 80 | unknown | global | +| 80 | x | local | +| 80 | y | non-local | +| 80 | z | non-local | +| 82 | inner | local | +| 87 | list | global | +| 87 | unknown | global | +| 87 | x | non-local | +| 87 | y | non-local | +| 87 | z | non-local | +| 89 | y | local | +| 89 | z | local | +| 90 | inner | local | +| 92 | following | global | +| 98 | a | local | +| 99 | b | local | +| 100 | c | local | +| 103 | BaseException | global | +| 105 | A | local | +| 106 | a | local | +| 111 | z | global | +| 114 | list | global | +| 114 | tuple | global | +| 115 | _tuple | local | +| 116 | _list | local | +| 119 | t | local | +| 120 | d | local | +| 123 | object | global | +| 128 | arg | non-local | +| 128 | args | local | +| 129 | wrapper | local | +| 131 | _internal | local | +| 136 | x | global | +| 140 | object | global | +| 142 | x | global | +| 143 | x | local | \ No newline at end of file diff --git a/python/ql/test/library-tests/PointsTo/lookup/Lookup.ql b/python/ql/test/library-tests/PointsTo/lookup/Lookup.ql new file mode 100644 index 00000000000..43007b7f816 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/lookup/Lookup.ql @@ -0,0 +1,12 @@ +import python + +from string l, NameNode n +where n.getLocation().getFile().getName().matches("%test.py") and +( + n.isGlobal() and l = "global" + or + n.isLocal() and l = "local" + or + n.isNonLocal() and l = "non-local" +) +select n.getLocation().getStartLine(), n.getId(), l diff --git a/python/ql/test/library-tests/PointsTo/lookup/test.py b/python/ql/test/library-tests/PointsTo/lookup/test.py new file mode 100644 index 00000000000..8b748230855 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/lookup/test.py @@ -0,0 +1,143 @@ +from __future__ import unicode_literals +import sys +class C(object): + + x = 'C_x' + + def __init__(self): + self.y = 'c_y' + +class D(C): + pass + +if len(sys.argv) > 2: + v1 = C +else: + v1 = D +v2 = v1() + +def f(): + if len(sys.argv) > 3: + v3 = C() + else: + v3 = D() + return v3 + +def g(arg): + return arg + +class X(object): + @classmethod + def method1(cls): + pass + + @deco + def method2(self): + pass + +v4 = g(f()) + +def deco(f): + return f + +class Y(object): + + @deco + def method2(self): + pass + +v1 +v2 +v3 +v4 +list + +def h(args): + if len(sys.argv) > 4: + v5 = C() + else: + v5 = D() + return v5, list(args) + +def j(): + return tuple, dict +dict +dict = 7 +dict +tuple = tuple +tuple + +from abc import abstractmethod +abstractmethod + +from module import unknown +unknown + +#Value of variables in inner functions +def outer(): + y = 1 + def inner(x): + return x + y + z + unknown + list + z = 2; + return inner + +def outer_use_vars(x): + y = 1 + def inner(): + return x + y + z + unknown + list + z = 2; + y + z + return inner + +y = lambda x : following() + +def following(): + pass + +def params_and_defaults(a, b={}, c = 1): + a + b + c + +def inner_cls(): + class A(BaseException): + pass + a = A() + raise a + + + + +z + +def multiple_assignment(): + _tuple, _list = tuple, list + _tuple + _list + +def vararg_kwarg(*t, **d): + t + d + + +class E(object): + + def _internal(arg): + # arg is not a C + def wrapper(args): + return arg(args) + return wrapper + + @_internal + def method(self, *args): + pass + +x = 1 +x + + +#Global in class scope +class F(object): + + x = x + x diff --git a/python/ql/test/library-tests/PointsTo/metaclass/test.expected b/python/ql/test/library-tests/PointsTo/metaclass/test.expected new file mode 100644 index 00000000000..b34df4189bd --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/metaclass/test.expected @@ -0,0 +1,7 @@ +| class C1 | class Meta1 | +| class C2 | class Meta2 | +| class C3 | builtin-class type | +| class C4 | class Meta2 | +| class Meta1 | builtin-class type | +| class Meta2 | builtin-class type | +| class NewStyleEvenForPython2 | builtin-class type | diff --git a/python/ql/test/library-tests/PointsTo/metaclass/test.py b/python/ql/test/library-tests/PointsTo/metaclass/test.py new file mode 100644 index 00000000000..c09b3546ecb --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/metaclass/test.py @@ -0,0 +1,36 @@ +import six + +class Meta1(type): + pass + +class Meta2(type): + pass + +@six.add_metaclass(Meta1) +class C1(object): + pass + +@six.add_metaclass(Meta2) +class C2(object): + pass + +#No explicit metaclass +class C3(object): + pass + +#Multiple non-conflicting metaclasses: +class C4(C2, object): + pass + +#Metaclass conflict +class C5(C2, C1): + pass + +@not_known_decorator +class C6(object): + pass + +__metaclass__ = type + +class NewStyleEvenForPython2: + pass diff --git a/python/ql/test/library-tests/PointsTo/metaclass/test.ql b/python/ql/test/library-tests/PointsTo/metaclass/test.ql new file mode 100644 index 00000000000..c1df0b003c5 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/metaclass/test.ql @@ -0,0 +1,6 @@ + +import python + +from ClassObject cls +where cls.getPyClass().getEnclosingModule().getName() = "test" +select cls.toString(), cls.getMetaClass().toString() diff --git a/python/ql/test/library-tests/PointsTo/new/Call.expected b/python/ql/test/library-tests/PointsTo/new/Call.expected new file mode 100644 index 00000000000..b97734a8302 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/Call.expected @@ -0,0 +1,28 @@ +| b_condition.py:36 | ControlFlowNode for isinstance() | isinstance | +| b_condition.py:82 | ControlFlowNode for callable() | callable | +| b_condition.py:102 | ControlFlowNode for isinstance() | isinstance | +| d_globals.py:29 | ControlFlowNode for init() | init | +| d_globals.py:77 | ControlFlowNode for set_g4() | set_g4 | +| d_globals.py:81 | ControlFlowNode for set_g4_indirect() | set_g4_indirect | +| d_globals.py:104 | ControlFlowNode for inner() | outer.inner | +| d_globals.py:128 | ControlFlowNode for Attribute() | list.append | +| g_class_init.py:6 | ControlFlowNode for Attribute() | C._init | +| g_class_init.py:11 | ControlFlowNode for Attribute() | C._init2 | +| g_class_init.py:18 | ControlFlowNode for isinstance() | isinstance | +| g_class_init.py:36 | ControlFlowNode for Attribute() | object.__init__ | +| l_calls.py:4 | ControlFlowNode for Attribute() | list.append | +| l_calls.py:7 | ControlFlowNode for len() | len | +| l_calls.py:9 | ControlFlowNode for foo() | foo | +| l_calls.py:10 | ControlFlowNode for bar() | bar | +| l_calls.py:24 | ControlFlowNode for Attribute() | Owner.cm | +| l_calls.py:25 | ControlFlowNode for Attribute() | Owner.cm2 | +| q_super.py:4 | ControlFlowNode for Attribute() | object.__init__ | +| q_super.py:12 | ControlFlowNode for Attribute() | Base2.__init__ | +| q_super.py:22 | ControlFlowNode for Attribute() | Base1.meth | +| q_super.py:27 | ControlFlowNode for Attribute() | Derived1.meth | +| q_super.py:32 | ControlFlowNode for Attribute() | Derived1.meth | +| q_super.py:38 | ControlFlowNode for Attribute() | Derived2.meth | +| q_super.py:52 | ControlFlowNode for Attribute() | DA.__init__ | +| q_super.py:59 | ControlFlowNode for Attribute() | DA.__init__ | +| q_super.py:66 | ControlFlowNode for Attribute() | DA.__init__ | +| q_super.py:76 | ControlFlowNode for i() | object.__init__ | diff --git a/python/ql/test/library-tests/PointsTo/new/Call.ql b/python/ql/test/library-tests/PointsTo/new/Call.ql new file mode 100644 index 00000000000..f740b0060f6 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/Call.ql @@ -0,0 +1,8 @@ + +import python +import Util + +from ControlFlowNode call, FunctionObject func + +where call = func.getACall() +select locate(call.getLocation(), "abdglq"), call.toString(), func.getQualifiedName() \ No newline at end of file diff --git a/python/ql/test/library-tests/PointsTo/new/ClassMethod.expected b/python/ql/test/library-tests/PointsTo/new/ClassMethod.expected new file mode 100644 index 00000000000..f93d242b1e4 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/ClassMethod.expected @@ -0,0 +1,2 @@ +| l_calls.py:24 | Function cm | code/l_calls.py:14 | +| l_calls.py:25 | Function cm2 | code/l_calls.py:18 | diff --git a/python/ql/test/library-tests/PointsTo/new/ClassMethod.ql b/python/ql/test/library-tests/PointsTo/new/ClassMethod.ql new file mode 100644 index 00000000000..2d13f2ae851 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/ClassMethod.ql @@ -0,0 +1,9 @@ + +import python +import semmle.python.types.Descriptors +import Util + +from ClassMethodObject cm, CallNode call +where call = cm.getACall() +select locate(call.getLocation(), "lp"), cm.getFunction().toString(), cm.(ControlFlowNode).getLocation().toString() + diff --git a/python/ql/test/library-tests/PointsTo/new/Dataflow.expected b/python/ql/test/library-tests/PointsTo/new/Dataflow.expected new file mode 100644 index 00000000000..5ea3736af76 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/Dataflow.expected @@ -0,0 +1,753 @@ +| __init__.py:0 | *_0 = ScopeEntryDefinition | +| __init__.py:0 | __name___0 = ScopeEntryDefinition | +| __init__.py:0 | __package___0 = ScopeEntryDefinition | +| __init__.py:0 | module2_0 = ImplicitSubModuleDefinition | +| __init__.py:0 | moduleX_0 = ImplicitSubModuleDefinition | +| __init__.py:0 | sys_0 = ScopeEntryDefinition | +| __init__.py:1 | *_1 = ImportStarRefinement(*_0) | +| __init__.py:1 | __name___1 = ImportStarRefinement(__name___0) | +| __init__.py:1 | __package___1 = ImportStarRefinement(__package___0) | +| __init__.py:1 | sys_1 = ImportStarRefinement(sys_0) | +| __init__.py:2 | *_2 = ImportStarRefinement(*_1) | +| __init__.py:2 | __name___2 = ImportStarRefinement(__name___1) | +| __init__.py:2 | __package___2 = ImportStarRefinement(__package___1) | +| __init__.py:2 | module_0 = ImportMember | +| __init__.py:3 | sys_2 = ImportExpr | +| __init__.py:4 | module3_0 = ImportMember | +| __init__.py:5 | module2_1 = IntegerLiteral | +| __init__.py:6 | module4_0 = ImportMember | +| __init__.py:7 | module5_0 = ImportMember | +| __init__.py:8 | moduleX_1 = ImportMember | +| a_simple.py:0 | __name___0 = ScopeEntryDefinition | +| a_simple.py:0 | __package___0 = ScopeEntryDefinition | +| a_simple.py:2 | f1_0 = FloatLiteral | +| a_simple.py:5 | i1_0 = IntegerLiteral | +| a_simple.py:6 | s_0 = Tuple | +| a_simple.py:8 | func_0 = FunctionExpr | +| a_simple.py:11 | C_0 = ClassExpr | +| a_simple.py:14 | d_0 = ParameterDefinition | +| a_simple.py:14 | t_0 = ParameterDefinition | +| a_simple.py:14 | vararg_kwarg_0 = FunctionExpr | +| a_simple.py:18 | multi_loop_0 = FunctionExpr | +| a_simple.py:18 | seq_0 = ParameterDefinition | +| a_simple.py:18 | y_0 = ScopeEntryDefinition | +| a_simple.py:19 | x_0 = None | +| a_simple.py:20 | x_1 = phi(x_0, x_2) | +| a_simple.py:20 | x_2 = ... | +| a_simple.py:20 | y_1 = phi(y_0, y_2) | +| a_simple.py:20 | y_2 = ... | +| a_simple.py:23 | with_definition_0 = FunctionExpr | +| a_simple.py:23 | x_0 = ParameterDefinition | +| a_simple.py:24 | y_0 = with | +| a_simple.py:27 | multi_loop_in_try_0 = FunctionExpr | +| a_simple.py:27 | p_0 = ScopeEntryDefinition | +| a_simple.py:27 | q_0 = ScopeEntryDefinition | +| a_simple.py:27 | x_0 = ParameterDefinition | +| a_simple.py:29 | p_1 = phi(p_0, p_2) | +| a_simple.py:29 | p_2 = ... | +| a_simple.py:29 | q_1 = phi(q_0, q_2) | +| a_simple.py:29 | q_2 = ... | +| a_simple.py:34 | args_0 = ParameterDefinition | +| a_simple.py:34 | f_0 = FunctionExpr | +| a_simple.py:34 | kwargs_0 = ParameterDefinition | +| b_condition.py:0 | __name___0 = ScopeEntryDefinition | +| b_condition.py:0 | __package___0 = ScopeEntryDefinition | +| b_condition.py:0 | double_attr_check_0 = ScopeEntryDefinition | +| b_condition.py:0 | g_0 = ScopeEntryDefinition | +| b_condition.py:0 | h_0 = ScopeEntryDefinition | +| b_condition.py:0 | k_0 = ScopeEntryDefinition | +| b_condition.py:0 | loop_0 = ScopeEntryDefinition | +| b_condition.py:0 | not_or_not_0 = ScopeEntryDefinition | +| b_condition.py:0 | odasa6261_0 = ScopeEntryDefinition | +| b_condition.py:0 | split_bool1_0 = ScopeEntryDefinition | +| b_condition.py:0 | v2_0 = ScopeEntryDefinition | +| b_condition.py:4 | f_0 = FunctionExpr | +| b_condition.py:4 | y_0 = ParameterDefinition | +| b_condition.py:5 | x_0 = IfExp | +| b_condition.py:8 | x_1 = IntegerLiteral | +| b_condition.py:9 | x_2 = Pi(x_0) [false] | +| b_condition.py:9 | x_3 = phi(x_1, x_2) | +| b_condition.py:11 | x_4 = IfExp | +| b_condition.py:14 | x_5 = IntegerLiteral | +| b_condition.py:15 | x_6 = Pi(x_4) [false] | +| b_condition.py:15 | x_7 = phi(x_5, x_6) | +| b_condition.py:17 | x_8 = IfExp | +| b_condition.py:20 | x_9 = None | +| b_condition.py:21 | x_10 = Pi(x_8) [false] | +| b_condition.py:21 | x_11 = phi(x_9, x_10) | +| b_condition.py:23 | x_12 = IfExp | +| b_condition.py:25 | x_13 = Pi(x_12) [true] | +| b_condition.py:25 | x_14 = IfExp | +| b_condition.py:26 | x_15 = ArgumentRefinement(x_14) | +| b_condition.py:28 | x_16 = IntegerLiteral | +| b_condition.py:29 | x_17 = phi(x_15, x_16) | +| b_condition.py:31 | x_18 = IfExp | +| b_condition.py:33 | x_19 = IntegerLiteral | +| b_condition.py:34 | x_20 = Pi(x_18) [false] | +| b_condition.py:34 | x_21 = phi(x_19, x_20) | +| b_condition.py:34 | x_22 = ArgumentRefinement(x_21) | +| b_condition.py:36 | x_23 = ArgumentRefinement(x_22) | +| b_condition.py:36 | x_24 = Pi(x_23) [true] | +| b_condition.py:37 | x_25 = ArgumentRefinement(x_24) | +| b_condition.py:39 | v2_1 = thing() | +| b_condition.py:41 | v2_2 = AttributeAssignment 'x'(v2_1) | +| b_condition.py:43 | v2_3 = Pi(v2_2) [true] | +| b_condition.py:47 | v2_4 = Pi(v2_2) [false] | +| b_condition.py:47 | v2_5 = phi(v2_3, v2_4) | +| b_condition.py:50 | g_1 = FunctionExpr | +| b_condition.py:50 | x_0 = ParameterDefinition | +| b_condition.py:50 | x_2 = Pi(x_0) [false] | +| b_condition.py:50 | x_3 = phi(x_1, x_2) | +| b_condition.py:52 | x_1 = Pi(x_0) [true] | +| b_condition.py:55 | loop_1 = FunctionExpr | +| b_condition.py:55 | seq_0 = ParameterDefinition | +| b_condition.py:55 | v_0 = ScopeEntryDefinition | +| b_condition.py:56 | v_1 = Pi(v_3) [false] | +| b_condition.py:56 | v_2 = phi(v_0, v_1, v_5) | +| b_condition.py:56 | v_3 = IterationDefinition | +| b_condition.py:58 | v_4 = Pi(v_3) [true] | +| b_condition.py:58 | v_5 = ArgumentRefinement(v_4) | +| b_condition.py:61 | double_attr_check_1 = FunctionExpr | +| b_condition.py:61 | x_0 = ParameterDefinition | +| b_condition.py:61 | x_5 = Pi(x_2) [false] | +| b_condition.py:61 | x_5 = Pi(x_3) [false] | +| b_condition.py:61 | x_7 = phi(x_1, x_4) | +| b_condition.py:61 | x_7 = phi(x_2, x_5) | +| b_condition.py:61 | y_0 = ParameterDefinition | +| b_condition.py:61 | y_2 = Pi(y_0) [false] | +| b_condition.py:61 | y_3 = phi(y_0, y_1) | +| b_condition.py:61 | y_3 = phi(y_1, y_2) | +| b_condition.py:63 | x_1 = Pi(x_0) [true] | +| b_condition.py:64 | x_2 = Pi(x_0) [false] | +| b_condition.py:65 | y_1 = Pi(y_0) [true] | +| b_condition.py:66 | x_3 = Pi(x_2) [true] | +| b_condition.py:67 | x_4 = Pi(x_3) [true] | +| b_condition.py:69 | h_1 = FunctionExpr | +| b_condition.py:70 | b_0 = IfExp | +| b_condition.py:72 | b_1 = IntegerLiteral | +| b_condition.py:73 | b_2 = Pi(b_0) [false] | +| b_condition.py:73 | b_3 = phi(b_1, b_2) | +| b_condition.py:75 | k_1 = FunctionExpr | +| b_condition.py:76 | t_0 = type | +| b_condition.py:78 | t_1 = object | +| b_condition.py:79 | t_2 = Pi(t_0) [false] | +| b_condition.py:79 | t_3 = phi(t_1, t_2) | +| b_condition.py:79 | t_4 = ArgumentRefinement(t_3) | +| b_condition.py:81 | bar_0 = ScopeEntryDefinition | +| b_condition.py:81 | bar_2 = phi(bar_0, bar_1) | +| b_condition.py:81 | foo_0 = ParameterDefinition | +| b_condition.py:81 | foo_4 = Pi(foo_1) [false] | +| b_condition.py:81 | foo_5 = phi(foo_2, foo_4) | +| b_condition.py:81 | odasa6261_1 = FunctionExpr | +| b_condition.py:82 | foo_1 = ArgumentRefinement(foo_0) | +| b_condition.py:83 | bar_1 = FunctionExpr | +| b_condition.py:83 | foo_2 = Pi(foo_1) [true] | +| b_condition.py:83 | foo_3 = ScopeEntryDefinition | +| b_condition.py:87 | split_bool1_1 = FunctionExpr | +| b_condition.py:87 | x_0 = ParameterDefinition | +| b_condition.py:87 | y_0 = ParameterDefinition | +| b_condition.py:88 | x_1 = Pi(x_0) [true] | +| b_condition.py:90 | x_4 = Pi(x_0) [false] | +| b_condition.py:90 | x_5 = SingleSuccessorGuard(x_4) [false] | +| b_condition.py:90 | x_6 = SingleSuccessorGuard(x_1) [false] | +| b_condition.py:90 | y_1 = Pi(y_0) [true] | +| b_condition.py:90 | y_4 = Pi(y_0) [false] | +| b_condition.py:92 | x_2 = SingleSuccessorGuard(x_5) [false] | +| b_condition.py:92 | x_7 = SingleSuccessorGuard(x_6) [true] | +| b_condition.py:93 | y_5 = ArgumentRefinement(y_4) | +| b_condition.py:95 | y_2 = ArgumentRefinement(y_1) | +| b_condition.py:96 | y_3 = SingleSuccessorGuard(y_2) [true] | +| b_condition.py:96 | y_6 = SingleSuccessorGuard(y_5) [false] | +| b_condition.py:97 | x_3 = ArgumentRefinement(x_2) | +| b_condition.py:99 | x_8 = ArgumentRefinement(x_7) | +| b_condition.py:101 | a_0 = ParameterDefinition | +| b_condition.py:101 | not_or_not_1 = FunctionExpr | +| b_condition.py:102 | a_1 = ArgumentRefinement(a_0) | +| b_condition.py:104 | a_2 = Pi(a_1) [false] | +| b_condition.py:105 | a_3 = Pi(a_2) [false] | +| b_condition.py:107 | a_4 = Pi(a_3) [false] | +| d_globals.py:0 | D_0 = ScopeEntryDefinition | +| d_globals.py:0 | Ugly_0 = ScopeEntryDefinition | +| d_globals.py:0 | X_0 = ScopeEntryDefinition | +| d_globals.py:0 | __name___0 = ScopeEntryDefinition | +| d_globals.py:0 | __package___0 = ScopeEntryDefinition | +| d_globals.py:0 | dict_0 = ScopeEntryDefinition | +| d_globals.py:0 | g3_0 = ScopeEntryDefinition | +| d_globals.py:0 | g4_0 = ScopeEntryDefinition | +| d_globals.py:0 | get_g4_0 = ScopeEntryDefinition | +| d_globals.py:0 | glob_0 = ScopeEntryDefinition | +| d_globals.py:0 | k_0 = ScopeEntryDefinition | +| d_globals.py:0 | modinit_0 = ScopeEntryDefinition | +| d_globals.py:0 | outer_0 = ScopeEntryDefinition | +| d_globals.py:0 | redefine_0 = ScopeEntryDefinition | +| d_globals.py:0 | set_g4_0 = ScopeEntryDefinition | +| d_globals.py:0 | set_g4_indirect_0 = ScopeEntryDefinition | +| d_globals.py:0 | tuple_0 = ScopeEntryDefinition | +| d_globals.py:0 | use_list_attribute_0 = ScopeEntryDefinition | +| d_globals.py:0 | x_0 = ScopeEntryDefinition | +| d_globals.py:0 | y_0 = ScopeEntryDefinition | +| d_globals.py:0 | z_0 = ScopeEntryDefinition | +| d_globals.py:2 | dict_2 = ScopeEntryDefinition | +| d_globals.py:2 | g1_2 = ScopeEntryDefinition | +| d_globals.py:2 | g2_2 = ScopeEntryDefinition | +| d_globals.py:2 | g3_2 = ScopeEntryDefinition | +| d_globals.py:2 | g4_1 = ScopeEntryDefinition | +| d_globals.py:2 | glob_2 = ScopeEntryDefinition | +| d_globals.py:2 | j_0 = FunctionExpr | +| d_globals.py:2 | tuple_2 = ScopeEntryDefinition | +| d_globals.py:2 | z_2 = ScopeEntryDefinition | +| d_globals.py:5 | dict_1 = IntegerLiteral | +| d_globals.py:7 | tuple_1 = tuple | +| d_globals.py:14 | g1_0 = None | +| d_globals.py:16 | assign_global_0 = FunctionExpr | +| d_globals.py:16 | g2_3 = ScopeEntryDefinition | +| d_globals.py:16 | g3_3 = ScopeEntryDefinition | +| d_globals.py:16 | g4_2 = ScopeEntryDefinition | +| d_globals.py:16 | glob_3 = ScopeEntryDefinition | +| d_globals.py:16 | z_3 = ScopeEntryDefinition | +| d_globals.py:18 | g1_3 = IntegerLiteral | +| d_globals.py:23 | g2_0 = None | +| d_globals.py:25 | g1_4 = ScopeEntryDefinition | +| d_globals.py:25 | g3_4 = ScopeEntryDefinition | +| d_globals.py:25 | g4_3 = ScopeEntryDefinition | +| d_globals.py:25 | glob_4 = ScopeEntryDefinition | +| d_globals.py:25 | init_0 = FunctionExpr | +| d_globals.py:25 | z_4 = ScopeEntryDefinition | +| d_globals.py:27 | g2_4 = IntegerLiteral | +| d_globals.py:29 | g1_1 = CallsiteRefinement(g1_0) | +| d_globals.py:29 | g2_1 = CallsiteRefinement(g2_0) | +| d_globals.py:29 | glob_1 = CallsiteRefinement(glob_0) | +| d_globals.py:29 | z_1 = CallsiteRefinement(z_0) | +| d_globals.py:33 | g3_1 = None | +| d_globals.py:35 | Ugly_1 = ClassExpr | +| d_globals.py:37 | __init___0 = FunctionExpr | +| d_globals.py:37 | g1_5 = ScopeEntryDefinition | +| d_globals.py:37 | g2_5 = ScopeEntryDefinition | +| d_globals.py:37 | g4_4 = ScopeEntryDefinition | +| d_globals.py:37 | glob_5 = ScopeEntryDefinition | +| d_globals.py:37 | self_0 = ParameterDefinition | +| d_globals.py:37 | z_5 = ScopeEntryDefinition | +| d_globals.py:39 | g3_5 = IntegerLiteral | +| d_globals.py:41 | g1_6 = ScopeEntryDefinition | +| d_globals.py:41 | g2_6 = ScopeEntryDefinition | +| d_globals.py:41 | g3_6 = ScopeEntryDefinition | +| d_globals.py:41 | g4_5 = ScopeEntryDefinition | +| d_globals.py:41 | glob_6 = ScopeEntryDefinition | +| d_globals.py:41 | meth_0 = FunctionExpr | +| d_globals.py:41 | self_0 = ParameterDefinition | +| d_globals.py:41 | z_6 = ScopeEntryDefinition | +| d_globals.py:46 | x_1 = IntegerLiteral | +| d_globals.py:49 | x_2 = IntegerLiteral | +| d_globals.py:51 | x_3 = phi(x_1, x_2) | +| d_globals.py:52 | y_1 = IntegerLiteral | +| d_globals.py:54 | y_2 = IntegerLiteral | +| d_globals.py:59 | y_3 = phi(y_1, y_2) | +| d_globals.py:62 | X_1 = ClassExpr | +| d_globals.py:62 | X_2 = ScopeEntryDefinition | +| d_globals.py:62 | g3_7 = ScopeEntryDefinition | +| d_globals.py:62 | y_0 = ScopeEntryDefinition | +| d_globals.py:62 | y_4 = ScopeEntryDefinition | +| d_globals.py:63 | y_1 = y | +| d_globals.py:64 | v4_0 = v3 | +| d_globals.py:70 | arg_0 = ParameterDefinition | +| d_globals.py:70 | g1_7 = ScopeEntryDefinition | +| d_globals.py:70 | g2_7 = ScopeEntryDefinition | +| d_globals.py:70 | g3_8 = ScopeEntryDefinition | +| d_globals.py:70 | g4_7 = ScopeEntryDefinition | +| d_globals.py:70 | glob_7 = ScopeEntryDefinition | +| d_globals.py:70 | k_1 = FunctionExpr | +| d_globals.py:70 | z_7 = ScopeEntryDefinition | +| d_globals.py:73 | g4_6 = None | +| d_globals.py:75 | g1_8 = ScopeEntryDefinition | +| d_globals.py:75 | g2_8 = ScopeEntryDefinition | +| d_globals.py:75 | g3_9 = ScopeEntryDefinition | +| d_globals.py:75 | g4_8 = ScopeEntryDefinition | +| d_globals.py:75 | get_g4_1 = FunctionExpr | +| d_globals.py:75 | glob_8 = ScopeEntryDefinition | +| d_globals.py:75 | set_g4_2 = ScopeEntryDefinition | +| d_globals.py:75 | z_8 = ScopeEntryDefinition | +| d_globals.py:77 | g1_9 = CallsiteRefinement(g1_8) | +| d_globals.py:77 | g2_9 = CallsiteRefinement(g2_8) | +| d_globals.py:77 | g3_10 = CallsiteRefinement(g3_9) | +| d_globals.py:77 | g4_9 = Pi(g4_8) [true] | +| d_globals.py:77 | g4_10 = CallsiteRefinement(g4_9) | +| d_globals.py:77 | glob_9 = CallsiteRefinement(glob_8) | +| d_globals.py:77 | z_9 = CallsiteRefinement(z_8) | +| d_globals.py:78 | g1_10 = phi(g1_8, g1_9) | +| d_globals.py:78 | g2_10 = phi(g2_8, g2_9) | +| d_globals.py:78 | g3_11 = phi(g3_9, g3_10) | +| d_globals.py:78 | g4_11 = Pi(g4_8) [false] | +| d_globals.py:78 | g4_12 = phi(g4_10, g4_11) | +| d_globals.py:78 | glob_10 = phi(glob_8, glob_9) | +| d_globals.py:78 | z_10 = phi(z_8, z_9) | +| d_globals.py:80 | g1_11 = ScopeEntryDefinition | +| d_globals.py:80 | g2_11 = ScopeEntryDefinition | +| d_globals.py:80 | g3_12 = ScopeEntryDefinition | +| d_globals.py:80 | g4_13 = ScopeEntryDefinition | +| d_globals.py:80 | glob_11 = ScopeEntryDefinition | +| d_globals.py:80 | set_g4_1 = FunctionExpr | +| d_globals.py:80 | set_g4_indirect_2 = ScopeEntryDefinition | +| d_globals.py:80 | z_11 = ScopeEntryDefinition | +| d_globals.py:81 | g1_12 = CallsiteRefinement(g1_11) | +| d_globals.py:81 | g2_12 = CallsiteRefinement(g2_11) | +| d_globals.py:81 | g3_13 = CallsiteRefinement(g3_12) | +| d_globals.py:81 | g4_14 = CallsiteRefinement(g4_13) | +| d_globals.py:81 | glob_12 = CallsiteRefinement(glob_11) | +| d_globals.py:81 | z_12 = CallsiteRefinement(z_11) | +| d_globals.py:83 | g1_13 = ScopeEntryDefinition | +| d_globals.py:83 | g2_13 = ScopeEntryDefinition | +| d_globals.py:83 | g3_14 = ScopeEntryDefinition | +| d_globals.py:83 | glob_13 = ScopeEntryDefinition | +| d_globals.py:83 | set_g4_indirect_1 = FunctionExpr | +| d_globals.py:83 | z_13 = ScopeEntryDefinition | +| d_globals.py:85 | g4_15 = False | +| d_globals.py:87 | modinit_1 = ClassExpr | +| d_globals.py:92 | modinit_2 = DeletionDefinition | +| d_globals.py:95 | g1_14 = ScopeEntryDefinition | +| d_globals.py:95 | g2_14 = ScopeEntryDefinition | +| d_globals.py:95 | g3_15 = ScopeEntryDefinition | +| d_globals.py:95 | g4_16 = ScopeEntryDefinition | +| d_globals.py:95 | glob_14 = ScopeEntryDefinition | +| d_globals.py:95 | outer_1 = FunctionExpr | +| d_globals.py:95 | z_14 = ScopeEntryDefinition | +| d_globals.py:96 | g1_16 = ScopeEntryDefinition | +| d_globals.py:96 | g2_16 = ScopeEntryDefinition | +| d_globals.py:96 | g3_17 = ScopeEntryDefinition | +| d_globals.py:96 | g4_18 = ScopeEntryDefinition | +| d_globals.py:96 | inner_0 = FunctionExpr | +| d_globals.py:96 | z_16 = ScopeEntryDefinition | +| d_globals.py:98 | glob_16 = IntegerLiteral | +| d_globals.py:101 | g1_17 = ScopeEntryDefinition | +| d_globals.py:101 | g2_17 = ScopeEntryDefinition | +| d_globals.py:101 | g3_18 = ScopeEntryDefinition | +| d_globals.py:101 | g4_19 = ScopeEntryDefinition | +| d_globals.py:101 | glob_17 = ScopeEntryDefinition | +| d_globals.py:101 | otherInner_0 = FunctionExpr | +| d_globals.py:101 | z_17 = ScopeEntryDefinition | +| d_globals.py:104 | g1_15 = CallsiteRefinement(g1_14) | +| d_globals.py:104 | g2_15 = CallsiteRefinement(g2_14) | +| d_globals.py:104 | g3_16 = CallsiteRefinement(g3_15) | +| d_globals.py:104 | g4_17 = CallsiteRefinement(g4_16) | +| d_globals.py:104 | glob_15 = CallsiteRefinement(glob_14) | +| d_globals.py:104 | z_15 = CallsiteRefinement(z_14) | +| d_globals.py:107 | g1_18 = ScopeEntryDefinition | +| d_globals.py:107 | g2_18 = ScopeEntryDefinition | +| d_globals.py:107 | g3_19 = ScopeEntryDefinition | +| d_globals.py:107 | g4_20 = ScopeEntryDefinition | +| d_globals.py:107 | glob_18 = ScopeEntryDefinition | +| d_globals.py:107 | redefine_1 = FunctionExpr | +| d_globals.py:107 | z_18 = ScopeEntryDefinition | +| d_globals.py:110 | z_19 = IntegerLiteral | +| d_globals.py:113 | glob_19 = IntegerLiteral | +| d_globals.py:118 | D_1 = ClassExpr | +| d_globals.py:120 | __init___0 = FunctionExpr | +| d_globals.py:120 | g1_19 = ScopeEntryDefinition | +| d_globals.py:120 | g2_19 = ScopeEntryDefinition | +| d_globals.py:120 | g3_20 = ScopeEntryDefinition | +| d_globals.py:120 | g4_21 = ScopeEntryDefinition | +| d_globals.py:120 | glob_20 = ScopeEntryDefinition | +| d_globals.py:120 | self_0 = ParameterDefinition | +| d_globals.py:120 | z_20 = ScopeEntryDefinition | +| d_globals.py:123 | dict_3 = ScopeEntryDefinition | +| d_globals.py:123 | foo_0 = FunctionExpr | +| d_globals.py:123 | g1_20 = ScopeEntryDefinition | +| d_globals.py:123 | g2_20 = ScopeEntryDefinition | +| d_globals.py:123 | g3_21 = ScopeEntryDefinition | +| d_globals.py:123 | g4_22 = ScopeEntryDefinition | +| d_globals.py:123 | glob_21 = ScopeEntryDefinition | +| d_globals.py:123 | self_0 = ParameterDefinition | +| d_globals.py:123 | z_21 = ScopeEntryDefinition | +| d_globals.py:126 | g1_21 = ScopeEntryDefinition | +| d_globals.py:126 | g2_21 = ScopeEntryDefinition | +| d_globals.py:126 | g3_22 = ScopeEntryDefinition | +| d_globals.py:126 | g4_23 = ScopeEntryDefinition | +| d_globals.py:126 | glob_22 = ScopeEntryDefinition | +| d_globals.py:126 | use_list_attribute_1 = FunctionExpr | +| d_globals.py:126 | z_22 = ScopeEntryDefinition | +| d_globals.py:127 | l_0 = List | +| d_globals.py:128 | g1_22 = CallsiteRefinement(g1_21) | +| d_globals.py:128 | g2_22 = CallsiteRefinement(g2_21) | +| d_globals.py:128 | g3_23 = CallsiteRefinement(g3_22) | +| d_globals.py:128 | g4_24 = CallsiteRefinement(g4_23) | +| d_globals.py:128 | glob_23 = CallsiteRefinement(glob_22) | +| d_globals.py:128 | l_1 = ArgumentRefinement(l_0) | +| d_globals.py:128 | z_23 = CallsiteRefinement(z_22) | +| e_temporal.py:0 | __name___0 = ScopeEntryDefinition | +| e_temporal.py:0 | __package___0 = ScopeEntryDefinition | +| e_temporal.py:0 | x_0 = ScopeEntryDefinition | +| e_temporal.py:2 | sys_0 = ImportExpr | +| e_temporal.py:4 | f_0 = FunctionExpr | +| e_temporal.py:4 | sys_1 = ScopeEntryDefinition | +| e_temporal.py:9 | arg_0 = ParameterDefinition | +| e_temporal.py:9 | g_0 = FunctionExpr | +| e_temporal.py:12 | x_1 = g() | +| f_finally.py:0 | __name___0 = ScopeEntryDefinition | +| f_finally.py:0 | __package___0 = ScopeEntryDefinition | +| f_finally.py:1 | Queue_0 = ClassExpr | +| f_finally.py:3 | close_0 = FunctionExpr | +| f_finally.py:3 | close_4 = Pi(close_0) [false] | +| f_finally.py:3 | close_5 = phi(close_3, close_4) | +| f_finally.py:3 | self_0 = ParameterDefinition | +| f_finally.py:3 | self_3 = phi(self_1, self_2) | +| f_finally.py:4 | self_1 = AttributeAssignment '_closed'(self_0) | +| f_finally.py:8 | close_0 = Attribute | +| f_finally.py:8 | close_1 = Attribute | +| f_finally.py:9 | close_2 = SingleSuccessorGuard(close_1) [true] | +| f_finally.py:10 | close_3 = Pi(close_0) [true] | +| f_finally.py:10 | self_2 = AttributeAssignment '_close'(self_1) | +| g_class_init.py:0 | __name___0 = ScopeEntryDefinition | +| g_class_init.py:0 | __package___0 = ScopeEntryDefinition | +| g_class_init.py:3 | C_0 = ClassExpr | +| g_class_init.py:5 | __init___0 = FunctionExpr | +| g_class_init.py:5 | self_0 = ParameterDefinition | +| g_class_init.py:6 | self_1 = SelfCallsiteRefinement(self_0) | +| g_class_init.py:7 | self_2 = AttributeAssignment 'x'(self_1) | +| g_class_init.py:9 | _init_0 = FunctionExpr | +| g_class_init.py:9 | self_0 = ParameterDefinition | +| g_class_init.py:10 | self_1 = AttributeAssignment 'y'(self_0) | +| g_class_init.py:11 | self_2 = SelfCallsiteRefinement(self_1) | +| g_class_init.py:13 | _init2_0 = FunctionExpr | +| g_class_init.py:13 | self_0 = ParameterDefinition | +| g_class_init.py:14 | self_1 = AttributeAssignment 'z'(self_0) | +| g_class_init.py:16 | method_0 = FunctionExpr | +| g_class_init.py:16 | self_0 = ParameterDefinition | +| g_class_init.py:19 | self_1 = Pi(self_0) [true] | +| g_class_init.py:20 | self_2 = Pi(self_0) [false] | +| g_class_init.py:20 | self_3 = phi(self_1, self_2) | +| g_class_init.py:24 | Oddities_0 = ClassExpr | +| g_class_init.py:24 | float_0 = ScopeEntryDefinition | +| g_class_init.py:24 | int_0 = ScopeEntryDefinition | +| g_class_init.py:26 | int_1 = int | +| g_class_init.py:27 | float_1 = float | +| g_class_init.py:28 | l_0 = len | +| g_class_init.py:29 | h_0 = hash | +| g_class_init.py:32 | D_0 = ClassExpr | +| g_class_init.py:34 | D_1 = ScopeEntryDefinition | +| g_class_init.py:34 | __init___0 = FunctionExpr | +| g_class_init.py:34 | self_0 = ParameterDefinition | +| g_class_init.py:35 | D_2 = ArgumentRefinement(D_1) | +| g_class_init.py:42 | V2_0 = Str | +| g_class_init.py:43 | V3_0 = Str | +| g_class_init.py:45 | E_0 = ClassExpr | +| g_class_init.py:46 | V2_1 = ScopeEntryDefinition | +| g_class_init.py:46 | V3_1 = ScopeEntryDefinition | +| g_class_init.py:46 | __init___0 = FunctionExpr | +| g_class_init.py:46 | c_0 = ParameterDefinition | +| g_class_init.py:46 | c_3 = phi(c_1, c_2) | +| g_class_init.py:46 | self_0 = ParameterDefinition | +| g_class_init.py:46 | self_3 = phi(self_1, self_2) | +| g_class_init.py:48 | c_1 = Pi(c_0) [true] | +| g_class_init.py:48 | self_1 = AttributeAssignment 'version'(self_0) | +| g_class_init.py:50 | c_2 = Pi(c_0) [false] | +| g_class_init.py:50 | self_2 = AttributeAssignment 'version'(self_0) | +| g_class_init.py:52 | V2_2 = ScopeEntryDefinition | +| g_class_init.py:52 | meth_0 = FunctionExpr | +| g_class_init.py:52 | self_0 = ParameterDefinition | +| g_class_init.py:52 | self_2 = Pi(self_0) [false] | +| g_class_init.py:52 | self_3 = phi(self_1, self_2) | +| g_class_init.py:54 | self_1 = Pi(self_0) [true] | +| h_classes.py:0 | Base_0 = ScopeEntryDefinition | +| h_classes.py:0 | D_0 = ScopeEntryDefinition | +| h_classes.py:0 | Derived1_0 = ScopeEntryDefinition | +| h_classes.py:0 | Derived2_0 = ScopeEntryDefinition | +| h_classes.py:0 | Derived3_0 = ScopeEntryDefinition | +| h_classes.py:0 | __name___0 = ScopeEntryDefinition | +| h_classes.py:0 | __package___0 = ScopeEntryDefinition | +| h_classes.py:0 | f_0 = ScopeEntryDefinition | +| h_classes.py:0 | k_0 = ScopeEntryDefinition | +| h_classes.py:0 | thing_0 = ScopeEntryDefinition | +| h_classes.py:1 | sys_0 = ImportExpr | +| h_classes.py:3 | C_0 = ClassExpr | +| h_classes.py:5 | x_0 = Str | +| h_classes.py:7 | __init___0 = FunctionExpr | +| h_classes.py:7 | self_0 = ParameterDefinition | +| h_classes.py:8 | self_1 = AttributeAssignment 'y'(self_0) | +| h_classes.py:11 | sys_1 = ArgumentRefinement(sys_0) | +| h_classes.py:14 | C_1 = ScopeEntryDefinition | +| h_classes.py:14 | arg_0 = ParameterDefinition | +| h_classes.py:14 | k_1 = FunctionExpr | +| h_classes.py:14 | sys_2 = ScopeEntryDefinition | +| h_classes.py:17 | arg_1 = ArgumentRefinement(arg_0) | +| h_classes.py:23 | Base_1 = ClassExpr | +| h_classes.py:25 | Derived1_2 = ScopeEntryDefinition | +| h_classes.py:25 | Derived2_2 = ScopeEntryDefinition | +| h_classes.py:25 | Derived3_2 = ScopeEntryDefinition | +| h_classes.py:25 | __init___0 = FunctionExpr | +| h_classes.py:25 | choice_0 = ParameterDefinition | +| h_classes.py:25 | choice_5 = phi(choice_1, choice_3, choice_4) | +| h_classes.py:25 | self_0 = ParameterDefinition | +| h_classes.py:25 | self_4 = phi(self_1, self_2, self_3) | +| h_classes.py:27 | choice_1 = Pi(choice_0) [true] | +| h_classes.py:27 | self_1 = AttributeAssignment '__class__'(self_0) | +| h_classes.py:28 | choice_2 = Pi(choice_0) [false] | +| h_classes.py:29 | choice_3 = Pi(choice_2) [true] | +| h_classes.py:29 | self_2 = AttributeAssignment '__class__'(self_0) | +| h_classes.py:31 | choice_4 = Pi(choice_2) [false] | +| h_classes.py:31 | self_3 = AttributeAssignment '__class__'(self_0) | +| h_classes.py:33 | Derived1_1 = ClassExpr | +| h_classes.py:36 | Derived2_1 = ClassExpr | +| h_classes.py:39 | Derived3_1 = ClassExpr | +| h_classes.py:42 | thing_1 = Base() | +| h_classes.py:45 | arg0_0 = ParameterDefinition | +| h_classes.py:45 | arg1_0 = ParameterDefinition | +| h_classes.py:45 | arg2_0 = ParameterDefinition | +| h_classes.py:45 | f_1 = FunctionExpr | +| h_classes.py:48 | D_1 = ClassExpr | +| h_classes.py:48 | f_2 = ScopeEntryDefinition | +| h_classes.py:50 | m_0 = f | +| h_classes.py:52 | arg1_0 = ParameterDefinition | +| h_classes.py:52 | n_0 = FunctionExpr | +| h_classes.py:52 | self_0 = ParameterDefinition | +| i_imports.py:0 | *_0 = ScopeEntryDefinition | +| i_imports.py:0 | BytesIO_0 = ScopeEntryDefinition | +| i_imports.py:0 | StringIO_0 = ScopeEntryDefinition | +| i_imports.py:0 | __name___0 = ScopeEntryDefinition | +| i_imports.py:0 | __package___0 = ScopeEntryDefinition | +| i_imports.py:0 | _io_0 = ScopeEntryDefinition | +| i_imports.py:0 | argv_0 = ScopeEntryDefinition | +| i_imports.py:0 | code_0 = ScopeEntryDefinition | +| i_imports.py:0 | io_0 = ScopeEntryDefinition | +| i_imports.py:0 | sys_0 = ScopeEntryDefinition | +| i_imports.py:0 | xyz_0 = ScopeEntryDefinition | +| i_imports.py:0 | z_0 = ScopeEntryDefinition | +| i_imports.py:3 | a_0 = IntegerLiteral | +| i_imports.py:4 | b_0 = IntegerLiteral | +| i_imports.py:5 | c_0 = IntegerLiteral | +| i_imports.py:7 | *_1 = ImportStarRefinement(*_0) | +| i_imports.py:7 | BytesIO_1 = ImportStarRefinement(BytesIO_0) | +| i_imports.py:7 | StringIO_1 = ImportStarRefinement(StringIO_0) | +| i_imports.py:7 | __name___1 = ImportStarRefinement(__name___0) | +| i_imports.py:7 | __package___1 = ImportStarRefinement(__package___0) | +| i_imports.py:7 | _io_1 = ImportStarRefinement(_io_0) | +| i_imports.py:7 | a_1 = ImportStarRefinement(a_0) | +| i_imports.py:7 | b_1 = ImportStarRefinement(b_0) | +| i_imports.py:7 | c_1 = ImportStarRefinement(c_0) | +| i_imports.py:7 | io_1 = ImportStarRefinement(io_0) | +| i_imports.py:7 | z_1 = ImportStarRefinement(z_0) | +| i_imports.py:8 | xyz_1 = ImportMember | +| i_imports.py:13 | argv_1 = ImportMember | +| i_imports.py:17 | sys_1 = ImportExpr | +| i_imports.py:23 | code_1 = ImportExpr | +| i_imports.py:27 | *_2 = ImportStarRefinement(*_1) | +| i_imports.py:27 | __name___2 = ImportStarRefinement(__name___1) | +| i_imports.py:27 | __package___2 = ImportStarRefinement(__package___1) | +| i_imports.py:27 | a_2 = ImportStarRefinement(a_1) | +| i_imports.py:27 | argv_2 = ImportStarRefinement(argv_1) | +| i_imports.py:27 | b_2 = ImportStarRefinement(b_1) | +| i_imports.py:27 | c_2 = ImportStarRefinement(c_1) | +| i_imports.py:27 | sys_2 = ImportStarRefinement(sys_1) | +| i_imports.py:27 | xyz_2 = ImportStarRefinement(xyz_1) | +| i_imports.py:27 | z_2 = ImportStarRefinement(z_1) | +| i_imports.py:29 | _io_2 = ImportExpr | +| i_imports.py:33 | io_2 = ImportExpr | +| i_imports.py:34 | StringIO_2 = Attribute | +| i_imports.py:35 | BytesIO_2 = Attribute | +| i_imports.py:37 | code_2 = ImportExpr | +| j_convoluted_imports.py:0 | __name___0 = ScopeEntryDefinition | +| j_convoluted_imports.py:0 | __package___0 = ScopeEntryDefinition | +| j_convoluted_imports.py:3 | module_0 = ImportMember | +| j_convoluted_imports.py:6 | x_0 = ImportMember | +| j_convoluted_imports.py:9 | C_0 = ClassExpr | +| j_convoluted_imports.py:11 | module2_0 = ImportMember | +| j_convoluted_imports.py:13 | f_0 = FunctionExpr | +| j_convoluted_imports.py:13 | self_0 = ParameterDefinition | +| j_convoluted_imports.py:14 | x_0 = ImportMember | +| j_convoluted_imports.py:16 | moduleX_0 = ImportMember | +| k_getsetattr.py:0 | __name___0 = ScopeEntryDefinition | +| k_getsetattr.py:0 | __package___0 = ScopeEntryDefinition | +| k_getsetattr.py:4 | C_0 = ClassExpr | +| k_getsetattr.py:6 | meth1_0 = FunctionExpr | +| k_getsetattr.py:6 | self_0 = ParameterDefinition | +| k_getsetattr.py:7 | self_1 = ArgumentRefinement(self_0) | +| k_getsetattr.py:8 | self_2 = ArgumentRefinement(self_1) | +| k_getsetattr.py:9 | self_3 = ArgumentRefinement(self_2) | +| k_getsetattr.py:10 | self_4 = ArgumentRefinement(self_3) | +| k_getsetattr.py:12 | meth2_0 = FunctionExpr | +| k_getsetattr.py:12 | self_0 = ParameterDefinition | +| k_getsetattr.py:13 | self_1 = ArgumentRefinement(self_0) | +| k_getsetattr.py:14 | self_2 = ArgumentRefinement(self_1) | +| k_getsetattr.py:15 | self_3 = SelfCallsiteRefinement(self_2) | +| k_getsetattr.py:16 | self_4 = ArgumentRefinement(self_3) | +| k_getsetattr.py:17 | self_5 = ArgumentRefinement(self_4) | +| k_getsetattr.py:18 | self_6 = ArgumentRefinement(self_5) | +| k_getsetattr.py:21 | C_1 = ScopeEntryDefinition | +| k_getsetattr.py:21 | cond_0 = ParameterDefinition | +| k_getsetattr.py:21 | k_0 = FunctionExpr | +| k_getsetattr.py:22 | c1_0 = C() | +| k_getsetattr.py:23 | c2_0 = C() | +| k_getsetattr.py:24 | c3_0 = C() | +| k_getsetattr.py:25 | c1_1 = AttributeAssignment 'a'(c1_0) | +| k_getsetattr.py:27 | c2_1 = AttributeAssignment 'a'(c2_0) | +| k_getsetattr.py:27 | cond_1 = Pi(cond_0) [true] | +| k_getsetattr.py:28 | c2_2 = phi(c2_0, c2_1) | +| k_getsetattr.py:28 | cond_2 = Pi(cond_0) [false] | +| k_getsetattr.py:28 | cond_3 = phi(cond_1, cond_2) | +| k_getsetattr.py:31 | c3_1 = AttributeAssignment 'a'(c3_0) | +| n_nesting.py:0 | D_0 = ScopeEntryDefinition | +| n_nesting.py:0 | __name___0 = ScopeEntryDefinition | +| n_nesting.py:0 | __package___0 = ScopeEntryDefinition | +| n_nesting.py:8 | C_0 = ScopeEntryDefinition | +| n_nesting.py:8 | compile_ops_0 = ParameterDefinition | +| n_nesting.py:8 | foo_0 = FunctionExpr | +| n_nesting.py:9 | C_1 = CallsiteRefinement(C_0) | +| n_nesting.py:9 | compile_ops_1 = ArgumentRefinement(compile_ops_0) | +| n_nesting.py:10 | C_5 = ScopeEntryDefinition | +| n_nesting.py:10 | compile_ops_2 = Pi(compile_ops_1) [true] | +| n_nesting.py:10 | compile_ops_3 = ScopeEntryDefinition | +| n_nesting.py:10 | inner_0 = FunctionExpr | +| n_nesting.py:10 | node_def_0 = ParameterDefinition | +| n_nesting.py:11 | C_6 = CallsiteRefinement(C_5) | +| n_nesting.py:11 | node_def_1 = ArgumentRefinement(node_def_0) | +| n_nesting.py:13 | C_7 = ScopeEntryDefinition | +| n_nesting.py:13 | compile_ops_4 = Pi(compile_ops_1) [false] | +| n_nesting.py:13 | compile_ops_5 = ScopeEntryDefinition | +| n_nesting.py:13 | inner_1 = FunctionExpr | +| n_nesting.py:13 | node_def_0 = ParameterDefinition | +| n_nesting.py:14 | C_8 = CallsiteRefinement(C_7) | +| n_nesting.py:14 | node_def_1 = ArgumentRefinement(node_def_0) | +| n_nesting.py:15 | attrs_0 = Dict | +| n_nesting.py:16 | compile_ops_6 = phi(compile_ops_2, compile_ops_4) | +| n_nesting.py:16 | inner_2 = phi(inner_0, inner_1) | +| n_nesting.py:22 | C_9 = ScopeEntryDefinition | +| n_nesting.py:22 | f1_0 = FunctionExpr | +| n_nesting.py:23 | C_10 = AttributeAssignment 'flag'(C_9) | +| n_nesting.py:24 | C_11 = ScopeEntryDefinition | +| n_nesting.py:24 | f1_1 = ScopeEntryDefinition | +| n_nesting.py:24 | f2_0 = FunctionExpr | +| n_nesting.py:25 | C_12 = CallsiteRefinement(C_11) | +| n_nesting.py:26 | C_13 = ScopeEntryDefinition | +| n_nesting.py:26 | f2_1 = ScopeEntryDefinition | +| n_nesting.py:26 | f3_0 = FunctionExpr | +| n_nesting.py:27 | C_14 = CallsiteRefinement(C_13) | +| n_nesting.py:28 | C_15 = ScopeEntryDefinition | +| n_nesting.py:28 | f3_1 = ScopeEntryDefinition | +| n_nesting.py:28 | f4_0 = FunctionExpr | +| n_nesting.py:29 | C_16 = CallsiteRefinement(C_15) | +| n_nesting.py:30 | C_2 = ClassExpr | +| n_nesting.py:31 | C_3 = CallsiteRefinement(C_2) | +| n_nesting.py:32 | D_1 = ClassExpr | +| n_nesting.py:34 | C_4 = IntegerLiteral | +| r_regressions.py:0 | TestFirst_0 = ScopeEntryDefinition | +| r_regressions.py:0 | __name___0 = ScopeEntryDefinition | +| r_regressions.py:0 | __package___0 = ScopeEntryDefinition | +| r_regressions.py:0 | _names_0 = ScopeEntryDefinition | +| r_regressions.py:0 | _names_3 = Pi(_names_1) [false] | +| r_regressions.py:0 | _names_4 = phi(_names_2, _names_3) | +| r_regressions.py:0 | sys_0 = ScopeEntryDefinition | +| r_regressions.py:0 | t_0 = ScopeEntryDefinition | +| r_regressions.py:0 | t_2 = phi(t_0, t_1) | +| r_regressions.py:5 | Queue_0 = ClassExpr | +| r_regressions.py:7 | __init___0 = FunctionExpr | +| r_regressions.py:7 | self_0 = ParameterDefinition | +| r_regressions.py:9 | self_1 = SelfCallsiteRefinement(self_0) | +| r_regressions.py:11 | _after_fork_0 = FunctionExpr | +| r_regressions.py:11 | self_0 = ParameterDefinition | +| r_regressions.py:12 | self_1 = AttributeAssignment '_closed'(self_0) | +| r_regressions.py:13 | self_2 = AttributeAssignment '_close'(self_1) | +| r_regressions.py:15 | close_0 = FunctionExpr | +| r_regressions.py:15 | close_4 = Pi(close_0) [false] | +| r_regressions.py:15 | close_5 = phi(close_3, close_4) | +| r_regressions.py:15 | self_0 = ParameterDefinition | +| r_regressions.py:15 | self_3 = phi(self_1, self_2) | +| r_regressions.py:16 | self_1 = AttributeAssignment '_closed'(self_0) | +| r_regressions.py:20 | close_0 = Attribute | +| r_regressions.py:20 | close_1 = Attribute | +| r_regressions.py:21 | close_2 = SingleSuccessorGuard(close_1) [true] | +| r_regressions.py:22 | close_3 = Pi(close_0) [true] | +| r_regressions.py:22 | self_2 = AttributeAssignment '_close'(self_1) | +| r_regressions.py:27 | f_0 = FunctionExpr | +| r_regressions.py:27 | x_0 = ParameterDefinition | +| r_regressions.py:27 | x_5 = phi(x_3, x_4) | +| r_regressions.py:27 | y_0 = ParameterDefinition | +| r_regressions.py:27 | y_7 = Pi(y_2) [false] | +| r_regressions.py:27 | y_8 = phi(y_3, y_6, y_7) | +| r_regressions.py:27 | z_0 = ParameterDefinition | +| r_regressions.py:27 | z_3 = Pi(z_0) [false] | +| r_regressions.py:27 | z_4 = phi(z_0, z_2, z_3) | +| r_regressions.py:31 | x_1 = Pi(x_0) [true] | +| r_regressions.py:33 | x_2 = Pi(x_0) [false] | +| r_regressions.py:33 | x_3 = phi(x_1, x_2) | +| r_regressions.py:33 | y_1 = Pi(y_0) [false] | +| r_regressions.py:33 | y_2 = phi(y_0, y_1) | +| r_regressions.py:36 | y_3 = Pi(y_2) [true] | +| r_regressions.py:39 | x_4 = phi(x_1, x_3) | +| r_regressions.py:39 | y_4 = Pi(y_0) [true] | +| r_regressions.py:39 | y_5 = phi(y_3, y_4) | +| r_regressions.py:39 | y_6 = ArgumentRefinement(y_5) | +| r_regressions.py:39 | z_1 = Pi(z_0) [true] | +| r_regressions.py:39 | z_2 = phi(z_0, z_1) | +| r_regressions.py:42 | find_library_0 = FunctionExpr | +| r_regressions.py:42 | name_0 = ParameterDefinition | +| r_regressions.py:43 | __0 = ... | +| r_regressions.py:43 | data_0 = ... | +| r_regressions.py:46 | fail_0 = FunctionExpr | +| r_regressions.py:46 | msg_0 = ParameterDefinition | +| r_regressions.py:49 | C_0 = ClassExpr | +| r_regressions.py:51 | fail_0 = FunctionExpr | +| r_regressions.py:51 | fail_1 = ScopeEntryDefinition | +| r_regressions.py:51 | msg_0 = ParameterDefinition | +| r_regressions.py:51 | self_0 = ParameterDefinition | +| r_regressions.py:52 | msg_1 = ArgumentRefinement(msg_0) | +| r_regressions.py:58 | decorator_0 = ParameterDefinition | +| r_regressions.py:58 | method_decorator_0 = FunctionExpr | +| r_regressions.py:58 | name_0 = ParameterDefinition | +| r_regressions.py:61 | _dec_0 = FunctionExpr | +| r_regressions.py:61 | func_0 = ScopeEntryDefinition | +| r_regressions.py:61 | is_class_6 = phi(is_class_4, is_class_5) | +| r_regressions.py:61 | name_1 = ScopeEntryDefinition | +| r_regressions.py:61 | obj_0 = ParameterDefinition | +| r_regressions.py:61 | obj_3 = phi(obj_1, obj_2) | +| r_regressions.py:62 | is_class_0 = isinstance() | +| r_regressions.py:62 | name_2 = CallsiteRefinement(name_1) | +| r_regressions.py:62 | obj_1 = ArgumentRefinement(obj_0) | +| r_regressions.py:64 | is_class_1 = Pi(is_class_0) [true] | +| r_regressions.py:64 | name_3 = CallsiteRefinement(name_2) | +| r_regressions.py:66 | func_1 = obj | +| r_regressions.py:66 | is_class_2 = Pi(is_class_0) [false] | +| r_regressions.py:68 | _wrapper_0 = FunctionExpr | +| r_regressions.py:68 | args_0 = ParameterDefinition | +| r_regressions.py:68 | func_2 = phi(func_0, func_1) | +| r_regressions.py:68 | is_class_3 = phi(is_class_1, is_class_2) | +| r_regressions.py:68 | kwargs_0 = ParameterDefinition | +| r_regressions.py:68 | name_4 = phi(name_2, name_3) | +| r_regressions.py:68 | self_0 = ParameterDefinition | +| r_regressions.py:73 | is_class_4 = Pi(is_class_3) [true] | +| r_regressions.py:73 | obj_2 = ArgumentRefinement(obj_1) | +| r_regressions.py:76 | is_class_5 = Pi(is_class_3) [false] | +| r_regressions.py:80 | deco_0 = FunctionExpr | +| r_regressions.py:80 | func_0 = ParameterDefinition | +| r_regressions.py:81 | _wrapper_0 = FunctionExpr | +| r_regressions.py:81 | args_0 = ParameterDefinition | +| r_regressions.py:81 | kwargs_0 = ParameterDefinition | +| r_regressions.py:85 | deco_1 = ArgumentRefinement(deco_0) | +| r_regressions.py:86 | TestFirst_1 = method_decorator()() | +| r_regressions.py:87 | method_0 = FunctionExpr | +| r_regressions.py:87 | self_0 = ParameterDefinition | +| r_regressions.py:93 | sys_1 = ImportExpr | +| r_regressions.py:95 | _names_1 = Attribute | +| r_regressions.py:98 | _names_2 = Pi(_names_1) [true] | +| r_regressions.py:98 | t_1 = ImportExpr | +| s_scopes.py:0 | __name___0 = ScopeEntryDefinition | +| s_scopes.py:0 | __package___0 = ScopeEntryDefinition | +| s_scopes.py:0 | float_0 = ScopeEntryDefinition | +| s_scopes.py:0 | x_0 = ScopeEntryDefinition | +| s_scopes.py:4 | float_1 = True | +| s_scopes.py:5 | float_2 = phi(float_0, float_1) | +| s_scopes.py:7 | C2_0 = ClassExpr | +| s_scopes.py:7 | float_0 = ScopeEntryDefinition | +| s_scopes.py:7 | float_3 = ScopeEntryDefinition | +| s_scopes.py:7 | int_0 = ScopeEntryDefinition | +| s_scopes.py:7 | str_0 = ScopeEntryDefinition | +| s_scopes.py:9 | i1_0 = int | +| s_scopes.py:10 | f1_0 = float | +| s_scopes.py:12 | int_1 = IntegerLiteral | +| s_scopes.py:15 | str_1 = FloatLiteral | +| s_scopes.py:17 | float_1 = None | +| s_scopes.py:18 | float_2 = phi(float_0, float_1) | +| s_scopes.py:18 | i2_0 = int | +| s_scopes.py:18 | str_2 = phi(str_0, str_1) | +| s_scopes.py:19 | s_0 = str | +| s_scopes.py:20 | f2_0 = float | +| s_scopes.py:22 | x_1 = x | +| s_scopes.py:23 | i_0 = int | +| s_scopes.py:24 | f_0 = float | diff --git a/python/ql/test/library-tests/PointsTo/new/Dataflow.ql b/python/ql/test/library-tests/PointsTo/new/Dataflow.ql new file mode 100755 index 00000000000..1761c3bc4ab --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/Dataflow.ql @@ -0,0 +1,8 @@ + + +import python +import Util + +from EssaVariable v, EssaDefinition def +where def = v.getDefinition() +select locate(def.getLocation(), "abdefghijknrs_"), v.getRepresentation() + " = " + def.getRepresentation() diff --git a/python/ql/test/library-tests/PointsTo/new/Definitions.expected b/python/ql/test/library-tests/PointsTo/new/Definitions.expected new file mode 100644 index 00000000000..f6576b569fc --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/Definitions.expected @@ -0,0 +1,428 @@ +| a_simple.py:0 | Global Variable __name__ | ScopeEntryDefinition | +| a_simple.py:0 | Global Variable __package__ | ScopeEntryDefinition | +| a_simple.py:2 | Global Variable f1 | AssignmentDefinition | +| a_simple.py:5 | Global Variable i1 | AssignmentDefinition | +| a_simple.py:6 | Global Variable s | AssignmentDefinition | +| a_simple.py:8 | Global Variable func | AssignmentDefinition | +| a_simple.py:11 | Global Variable C | AssignmentDefinition | +| a_simple.py:14 | Global Variable vararg_kwarg | AssignmentDefinition | +| a_simple.py:14 | Local Variable d | ParameterDefinition | +| a_simple.py:14 | Local Variable t | ParameterDefinition | +| a_simple.py:18 | Global Variable multi_loop | AssignmentDefinition | +| a_simple.py:18 | Local Variable seq | ParameterDefinition | +| a_simple.py:18 | Local Variable y | ScopeEntryDefinition | +| a_simple.py:19 | Local Variable x | AssignmentDefinition | +| a_simple.py:20 | Local Variable x | MultiAssignmentDefinition | +| a_simple.py:20 | Local Variable x | PhiFunction | +| a_simple.py:20 | Local Variable y | MultiAssignmentDefinition | +| a_simple.py:20 | Local Variable y | PhiFunction | +| a_simple.py:23 | Global Variable with_definition | AssignmentDefinition | +| a_simple.py:23 | Local Variable x | ParameterDefinition | +| a_simple.py:24 | Local Variable y | WithDefinition | +| a_simple.py:27 | Global Variable multi_loop_in_try | AssignmentDefinition | +| a_simple.py:27 | Local Variable p | ScopeEntryDefinition | +| a_simple.py:27 | Local Variable q | ScopeEntryDefinition | +| a_simple.py:27 | Local Variable x | ParameterDefinition | +| a_simple.py:29 | Local Variable p | MultiAssignmentDefinition | +| a_simple.py:29 | Local Variable p | PhiFunction | +| a_simple.py:29 | Local Variable q | MultiAssignmentDefinition | +| a_simple.py:29 | Local Variable q | PhiFunction | +| a_simple.py:34 | Global Variable f | AssignmentDefinition | +| a_simple.py:34 | Local Variable args | ParameterDefinition | +| a_simple.py:34 | Local Variable kwargs | ParameterDefinition | +| b_condition.py:0 | Global Variable __name__ | ScopeEntryDefinition | +| b_condition.py:0 | Global Variable __package__ | ScopeEntryDefinition | +| b_condition.py:0 | Global Variable double_attr_check | ScopeEntryDefinition | +| b_condition.py:0 | Global Variable g | ScopeEntryDefinition | +| b_condition.py:0 | Global Variable h | ScopeEntryDefinition | +| b_condition.py:0 | Global Variable k | ScopeEntryDefinition | +| b_condition.py:0 | Global Variable loop | ScopeEntryDefinition | +| b_condition.py:0 | Global Variable not_or_not | ScopeEntryDefinition | +| b_condition.py:0 | Global Variable odasa6261 | ScopeEntryDefinition | +| b_condition.py:0 | Global Variable split_bool1 | ScopeEntryDefinition | +| b_condition.py:0 | Global Variable v2 | ScopeEntryDefinition | +| b_condition.py:4 | Global Variable f | AssignmentDefinition | +| b_condition.py:4 | Local Variable y | ParameterDefinition | +| b_condition.py:5 | Local Variable x | AssignmentDefinition | +| b_condition.py:8 | Local Variable x | AssignmentDefinition | +| b_condition.py:9 | Local Variable x | PhiFunction | +| b_condition.py:9 | Local Variable x | PyEdgeRefinement | +| b_condition.py:11 | Local Variable x | AssignmentDefinition | +| b_condition.py:14 | Local Variable x | AssignmentDefinition | +| b_condition.py:15 | Local Variable x | PhiFunction | +| b_condition.py:15 | Local Variable x | PyEdgeRefinement | +| b_condition.py:17 | Local Variable x | AssignmentDefinition | +| b_condition.py:20 | Local Variable x | AssignmentDefinition | +| b_condition.py:21 | Local Variable x | PhiFunction | +| b_condition.py:21 | Local Variable x | PyEdgeRefinement | +| b_condition.py:23 | Local Variable x | AssignmentDefinition | +| b_condition.py:25 | Local Variable x | AssignmentDefinition | +| b_condition.py:25 | Local Variable x | PyEdgeRefinement | +| b_condition.py:26 | Local Variable x | ArgumentRefinement | +| b_condition.py:28 | Local Variable x | AssignmentDefinition | +| b_condition.py:29 | Local Variable x | PhiFunction | +| b_condition.py:31 | Local Variable x | AssignmentDefinition | +| b_condition.py:33 | Local Variable x | AssignmentDefinition | +| b_condition.py:34 | Local Variable x | ArgumentRefinement | +| b_condition.py:34 | Local Variable x | PhiFunction | +| b_condition.py:34 | Local Variable x | PyEdgeRefinement | +| b_condition.py:36 | Local Variable x | ArgumentRefinement | +| b_condition.py:36 | Local Variable x | PyEdgeRefinement | +| b_condition.py:37 | Local Variable x | ArgumentRefinement | +| b_condition.py:39 | Global Variable v2 | AssignmentDefinition | +| b_condition.py:41 | Global Variable v2 | AttributeAssignment | +| b_condition.py:43 | Global Variable v2 | PyEdgeRefinement | +| b_condition.py:47 | Global Variable v2 | PhiFunction | +| b_condition.py:47 | Global Variable v2 | PyEdgeRefinement | +| b_condition.py:50 | Global Variable g | AssignmentDefinition | +| b_condition.py:50 | Local Variable x | ParameterDefinition | +| b_condition.py:50 | Local Variable x | PhiFunction | +| b_condition.py:50 | Local Variable x | PyEdgeRefinement | +| b_condition.py:52 | Local Variable x | PyEdgeRefinement | +| b_condition.py:55 | Global Variable loop | AssignmentDefinition | +| b_condition.py:55 | Local Variable seq | ParameterDefinition | +| b_condition.py:55 | Local Variable v | ScopeEntryDefinition | +| b_condition.py:56 | Local Variable v | IterationDefinition | +| b_condition.py:56 | Local Variable v | PhiFunction | +| b_condition.py:56 | Local Variable v | PyEdgeRefinement | +| b_condition.py:58 | Local Variable v | ArgumentRefinement | +| b_condition.py:58 | Local Variable v | PyEdgeRefinement | +| b_condition.py:61 | Global Variable double_attr_check | AssignmentDefinition | +| b_condition.py:61 | Local Variable x | ParameterDefinition | +| b_condition.py:61 | Local Variable x | PhiFunction | +| b_condition.py:61 | Local Variable x | PyEdgeRefinement | +| b_condition.py:61 | Local Variable y | ParameterDefinition | +| b_condition.py:61 | Local Variable y | PhiFunction | +| b_condition.py:61 | Local Variable y | PyEdgeRefinement | +| b_condition.py:63 | Local Variable x | PyEdgeRefinement | +| b_condition.py:64 | Local Variable x | PyEdgeRefinement | +| b_condition.py:65 | Local Variable y | PyEdgeRefinement | +| b_condition.py:66 | Local Variable x | PyEdgeRefinement | +| b_condition.py:67 | Local Variable x | PyEdgeRefinement | +| b_condition.py:69 | Global Variable h | AssignmentDefinition | +| b_condition.py:70 | Local Variable b | AssignmentDefinition | +| b_condition.py:72 | Local Variable b | AssignmentDefinition | +| b_condition.py:73 | Local Variable b | PhiFunction | +| b_condition.py:73 | Local Variable b | PyEdgeRefinement | +| b_condition.py:75 | Global Variable k | AssignmentDefinition | +| b_condition.py:76 | Local Variable t | AssignmentDefinition | +| b_condition.py:78 | Local Variable t | AssignmentDefinition | +| b_condition.py:79 | Local Variable t | ArgumentRefinement | +| b_condition.py:79 | Local Variable t | PhiFunction | +| b_condition.py:79 | Local Variable t | PyEdgeRefinement | +| b_condition.py:81 | Global Variable odasa6261 | AssignmentDefinition | +| b_condition.py:81 | Local Variable bar | PhiFunction | +| b_condition.py:81 | Local Variable bar | ScopeEntryDefinition | +| b_condition.py:81 | Local Variable foo | ParameterDefinition | +| b_condition.py:81 | Local Variable foo | PhiFunction | +| b_condition.py:81 | Local Variable foo | PyEdgeRefinement | +| b_condition.py:82 | Local Variable foo | ArgumentRefinement | +| b_condition.py:83 | Local Variable bar | AssignmentDefinition | +| b_condition.py:83 | Local Variable foo | PyEdgeRefinement | +| b_condition.py:83 | Local Variable foo | ScopeEntryDefinition | +| b_condition.py:87 | Global Variable split_bool1 | AssignmentDefinition | +| b_condition.py:87 | Local Variable x | ParameterDefinition | +| b_condition.py:87 | Local Variable y | ParameterDefinition | +| b_condition.py:88 | Local Variable x | PyEdgeRefinement | +| b_condition.py:90 | Local Variable x | PyEdgeRefinement | +| b_condition.py:90 | Local Variable x | SingleSuccessorGuard | +| b_condition.py:90 | Local Variable y | PyEdgeRefinement | +| b_condition.py:92 | Local Variable x | SingleSuccessorGuard | +| b_condition.py:93 | Local Variable y | ArgumentRefinement | +| b_condition.py:95 | Local Variable y | ArgumentRefinement | +| b_condition.py:96 | Local Variable y | SingleSuccessorGuard | +| b_condition.py:97 | Local Variable x | ArgumentRefinement | +| b_condition.py:99 | Local Variable x | ArgumentRefinement | +| b_condition.py:101 | Global Variable not_or_not | AssignmentDefinition | +| b_condition.py:101 | Local Variable a | ParameterDefinition | +| b_condition.py:102 | Local Variable a | ArgumentRefinement | +| b_condition.py:104 | Local Variable a | PyEdgeRefinement | +| b_condition.py:105 | Local Variable a | PyEdgeRefinement | +| b_condition.py:107 | Local Variable a | PyEdgeRefinement | +| d_globals.py:0 | Global Variable D | ScopeEntryDefinition | +| d_globals.py:0 | Global Variable Ugly | ScopeEntryDefinition | +| d_globals.py:0 | Global Variable X | ScopeEntryDefinition | +| d_globals.py:0 | Global Variable __name__ | ScopeEntryDefinition | +| d_globals.py:0 | Global Variable __package__ | ScopeEntryDefinition | +| d_globals.py:0 | Global Variable dict | ScopeEntryDefinition | +| d_globals.py:0 | Global Variable g3 | ScopeEntryDefinition | +| d_globals.py:0 | Global Variable g4 | ScopeEntryDefinition | +| d_globals.py:0 | Global Variable get_g4 | ScopeEntryDefinition | +| d_globals.py:0 | Global Variable glob | ScopeEntryDefinition | +| d_globals.py:0 | Global Variable k | ScopeEntryDefinition | +| d_globals.py:0 | Global Variable modinit | ScopeEntryDefinition | +| d_globals.py:0 | Global Variable outer | ScopeEntryDefinition | +| d_globals.py:0 | Global Variable redefine | ScopeEntryDefinition | +| d_globals.py:0 | Global Variable set_g4 | ScopeEntryDefinition | +| d_globals.py:0 | Global Variable set_g4_indirect | ScopeEntryDefinition | +| d_globals.py:0 | Global Variable tuple | ScopeEntryDefinition | +| d_globals.py:0 | Global Variable use_list_attribute | ScopeEntryDefinition | +| d_globals.py:0 | Global Variable x | ScopeEntryDefinition | +| d_globals.py:0 | Global Variable y | ScopeEntryDefinition | +| d_globals.py:0 | Global Variable z | ScopeEntryDefinition | +| d_globals.py:2 | Global Variable dict | ScopeEntryDefinition | +| d_globals.py:2 | Global Variable g1 | ScopeEntryDefinition | +| d_globals.py:2 | Global Variable g2 | ScopeEntryDefinition | +| d_globals.py:2 | Global Variable g3 | ScopeEntryDefinition | +| d_globals.py:2 | Global Variable g4 | ScopeEntryDefinition | +| d_globals.py:2 | Global Variable glob | ScopeEntryDefinition | +| d_globals.py:2 | Global Variable j | AssignmentDefinition | +| d_globals.py:2 | Global Variable tuple | ScopeEntryDefinition | +| d_globals.py:2 | Global Variable z | ScopeEntryDefinition | +| d_globals.py:5 | Global Variable dict | AssignmentDefinition | +| d_globals.py:7 | Global Variable tuple | AssignmentDefinition | +| d_globals.py:14 | Global Variable g1 | AssignmentDefinition | +| d_globals.py:16 | Global Variable assign_global | AssignmentDefinition | +| d_globals.py:16 | Global Variable g2 | ScopeEntryDefinition | +| d_globals.py:16 | Global Variable g3 | ScopeEntryDefinition | +| d_globals.py:16 | Global Variable g4 | ScopeEntryDefinition | +| d_globals.py:16 | Global Variable glob | ScopeEntryDefinition | +| d_globals.py:16 | Global Variable z | ScopeEntryDefinition | +| d_globals.py:18 | Global Variable g1 | AssignmentDefinition | +| d_globals.py:23 | Global Variable g2 | AssignmentDefinition | +| d_globals.py:25 | Global Variable g1 | ScopeEntryDefinition | +| d_globals.py:25 | Global Variable g3 | ScopeEntryDefinition | +| d_globals.py:25 | Global Variable g4 | ScopeEntryDefinition | +| d_globals.py:25 | Global Variable glob | ScopeEntryDefinition | +| d_globals.py:25 | Global Variable init | AssignmentDefinition | +| d_globals.py:25 | Global Variable z | ScopeEntryDefinition | +| d_globals.py:27 | Global Variable g2 | AssignmentDefinition | +| d_globals.py:29 | Global Variable g1 | CallsiteRefinement | +| d_globals.py:29 | Global Variable g2 | CallsiteRefinement | +| d_globals.py:29 | Global Variable glob | CallsiteRefinement | +| d_globals.py:29 | Global Variable z | CallsiteRefinement | +| d_globals.py:33 | Global Variable g3 | AssignmentDefinition | +| d_globals.py:35 | Global Variable Ugly | AssignmentDefinition | +| d_globals.py:37 | Global Variable g1 | ScopeEntryDefinition | +| d_globals.py:37 | Global Variable g2 | ScopeEntryDefinition | +| d_globals.py:37 | Global Variable g4 | ScopeEntryDefinition | +| d_globals.py:37 | Global Variable glob | ScopeEntryDefinition | +| d_globals.py:37 | Global Variable z | ScopeEntryDefinition | +| d_globals.py:37 | Local Variable __init__ | AssignmentDefinition | +| d_globals.py:37 | Local Variable self | ParameterDefinition | +| d_globals.py:39 | Global Variable g3 | AssignmentDefinition | +| d_globals.py:41 | Global Variable g1 | ScopeEntryDefinition | +| d_globals.py:41 | Global Variable g2 | ScopeEntryDefinition | +| d_globals.py:41 | Global Variable g3 | ScopeEntryDefinition | +| d_globals.py:41 | Global Variable g4 | ScopeEntryDefinition | +| d_globals.py:41 | Global Variable glob | ScopeEntryDefinition | +| d_globals.py:41 | Global Variable z | ScopeEntryDefinition | +| d_globals.py:41 | Local Variable meth | AssignmentDefinition | +| d_globals.py:41 | Local Variable self | ParameterDefinition | +| d_globals.py:46 | Global Variable x | AssignmentDefinition | +| d_globals.py:49 | Global Variable x | AssignmentDefinition | +| d_globals.py:51 | Global Variable x | PhiFunction | +| d_globals.py:52 | Global Variable y | AssignmentDefinition | +| d_globals.py:54 | Global Variable y | AssignmentDefinition | +| d_globals.py:59 | Global Variable y | PhiFunction | +| d_globals.py:62 | Global Variable X | AssignmentDefinition | +| d_globals.py:62 | Global Variable X | ScopeEntryDefinition | +| d_globals.py:62 | Global Variable g3 | ScopeEntryDefinition | +| d_globals.py:62 | Global Variable y | ScopeEntryDefinition | +| d_globals.py:62 | Local Variable y | ScopeEntryDefinition | +| d_globals.py:63 | Local Variable y | AssignmentDefinition | +| d_globals.py:64 | Local Variable v4 | AssignmentDefinition | +| d_globals.py:70 | Global Variable g1 | ScopeEntryDefinition | +| d_globals.py:70 | Global Variable g2 | ScopeEntryDefinition | +| d_globals.py:70 | Global Variable g3 | ScopeEntryDefinition | +| d_globals.py:70 | Global Variable g4 | ScopeEntryDefinition | +| d_globals.py:70 | Global Variable glob | ScopeEntryDefinition | +| d_globals.py:70 | Global Variable k | AssignmentDefinition | +| d_globals.py:70 | Global Variable z | ScopeEntryDefinition | +| d_globals.py:70 | Local Variable arg | ParameterDefinition | +| d_globals.py:73 | Global Variable g4 | AssignmentDefinition | +| d_globals.py:75 | Global Variable g1 | ScopeEntryDefinition | +| d_globals.py:75 | Global Variable g2 | ScopeEntryDefinition | +| d_globals.py:75 | Global Variable g3 | ScopeEntryDefinition | +| d_globals.py:75 | Global Variable g4 | ScopeEntryDefinition | +| d_globals.py:75 | Global Variable get_g4 | AssignmentDefinition | +| d_globals.py:75 | Global Variable glob | ScopeEntryDefinition | +| d_globals.py:75 | Global Variable set_g4 | ScopeEntryDefinition | +| d_globals.py:75 | Global Variable z | ScopeEntryDefinition | +| d_globals.py:77 | Global Variable g1 | CallsiteRefinement | +| d_globals.py:77 | Global Variable g2 | CallsiteRefinement | +| d_globals.py:77 | Global Variable g3 | CallsiteRefinement | +| d_globals.py:77 | Global Variable g4 | CallsiteRefinement | +| d_globals.py:77 | Global Variable g4 | PyEdgeRefinement | +| d_globals.py:77 | Global Variable glob | CallsiteRefinement | +| d_globals.py:77 | Global Variable z | CallsiteRefinement | +| d_globals.py:78 | Global Variable g1 | PhiFunction | +| d_globals.py:78 | Global Variable g2 | PhiFunction | +| d_globals.py:78 | Global Variable g3 | PhiFunction | +| d_globals.py:78 | Global Variable g4 | PhiFunction | +| d_globals.py:78 | Global Variable g4 | PyEdgeRefinement | +| d_globals.py:78 | Global Variable glob | PhiFunction | +| d_globals.py:78 | Global Variable z | PhiFunction | +| d_globals.py:80 | Global Variable g1 | ScopeEntryDefinition | +| d_globals.py:80 | Global Variable g2 | ScopeEntryDefinition | +| d_globals.py:80 | Global Variable g3 | ScopeEntryDefinition | +| d_globals.py:80 | Global Variable g4 | ScopeEntryDefinition | +| d_globals.py:80 | Global Variable glob | ScopeEntryDefinition | +| d_globals.py:80 | Global Variable set_g4 | AssignmentDefinition | +| d_globals.py:80 | Global Variable set_g4_indirect | ScopeEntryDefinition | +| d_globals.py:80 | Global Variable z | ScopeEntryDefinition | +| d_globals.py:81 | Global Variable g1 | CallsiteRefinement | +| d_globals.py:81 | Global Variable g2 | CallsiteRefinement | +| d_globals.py:81 | Global Variable g3 | CallsiteRefinement | +| d_globals.py:81 | Global Variable g4 | CallsiteRefinement | +| d_globals.py:81 | Global Variable glob | CallsiteRefinement | +| d_globals.py:81 | Global Variable z | CallsiteRefinement | +| d_globals.py:83 | Global Variable g1 | ScopeEntryDefinition | +| d_globals.py:83 | Global Variable g2 | ScopeEntryDefinition | +| d_globals.py:83 | Global Variable g3 | ScopeEntryDefinition | +| d_globals.py:83 | Global Variable glob | ScopeEntryDefinition | +| d_globals.py:83 | Global Variable set_g4_indirect | AssignmentDefinition | +| d_globals.py:83 | Global Variable z | ScopeEntryDefinition | +| d_globals.py:85 | Global Variable g4 | AssignmentDefinition | +| d_globals.py:87 | Global Variable modinit | AssignmentDefinition | +| d_globals.py:92 | Global Variable modinit | DeletionDefinition | +| d_globals.py:95 | Global Variable g1 | ScopeEntryDefinition | +| d_globals.py:95 | Global Variable g2 | ScopeEntryDefinition | +| d_globals.py:95 | Global Variable g3 | ScopeEntryDefinition | +| d_globals.py:95 | Global Variable g4 | ScopeEntryDefinition | +| d_globals.py:95 | Global Variable glob | ScopeEntryDefinition | +| d_globals.py:95 | Global Variable outer | AssignmentDefinition | +| d_globals.py:95 | Global Variable z | ScopeEntryDefinition | +| d_globals.py:96 | Global Variable g1 | ScopeEntryDefinition | +| d_globals.py:96 | Global Variable g2 | ScopeEntryDefinition | +| d_globals.py:96 | Global Variable g3 | ScopeEntryDefinition | +| d_globals.py:96 | Global Variable g4 | ScopeEntryDefinition | +| d_globals.py:96 | Global Variable z | ScopeEntryDefinition | +| d_globals.py:96 | Local Variable inner | AssignmentDefinition | +| d_globals.py:98 | Global Variable glob | AssignmentDefinition | +| d_globals.py:101 | Global Variable g1 | ScopeEntryDefinition | +| d_globals.py:101 | Global Variable g2 | ScopeEntryDefinition | +| d_globals.py:101 | Global Variable g3 | ScopeEntryDefinition | +| d_globals.py:101 | Global Variable g4 | ScopeEntryDefinition | +| d_globals.py:101 | Global Variable glob | ScopeEntryDefinition | +| d_globals.py:101 | Global Variable z | ScopeEntryDefinition | +| d_globals.py:101 | Local Variable otherInner | AssignmentDefinition | +| d_globals.py:104 | Global Variable g1 | CallsiteRefinement | +| d_globals.py:104 | Global Variable g2 | CallsiteRefinement | +| d_globals.py:104 | Global Variable g3 | CallsiteRefinement | +| d_globals.py:104 | Global Variable g4 | CallsiteRefinement | +| d_globals.py:104 | Global Variable glob | CallsiteRefinement | +| d_globals.py:104 | Global Variable z | CallsiteRefinement | +| d_globals.py:107 | Global Variable g1 | ScopeEntryDefinition | +| d_globals.py:107 | Global Variable g2 | ScopeEntryDefinition | +| d_globals.py:107 | Global Variable g3 | ScopeEntryDefinition | +| d_globals.py:107 | Global Variable g4 | ScopeEntryDefinition | +| d_globals.py:107 | Global Variable glob | ScopeEntryDefinition | +| d_globals.py:107 | Global Variable redefine | AssignmentDefinition | +| d_globals.py:107 | Global Variable z | ScopeEntryDefinition | +| d_globals.py:110 | Global Variable z | AssignmentDefinition | +| d_globals.py:113 | Global Variable glob | AssignmentDefinition | +| d_globals.py:118 | Global Variable D | AssignmentDefinition | +| d_globals.py:120 | Global Variable g1 | ScopeEntryDefinition | +| d_globals.py:120 | Global Variable g2 | ScopeEntryDefinition | +| d_globals.py:120 | Global Variable g3 | ScopeEntryDefinition | +| d_globals.py:120 | Global Variable g4 | ScopeEntryDefinition | +| d_globals.py:120 | Global Variable glob | ScopeEntryDefinition | +| d_globals.py:120 | Global Variable z | ScopeEntryDefinition | +| d_globals.py:120 | Local Variable __init__ | AssignmentDefinition | +| d_globals.py:120 | Local Variable self | ParameterDefinition | +| d_globals.py:123 | Global Variable dict | ScopeEntryDefinition | +| d_globals.py:123 | Global Variable g1 | ScopeEntryDefinition | +| d_globals.py:123 | Global Variable g2 | ScopeEntryDefinition | +| d_globals.py:123 | Global Variable g3 | ScopeEntryDefinition | +| d_globals.py:123 | Global Variable g4 | ScopeEntryDefinition | +| d_globals.py:123 | Global Variable glob | ScopeEntryDefinition | +| d_globals.py:123 | Global Variable z | ScopeEntryDefinition | +| d_globals.py:123 | Local Variable foo | AssignmentDefinition | +| d_globals.py:123 | Local Variable self | ParameterDefinition | +| d_globals.py:126 | Global Variable g1 | ScopeEntryDefinition | +| d_globals.py:126 | Global Variable g2 | ScopeEntryDefinition | +| d_globals.py:126 | Global Variable g3 | ScopeEntryDefinition | +| d_globals.py:126 | Global Variable g4 | ScopeEntryDefinition | +| d_globals.py:126 | Global Variable glob | ScopeEntryDefinition | +| d_globals.py:126 | Global Variable use_list_attribute | AssignmentDefinition | +| d_globals.py:126 | Global Variable z | ScopeEntryDefinition | +| d_globals.py:127 | Local Variable l | AssignmentDefinition | +| d_globals.py:128 | Global Variable g1 | CallsiteRefinement | +| d_globals.py:128 | Global Variable g2 | CallsiteRefinement | +| d_globals.py:128 | Global Variable g3 | CallsiteRefinement | +| d_globals.py:128 | Global Variable g4 | CallsiteRefinement | +| d_globals.py:128 | Global Variable glob | CallsiteRefinement | +| d_globals.py:128 | Global Variable z | CallsiteRefinement | +| d_globals.py:128 | Local Variable l | ArgumentRefinement | +| g_class_init.py:0 | Global Variable __name__ | ScopeEntryDefinition | +| g_class_init.py:0 | Global Variable __package__ | ScopeEntryDefinition | +| g_class_init.py:3 | Global Variable C | AssignmentDefinition | +| g_class_init.py:5 | Local Variable __init__ | AssignmentDefinition | +| g_class_init.py:5 | Local Variable self | ParameterDefinition | +| g_class_init.py:6 | Local Variable self | SelfCallsiteRefinement | +| g_class_init.py:7 | Local Variable self | AttributeAssignment | +| g_class_init.py:9 | Local Variable _init | AssignmentDefinition | +| g_class_init.py:9 | Local Variable self | ParameterDefinition | +| g_class_init.py:10 | Local Variable self | AttributeAssignment | +| g_class_init.py:11 | Local Variable self | SelfCallsiteRefinement | +| g_class_init.py:13 | Local Variable _init2 | AssignmentDefinition | +| g_class_init.py:13 | Local Variable self | ParameterDefinition | +| g_class_init.py:14 | Local Variable self | AttributeAssignment | +| g_class_init.py:16 | Local Variable method | AssignmentDefinition | +| g_class_init.py:16 | Local Variable self | ParameterDefinition | +| g_class_init.py:19 | Local Variable self | PyEdgeRefinement | +| g_class_init.py:20 | Local Variable self | PhiFunction | +| g_class_init.py:20 | Local Variable self | PyEdgeRefinement | +| g_class_init.py:24 | Global Variable Oddities | AssignmentDefinition | +| g_class_init.py:24 | Local Variable float | ScopeEntryDefinition | +| g_class_init.py:24 | Local Variable int | ScopeEntryDefinition | +| g_class_init.py:26 | Local Variable int | AssignmentDefinition | +| g_class_init.py:27 | Local Variable float | AssignmentDefinition | +| g_class_init.py:28 | Local Variable l | AssignmentDefinition | +| g_class_init.py:29 | Local Variable h | AssignmentDefinition | +| g_class_init.py:32 | Global Variable D | AssignmentDefinition | +| g_class_init.py:34 | Global Variable D | ScopeEntryDefinition | +| g_class_init.py:34 | Local Variable __init__ | AssignmentDefinition | +| g_class_init.py:34 | Local Variable self | ParameterDefinition | +| g_class_init.py:35 | Global Variable D | ArgumentRefinement | +| g_class_init.py:42 | Global Variable V2 | AssignmentDefinition | +| g_class_init.py:43 | Global Variable V3 | AssignmentDefinition | +| g_class_init.py:45 | Global Variable E | AssignmentDefinition | +| g_class_init.py:46 | Global Variable V2 | ScopeEntryDefinition | +| g_class_init.py:46 | Global Variable V3 | ScopeEntryDefinition | +| g_class_init.py:46 | Local Variable __init__ | AssignmentDefinition | +| g_class_init.py:46 | Local Variable c | ParameterDefinition | +| g_class_init.py:46 | Local Variable c | PhiFunction | +| g_class_init.py:46 | Local Variable self | ParameterDefinition | +| g_class_init.py:46 | Local Variable self | PhiFunction | +| g_class_init.py:48 | Local Variable c | PyEdgeRefinement | +| g_class_init.py:48 | Local Variable self | AttributeAssignment | +| g_class_init.py:50 | Local Variable c | PyEdgeRefinement | +| g_class_init.py:50 | Local Variable self | AttributeAssignment | +| g_class_init.py:52 | Global Variable V2 | ScopeEntryDefinition | +| g_class_init.py:52 | Local Variable meth | AssignmentDefinition | +| g_class_init.py:52 | Local Variable self | ParameterDefinition | +| g_class_init.py:52 | Local Variable self | PhiFunction | +| g_class_init.py:52 | Local Variable self | PyEdgeRefinement | +| g_class_init.py:54 | Local Variable self | PyEdgeRefinement | +| k_getsetattr.py:0 | Global Variable __name__ | ScopeEntryDefinition | +| k_getsetattr.py:0 | Global Variable __package__ | ScopeEntryDefinition | +| k_getsetattr.py:4 | Global Variable C | AssignmentDefinition | +| k_getsetattr.py:6 | Local Variable meth1 | AssignmentDefinition | +| k_getsetattr.py:6 | Local Variable self | ParameterDefinition | +| k_getsetattr.py:7 | Local Variable self | ArgumentRefinement | +| k_getsetattr.py:8 | Local Variable self | ArgumentRefinement | +| k_getsetattr.py:9 | Local Variable self | ArgumentRefinement | +| k_getsetattr.py:10 | Local Variable self | ArgumentRefinement | +| k_getsetattr.py:12 | Local Variable meth2 | AssignmentDefinition | +| k_getsetattr.py:12 | Local Variable self | ParameterDefinition | +| k_getsetattr.py:13 | Local Variable self | ArgumentRefinement | +| k_getsetattr.py:14 | Local Variable self | ArgumentRefinement | +| k_getsetattr.py:15 | Local Variable self | SelfCallsiteRefinement | +| k_getsetattr.py:16 | Local Variable self | ArgumentRefinement | +| k_getsetattr.py:17 | Local Variable self | ArgumentRefinement | +| k_getsetattr.py:18 | Local Variable self | ArgumentRefinement | +| k_getsetattr.py:21 | Global Variable C | ScopeEntryDefinition | +| k_getsetattr.py:21 | Global Variable k | AssignmentDefinition | +| k_getsetattr.py:21 | Local Variable cond | ParameterDefinition | +| k_getsetattr.py:22 | Local Variable c1 | AssignmentDefinition | +| k_getsetattr.py:23 | Local Variable c2 | AssignmentDefinition | +| k_getsetattr.py:24 | Local Variable c3 | AssignmentDefinition | +| k_getsetattr.py:25 | Local Variable c1 | AttributeAssignment | +| k_getsetattr.py:27 | Local Variable c2 | AttributeAssignment | +| k_getsetattr.py:27 | Local Variable cond | PyEdgeRefinement | +| k_getsetattr.py:28 | Local Variable c2 | PhiFunction | +| k_getsetattr.py:28 | Local Variable cond | PhiFunction | +| k_getsetattr.py:28 | Local Variable cond | PyEdgeRefinement | +| k_getsetattr.py:31 | Local Variable c3 | AttributeAssignment | diff --git a/python/ql/test/library-tests/PointsTo/new/Definitions.ql b/python/ql/test/library-tests/PointsTo/new/Definitions.ql new file mode 100644 index 00000000000..166e9391868 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/Definitions.ql @@ -0,0 +1,8 @@ + +import python + +import Util + +from EssaDefinition def, Variable v +where v = def.getSourceVariable() +select locate(def.getLocation(), "abdgk"), v.toString(), def.getAQlClass() \ No newline at end of file diff --git a/python/ql/test/library-tests/PointsTo/new/Live.expected b/python/ql/test/library-tests/PointsTo/new/Live.expected new file mode 100644 index 00000000000..a0a70d136c7 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/Live.expected @@ -0,0 +1,424 @@ +| Global Variable Exception | b_condition.py:0 | entry | +| Global Variable Exception | b_condition.py:42 | exit | +| Global Variable Exception | b_condition.py:43 | entry | +| Global Variable Exception | b_condition.py:44 | exit | +| Global Variable Exception | b_condition.py:47 | entry | +| Global Variable Exception | b_condition.py:101 | entry | +| Global Variable Exception | b_condition.py:102 | exit | +| Global Variable Exception | b_condition.py:104 | entry | +| Global Variable Exception | b_condition.py:104 | exit | +| Global Variable Exception | b_condition.py:105 | entry | +| Global Variable Exception | b_condition.py:105 | exit | +| Global Variable Exception | b_condition.py:106 | entry | +| Global Variable TypeError | b_condition.py:0 | entry | +| Global Variable TypeError | b_condition.py:42 | exit | +| Global Variable TypeError | b_condition.py:43 | entry | +| Global Variable TypeError | b_condition.py:44 | exit | +| Global Variable TypeError | b_condition.py:47 | entry | +| Global Variable TypeError | b_condition.py:101 | entry | +| Global Variable TypeError | b_condition.py:102 | exit | +| Global Variable TypeError | b_condition.py:103 | entry | +| Global Variable __name__ | b_condition.py:42 | exit | +| Global Variable __name__ | b_condition.py:43 | entry | +| Global Variable __name__ | b_condition.py:44 | exit | +| Global Variable __name__ | b_condition.py:47 | entry | +| Global Variable __package__ | b_condition.py:42 | exit | +| Global Variable __package__ | b_condition.py:43 | entry | +| Global Variable __package__ | b_condition.py:44 | exit | +| Global Variable __package__ | b_condition.py:47 | entry | +| Global Variable callable | b_condition.py:0 | entry | +| Global Variable callable | b_condition.py:42 | exit | +| Global Variable callable | b_condition.py:43 | entry | +| Global Variable callable | b_condition.py:44 | exit | +| Global Variable callable | b_condition.py:47 | entry | +| Global Variable callable | b_condition.py:81 | entry | +| Global Variable cond | b_condition.py:0 | entry | +| Global Variable cond | b_condition.py:4 | entry | +| Global Variable cond | b_condition.py:5 | entry | +| Global Variable cond | b_condition.py:5 | exit | +| Global Variable cond | b_condition.py:7 | exit | +| Global Variable cond | b_condition.py:8 | entry | +| Global Variable cond | b_condition.py:8 | exit | +| Global Variable cond | b_condition.py:9 | entry | +| Global Variable cond | b_condition.py:11 | entry | +| Global Variable cond | b_condition.py:11 | exit | +| Global Variable cond | b_condition.py:13 | exit | +| Global Variable cond | b_condition.py:14 | entry | +| Global Variable cond | b_condition.py:14 | exit | +| Global Variable cond | b_condition.py:15 | entry | +| Global Variable cond | b_condition.py:17 | entry | +| Global Variable cond | b_condition.py:17 | exit | +| Global Variable cond | b_condition.py:19 | exit | +| Global Variable cond | b_condition.py:20 | entry | +| Global Variable cond | b_condition.py:20 | exit | +| Global Variable cond | b_condition.py:21 | entry | +| Global Variable cond | b_condition.py:23 | entry | +| Global Variable cond | b_condition.py:23 | exit | +| Global Variable cond | b_condition.py:25 | entry | +| Global Variable cond | b_condition.py:25 | exit | +| Global Variable cond | b_condition.py:27 | exit | +| Global Variable cond | b_condition.py:28 | entry | +| Global Variable cond | b_condition.py:28 | exit | +| Global Variable cond | b_condition.py:29 | entry | +| Global Variable cond | b_condition.py:42 | exit | +| Global Variable cond | b_condition.py:43 | entry | +| Global Variable cond | b_condition.py:44 | exit | +| Global Variable cond | b_condition.py:47 | entry | +| Global Variable cond | b_condition.py:69 | entry | +| Global Variable double_attr_check | b_condition.py:42 | exit | +| Global Variable double_attr_check | b_condition.py:43 | entry | +| Global Variable f | b_condition.py:42 | exit | +| Global Variable f | b_condition.py:43 | entry | +| Global Variable f | b_condition.py:44 | exit | +| Global Variable f | b_condition.py:47 | entry | +| Global Variable g | b_condition.py:42 | exit | +| Global Variable g | b_condition.py:43 | entry | +| Global Variable h | b_condition.py:42 | exit | +| Global Variable h | b_condition.py:43 | entry | +| Global Variable int | b_condition.py:0 | entry | +| Global Variable int | b_condition.py:4 | entry | +| Global Variable int | b_condition.py:5 | entry | +| Global Variable int | b_condition.py:5 | exit | +| Global Variable int | b_condition.py:7 | exit | +| Global Variable int | b_condition.py:8 | entry | +| Global Variable int | b_condition.py:8 | exit | +| Global Variable int | b_condition.py:9 | entry | +| Global Variable int | b_condition.py:11 | entry | +| Global Variable int | b_condition.py:11 | exit | +| Global Variable int | b_condition.py:13 | exit | +| Global Variable int | b_condition.py:14 | entry | +| Global Variable int | b_condition.py:14 | exit | +| Global Variable int | b_condition.py:15 | entry | +| Global Variable int | b_condition.py:17 | entry | +| Global Variable int | b_condition.py:17 | exit | +| Global Variable int | b_condition.py:19 | exit | +| Global Variable int | b_condition.py:20 | entry | +| Global Variable int | b_condition.py:20 | exit | +| Global Variable int | b_condition.py:21 | entry | +| Global Variable int | b_condition.py:23 | entry | +| Global Variable int | b_condition.py:23 | exit | +| Global Variable int | b_condition.py:25 | entry | +| Global Variable int | b_condition.py:25 | exit | +| Global Variable int | b_condition.py:27 | exit | +| Global Variable int | b_condition.py:28 | entry | +| Global Variable int | b_condition.py:28 | exit | +| Global Variable int | b_condition.py:29 | entry | +| Global Variable int | b_condition.py:31 | entry | +| Global Variable int | b_condition.py:31 | exit | +| Global Variable int | b_condition.py:32 | exit | +| Global Variable int | b_condition.py:33 | entry | +| Global Variable int | b_condition.py:33 | exit | +| Global Variable int | b_condition.py:34 | entry | +| Global Variable int | b_condition.py:42 | exit | +| Global Variable int | b_condition.py:43 | entry | +| Global Variable int | b_condition.py:44 | exit | +| Global Variable int | b_condition.py:47 | entry | +| Global Variable isinstance | b_condition.py:0 | entry | +| Global Variable isinstance | b_condition.py:4 | entry | +| Global Variable isinstance | b_condition.py:5 | entry | +| Global Variable isinstance | b_condition.py:5 | exit | +| Global Variable isinstance | b_condition.py:7 | exit | +| Global Variable isinstance | b_condition.py:8 | entry | +| Global Variable isinstance | b_condition.py:8 | exit | +| Global Variable isinstance | b_condition.py:9 | entry | +| Global Variable isinstance | b_condition.py:11 | entry | +| Global Variable isinstance | b_condition.py:11 | exit | +| Global Variable isinstance | b_condition.py:13 | exit | +| Global Variable isinstance | b_condition.py:14 | entry | +| Global Variable isinstance | b_condition.py:14 | exit | +| Global Variable isinstance | b_condition.py:15 | entry | +| Global Variable isinstance | b_condition.py:17 | entry | +| Global Variable isinstance | b_condition.py:17 | exit | +| Global Variable isinstance | b_condition.py:19 | exit | +| Global Variable isinstance | b_condition.py:20 | entry | +| Global Variable isinstance | b_condition.py:20 | exit | +| Global Variable isinstance | b_condition.py:21 | entry | +| Global Variable isinstance | b_condition.py:23 | entry | +| Global Variable isinstance | b_condition.py:23 | exit | +| Global Variable isinstance | b_condition.py:25 | entry | +| Global Variable isinstance | b_condition.py:25 | exit | +| Global Variable isinstance | b_condition.py:27 | exit | +| Global Variable isinstance | b_condition.py:28 | entry | +| Global Variable isinstance | b_condition.py:28 | exit | +| Global Variable isinstance | b_condition.py:29 | entry | +| Global Variable isinstance | b_condition.py:31 | entry | +| Global Variable isinstance | b_condition.py:31 | exit | +| Global Variable isinstance | b_condition.py:32 | exit | +| Global Variable isinstance | b_condition.py:33 | entry | +| Global Variable isinstance | b_condition.py:33 | exit | +| Global Variable isinstance | b_condition.py:34 | entry | +| Global Variable isinstance | b_condition.py:42 | exit | +| Global Variable isinstance | b_condition.py:43 | entry | +| Global Variable isinstance | b_condition.py:44 | exit | +| Global Variable isinstance | b_condition.py:47 | entry | +| Global Variable isinstance | b_condition.py:101 | entry | +| Global Variable k | b_condition.py:42 | exit | +| Global Variable k | b_condition.py:43 | entry | +| Global Variable list | b_condition.py:0 | entry | +| Global Variable list | b_condition.py:42 | exit | +| Global Variable list | b_condition.py:43 | entry | +| Global Variable list | b_condition.py:44 | exit | +| Global Variable list | b_condition.py:47 | entry | +| Global Variable list | b_condition.py:101 | entry | +| Global Variable loop | b_condition.py:42 | exit | +| Global Variable loop | b_condition.py:43 | entry | +| Global Variable not_or_not | b_condition.py:42 | exit | +| Global Variable not_or_not | b_condition.py:43 | entry | +| Global Variable object | b_condition.py:0 | entry | +| Global Variable object | b_condition.py:42 | exit | +| Global Variable object | b_condition.py:43 | entry | +| Global Variable object | b_condition.py:44 | exit | +| Global Variable object | b_condition.py:47 | entry | +| Global Variable object | b_condition.py:75 | entry | +| Global Variable object | b_condition.py:77 | exit | +| Global Variable object | b_condition.py:78 | entry | +| Global Variable odasa6261 | b_condition.py:42 | exit | +| Global Variable odasa6261 | b_condition.py:43 | entry | +| Global Variable seq | b_condition.py:0 | entry | +| Global Variable seq | b_condition.py:42 | exit | +| Global Variable seq | b_condition.py:43 | entry | +| Global Variable seq | b_condition.py:44 | exit | +| Global Variable seq | b_condition.py:47 | entry | +| Global Variable seq | b_condition.py:61 | entry | +| Global Variable seq | b_condition.py:62 | exit | +| Global Variable seq | b_condition.py:64 | entry | +| Global Variable seq | b_condition.py:64 | exit | +| Global Variable seq | b_condition.py:65 | entry | +| Global Variable seq | b_condition.py:65 | exit | +| Global Variable seq | b_condition.py:66 | entry | +| Global Variable split_bool1 | b_condition.py:42 | exit | +| Global Variable split_bool1 | b_condition.py:43 | entry | +| Global Variable thing | b_condition.py:0 | entry | +| Global Variable thing | b_condition.py:42 | exit | +| Global Variable thing | b_condition.py:43 | entry | +| Global Variable thing | b_condition.py:44 | exit | +| Global Variable thing | b_condition.py:47 | entry | +| Global Variable tuple | b_condition.py:0 | entry | +| Global Variable tuple | b_condition.py:42 | exit | +| Global Variable tuple | b_condition.py:43 | entry | +| Global Variable tuple | b_condition.py:44 | exit | +| Global Variable tuple | b_condition.py:47 | entry | +| Global Variable tuple | b_condition.py:101 | entry | +| Global Variable type | b_condition.py:0 | entry | +| Global Variable type | b_condition.py:42 | exit | +| Global Variable type | b_condition.py:43 | entry | +| Global Variable type | b_condition.py:44 | exit | +| Global Variable type | b_condition.py:47 | entry | +| Global Variable type | b_condition.py:75 | entry | +| Global Variable unknown | b_condition.py:0 | entry | +| Global Variable unknown | b_condition.py:4 | entry | +| Global Variable unknown | b_condition.py:5 | entry | +| Global Variable unknown | b_condition.py:5 | exit | +| Global Variable unknown | b_condition.py:7 | exit | +| Global Variable unknown | b_condition.py:8 | entry | +| Global Variable unknown | b_condition.py:8 | exit | +| Global Variable unknown | b_condition.py:9 | entry | +| Global Variable unknown | b_condition.py:11 | entry | +| Global Variable unknown | b_condition.py:11 | exit | +| Global Variable unknown | b_condition.py:13 | exit | +| Global Variable unknown | b_condition.py:14 | entry | +| Global Variable unknown | b_condition.py:14 | exit | +| Global Variable unknown | b_condition.py:15 | entry | +| Global Variable unknown | b_condition.py:17 | entry | +| Global Variable unknown | b_condition.py:17 | exit | +| Global Variable unknown | b_condition.py:19 | exit | +| Global Variable unknown | b_condition.py:20 | entry | +| Global Variable unknown | b_condition.py:20 | exit | +| Global Variable unknown | b_condition.py:21 | entry | +| Global Variable unknown | b_condition.py:23 | entry | +| Global Variable unknown | b_condition.py:23 | exit | +| Global Variable unknown | b_condition.py:25 | entry | +| Global Variable unknown | b_condition.py:25 | exit | +| Global Variable unknown | b_condition.py:27 | exit | +| Global Variable unknown | b_condition.py:28 | entry | +| Global Variable unknown | b_condition.py:28 | exit | +| Global Variable unknown | b_condition.py:29 | entry | +| Global Variable unknown | b_condition.py:31 | entry | +| Global Variable unknown | b_condition.py:31 | exit | +| Global Variable unknown | b_condition.py:42 | exit | +| Global Variable unknown | b_condition.py:43 | entry | +| Global Variable unknown | b_condition.py:44 | exit | +| Global Variable unknown | b_condition.py:47 | entry | +| Global Variable unknown | b_condition.py:69 | entry | +| Global Variable unknown | b_condition.py:70 | entry | +| Global Variable unknown | b_condition.py:70 | exit | +| Global Variable use | b_condition.py:0 | entry | +| Global Variable use | b_condition.py:4 | entry | +| Global Variable use | b_condition.py:5 | entry | +| Global Variable use | b_condition.py:5 | exit | +| Global Variable use | b_condition.py:7 | exit | +| Global Variable use | b_condition.py:8 | entry | +| Global Variable use | b_condition.py:8 | exit | +| Global Variable use | b_condition.py:9 | entry | +| Global Variable use | b_condition.py:11 | entry | +| Global Variable use | b_condition.py:11 | exit | +| Global Variable use | b_condition.py:13 | exit | +| Global Variable use | b_condition.py:14 | entry | +| Global Variable use | b_condition.py:14 | exit | +| Global Variable use | b_condition.py:15 | entry | +| Global Variable use | b_condition.py:17 | entry | +| Global Variable use | b_condition.py:17 | exit | +| Global Variable use | b_condition.py:19 | exit | +| Global Variable use | b_condition.py:20 | entry | +| Global Variable use | b_condition.py:20 | exit | +| Global Variable use | b_condition.py:21 | entry | +| Global Variable use | b_condition.py:23 | entry | +| Global Variable use | b_condition.py:23 | exit | +| Global Variable use | b_condition.py:25 | entry | +| Global Variable use | b_condition.py:25 | exit | +| Global Variable use | b_condition.py:27 | exit | +| Global Variable use | b_condition.py:28 | entry | +| Global Variable use | b_condition.py:28 | exit | +| Global Variable use | b_condition.py:29 | entry | +| Global Variable use | b_condition.py:31 | entry | +| Global Variable use | b_condition.py:31 | exit | +| Global Variable use | b_condition.py:32 | exit | +| Global Variable use | b_condition.py:33 | entry | +| Global Variable use | b_condition.py:33 | exit | +| Global Variable use | b_condition.py:34 | entry | +| Global Variable use | b_condition.py:36 | entry | +| Global Variable use | b_condition.py:36 | exit | +| Global Variable use | b_condition.py:42 | exit | +| Global Variable use | b_condition.py:43 | entry | +| Global Variable use | b_condition.py:44 | exit | +| Global Variable use | b_condition.py:47 | entry | +| Global Variable use | b_condition.py:55 | entry | +| Global Variable use | b_condition.py:56 | entry | +| Global Variable use | b_condition.py:56 | exit | +| Global Variable use | b_condition.py:57 | exit | +| Global Variable use | b_condition.py:58 | entry | +| Global Variable use | b_condition.py:58 | exit | +| Global Variable use | b_condition.py:75 | entry | +| Global Variable use | b_condition.py:77 | exit | +| Global Variable use | b_condition.py:78 | entry | +| Global Variable use | b_condition.py:78 | exit | +| Global Variable use | b_condition.py:79 | entry | +| Global Variable use | b_condition.py:87 | entry | +| Global Variable use | b_condition.py:88 | entry | +| Global Variable use | b_condition.py:88 | exit | +| Global Variable use | b_condition.py:90 | entry | +| Global Variable use | b_condition.py:90 | exit | +| Global Variable v2 | b_condition.py:42 | exit | +| Global Variable v2 | b_condition.py:43 | entry | +| Global Variable v2 | b_condition.py:44 | exit | +| Global Variable v2 | b_condition.py:47 | entry | +| Local Variable a | b_condition.py:102 | exit | +| Local Variable a | b_condition.py:104 | entry | +| Local Variable a | b_condition.py:104 | exit | +| Local Variable a | b_condition.py:105 | entry | +| Local Variable a | b_condition.py:105 | exit | +| Local Variable a | b_condition.py:107 | entry | +| Local Variable b | b_condition.py:71 | exit | +| Local Variable b | b_condition.py:72 | exit | +| Local Variable b | b_condition.py:73 | entry | +| Local Variable bar | b_condition.py:81 | entry | +| Local Variable bar | b_condition.py:82 | exit | +| Local Variable bar | b_condition.py:83 | exit | +| Local Variable foo | b_condition.py:81 | entry | +| Local Variable foo | b_condition.py:82 | exit | +| Local Variable foo | b_condition.py:83 | entry | +| Local Variable foo | b_condition.py:83 | exit | +| Local Variable seq | b_condition.py:55 | entry | +| Local Variable seq | b_condition.py:56 | entry | +| Local Variable seq | b_condition.py:56 | exit | +| Local Variable seq | b_condition.py:57 | exit | +| Local Variable seq | b_condition.py:58 | entry | +| Local Variable seq | b_condition.py:58 | exit | +| Local Variable t | b_condition.py:77 | exit | +| Local Variable t | b_condition.py:78 | exit | +| Local Variable t | b_condition.py:79 | entry | +| Local Variable v | b_condition.py:55 | entry | +| Local Variable v | b_condition.py:56 | entry | +| Local Variable v | b_condition.py:56 | exit | +| Local Variable v | b_condition.py:57 | exit | +| Local Variable v | b_condition.py:58 | entry | +| Local Variable v | b_condition.py:58 | exit | +| Local Variable x | b_condition.py:7 | exit | +| Local Variable x | b_condition.py:8 | exit | +| Local Variable x | b_condition.py:9 | entry | +| Local Variable x | b_condition.py:13 | exit | +| Local Variable x | b_condition.py:14 | exit | +| Local Variable x | b_condition.py:15 | entry | +| Local Variable x | b_condition.py:19 | exit | +| Local Variable x | b_condition.py:20 | exit | +| Local Variable x | b_condition.py:21 | entry | +| Local Variable x | b_condition.py:25 | entry | +| Local Variable x | b_condition.py:25 | exit | +| Local Variable x | b_condition.py:27 | exit | +| Local Variable x | b_condition.py:28 | exit | +| Local Variable x | b_condition.py:29 | entry | +| Local Variable x | b_condition.py:32 | exit | +| Local Variable x | b_condition.py:33 | exit | +| Local Variable x | b_condition.py:34 | entry | +| Local Variable x | b_condition.py:36 | entry | +| Local Variable x | b_condition.py:36 | exit | +| Local Variable x | b_condition.py:50 | entry | +| Local Variable x | b_condition.py:51 | exit | +| Local Variable x | b_condition.py:52 | entry | +| Local Variable x | b_condition.py:52 | exit | +| Local Variable x | b_condition.py:61 | entry | +| Local Variable x | b_condition.py:62 | exit | +| Local Variable x | b_condition.py:63 | entry | +| Local Variable x | b_condition.py:63 | exit | +| Local Variable x | b_condition.py:64 | entry | +| Local Variable x | b_condition.py:64 | exit | +| Local Variable x | b_condition.py:65 | entry | +| Local Variable x | b_condition.py:65 | exit | +| Local Variable x | b_condition.py:66 | entry | +| Local Variable x | b_condition.py:66 | exit | +| Local Variable x | b_condition.py:67 | entry | +| Local Variable x | b_condition.py:67 | exit | +| Local Variable x | b_condition.py:88 | entry | +| Local Variable x | b_condition.py:88 | exit | +| Local Variable x | b_condition.py:90 | entry | +| Local Variable x | b_condition.py:90 | exit | +| Local Variable y | b_condition.py:5 | entry | +| Local Variable y | b_condition.py:5 | exit | +| Local Variable y | b_condition.py:7 | exit | +| Local Variable y | b_condition.py:8 | entry | +| Local Variable y | b_condition.py:8 | exit | +| Local Variable y | b_condition.py:9 | entry | +| Local Variable y | b_condition.py:11 | entry | +| Local Variable y | b_condition.py:11 | exit | +| Local Variable y | b_condition.py:13 | exit | +| Local Variable y | b_condition.py:14 | entry | +| Local Variable y | b_condition.py:14 | exit | +| Local Variable y | b_condition.py:15 | entry | +| Local Variable y | b_condition.py:17 | entry | +| Local Variable y | b_condition.py:17 | exit | +| Local Variable y | b_condition.py:19 | exit | +| Local Variable y | b_condition.py:20 | entry | +| Local Variable y | b_condition.py:20 | exit | +| Local Variable y | b_condition.py:21 | entry | +| Local Variable y | b_condition.py:23 | entry | +| Local Variable y | b_condition.py:23 | exit | +| Local Variable y | b_condition.py:25 | entry | +| Local Variable y | b_condition.py:25 | exit | +| Local Variable y | b_condition.py:27 | exit | +| Local Variable y | b_condition.py:28 | entry | +| Local Variable y | b_condition.py:28 | exit | +| Local Variable y | b_condition.py:29 | entry | +| Local Variable y | b_condition.py:31 | entry | +| Local Variable y | b_condition.py:31 | exit | +| Local Variable y | b_condition.py:32 | exit | +| Local Variable y | b_condition.py:33 | entry | +| Local Variable y | b_condition.py:33 | exit | +| Local Variable y | b_condition.py:34 | entry | +| Local Variable y | b_condition.py:36 | entry | +| Local Variable y | b_condition.py:36 | exit | +| Local Variable y | b_condition.py:61 | entry | +| Local Variable y | b_condition.py:62 | exit | +| Local Variable y | b_condition.py:63 | entry | +| Local Variable y | b_condition.py:63 | exit | +| Local Variable y | b_condition.py:64 | entry | +| Local Variable y | b_condition.py:64 | exit | +| Local Variable y | b_condition.py:65 | entry | +| Local Variable y | b_condition.py:65 | exit | +| Local Variable y | b_condition.py:66 | entry | +| Local Variable y | b_condition.py:66 | exit | +| Local Variable y | b_condition.py:67 | entry | +| Local Variable y | b_condition.py:67 | exit | +| Local Variable y | b_condition.py:88 | entry | +| Local Variable y | b_condition.py:88 | exit | +| Local Variable y | b_condition.py:90 | entry | +| Local Variable y | b_condition.py:90 | exit | diff --git a/python/ql/test/library-tests/PointsTo/new/Live.ql b/python/ql/test/library-tests/PointsTo/new/Live.ql new file mode 100644 index 00000000000..ffd60fe5e6b --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/Live.ql @@ -0,0 +1,15 @@ + +import python +import semmle.dataflow.SSA +import semmle.dataflow.SsaCompute + +import Util + +from Variable var, BasicBlock b, ControlFlowNode loc, string end +where +Liveness::liveAtEntry(var, b) and end = "entry" and loc = b.getNode(0) +or +Liveness::liveAtExit(var, b) and end = "exit" and loc = b.getLastNode() + + +select var, locate(loc.getLocation(), "b"), end \ No newline at end of file diff --git a/python/ql/test/library-tests/PointsTo/new/NameSpace.expected b/python/ql/test/library-tests/PointsTo/new/NameSpace.expected new file mode 100644 index 00000000000..5f84595de0a --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/NameSpace.expected @@ -0,0 +1,191 @@ +| a_simple.py:0 | Module code.a_simple | C | class C | +| a_simple.py:0 | Module code.a_simple | f | Function f | +| a_simple.py:0 | Module code.a_simple | f1 | float 1.0 | +| a_simple.py:0 | Module code.a_simple | func | Function func | +| a_simple.py:0 | Module code.a_simple | i1 | int 0 | +| a_simple.py:0 | Module code.a_simple | multi_loop | Function multi_loop | +| a_simple.py:0 | Module code.a_simple | multi_loop_in_try | Function multi_loop_in_try | +| a_simple.py:0 | Module code.a_simple | s | Tuple | +| a_simple.py:0 | Module code.a_simple | vararg_kwarg | Function vararg_kwarg | +| a_simple.py:0 | Module code.a_simple | with_definition | Function with_definition | +| b_condition.py:0 | Module code.b_condition | double_attr_check | Function double_attr_check | +| b_condition.py:0 | Module code.b_condition | f | Function f | +| b_condition.py:0 | Module code.b_condition | g | Function g | +| b_condition.py:0 | Module code.b_condition | h | Function h | +| b_condition.py:0 | Module code.b_condition | k | Function k | +| b_condition.py:0 | Module code.b_condition | loop | Function loop | +| b_condition.py:0 | Module code.b_condition | not_or_not | Function not_or_not | +| b_condition.py:0 | Module code.b_condition | odasa6261 | Function odasa6261 | +| b_condition.py:0 | Module code.b_condition | split_bool1 | Function split_bool1 | +| c_tests.py:0 | Module code.c_tests | complex_test | Function complex_test | +| c_tests.py:0 | Module code.c_tests | compound | Function compound | +| c_tests.py:0 | Module code.c_tests | f | Function f | +| c_tests.py:0 | Module code.c_tests | h | Function h | +| c_tests.py:0 | Module code.c_tests | others | Function others | +| d_globals.py:0 | Module code.d_globals | D | class D | +| d_globals.py:0 | Module code.d_globals | Ugly | class Ugly | +| d_globals.py:0 | Module code.d_globals | X | class X | +| d_globals.py:0 | Module code.d_globals | assign_global | Function assign_global | +| d_globals.py:0 | Module code.d_globals | dict | int 7 | +| d_globals.py:0 | Module code.d_globals | g1 | NoneType None | +| d_globals.py:0 | Module code.d_globals | g2 | int 102 | +| d_globals.py:0 | Module code.d_globals | g3 | NoneType None | +| d_globals.py:0 | Module code.d_globals | g4 | NoneType None | +| d_globals.py:0 | Module code.d_globals | get_g4 | Function get_g4 | +| d_globals.py:0 | Module code.d_globals | init | Function init | +| d_globals.py:0 | Module code.d_globals | j | Function j | +| d_globals.py:0 | Module code.d_globals | k | Function k | +| d_globals.py:0 | Module code.d_globals | outer | Function outer | +| d_globals.py:0 | Module code.d_globals | redefine | Function redefine | +| d_globals.py:0 | Module code.d_globals | set_g4 | Function set_g4 | +| d_globals.py:0 | Module code.d_globals | set_g4_indirect | Function set_g4_indirect | +| d_globals.py:0 | Module code.d_globals | tuple | builtin-class tuple | +| d_globals.py:0 | Module code.d_globals | use_list_attribute | Function use_list_attribute | +| d_globals.py:0 | Module code.d_globals | x | int 1 | +| d_globals.py:0 | Module code.d_globals | x | int 3 | +| d_globals.py:0 | Module code.d_globals | y | int 1 | +| d_globals.py:0 | Module code.d_globals | y | int 2 | +| d_globals.py:35 | Class Ugly | __init__ | Function __init__ | +| d_globals.py:35 | Class Ugly | meth | Function meth | +| d_globals.py:62 | Class X | y | int 1 | +| d_globals.py:62 | Class X | y | int 2 | +| d_globals.py:118 | Class D | __init__ | Function __init__ | +| d_globals.py:118 | Class D | foo | Function foo | +| g_class_init.py:0 | Module code.g_class_init | C | class C | +| g_class_init.py:0 | Module code.g_class_init | D | class D | +| g_class_init.py:0 | Module code.g_class_init | E | class E | +| g_class_init.py:0 | Module code.g_class_init | Oddities | class Oddities | +| g_class_init.py:0 | Module code.g_class_init | V2 | 'v2' | +| g_class_init.py:0 | Module code.g_class_init | V3 | 'v3' | +| g_class_init.py:3 | Class C | __init__ | Function __init__ | +| g_class_init.py:3 | Class C | _init | Function _init | +| g_class_init.py:3 | Class C | _init2 | Function _init2 | +| g_class_init.py:3 | Class C | method | Function method | +| g_class_init.py:24 | Class Oddities | float | builtin-class float | +| g_class_init.py:24 | Class Oddities | h | Builtin-function hash | +| g_class_init.py:24 | Class Oddities | int | builtin-class int | +| g_class_init.py:24 | Class Oddities | l | Builtin-function len | +| g_class_init.py:32 | Class D | __init__ | Function __init__ | +| g_class_init.py:45 | Class E | __init__ | Function __init__ | +| g_class_init.py:45 | Class E | meth | Function meth | +| h_classes.py:0 | Module code.h_classes | Base | class Base | +| h_classes.py:0 | Module code.h_classes | C | class C | +| h_classes.py:0 | Module code.h_classes | D | class D | +| h_classes.py:0 | Module code.h_classes | Derived1 | class Derived1 | +| h_classes.py:0 | Module code.h_classes | Derived2 | class Derived2 | +| h_classes.py:0 | Module code.h_classes | Derived3 | class Derived3 | +| h_classes.py:0 | Module code.h_classes | f | Function f | +| h_classes.py:0 | Module code.h_classes | k | Function k | +| h_classes.py:0 | Module code.h_classes | sys | Module sys | +| h_classes.py:3 | Class C | __init__ | Function __init__ | +| h_classes.py:3 | Class C | x | 'C_x' | +| h_classes.py:23 | Class Base | __init__ | Function __init__ | +| h_classes.py:48 | Class D | m | Function f | +| h_classes.py:48 | Class D | n | Function n | +| i_imports.py:0 | Module code.i_imports | BytesIO | builtin-class _io.BytesIO | +| i_imports.py:0 | Module code.i_imports | StringIO | builtin-class _io.StringIO | +| i_imports.py:0 | Module code.i_imports | _io | Module _io | +| i_imports.py:0 | Module code.i_imports | a | int 1 | +| i_imports.py:0 | Module code.i_imports | argv | list object | +| i_imports.py:0 | Module code.i_imports | b | int 2 | +| i_imports.py:0 | Module code.i_imports | c | int 3 | +| i_imports.py:0 | Module code.i_imports | code | Module code | +| i_imports.py:0 | Module code.i_imports | io | Module io | +| i_imports.py:0 | Module code.i_imports | module1 | Module code.test_package.module1 | +| i_imports.py:0 | Module code.i_imports | module2 | Module code.test_package.module2 | +| i_imports.py:0 | Module code.i_imports | p | int 1 | +| i_imports.py:0 | Module code.i_imports | q | int 2 | +| i_imports.py:0 | Module code.i_imports | r | Dict | +| i_imports.py:0 | Module code.i_imports | s | NoneType None | +| i_imports.py:0 | Module code.i_imports | sys | Module sys | +| i_imports.py:0 | Module code.i_imports | x | float 1.0 | +| i_imports.py:0 | Module code.i_imports | xyz | Module code.xyz | +| i_imports.py:0 | Module code.i_imports | y | float 2.0 | +| i_imports.py:0 | Module code.i_imports | z | float 3.0 | +| j_convoluted_imports.py:0 | Module code.j_convoluted_imports | C | class C | +| j_convoluted_imports.py:0 | Module code.j_convoluted_imports | module | Function module | +| j_convoluted_imports.py:0 | Module code.j_convoluted_imports | moduleX | Module code.package.moduleX | +| j_convoluted_imports.py:0 | Module code.j_convoluted_imports | x | Module code.package.x | +| j_convoluted_imports.py:9 | Class C | f | Function f | +| j_convoluted_imports.py:9 | Class C | module2 | int 7 | +| k_getsetattr.py:0 | Module code.k_getsetattr | C | class C | +| k_getsetattr.py:0 | Module code.k_getsetattr | k | Function k | +| k_getsetattr.py:4 | Class C | meth1 | Function meth1 | +| k_getsetattr.py:4 | Class C | meth2 | Function meth2 | +| l_calls.py:0 | Module code.l_calls | Owner | class Owner | +| l_calls.py:0 | Module code.l_calls | bar | Function bar | +| l_calls.py:0 | Module code.l_calls | foo | Function foo | +| l_calls.py:12 | Class Owner | cm | classmethod() | +| l_calls.py:12 | Class Owner | cm2 | classmethod() | +| l_calls.py:12 | Class Owner | m | Function m | +| o_no_returns.py:0 | Module code.o_no_returns | bar | Function bar | +| o_no_returns.py:0 | Module code.o_no_returns | fail | Function fail | +| o_no_returns.py:0 | Module code.o_no_returns | foo | Function foo | +| o_no_returns.py:0 | Module code.o_no_returns | sys | Module sys | +| p_decorators.py:0 | Module code.p_decorators | C | class C | +| p_decorators.py:0 | Module code.p_decorators | bar | Function bar | +| p_decorators.py:0 | Module code.p_decorators | complex | Function complex | +| p_decorators.py:0 | Module code.p_decorators | foo | Function foo | +| p_decorators.py:0 | Module code.p_decorators | simple | Function simple | +| p_decorators.py:24 | Class C | cmeth | classmethod() | +| p_decorators.py:24 | Class C | smeth | staticmethod() | +| q_super.py:0 | Module code.q_super | Base1 | class Base1 | +| q_super.py:0 | Module code.q_super | Base2 | class Base2 | +| q_super.py:0 | Module code.q_super | DA | class DA | +| q_super.py:0 | Module code.q_super | DB | class DB | +| q_super.py:0 | Module code.q_super | DD | class DD | +| q_super.py:0 | Module code.q_super | DE | class DE | +| q_super.py:0 | Module code.q_super | Derived1 | class Derived1 | +| q_super.py:0 | Module code.q_super | Derived2 | class Derived2 | +| q_super.py:0 | Module code.q_super | Derived4 | class Derived4 | +| q_super.py:0 | Module code.q_super | Derived5 | class Derived5 | +| q_super.py:0 | Module code.q_super | M | class M | +| q_super.py:0 | Module code.q_super | N | class N | +| q_super.py:0 | Module code.q_super | Wrong1 | class Wrong1 | +| q_super.py:1 | Class Base2 | __init__ | Function __init__ | +| q_super.py:8 | Class Derived4 | __init__ | Function __init__ | +| q_super.py:14 | Class Base1 | meth | Function meth | +| q_super.py:19 | Class Derived1 | meth | Function meth | +| q_super.py:24 | Class Derived2 | meth | Function meth | +| q_super.py:29 | Class Derived5 | meth | Function meth | +| q_super.py:35 | Class Wrong1 | meth | Function meth | +| q_super.py:41 | Class DA | __init__ | Function __init__ | +| q_super.py:46 | Class DB | DC | class DC | +| q_super.py:48 | Class DC | __init__ | Function __init__ | +| q_super.py:55 | Class DD | __init__ | Function __init__ | +| q_super.py:61 | Class DE | DF | class DF | +| q_super.py:63 | Class DF | __init__ | Function __init__ | +| q_super.py:71 | Class M | __init__ | Function __init__ | +| r_regressions.py:0 | Module code.r_regressions | C | class C | +| r_regressions.py:0 | Module code.r_regressions | Queue | class Queue | +| r_regressions.py:0 | Module code.r_regressions | TestFirst | class TestFirst | +| r_regressions.py:0 | Module code.r_regressions | _names | tuple object | +| r_regressions.py:0 | Module code.r_regressions | deco | Function deco | +| r_regressions.py:0 | Module code.r_regressions | f | Function f | +| r_regressions.py:0 | Module code.r_regressions | fail | Function fail | +| r_regressions.py:0 | Module code.r_regressions | find_library | Function find_library | +| r_regressions.py:0 | Module code.r_regressions | method_decorator | Function method_decorator | +| r_regressions.py:0 | Module code.r_regressions | sys | Module sys | +| r_regressions.py:0 | Module code.r_regressions | t | Module time | +| r_regressions.py:5 | Class Queue | __init__ | Function __init__ | +| r_regressions.py:5 | Class Queue | _after_fork | Function _after_fork | +| r_regressions.py:5 | Class Queue | close | Function close | +| r_regressions.py:49 | Class C | fail | Function fail | +| r_regressions.py:86 | Class TestFirst | method | Function method | +| s_scopes.py:0 | Module code.s_scopes | C2 | class C2 | +| s_scopes.py:0 | Module code.s_scopes | f | bool True | +| s_scopes.py:0 | Module code.s_scopes | f | builtin-class float | +| s_scopes.py:0 | Module code.s_scopes | float | bool True | +| s_scopes.py:0 | Module code.s_scopes | i | builtin-class int | +| s_scopes.py:7 | Class C2 | f1 | bool True | +| s_scopes.py:7 | Class C2 | f1 | builtin-class float | +| s_scopes.py:7 | Class C2 | f2 | NoneType None | +| s_scopes.py:7 | Class C2 | f2 | bool True | +| s_scopes.py:7 | Class C2 | f2 | builtin-class float | +| s_scopes.py:7 | Class C2 | float | NoneType None | +| s_scopes.py:7 | Class C2 | i1 | builtin-class int | +| s_scopes.py:7 | Class C2 | i2 | int 0 | +| s_scopes.py:7 | Class C2 | int | int 0 | +| s_scopes.py:7 | Class C2 | s | builtin-class str | +| s_scopes.py:7 | Class C2 | s | float 1.0 | +| s_scopes.py:7 | Class C2 | str | float 1.0 | diff --git a/python/ql/test/library-tests/PointsTo/new/NameSpace.ql b/python/ql/test/library-tests/PointsTo/new/NameSpace.ql new file mode 100644 index 00000000000..4e30796dc0b --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/NameSpace.ql @@ -0,0 +1,18 @@ +import python +import Util + +from Scope s, string name, Object val +where name != "__name__" and +( + exists(ModuleObject m | + m.getModule() = s and + m.attributeRefersTo(name, val, _) + ) + or + exists(ClassObject cls | + cls.getPyClass() = s and + cls.declaredAttribute(name) = val + ) +) + +select locate(s.getLocation(), "abcdghijklopqrs"), s.toString(), name, repr(val) \ No newline at end of file diff --git a/python/ql/test/library-tests/PointsTo/new/Parameters.expected b/python/ql/test/library-tests/PointsTo/new/Parameters.expected new file mode 100644 index 00000000000..69870516007 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/Parameters.expected @@ -0,0 +1,8 @@ +| g_class_init.py:5 | Essa node definition | true | +| g_class_init.py:9 | Essa node definition | true | +| g_class_init.py:13 | Essa node definition | true | +| g_class_init.py:16 | Essa node definition | true | +| g_class_init.py:34 | Essa node definition | true | +| g_class_init.py:46 | Essa node definition | false | +| g_class_init.py:46 | Essa node definition | true | +| g_class_init.py:52 | Essa node definition | true | diff --git a/python/ql/test/library-tests/PointsTo/new/Parameters.ql b/python/ql/test/library-tests/PointsTo/new/Parameters.ql new file mode 100644 index 00000000000..e3a76f9dc70 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/Parameters.ql @@ -0,0 +1,10 @@ + +import python + +import Util + +from ParameterDefinition param, boolean self +where +if param.isSelf() then self = true else self = false + +select locate(param.getLocation(), "g"), param.toString(), self diff --git a/python/ql/test/library-tests/PointsTo/new/PointsToNone.expected b/python/ql/test/library-tests/PointsTo/new/PointsToNone.expected new file mode 100644 index 00000000000..f5f838edd8a --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/PointsToNone.expected @@ -0,0 +1,98 @@ +| a_simple.py:19 | ControlFlowNode for None | 19 | +| a_simple.py:19 | ControlFlowNode for x | 19 | +| b_condition.py:5 | ControlFlowNode for IfExp | 5 | +| b_condition.py:5 | ControlFlowNode for None | 5 | +| b_condition.py:5 | ControlFlowNode for x | 5 | +| b_condition.py:7 | ControlFlowNode for None | 7 | +| b_condition.py:7 | ControlFlowNode for x | 5 | +| b_condition.py:11 | ControlFlowNode for IfExp | 11 | +| b_condition.py:11 | ControlFlowNode for None | 11 | +| b_condition.py:11 | ControlFlowNode for x | 11 | +| b_condition.py:13 | ControlFlowNode for None | 13 | +| b_condition.py:13 | ControlFlowNode for x | 11 | +| b_condition.py:15 | ControlFlowNode for x | 11 | +| b_condition.py:17 | ControlFlowNode for IfExp | 17 | +| b_condition.py:17 | ControlFlowNode for None | 17 | +| b_condition.py:17 | ControlFlowNode for x | 17 | +| b_condition.py:19 | ControlFlowNode for x | 17 | +| b_condition.py:20 | ControlFlowNode for None | 20 | +| b_condition.py:20 | ControlFlowNode for x | 20 | +| b_condition.py:21 | ControlFlowNode for x | 20 | +| b_condition.py:23 | ControlFlowNode for IfExp | 23 | +| b_condition.py:23 | ControlFlowNode for None | 23 | +| b_condition.py:23 | ControlFlowNode for x | 23 | +| b_condition.py:25 | ControlFlowNode for x | 23 | +| b_condition.py:42 | ControlFlowNode for None | 42 | +| b_condition.py:87 | ControlFlowNode for None | 87 | +| b_condition.py:88 | ControlFlowNode for x | 87 | +| b_condition.py:88 | ControlFlowNode for y | 87 | +| b_condition.py:90 | ControlFlowNode for x | 87 | +| b_condition.py:90 | ControlFlowNode for y | 87 | +| b_condition.py:92 | ControlFlowNode for x | 87 | +| b_condition.py:93 | ControlFlowNode for y | 87 | +| b_condition.py:96 | ControlFlowNode for y | 87 | +| b_condition.py:97 | ControlFlowNode for x | 87 | +| c_tests.py:5 | ControlFlowNode for IfExp | 5 | +| c_tests.py:5 | ControlFlowNode for None | 5 | +| c_tests.py:5 | ControlFlowNode for x | 5 | +| c_tests.py:7 | ControlFlowNode for None | 7 | +| c_tests.py:7 | ControlFlowNode for x | 5 | +| c_tests.py:32 | ControlFlowNode for Attribute | 32 | +| c_tests.py:32 | ControlFlowNode for IfExp | 32 | +| c_tests.py:32 | ControlFlowNode for None | 32 | +| c_tests.py:34 | ControlFlowNode for Attribute | 32 | +| c_tests.py:34 | ControlFlowNode for None | 34 | +| c_tests.py:90 | ControlFlowNode for IfExp | 90 | +| c_tests.py:90 | ControlFlowNode for None | 90 | +| c_tests.py:90 | ControlFlowNode for x | 90 | +| c_tests.py:91 | ControlFlowNode for x | 90 | +| c_tests.py:94 | ControlFlowNode for IfExp | 94 | +| c_tests.py:94 | ControlFlowNode for None | 94 | +| c_tests.py:94 | ControlFlowNode for x | 94 | +| c_tests.py:95 | ControlFlowNode for x | 94 | +| d_globals.py:14 | ControlFlowNode for None | 14 | +| d_globals.py:14 | ControlFlowNode for g1 | 14 | +| d_globals.py:23 | ControlFlowNode for None | 23 | +| d_globals.py:23 | ControlFlowNode for g2 | 23 | +| d_globals.py:29 | ControlFlowNode for init() | 25 | +| d_globals.py:33 | ControlFlowNode for None | 33 | +| d_globals.py:33 | ControlFlowNode for g3 | 33 | +| d_globals.py:66 | ControlFlowNode for g3 | 33 | +| d_globals.py:73 | ControlFlowNode for None | 73 | +| d_globals.py:73 | ControlFlowNode for g4 | 73 | +| d_globals.py:76 | ControlFlowNode for g4 | 73 | +| d_globals.py:77 | ControlFlowNode for set_g4() | 80 | +| d_globals.py:81 | ControlFlowNode for set_g4_indirect() | 83 | +| d_globals.py:128 | ControlFlowNode for Attribute() | 128 | +| g_class_init.py:6 | ControlFlowNode for Attribute() | 9 | +| g_class_init.py:11 | ControlFlowNode for Attribute() | 13 | +| i_imports.py:38 | ControlFlowNode for Attribute() | 24 | +| k_getsetattr.py:7 | ControlFlowNode for setattr() | 7 | +| k_getsetattr.py:8 | ControlFlowNode for setattr() | 8 | +| k_getsetattr.py:13 | ControlFlowNode for setattr() | 13 | +| k_getsetattr.py:14 | ControlFlowNode for setattr() | 14 | +| k_getsetattr.py:15 | ControlFlowNode for Attribute() | 6 | +| l_calls.py:4 | ControlFlowNode for Attribute() | 4 | +| l_calls.py:9 | ControlFlowNode for foo() | 4 | +| m_attributes.py:12 | ControlFlowNode for Attribute() | 8 | +| m_attributes.py:13 | ControlFlowNode for Attribute() | 8 | +| o_no_returns.py:7 | ControlFlowNode for fail() | 10 | +| o_no_returns.py:15 | ControlFlowNode for bar() | 5 | +| o_no_returns.py:21 | ControlFlowNode for bar() | 5 | +| q_super.py:12 | ControlFlowNode for Attribute() | 3 | +| q_super.py:52 | ControlFlowNode for Attribute() | 43 | +| q_super.py:59 | ControlFlowNode for Attribute() | 43 | +| q_super.py:66 | ControlFlowNode for Attribute() | 43 | +| r_regressions.py:9 | ControlFlowNode for Attribute() | 11 | +| r_regressions.py:13 | ControlFlowNode for Attribute | 13 | +| r_regressions.py:13 | ControlFlowNode for None | 13 | +| r_regressions.py:20 | ControlFlowNode for Attribute | 13 | +| r_regressions.py:20 | ControlFlowNode for close | 13 | +| r_regressions.py:21 | ControlFlowNode for close | 13 | +| r_regressions.py:22 | ControlFlowNode for Attribute | 22 | +| r_regressions.py:22 | ControlFlowNode for None | 22 | +| r_regressions.py:27 | ControlFlowNode for None | 27 | +| r_regressions.py:31 | ControlFlowNode for y | 27 | +| r_regressions.py:33 | ControlFlowNode for y | 27 | +| r_regressions.py:52 | ControlFlowNode for fail() | 46 | +| r_regressions.py:73 | ControlFlowNode for setattr() | 73 | diff --git a/python/ql/test/library-tests/PointsTo/new/PointsToNone.ql b/python/ql/test/library-tests/PointsTo/new/PointsToNone.ql new file mode 100644 index 00000000000..3bebd98bff1 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/PointsToNone.ql @@ -0,0 +1,9 @@ +import python +import Util + +from ControlFlowNode f, ControlFlowNode x + +where +f.refersTo(theNoneObject(), _, x) + +select locate(f.getLocation(), "abcdghijklmopqr"), f.toString(), x.getLocation().getStartLine() diff --git a/python/ql/test/library-tests/PointsTo/new/PointsToUnknown.expected b/python/ql/test/library-tests/PointsTo/new/PointsToUnknown.expected new file mode 100644 index 00000000000..0529792ac07 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/PointsToUnknown.expected @@ -0,0 +1,227 @@ +| a_simple.py:15 | ControlFlowNode for t | 14 | +| a_simple.py:16 | ControlFlowNode for d | 14 | +| a_simple.py:20 | ControlFlowNode for seq | 18 | +| a_simple.py:24 | ControlFlowNode for x | 23 | +| a_simple.py:29 | ControlFlowNode for x | 27 | +| a_simple.py:35 | ControlFlowNode for Subscript | 35 | +| a_simple.py:35 | ControlFlowNode for args | 34 | +| a_simple.py:36 | ControlFlowNode for Subscript | 36 | +| a_simple.py:36 | ControlFlowNode for kwargs | 34 | +| b_condition.py:5 | ControlFlowNode for IfExp | 5 | +| b_condition.py:5 | ControlFlowNode for cond | 5 | +| b_condition.py:5 | ControlFlowNode for unknown | 5 | +| b_condition.py:5 | ControlFlowNode for unknown() | 5 | +| b_condition.py:5 | ControlFlowNode for x | 5 | +| b_condition.py:7 | ControlFlowNode for x | 5 | +| b_condition.py:9 | ControlFlowNode for use | 9 | +| b_condition.py:9 | ControlFlowNode for use() | 9 | +| b_condition.py:9 | ControlFlowNode for x | 5 | +| b_condition.py:11 | ControlFlowNode for IfExp | 11 | +| b_condition.py:11 | ControlFlowNode for cond | 11 | +| b_condition.py:11 | ControlFlowNode for unknown | 11 | +| b_condition.py:11 | ControlFlowNode for unknown() | 11 | +| b_condition.py:11 | ControlFlowNode for x | 11 | +| b_condition.py:13 | ControlFlowNode for x | 11 | +| b_condition.py:15 | ControlFlowNode for use | 15 | +| b_condition.py:15 | ControlFlowNode for use() | 15 | +| b_condition.py:15 | ControlFlowNode for x | 11 | +| b_condition.py:17 | ControlFlowNode for IfExp | 17 | +| b_condition.py:17 | ControlFlowNode for cond | 17 | +| b_condition.py:17 | ControlFlowNode for unknown | 17 | +| b_condition.py:17 | ControlFlowNode for unknown() | 17 | +| b_condition.py:17 | ControlFlowNode for x | 17 | +| b_condition.py:19 | ControlFlowNode for x | 17 | +| b_condition.py:21 | ControlFlowNode for use | 21 | +| b_condition.py:21 | ControlFlowNode for use() | 21 | +| b_condition.py:21 | ControlFlowNode for x | 17 | +| b_condition.py:23 | ControlFlowNode for IfExp | 23 | +| b_condition.py:23 | ControlFlowNode for cond | 23 | +| b_condition.py:23 | ControlFlowNode for unknown | 23 | +| b_condition.py:23 | ControlFlowNode for unknown() | 23 | +| b_condition.py:23 | ControlFlowNode for x | 23 | +| b_condition.py:25 | ControlFlowNode for IfExp | 23 | +| b_condition.py:25 | ControlFlowNode for x | 23 | +| b_condition.py:26 | ControlFlowNode for use | 26 | +| b_condition.py:26 | ControlFlowNode for use() | 26 | +| b_condition.py:26 | ControlFlowNode for x | 23 | +| b_condition.py:27 | ControlFlowNode for unknown | 27 | +| b_condition.py:27 | ControlFlowNode for unknown() | 27 | +| b_condition.py:29 | ControlFlowNode for use | 29 | +| b_condition.py:29 | ControlFlowNode for use() | 29 | +| b_condition.py:29 | ControlFlowNode for x | 23 | +| b_condition.py:31 | ControlFlowNode for IfExp | 31 | +| b_condition.py:31 | ControlFlowNode for cond | 31 | +| b_condition.py:31 | ControlFlowNode for unknown | 31 | +| b_condition.py:31 | ControlFlowNode for unknown() | 31 | +| b_condition.py:31 | ControlFlowNode for x | 31 | +| b_condition.py:32 | ControlFlowNode for x | 31 | +| b_condition.py:34 | ControlFlowNode for use | 34 | +| b_condition.py:34 | ControlFlowNode for use() | 34 | +| b_condition.py:34 | ControlFlowNode for x | 31 | +| b_condition.py:36 | ControlFlowNode for x | 31 | +| b_condition.py:37 | ControlFlowNode for use | 37 | +| b_condition.py:37 | ControlFlowNode for use() | 37 | +| b_condition.py:37 | ControlFlowNode for x | 31 | +| b_condition.py:39 | ControlFlowNode for thing | 39 | +| b_condition.py:39 | ControlFlowNode for thing() | 39 | +| b_condition.py:39 | ControlFlowNode for v2 | 39 | +| b_condition.py:41 | ControlFlowNode for Attribute | 39 | +| b_condition.py:41 | ControlFlowNode for v2 | 39 | +| b_condition.py:42 | ControlFlowNode for Attribute | 39 | +| b_condition.py:42 | ControlFlowNode for v2 | 39 | +| b_condition.py:43 | ControlFlowNode for Attribute | 39 | +| b_condition.py:43 | ControlFlowNode for use | 43 | +| b_condition.py:43 | ControlFlowNode for use() | 43 | +| b_condition.py:43 | ControlFlowNode for v2 | 39 | +| b_condition.py:44 | ControlFlowNode for Attribute | 39 | +| b_condition.py:44 | ControlFlowNode for use | 44 | +| b_condition.py:44 | ControlFlowNode for use() | 44 | +| b_condition.py:44 | ControlFlowNode for v2 | 39 | +| b_condition.py:51 | ControlFlowNode for x | 50 | +| b_condition.py:52 | ControlFlowNode for x | 50 | +| b_condition.py:56 | ControlFlowNode for seq | 55 | +| b_condition.py:57 | ControlFlowNode for v | 56 | +| b_condition.py:58 | ControlFlowNode for use | 58 | +| b_condition.py:58 | ControlFlowNode for use() | 58 | +| b_condition.py:58 | ControlFlowNode for v | 56 | +| b_condition.py:62 | ControlFlowNode for Attribute | 61 | +| b_condition.py:62 | ControlFlowNode for x | 61 | +| b_condition.py:64 | ControlFlowNode for y | 61 | +| b_condition.py:65 | ControlFlowNode for Attribute | 61 | +| b_condition.py:65 | ControlFlowNode for x | 61 | +| b_condition.py:66 | ControlFlowNode for Attribute | 61 | +| b_condition.py:66 | ControlFlowNode for seq | 66 | +| b_condition.py:66 | ControlFlowNode for x | 61 | +| b_condition.py:70 | ControlFlowNode for IfExp | 70 | +| b_condition.py:70 | ControlFlowNode for b | 70 | +| b_condition.py:70 | ControlFlowNode for cond | 70 | +| b_condition.py:70 | ControlFlowNode for unknown | 70 | +| b_condition.py:70 | ControlFlowNode for unknown() | 70 | +| b_condition.py:71 | ControlFlowNode for b | 70 | +| b_condition.py:73 | ControlFlowNode for b | 70 | +| b_condition.py:79 | ControlFlowNode for use | 79 | +| b_condition.py:79 | ControlFlowNode for use() | 79 | +| b_condition.py:82 | ControlFlowNode for foo | 81 | +| b_condition.py:88 | ControlFlowNode for x | 87 | +| b_condition.py:88 | ControlFlowNode for y | 87 | +| b_condition.py:90 | ControlFlowNode for x | 87 | +| b_condition.py:90 | ControlFlowNode for y | 87 | +| b_condition.py:93 | ControlFlowNode for use | 93 | +| b_condition.py:93 | ControlFlowNode for use() | 93 | +| b_condition.py:93 | ControlFlowNode for y | 87 | +| b_condition.py:95 | ControlFlowNode for use | 95 | +| b_condition.py:95 | ControlFlowNode for use() | 95 | +| b_condition.py:95 | ControlFlowNode for y | 87 | +| b_condition.py:96 | ControlFlowNode for y | 87 | +| b_condition.py:97 | ControlFlowNode for use | 97 | +| b_condition.py:97 | ControlFlowNode for use() | 97 | +| b_condition.py:99 | ControlFlowNode for use | 99 | +| b_condition.py:99 | ControlFlowNode for use() | 99 | +| b_condition.py:102 | ControlFlowNode for a | 101 | +| b_condition.py:104 | ControlFlowNode for a | 101 | +| b_condition.py:105 | ControlFlowNode for Subscript | 105 | +| b_condition.py:105 | ControlFlowNode for a | 101 | +| c_tests.py:5 | ControlFlowNode for IfExp | 5 | +| c_tests.py:5 | ControlFlowNode for cond | 5 | +| c_tests.py:5 | ControlFlowNode for unknown | 5 | +| c_tests.py:5 | ControlFlowNode for unknown() | 5 | +| c_tests.py:5 | ControlFlowNode for x | 5 | +| c_tests.py:7 | ControlFlowNode for x | 5 | +| c_tests.py:10 | ControlFlowNode for cond | 10 | +| c_tests.py:15 | ControlFlowNode for cond | 15 | +| c_tests.py:21 | ControlFlowNode for cond | 21 | +| c_tests.py:21 | ControlFlowNode for unknown | 21 | +| c_tests.py:21 | ControlFlowNode for unknown() | 21 | +| c_tests.py:32 | ControlFlowNode for Attribute | 4 | +| c_tests.py:32 | ControlFlowNode for Attribute | 32 | +| c_tests.py:32 | ControlFlowNode for IfExp | 32 | +| c_tests.py:32 | ControlFlowNode for cond | 32 | +| c_tests.py:32 | ControlFlowNode for unknown | 32 | +| c_tests.py:32 | ControlFlowNode for unknown() | 32 | +| c_tests.py:32 | ControlFlowNode for y | 4 | +| c_tests.py:34 | ControlFlowNode for Attribute | 4 | +| c_tests.py:34 | ControlFlowNode for Attribute | 32 | +| c_tests.py:34 | ControlFlowNode for y | 4 | +| c_tests.py:37 | ControlFlowNode for Attribute | 4 | +| c_tests.py:37 | ControlFlowNode for cond | 37 | +| c_tests.py:37 | ControlFlowNode for y | 4 | +| c_tests.py:39 | ControlFlowNode for Attribute | 4 | +| c_tests.py:39 | ControlFlowNode for y | 4 | +| c_tests.py:42 | ControlFlowNode for Attribute | 4 | +| c_tests.py:42 | ControlFlowNode for cond | 42 | +| c_tests.py:42 | ControlFlowNode for y | 4 | +| c_tests.py:44 | ControlFlowNode for Attribute | 4 | +| c_tests.py:44 | ControlFlowNode for y | 4 | +| c_tests.py:48 | ControlFlowNode for Attribute | 4 | +| c_tests.py:48 | ControlFlowNode for cond | 48 | +| c_tests.py:48 | ControlFlowNode for unknown | 48 | +| c_tests.py:48 | ControlFlowNode for unknown() | 48 | +| c_tests.py:48 | ControlFlowNode for y | 4 | +| c_tests.py:50 | ControlFlowNode for Attribute | 4 | +| c_tests.py:50 | ControlFlowNode for y | 4 | +| c_tests.py:53 | ControlFlowNode for Attribute | 4 | +| c_tests.py:53 | ControlFlowNode for y | 4 | +| c_tests.py:58 | ControlFlowNode for cond | 58 | +| c_tests.py:63 | ControlFlowNode for cond | 63 | +| c_tests.py:73 | ControlFlowNode for x | 71 | +| c_tests.py:73 | ControlFlowNode for y | 71 | +| c_tests.py:74 | ControlFlowNode for x | 71 | +| c_tests.py:74 | ControlFlowNode for y | 71 | +| c_tests.py:76 | ControlFlowNode for x | 71 | +| c_tests.py:76 | ControlFlowNode for y | 71 | +| c_tests.py:77 | ControlFlowNode for x | 71 | +| c_tests.py:77 | ControlFlowNode for y | 71 | +| c_tests.py:80 | ControlFlowNode for IfExp | 80 | +| c_tests.py:80 | ControlFlowNode for b | 80 | +| c_tests.py:80 | ControlFlowNode for cond | 80 | +| c_tests.py:80 | ControlFlowNode for unknown | 80 | +| c_tests.py:80 | ControlFlowNode for unknown() | 80 | +| c_tests.py:81 | ControlFlowNode for b | 80 | +| c_tests.py:83 | ControlFlowNode for IfExp | 83 | +| c_tests.py:83 | ControlFlowNode for b | 83 | +| c_tests.py:83 | ControlFlowNode for cond | 83 | +| c_tests.py:83 | ControlFlowNode for unknown | 83 | +| c_tests.py:83 | ControlFlowNode for unknown() | 83 | +| c_tests.py:84 | ControlFlowNode for b | 83 | +| c_tests.py:87 | ControlFlowNode for unknown | 87 | +| c_tests.py:87 | ControlFlowNode for unknown() | 87 | +| c_tests.py:90 | ControlFlowNode for IfExp | 90 | +| c_tests.py:90 | ControlFlowNode for cond | 90 | +| c_tests.py:90 | ControlFlowNode for unknown | 90 | +| c_tests.py:90 | ControlFlowNode for unknown() | 90 | +| c_tests.py:90 | ControlFlowNode for x | 90 | +| c_tests.py:91 | ControlFlowNode for x | 90 | +| c_tests.py:94 | ControlFlowNode for IfExp | 94 | +| c_tests.py:94 | ControlFlowNode for cond | 94 | +| c_tests.py:94 | ControlFlowNode for unknown | 94 | +| c_tests.py:94 | ControlFlowNode for unknown() | 94 | +| c_tests.py:94 | ControlFlowNode for x | 94 | +| c_tests.py:95 | ControlFlowNode for x | 94 | +| c_tests.py:99 | ControlFlowNode for bar | 99 | +| c_tests.py:99 | ControlFlowNode for bar() | 99 | +| c_tests.py:99 | ControlFlowNode for foo | 99 | +| c_tests.py:99 | ControlFlowNode for foo() | 99 | +| c_tests.py:99 | ControlFlowNode for x | 98 | +| c_tests.py:100 | ControlFlowNode for use | 100 | +| c_tests.py:100 | ControlFlowNode for use() | 100 | +| c_tests.py:100 | ControlFlowNode for x | 98 | +| h_classes.py:12 | ControlFlowNode for name | 12 | +| h_classes.py:17 | ControlFlowNode for arg | 14 | +| h_classes.py:18 | ControlFlowNode for name | 18 | +| h_classes.py:26 | ControlFlowNode for choice | 25 | +| h_classes.py:28 | ControlFlowNode for choice | 25 | +| h_classes.py:42 | ControlFlowNode for unknown | 42 | +| h_classes.py:42 | ControlFlowNode for unknown() | 42 | +| r_regressions.py:29 | ControlFlowNode for x | 27 | +| r_regressions.py:31 | ControlFlowNode for y | 27 | +| r_regressions.py:33 | ControlFlowNode for y | 27 | +| r_regressions.py:36 | ControlFlowNode for z | 27 | +| r_regressions.py:39 | ControlFlowNode for use | 39 | +| r_regressions.py:39 | ControlFlowNode for use() | 39 | +| r_regressions.py:39 | ControlFlowNode for y | 27 | +| r_regressions.py:43 | ControlFlowNode for List | 43 | +| r_regressions.py:43 | ControlFlowNode for x | 43 | +| r_regressions.py:43 | ControlFlowNode for x() | 43 | +| r_regressions.py:52 | ControlFlowNode for msg | 51 | +| r_regressions.py:64 | ControlFlowNode for do_validation | 64 | +| r_regressions.py:64 | ControlFlowNode for do_validation() | 64 | diff --git a/python/ql/test/library-tests/PointsTo/new/PointsToUnknown.ql b/python/ql/test/library-tests/PointsTo/new/PointsToUnknown.ql new file mode 100644 index 00000000000..e8258bc53a3 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/PointsToUnknown.ql @@ -0,0 +1,9 @@ +import python +import Util +import semmle.python.pointsto.PointsTo + +from ControlFlowNode f, ControlFlowNode x + +where PointsTo::points_to(f, _, unknownValue(), _, x) + +select locate(f.getLocation(), "abchr"), f.toString(), x.getLocation().getStartLine() diff --git a/python/ql/test/library-tests/PointsTo/new/PointsToWithContext.expected b/python/ql/test/library-tests/PointsTo/new/PointsToWithContext.expected new file mode 100755 index 00000000000..80ac9fb72c9 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/PointsToWithContext.expected @@ -0,0 +1,1111 @@ +| a_simple.py:2 | ControlFlowNode for FloatLiteral | float 1.0 | builtin-class float | 2 | import | +| a_simple.py:2 | ControlFlowNode for f1 | float 1.0 | builtin-class float | 2 | import | +| a_simple.py:3 | ControlFlowNode for dict | builtin-class dict | builtin-class type | 3 | import | +| a_simple.py:4 | ControlFlowNode for tuple | builtin-class tuple | builtin-class type | 4 | import | +| a_simple.py:5 | ControlFlowNode for IntegerLiteral | int 0 | builtin-class int | 5 | import | +| a_simple.py:5 | ControlFlowNode for i1 | int 0 | builtin-class int | 5 | import | +| a_simple.py:6 | ControlFlowNode for Tuple | Tuple | builtin-class tuple | 6 | import | +| a_simple.py:6 | ControlFlowNode for s | Tuple | builtin-class tuple | 6 | import | +| a_simple.py:8 | ControlFlowNode for FunctionExpr | Function func | builtin-class function | 8 | import | +| a_simple.py:8 | ControlFlowNode for func | Function func | builtin-class function | 8 | import | +| a_simple.py:11 | ControlFlowNode for C | class C | builtin-class type | 11 | import | +| a_simple.py:11 | ControlFlowNode for ClassExpr | class C | builtin-class type | 11 | import | +| a_simple.py:11 | ControlFlowNode for object | builtin-class object | builtin-class type | 11 | import | +| a_simple.py:14 | ControlFlowNode for FunctionExpr | Function vararg_kwarg | builtin-class function | 14 | import | +| a_simple.py:14 | ControlFlowNode for d | d | builtin-class dict | 14 | runtime | +| a_simple.py:14 | ControlFlowNode for t | t | builtin-class tuple | 14 | runtime | +| a_simple.py:14 | ControlFlowNode for vararg_kwarg | Function vararg_kwarg | builtin-class function | 14 | import | +| a_simple.py:15 | ControlFlowNode for t | t | builtin-class tuple | 14 | runtime | +| a_simple.py:16 | ControlFlowNode for d | d | builtin-class dict | 14 | runtime | +| a_simple.py:18 | ControlFlowNode for FunctionExpr | Function multi_loop | builtin-class function | 18 | import | +| a_simple.py:18 | ControlFlowNode for multi_loop | Function multi_loop | builtin-class function | 18 | import | +| a_simple.py:19 | ControlFlowNode for None | NoneType None | builtin-class NoneType | 19 | runtime | +| a_simple.py:19 | ControlFlowNode for x | NoneType None | builtin-class NoneType | 19 | runtime | +| a_simple.py:20 | ControlFlowNode for Tuple | Tuple | builtin-class tuple | 20 | runtime | +| a_simple.py:23 | ControlFlowNode for FunctionExpr | Function with_definition | builtin-class function | 23 | import | +| a_simple.py:23 | ControlFlowNode for with_definition | Function with_definition | builtin-class function | 23 | import | +| a_simple.py:27 | ControlFlowNode for FunctionExpr | Function multi_loop_in_try | builtin-class function | 27 | import | +| a_simple.py:27 | ControlFlowNode for multi_loop_in_try | Function multi_loop_in_try | builtin-class function | 27 | import | +| a_simple.py:29 | ControlFlowNode for Tuple | Tuple | builtin-class tuple | 29 | runtime | +| a_simple.py:31 | ControlFlowNode for KeyError | builtin-class KeyError | builtin-class type | 31 | runtime | +| a_simple.py:34 | ControlFlowNode for FunctionExpr | Function f | builtin-class function | 34 | import | +| a_simple.py:34 | ControlFlowNode for args | args | builtin-class tuple | 34 | runtime | +| a_simple.py:34 | ControlFlowNode for f | Function f | builtin-class function | 34 | import | +| a_simple.py:34 | ControlFlowNode for kwargs | kwargs | builtin-class dict | 34 | runtime | +| a_simple.py:35 | ControlFlowNode for IntegerLiteral | int 0 | builtin-class int | 35 | runtime | +| a_simple.py:35 | ControlFlowNode for UnaryExpr | bool False | builtin-class bool | 35 | runtime | +| a_simple.py:35 | ControlFlowNode for UnaryExpr | bool True | builtin-class bool | 35 | runtime | +| a_simple.py:35 | ControlFlowNode for args | args | builtin-class tuple | 34 | runtime | +| a_simple.py:36 | ControlFlowNode for Str | 'x' | builtin-class str | 36 | runtime | +| a_simple.py:36 | ControlFlowNode for UnaryExpr | bool False | builtin-class bool | 36 | runtime | +| a_simple.py:36 | ControlFlowNode for UnaryExpr | bool True | builtin-class bool | 36 | runtime | +| a_simple.py:36 | ControlFlowNode for kwargs | kwargs | builtin-class dict | 34 | runtime | +| b_condition.py:4 | ControlFlowNode for FunctionExpr | Function f | builtin-class function | 4 | import | +| b_condition.py:4 | ControlFlowNode for f | Function f | builtin-class function | 4 | import | +| b_condition.py:5 | ControlFlowNode for IfExp | NoneType None | builtin-class NoneType | 5 | runtime | +| b_condition.py:5 | ControlFlowNode for None | NoneType None | builtin-class NoneType | 5 | runtime | +| b_condition.py:5 | ControlFlowNode for x | NoneType None | builtin-class NoneType | 5 | runtime | +| b_condition.py:7 | ControlFlowNode for Compare | bool False | builtin-class bool | 7 | runtime | +| b_condition.py:7 | ControlFlowNode for Compare | bool True | builtin-class bool | 7 | runtime | +| b_condition.py:7 | ControlFlowNode for None | NoneType None | builtin-class NoneType | 7 | runtime | +| b_condition.py:7 | ControlFlowNode for x | NoneType None | builtin-class NoneType | 5 | runtime | +| b_condition.py:8 | ControlFlowNode for IntegerLiteral | int 7 | builtin-class int | 8 | runtime | +| b_condition.py:8 | ControlFlowNode for x | int 7 | builtin-class int | 8 | runtime | +| b_condition.py:9 | ControlFlowNode for x | int 7 | builtin-class int | 8 | runtime | +| b_condition.py:11 | ControlFlowNode for IfExp | NoneType None | builtin-class NoneType | 11 | runtime | +| b_condition.py:11 | ControlFlowNode for None | NoneType None | builtin-class NoneType | 11 | runtime | +| b_condition.py:11 | ControlFlowNode for x | NoneType None | builtin-class NoneType | 11 | runtime | +| b_condition.py:13 | ControlFlowNode for Compare | bool False | builtin-class bool | 13 | runtime | +| b_condition.py:13 | ControlFlowNode for Compare | bool True | builtin-class bool | 13 | runtime | +| b_condition.py:13 | ControlFlowNode for None | NoneType None | builtin-class NoneType | 13 | runtime | +| b_condition.py:13 | ControlFlowNode for x | NoneType None | builtin-class NoneType | 11 | runtime | +| b_condition.py:14 | ControlFlowNode for IntegerLiteral | int 7 | builtin-class int | 14 | runtime | +| b_condition.py:14 | ControlFlowNode for x | int 7 | builtin-class int | 14 | runtime | +| b_condition.py:15 | ControlFlowNode for x | NoneType None | builtin-class NoneType | 11 | runtime | +| b_condition.py:15 | ControlFlowNode for x | int 7 | builtin-class int | 14 | runtime | +| b_condition.py:17 | ControlFlowNode for IfExp | NoneType None | builtin-class NoneType | 17 | runtime | +| b_condition.py:17 | ControlFlowNode for None | NoneType None | builtin-class NoneType | 17 | runtime | +| b_condition.py:17 | ControlFlowNode for x | NoneType None | builtin-class NoneType | 17 | runtime | +| b_condition.py:19 | ControlFlowNode for UnaryExpr | bool False | builtin-class bool | 19 | runtime | +| b_condition.py:19 | ControlFlowNode for UnaryExpr | bool True | builtin-class bool | 19 | runtime | +| b_condition.py:19 | ControlFlowNode for x | NoneType None | builtin-class NoneType | 17 | runtime | +| b_condition.py:20 | ControlFlowNode for None | NoneType None | builtin-class NoneType | 20 | runtime | +| b_condition.py:20 | ControlFlowNode for x | NoneType None | builtin-class NoneType | 20 | runtime | +| b_condition.py:21 | ControlFlowNode for x | NoneType None | builtin-class NoneType | 20 | runtime | +| b_condition.py:23 | ControlFlowNode for IfExp | NoneType None | builtin-class NoneType | 23 | runtime | +| b_condition.py:23 | ControlFlowNode for None | NoneType None | builtin-class NoneType | 23 | runtime | +| b_condition.py:23 | ControlFlowNode for x | NoneType None | builtin-class NoneType | 23 | runtime | +| b_condition.py:25 | ControlFlowNode for IfExp | int 1 | builtin-class int | 25 | runtime | +| b_condition.py:25 | ControlFlowNode for IntegerLiteral | int 1 | builtin-class int | 25 | runtime | +| b_condition.py:25 | ControlFlowNode for x | NoneType None | builtin-class NoneType | 23 | runtime | +| b_condition.py:25 | ControlFlowNode for x | int 1 | builtin-class int | 25 | runtime | +| b_condition.py:26 | ControlFlowNode for x | int 1 | builtin-class int | 25 | runtime | +| b_condition.py:28 | ControlFlowNode for IntegerLiteral | int 1 | builtin-class int | 28 | runtime | +| b_condition.py:28 | ControlFlowNode for x | int 1 | builtin-class int | 28 | runtime | +| b_condition.py:29 | ControlFlowNode for x | int 1 | builtin-class int | 25 | runtime | +| b_condition.py:29 | ControlFlowNode for x | int 1 | builtin-class int | 28 | runtime | +| b_condition.py:31 | ControlFlowNode for IfExp | int 1 | builtin-class int | 31 | runtime | +| b_condition.py:31 | ControlFlowNode for IntegerLiteral | int 1 | builtin-class int | 31 | runtime | +| b_condition.py:31 | ControlFlowNode for x | int 1 | builtin-class int | 31 | runtime | +| b_condition.py:32 | ControlFlowNode for UnaryExpr | bool False | builtin-class bool | 32 | runtime | +| b_condition.py:32 | ControlFlowNode for UnaryExpr | bool True | builtin-class bool | 32 | runtime | +| b_condition.py:32 | ControlFlowNode for x | int 1 | builtin-class int | 31 | runtime | +| b_condition.py:33 | ControlFlowNode for IntegerLiteral | int 7 | builtin-class int | 33 | runtime | +| b_condition.py:33 | ControlFlowNode for x | int 7 | builtin-class int | 33 | runtime | +| b_condition.py:34 | ControlFlowNode for x | int 1 | builtin-class int | 31 | runtime | +| b_condition.py:34 | ControlFlowNode for x | int 7 | builtin-class int | 33 | runtime | +| b_condition.py:36 | ControlFlowNode for int | builtin-class int | builtin-class type | 36 | runtime | +| b_condition.py:36 | ControlFlowNode for isinstance | Builtin-function isinstance | builtin-class builtin_function_or_method | 36 | runtime | +| b_condition.py:36 | ControlFlowNode for isinstance() | bool False | builtin-class bool | 36 | runtime | +| b_condition.py:36 | ControlFlowNode for isinstance() | bool True | builtin-class bool | 36 | runtime | +| b_condition.py:36 | ControlFlowNode for x | int 1 | builtin-class int | 31 | runtime | +| b_condition.py:36 | ControlFlowNode for x | int 7 | builtin-class int | 33 | runtime | +| b_condition.py:37 | ControlFlowNode for x | int 1 | builtin-class int | 31 | runtime | +| b_condition.py:37 | ControlFlowNode for x | int 7 | builtin-class int | 33 | runtime | +| b_condition.py:41 | ControlFlowNode for Attribute | int 1 | builtin-class int | 41 | import | +| b_condition.py:41 | ControlFlowNode for IntegerLiteral | int 1 | builtin-class int | 41 | import | +| b_condition.py:42 | ControlFlowNode for Compare | bool False | builtin-class bool | 42 | import | +| b_condition.py:42 | ControlFlowNode for Compare | bool True | builtin-class bool | 42 | import | +| b_condition.py:42 | ControlFlowNode for None | NoneType None | builtin-class NoneType | 42 | import | +| b_condition.py:43 | ControlFlowNode for Attribute | int 1 | builtin-class int | 41 | import | +| b_condition.py:50 | ControlFlowNode for FunctionExpr | Function g | builtin-class function | 50 | import | +| b_condition.py:50 | ControlFlowNode for g | Function g | builtin-class function | 50 | import | +| b_condition.py:55 | ControlFlowNode for FunctionExpr | Function loop | builtin-class function | 55 | import | +| b_condition.py:55 | ControlFlowNode for loop | Function loop | builtin-class function | 55 | import | +| b_condition.py:61 | ControlFlowNode for FunctionExpr | Function double_attr_check | builtin-class function | 61 | import | +| b_condition.py:61 | ControlFlowNode for double_attr_check | Function double_attr_check | builtin-class function | 61 | import | +| b_condition.py:62 | ControlFlowNode for Compare | bool False | builtin-class bool | 62 | runtime | +| b_condition.py:62 | ControlFlowNode for Compare | bool True | builtin-class bool | 62 | runtime | +| b_condition.py:62 | ControlFlowNode for IntegerLiteral | int 3 | builtin-class int | 62 | runtime | +| b_condition.py:65 | ControlFlowNode for Compare | bool False | builtin-class bool | 65 | runtime | +| b_condition.py:65 | ControlFlowNode for Compare | bool True | builtin-class bool | 65 | runtime | +| b_condition.py:65 | ControlFlowNode for IntegerLiteral | int 0 | builtin-class int | 65 | runtime | +| b_condition.py:66 | ControlFlowNode for Compare | bool False | builtin-class bool | 66 | runtime | +| b_condition.py:66 | ControlFlowNode for Compare | bool True | builtin-class bool | 66 | runtime | +| b_condition.py:69 | ControlFlowNode for FunctionExpr | Function h | builtin-class function | 69 | import | +| b_condition.py:69 | ControlFlowNode for h | Function h | builtin-class function | 69 | import | +| b_condition.py:70 | ControlFlowNode for IfExp | bool True | builtin-class bool | 70 | runtime | +| b_condition.py:70 | ControlFlowNode for True | bool True | builtin-class bool | 70 | runtime | +| b_condition.py:70 | ControlFlowNode for b | bool True | builtin-class bool | 70 | runtime | +| b_condition.py:71 | ControlFlowNode for UnaryExpr | bool False | builtin-class bool | 71 | runtime | +| b_condition.py:71 | ControlFlowNode for UnaryExpr | bool True | builtin-class bool | 71 | runtime | +| b_condition.py:71 | ControlFlowNode for b | bool True | builtin-class bool | 70 | runtime | +| b_condition.py:72 | ControlFlowNode for IntegerLiteral | int 7 | builtin-class int | 72 | runtime | +| b_condition.py:72 | ControlFlowNode for b | int 7 | builtin-class int | 72 | runtime | +| b_condition.py:73 | ControlFlowNode for b | bool True | builtin-class bool | 70 | runtime | +| b_condition.py:73 | ControlFlowNode for b | int 7 | builtin-class int | 72 | runtime | +| b_condition.py:75 | ControlFlowNode for FunctionExpr | Function k | builtin-class function | 75 | import | +| b_condition.py:75 | ControlFlowNode for k | Function k | builtin-class function | 75 | import | +| b_condition.py:76 | ControlFlowNode for t | builtin-class type | builtin-class type | 76 | runtime | +| b_condition.py:76 | ControlFlowNode for type | builtin-class type | builtin-class type | 76 | runtime | +| b_condition.py:77 | ControlFlowNode for Compare | bool True | builtin-class bool | 77 | runtime | +| b_condition.py:77 | ControlFlowNode for object | builtin-class object | builtin-class type | 77 | runtime | +| b_condition.py:77 | ControlFlowNode for t | builtin-class type | builtin-class type | 76 | runtime | +| b_condition.py:78 | ControlFlowNode for object | builtin-class object | builtin-class type | 78 | runtime | +| b_condition.py:78 | ControlFlowNode for t | builtin-class object | builtin-class type | 78 | runtime | +| b_condition.py:79 | ControlFlowNode for t | builtin-class object | builtin-class type | 78 | runtime | +| b_condition.py:81 | ControlFlowNode for FunctionExpr | Function odasa6261 | builtin-class function | 81 | import | +| b_condition.py:81 | ControlFlowNode for True | bool True | builtin-class bool | 81 | import | +| b_condition.py:81 | ControlFlowNode for odasa6261 | Function odasa6261 | builtin-class function | 81 | import | +| b_condition.py:82 | ControlFlowNode for callable | Builtin-function callable | builtin-class builtin_function_or_method | 82 | runtime | +| b_condition.py:82 | ControlFlowNode for callable() | bool False | builtin-class bool | 82 | runtime | +| b_condition.py:82 | ControlFlowNode for callable() | bool True | builtin-class bool | 82 | runtime | +| b_condition.py:82 | ControlFlowNode for foo | bool True | builtin-class bool | 81 | runtime | +| b_condition.py:83 | ControlFlowNode for FunctionExpr | Function bar | builtin-class function | 83 | runtime | +| b_condition.py:83 | ControlFlowNode for bar | Function bar | builtin-class function | 83 | runtime | +| b_condition.py:87 | ControlFlowNode for FunctionExpr | Function split_bool1 | builtin-class function | 87 | import | +| b_condition.py:87 | ControlFlowNode for None | NoneType None | builtin-class NoneType | 87 | import | +| b_condition.py:87 | ControlFlowNode for split_bool1 | Function split_bool1 | builtin-class function | 87 | import | +| b_condition.py:88 | ControlFlowNode for x | NoneType None | builtin-class NoneType | 87 | runtime | +| b_condition.py:88 | ControlFlowNode for y | NoneType None | builtin-class NoneType | 87 | runtime | +| b_condition.py:90 | ControlFlowNode for x | NoneType None | builtin-class NoneType | 87 | runtime | +| b_condition.py:90 | ControlFlowNode for y | NoneType None | builtin-class NoneType | 87 | runtime | +| b_condition.py:92 | ControlFlowNode for x | NoneType None | builtin-class NoneType | 87 | runtime | +| b_condition.py:93 | ControlFlowNode for y | NoneType None | builtin-class NoneType | 87 | runtime | +| b_condition.py:96 | ControlFlowNode for y | NoneType None | builtin-class NoneType | 87 | runtime | +| b_condition.py:97 | ControlFlowNode for x | NoneType None | builtin-class NoneType | 87 | runtime | +| b_condition.py:101 | ControlFlowNode for FunctionExpr | Function not_or_not | builtin-class function | 101 | import | +| b_condition.py:101 | ControlFlowNode for a | a | builtin-class tuple | 101 | runtime | +| b_condition.py:101 | ControlFlowNode for not_or_not | Function not_or_not | builtin-class function | 101 | import | +| b_condition.py:102 | ControlFlowNode for Tuple | Tuple | builtin-class tuple | 102 | runtime | +| b_condition.py:102 | ControlFlowNode for UnaryExpr | bool False | builtin-class bool | 102 | runtime | +| b_condition.py:102 | ControlFlowNode for UnaryExpr | bool True | builtin-class bool | 102 | runtime | +| b_condition.py:102 | ControlFlowNode for a | a | builtin-class tuple | 101 | runtime | +| b_condition.py:102 | ControlFlowNode for isinstance | Builtin-function isinstance | builtin-class builtin_function_or_method | 102 | runtime | +| b_condition.py:102 | ControlFlowNode for isinstance() | bool False | builtin-class bool | 102 | runtime | +| b_condition.py:102 | ControlFlowNode for isinstance() | bool True | builtin-class bool | 102 | runtime | +| b_condition.py:102 | ControlFlowNode for list | builtin-class list | builtin-class type | 102 | runtime | +| b_condition.py:102 | ControlFlowNode for tuple | builtin-class tuple | builtin-class type | 102 | runtime | +| b_condition.py:103 | ControlFlowNode for TypeError | builtin-class TypeError | builtin-class type | 103 | runtime | +| b_condition.py:103 | ControlFlowNode for TypeError() | TypeError() | builtin-class TypeError | 103 | runtime | +| b_condition.py:104 | ControlFlowNode for UnaryExpr | bool False | builtin-class bool | 104 | runtime | +| b_condition.py:104 | ControlFlowNode for UnaryExpr | bool True | builtin-class bool | 104 | runtime | +| b_condition.py:104 | ControlFlowNode for a | a | builtin-class tuple | 101 | runtime | +| b_condition.py:105 | ControlFlowNode for IntegerLiteral | int 0 | builtin-class int | 105 | runtime | +| b_condition.py:105 | ControlFlowNode for UnaryExpr | bool False | builtin-class bool | 105 | runtime | +| b_condition.py:105 | ControlFlowNode for UnaryExpr | bool True | builtin-class bool | 105 | runtime | +| b_condition.py:105 | ControlFlowNode for a | a | builtin-class tuple | 101 | runtime | +| b_condition.py:106 | ControlFlowNode for Exception | builtin-class Exception | builtin-class type | 106 | runtime | +| b_condition.py:106 | ControlFlowNode for Exception() | Exception() | builtin-class Exception | 106 | runtime | +| b_condition.py:107 | ControlFlowNode for Str | 'Hello' | builtin-class str | 107 | runtime | +| e_temporal.py:2 | ControlFlowNode for ImportExpr | Module sys | builtin-class module | 2 | import | +| e_temporal.py:2 | ControlFlowNode for sys | Module sys | builtin-class module | 2 | import | +| e_temporal.py:4 | ControlFlowNode for FunctionExpr | Function f | builtin-class function | 4 | import | +| e_temporal.py:4 | ControlFlowNode for f | Function f | builtin-class function | 4 | import | +| e_temporal.py:5 | ControlFlowNode for Attribute | list object | builtin-class list | 5 | code/e_temporal.py:12 from import | +| e_temporal.py:5 | ControlFlowNode for Attribute | list object | builtin-class list | 5 | runtime | +| e_temporal.py:5 | ControlFlowNode for Compare | bool False | builtin-class bool | 5 | code/e_temporal.py:12 from import | +| e_temporal.py:5 | ControlFlowNode for Compare | bool False | builtin-class bool | 5 | runtime | +| e_temporal.py:5 | ControlFlowNode for Compare | bool True | builtin-class bool | 5 | code/e_temporal.py:12 from import | +| e_temporal.py:5 | ControlFlowNode for Compare | bool True | builtin-class bool | 5 | runtime | +| e_temporal.py:5 | ControlFlowNode for IntegerLiteral | int 3 | builtin-class int | 5 | code/e_temporal.py:12 from import | +| e_temporal.py:5 | ControlFlowNode for IntegerLiteral | int 3 | builtin-class int | 5 | runtime | +| e_temporal.py:5 | ControlFlowNode for len | Builtin-function len | builtin-class builtin_function_or_method | 5 | code/e_temporal.py:12 from import | +| e_temporal.py:5 | ControlFlowNode for len | Builtin-function len | builtin-class builtin_function_or_method | 5 | runtime | +| e_temporal.py:5 | ControlFlowNode for len() | len() | builtin-class int | 5 | code/e_temporal.py:12 from import | +| e_temporal.py:5 | ControlFlowNode for len() | len() | builtin-class int | 5 | runtime | +| e_temporal.py:5 | ControlFlowNode for sys | Module sys | builtin-class module | 2 | code/e_temporal.py:12 from import | +| e_temporal.py:5 | ControlFlowNode for sys | Module sys | builtin-class module | 2 | runtime | +| e_temporal.py:7 | ControlFlowNode for IntegerLiteral | int 1 | builtin-class int | 7 | code/e_temporal.py:12 from import | +| e_temporal.py:7 | ControlFlowNode for IntegerLiteral | int 1 | builtin-class int | 7 | runtime | +| e_temporal.py:9 | ControlFlowNode for FunctionExpr | Function g | builtin-class function | 9 | import | +| e_temporal.py:9 | ControlFlowNode for g | Function g | builtin-class function | 9 | import | +| e_temporal.py:10 | ControlFlowNode for arg | int 1 | builtin-class int | 7 | code/e_temporal.py:12 from import | +| e_temporal.py:12 | ControlFlowNode for f | Function f | builtin-class function | 4 | import | +| e_temporal.py:12 | ControlFlowNode for f() | int 1 | builtin-class int | 7 | import | +| e_temporal.py:12 | ControlFlowNode for g | Function g | builtin-class function | 9 | import | +| e_temporal.py:12 | ControlFlowNode for g() | int 1 | builtin-class int | 7 | import | +| e_temporal.py:12 | ControlFlowNode for x | int 1 | builtin-class int | 7 | import | +| g_class_init.py:3 | ControlFlowNode for C | class C | builtin-class type | 3 | import | +| g_class_init.py:3 | ControlFlowNode for ClassExpr | class C | builtin-class type | 3 | import | +| g_class_init.py:3 | ControlFlowNode for object | builtin-class object | builtin-class type | 3 | import | +| g_class_init.py:5 | ControlFlowNode for FunctionExpr | Function __init__ | builtin-class function | 5 | import | +| g_class_init.py:5 | ControlFlowNode for __init__ | Function __init__ | builtin-class function | 5 | import | +| g_class_init.py:6 | ControlFlowNode for Attribute() | NoneType None | builtin-class NoneType | 9 | runtime | +| g_class_init.py:6 | ControlFlowNode for self | self | class C | 5 | runtime | +| g_class_init.py:7 | ControlFlowNode for Attribute | int 1 | builtin-class int | 7 | runtime | +| g_class_init.py:7 | ControlFlowNode for IntegerLiteral | int 1 | builtin-class int | 7 | runtime | +| g_class_init.py:7 | ControlFlowNode for self | self | class C | 5 | runtime | +| g_class_init.py:9 | ControlFlowNode for FunctionExpr | Function _init | builtin-class function | 9 | import | +| g_class_init.py:9 | ControlFlowNode for _init | Function _init | builtin-class function | 9 | import | +| g_class_init.py:10 | ControlFlowNode for Attribute | int 2 | builtin-class int | 10 | code/g_class_init.py:6 from runtime | +| g_class_init.py:10 | ControlFlowNode for IntegerLiteral | int 2 | builtin-class int | 10 | code/g_class_init.py:6 from runtime | +| g_class_init.py:10 | ControlFlowNode for self | self | class C | 5 | code/g_class_init.py:6 from runtime | +| g_class_init.py:11 | ControlFlowNode for Attribute() | NoneType None | builtin-class NoneType | 13 | code/g_class_init.py:6 from runtime | +| g_class_init.py:11 | ControlFlowNode for self | self | class C | 5 | code/g_class_init.py:6 from runtime | +| g_class_init.py:13 | ControlFlowNode for FunctionExpr | Function _init2 | builtin-class function | 13 | import | +| g_class_init.py:13 | ControlFlowNode for _init2 | Function _init2 | builtin-class function | 13 | import | +| g_class_init.py:14 | ControlFlowNode for Attribute | int 3 | builtin-class int | 14 | code/g_class_init.py:11 from code/g_class_init.py:6 from runtime | +| g_class_init.py:14 | ControlFlowNode for IntegerLiteral | int 3 | builtin-class int | 14 | code/g_class_init.py:11 from code/g_class_init.py:6 from runtime | +| g_class_init.py:14 | ControlFlowNode for self | self | class C | 5 | code/g_class_init.py:11 from code/g_class_init.py:6 from runtime | +| g_class_init.py:16 | ControlFlowNode for FunctionExpr | Function method | builtin-class function | 16 | import | +| g_class_init.py:16 | ControlFlowNode for method | Function method | builtin-class function | 16 | import | +| g_class_init.py:17 | ControlFlowNode for Attribute | int 1 | builtin-class int | 7 | runtime | +| g_class_init.py:17 | ControlFlowNode for self | self | class C | 16 | runtime | +| g_class_init.py:18 | ControlFlowNode for Attribute | int 2 | builtin-class int | 10 | runtime | +| g_class_init.py:18 | ControlFlowNode for int | builtin-class int | builtin-class type | 18 | runtime | +| g_class_init.py:18 | ControlFlowNode for isinstance | Builtin-function isinstance | builtin-class builtin_function_or_method | 18 | runtime | +| g_class_init.py:18 | ControlFlowNode for isinstance() | bool True | builtin-class bool | 18 | runtime | +| g_class_init.py:18 | ControlFlowNode for self | self | class C | 16 | runtime | +| g_class_init.py:19 | ControlFlowNode for Attribute | int 2 | builtin-class int | 10 | runtime | +| g_class_init.py:19 | ControlFlowNode for self | self | class C | 16 | runtime | +| g_class_init.py:20 | ControlFlowNode for Attribute | int 3 | builtin-class int | 14 | runtime | +| g_class_init.py:20 | ControlFlowNode for self | self | class C | 16 | runtime | +| g_class_init.py:24 | ControlFlowNode for ClassExpr | class Oddities | builtin-class type | 24 | import | +| g_class_init.py:24 | ControlFlowNode for Oddities | class Oddities | builtin-class type | 24 | import | +| g_class_init.py:24 | ControlFlowNode for object | builtin-class object | builtin-class type | 24 | import | +| g_class_init.py:26 | ControlFlowNode for int | builtin-class int | builtin-class type | 26 | import | +| g_class_init.py:27 | ControlFlowNode for float | builtin-class float | builtin-class type | 27 | import | +| g_class_init.py:28 | ControlFlowNode for l | Builtin-function len | builtin-class builtin_function_or_method | 28 | import | +| g_class_init.py:28 | ControlFlowNode for len | Builtin-function len | builtin-class builtin_function_or_method | 28 | import | +| g_class_init.py:29 | ControlFlowNode for h | Builtin-function hash | builtin-class builtin_function_or_method | 29 | import | +| g_class_init.py:29 | ControlFlowNode for hash | Builtin-function hash | builtin-class builtin_function_or_method | 29 | import | +| g_class_init.py:32 | ControlFlowNode for ClassExpr | class D | builtin-class type | 32 | import | +| g_class_init.py:32 | ControlFlowNode for D | class D | builtin-class type | 32 | import | +| g_class_init.py:32 | ControlFlowNode for object | builtin-class object | builtin-class type | 32 | import | +| g_class_init.py:34 | ControlFlowNode for FunctionExpr | Function __init__ | builtin-class function | 34 | import | +| g_class_init.py:34 | ControlFlowNode for __init__ | Function __init__ | builtin-class function | 34 | import | +| g_class_init.py:35 | ControlFlowNode for Attribute | super().x | builtin-class method | 35 | runtime | +| g_class_init.py:35 | ControlFlowNode for D | class D | builtin-class type | 32 | runtime | +| g_class_init.py:35 | ControlFlowNode for self | self | class D | 34 | runtime | +| g_class_init.py:35 | ControlFlowNode for super | builtin-class super | builtin-class type | 35 | runtime | +| g_class_init.py:35 | ControlFlowNode for super() | super() | builtin-class super | 35 | runtime | +| g_class_init.py:36 | ControlFlowNode for Attribute | super().__init__ | builtin-class method | 36 | runtime | +| g_class_init.py:36 | ControlFlowNode for D | class D | builtin-class type | 32 | runtime | +| g_class_init.py:36 | ControlFlowNode for self | self | class D | 34 | runtime | +| g_class_init.py:36 | ControlFlowNode for super | builtin-class super | builtin-class type | 36 | runtime | +| g_class_init.py:36 | ControlFlowNode for super() | super() | builtin-class super | 36 | runtime | +| g_class_init.py:42 | ControlFlowNode for Str | 'v2' | builtin-class str | 42 | import | +| g_class_init.py:42 | ControlFlowNode for V2 | 'v2' | builtin-class str | 42 | import | +| g_class_init.py:43 | ControlFlowNode for Str | 'v3' | builtin-class str | 43 | import | +| g_class_init.py:43 | ControlFlowNode for V3 | 'v3' | builtin-class str | 43 | import | +| g_class_init.py:45 | ControlFlowNode for ClassExpr | class E | builtin-class type | 45 | import | +| g_class_init.py:45 | ControlFlowNode for E | class E | builtin-class type | 45 | import | +| g_class_init.py:45 | ControlFlowNode for object | builtin-class object | builtin-class type | 45 | import | +| g_class_init.py:46 | ControlFlowNode for FunctionExpr | Function __init__ | builtin-class function | 46 | import | +| g_class_init.py:46 | ControlFlowNode for __init__ | Function __init__ | builtin-class function | 46 | import | +| g_class_init.py:48 | ControlFlowNode for Attribute | 'v2' | builtin-class str | 42 | runtime | +| g_class_init.py:48 | ControlFlowNode for V2 | 'v2' | builtin-class str | 42 | runtime | +| g_class_init.py:48 | ControlFlowNode for self | self | class E | 46 | runtime | +| g_class_init.py:50 | ControlFlowNode for Attribute | 'v3' | builtin-class str | 43 | runtime | +| g_class_init.py:50 | ControlFlowNode for V3 | 'v3' | builtin-class str | 43 | runtime | +| g_class_init.py:50 | ControlFlowNode for self | self | class E | 46 | runtime | +| g_class_init.py:52 | ControlFlowNode for FunctionExpr | Function meth | builtin-class function | 52 | import | +| g_class_init.py:52 | ControlFlowNode for meth | Function meth | builtin-class function | 52 | import | +| g_class_init.py:53 | ControlFlowNode for Attribute | 'v2' | builtin-class str | 42 | runtime | +| g_class_init.py:53 | ControlFlowNode for Attribute | 'v3' | builtin-class str | 43 | runtime | +| g_class_init.py:53 | ControlFlowNode for Compare | bool False | builtin-class bool | 53 | runtime | +| g_class_init.py:53 | ControlFlowNode for Compare | bool True | builtin-class bool | 53 | runtime | +| g_class_init.py:53 | ControlFlowNode for V2 | 'v2' | builtin-class str | 42 | runtime | +| g_class_init.py:53 | ControlFlowNode for self | self | class E | 52 | runtime | +| h_classes.py:1 | ControlFlowNode for ImportExpr | Module sys | builtin-class module | 1 | import | +| h_classes.py:1 | ControlFlowNode for sys | Module sys | builtin-class module | 1 | import | +| h_classes.py:3 | ControlFlowNode for C | class C | builtin-class type | 3 | import | +| h_classes.py:3 | ControlFlowNode for ClassExpr | class C | builtin-class type | 3 | import | +| h_classes.py:3 | ControlFlowNode for object | builtin-class object | builtin-class type | 3 | import | +| h_classes.py:5 | ControlFlowNode for Str | 'C_x' | builtin-class str | 5 | import | +| h_classes.py:5 | ControlFlowNode for x | 'C_x' | builtin-class str | 5 | import | +| h_classes.py:7 | ControlFlowNode for FunctionExpr | Function __init__ | builtin-class function | 7 | import | +| h_classes.py:7 | ControlFlowNode for __init__ | Function __init__ | builtin-class function | 7 | import | +| h_classes.py:8 | ControlFlowNode for Attribute | 'c_y' | builtin-class str | 8 | code/h_classes.py:10 from import | +| h_classes.py:8 | ControlFlowNode for Attribute | 'c_y' | builtin-class str | 8 | code/h_classes.py:15 from runtime | +| h_classes.py:8 | ControlFlowNode for Attribute | 'c_y' | builtin-class str | 8 | runtime | +| h_classes.py:8 | ControlFlowNode for Str | 'c_y' | builtin-class str | 8 | code/h_classes.py:10 from import | +| h_classes.py:8 | ControlFlowNode for Str | 'c_y' | builtin-class str | 8 | code/h_classes.py:15 from runtime | +| h_classes.py:8 | ControlFlowNode for Str | 'c_y' | builtin-class str | 8 | runtime | +| h_classes.py:8 | ControlFlowNode for self | self | class C | 7 | runtime | +| h_classes.py:10 | ControlFlowNode for C | class C | builtin-class type | 3 | import | +| h_classes.py:10 | ControlFlowNode for C() | C() | class C | 10 | import | +| h_classes.py:10 | ControlFlowNode for type | builtin-class type | builtin-class type | 10 | import | +| h_classes.py:10 | ControlFlowNode for type() | class C | builtin-class type | 3 | import | +| h_classes.py:11 | ControlFlowNode for sys | Module sys | builtin-class module | 1 | import | +| h_classes.py:11 | ControlFlowNode for type | builtin-class type | builtin-class type | 11 | import | +| h_classes.py:11 | ControlFlowNode for type() | builtin-class module | builtin-class type | 11 | import | +| h_classes.py:12 | ControlFlowNode for Dict | Dict | builtin-class dict | 12 | import | +| h_classes.py:12 | ControlFlowNode for Tuple | Tuple | builtin-class tuple | 12 | import | +| h_classes.py:12 | ControlFlowNode for object | builtin-class object | builtin-class type | 12 | import | +| h_classes.py:12 | ControlFlowNode for type | builtin-class type | builtin-class type | 12 | import | +| h_classes.py:14 | ControlFlowNode for FunctionExpr | Function k | builtin-class function | 14 | import | +| h_classes.py:14 | ControlFlowNode for k | Function k | builtin-class function | 14 | import | +| h_classes.py:15 | ControlFlowNode for C | class C | builtin-class type | 3 | runtime | +| h_classes.py:15 | ControlFlowNode for C() | C() | class C | 15 | runtime | +| h_classes.py:15 | ControlFlowNode for type | builtin-class type | builtin-class type | 15 | runtime | +| h_classes.py:15 | ControlFlowNode for type() | class C | builtin-class type | 3 | runtime | +| h_classes.py:16 | ControlFlowNode for sys | Module sys | builtin-class module | 1 | runtime | +| h_classes.py:16 | ControlFlowNode for type | builtin-class type | builtin-class type | 16 | runtime | +| h_classes.py:16 | ControlFlowNode for type() | builtin-class module | builtin-class type | 16 | runtime | +| h_classes.py:17 | ControlFlowNode for type | builtin-class type | builtin-class type | 17 | runtime | +| h_classes.py:17 | ControlFlowNode for type() | *UNKNOWN TYPE* | builtin-class type | 17 | runtime | +| h_classes.py:18 | ControlFlowNode for Dict | Dict | builtin-class dict | 18 | runtime | +| h_classes.py:18 | ControlFlowNode for Tuple | Tuple | builtin-class tuple | 18 | runtime | +| h_classes.py:18 | ControlFlowNode for object | builtin-class object | builtin-class type | 18 | runtime | +| h_classes.py:18 | ControlFlowNode for type | builtin-class type | builtin-class type | 18 | runtime | +| h_classes.py:23 | ControlFlowNode for Base | class Base | builtin-class type | 23 | import | +| h_classes.py:23 | ControlFlowNode for ClassExpr | class Base | builtin-class type | 23 | import | +| h_classes.py:23 | ControlFlowNode for object | builtin-class object | builtin-class type | 23 | import | +| h_classes.py:25 | ControlFlowNode for FunctionExpr | Function __init__ | builtin-class function | 25 | import | +| h_classes.py:25 | ControlFlowNode for __init__ | Function __init__ | builtin-class function | 25 | import | +| h_classes.py:26 | ControlFlowNode for Compare | bool False | builtin-class bool | 26 | runtime | +| h_classes.py:26 | ControlFlowNode for Compare | bool True | builtin-class bool | 26 | runtime | +| h_classes.py:26 | ControlFlowNode for IntegerLiteral | int 1 | builtin-class int | 26 | runtime | +| h_classes.py:27 | ControlFlowNode for Attribute | class Derived1 | builtin-class type | 33 | runtime | +| h_classes.py:27 | ControlFlowNode for Derived1 | class Derived1 | builtin-class type | 33 | runtime | +| h_classes.py:27 | ControlFlowNode for self | self | class Base | 25 | runtime | +| h_classes.py:28 | ControlFlowNode for Compare | bool False | builtin-class bool | 28 | runtime | +| h_classes.py:28 | ControlFlowNode for Compare | bool True | builtin-class bool | 28 | runtime | +| h_classes.py:28 | ControlFlowNode for IntegerLiteral | int 2 | builtin-class int | 28 | runtime | +| h_classes.py:29 | ControlFlowNode for Attribute | class Derived2 | builtin-class type | 36 | runtime | +| h_classes.py:29 | ControlFlowNode for Derived2 | class Derived2 | builtin-class type | 36 | runtime | +| h_classes.py:29 | ControlFlowNode for self | self | class Base | 25 | runtime | +| h_classes.py:31 | ControlFlowNode for Attribute | class Derived3 | builtin-class type | 39 | runtime | +| h_classes.py:31 | ControlFlowNode for Derived3 | class Derived3 | builtin-class type | 39 | runtime | +| h_classes.py:31 | ControlFlowNode for self | self | class Base | 25 | runtime | +| h_classes.py:33 | ControlFlowNode for Base | class Base | builtin-class type | 23 | import | +| h_classes.py:33 | ControlFlowNode for ClassExpr | class Derived1 | builtin-class type | 33 | import | +| h_classes.py:33 | ControlFlowNode for Derived1 | class Derived1 | builtin-class type | 33 | import | +| h_classes.py:36 | ControlFlowNode for Base | class Base | builtin-class type | 23 | import | +| h_classes.py:36 | ControlFlowNode for ClassExpr | class Derived2 | builtin-class type | 36 | import | +| h_classes.py:36 | ControlFlowNode for Derived2 | class Derived2 | builtin-class type | 36 | import | +| h_classes.py:39 | ControlFlowNode for Base | class Base | builtin-class type | 23 | import | +| h_classes.py:39 | ControlFlowNode for ClassExpr | class Derived3 | builtin-class type | 39 | import | +| h_classes.py:39 | ControlFlowNode for Derived3 | class Derived3 | builtin-class type | 39 | import | +| h_classes.py:42 | ControlFlowNode for Base | class Base | builtin-class type | 23 | import | +| h_classes.py:45 | ControlFlowNode for FunctionExpr | Function f | builtin-class function | 45 | import | +| h_classes.py:45 | ControlFlowNode for f | Function f | builtin-class function | 45 | import | +| h_classes.py:48 | ControlFlowNode for ClassExpr | class D | builtin-class type | 48 | import | +| h_classes.py:48 | ControlFlowNode for D | class D | builtin-class type | 48 | import | +| h_classes.py:48 | ControlFlowNode for object | builtin-class object | builtin-class type | 48 | import | +| h_classes.py:50 | ControlFlowNode for f | Function f | builtin-class function | 45 | import | +| h_classes.py:50 | ControlFlowNode for m | Function f | builtin-class function | 45 | import | +| h_classes.py:52 | ControlFlowNode for FunctionExpr | Function n | builtin-class function | 52 | import | +| h_classes.py:52 | ControlFlowNode for n | Function n | builtin-class function | 52 | import | +| i_imports.py:3 | ControlFlowNode for IntegerLiteral | int 1 | builtin-class int | 3 | import | +| i_imports.py:3 | ControlFlowNode for a | int 1 | builtin-class int | 3 | import | +| i_imports.py:4 | ControlFlowNode for IntegerLiteral | int 2 | builtin-class int | 4 | import | +| i_imports.py:4 | ControlFlowNode for b | int 2 | builtin-class int | 4 | import | +| i_imports.py:5 | ControlFlowNode for IntegerLiteral | int 3 | builtin-class int | 5 | import | +| i_imports.py:5 | ControlFlowNode for c | int 3 | builtin-class int | 5 | import | +| i_imports.py:7 | ControlFlowNode for ImportExpr | Module code.xyz | builtin-class module | 7 | import | +| i_imports.py:8 | ControlFlowNode for ImportExpr | Module code | builtin-class module | 8 | import | +| i_imports.py:8 | ControlFlowNode for ImportMember | Module code.xyz | builtin-class module | 0 | import | +| i_imports.py:8 | ControlFlowNode for xyz | Module code.xyz | builtin-class module | 0 | import | +| i_imports.py:9 | ControlFlowNode for Attribute | float 1.0 | builtin-class float | 2 | import | +| i_imports.py:9 | ControlFlowNode for xyz | Module code.xyz | builtin-class module | 0 | import | +| i_imports.py:10 | ControlFlowNode for z | float 3.0 | builtin-class float | 4 | import | +| i_imports.py:11 | ControlFlowNode for a | int 1 | builtin-class int | 3 | import | +| i_imports.py:13 | ControlFlowNode for ImportExpr | Module sys | builtin-class module | 13 | import | +| i_imports.py:13 | ControlFlowNode for ImportMember | list object | builtin-class list | 13 | import | +| i_imports.py:13 | ControlFlowNode for argv | list object | builtin-class list | 13 | import | +| i_imports.py:15 | ControlFlowNode for argv | list object | builtin-class list | 13 | import | +| i_imports.py:17 | ControlFlowNode for ImportExpr | Module sys | builtin-class module | 17 | import | +| i_imports.py:17 | ControlFlowNode for sys | Module sys | builtin-class module | 17 | import | +| i_imports.py:18 | ControlFlowNode for Attribute | list object | builtin-class list | 18 | import | +| i_imports.py:18 | ControlFlowNode for sys | Module sys | builtin-class module | 17 | import | +| i_imports.py:23 | ControlFlowNode for ImportExpr | Module code | builtin-class module | 23 | import | +| i_imports.py:23 | ControlFlowNode for code | Module code | builtin-class module | 23 | import | +| i_imports.py:24 | ControlFlowNode for Attribute | Module code.package.x | builtin-class module | 0 | import | +| i_imports.py:24 | ControlFlowNode for code | Module code | builtin-class module | 23 | import | +| i_imports.py:27 | ControlFlowNode for ImportExpr | Module code.test_package | builtin-class module | 27 | import | +| i_imports.py:29 | ControlFlowNode for ImportExpr | Module _io | builtin-class module | 29 | import | +| i_imports.py:29 | ControlFlowNode for _io | Module _io | builtin-class module | 29 | import | +| i_imports.py:30 | ControlFlowNode for Attribute | builtin-class _io.StringIO | builtin-class type | 30 | import | +| i_imports.py:30 | ControlFlowNode for StringIO | builtin-class _io.StringIO | builtin-class type | 30 | import | +| i_imports.py:30 | ControlFlowNode for _io | Module _io | builtin-class module | 29 | import | +| i_imports.py:31 | ControlFlowNode for Attribute | builtin-class _io.BytesIO | builtin-class type | 31 | import | +| i_imports.py:31 | ControlFlowNode for BytesIO | builtin-class _io.BytesIO | builtin-class type | 31 | import | +| i_imports.py:31 | ControlFlowNode for _io | Module _io | builtin-class module | 29 | import | +| i_imports.py:33 | ControlFlowNode for ImportExpr | Module io | builtin-class module | 33 | import | +| i_imports.py:33 | ControlFlowNode for io | Module io | builtin-class module | 33 | import | +| i_imports.py:34 | ControlFlowNode for Attribute | builtin-class _io.StringIO | builtin-class type | 55 | import | +| i_imports.py:34 | ControlFlowNode for StringIO | builtin-class _io.StringIO | builtin-class type | 55 | import | +| i_imports.py:34 | ControlFlowNode for io | Module io | builtin-class module | 33 | import | +| i_imports.py:35 | ControlFlowNode for Attribute | builtin-class _io.BytesIO | builtin-class type | 55 | import | +| i_imports.py:35 | ControlFlowNode for BytesIO | builtin-class _io.BytesIO | builtin-class type | 55 | import | +| i_imports.py:35 | ControlFlowNode for io | Module io | builtin-class module | 33 | import | +| i_imports.py:37 | ControlFlowNode for ImportExpr | Module code | builtin-class module | 37 | import | +| i_imports.py:37 | ControlFlowNode for code | Module code | builtin-class module | 37 | import | +| i_imports.py:38 | ControlFlowNode for Attribute | Function f2 | builtin-class function | 24 | import | +| i_imports.py:38 | ControlFlowNode for Attribute | Module code.n_nesting | builtin-class module | 0 | import | +| i_imports.py:38 | ControlFlowNode for Attribute() | NoneType None | builtin-class NoneType | 24 | import | +| i_imports.py:38 | ControlFlowNode for code | Module code | builtin-class module | 37 | import | +| j_convoluted_imports.py:2 | ControlFlowNode for ImportExpr | Module code.package | builtin-class module | 2 | import | +| j_convoluted_imports.py:3 | ControlFlowNode for ImportMember | Function module | builtin-class function | 2 | import | +| j_convoluted_imports.py:3 | ControlFlowNode for module | Function module | builtin-class function | 2 | import | +| j_convoluted_imports.py:5 | ControlFlowNode for ImportExpr | Module code.package | builtin-class module | 5 | import | +| j_convoluted_imports.py:6 | ControlFlowNode for ImportMember | Module code.package.x | builtin-class module | 0 | import | +| j_convoluted_imports.py:6 | ControlFlowNode for x | Module code.package.x | builtin-class module | 0 | import | +| j_convoluted_imports.py:9 | ControlFlowNode for C | class C | builtin-class type | 9 | import | +| j_convoluted_imports.py:9 | ControlFlowNode for ClassExpr | class C | builtin-class type | 9 | import | +| j_convoluted_imports.py:9 | ControlFlowNode for object | builtin-class object | builtin-class type | 9 | import | +| j_convoluted_imports.py:11 | ControlFlowNode for ImportExpr | Module code.package | builtin-class module | 11 | import | +| j_convoluted_imports.py:11 | ControlFlowNode for ImportMember | int 7 | builtin-class int | 5 | import | +| j_convoluted_imports.py:11 | ControlFlowNode for module2 | int 7 | builtin-class int | 5 | import | +| j_convoluted_imports.py:13 | ControlFlowNode for FunctionExpr | Function f | builtin-class function | 13 | import | +| j_convoluted_imports.py:13 | ControlFlowNode for f | Function f | builtin-class function | 13 | import | +| j_convoluted_imports.py:14 | ControlFlowNode for ImportExpr | Module code.package | builtin-class module | 14 | runtime | +| j_convoluted_imports.py:14 | ControlFlowNode for ImportMember | Module code.package.x | builtin-class module | 0 | runtime | +| j_convoluted_imports.py:14 | ControlFlowNode for x | Module code.package.x | builtin-class module | 0 | runtime | +| j_convoluted_imports.py:16 | ControlFlowNode for ImportExpr | Module code.package | builtin-class module | 16 | import | +| j_convoluted_imports.py:16 | ControlFlowNode for ImportMember | Module code.package.moduleX | builtin-class module | 0 | import | +| j_convoluted_imports.py:16 | ControlFlowNode for moduleX | Module code.package.moduleX | builtin-class module | 0 | import | +| j_convoluted_imports.py:17 | ControlFlowNode for Attribute | class Y | builtin-class type | 1 | import | +| j_convoluted_imports.py:17 | ControlFlowNode for moduleX | Module code.package.moduleX | builtin-class module | 0 | import | +| k_getsetattr.py:4 | ControlFlowNode for C | class C | builtin-class type | 4 | import | +| k_getsetattr.py:4 | ControlFlowNode for ClassExpr | class C | builtin-class type | 4 | import | +| k_getsetattr.py:4 | ControlFlowNode for object | builtin-class object | builtin-class type | 4 | import | +| k_getsetattr.py:6 | ControlFlowNode for FunctionExpr | Function meth1 | builtin-class function | 6 | import | +| k_getsetattr.py:6 | ControlFlowNode for meth1 | Function meth1 | builtin-class function | 6 | import | +| k_getsetattr.py:7 | ControlFlowNode for IntegerLiteral | int 0 | builtin-class int | 7 | code/k_getsetattr.py:15 from runtime | +| k_getsetattr.py:7 | ControlFlowNode for IntegerLiteral | int 0 | builtin-class int | 7 | runtime | +| k_getsetattr.py:7 | ControlFlowNode for Str | 'a' | builtin-class str | 7 | code/k_getsetattr.py:15 from runtime | +| k_getsetattr.py:7 | ControlFlowNode for Str | 'a' | builtin-class str | 7 | runtime | +| k_getsetattr.py:7 | ControlFlowNode for self | self | class C | 6 | runtime | +| k_getsetattr.py:7 | ControlFlowNode for self | self | class C | 12 | code/k_getsetattr.py:15 from runtime | +| k_getsetattr.py:7 | ControlFlowNode for setattr | Builtin-function setattr | builtin-class builtin_function_or_method | 7 | code/k_getsetattr.py:15 from runtime | +| k_getsetattr.py:7 | ControlFlowNode for setattr | Builtin-function setattr | builtin-class builtin_function_or_method | 7 | runtime | +| k_getsetattr.py:7 | ControlFlowNode for setattr() | NoneType None | builtin-class NoneType | 7 | code/k_getsetattr.py:15 from runtime | +| k_getsetattr.py:7 | ControlFlowNode for setattr() | NoneType None | builtin-class NoneType | 7 | runtime | +| k_getsetattr.py:8 | ControlFlowNode for IntegerLiteral | int 1 | builtin-class int | 8 | code/k_getsetattr.py:15 from runtime | +| k_getsetattr.py:8 | ControlFlowNode for IntegerLiteral | int 1 | builtin-class int | 8 | runtime | +| k_getsetattr.py:8 | ControlFlowNode for Str | 'b' | builtin-class str | 8 | code/k_getsetattr.py:15 from runtime | +| k_getsetattr.py:8 | ControlFlowNode for Str | 'b' | builtin-class str | 8 | runtime | +| k_getsetattr.py:8 | ControlFlowNode for self | self | class C | 6 | runtime | +| k_getsetattr.py:8 | ControlFlowNode for self | self | class C | 12 | code/k_getsetattr.py:15 from runtime | +| k_getsetattr.py:8 | ControlFlowNode for setattr | Builtin-function setattr | builtin-class builtin_function_or_method | 8 | code/k_getsetattr.py:15 from runtime | +| k_getsetattr.py:8 | ControlFlowNode for setattr | Builtin-function setattr | builtin-class builtin_function_or_method | 8 | runtime | +| k_getsetattr.py:8 | ControlFlowNode for setattr() | NoneType None | builtin-class NoneType | 8 | code/k_getsetattr.py:15 from runtime | +| k_getsetattr.py:8 | ControlFlowNode for setattr() | NoneType None | builtin-class NoneType | 8 | runtime | +| k_getsetattr.py:9 | ControlFlowNode for Str | 'a' | builtin-class str | 9 | code/k_getsetattr.py:15 from runtime | +| k_getsetattr.py:9 | ControlFlowNode for Str | 'a' | builtin-class str | 9 | runtime | +| k_getsetattr.py:9 | ControlFlowNode for getattr | Builtin-function getattr | builtin-class builtin_function_or_method | 9 | code/k_getsetattr.py:15 from runtime | +| k_getsetattr.py:9 | ControlFlowNode for getattr | Builtin-function getattr | builtin-class builtin_function_or_method | 9 | runtime | +| k_getsetattr.py:9 | ControlFlowNode for getattr() | int 0 | builtin-class int | 7 | code/k_getsetattr.py:15 from runtime | +| k_getsetattr.py:9 | ControlFlowNode for getattr() | int 0 | builtin-class int | 7 | runtime | +| k_getsetattr.py:9 | ControlFlowNode for self | self | class C | 6 | runtime | +| k_getsetattr.py:9 | ControlFlowNode for self | self | class C | 12 | code/k_getsetattr.py:15 from runtime | +| k_getsetattr.py:10 | ControlFlowNode for Str | 'c' | builtin-class str | 10 | code/k_getsetattr.py:15 from runtime | +| k_getsetattr.py:10 | ControlFlowNode for Str | 'c' | builtin-class str | 10 | runtime | +| k_getsetattr.py:10 | ControlFlowNode for getattr | Builtin-function getattr | builtin-class builtin_function_or_method | 10 | code/k_getsetattr.py:15 from runtime | +| k_getsetattr.py:10 | ControlFlowNode for getattr | Builtin-function getattr | builtin-class builtin_function_or_method | 10 | runtime | +| k_getsetattr.py:10 | ControlFlowNode for getattr() | int 2 | builtin-class int | 14 | code/k_getsetattr.py:15 from runtime | +| k_getsetattr.py:10 | ControlFlowNode for self | self | class C | 6 | runtime | +| k_getsetattr.py:10 | ControlFlowNode for self | self | class C | 12 | code/k_getsetattr.py:15 from runtime | +| k_getsetattr.py:12 | ControlFlowNode for FunctionExpr | Function meth2 | builtin-class function | 12 | import | +| k_getsetattr.py:12 | ControlFlowNode for meth2 | Function meth2 | builtin-class function | 12 | import | +| k_getsetattr.py:13 | ControlFlowNode for FloatLiteral | float 7.0 | builtin-class float | 13 | runtime | +| k_getsetattr.py:13 | ControlFlowNode for Str | 'a' | builtin-class str | 13 | runtime | +| k_getsetattr.py:13 | ControlFlowNode for self | self | class C | 12 | runtime | +| k_getsetattr.py:13 | ControlFlowNode for setattr | Builtin-function setattr | builtin-class builtin_function_or_method | 13 | runtime | +| k_getsetattr.py:13 | ControlFlowNode for setattr() | NoneType None | builtin-class NoneType | 13 | runtime | +| k_getsetattr.py:14 | ControlFlowNode for IntegerLiteral | int 2 | builtin-class int | 14 | runtime | +| k_getsetattr.py:14 | ControlFlowNode for Str | 'c' | builtin-class str | 14 | runtime | +| k_getsetattr.py:14 | ControlFlowNode for self | self | class C | 12 | runtime | +| k_getsetattr.py:14 | ControlFlowNode for setattr | Builtin-function setattr | builtin-class builtin_function_or_method | 14 | runtime | +| k_getsetattr.py:14 | ControlFlowNode for setattr() | NoneType None | builtin-class NoneType | 14 | runtime | +| k_getsetattr.py:15 | ControlFlowNode for Attribute() | NoneType None | builtin-class NoneType | 6 | runtime | +| k_getsetattr.py:15 | ControlFlowNode for self | self | class C | 12 | runtime | +| k_getsetattr.py:16 | ControlFlowNode for Str | 'a' | builtin-class str | 16 | runtime | +| k_getsetattr.py:16 | ControlFlowNode for getattr | Builtin-function getattr | builtin-class builtin_function_or_method | 16 | runtime | +| k_getsetattr.py:16 | ControlFlowNode for getattr() | int 0 | builtin-class int | 7 | runtime | +| k_getsetattr.py:16 | ControlFlowNode for self | self | class C | 12 | runtime | +| k_getsetattr.py:17 | ControlFlowNode for Str | 'b' | builtin-class str | 17 | runtime | +| k_getsetattr.py:17 | ControlFlowNode for getattr | Builtin-function getattr | builtin-class builtin_function_or_method | 17 | runtime | +| k_getsetattr.py:17 | ControlFlowNode for getattr() | int 1 | builtin-class int | 8 | runtime | +| k_getsetattr.py:17 | ControlFlowNode for self | self | class C | 12 | runtime | +| k_getsetattr.py:18 | ControlFlowNode for Str | 'c' | builtin-class str | 18 | runtime | +| k_getsetattr.py:18 | ControlFlowNode for getattr | Builtin-function getattr | builtin-class builtin_function_or_method | 18 | runtime | +| k_getsetattr.py:18 | ControlFlowNode for getattr() | int 2 | builtin-class int | 14 | runtime | +| k_getsetattr.py:18 | ControlFlowNode for self | self | class C | 12 | runtime | +| k_getsetattr.py:21 | ControlFlowNode for FunctionExpr | Function k | builtin-class function | 21 | import | +| k_getsetattr.py:21 | ControlFlowNode for k | Function k | builtin-class function | 21 | import | +| k_getsetattr.py:22 | ControlFlowNode for C | class C | builtin-class type | 4 | runtime | +| k_getsetattr.py:22 | ControlFlowNode for C() | C() | class C | 22 | runtime | +| k_getsetattr.py:22 | ControlFlowNode for c1 | C() | class C | 22 | runtime | +| k_getsetattr.py:23 | ControlFlowNode for C | class C | builtin-class type | 4 | runtime | +| k_getsetattr.py:23 | ControlFlowNode for C() | C() | class C | 23 | runtime | +| k_getsetattr.py:23 | ControlFlowNode for c2 | C() | class C | 23 | runtime | +| k_getsetattr.py:24 | ControlFlowNode for C | class C | builtin-class type | 4 | runtime | +| k_getsetattr.py:24 | ControlFlowNode for C() | C() | class C | 24 | runtime | +| k_getsetattr.py:24 | ControlFlowNode for c3 | C() | class C | 24 | runtime | +| k_getsetattr.py:25 | ControlFlowNode for Attribute | int 10 | builtin-class int | 25 | runtime | +| k_getsetattr.py:25 | ControlFlowNode for IntegerLiteral | int 10 | builtin-class int | 25 | runtime | +| k_getsetattr.py:25 | ControlFlowNode for c1 | C() | class C | 22 | runtime | +| k_getsetattr.py:27 | ControlFlowNode for Attribute | int 20 | builtin-class int | 27 | runtime | +| k_getsetattr.py:27 | ControlFlowNode for IntegerLiteral | int 20 | builtin-class int | 27 | runtime | +| k_getsetattr.py:27 | ControlFlowNode for c2 | C() | class C | 23 | runtime | +| k_getsetattr.py:28 | ControlFlowNode for Attribute | int 10 | builtin-class int | 25 | runtime | +| k_getsetattr.py:28 | ControlFlowNode for c1 | C() | class C | 22 | runtime | +| k_getsetattr.py:29 | ControlFlowNode for Attribute | int 20 | builtin-class int | 27 | runtime | +| k_getsetattr.py:29 | ControlFlowNode for c2 | C() | class C | 23 | runtime | +| k_getsetattr.py:30 | ControlFlowNode for c3 | C() | class C | 24 | runtime | +| k_getsetattr.py:31 | ControlFlowNode for Attribute | int 30 | builtin-class int | 31 | runtime | +| k_getsetattr.py:31 | ControlFlowNode for IntegerLiteral | int 30 | builtin-class int | 31 | runtime | +| k_getsetattr.py:31 | ControlFlowNode for c3 | C() | class C | 24 | runtime | +| l_calls.py:3 | ControlFlowNode for FunctionExpr | Function foo | builtin-class function | 3 | import | +| l_calls.py:3 | ControlFlowNode for List | List | builtin-class list | 3 | import | +| l_calls.py:3 | ControlFlowNode for foo | Function foo | builtin-class function | 3 | import | +| l_calls.py:4 | ControlFlowNode for Attribute() | NoneType None | builtin-class NoneType | 4 | code/l_calls.py:9 from import | +| l_calls.py:4 | ControlFlowNode for Attribute() | NoneType None | builtin-class NoneType | 4 | runtime | +| l_calls.py:4 | ControlFlowNode for Str | 'x' | builtin-class str | 4 | code/l_calls.py:9 from import | +| l_calls.py:4 | ControlFlowNode for Str | 'x' | builtin-class str | 4 | runtime | +| l_calls.py:4 | ControlFlowNode for x | List | builtin-class list | 3 | code/l_calls.py:9 from import | +| l_calls.py:4 | ControlFlowNode for x | List | builtin-class list | 3 | runtime | +| l_calls.py:6 | ControlFlowNode for FunctionExpr | Function bar | builtin-class function | 6 | import | +| l_calls.py:6 | ControlFlowNode for List | List | builtin-class list | 6 | import | +| l_calls.py:6 | ControlFlowNode for bar | Function bar | builtin-class function | 6 | import | +| l_calls.py:7 | ControlFlowNode for len | Builtin-function len | builtin-class builtin_function_or_method | 7 | code/l_calls.py:10 from import | +| l_calls.py:7 | ControlFlowNode for len | Builtin-function len | builtin-class builtin_function_or_method | 7 | runtime | +| l_calls.py:7 | ControlFlowNode for len() | len() | builtin-class int | 7 | code/l_calls.py:10 from import | +| l_calls.py:7 | ControlFlowNode for len() | len() | builtin-class int | 7 | runtime | +| l_calls.py:7 | ControlFlowNode for x | List | builtin-class list | 6 | code/l_calls.py:10 from import | +| l_calls.py:7 | ControlFlowNode for x | List | builtin-class list | 6 | runtime | +| l_calls.py:9 | ControlFlowNode for foo | Function foo | builtin-class function | 3 | import | +| l_calls.py:9 | ControlFlowNode for foo() | NoneType None | builtin-class NoneType | 4 | import | +| l_calls.py:10 | ControlFlowNode for bar | Function bar | builtin-class function | 6 | import | +| l_calls.py:10 | ControlFlowNode for bar() | len() | builtin-class int | 7 | import | +| l_calls.py:12 | ControlFlowNode for ClassExpr | class Owner | builtin-class type | 12 | import | +| l_calls.py:12 | ControlFlowNode for Owner | class Owner | builtin-class type | 12 | import | +| l_calls.py:12 | ControlFlowNode for object | builtin-class object | builtin-class type | 12 | import | +| l_calls.py:14 | ControlFlowNode for classmethod | builtin-class classmethod | builtin-class type | 14 | import | +| l_calls.py:14 | ControlFlowNode for classmethod() | classmethod() | builtin-class classmethod | 14 | import | +| l_calls.py:15 | ControlFlowNode for FunctionExpr | Function cm | builtin-class function | 15 | import | +| l_calls.py:15 | ControlFlowNode for cm | classmethod() | builtin-class classmethod | 14 | import | +| l_calls.py:16 | ControlFlowNode for cls | class Owner | builtin-class type | 23 | code/l_calls.py:24 from runtime | +| l_calls.py:18 | ControlFlowNode for classmethod | builtin-class classmethod | builtin-class type | 18 | import | +| l_calls.py:18 | ControlFlowNode for classmethod() | classmethod() | builtin-class classmethod | 18 | import | +| l_calls.py:19 | ControlFlowNode for FunctionExpr | Function cm2 | builtin-class function | 19 | import | +| l_calls.py:19 | ControlFlowNode for cm2 | classmethod() | builtin-class classmethod | 18 | import | +| l_calls.py:20 | ControlFlowNode for arg | int 1 | builtin-class int | 25 | code/l_calls.py:25 from runtime | +| l_calls.py:23 | ControlFlowNode for FunctionExpr | Function m | builtin-class function | 23 | import | +| l_calls.py:23 | ControlFlowNode for m | Function m | builtin-class function | 23 | import | +| l_calls.py:24 | ControlFlowNode for Attribute() | class Owner | builtin-class type | 23 | runtime | +| l_calls.py:24 | ControlFlowNode for IntegerLiteral | int 0 | builtin-class int | 24 | runtime | +| l_calls.py:24 | ControlFlowNode for a | class Owner | builtin-class type | 23 | runtime | +| l_calls.py:24 | ControlFlowNode for self | self | class Owner | 23 | runtime | +| l_calls.py:25 | ControlFlowNode for Attribute() | int 1 | builtin-class int | 25 | runtime | +| l_calls.py:25 | ControlFlowNode for IntegerLiteral | int 1 | builtin-class int | 25 | runtime | +| l_calls.py:25 | ControlFlowNode for a | class Owner | builtin-class type | 23 | runtime | +| m_attributes.py:3 | ControlFlowNode for C | class C | builtin-class type | 3 | import | +| m_attributes.py:3 | ControlFlowNode for ClassExpr | class C | builtin-class type | 3 | import | +| m_attributes.py:3 | ControlFlowNode for object | builtin-class object | builtin-class type | 3 | import | +| m_attributes.py:5 | ControlFlowNode for FunctionExpr | Function __init__ | builtin-class function | 5 | import | +| m_attributes.py:5 | ControlFlowNode for IntegerLiteral | int 17 | builtin-class int | 5 | import | +| m_attributes.py:5 | ControlFlowNode for __init__ | Function __init__ | builtin-class function | 5 | import | +| m_attributes.py:6 | ControlFlowNode for Attribute | int 17 | builtin-class int | 5 | runtime | +| m_attributes.py:6 | ControlFlowNode for Attribute | int 100 | builtin-class int | 13 | code/m_attributes.py:13 from import | +| m_attributes.py:6 | ControlFlowNode for a | int 17 | builtin-class int | 5 | runtime | +| m_attributes.py:6 | ControlFlowNode for a | int 100 | builtin-class int | 13 | code/m_attributes.py:13 from import | +| m_attributes.py:6 | ControlFlowNode for self | self | class C | 5 | runtime | +| m_attributes.py:8 | ControlFlowNode for FunctionExpr | Function foo | builtin-class function | 8 | import | +| m_attributes.py:8 | ControlFlowNode for foo | Function foo | builtin-class function | 8 | import | +| m_attributes.py:9 | ControlFlowNode for Attribute | int 17 | builtin-class int | 5 | runtime | +| m_attributes.py:9 | ControlFlowNode for self | self | class C | 8 | runtime | +| m_attributes.py:10 | ControlFlowNode for other | C() | class C | 12 | code/m_attributes.py:12 from import | +| m_attributes.py:10 | ControlFlowNode for other | C() | class C | 13 | code/m_attributes.py:13 from import | +| m_attributes.py:12 | ControlFlowNode for Attribute() | NoneType None | builtin-class NoneType | 8 | import | +| m_attributes.py:12 | ControlFlowNode for C | class C | builtin-class type | 3 | import | +| m_attributes.py:12 | ControlFlowNode for C() | C() | class C | 12 | import | +| m_attributes.py:13 | ControlFlowNode for Attribute() | NoneType None | builtin-class NoneType | 8 | import | +| m_attributes.py:13 | ControlFlowNode for C | class C | builtin-class type | 3 | import | +| m_attributes.py:13 | ControlFlowNode for C() | C() | class C | 13 | import | +| m_attributes.py:13 | ControlFlowNode for IntegerLiteral | int 100 | builtin-class int | 13 | import | +| n_nesting.py:8 | ControlFlowNode for FunctionExpr | Function foo | builtin-class function | 8 | import | +| n_nesting.py:8 | ControlFlowNode for True | bool True | builtin-class bool | 8 | import | +| n_nesting.py:8 | ControlFlowNode for foo | Function foo | builtin-class function | 8 | import | +| n_nesting.py:9 | ControlFlowNode for callable | Builtin-function callable | builtin-class builtin_function_or_method | 9 | runtime | +| n_nesting.py:9 | ControlFlowNode for callable() | bool False | builtin-class bool | 9 | runtime | +| n_nesting.py:9 | ControlFlowNode for callable() | bool True | builtin-class bool | 9 | runtime | +| n_nesting.py:9 | ControlFlowNode for compile_ops | bool True | builtin-class bool | 8 | runtime | +| n_nesting.py:10 | ControlFlowNode for FunctionExpr | Function inner | builtin-class function | 10 | runtime | +| n_nesting.py:10 | ControlFlowNode for inner | Function inner | builtin-class function | 10 | runtime | +| n_nesting.py:13 | ControlFlowNode for FunctionExpr | Function inner | builtin-class function | 13 | runtime | +| n_nesting.py:13 | ControlFlowNode for inner | Function inner | builtin-class function | 13 | runtime | +| n_nesting.py:15 | ControlFlowNode for Dict | Dict | builtin-class dict | 15 | runtime | +| n_nesting.py:15 | ControlFlowNode for attrs | Dict | builtin-class dict | 15 | runtime | +| n_nesting.py:16 | ControlFlowNode for Str | 'inner' | builtin-class str | 16 | runtime | +| n_nesting.py:16 | ControlFlowNode for inner | Function inner | builtin-class function | 10 | runtime | +| n_nesting.py:16 | ControlFlowNode for inner | Function inner | builtin-class function | 13 | runtime | +| n_nesting.py:18 | ControlFlowNode for attrs | Dict | builtin-class dict | 15 | runtime | +| n_nesting.py:22 | ControlFlowNode for FunctionExpr | Function f1 | builtin-class function | 22 | import | +| n_nesting.py:22 | ControlFlowNode for f1 | Function f1 | builtin-class function | 22 | import | +| n_nesting.py:23 | ControlFlowNode for Attribute | int 1 | builtin-class int | 23 | code/n_nesting.py:25 from code/i_imports.py:38 from import | +| n_nesting.py:23 | ControlFlowNode for Attribute | int 1 | builtin-class int | 23 | code/n_nesting.py:25 from code/n_nesting.py:27 from code/n_nesting.py:29 from runtime | +| n_nesting.py:23 | ControlFlowNode for Attribute | int 1 | builtin-class int | 23 | code/n_nesting.py:25 from code/n_nesting.py:27 from runtime | +| n_nesting.py:23 | ControlFlowNode for Attribute | int 1 | builtin-class int | 23 | code/n_nesting.py:25 from runtime | +| n_nesting.py:23 | ControlFlowNode for Attribute | int 1 | builtin-class int | 23 | runtime | +| n_nesting.py:23 | ControlFlowNode for C | int 1 | builtin-class int | 34 | code/n_nesting.py:25 from code/i_imports.py:38 from import | +| n_nesting.py:23 | ControlFlowNode for C | int 1 | builtin-class int | 34 | code/n_nesting.py:25 from code/n_nesting.py:27 from code/n_nesting.py:29 from runtime | +| n_nesting.py:23 | ControlFlowNode for C | int 1 | builtin-class int | 34 | code/n_nesting.py:25 from code/n_nesting.py:27 from runtime | +| n_nesting.py:23 | ControlFlowNode for C | int 1 | builtin-class int | 34 | code/n_nesting.py:25 from runtime | +| n_nesting.py:23 | ControlFlowNode for C | int 1 | builtin-class int | 34 | runtime | +| n_nesting.py:23 | ControlFlowNode for IntegerLiteral | int 1 | builtin-class int | 23 | code/n_nesting.py:25 from code/i_imports.py:38 from import | +| n_nesting.py:23 | ControlFlowNode for IntegerLiteral | int 1 | builtin-class int | 23 | code/n_nesting.py:25 from code/n_nesting.py:27 from code/n_nesting.py:29 from runtime | +| n_nesting.py:23 | ControlFlowNode for IntegerLiteral | int 1 | builtin-class int | 23 | code/n_nesting.py:25 from code/n_nesting.py:27 from runtime | +| n_nesting.py:23 | ControlFlowNode for IntegerLiteral | int 1 | builtin-class int | 23 | code/n_nesting.py:25 from runtime | +| n_nesting.py:23 | ControlFlowNode for IntegerLiteral | int 1 | builtin-class int | 23 | runtime | +| n_nesting.py:24 | ControlFlowNode for FunctionExpr | Function f2 | builtin-class function | 24 | import | +| n_nesting.py:24 | ControlFlowNode for f2 | Function f2 | builtin-class function | 24 | import | +| n_nesting.py:25 | ControlFlowNode for f1 | Function f1 | builtin-class function | 22 | code/i_imports.py:38 from import | +| n_nesting.py:25 | ControlFlowNode for f1 | Function f1 | builtin-class function | 22 | code/n_nesting.py:27 from code/n_nesting.py:29 from code/n_nesting.py:31 from import | +| n_nesting.py:25 | ControlFlowNode for f1 | Function f1 | builtin-class function | 22 | code/n_nesting.py:27 from code/n_nesting.py:29 from runtime | +| n_nesting.py:25 | ControlFlowNode for f1 | Function f1 | builtin-class function | 22 | code/n_nesting.py:27 from runtime | +| n_nesting.py:25 | ControlFlowNode for f1 | Function f1 | builtin-class function | 22 | runtime | +| n_nesting.py:25 | ControlFlowNode for f1() | NoneType None | builtin-class NoneType | 22 | code/i_imports.py:38 from import | +| n_nesting.py:25 | ControlFlowNode for f1() | NoneType None | builtin-class NoneType | 22 | code/n_nesting.py:27 from code/n_nesting.py:29 from code/n_nesting.py:31 from import | +| n_nesting.py:25 | ControlFlowNode for f1() | NoneType None | builtin-class NoneType | 22 | code/n_nesting.py:27 from code/n_nesting.py:29 from runtime | +| n_nesting.py:25 | ControlFlowNode for f1() | NoneType None | builtin-class NoneType | 22 | code/n_nesting.py:27 from runtime | +| n_nesting.py:25 | ControlFlowNode for f1() | NoneType None | builtin-class NoneType | 22 | runtime | +| n_nesting.py:26 | ControlFlowNode for FunctionExpr | Function f3 | builtin-class function | 26 | import | +| n_nesting.py:26 | ControlFlowNode for f3 | Function f3 | builtin-class function | 26 | import | +| n_nesting.py:27 | ControlFlowNode for f2 | Function f2 | builtin-class function | 24 | code/n_nesting.py:29 from code/n_nesting.py:31 from import | +| n_nesting.py:27 | ControlFlowNode for f2 | Function f2 | builtin-class function | 24 | code/n_nesting.py:29 from runtime | +| n_nesting.py:27 | ControlFlowNode for f2 | Function f2 | builtin-class function | 24 | runtime | +| n_nesting.py:27 | ControlFlowNode for f2() | NoneType None | builtin-class NoneType | 24 | code/n_nesting.py:29 from code/n_nesting.py:31 from import | +| n_nesting.py:27 | ControlFlowNode for f2() | NoneType None | builtin-class NoneType | 24 | code/n_nesting.py:29 from runtime | +| n_nesting.py:27 | ControlFlowNode for f2() | NoneType None | builtin-class NoneType | 24 | runtime | +| n_nesting.py:28 | ControlFlowNode for FunctionExpr | Function f4 | builtin-class function | 28 | import | +| n_nesting.py:28 | ControlFlowNode for f4 | Function f4 | builtin-class function | 28 | import | +| n_nesting.py:29 | ControlFlowNode for f3 | Function f3 | builtin-class function | 26 | code/n_nesting.py:31 from import | +| n_nesting.py:29 | ControlFlowNode for f3 | Function f3 | builtin-class function | 26 | runtime | +| n_nesting.py:29 | ControlFlowNode for f3() | NoneType None | builtin-class NoneType | 26 | code/n_nesting.py:31 from import | +| n_nesting.py:29 | ControlFlowNode for f3() | NoneType None | builtin-class NoneType | 26 | runtime | +| n_nesting.py:30 | ControlFlowNode for C | class C | builtin-class type | 30 | import | +| n_nesting.py:30 | ControlFlowNode for ClassExpr | class C | builtin-class type | 30 | import | +| n_nesting.py:30 | ControlFlowNode for object | builtin-class object | builtin-class type | 30 | import | +| n_nesting.py:31 | ControlFlowNode for f4 | Function f4 | builtin-class function | 28 | import | +| n_nesting.py:31 | ControlFlowNode for f4() | NoneType None | builtin-class NoneType | 28 | import | +| n_nesting.py:32 | ControlFlowNode for C | class C | builtin-class type | 30 | import | +| n_nesting.py:32 | ControlFlowNode for ClassExpr | class D | builtin-class type | 32 | import | +| n_nesting.py:32 | ControlFlowNode for D | class D | builtin-class type | 32 | import | +| n_nesting.py:34 | ControlFlowNode for C | int 1 | builtin-class int | 34 | import | +| n_nesting.py:34 | ControlFlowNode for IntegerLiteral | int 1 | builtin-class int | 34 | import | +| p_decorators.py:3 | ControlFlowNode for FunctionExpr | Function simple | builtin-class function | 3 | import | +| p_decorators.py:3 | ControlFlowNode for simple | Function simple | builtin-class function | 3 | import | +| p_decorators.py:4 | ControlFlowNode for Attribute | 'Hello' | builtin-class str | 4 | code/p_decorators.py:7 from import | +| p_decorators.py:4 | ControlFlowNode for Attribute | 'Hello' | builtin-class str | 4 | runtime | +| p_decorators.py:4 | ControlFlowNode for Str | 'Hello' | builtin-class str | 4 | code/p_decorators.py:7 from import | +| p_decorators.py:4 | ControlFlowNode for Str | 'Hello' | builtin-class str | 4 | runtime | +| p_decorators.py:4 | ControlFlowNode for func | Function foo | builtin-class function | 8 | code/p_decorators.py:7 from import | +| p_decorators.py:5 | ControlFlowNode for func | Function foo | builtin-class function | 8 | code/p_decorators.py:7 from import | +| p_decorators.py:7 | ControlFlowNode for simple | Function simple | builtin-class function | 3 | import | +| p_decorators.py:7 | ControlFlowNode for simple() | Function foo | builtin-class function | 8 | import | +| p_decorators.py:8 | ControlFlowNode for FunctionExpr | Function foo | builtin-class function | 8 | import | +| p_decorators.py:8 | ControlFlowNode for foo | Function foo | builtin-class function | 8 | import | +| p_decorators.py:11 | ControlFlowNode for FunctionExpr | Function complex | builtin-class function | 11 | import | +| p_decorators.py:11 | ControlFlowNode for complex | Function complex | builtin-class function | 11 | import | +| p_decorators.py:12 | ControlFlowNode for FunctionExpr | Function annotate | builtin-class function | 12 | code/p_decorators.py:17 from import | +| p_decorators.py:12 | ControlFlowNode for FunctionExpr | Function annotate | builtin-class function | 12 | runtime | +| p_decorators.py:12 | ControlFlowNode for annotate | Function annotate | builtin-class function | 12 | code/p_decorators.py:17 from import | +| p_decorators.py:12 | ControlFlowNode for annotate | Function annotate | builtin-class function | 12 | runtime | +| p_decorators.py:13 | ControlFlowNode for func | Function bar | builtin-class function | 18 | code/p_decorators.py:17 from import | +| p_decorators.py:14 | ControlFlowNode for func | Function bar | builtin-class function | 18 | code/p_decorators.py:17 from import | +| p_decorators.py:15 | ControlFlowNode for annotate | Function annotate | builtin-class function | 12 | code/p_decorators.py:17 from import | +| p_decorators.py:15 | ControlFlowNode for annotate | Function annotate | builtin-class function | 12 | runtime | +| p_decorators.py:17 | ControlFlowNode for Str | 'Hi' | builtin-class str | 17 | import | +| p_decorators.py:17 | ControlFlowNode for complex | Function complex | builtin-class function | 11 | import | +| p_decorators.py:17 | ControlFlowNode for complex() | Function annotate | builtin-class function | 12 | import | +| p_decorators.py:17 | ControlFlowNode for complex()() | Function bar | builtin-class function | 18 | import | +| p_decorators.py:18 | ControlFlowNode for FunctionExpr | Function bar | builtin-class function | 18 | import | +| p_decorators.py:18 | ControlFlowNode for bar | Function bar | builtin-class function | 18 | import | +| p_decorators.py:21 | ControlFlowNode for foo | Function foo | builtin-class function | 8 | import | +| p_decorators.py:22 | ControlFlowNode for bar | Function bar | builtin-class function | 18 | import | +| p_decorators.py:24 | ControlFlowNode for C | class C | builtin-class type | 24 | import | +| p_decorators.py:24 | ControlFlowNode for ClassExpr | class C | builtin-class type | 24 | import | +| p_decorators.py:24 | ControlFlowNode for object | builtin-class object | builtin-class type | 24 | import | +| p_decorators.py:26 | ControlFlowNode for staticmethod | builtin-class staticmethod | builtin-class type | 26 | import | +| p_decorators.py:26 | ControlFlowNode for staticmethod() | staticmethod() | builtin-class staticmethod | 26 | import | +| p_decorators.py:27 | ControlFlowNode for FunctionExpr | Function smeth | builtin-class function | 27 | import | +| p_decorators.py:27 | ControlFlowNode for smeth | staticmethod() | builtin-class staticmethod | 26 | import | +| p_decorators.py:31 | ControlFlowNode for classmethod | builtin-class classmethod | builtin-class type | 31 | import | +| p_decorators.py:31 | ControlFlowNode for classmethod() | classmethod() | builtin-class classmethod | 31 | import | +| p_decorators.py:32 | ControlFlowNode for FunctionExpr | Function cmeth | builtin-class function | 32 | import | +| p_decorators.py:32 | ControlFlowNode for cmeth | classmethod() | builtin-class classmethod | 31 | import | +| q_super.py:1 | ControlFlowNode for Base2 | class Base2 | builtin-class type | 1 | import | +| q_super.py:1 | ControlFlowNode for ClassExpr | class Base2 | builtin-class type | 1 | import | +| q_super.py:1 | ControlFlowNode for object | builtin-class object | builtin-class type | 1 | import | +| q_super.py:3 | ControlFlowNode for FunctionExpr | Function __init__ | builtin-class function | 3 | import | +| q_super.py:3 | ControlFlowNode for __init__ | Function __init__ | builtin-class function | 3 | import | +| q_super.py:4 | ControlFlowNode for Attribute | super().__init__ | builtin-class method | 4 | code/q_super.py:12 from runtime | +| q_super.py:4 | ControlFlowNode for Attribute | super().__init__ | builtin-class method | 4 | runtime | +| q_super.py:4 | ControlFlowNode for Base2 | class Base2 | builtin-class type | 1 | code/q_super.py:12 from runtime | +| q_super.py:4 | ControlFlowNode for Base2 | class Base2 | builtin-class type | 1 | runtime | +| q_super.py:4 | ControlFlowNode for self | self | class Base2 | 3 | runtime | +| q_super.py:4 | ControlFlowNode for self | self | class Derived4 | 10 | code/q_super.py:12 from runtime | +| q_super.py:4 | ControlFlowNode for super | builtin-class super | builtin-class type | 4 | code/q_super.py:12 from runtime | +| q_super.py:4 | ControlFlowNode for super | builtin-class super | builtin-class type | 4 | runtime | +| q_super.py:4 | ControlFlowNode for super() | super() | builtin-class super | 4 | code/q_super.py:12 from runtime | +| q_super.py:4 | ControlFlowNode for super() | super() | builtin-class super | 4 | runtime | +| q_super.py:8 | ControlFlowNode for Base2 | class Base2 | builtin-class type | 1 | import | +| q_super.py:8 | ControlFlowNode for ClassExpr | class Derived4 | builtin-class type | 8 | import | +| q_super.py:8 | ControlFlowNode for Derived4 | class Derived4 | builtin-class type | 8 | import | +| q_super.py:10 | ControlFlowNode for FunctionExpr | Function __init__ | builtin-class function | 10 | import | +| q_super.py:10 | ControlFlowNode for __init__ | Function __init__ | builtin-class function | 10 | import | +| q_super.py:11 | ControlFlowNode for Base2 | class Base2 | builtin-class type | 1 | runtime | +| q_super.py:11 | ControlFlowNode for self | self | class Derived4 | 10 | runtime | +| q_super.py:11 | ControlFlowNode for super | builtin-class super | builtin-class type | 11 | runtime | +| q_super.py:11 | ControlFlowNode for super() | super() | builtin-class super | 11 | runtime | +| q_super.py:12 | ControlFlowNode for Attribute | super().__init__ | builtin-class method | 12 | runtime | +| q_super.py:12 | ControlFlowNode for Attribute() | NoneType None | builtin-class NoneType | 3 | runtime | +| q_super.py:12 | ControlFlowNode for Derived4 | class Derived4 | builtin-class type | 8 | runtime | +| q_super.py:12 | ControlFlowNode for self | self | class Derived4 | 10 | runtime | +| q_super.py:12 | ControlFlowNode for super | builtin-class super | builtin-class type | 12 | runtime | +| q_super.py:12 | ControlFlowNode for super() | super() | builtin-class super | 12 | runtime | +| q_super.py:14 | ControlFlowNode for Base1 | class Base1 | builtin-class type | 14 | import | +| q_super.py:14 | ControlFlowNode for ClassExpr | class Base1 | builtin-class type | 14 | import | +| q_super.py:14 | ControlFlowNode for object | builtin-class object | builtin-class type | 14 | import | +| q_super.py:16 | ControlFlowNode for FunctionExpr | Function meth | builtin-class function | 16 | import | +| q_super.py:16 | ControlFlowNode for meth | Function meth | builtin-class function | 16 | import | +| q_super.py:17 | ControlFlowNode for IntegerLiteral | int 7 | builtin-class int | 17 | code/q_super.py:22 from code/q_super.py:27 from code/q_super.py:38 from runtime | +| q_super.py:17 | ControlFlowNode for IntegerLiteral | int 7 | builtin-class int | 17 | code/q_super.py:22 from code/q_super.py:27 from runtime | +| q_super.py:17 | ControlFlowNode for IntegerLiteral | int 7 | builtin-class int | 17 | code/q_super.py:22 from code/q_super.py:32 from runtime | +| q_super.py:17 | ControlFlowNode for IntegerLiteral | int 7 | builtin-class int | 17 | code/q_super.py:22 from runtime | +| q_super.py:17 | ControlFlowNode for IntegerLiteral | int 7 | builtin-class int | 17 | runtime | +| q_super.py:19 | ControlFlowNode for Base1 | class Base1 | builtin-class type | 14 | import | +| q_super.py:19 | ControlFlowNode for ClassExpr | class Derived1 | builtin-class type | 19 | import | +| q_super.py:19 | ControlFlowNode for Derived1 | class Derived1 | builtin-class type | 19 | import | +| q_super.py:21 | ControlFlowNode for FunctionExpr | Function meth | builtin-class function | 21 | import | +| q_super.py:21 | ControlFlowNode for meth | Function meth | builtin-class function | 21 | import | +| q_super.py:22 | ControlFlowNode for Attribute | super().meth | builtin-class method | 22 | code/q_super.py:27 from code/q_super.py:38 from runtime | +| q_super.py:22 | ControlFlowNode for Attribute | super().meth | builtin-class method | 22 | code/q_super.py:27 from runtime | +| q_super.py:22 | ControlFlowNode for Attribute | super().meth | builtin-class method | 22 | code/q_super.py:32 from runtime | +| q_super.py:22 | ControlFlowNode for Attribute | super().meth | builtin-class method | 22 | runtime | +| q_super.py:22 | ControlFlowNode for Attribute() | int 7 | builtin-class int | 17 | code/q_super.py:27 from code/q_super.py:38 from runtime | +| q_super.py:22 | ControlFlowNode for Attribute() | int 7 | builtin-class int | 17 | code/q_super.py:27 from runtime | +| q_super.py:22 | ControlFlowNode for Attribute() | int 7 | builtin-class int | 17 | code/q_super.py:32 from runtime | +| q_super.py:22 | ControlFlowNode for Attribute() | int 7 | builtin-class int | 17 | runtime | +| q_super.py:22 | ControlFlowNode for Derived1 | class Derived1 | builtin-class type | 19 | code/q_super.py:27 from code/q_super.py:38 from runtime | +| q_super.py:22 | ControlFlowNode for Derived1 | class Derived1 | builtin-class type | 19 | code/q_super.py:27 from runtime | +| q_super.py:22 | ControlFlowNode for Derived1 | class Derived1 | builtin-class type | 19 | code/q_super.py:32 from runtime | +| q_super.py:22 | ControlFlowNode for Derived1 | class Derived1 | builtin-class type | 19 | runtime | +| q_super.py:22 | ControlFlowNode for self | self | class Derived1 | 21 | runtime | +| q_super.py:22 | ControlFlowNode for self | self | class Derived2 | 26 | code/q_super.py:27 from runtime | +| q_super.py:22 | ControlFlowNode for self | self | class Derived5 | 31 | code/q_super.py:32 from runtime | +| q_super.py:22 | ControlFlowNode for self | self | class Wrong1 | 37 | code/q_super.py:27 from code/q_super.py:38 from runtime | +| q_super.py:22 | ControlFlowNode for super | builtin-class super | builtin-class type | 22 | code/q_super.py:27 from code/q_super.py:38 from runtime | +| q_super.py:22 | ControlFlowNode for super | builtin-class super | builtin-class type | 22 | code/q_super.py:27 from runtime | +| q_super.py:22 | ControlFlowNode for super | builtin-class super | builtin-class type | 22 | code/q_super.py:32 from runtime | +| q_super.py:22 | ControlFlowNode for super | builtin-class super | builtin-class type | 22 | runtime | +| q_super.py:22 | ControlFlowNode for super() | super() | builtin-class super | 22 | code/q_super.py:27 from code/q_super.py:38 from runtime | +| q_super.py:22 | ControlFlowNode for super() | super() | builtin-class super | 22 | code/q_super.py:27 from runtime | +| q_super.py:22 | ControlFlowNode for super() | super() | builtin-class super | 22 | code/q_super.py:32 from runtime | +| q_super.py:22 | ControlFlowNode for super() | super() | builtin-class super | 22 | runtime | +| q_super.py:24 | ControlFlowNode for ClassExpr | class Derived2 | builtin-class type | 24 | import | +| q_super.py:24 | ControlFlowNode for Derived1 | class Derived1 | builtin-class type | 19 | import | +| q_super.py:24 | ControlFlowNode for Derived2 | class Derived2 | builtin-class type | 24 | import | +| q_super.py:26 | ControlFlowNode for FunctionExpr | Function meth | builtin-class function | 26 | import | +| q_super.py:26 | ControlFlowNode for meth | Function meth | builtin-class function | 26 | import | +| q_super.py:27 | ControlFlowNode for Attribute | super().meth | builtin-class method | 27 | code/q_super.py:38 from runtime | +| q_super.py:27 | ControlFlowNode for Attribute | super().meth | builtin-class method | 27 | runtime | +| q_super.py:27 | ControlFlowNode for Attribute() | int 7 | builtin-class int | 17 | code/q_super.py:38 from runtime | +| q_super.py:27 | ControlFlowNode for Attribute() | int 7 | builtin-class int | 17 | runtime | +| q_super.py:27 | ControlFlowNode for Derived2 | class Derived2 | builtin-class type | 24 | code/q_super.py:38 from runtime | +| q_super.py:27 | ControlFlowNode for Derived2 | class Derived2 | builtin-class type | 24 | runtime | +| q_super.py:27 | ControlFlowNode for self | self | class Derived2 | 26 | runtime | +| q_super.py:27 | ControlFlowNode for self | self | class Wrong1 | 37 | code/q_super.py:38 from runtime | +| q_super.py:27 | ControlFlowNode for super | builtin-class super | builtin-class type | 27 | code/q_super.py:38 from runtime | +| q_super.py:27 | ControlFlowNode for super | builtin-class super | builtin-class type | 27 | runtime | +| q_super.py:27 | ControlFlowNode for super() | super() | builtin-class super | 27 | code/q_super.py:38 from runtime | +| q_super.py:27 | ControlFlowNode for super() | super() | builtin-class super | 27 | runtime | +| q_super.py:29 | ControlFlowNode for ClassExpr | class Derived5 | builtin-class type | 29 | import | +| q_super.py:29 | ControlFlowNode for Derived1 | class Derived1 | builtin-class type | 19 | import | +| q_super.py:29 | ControlFlowNode for Derived5 | class Derived5 | builtin-class type | 29 | import | +| q_super.py:31 | ControlFlowNode for FunctionExpr | Function meth | builtin-class function | 31 | import | +| q_super.py:31 | ControlFlowNode for meth | Function meth | builtin-class function | 31 | import | +| q_super.py:32 | ControlFlowNode for Attribute | super().meth | builtin-class method | 32 | runtime | +| q_super.py:32 | ControlFlowNode for Attribute() | int 7 | builtin-class int | 17 | runtime | +| q_super.py:32 | ControlFlowNode for Derived5 | class Derived5 | builtin-class type | 29 | runtime | +| q_super.py:32 | ControlFlowNode for self | self | class Derived5 | 31 | runtime | +| q_super.py:32 | ControlFlowNode for super | builtin-class super | builtin-class type | 32 | runtime | +| q_super.py:32 | ControlFlowNode for super() | super() | builtin-class super | 32 | runtime | +| q_super.py:35 | ControlFlowNode for ClassExpr | class Wrong1 | builtin-class type | 35 | import | +| q_super.py:35 | ControlFlowNode for Derived2 | class Derived2 | builtin-class type | 24 | import | +| q_super.py:35 | ControlFlowNode for Derived5 | class Derived5 | builtin-class type | 29 | import | +| q_super.py:35 | ControlFlowNode for Wrong1 | class Wrong1 | builtin-class type | 35 | import | +| q_super.py:37 | ControlFlowNode for FunctionExpr | Function meth | builtin-class function | 37 | import | +| q_super.py:37 | ControlFlowNode for meth | Function meth | builtin-class function | 37 | import | +| q_super.py:38 | ControlFlowNode for Attribute | super().meth | builtin-class method | 38 | runtime | +| q_super.py:38 | ControlFlowNode for Attribute() | int 7 | builtin-class int | 17 | runtime | +| q_super.py:38 | ControlFlowNode for Derived5 | class Derived5 | builtin-class type | 29 | runtime | +| q_super.py:38 | ControlFlowNode for self | self | class Wrong1 | 37 | runtime | +| q_super.py:38 | ControlFlowNode for super | builtin-class super | builtin-class type | 38 | runtime | +| q_super.py:38 | ControlFlowNode for super() | super() | builtin-class super | 38 | runtime | +| q_super.py:41 | ControlFlowNode for ClassExpr | class DA | builtin-class type | 41 | import | +| q_super.py:41 | ControlFlowNode for DA | class DA | builtin-class type | 41 | import | +| q_super.py:41 | ControlFlowNode for object | builtin-class object | builtin-class type | 41 | import | +| q_super.py:43 | ControlFlowNode for FunctionExpr | Function __init__ | builtin-class function | 43 | import | +| q_super.py:43 | ControlFlowNode for __init__ | Function __init__ | builtin-class function | 43 | import | +| q_super.py:46 | ControlFlowNode for ClassExpr | class DB | builtin-class type | 46 | import | +| q_super.py:46 | ControlFlowNode for DA | class DA | builtin-class type | 41 | import | +| q_super.py:46 | ControlFlowNode for DB | class DB | builtin-class type | 46 | import | +| q_super.py:48 | ControlFlowNode for ClassExpr | class DC | builtin-class type | 48 | import | +| q_super.py:48 | ControlFlowNode for DA | class DA | builtin-class type | 41 | import | +| q_super.py:48 | ControlFlowNode for DC | class DC | builtin-class type | 48 | import | +| q_super.py:50 | ControlFlowNode for FunctionExpr | Function __init__ | builtin-class function | 50 | import | +| q_super.py:50 | ControlFlowNode for __init__ | Function __init__ | builtin-class function | 50 | import | +| q_super.py:51 | ControlFlowNode for Attribute | class DC | builtin-class type | 48 | runtime | +| q_super.py:51 | ControlFlowNode for DB | class DB | builtin-class type | 46 | runtime | +| q_super.py:51 | ControlFlowNode for self | self | class DC | 50 | runtime | +| q_super.py:51 | ControlFlowNode for sup | super() | builtin-class super | 51 | runtime | +| q_super.py:51 | ControlFlowNode for super | builtin-class super | builtin-class type | 51 | runtime | +| q_super.py:51 | ControlFlowNode for super() | super() | builtin-class super | 51 | runtime | +| q_super.py:52 | ControlFlowNode for Attribute | super().__init__ | builtin-class method | 52 | runtime | +| q_super.py:52 | ControlFlowNode for Attribute() | NoneType None | builtin-class NoneType | 43 | runtime | +| q_super.py:52 | ControlFlowNode for sup | super() | builtin-class super | 51 | runtime | +| q_super.py:55 | ControlFlowNode for ClassExpr | class DD | builtin-class type | 55 | import | +| q_super.py:55 | ControlFlowNode for DA | class DA | builtin-class type | 41 | import | +| q_super.py:55 | ControlFlowNode for DD | class DD | builtin-class type | 55 | import | +| q_super.py:57 | ControlFlowNode for FunctionExpr | Function __init__ | builtin-class function | 57 | import | +| q_super.py:57 | ControlFlowNode for __init__ | Function __init__ | builtin-class function | 57 | import | +| q_super.py:58 | ControlFlowNode for DD | class DD | builtin-class type | 55 | runtime | +| q_super.py:58 | ControlFlowNode for self | self | class DD | 57 | runtime | +| q_super.py:58 | ControlFlowNode for sup | super() | builtin-class super | 58 | runtime | +| q_super.py:58 | ControlFlowNode for super | builtin-class super | builtin-class type | 58 | runtime | +| q_super.py:58 | ControlFlowNode for super() | super() | builtin-class super | 58 | runtime | +| q_super.py:59 | ControlFlowNode for Attribute | super().__init__ | builtin-class method | 59 | runtime | +| q_super.py:59 | ControlFlowNode for Attribute() | NoneType None | builtin-class NoneType | 43 | runtime | +| q_super.py:59 | ControlFlowNode for sup | super() | builtin-class super | 58 | runtime | +| q_super.py:61 | ControlFlowNode for ClassExpr | class DE | builtin-class type | 61 | import | +| q_super.py:61 | ControlFlowNode for DA | class DA | builtin-class type | 41 | import | +| q_super.py:61 | ControlFlowNode for DE | class DE | builtin-class type | 61 | import | +| q_super.py:63 | ControlFlowNode for ClassExpr | class DF | builtin-class type | 63 | import | +| q_super.py:63 | ControlFlowNode for DA | class DA | builtin-class type | 41 | import | +| q_super.py:63 | ControlFlowNode for DF | class DF | builtin-class type | 63 | import | +| q_super.py:65 | ControlFlowNode for FunctionExpr | Function __init__ | builtin-class function | 65 | import | +| q_super.py:65 | ControlFlowNode for __init__ | Function __init__ | builtin-class function | 65 | import | +| q_super.py:66 | ControlFlowNode for Attribute | class DF | builtin-class type | 63 | runtime | +| q_super.py:66 | ControlFlowNode for Attribute | super().__init__ | builtin-class method | 66 | runtime | +| q_super.py:66 | ControlFlowNode for Attribute() | NoneType None | builtin-class NoneType | 43 | runtime | +| q_super.py:66 | ControlFlowNode for DE | class DE | builtin-class type | 61 | runtime | +| q_super.py:66 | ControlFlowNode for self | self | class DF | 65 | runtime | +| q_super.py:66 | ControlFlowNode for super | builtin-class super | builtin-class type | 66 | runtime | +| q_super.py:66 | ControlFlowNode for super() | super() | builtin-class super | 66 | runtime | +| q_super.py:68 | ControlFlowNode for ClassExpr | class N | builtin-class type | 68 | import | +| q_super.py:68 | ControlFlowNode for N | class N | builtin-class type | 68 | import | +| q_super.py:68 | ControlFlowNode for object | builtin-class object | builtin-class type | 68 | import | +| q_super.py:71 | ControlFlowNode for ClassExpr | class M | builtin-class type | 71 | import | +| q_super.py:71 | ControlFlowNode for M | class M | builtin-class type | 71 | import | +| q_super.py:71 | ControlFlowNode for N | class N | builtin-class type | 68 | import | +| q_super.py:73 | ControlFlowNode for FunctionExpr | Function __init__ | builtin-class function | 73 | import | +| q_super.py:73 | ControlFlowNode for __init__ | Function __init__ | builtin-class function | 73 | import | +| q_super.py:74 | ControlFlowNode for M | class M | builtin-class type | 71 | runtime | +| q_super.py:74 | ControlFlowNode for s | super() | builtin-class super | 74 | runtime | +| q_super.py:74 | ControlFlowNode for self | self | class M | 73 | runtime | +| q_super.py:74 | ControlFlowNode for super | builtin-class super | builtin-class type | 74 | runtime | +| q_super.py:74 | ControlFlowNode for super() | super() | builtin-class super | 74 | runtime | +| q_super.py:75 | ControlFlowNode for Attribute | super().__init__ | builtin-class method | 75 | runtime | +| q_super.py:75 | ControlFlowNode for i | super().__init__ | builtin-class method | 75 | runtime | +| q_super.py:75 | ControlFlowNode for s | super() | builtin-class super | 74 | runtime | +| q_super.py:76 | ControlFlowNode for i | super().__init__ | builtin-class method | 75 | runtime | +| r_regressions.py:5 | ControlFlowNode for ClassExpr | class Queue | builtin-class type | 5 | import | +| r_regressions.py:5 | ControlFlowNode for Queue | class Queue | builtin-class type | 5 | import | +| r_regressions.py:5 | ControlFlowNode for object | builtin-class object | builtin-class type | 5 | import | +| r_regressions.py:7 | ControlFlowNode for FunctionExpr | Function __init__ | builtin-class function | 7 | import | +| r_regressions.py:7 | ControlFlowNode for __init__ | Function __init__ | builtin-class function | 7 | import | +| r_regressions.py:9 | ControlFlowNode for Attribute() | NoneType None | builtin-class NoneType | 11 | runtime | +| r_regressions.py:9 | ControlFlowNode for self | self | class Queue | 7 | runtime | +| r_regressions.py:11 | ControlFlowNode for FunctionExpr | Function _after_fork | builtin-class function | 11 | import | +| r_regressions.py:11 | ControlFlowNode for _after_fork | Function _after_fork | builtin-class function | 11 | import | +| r_regressions.py:12 | ControlFlowNode for Attribute | bool False | builtin-class bool | 12 | code/r_regressions.py:9 from runtime | +| r_regressions.py:12 | ControlFlowNode for False | bool False | builtin-class bool | 12 | code/r_regressions.py:9 from runtime | +| r_regressions.py:12 | ControlFlowNode for self | self | class Queue | 7 | code/r_regressions.py:9 from runtime | +| r_regressions.py:13 | ControlFlowNode for Attribute | NoneType None | builtin-class NoneType | 13 | code/r_regressions.py:9 from runtime | +| r_regressions.py:13 | ControlFlowNode for None | NoneType None | builtin-class NoneType | 13 | code/r_regressions.py:9 from runtime | +| r_regressions.py:13 | ControlFlowNode for self | self | class Queue | 7 | code/r_regressions.py:9 from runtime | +| r_regressions.py:15 | ControlFlowNode for FunctionExpr | Function close | builtin-class function | 15 | import | +| r_regressions.py:15 | ControlFlowNode for close | Function close | builtin-class function | 15 | import | +| r_regressions.py:16 | ControlFlowNode for Attribute | bool True | builtin-class bool | 16 | runtime | +| r_regressions.py:16 | ControlFlowNode for True | bool True | builtin-class bool | 16 | runtime | +| r_regressions.py:16 | ControlFlowNode for self | self | class Queue | 15 | runtime | +| r_regressions.py:18 | ControlFlowNode for self | self | class Queue | 15 | runtime | +| r_regressions.py:20 | ControlFlowNode for Attribute | NoneType None | builtin-class NoneType | 13 | runtime | +| r_regressions.py:20 | ControlFlowNode for close | NoneType None | builtin-class NoneType | 13 | runtime | +| r_regressions.py:20 | ControlFlowNode for self | self | class Queue | 15 | runtime | +| r_regressions.py:21 | ControlFlowNode for close | NoneType None | builtin-class NoneType | 13 | runtime | +| r_regressions.py:22 | ControlFlowNode for Attribute | NoneType None | builtin-class NoneType | 22 | runtime | +| r_regressions.py:22 | ControlFlowNode for None | NoneType None | builtin-class NoneType | 22 | runtime | +| r_regressions.py:22 | ControlFlowNode for self | self | class Queue | 15 | runtime | +| r_regressions.py:27 | ControlFlowNode for FunctionExpr | Function f | builtin-class function | 27 | import | +| r_regressions.py:27 | ControlFlowNode for IntegerLiteral | int 0 | builtin-class int | 27 | import | +| r_regressions.py:27 | ControlFlowNode for None | NoneType None | builtin-class NoneType | 27 | import | +| r_regressions.py:27 | ControlFlowNode for f | Function f | builtin-class function | 27 | import | +| r_regressions.py:31 | ControlFlowNode for y | NoneType None | builtin-class NoneType | 27 | runtime | +| r_regressions.py:33 | ControlFlowNode for y | NoneType None | builtin-class NoneType | 27 | runtime | +| r_regressions.py:35 | ControlFlowNode for UnaryExpr | bool False | builtin-class bool | 35 | runtime | +| r_regressions.py:35 | ControlFlowNode for UnaryExpr | bool True | builtin-class bool | 35 | runtime | +| r_regressions.py:36 | ControlFlowNode for z | int 0 | builtin-class int | 27 | runtime | +| r_regressions.py:42 | ControlFlowNode for FunctionExpr | Function find_library | builtin-class function | 42 | import | +| r_regressions.py:42 | ControlFlowNode for find_library | Function find_library | builtin-class function | 42 | import | +| r_regressions.py:43 | ControlFlowNode for List | List | builtin-class list | 43 | runtime | +| r_regressions.py:46 | ControlFlowNode for FunctionExpr | Function fail | builtin-class function | 46 | import | +| r_regressions.py:46 | ControlFlowNode for fail | Function fail | builtin-class function | 46 | import | +| r_regressions.py:49 | ControlFlowNode for C | class C | builtin-class type | 49 | import | +| r_regressions.py:49 | ControlFlowNode for ClassExpr | class C | builtin-class type | 49 | import | +| r_regressions.py:49 | ControlFlowNode for object | builtin-class object | builtin-class type | 49 | import | +| r_regressions.py:51 | ControlFlowNode for FunctionExpr | Function fail | builtin-class function | 51 | import | +| r_regressions.py:51 | ControlFlowNode for fail | Function fail | builtin-class function | 51 | import | +| r_regressions.py:52 | ControlFlowNode for fail | Function fail | builtin-class function | 46 | runtime | +| r_regressions.py:52 | ControlFlowNode for fail() | NoneType None | builtin-class NoneType | 46 | runtime | +| r_regressions.py:58 | ControlFlowNode for FunctionExpr | Function method_decorator | builtin-class function | 58 | import | +| r_regressions.py:58 | ControlFlowNode for Str | '' | builtin-class str | 58 | import | +| r_regressions.py:58 | ControlFlowNode for method_decorator | Function method_decorator | builtin-class function | 58 | import | +| r_regressions.py:61 | ControlFlowNode for FunctionExpr | Function _dec | builtin-class function | 61 | code/r_regressions.py:85 from import | +| r_regressions.py:61 | ControlFlowNode for FunctionExpr | Function _dec | builtin-class function | 61 | runtime | +| r_regressions.py:61 | ControlFlowNode for _dec | Function _dec | builtin-class function | 61 | code/r_regressions.py:85 from import | +| r_regressions.py:61 | ControlFlowNode for _dec | Function _dec | builtin-class function | 61 | runtime | +| r_regressions.py:62 | ControlFlowNode for is_class | bool True | builtin-class bool | 62 | code/r_regressions.py:85 from import | +| r_regressions.py:62 | ControlFlowNode for isinstance | Builtin-function isinstance | builtin-class builtin_function_or_method | 62 | code/r_regressions.py:85 from import | +| r_regressions.py:62 | ControlFlowNode for isinstance() | bool True | builtin-class bool | 62 | code/r_regressions.py:85 from import | +| r_regressions.py:62 | ControlFlowNode for obj | class TestFirst | builtin-class type | 86 | code/r_regressions.py:85 from import | +| r_regressions.py:62 | ControlFlowNode for type | builtin-class type | builtin-class type | 62 | code/r_regressions.py:85 from import | +| r_regressions.py:63 | ControlFlowNode for is_class | bool True | builtin-class bool | 62 | code/r_regressions.py:85 from import | +| r_regressions.py:68 | ControlFlowNode for FunctionExpr | Function _wrapper | builtin-class function | 68 | code/r_regressions.py:85 from import | +| r_regressions.py:68 | ControlFlowNode for _wrapper | Function _wrapper | builtin-class function | 68 | code/r_regressions.py:85 from import | +| r_regressions.py:72 | ControlFlowNode for is_class | bool True | builtin-class bool | 62 | code/r_regressions.py:85 from import | +| r_regressions.py:73 | ControlFlowNode for _wrapper | Function _wrapper | builtin-class function | 68 | code/r_regressions.py:85 from import | +| r_regressions.py:73 | ControlFlowNode for obj | class TestFirst | builtin-class type | 86 | code/r_regressions.py:85 from import | +| r_regressions.py:73 | ControlFlowNode for setattr | Builtin-function setattr | builtin-class builtin_function_or_method | 73 | code/r_regressions.py:85 from import | +| r_regressions.py:73 | ControlFlowNode for setattr() | NoneType None | builtin-class NoneType | 73 | code/r_regressions.py:85 from import | +| r_regressions.py:74 | ControlFlowNode for obj | class TestFirst | builtin-class type | 86 | code/r_regressions.py:85 from import | +| r_regressions.py:78 | ControlFlowNode for _dec | Function _dec | builtin-class function | 61 | code/r_regressions.py:85 from import | +| r_regressions.py:78 | ControlFlowNode for _dec | Function _dec | builtin-class function | 61 | runtime | +| r_regressions.py:80 | ControlFlowNode for FunctionExpr | Function deco | builtin-class function | 80 | import | +| r_regressions.py:80 | ControlFlowNode for deco | Function deco | builtin-class function | 80 | import | +| r_regressions.py:81 | ControlFlowNode for FunctionExpr | Function _wrapper | builtin-class function | 81 | runtime | +| r_regressions.py:81 | ControlFlowNode for _wrapper | Function _wrapper | builtin-class function | 81 | runtime | +| r_regressions.py:83 | ControlFlowNode for _wrapper | Function _wrapper | builtin-class function | 81 | runtime | +| r_regressions.py:85 | ControlFlowNode for Str | 'method' | builtin-class str | 85 | import | +| r_regressions.py:85 | ControlFlowNode for deco | Function deco | builtin-class function | 80 | import | +| r_regressions.py:85 | ControlFlowNode for method_decorator | Function method_decorator | builtin-class function | 58 | import | +| r_regressions.py:85 | ControlFlowNode for method_decorator() | Function _dec | builtin-class function | 61 | import | +| r_regressions.py:85 | ControlFlowNode for method_decorator()() | class TestFirst | builtin-class type | 86 | import | +| r_regressions.py:86 | ControlFlowNode for ClassExpr | class TestFirst | builtin-class type | 86 | import | +| r_regressions.py:86 | ControlFlowNode for TestFirst | class TestFirst | builtin-class type | 86 | import | +| r_regressions.py:86 | ControlFlowNode for object | builtin-class object | builtin-class type | 86 | import | +| r_regressions.py:87 | ControlFlowNode for FunctionExpr | Function method | builtin-class function | 87 | import | +| r_regressions.py:87 | ControlFlowNode for method | Function method | builtin-class function | 87 | import | +| r_regressions.py:88 | ControlFlowNode for Str | 'hello world' | builtin-class str | 88 | code/r_regressions.py:90 from import | +| r_regressions.py:88 | ControlFlowNode for Str | 'hello world' | builtin-class str | 88 | runtime | +| r_regressions.py:90 | ControlFlowNode for Attribute() | 'hello world' | builtin-class str | 88 | import | +| r_regressions.py:90 | ControlFlowNode for TestFirst | class TestFirst | builtin-class type | 86 | import | +| r_regressions.py:90 | ControlFlowNode for TestFirst() | TestFirst() | class TestFirst | 90 | import | +| r_regressions.py:93 | ControlFlowNode for ImportExpr | Module sys | builtin-class module | 93 | import | +| r_regressions.py:93 | ControlFlowNode for sys | Module sys | builtin-class module | 93 | import | +| r_regressions.py:95 | ControlFlowNode for Attribute | tuple object | builtin-class tuple | 95 | import | +| r_regressions.py:95 | ControlFlowNode for _names | tuple object | builtin-class tuple | 95 | import | +| r_regressions.py:95 | ControlFlowNode for sys | Module sys | builtin-class module | 93 | import | +| r_regressions.py:97 | ControlFlowNode for Compare | bool True | builtin-class bool | 97 | import | +| r_regressions.py:97 | ControlFlowNode for Str | 'time' | builtin-class str | 97 | import | +| r_regressions.py:97 | ControlFlowNode for _names | tuple object | builtin-class tuple | 95 | import | +| r_regressions.py:98 | ControlFlowNode for ImportExpr | Module time | builtin-class module | 98 | import | +| r_regressions.py:98 | ControlFlowNode for t | Module time | builtin-class module | 98 | import | +| s_scopes.py:4 | ControlFlowNode for True | bool True | builtin-class bool | 4 | import | +| s_scopes.py:4 | ControlFlowNode for float | bool True | builtin-class bool | 4 | import | +| s_scopes.py:7 | ControlFlowNode for C2 | class C2 | builtin-class type | 7 | import | +| s_scopes.py:7 | ControlFlowNode for ClassExpr | class C2 | builtin-class type | 7 | import | +| s_scopes.py:7 | ControlFlowNode for object | builtin-class object | builtin-class type | 7 | import | +| s_scopes.py:9 | ControlFlowNode for i1 | builtin-class int | builtin-class type | 9 | import | +| s_scopes.py:9 | ControlFlowNode for int | builtin-class int | builtin-class type | 9 | import | +| s_scopes.py:10 | ControlFlowNode for f1 | bool True | builtin-class bool | 4 | import | +| s_scopes.py:10 | ControlFlowNode for f1 | builtin-class float | builtin-class type | 10 | import | +| s_scopes.py:10 | ControlFlowNode for float | bool True | builtin-class bool | 4 | import | +| s_scopes.py:10 | ControlFlowNode for float | builtin-class float | builtin-class type | 10 | import | +| s_scopes.py:12 | ControlFlowNode for IntegerLiteral | int 0 | builtin-class int | 12 | import | +| s_scopes.py:12 | ControlFlowNode for int | int 0 | builtin-class int | 12 | import | +| s_scopes.py:15 | ControlFlowNode for FloatLiteral | float 1.0 | builtin-class float | 15 | import | +| s_scopes.py:15 | ControlFlowNode for str | float 1.0 | builtin-class float | 15 | import | +| s_scopes.py:17 | ControlFlowNode for None | NoneType None | builtin-class NoneType | 17 | import | +| s_scopes.py:17 | ControlFlowNode for float | NoneType None | builtin-class NoneType | 17 | import | +| s_scopes.py:18 | ControlFlowNode for i2 | int 0 | builtin-class int | 12 | import | +| s_scopes.py:18 | ControlFlowNode for int | int 0 | builtin-class int | 12 | import | +| s_scopes.py:19 | ControlFlowNode for s | builtin-class str | builtin-class type | 19 | import | +| s_scopes.py:19 | ControlFlowNode for s | float 1.0 | builtin-class float | 15 | import | +| s_scopes.py:19 | ControlFlowNode for str | builtin-class str | builtin-class type | 19 | import | +| s_scopes.py:19 | ControlFlowNode for str | float 1.0 | builtin-class float | 15 | import | +| s_scopes.py:20 | ControlFlowNode for f2 | NoneType None | builtin-class NoneType | 17 | import | +| s_scopes.py:20 | ControlFlowNode for f2 | bool True | builtin-class bool | 4 | import | +| s_scopes.py:20 | ControlFlowNode for f2 | builtin-class float | builtin-class type | 20 | import | +| s_scopes.py:20 | ControlFlowNode for float | NoneType None | builtin-class NoneType | 17 | import | +| s_scopes.py:20 | ControlFlowNode for float | bool True | builtin-class bool | 4 | import | +| s_scopes.py:20 | ControlFlowNode for float | builtin-class float | builtin-class type | 20 | import | +| s_scopes.py:23 | ControlFlowNode for i | builtin-class int | builtin-class type | 23 | import | +| s_scopes.py:23 | ControlFlowNode for int | builtin-class int | builtin-class type | 23 | import | +| s_scopes.py:24 | ControlFlowNode for f | bool True | builtin-class bool | 4 | import | +| s_scopes.py:24 | ControlFlowNode for f | builtin-class float | builtin-class type | 24 | import | +| s_scopes.py:24 | ControlFlowNode for float | bool True | builtin-class bool | 4 | import | +| s_scopes.py:24 | ControlFlowNode for float | builtin-class float | builtin-class type | 24 | import | +| t_type.py:1 | ControlFlowNode for ImportExpr | Module sys | builtin-class module | 1 | import | +| t_type.py:1 | ControlFlowNode for sys | Module sys | builtin-class module | 1 | import | +| t_type.py:3 | ControlFlowNode for C | class C | builtin-class type | 3 | import | +| t_type.py:3 | ControlFlowNode for ClassExpr | class C | builtin-class type | 3 | import | +| t_type.py:3 | ControlFlowNode for object | builtin-class object | builtin-class type | 3 | import | +| t_type.py:6 | ControlFlowNode for C | class C | builtin-class type | 3 | import | +| t_type.py:6 | ControlFlowNode for C() | C() | class C | 6 | import | +| t_type.py:6 | ControlFlowNode for type | builtin-class type | builtin-class type | 6 | import | +| t_type.py:6 | ControlFlowNode for type() | class C | builtin-class type | 3 | import | +| t_type.py:7 | ControlFlowNode for sys | Module sys | builtin-class module | 1 | import | +| t_type.py:7 | ControlFlowNode for type | builtin-class type | builtin-class type | 7 | import | +| t_type.py:7 | ControlFlowNode for type() | builtin-class module | builtin-class type | 7 | import | +| t_type.py:9 | ControlFlowNode for type | builtin-class type | builtin-class type | 9 | import | +| t_type.py:10 | ControlFlowNode for Dict | Dict | builtin-class dict | 10 | import | +| t_type.py:10 | ControlFlowNode for Tuple | Tuple | builtin-class tuple | 10 | import | +| t_type.py:10 | ControlFlowNode for object | builtin-class object | builtin-class type | 10 | import | +| t_type.py:10 | ControlFlowNode for type | builtin-class type | builtin-class type | 10 | import | +| t_type.py:12 | ControlFlowNode for FunctionExpr | Function k | builtin-class function | 12 | import | +| t_type.py:12 | ControlFlowNode for k | Function k | builtin-class function | 12 | import | +| t_type.py:13 | ControlFlowNode for C | class C | builtin-class type | 3 | runtime | +| t_type.py:13 | ControlFlowNode for C() | C() | class C | 13 | runtime | +| t_type.py:13 | ControlFlowNode for type | builtin-class type | builtin-class type | 13 | runtime | +| t_type.py:13 | ControlFlowNode for type() | class C | builtin-class type | 3 | runtime | +| t_type.py:14 | ControlFlowNode for sys | Module sys | builtin-class module | 1 | runtime | +| t_type.py:14 | ControlFlowNode for type | builtin-class type | builtin-class type | 14 | runtime | +| t_type.py:14 | ControlFlowNode for type() | builtin-class module | builtin-class type | 14 | runtime | +| t_type.py:15 | ControlFlowNode for type | builtin-class type | builtin-class type | 15 | runtime | +| t_type.py:15 | ControlFlowNode for type() | *UNKNOWN TYPE* | builtin-class type | 15 | runtime | +| t_type.py:16 | ControlFlowNode for Dict | Dict | builtin-class dict | 16 | runtime | +| t_type.py:16 | ControlFlowNode for Tuple | Tuple | builtin-class tuple | 16 | runtime | +| t_type.py:16 | ControlFlowNode for object | builtin-class object | builtin-class type | 16 | runtime | +| t_type.py:16 | ControlFlowNode for type | builtin-class type | builtin-class type | 16 | runtime | +| u_paired_values.py:2 | ControlFlowNode for FunctionExpr | Function return_if_true | builtin-class function | 2 | import | +| u_paired_values.py:2 | ControlFlowNode for return_if_true | Function return_if_true | builtin-class function | 2 | import | +| u_paired_values.py:3 | ControlFlowNode for cond | bool False | builtin-class bool | 8 | code/u_paired_values.py:8 from code/u_paired_values.py:14 from import | +| u_paired_values.py:3 | ControlFlowNode for cond | bool False | builtin-class bool | 8 | code/u_paired_values.py:8 from runtime | +| u_paired_values.py:3 | ControlFlowNode for cond | bool True | builtin-class bool | 8 | code/u_paired_values.py:8 from code/u_paired_values.py:11 from import | +| u_paired_values.py:3 | ControlFlowNode for cond | bool True | builtin-class bool | 8 | code/u_paired_values.py:8 from runtime | +| u_paired_values.py:4 | ControlFlowNode for val | int 1 | builtin-class int | 8 | code/u_paired_values.py:8 from code/u_paired_values.py:11 from import | +| u_paired_values.py:4 | ControlFlowNode for val | int 1 | builtin-class int | 8 | code/u_paired_values.py:8 from runtime | +| u_paired_values.py:5 | ControlFlowNode for Exception | builtin-class Exception | builtin-class type | 5 | code/u_paired_values.py:8 from code/u_paired_values.py:14 from import | +| u_paired_values.py:5 | ControlFlowNode for Exception | builtin-class Exception | builtin-class type | 5 | code/u_paired_values.py:8 from runtime | +| u_paired_values.py:5 | ControlFlowNode for Exception | builtin-class Exception | builtin-class type | 5 | runtime | +| u_paired_values.py:5 | ControlFlowNode for Exception() | Exception() | builtin-class Exception | 5 | code/u_paired_values.py:8 from code/u_paired_values.py:14 from import | +| u_paired_values.py:5 | ControlFlowNode for Exception() | Exception() | builtin-class Exception | 5 | code/u_paired_values.py:8 from runtime | +| u_paired_values.py:5 | ControlFlowNode for Exception() | Exception() | builtin-class Exception | 5 | runtime | +| u_paired_values.py:7 | ControlFlowNode for FunctionExpr | Function test | builtin-class function | 7 | import | +| u_paired_values.py:7 | ControlFlowNode for test | Function test | builtin-class function | 7 | import | +| u_paired_values.py:8 | ControlFlowNode for False | bool False | builtin-class bool | 8 | code/u_paired_values.py:14 from import | +| u_paired_values.py:8 | ControlFlowNode for False | bool False | builtin-class bool | 8 | runtime | +| u_paired_values.py:8 | ControlFlowNode for IfExp | int 1 | builtin-class int | 8 | code/u_paired_values.py:11 from import | +| u_paired_values.py:8 | ControlFlowNode for IfExp | int 1 | builtin-class int | 8 | runtime | +| u_paired_values.py:8 | ControlFlowNode for IntegerLiteral | int 1 | builtin-class int | 8 | code/u_paired_values.py:11 from import | +| u_paired_values.py:8 | ControlFlowNode for IntegerLiteral | int 1 | builtin-class int | 8 | runtime | +| u_paired_values.py:8 | ControlFlowNode for IntegerLiteral | int 2 | builtin-class int | 8 | code/u_paired_values.py:14 from import | +| u_paired_values.py:8 | ControlFlowNode for IntegerLiteral | int 2 | builtin-class int | 8 | runtime | +| u_paired_values.py:8 | ControlFlowNode for True | bool True | builtin-class bool | 8 | code/u_paired_values.py:11 from import | +| u_paired_values.py:8 | ControlFlowNode for True | bool True | builtin-class bool | 8 | runtime | +| u_paired_values.py:8 | ControlFlowNode for cond | bool False | builtin-class bool | 14 | code/u_paired_values.py:14 from import | +| u_paired_values.py:8 | ControlFlowNode for cond | bool True | builtin-class bool | 11 | code/u_paired_values.py:11 from import | +| u_paired_values.py:8 | ControlFlowNode for return_if_true | Function return_if_true | builtin-class function | 2 | code/u_paired_values.py:11 from import | +| u_paired_values.py:8 | ControlFlowNode for return_if_true | Function return_if_true | builtin-class function | 2 | code/u_paired_values.py:14 from import | +| u_paired_values.py:8 | ControlFlowNode for return_if_true | Function return_if_true | builtin-class function | 2 | runtime | +| u_paired_values.py:8 | ControlFlowNode for return_if_true() | int 1 | builtin-class int | 8 | code/u_paired_values.py:11 from import | +| u_paired_values.py:8 | ControlFlowNode for return_if_true() | int 1 | builtin-class int | 8 | runtime | +| u_paired_values.py:8 | ControlFlowNode for x | int 1 | builtin-class int | 8 | code/u_paired_values.py:11 from import | +| u_paired_values.py:8 | ControlFlowNode for x | int 1 | builtin-class int | 8 | runtime | +| u_paired_values.py:9 | ControlFlowNode for x | int 1 | builtin-class int | 8 | code/u_paired_values.py:11 from import | +| u_paired_values.py:9 | ControlFlowNode for x | int 1 | builtin-class int | 8 | runtime | +| u_paired_values.py:11 | ControlFlowNode for True | bool True | builtin-class bool | 11 | import | +| u_paired_values.py:11 | ControlFlowNode for test | Function test | builtin-class function | 7 | import | +| u_paired_values.py:11 | ControlFlowNode for test() | int 1 | builtin-class int | 8 | import | +| u_paired_values.py:11 | ControlFlowNode for y | int 1 | builtin-class int | 8 | import | +| u_paired_values.py:12 | ControlFlowNode for y | int 1 | builtin-class int | 8 | import | +| u_paired_values.py:14 | ControlFlowNode for False | bool False | builtin-class bool | 14 | import | +| u_paired_values.py:14 | ControlFlowNode for test | Function test | builtin-class function | 7 | import | diff --git a/python/ql/test/library-tests/PointsTo/new/PointsToWithContext.ql b/python/ql/test/library-tests/PointsTo/new/PointsToWithContext.ql new file mode 100755 index 00000000000..e2ef1fc3c61 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/PointsToWithContext.ql @@ -0,0 +1,10 @@ +import python +import Util +import semmle.python.pointsto.PointsTo +import semmle.python.pointsto.PointsToContext + +from ControlFlowNode f, Object o, ClassObject c, ControlFlowNode x, PointsToContext ctx + +where PointsTo::points_to(f, ctx, o, c, x) + +select locate(f.getLocation(), "abeghijklmnpqrstu"), f.toString(), repr(o), repr(c), x.getLocation().getStartLine(), ctx diff --git a/python/ql/test/library-tests/PointsTo/new/PointsToWithType.expected b/python/ql/test/library-tests/PointsTo/new/PointsToWithType.expected new file mode 100644 index 00000000000..f3fc21e75b5 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/PointsToWithType.expected @@ -0,0 +1,712 @@ +| a_simple.py:2 | ControlFlowNode for FloatLiteral | float 1.0 | builtin-class float | 2 | +| a_simple.py:2 | ControlFlowNode for f1 | float 1.0 | builtin-class float | 2 | +| a_simple.py:3 | ControlFlowNode for dict | builtin-class dict | builtin-class type | 3 | +| a_simple.py:4 | ControlFlowNode for tuple | builtin-class tuple | builtin-class type | 4 | +| a_simple.py:5 | ControlFlowNode for IntegerLiteral | int 0 | builtin-class int | 5 | +| a_simple.py:5 | ControlFlowNode for i1 | int 0 | builtin-class int | 5 | +| a_simple.py:6 | ControlFlowNode for Tuple | Tuple | builtin-class tuple | 6 | +| a_simple.py:6 | ControlFlowNode for s | Tuple | builtin-class tuple | 6 | +| a_simple.py:8 | ControlFlowNode for FunctionExpr | Function func | builtin-class function | 8 | +| a_simple.py:8 | ControlFlowNode for func | Function func | builtin-class function | 8 | +| a_simple.py:11 | ControlFlowNode for C | class C | builtin-class type | 11 | +| a_simple.py:11 | ControlFlowNode for ClassExpr | class C | builtin-class type | 11 | +| a_simple.py:11 | ControlFlowNode for object | builtin-class object | builtin-class type | 11 | +| a_simple.py:14 | ControlFlowNode for FunctionExpr | Function vararg_kwarg | builtin-class function | 14 | +| a_simple.py:14 | ControlFlowNode for d | d | builtin-class dict | 14 | +| a_simple.py:14 | ControlFlowNode for t | t | builtin-class tuple | 14 | +| a_simple.py:14 | ControlFlowNode for vararg_kwarg | Function vararg_kwarg | builtin-class function | 14 | +| a_simple.py:15 | ControlFlowNode for t | t | builtin-class tuple | 14 | +| a_simple.py:16 | ControlFlowNode for d | d | builtin-class dict | 14 | +| a_simple.py:18 | ControlFlowNode for FunctionExpr | Function multi_loop | builtin-class function | 18 | +| a_simple.py:18 | ControlFlowNode for multi_loop | Function multi_loop | builtin-class function | 18 | +| a_simple.py:19 | ControlFlowNode for None | NoneType None | builtin-class NoneType | 19 | +| a_simple.py:19 | ControlFlowNode for x | NoneType None | builtin-class NoneType | 19 | +| a_simple.py:20 | ControlFlowNode for Tuple | Tuple | builtin-class tuple | 20 | +| a_simple.py:23 | ControlFlowNode for FunctionExpr | Function with_definition | builtin-class function | 23 | +| a_simple.py:23 | ControlFlowNode for with_definition | Function with_definition | builtin-class function | 23 | +| a_simple.py:27 | ControlFlowNode for FunctionExpr | Function multi_loop_in_try | builtin-class function | 27 | +| a_simple.py:27 | ControlFlowNode for multi_loop_in_try | Function multi_loop_in_try | builtin-class function | 27 | +| a_simple.py:29 | ControlFlowNode for Tuple | Tuple | builtin-class tuple | 29 | +| a_simple.py:31 | ControlFlowNode for KeyError | builtin-class KeyError | builtin-class type | 31 | +| a_simple.py:34 | ControlFlowNode for FunctionExpr | Function f | builtin-class function | 34 | +| a_simple.py:34 | ControlFlowNode for args | args | builtin-class tuple | 34 | +| a_simple.py:34 | ControlFlowNode for f | Function f | builtin-class function | 34 | +| a_simple.py:34 | ControlFlowNode for kwargs | kwargs | builtin-class dict | 34 | +| a_simple.py:35 | ControlFlowNode for IntegerLiteral | int 0 | builtin-class int | 35 | +| a_simple.py:35 | ControlFlowNode for UnaryExpr | bool False | builtin-class bool | 35 | +| a_simple.py:35 | ControlFlowNode for UnaryExpr | bool True | builtin-class bool | 35 | +| a_simple.py:35 | ControlFlowNode for args | args | builtin-class tuple | 34 | +| a_simple.py:36 | ControlFlowNode for Str | 'x' | builtin-class str | 36 | +| a_simple.py:36 | ControlFlowNode for UnaryExpr | bool False | builtin-class bool | 36 | +| a_simple.py:36 | ControlFlowNode for UnaryExpr | bool True | builtin-class bool | 36 | +| a_simple.py:36 | ControlFlowNode for kwargs | kwargs | builtin-class dict | 34 | +| b_condition.py:4 | ControlFlowNode for FunctionExpr | Function f | builtin-class function | 4 | +| b_condition.py:4 | ControlFlowNode for f | Function f | builtin-class function | 4 | +| b_condition.py:5 | ControlFlowNode for IfExp | NoneType None | builtin-class NoneType | 5 | +| b_condition.py:5 | ControlFlowNode for None | NoneType None | builtin-class NoneType | 5 | +| b_condition.py:5 | ControlFlowNode for x | NoneType None | builtin-class NoneType | 5 | +| b_condition.py:7 | ControlFlowNode for Compare | bool False | builtin-class bool | 7 | +| b_condition.py:7 | ControlFlowNode for Compare | bool True | builtin-class bool | 7 | +| b_condition.py:7 | ControlFlowNode for None | NoneType None | builtin-class NoneType | 7 | +| b_condition.py:7 | ControlFlowNode for x | NoneType None | builtin-class NoneType | 5 | +| b_condition.py:8 | ControlFlowNode for IntegerLiteral | int 7 | builtin-class int | 8 | +| b_condition.py:8 | ControlFlowNode for x | int 7 | builtin-class int | 8 | +| b_condition.py:9 | ControlFlowNode for x | int 7 | builtin-class int | 8 | +| b_condition.py:11 | ControlFlowNode for IfExp | NoneType None | builtin-class NoneType | 11 | +| b_condition.py:11 | ControlFlowNode for None | NoneType None | builtin-class NoneType | 11 | +| b_condition.py:11 | ControlFlowNode for x | NoneType None | builtin-class NoneType | 11 | +| b_condition.py:13 | ControlFlowNode for Compare | bool False | builtin-class bool | 13 | +| b_condition.py:13 | ControlFlowNode for Compare | bool True | builtin-class bool | 13 | +| b_condition.py:13 | ControlFlowNode for None | NoneType None | builtin-class NoneType | 13 | +| b_condition.py:13 | ControlFlowNode for x | NoneType None | builtin-class NoneType | 11 | +| b_condition.py:14 | ControlFlowNode for IntegerLiteral | int 7 | builtin-class int | 14 | +| b_condition.py:14 | ControlFlowNode for x | int 7 | builtin-class int | 14 | +| b_condition.py:15 | ControlFlowNode for x | NoneType None | builtin-class NoneType | 11 | +| b_condition.py:15 | ControlFlowNode for x | int 7 | builtin-class int | 14 | +| b_condition.py:17 | ControlFlowNode for IfExp | NoneType None | builtin-class NoneType | 17 | +| b_condition.py:17 | ControlFlowNode for None | NoneType None | builtin-class NoneType | 17 | +| b_condition.py:17 | ControlFlowNode for x | NoneType None | builtin-class NoneType | 17 | +| b_condition.py:19 | ControlFlowNode for UnaryExpr | bool False | builtin-class bool | 19 | +| b_condition.py:19 | ControlFlowNode for UnaryExpr | bool True | builtin-class bool | 19 | +| b_condition.py:19 | ControlFlowNode for x | NoneType None | builtin-class NoneType | 17 | +| b_condition.py:20 | ControlFlowNode for None | NoneType None | builtin-class NoneType | 20 | +| b_condition.py:20 | ControlFlowNode for x | NoneType None | builtin-class NoneType | 20 | +| b_condition.py:21 | ControlFlowNode for x | NoneType None | builtin-class NoneType | 20 | +| b_condition.py:23 | ControlFlowNode for IfExp | NoneType None | builtin-class NoneType | 23 | +| b_condition.py:23 | ControlFlowNode for None | NoneType None | builtin-class NoneType | 23 | +| b_condition.py:23 | ControlFlowNode for x | NoneType None | builtin-class NoneType | 23 | +| b_condition.py:25 | ControlFlowNode for IfExp | int 1 | builtin-class int | 25 | +| b_condition.py:25 | ControlFlowNode for IntegerLiteral | int 1 | builtin-class int | 25 | +| b_condition.py:25 | ControlFlowNode for x | NoneType None | builtin-class NoneType | 23 | +| b_condition.py:25 | ControlFlowNode for x | int 1 | builtin-class int | 25 | +| b_condition.py:26 | ControlFlowNode for x | int 1 | builtin-class int | 25 | +| b_condition.py:28 | ControlFlowNode for IntegerLiteral | int 1 | builtin-class int | 28 | +| b_condition.py:28 | ControlFlowNode for x | int 1 | builtin-class int | 28 | +| b_condition.py:29 | ControlFlowNode for x | int 1 | builtin-class int | 25 | +| b_condition.py:29 | ControlFlowNode for x | int 1 | builtin-class int | 28 | +| b_condition.py:31 | ControlFlowNode for IfExp | int 1 | builtin-class int | 31 | +| b_condition.py:31 | ControlFlowNode for IntegerLiteral | int 1 | builtin-class int | 31 | +| b_condition.py:31 | ControlFlowNode for x | int 1 | builtin-class int | 31 | +| b_condition.py:32 | ControlFlowNode for UnaryExpr | bool False | builtin-class bool | 32 | +| b_condition.py:32 | ControlFlowNode for UnaryExpr | bool True | builtin-class bool | 32 | +| b_condition.py:32 | ControlFlowNode for x | int 1 | builtin-class int | 31 | +| b_condition.py:33 | ControlFlowNode for IntegerLiteral | int 7 | builtin-class int | 33 | +| b_condition.py:33 | ControlFlowNode for x | int 7 | builtin-class int | 33 | +| b_condition.py:34 | ControlFlowNode for x | int 1 | builtin-class int | 31 | +| b_condition.py:34 | ControlFlowNode for x | int 7 | builtin-class int | 33 | +| b_condition.py:36 | ControlFlowNode for int | builtin-class int | builtin-class type | 36 | +| b_condition.py:36 | ControlFlowNode for isinstance | Builtin-function isinstance | builtin-class builtin_function_or_method | 36 | +| b_condition.py:36 | ControlFlowNode for isinstance() | bool False | builtin-class bool | 36 | +| b_condition.py:36 | ControlFlowNode for isinstance() | bool True | builtin-class bool | 36 | +| b_condition.py:36 | ControlFlowNode for x | int 1 | builtin-class int | 31 | +| b_condition.py:36 | ControlFlowNode for x | int 7 | builtin-class int | 33 | +| b_condition.py:37 | ControlFlowNode for x | int 1 | builtin-class int | 31 | +| b_condition.py:37 | ControlFlowNode for x | int 7 | builtin-class int | 33 | +| b_condition.py:41 | ControlFlowNode for Attribute | int 1 | builtin-class int | 41 | +| b_condition.py:41 | ControlFlowNode for IntegerLiteral | int 1 | builtin-class int | 41 | +| b_condition.py:42 | ControlFlowNode for Compare | bool False | builtin-class bool | 42 | +| b_condition.py:42 | ControlFlowNode for Compare | bool True | builtin-class bool | 42 | +| b_condition.py:42 | ControlFlowNode for None | NoneType None | builtin-class NoneType | 42 | +| b_condition.py:43 | ControlFlowNode for Attribute | int 1 | builtin-class int | 41 | +| b_condition.py:50 | ControlFlowNode for FunctionExpr | Function g | builtin-class function | 50 | +| b_condition.py:50 | ControlFlowNode for g | Function g | builtin-class function | 50 | +| b_condition.py:55 | ControlFlowNode for FunctionExpr | Function loop | builtin-class function | 55 | +| b_condition.py:55 | ControlFlowNode for loop | Function loop | builtin-class function | 55 | +| b_condition.py:61 | ControlFlowNode for FunctionExpr | Function double_attr_check | builtin-class function | 61 | +| b_condition.py:61 | ControlFlowNode for double_attr_check | Function double_attr_check | builtin-class function | 61 | +| b_condition.py:62 | ControlFlowNode for Compare | bool False | builtin-class bool | 62 | +| b_condition.py:62 | ControlFlowNode for Compare | bool True | builtin-class bool | 62 | +| b_condition.py:62 | ControlFlowNode for IntegerLiteral | int 3 | builtin-class int | 62 | +| b_condition.py:65 | ControlFlowNode for Compare | bool False | builtin-class bool | 65 | +| b_condition.py:65 | ControlFlowNode for Compare | bool True | builtin-class bool | 65 | +| b_condition.py:65 | ControlFlowNode for IntegerLiteral | int 0 | builtin-class int | 65 | +| b_condition.py:66 | ControlFlowNode for Compare | bool False | builtin-class bool | 66 | +| b_condition.py:66 | ControlFlowNode for Compare | bool True | builtin-class bool | 66 | +| b_condition.py:69 | ControlFlowNode for FunctionExpr | Function h | builtin-class function | 69 | +| b_condition.py:69 | ControlFlowNode for h | Function h | builtin-class function | 69 | +| b_condition.py:70 | ControlFlowNode for IfExp | bool True | builtin-class bool | 70 | +| b_condition.py:70 | ControlFlowNode for True | bool True | builtin-class bool | 70 | +| b_condition.py:70 | ControlFlowNode for b | bool True | builtin-class bool | 70 | +| b_condition.py:71 | ControlFlowNode for UnaryExpr | bool False | builtin-class bool | 71 | +| b_condition.py:71 | ControlFlowNode for UnaryExpr | bool True | builtin-class bool | 71 | +| b_condition.py:71 | ControlFlowNode for b | bool True | builtin-class bool | 70 | +| b_condition.py:72 | ControlFlowNode for IntegerLiteral | int 7 | builtin-class int | 72 | +| b_condition.py:72 | ControlFlowNode for b | int 7 | builtin-class int | 72 | +| b_condition.py:73 | ControlFlowNode for b | bool True | builtin-class bool | 70 | +| b_condition.py:73 | ControlFlowNode for b | int 7 | builtin-class int | 72 | +| b_condition.py:75 | ControlFlowNode for FunctionExpr | Function k | builtin-class function | 75 | +| b_condition.py:75 | ControlFlowNode for k | Function k | builtin-class function | 75 | +| b_condition.py:76 | ControlFlowNode for t | builtin-class type | builtin-class type | 76 | +| b_condition.py:76 | ControlFlowNode for type | builtin-class type | builtin-class type | 76 | +| b_condition.py:77 | ControlFlowNode for Compare | bool True | builtin-class bool | 77 | +| b_condition.py:77 | ControlFlowNode for object | builtin-class object | builtin-class type | 77 | +| b_condition.py:77 | ControlFlowNode for t | builtin-class type | builtin-class type | 76 | +| b_condition.py:78 | ControlFlowNode for object | builtin-class object | builtin-class type | 78 | +| b_condition.py:78 | ControlFlowNode for t | builtin-class object | builtin-class type | 78 | +| b_condition.py:79 | ControlFlowNode for t | builtin-class object | builtin-class type | 78 | +| b_condition.py:81 | ControlFlowNode for FunctionExpr | Function odasa6261 | builtin-class function | 81 | +| b_condition.py:81 | ControlFlowNode for True | bool True | builtin-class bool | 81 | +| b_condition.py:81 | ControlFlowNode for odasa6261 | Function odasa6261 | builtin-class function | 81 | +| b_condition.py:82 | ControlFlowNode for callable | Builtin-function callable | builtin-class builtin_function_or_method | 82 | +| b_condition.py:82 | ControlFlowNode for callable() | bool False | builtin-class bool | 82 | +| b_condition.py:82 | ControlFlowNode for callable() | bool True | builtin-class bool | 82 | +| b_condition.py:82 | ControlFlowNode for foo | bool True | builtin-class bool | 81 | +| b_condition.py:83 | ControlFlowNode for FunctionExpr | Function bar | builtin-class function | 83 | +| b_condition.py:83 | ControlFlowNode for bar | Function bar | builtin-class function | 83 | +| b_condition.py:87 | ControlFlowNode for FunctionExpr | Function split_bool1 | builtin-class function | 87 | +| b_condition.py:87 | ControlFlowNode for None | NoneType None | builtin-class NoneType | 87 | +| b_condition.py:87 | ControlFlowNode for split_bool1 | Function split_bool1 | builtin-class function | 87 | +| b_condition.py:88 | ControlFlowNode for x | NoneType None | builtin-class NoneType | 87 | +| b_condition.py:88 | ControlFlowNode for y | NoneType None | builtin-class NoneType | 87 | +| b_condition.py:90 | ControlFlowNode for x | NoneType None | builtin-class NoneType | 87 | +| b_condition.py:90 | ControlFlowNode for y | NoneType None | builtin-class NoneType | 87 | +| b_condition.py:92 | ControlFlowNode for x | NoneType None | builtin-class NoneType | 87 | +| b_condition.py:93 | ControlFlowNode for y | NoneType None | builtin-class NoneType | 87 | +| b_condition.py:96 | ControlFlowNode for y | NoneType None | builtin-class NoneType | 87 | +| b_condition.py:97 | ControlFlowNode for x | NoneType None | builtin-class NoneType | 87 | +| b_condition.py:101 | ControlFlowNode for FunctionExpr | Function not_or_not | builtin-class function | 101 | +| b_condition.py:101 | ControlFlowNode for a | a | builtin-class tuple | 101 | +| b_condition.py:101 | ControlFlowNode for not_or_not | Function not_or_not | builtin-class function | 101 | +| b_condition.py:102 | ControlFlowNode for Tuple | Tuple | builtin-class tuple | 102 | +| b_condition.py:102 | ControlFlowNode for UnaryExpr | bool False | builtin-class bool | 102 | +| b_condition.py:102 | ControlFlowNode for UnaryExpr | bool True | builtin-class bool | 102 | +| b_condition.py:102 | ControlFlowNode for a | a | builtin-class tuple | 101 | +| b_condition.py:102 | ControlFlowNode for isinstance | Builtin-function isinstance | builtin-class builtin_function_or_method | 102 | +| b_condition.py:102 | ControlFlowNode for isinstance() | bool False | builtin-class bool | 102 | +| b_condition.py:102 | ControlFlowNode for isinstance() | bool True | builtin-class bool | 102 | +| b_condition.py:102 | ControlFlowNode for list | builtin-class list | builtin-class type | 102 | +| b_condition.py:102 | ControlFlowNode for tuple | builtin-class tuple | builtin-class type | 102 | +| b_condition.py:103 | ControlFlowNode for TypeError | builtin-class TypeError | builtin-class type | 103 | +| b_condition.py:103 | ControlFlowNode for TypeError() | TypeError() | builtin-class TypeError | 103 | +| b_condition.py:104 | ControlFlowNode for UnaryExpr | bool False | builtin-class bool | 104 | +| b_condition.py:104 | ControlFlowNode for UnaryExpr | bool True | builtin-class bool | 104 | +| b_condition.py:104 | ControlFlowNode for a | a | builtin-class tuple | 101 | +| b_condition.py:105 | ControlFlowNode for IntegerLiteral | int 0 | builtin-class int | 105 | +| b_condition.py:105 | ControlFlowNode for UnaryExpr | bool False | builtin-class bool | 105 | +| b_condition.py:105 | ControlFlowNode for UnaryExpr | bool True | builtin-class bool | 105 | +| b_condition.py:105 | ControlFlowNode for a | a | builtin-class tuple | 101 | +| b_condition.py:106 | ControlFlowNode for Exception | builtin-class Exception | builtin-class type | 106 | +| b_condition.py:106 | ControlFlowNode for Exception() | Exception() | builtin-class Exception | 106 | +| b_condition.py:107 | ControlFlowNode for Str | 'Hello' | builtin-class str | 107 | +| d_globals.py:2 | ControlFlowNode for FunctionExpr | Function j | builtin-class function | 2 | +| d_globals.py:2 | ControlFlowNode for j | Function j | builtin-class function | 2 | +| d_globals.py:3 | ControlFlowNode for Tuple | Tuple | builtin-class tuple | 3 | +| d_globals.py:3 | ControlFlowNode for dict | int 7 | builtin-class int | 5 | +| d_globals.py:3 | ControlFlowNode for tuple | builtin-class tuple | builtin-class type | 7 | +| d_globals.py:4 | ControlFlowNode for dict | builtin-class dict | builtin-class type | 4 | +| d_globals.py:5 | ControlFlowNode for IntegerLiteral | int 7 | builtin-class int | 5 | +| d_globals.py:5 | ControlFlowNode for dict | int 7 | builtin-class int | 5 | +| d_globals.py:6 | ControlFlowNode for dict | int 7 | builtin-class int | 5 | +| d_globals.py:7 | ControlFlowNode for tuple | builtin-class tuple | builtin-class type | 7 | +| d_globals.py:8 | ControlFlowNode for tuple | builtin-class tuple | builtin-class type | 7 | +| d_globals.py:14 | ControlFlowNode for None | NoneType None | builtin-class NoneType | 14 | +| d_globals.py:14 | ControlFlowNode for g1 | NoneType None | builtin-class NoneType | 14 | +| d_globals.py:16 | ControlFlowNode for FunctionExpr | Function assign_global | builtin-class function | 16 | +| d_globals.py:16 | ControlFlowNode for assign_global | Function assign_global | builtin-class function | 16 | +| d_globals.py:18 | ControlFlowNode for IntegerLiteral | int 101 | builtin-class int | 18 | +| d_globals.py:18 | ControlFlowNode for g1 | int 101 | builtin-class int | 18 | +| d_globals.py:19 | ControlFlowNode for g1 | int 101 | builtin-class int | 18 | +| d_globals.py:23 | ControlFlowNode for None | NoneType None | builtin-class NoneType | 23 | +| d_globals.py:23 | ControlFlowNode for g2 | NoneType None | builtin-class NoneType | 23 | +| d_globals.py:25 | ControlFlowNode for FunctionExpr | Function init | builtin-class function | 25 | +| d_globals.py:25 | ControlFlowNode for init | Function init | builtin-class function | 25 | +| d_globals.py:27 | ControlFlowNode for IntegerLiteral | int 102 | builtin-class int | 27 | +| d_globals.py:27 | ControlFlowNode for g2 | int 102 | builtin-class int | 27 | +| d_globals.py:29 | ControlFlowNode for init | Function init | builtin-class function | 25 | +| d_globals.py:29 | ControlFlowNode for init() | NoneType None | builtin-class NoneType | 25 | +| d_globals.py:30 | ControlFlowNode for g2 | int 102 | builtin-class int | 27 | +| d_globals.py:33 | ControlFlowNode for None | NoneType None | builtin-class NoneType | 33 | +| d_globals.py:33 | ControlFlowNode for g3 | NoneType None | builtin-class NoneType | 33 | +| d_globals.py:35 | ControlFlowNode for ClassExpr | class Ugly | builtin-class type | 35 | +| d_globals.py:35 | ControlFlowNode for Ugly | class Ugly | builtin-class type | 35 | +| d_globals.py:35 | ControlFlowNode for object | builtin-class object | builtin-class type | 35 | +| d_globals.py:37 | ControlFlowNode for FunctionExpr | Function __init__ | builtin-class function | 37 | +| d_globals.py:37 | ControlFlowNode for __init__ | Function __init__ | builtin-class function | 37 | +| d_globals.py:39 | ControlFlowNode for IntegerLiteral | int 103 | builtin-class int | 39 | +| d_globals.py:39 | ControlFlowNode for g3 | int 103 | builtin-class int | 39 | +| d_globals.py:41 | ControlFlowNode for FunctionExpr | Function meth | builtin-class function | 41 | +| d_globals.py:41 | ControlFlowNode for meth | Function meth | builtin-class function | 41 | +| d_globals.py:42 | ControlFlowNode for g3 | int 103 | builtin-class int | 39 | +| d_globals.py:45 | ControlFlowNode for IntegerLiteral | int 0 | builtin-class int | 45 | +| d_globals.py:45 | ControlFlowNode for x | int 0 | builtin-class int | 45 | +| d_globals.py:46 | ControlFlowNode for IntegerLiteral | int 1 | builtin-class int | 46 | +| d_globals.py:46 | ControlFlowNode for x | int 1 | builtin-class int | 46 | +| d_globals.py:47 | ControlFlowNode for x | int 1 | builtin-class int | 46 | +| d_globals.py:49 | ControlFlowNode for IntegerLiteral | int 3 | builtin-class int | 49 | +| d_globals.py:49 | ControlFlowNode for x | int 3 | builtin-class int | 49 | +| d_globals.py:52 | ControlFlowNode for IntegerLiteral | int 1 | builtin-class int | 52 | +| d_globals.py:52 | ControlFlowNode for y | int 1 | builtin-class int | 52 | +| d_globals.py:54 | ControlFlowNode for IntegerLiteral | int 2 | builtin-class int | 54 | +| d_globals.py:54 | ControlFlowNode for y | int 2 | builtin-class int | 54 | +| d_globals.py:59 | ControlFlowNode for y | int 1 | builtin-class int | 52 | +| d_globals.py:59 | ControlFlowNode for y | int 2 | builtin-class int | 54 | +| d_globals.py:62 | ControlFlowNode for ClassExpr | class X | builtin-class type | 62 | +| d_globals.py:62 | ControlFlowNode for X | class X | builtin-class type | 62 | +| d_globals.py:62 | ControlFlowNode for object | builtin-class object | builtin-class type | 62 | +| d_globals.py:63 | ControlFlowNode for y | int 1 | builtin-class int | 52 | +| d_globals.py:63 | ControlFlowNode for y | int 2 | builtin-class int | 54 | +| d_globals.py:66 | ControlFlowNode for g3 | NoneType None | builtin-class NoneType | 33 | +| d_globals.py:68 | ControlFlowNode for type | builtin-class type | builtin-class type | 68 | +| d_globals.py:70 | ControlFlowNode for FunctionExpr | Function k | builtin-class function | 70 | +| d_globals.py:70 | ControlFlowNode for k | Function k | builtin-class function | 70 | +| d_globals.py:71 | ControlFlowNode for type | builtin-class type | builtin-class type | 71 | +| d_globals.py:73 | ControlFlowNode for None | NoneType None | builtin-class NoneType | 73 | +| d_globals.py:73 | ControlFlowNode for g4 | NoneType None | builtin-class NoneType | 73 | +| d_globals.py:75 | ControlFlowNode for FunctionExpr | Function get_g4 | builtin-class function | 75 | +| d_globals.py:75 | ControlFlowNode for get_g4 | Function get_g4 | builtin-class function | 75 | +| d_globals.py:76 | ControlFlowNode for UnaryExpr | bool True | builtin-class bool | 76 | +| d_globals.py:76 | ControlFlowNode for g4 | NoneType None | builtin-class NoneType | 73 | +| d_globals.py:77 | ControlFlowNode for set_g4 | Function set_g4 | builtin-class function | 80 | +| d_globals.py:77 | ControlFlowNode for set_g4() | NoneType None | builtin-class NoneType | 80 | +| d_globals.py:78 | ControlFlowNode for g4 | bool False | builtin-class bool | 85 | +| d_globals.py:80 | ControlFlowNode for FunctionExpr | Function set_g4 | builtin-class function | 80 | +| d_globals.py:80 | ControlFlowNode for set_g4 | Function set_g4 | builtin-class function | 80 | +| d_globals.py:81 | ControlFlowNode for set_g4_indirect | Function set_g4_indirect | builtin-class function | 83 | +| d_globals.py:81 | ControlFlowNode for set_g4_indirect() | NoneType None | builtin-class NoneType | 83 | +| d_globals.py:83 | ControlFlowNode for FunctionExpr | Function set_g4_indirect | builtin-class function | 83 | +| d_globals.py:83 | ControlFlowNode for set_g4_indirect | Function set_g4_indirect | builtin-class function | 83 | +| d_globals.py:85 | ControlFlowNode for False | bool False | builtin-class bool | 85 | +| d_globals.py:85 | ControlFlowNode for g4 | bool False | builtin-class bool | 85 | +| d_globals.py:87 | ControlFlowNode for ClassExpr | class modinit | builtin-class type | 87 | +| d_globals.py:87 | ControlFlowNode for modinit | class modinit | builtin-class type | 87 | +| d_globals.py:87 | ControlFlowNode for object | builtin-class object | builtin-class type | 87 | +| d_globals.py:90 | ControlFlowNode for IntegerLiteral | int 0 | builtin-class int | 90 | +| d_globals.py:90 | ControlFlowNode for z | int 0 | builtin-class int | 90 | +| d_globals.py:95 | ControlFlowNode for FunctionExpr | Function outer | builtin-class function | 95 | +| d_globals.py:95 | ControlFlowNode for outer | Function outer | builtin-class function | 95 | +| d_globals.py:96 | ControlFlowNode for FunctionExpr | Function inner | builtin-class function | 96 | +| d_globals.py:96 | ControlFlowNode for inner | Function inner | builtin-class function | 96 | +| d_globals.py:98 | ControlFlowNode for IntegerLiteral | int 100 | builtin-class int | 98 | +| d_globals.py:98 | ControlFlowNode for glob | int 100 | builtin-class int | 98 | +| d_globals.py:99 | ControlFlowNode for glob | int 100 | builtin-class int | 98 | +| d_globals.py:101 | ControlFlowNode for FunctionExpr | Function otherInner | builtin-class function | 101 | +| d_globals.py:101 | ControlFlowNode for otherInner | Function otherInner | builtin-class function | 101 | +| d_globals.py:104 | ControlFlowNode for inner | Function inner | builtin-class function | 96 | +| d_globals.py:104 | ControlFlowNode for inner() | int 100 | builtin-class int | 98 | +| d_globals.py:107 | ControlFlowNode for FunctionExpr | Function redefine | builtin-class function | 107 | +| d_globals.py:107 | ControlFlowNode for redefine | Function redefine | builtin-class function | 107 | +| d_globals.py:110 | ControlFlowNode for IntegerLiteral | int 1 | builtin-class int | 110 | +| d_globals.py:110 | ControlFlowNode for z | int 1 | builtin-class int | 110 | +| d_globals.py:111 | ControlFlowNode for z | int 1 | builtin-class int | 110 | +| d_globals.py:113 | ControlFlowNode for IntegerLiteral | int 50 | builtin-class int | 113 | +| d_globals.py:113 | ControlFlowNode for glob | int 50 | builtin-class int | 113 | +| d_globals.py:114 | ControlFlowNode for glob | int 50 | builtin-class int | 113 | +| d_globals.py:118 | ControlFlowNode for ClassExpr | class D | builtin-class type | 118 | +| d_globals.py:118 | ControlFlowNode for D | class D | builtin-class type | 118 | +| d_globals.py:118 | ControlFlowNode for object | builtin-class object | builtin-class type | 118 | +| d_globals.py:120 | ControlFlowNode for FunctionExpr | Function __init__ | builtin-class function | 120 | +| d_globals.py:120 | ControlFlowNode for __init__ | Function __init__ | builtin-class function | 120 | +| d_globals.py:123 | ControlFlowNode for FunctionExpr | Function foo | builtin-class function | 123 | +| d_globals.py:123 | ControlFlowNode for foo | Function foo | builtin-class function | 123 | +| d_globals.py:124 | ControlFlowNode for dict | int 7 | builtin-class int | 5 | +| d_globals.py:126 | ControlFlowNode for FunctionExpr | Function use_list_attribute | builtin-class function | 126 | +| d_globals.py:126 | ControlFlowNode for use_list_attribute | Function use_list_attribute | builtin-class function | 126 | +| d_globals.py:127 | ControlFlowNode for List | List | builtin-class list | 127 | +| d_globals.py:127 | ControlFlowNode for l | List | builtin-class list | 127 | +| d_globals.py:128 | ControlFlowNode for Attribute | Builtin-method append | builtin-class method_descriptor | 128 | +| d_globals.py:128 | ControlFlowNode for Attribute() | NoneType None | builtin-class NoneType | 128 | +| d_globals.py:128 | ControlFlowNode for IntegerLiteral | int 0 | builtin-class int | 128 | +| d_globals.py:128 | ControlFlowNode for l | List | builtin-class list | 127 | +| d_globals.py:128 | ControlFlowNode for list | builtin-class list | builtin-class type | 128 | +| d_globals.py:129 | ControlFlowNode for l | List | builtin-class list | 127 | +| e_temporal.py:2 | ControlFlowNode for ImportExpr | Module sys | builtin-class module | 2 | +| e_temporal.py:2 | ControlFlowNode for sys | Module sys | builtin-class module | 2 | +| e_temporal.py:4 | ControlFlowNode for FunctionExpr | Function f | builtin-class function | 4 | +| e_temporal.py:4 | ControlFlowNode for f | Function f | builtin-class function | 4 | +| e_temporal.py:5 | ControlFlowNode for Attribute | list object | builtin-class list | 5 | +| e_temporal.py:5 | ControlFlowNode for Compare | bool False | builtin-class bool | 5 | +| e_temporal.py:5 | ControlFlowNode for Compare | bool True | builtin-class bool | 5 | +| e_temporal.py:5 | ControlFlowNode for IntegerLiteral | int 3 | builtin-class int | 5 | +| e_temporal.py:5 | ControlFlowNode for len | Builtin-function len | builtin-class builtin_function_or_method | 5 | +| e_temporal.py:5 | ControlFlowNode for len() | len() | builtin-class int | 5 | +| e_temporal.py:5 | ControlFlowNode for sys | Module sys | builtin-class module | 2 | +| e_temporal.py:7 | ControlFlowNode for IntegerLiteral | int 1 | builtin-class int | 7 | +| e_temporal.py:9 | ControlFlowNode for FunctionExpr | Function g | builtin-class function | 9 | +| e_temporal.py:9 | ControlFlowNode for g | Function g | builtin-class function | 9 | +| e_temporal.py:10 | ControlFlowNode for arg | int 1 | builtin-class int | 7 | +| e_temporal.py:12 | ControlFlowNode for f | Function f | builtin-class function | 4 | +| e_temporal.py:12 | ControlFlowNode for f() | int 1 | builtin-class int | 7 | +| e_temporal.py:12 | ControlFlowNode for g | Function g | builtin-class function | 9 | +| e_temporal.py:12 | ControlFlowNode for g() | int 1 | builtin-class int | 7 | +| e_temporal.py:12 | ControlFlowNode for x | int 1 | builtin-class int | 7 | +| g_class_init.py:3 | ControlFlowNode for C | class C | builtin-class type | 3 | +| g_class_init.py:3 | ControlFlowNode for ClassExpr | class C | builtin-class type | 3 | +| g_class_init.py:3 | ControlFlowNode for object | builtin-class object | builtin-class type | 3 | +| g_class_init.py:5 | ControlFlowNode for FunctionExpr | Function __init__ | builtin-class function | 5 | +| g_class_init.py:5 | ControlFlowNode for __init__ | Function __init__ | builtin-class function | 5 | +| g_class_init.py:6 | ControlFlowNode for Attribute() | NoneType None | builtin-class NoneType | 9 | +| g_class_init.py:6 | ControlFlowNode for self | self | class C | 5 | +| g_class_init.py:7 | ControlFlowNode for Attribute | int 1 | builtin-class int | 7 | +| g_class_init.py:7 | ControlFlowNode for IntegerLiteral | int 1 | builtin-class int | 7 | +| g_class_init.py:7 | ControlFlowNode for self | self | class C | 5 | +| g_class_init.py:9 | ControlFlowNode for FunctionExpr | Function _init | builtin-class function | 9 | +| g_class_init.py:9 | ControlFlowNode for _init | Function _init | builtin-class function | 9 | +| g_class_init.py:10 | ControlFlowNode for Attribute | int 2 | builtin-class int | 10 | +| g_class_init.py:10 | ControlFlowNode for IntegerLiteral | int 2 | builtin-class int | 10 | +| g_class_init.py:10 | ControlFlowNode for self | self | class C | 5 | +| g_class_init.py:11 | ControlFlowNode for Attribute() | NoneType None | builtin-class NoneType | 13 | +| g_class_init.py:11 | ControlFlowNode for self | self | class C | 5 | +| g_class_init.py:13 | ControlFlowNode for FunctionExpr | Function _init2 | builtin-class function | 13 | +| g_class_init.py:13 | ControlFlowNode for _init2 | Function _init2 | builtin-class function | 13 | +| g_class_init.py:14 | ControlFlowNode for Attribute | int 3 | builtin-class int | 14 | +| g_class_init.py:14 | ControlFlowNode for IntegerLiteral | int 3 | builtin-class int | 14 | +| g_class_init.py:14 | ControlFlowNode for self | self | class C | 5 | +| g_class_init.py:16 | ControlFlowNode for FunctionExpr | Function method | builtin-class function | 16 | +| g_class_init.py:16 | ControlFlowNode for method | Function method | builtin-class function | 16 | +| g_class_init.py:17 | ControlFlowNode for Attribute | int 1 | builtin-class int | 7 | +| g_class_init.py:17 | ControlFlowNode for self | self | class C | 16 | +| g_class_init.py:18 | ControlFlowNode for Attribute | int 2 | builtin-class int | 10 | +| g_class_init.py:18 | ControlFlowNode for int | builtin-class int | builtin-class type | 18 | +| g_class_init.py:18 | ControlFlowNode for isinstance | Builtin-function isinstance | builtin-class builtin_function_or_method | 18 | +| g_class_init.py:18 | ControlFlowNode for isinstance() | bool True | builtin-class bool | 18 | +| g_class_init.py:18 | ControlFlowNode for self | self | class C | 16 | +| g_class_init.py:19 | ControlFlowNode for Attribute | int 2 | builtin-class int | 10 | +| g_class_init.py:19 | ControlFlowNode for self | self | class C | 16 | +| g_class_init.py:20 | ControlFlowNode for Attribute | int 3 | builtin-class int | 14 | +| g_class_init.py:20 | ControlFlowNode for self | self | class C | 16 | +| g_class_init.py:24 | ControlFlowNode for ClassExpr | class Oddities | builtin-class type | 24 | +| g_class_init.py:24 | ControlFlowNode for Oddities | class Oddities | builtin-class type | 24 | +| g_class_init.py:24 | ControlFlowNode for object | builtin-class object | builtin-class type | 24 | +| g_class_init.py:26 | ControlFlowNode for int | builtin-class int | builtin-class type | 26 | +| g_class_init.py:27 | ControlFlowNode for float | builtin-class float | builtin-class type | 27 | +| g_class_init.py:28 | ControlFlowNode for l | Builtin-function len | builtin-class builtin_function_or_method | 28 | +| g_class_init.py:28 | ControlFlowNode for len | Builtin-function len | builtin-class builtin_function_or_method | 28 | +| g_class_init.py:29 | ControlFlowNode for h | Builtin-function hash | builtin-class builtin_function_or_method | 29 | +| g_class_init.py:29 | ControlFlowNode for hash | Builtin-function hash | builtin-class builtin_function_or_method | 29 | +| g_class_init.py:32 | ControlFlowNode for ClassExpr | class D | builtin-class type | 32 | +| g_class_init.py:32 | ControlFlowNode for D | class D | builtin-class type | 32 | +| g_class_init.py:32 | ControlFlowNode for object | builtin-class object | builtin-class type | 32 | +| g_class_init.py:34 | ControlFlowNode for FunctionExpr | Function __init__ | builtin-class function | 34 | +| g_class_init.py:34 | ControlFlowNode for __init__ | Function __init__ | builtin-class function | 34 | +| g_class_init.py:35 | ControlFlowNode for Attribute | super().x | builtin-class method | 35 | +| g_class_init.py:35 | ControlFlowNode for D | class D | builtin-class type | 32 | +| g_class_init.py:35 | ControlFlowNode for self | self | class D | 34 | +| g_class_init.py:35 | ControlFlowNode for super | builtin-class super | builtin-class type | 35 | +| g_class_init.py:35 | ControlFlowNode for super() | super() | builtin-class super | 35 | +| g_class_init.py:36 | ControlFlowNode for Attribute | super().__init__ | builtin-class method | 36 | +| g_class_init.py:36 | ControlFlowNode for D | class D | builtin-class type | 32 | +| g_class_init.py:36 | ControlFlowNode for self | self | class D | 34 | +| g_class_init.py:36 | ControlFlowNode for super | builtin-class super | builtin-class type | 36 | +| g_class_init.py:36 | ControlFlowNode for super() | super() | builtin-class super | 36 | +| g_class_init.py:42 | ControlFlowNode for Str | 'v2' | builtin-class str | 42 | +| g_class_init.py:42 | ControlFlowNode for V2 | 'v2' | builtin-class str | 42 | +| g_class_init.py:43 | ControlFlowNode for Str | 'v3' | builtin-class str | 43 | +| g_class_init.py:43 | ControlFlowNode for V3 | 'v3' | builtin-class str | 43 | +| g_class_init.py:45 | ControlFlowNode for ClassExpr | class E | builtin-class type | 45 | +| g_class_init.py:45 | ControlFlowNode for E | class E | builtin-class type | 45 | +| g_class_init.py:45 | ControlFlowNode for object | builtin-class object | builtin-class type | 45 | +| g_class_init.py:46 | ControlFlowNode for FunctionExpr | Function __init__ | builtin-class function | 46 | +| g_class_init.py:46 | ControlFlowNode for __init__ | Function __init__ | builtin-class function | 46 | +| g_class_init.py:48 | ControlFlowNode for Attribute | 'v2' | builtin-class str | 42 | +| g_class_init.py:48 | ControlFlowNode for V2 | 'v2' | builtin-class str | 42 | +| g_class_init.py:48 | ControlFlowNode for self | self | class E | 46 | +| g_class_init.py:50 | ControlFlowNode for Attribute | 'v3' | builtin-class str | 43 | +| g_class_init.py:50 | ControlFlowNode for V3 | 'v3' | builtin-class str | 43 | +| g_class_init.py:50 | ControlFlowNode for self | self | class E | 46 | +| g_class_init.py:52 | ControlFlowNode for FunctionExpr | Function meth | builtin-class function | 52 | +| g_class_init.py:52 | ControlFlowNode for meth | Function meth | builtin-class function | 52 | +| g_class_init.py:53 | ControlFlowNode for Attribute | 'v2' | builtin-class str | 42 | +| g_class_init.py:53 | ControlFlowNode for Attribute | 'v3' | builtin-class str | 43 | +| g_class_init.py:53 | ControlFlowNode for Compare | bool False | builtin-class bool | 53 | +| g_class_init.py:53 | ControlFlowNode for Compare | bool True | builtin-class bool | 53 | +| g_class_init.py:53 | ControlFlowNode for V2 | 'v2' | builtin-class str | 42 | +| g_class_init.py:53 | ControlFlowNode for self | self | class E | 52 | +| h_classes.py:1 | ControlFlowNode for ImportExpr | Module sys | builtin-class module | 1 | +| h_classes.py:1 | ControlFlowNode for sys | Module sys | builtin-class module | 1 | +| h_classes.py:3 | ControlFlowNode for C | class C | builtin-class type | 3 | +| h_classes.py:3 | ControlFlowNode for ClassExpr | class C | builtin-class type | 3 | +| h_classes.py:3 | ControlFlowNode for object | builtin-class object | builtin-class type | 3 | +| h_classes.py:5 | ControlFlowNode for Str | 'C_x' | builtin-class str | 5 | +| h_classes.py:5 | ControlFlowNode for x | 'C_x' | builtin-class str | 5 | +| h_classes.py:7 | ControlFlowNode for FunctionExpr | Function __init__ | builtin-class function | 7 | +| h_classes.py:7 | ControlFlowNode for __init__ | Function __init__ | builtin-class function | 7 | +| h_classes.py:8 | ControlFlowNode for Attribute | 'c_y' | builtin-class str | 8 | +| h_classes.py:8 | ControlFlowNode for Str | 'c_y' | builtin-class str | 8 | +| h_classes.py:8 | ControlFlowNode for self | self | class C | 7 | +| h_classes.py:10 | ControlFlowNode for C | class C | builtin-class type | 3 | +| h_classes.py:10 | ControlFlowNode for C() | C() | class C | 10 | +| h_classes.py:10 | ControlFlowNode for type | builtin-class type | builtin-class type | 10 | +| h_classes.py:10 | ControlFlowNode for type() | class C | builtin-class type | 3 | +| h_classes.py:11 | ControlFlowNode for sys | Module sys | builtin-class module | 1 | +| h_classes.py:11 | ControlFlowNode for type | builtin-class type | builtin-class type | 11 | +| h_classes.py:11 | ControlFlowNode for type() | builtin-class module | builtin-class type | 11 | +| h_classes.py:12 | ControlFlowNode for Dict | Dict | builtin-class dict | 12 | +| h_classes.py:12 | ControlFlowNode for Tuple | Tuple | builtin-class tuple | 12 | +| h_classes.py:12 | ControlFlowNode for object | builtin-class object | builtin-class type | 12 | +| h_classes.py:12 | ControlFlowNode for type | builtin-class type | builtin-class type | 12 | +| h_classes.py:14 | ControlFlowNode for FunctionExpr | Function k | builtin-class function | 14 | +| h_classes.py:14 | ControlFlowNode for k | Function k | builtin-class function | 14 | +| h_classes.py:15 | ControlFlowNode for C | class C | builtin-class type | 3 | +| h_classes.py:15 | ControlFlowNode for C() | C() | class C | 15 | +| h_classes.py:15 | ControlFlowNode for type | builtin-class type | builtin-class type | 15 | +| h_classes.py:15 | ControlFlowNode for type() | class C | builtin-class type | 3 | +| h_classes.py:16 | ControlFlowNode for sys | Module sys | builtin-class module | 1 | +| h_classes.py:16 | ControlFlowNode for type | builtin-class type | builtin-class type | 16 | +| h_classes.py:16 | ControlFlowNode for type() | builtin-class module | builtin-class type | 16 | +| h_classes.py:17 | ControlFlowNode for type | builtin-class type | builtin-class type | 17 | +| h_classes.py:17 | ControlFlowNode for type() | *UNKNOWN TYPE* | builtin-class type | 17 | +| h_classes.py:18 | ControlFlowNode for Dict | Dict | builtin-class dict | 18 | +| h_classes.py:18 | ControlFlowNode for Tuple | Tuple | builtin-class tuple | 18 | +| h_classes.py:18 | ControlFlowNode for object | builtin-class object | builtin-class type | 18 | +| h_classes.py:18 | ControlFlowNode for type | builtin-class type | builtin-class type | 18 | +| h_classes.py:23 | ControlFlowNode for Base | class Base | builtin-class type | 23 | +| h_classes.py:23 | ControlFlowNode for ClassExpr | class Base | builtin-class type | 23 | +| h_classes.py:23 | ControlFlowNode for object | builtin-class object | builtin-class type | 23 | +| h_classes.py:25 | ControlFlowNode for FunctionExpr | Function __init__ | builtin-class function | 25 | +| h_classes.py:25 | ControlFlowNode for __init__ | Function __init__ | builtin-class function | 25 | +| h_classes.py:26 | ControlFlowNode for Compare | bool False | builtin-class bool | 26 | +| h_classes.py:26 | ControlFlowNode for Compare | bool True | builtin-class bool | 26 | +| h_classes.py:26 | ControlFlowNode for IntegerLiteral | int 1 | builtin-class int | 26 | +| h_classes.py:27 | ControlFlowNode for Attribute | class Derived1 | builtin-class type | 33 | +| h_classes.py:27 | ControlFlowNode for Derived1 | class Derived1 | builtin-class type | 33 | +| h_classes.py:27 | ControlFlowNode for self | self | class Base | 25 | +| h_classes.py:28 | ControlFlowNode for Compare | bool False | builtin-class bool | 28 | +| h_classes.py:28 | ControlFlowNode for Compare | bool True | builtin-class bool | 28 | +| h_classes.py:28 | ControlFlowNode for IntegerLiteral | int 2 | builtin-class int | 28 | +| h_classes.py:29 | ControlFlowNode for Attribute | class Derived2 | builtin-class type | 36 | +| h_classes.py:29 | ControlFlowNode for Derived2 | class Derived2 | builtin-class type | 36 | +| h_classes.py:29 | ControlFlowNode for self | self | class Base | 25 | +| h_classes.py:31 | ControlFlowNode for Attribute | class Derived3 | builtin-class type | 39 | +| h_classes.py:31 | ControlFlowNode for Derived3 | class Derived3 | builtin-class type | 39 | +| h_classes.py:31 | ControlFlowNode for self | self | class Base | 25 | +| h_classes.py:33 | ControlFlowNode for Base | class Base | builtin-class type | 23 | +| h_classes.py:33 | ControlFlowNode for ClassExpr | class Derived1 | builtin-class type | 33 | +| h_classes.py:33 | ControlFlowNode for Derived1 | class Derived1 | builtin-class type | 33 | +| h_classes.py:36 | ControlFlowNode for Base | class Base | builtin-class type | 23 | +| h_classes.py:36 | ControlFlowNode for ClassExpr | class Derived2 | builtin-class type | 36 | +| h_classes.py:36 | ControlFlowNode for Derived2 | class Derived2 | builtin-class type | 36 | +| h_classes.py:39 | ControlFlowNode for Base | class Base | builtin-class type | 23 | +| h_classes.py:39 | ControlFlowNode for ClassExpr | class Derived3 | builtin-class type | 39 | +| h_classes.py:39 | ControlFlowNode for Derived3 | class Derived3 | builtin-class type | 39 | +| h_classes.py:42 | ControlFlowNode for Base | class Base | builtin-class type | 23 | +| h_classes.py:45 | ControlFlowNode for FunctionExpr | Function f | builtin-class function | 45 | +| h_classes.py:45 | ControlFlowNode for f | Function f | builtin-class function | 45 | +| h_classes.py:48 | ControlFlowNode for ClassExpr | class D | builtin-class type | 48 | +| h_classes.py:48 | ControlFlowNode for D | class D | builtin-class type | 48 | +| h_classes.py:48 | ControlFlowNode for object | builtin-class object | builtin-class type | 48 | +| h_classes.py:50 | ControlFlowNode for f | Function f | builtin-class function | 45 | +| h_classes.py:50 | ControlFlowNode for m | Function f | builtin-class function | 45 | +| h_classes.py:52 | ControlFlowNode for FunctionExpr | Function n | builtin-class function | 52 | +| h_classes.py:52 | ControlFlowNode for n | Function n | builtin-class function | 52 | +| i_imports.py:3 | ControlFlowNode for IntegerLiteral | int 1 | builtin-class int | 3 | +| i_imports.py:3 | ControlFlowNode for a | int 1 | builtin-class int | 3 | +| i_imports.py:4 | ControlFlowNode for IntegerLiteral | int 2 | builtin-class int | 4 | +| i_imports.py:4 | ControlFlowNode for b | int 2 | builtin-class int | 4 | +| i_imports.py:5 | ControlFlowNode for IntegerLiteral | int 3 | builtin-class int | 5 | +| i_imports.py:5 | ControlFlowNode for c | int 3 | builtin-class int | 5 | +| i_imports.py:7 | ControlFlowNode for ImportExpr | Module code.xyz | builtin-class module | 7 | +| i_imports.py:8 | ControlFlowNode for ImportExpr | Module code | builtin-class module | 8 | +| i_imports.py:8 | ControlFlowNode for ImportMember | Module code.xyz | builtin-class module | 0 | +| i_imports.py:8 | ControlFlowNode for xyz | Module code.xyz | builtin-class module | 0 | +| i_imports.py:9 | ControlFlowNode for Attribute | float 1.0 | builtin-class float | 2 | +| i_imports.py:9 | ControlFlowNode for xyz | Module code.xyz | builtin-class module | 0 | +| i_imports.py:10 | ControlFlowNode for z | float 3.0 | builtin-class float | 4 | +| i_imports.py:11 | ControlFlowNode for a | int 1 | builtin-class int | 3 | +| i_imports.py:13 | ControlFlowNode for ImportExpr | Module sys | builtin-class module | 13 | +| i_imports.py:13 | ControlFlowNode for ImportMember | list object | builtin-class list | 13 | +| i_imports.py:13 | ControlFlowNode for argv | list object | builtin-class list | 13 | +| i_imports.py:15 | ControlFlowNode for argv | list object | builtin-class list | 13 | +| i_imports.py:17 | ControlFlowNode for ImportExpr | Module sys | builtin-class module | 17 | +| i_imports.py:17 | ControlFlowNode for sys | Module sys | builtin-class module | 17 | +| i_imports.py:18 | ControlFlowNode for Attribute | list object | builtin-class list | 18 | +| i_imports.py:18 | ControlFlowNode for sys | Module sys | builtin-class module | 17 | +| i_imports.py:23 | ControlFlowNode for ImportExpr | Module code | builtin-class module | 23 | +| i_imports.py:23 | ControlFlowNode for code | Module code | builtin-class module | 23 | +| i_imports.py:24 | ControlFlowNode for Attribute | Module code.package.x | builtin-class module | 0 | +| i_imports.py:24 | ControlFlowNode for code | Module code | builtin-class module | 23 | +| i_imports.py:27 | ControlFlowNode for ImportExpr | Module code.test_package | builtin-class module | 27 | +| i_imports.py:29 | ControlFlowNode for ImportExpr | Module _io | builtin-class module | 29 | +| i_imports.py:29 | ControlFlowNode for _io | Module _io | builtin-class module | 29 | +| i_imports.py:30 | ControlFlowNode for Attribute | builtin-class _io.StringIO | builtin-class type | 30 | +| i_imports.py:30 | ControlFlowNode for StringIO | builtin-class _io.StringIO | builtin-class type | 30 | +| i_imports.py:30 | ControlFlowNode for _io | Module _io | builtin-class module | 29 | +| i_imports.py:31 | ControlFlowNode for Attribute | builtin-class _io.BytesIO | builtin-class type | 31 | +| i_imports.py:31 | ControlFlowNode for BytesIO | builtin-class _io.BytesIO | builtin-class type | 31 | +| i_imports.py:31 | ControlFlowNode for _io | Module _io | builtin-class module | 29 | +| i_imports.py:33 | ControlFlowNode for ImportExpr | Module io | builtin-class module | 33 | +| i_imports.py:33 | ControlFlowNode for io | Module io | builtin-class module | 33 | +| i_imports.py:34 | ControlFlowNode for Attribute | builtin-class _io.StringIO | builtin-class type | 55 | +| i_imports.py:34 | ControlFlowNode for StringIO | builtin-class _io.StringIO | builtin-class type | 55 | +| i_imports.py:34 | ControlFlowNode for io | Module io | builtin-class module | 33 | +| i_imports.py:35 | ControlFlowNode for Attribute | builtin-class _io.BytesIO | builtin-class type | 55 | +| i_imports.py:35 | ControlFlowNode for BytesIO | builtin-class _io.BytesIO | builtin-class type | 55 | +| i_imports.py:35 | ControlFlowNode for io | Module io | builtin-class module | 33 | +| i_imports.py:37 | ControlFlowNode for ImportExpr | Module code | builtin-class module | 37 | +| i_imports.py:37 | ControlFlowNode for code | Module code | builtin-class module | 37 | +| i_imports.py:38 | ControlFlowNode for Attribute | Function f2 | builtin-class function | 24 | +| i_imports.py:38 | ControlFlowNode for Attribute | Module code.n_nesting | builtin-class module | 0 | +| i_imports.py:38 | ControlFlowNode for Attribute() | NoneType None | builtin-class NoneType | 24 | +| i_imports.py:38 | ControlFlowNode for code | Module code | builtin-class module | 37 | +| j_convoluted_imports.py:2 | ControlFlowNode for ImportExpr | Module code.package | builtin-class module | 2 | +| j_convoluted_imports.py:3 | ControlFlowNode for ImportMember | Function module | builtin-class function | 2 | +| j_convoluted_imports.py:3 | ControlFlowNode for module | Function module | builtin-class function | 2 | +| j_convoluted_imports.py:5 | ControlFlowNode for ImportExpr | Module code.package | builtin-class module | 5 | +| j_convoluted_imports.py:6 | ControlFlowNode for ImportMember | Module code.package.x | builtin-class module | 0 | +| j_convoluted_imports.py:6 | ControlFlowNode for x | Module code.package.x | builtin-class module | 0 | +| j_convoluted_imports.py:9 | ControlFlowNode for C | class C | builtin-class type | 9 | +| j_convoluted_imports.py:9 | ControlFlowNode for ClassExpr | class C | builtin-class type | 9 | +| j_convoluted_imports.py:9 | ControlFlowNode for object | builtin-class object | builtin-class type | 9 | +| j_convoluted_imports.py:11 | ControlFlowNode for ImportExpr | Module code.package | builtin-class module | 11 | +| j_convoluted_imports.py:11 | ControlFlowNode for ImportMember | int 7 | builtin-class int | 5 | +| j_convoluted_imports.py:11 | ControlFlowNode for module2 | int 7 | builtin-class int | 5 | +| j_convoluted_imports.py:13 | ControlFlowNode for FunctionExpr | Function f | builtin-class function | 13 | +| j_convoluted_imports.py:13 | ControlFlowNode for f | Function f | builtin-class function | 13 | +| j_convoluted_imports.py:14 | ControlFlowNode for ImportExpr | Module code.package | builtin-class module | 14 | +| j_convoluted_imports.py:14 | ControlFlowNode for ImportMember | Module code.package.x | builtin-class module | 0 | +| j_convoluted_imports.py:14 | ControlFlowNode for x | Module code.package.x | builtin-class module | 0 | +| j_convoluted_imports.py:16 | ControlFlowNode for ImportExpr | Module code.package | builtin-class module | 16 | +| j_convoluted_imports.py:16 | ControlFlowNode for ImportMember | Module code.package.moduleX | builtin-class module | 0 | +| j_convoluted_imports.py:16 | ControlFlowNode for moduleX | Module code.package.moduleX | builtin-class module | 0 | +| j_convoluted_imports.py:17 | ControlFlowNode for Attribute | class Y | builtin-class type | 1 | +| j_convoluted_imports.py:17 | ControlFlowNode for moduleX | Module code.package.moduleX | builtin-class module | 0 | +| k_getsetattr.py:4 | ControlFlowNode for C | class C | builtin-class type | 4 | +| k_getsetattr.py:4 | ControlFlowNode for ClassExpr | class C | builtin-class type | 4 | +| k_getsetattr.py:4 | ControlFlowNode for object | builtin-class object | builtin-class type | 4 | +| k_getsetattr.py:6 | ControlFlowNode for FunctionExpr | Function meth1 | builtin-class function | 6 | +| k_getsetattr.py:6 | ControlFlowNode for meth1 | Function meth1 | builtin-class function | 6 | +| k_getsetattr.py:7 | ControlFlowNode for IntegerLiteral | int 0 | builtin-class int | 7 | +| k_getsetattr.py:7 | ControlFlowNode for Str | 'a' | builtin-class str | 7 | +| k_getsetattr.py:7 | ControlFlowNode for self | self | class C | 6 | +| k_getsetattr.py:7 | ControlFlowNode for self | self | class C | 12 | +| k_getsetattr.py:7 | ControlFlowNode for setattr | Builtin-function setattr | builtin-class builtin_function_or_method | 7 | +| k_getsetattr.py:7 | ControlFlowNode for setattr() | NoneType None | builtin-class NoneType | 7 | +| k_getsetattr.py:8 | ControlFlowNode for IntegerLiteral | int 1 | builtin-class int | 8 | +| k_getsetattr.py:8 | ControlFlowNode for Str | 'b' | builtin-class str | 8 | +| k_getsetattr.py:8 | ControlFlowNode for self | self | class C | 6 | +| k_getsetattr.py:8 | ControlFlowNode for self | self | class C | 12 | +| k_getsetattr.py:8 | ControlFlowNode for setattr | Builtin-function setattr | builtin-class builtin_function_or_method | 8 | +| k_getsetattr.py:8 | ControlFlowNode for setattr() | NoneType None | builtin-class NoneType | 8 | +| k_getsetattr.py:9 | ControlFlowNode for Str | 'a' | builtin-class str | 9 | +| k_getsetattr.py:9 | ControlFlowNode for getattr | Builtin-function getattr | builtin-class builtin_function_or_method | 9 | +| k_getsetattr.py:9 | ControlFlowNode for getattr() | int 0 | builtin-class int | 7 | +| k_getsetattr.py:9 | ControlFlowNode for self | self | class C | 6 | +| k_getsetattr.py:9 | ControlFlowNode for self | self | class C | 12 | +| k_getsetattr.py:10 | ControlFlowNode for Str | 'c' | builtin-class str | 10 | +| k_getsetattr.py:10 | ControlFlowNode for getattr | Builtin-function getattr | builtin-class builtin_function_or_method | 10 | +| k_getsetattr.py:10 | ControlFlowNode for getattr() | int 2 | builtin-class int | 14 | +| k_getsetattr.py:10 | ControlFlowNode for self | self | class C | 6 | +| k_getsetattr.py:10 | ControlFlowNode for self | self | class C | 12 | +| k_getsetattr.py:12 | ControlFlowNode for FunctionExpr | Function meth2 | builtin-class function | 12 | +| k_getsetattr.py:12 | ControlFlowNode for meth2 | Function meth2 | builtin-class function | 12 | +| k_getsetattr.py:13 | ControlFlowNode for FloatLiteral | float 7.0 | builtin-class float | 13 | +| k_getsetattr.py:13 | ControlFlowNode for Str | 'a' | builtin-class str | 13 | +| k_getsetattr.py:13 | ControlFlowNode for self | self | class C | 12 | +| k_getsetattr.py:13 | ControlFlowNode for setattr | Builtin-function setattr | builtin-class builtin_function_or_method | 13 | +| k_getsetattr.py:13 | ControlFlowNode for setattr() | NoneType None | builtin-class NoneType | 13 | +| k_getsetattr.py:14 | ControlFlowNode for IntegerLiteral | int 2 | builtin-class int | 14 | +| k_getsetattr.py:14 | ControlFlowNode for Str | 'c' | builtin-class str | 14 | +| k_getsetattr.py:14 | ControlFlowNode for self | self | class C | 12 | +| k_getsetattr.py:14 | ControlFlowNode for setattr | Builtin-function setattr | builtin-class builtin_function_or_method | 14 | +| k_getsetattr.py:14 | ControlFlowNode for setattr() | NoneType None | builtin-class NoneType | 14 | +| k_getsetattr.py:15 | ControlFlowNode for Attribute() | NoneType None | builtin-class NoneType | 6 | +| k_getsetattr.py:15 | ControlFlowNode for self | self | class C | 12 | +| k_getsetattr.py:16 | ControlFlowNode for Str | 'a' | builtin-class str | 16 | +| k_getsetattr.py:16 | ControlFlowNode for getattr | Builtin-function getattr | builtin-class builtin_function_or_method | 16 | +| k_getsetattr.py:16 | ControlFlowNode for getattr() | int 0 | builtin-class int | 7 | +| k_getsetattr.py:16 | ControlFlowNode for self | self | class C | 12 | +| k_getsetattr.py:17 | ControlFlowNode for Str | 'b' | builtin-class str | 17 | +| k_getsetattr.py:17 | ControlFlowNode for getattr | Builtin-function getattr | builtin-class builtin_function_or_method | 17 | +| k_getsetattr.py:17 | ControlFlowNode for getattr() | int 1 | builtin-class int | 8 | +| k_getsetattr.py:17 | ControlFlowNode for self | self | class C | 12 | +| k_getsetattr.py:18 | ControlFlowNode for Str | 'c' | builtin-class str | 18 | +| k_getsetattr.py:18 | ControlFlowNode for getattr | Builtin-function getattr | builtin-class builtin_function_or_method | 18 | +| k_getsetattr.py:18 | ControlFlowNode for getattr() | int 2 | builtin-class int | 14 | +| k_getsetattr.py:18 | ControlFlowNode for self | self | class C | 12 | +| k_getsetattr.py:21 | ControlFlowNode for FunctionExpr | Function k | builtin-class function | 21 | +| k_getsetattr.py:21 | ControlFlowNode for k | Function k | builtin-class function | 21 | +| k_getsetattr.py:22 | ControlFlowNode for C | class C | builtin-class type | 4 | +| k_getsetattr.py:22 | ControlFlowNode for C() | C() | class C | 22 | +| k_getsetattr.py:22 | ControlFlowNode for c1 | C() | class C | 22 | +| k_getsetattr.py:23 | ControlFlowNode for C | class C | builtin-class type | 4 | +| k_getsetattr.py:23 | ControlFlowNode for C() | C() | class C | 23 | +| k_getsetattr.py:23 | ControlFlowNode for c2 | C() | class C | 23 | +| k_getsetattr.py:24 | ControlFlowNode for C | class C | builtin-class type | 4 | +| k_getsetattr.py:24 | ControlFlowNode for C() | C() | class C | 24 | +| k_getsetattr.py:24 | ControlFlowNode for c3 | C() | class C | 24 | +| k_getsetattr.py:25 | ControlFlowNode for Attribute | int 10 | builtin-class int | 25 | +| k_getsetattr.py:25 | ControlFlowNode for IntegerLiteral | int 10 | builtin-class int | 25 | +| k_getsetattr.py:25 | ControlFlowNode for c1 | C() | class C | 22 | +| k_getsetattr.py:27 | ControlFlowNode for Attribute | int 20 | builtin-class int | 27 | +| k_getsetattr.py:27 | ControlFlowNode for IntegerLiteral | int 20 | builtin-class int | 27 | +| k_getsetattr.py:27 | ControlFlowNode for c2 | C() | class C | 23 | +| k_getsetattr.py:28 | ControlFlowNode for Attribute | int 10 | builtin-class int | 25 | +| k_getsetattr.py:28 | ControlFlowNode for c1 | C() | class C | 22 | +| k_getsetattr.py:29 | ControlFlowNode for Attribute | int 20 | builtin-class int | 27 | +| k_getsetattr.py:29 | ControlFlowNode for c2 | C() | class C | 23 | +| k_getsetattr.py:30 | ControlFlowNode for c3 | C() | class C | 24 | +| k_getsetattr.py:31 | ControlFlowNode for Attribute | int 30 | builtin-class int | 31 | +| k_getsetattr.py:31 | ControlFlowNode for IntegerLiteral | int 30 | builtin-class int | 31 | +| k_getsetattr.py:31 | ControlFlowNode for c3 | C() | class C | 24 | +| l_calls.py:3 | ControlFlowNode for FunctionExpr | Function foo | builtin-class function | 3 | +| l_calls.py:3 | ControlFlowNode for List | List | builtin-class list | 3 | +| l_calls.py:3 | ControlFlowNode for foo | Function foo | builtin-class function | 3 | +| l_calls.py:4 | ControlFlowNode for Attribute() | NoneType None | builtin-class NoneType | 4 | +| l_calls.py:4 | ControlFlowNode for Str | 'x' | builtin-class str | 4 | +| l_calls.py:4 | ControlFlowNode for x | List | builtin-class list | 3 | +| l_calls.py:6 | ControlFlowNode for FunctionExpr | Function bar | builtin-class function | 6 | +| l_calls.py:6 | ControlFlowNode for List | List | builtin-class list | 6 | +| l_calls.py:6 | ControlFlowNode for bar | Function bar | builtin-class function | 6 | +| l_calls.py:7 | ControlFlowNode for len | Builtin-function len | builtin-class builtin_function_or_method | 7 | +| l_calls.py:7 | ControlFlowNode for len() | len() | builtin-class int | 7 | +| l_calls.py:7 | ControlFlowNode for x | List | builtin-class list | 6 | +| l_calls.py:9 | ControlFlowNode for foo | Function foo | builtin-class function | 3 | +| l_calls.py:9 | ControlFlowNode for foo() | NoneType None | builtin-class NoneType | 4 | +| l_calls.py:10 | ControlFlowNode for bar | Function bar | builtin-class function | 6 | +| l_calls.py:10 | ControlFlowNode for bar() | len() | builtin-class int | 7 | +| l_calls.py:12 | ControlFlowNode for ClassExpr | class Owner | builtin-class type | 12 | +| l_calls.py:12 | ControlFlowNode for Owner | class Owner | builtin-class type | 12 | +| l_calls.py:12 | ControlFlowNode for object | builtin-class object | builtin-class type | 12 | +| l_calls.py:14 | ControlFlowNode for classmethod | builtin-class classmethod | builtin-class type | 14 | +| l_calls.py:14 | ControlFlowNode for classmethod() | classmethod() | builtin-class classmethod | 14 | +| l_calls.py:15 | ControlFlowNode for FunctionExpr | Function cm | builtin-class function | 15 | +| l_calls.py:15 | ControlFlowNode for cm | classmethod() | builtin-class classmethod | 14 | +| l_calls.py:16 | ControlFlowNode for cls | class Owner | builtin-class type | 23 | +| l_calls.py:18 | ControlFlowNode for classmethod | builtin-class classmethod | builtin-class type | 18 | +| l_calls.py:18 | ControlFlowNode for classmethod() | classmethod() | builtin-class classmethod | 18 | +| l_calls.py:19 | ControlFlowNode for FunctionExpr | Function cm2 | builtin-class function | 19 | +| l_calls.py:19 | ControlFlowNode for cm2 | classmethod() | builtin-class classmethod | 18 | +| l_calls.py:20 | ControlFlowNode for arg | int 1 | builtin-class int | 25 | +| l_calls.py:23 | ControlFlowNode for FunctionExpr | Function m | builtin-class function | 23 | +| l_calls.py:23 | ControlFlowNode for m | Function m | builtin-class function | 23 | +| l_calls.py:24 | ControlFlowNode for Attribute() | class Owner | builtin-class type | 23 | +| l_calls.py:24 | ControlFlowNode for IntegerLiteral | int 0 | builtin-class int | 24 | +| l_calls.py:24 | ControlFlowNode for a | class Owner | builtin-class type | 23 | +| l_calls.py:24 | ControlFlowNode for self | self | class Owner | 23 | +| l_calls.py:25 | ControlFlowNode for Attribute() | int 1 | builtin-class int | 25 | +| l_calls.py:25 | ControlFlowNode for IntegerLiteral | int 1 | builtin-class int | 25 | +| l_calls.py:25 | ControlFlowNode for a | class Owner | builtin-class type | 23 | +| s_scopes.py:4 | ControlFlowNode for True | bool True | builtin-class bool | 4 | +| s_scopes.py:4 | ControlFlowNode for float | bool True | builtin-class bool | 4 | +| s_scopes.py:7 | ControlFlowNode for C2 | class C2 | builtin-class type | 7 | +| s_scopes.py:7 | ControlFlowNode for ClassExpr | class C2 | builtin-class type | 7 | +| s_scopes.py:7 | ControlFlowNode for object | builtin-class object | builtin-class type | 7 | +| s_scopes.py:9 | ControlFlowNode for i1 | builtin-class int | builtin-class type | 9 | +| s_scopes.py:9 | ControlFlowNode for int | builtin-class int | builtin-class type | 9 | +| s_scopes.py:10 | ControlFlowNode for f1 | bool True | builtin-class bool | 4 | +| s_scopes.py:10 | ControlFlowNode for f1 | builtin-class float | builtin-class type | 10 | +| s_scopes.py:10 | ControlFlowNode for float | bool True | builtin-class bool | 4 | +| s_scopes.py:10 | ControlFlowNode for float | builtin-class float | builtin-class type | 10 | +| s_scopes.py:12 | ControlFlowNode for IntegerLiteral | int 0 | builtin-class int | 12 | +| s_scopes.py:12 | ControlFlowNode for int | int 0 | builtin-class int | 12 | +| s_scopes.py:15 | ControlFlowNode for FloatLiteral | float 1.0 | builtin-class float | 15 | +| s_scopes.py:15 | ControlFlowNode for str | float 1.0 | builtin-class float | 15 | +| s_scopes.py:17 | ControlFlowNode for None | NoneType None | builtin-class NoneType | 17 | +| s_scopes.py:17 | ControlFlowNode for float | NoneType None | builtin-class NoneType | 17 | +| s_scopes.py:18 | ControlFlowNode for i2 | int 0 | builtin-class int | 12 | +| s_scopes.py:18 | ControlFlowNode for int | int 0 | builtin-class int | 12 | +| s_scopes.py:19 | ControlFlowNode for s | builtin-class str | builtin-class type | 19 | +| s_scopes.py:19 | ControlFlowNode for s | float 1.0 | builtin-class float | 15 | +| s_scopes.py:19 | ControlFlowNode for str | builtin-class str | builtin-class type | 19 | +| s_scopes.py:19 | ControlFlowNode for str | float 1.0 | builtin-class float | 15 | +| s_scopes.py:20 | ControlFlowNode for f2 | NoneType None | builtin-class NoneType | 17 | +| s_scopes.py:20 | ControlFlowNode for f2 | bool True | builtin-class bool | 4 | +| s_scopes.py:20 | ControlFlowNode for f2 | builtin-class float | builtin-class type | 20 | +| s_scopes.py:20 | ControlFlowNode for float | NoneType None | builtin-class NoneType | 17 | +| s_scopes.py:20 | ControlFlowNode for float | bool True | builtin-class bool | 4 | +| s_scopes.py:20 | ControlFlowNode for float | builtin-class float | builtin-class type | 20 | +| s_scopes.py:23 | ControlFlowNode for i | builtin-class int | builtin-class type | 23 | +| s_scopes.py:23 | ControlFlowNode for int | builtin-class int | builtin-class type | 23 | +| s_scopes.py:24 | ControlFlowNode for f | bool True | builtin-class bool | 4 | +| s_scopes.py:24 | ControlFlowNode for f | builtin-class float | builtin-class type | 24 | +| s_scopes.py:24 | ControlFlowNode for float | bool True | builtin-class bool | 4 | +| s_scopes.py:24 | ControlFlowNode for float | builtin-class float | builtin-class type | 24 | diff --git a/python/ql/test/library-tests/PointsTo/new/PointsToWithType.ql b/python/ql/test/library-tests/PointsTo/new/PointsToWithType.ql new file mode 100644 index 00000000000..0c845f6bc3c --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/PointsToWithType.ql @@ -0,0 +1,9 @@ +import python +import Util +import semmle.python.pointsto.PointsTo + +from ControlFlowNode f, Object o, ClassObject c, ControlFlowNode x + +where PointsTo::points_to(f, _, o, c, x) + +select locate(f.getLocation(), "abdeghijkls"), f.toString(), repr(o), repr(c), x.getLocation().getStartLine() diff --git a/python/ql/test/library-tests/PointsTo/new/Precedes.expected b/python/ql/test/library-tests/PointsTo/new/Precedes.expected new file mode 100644 index 00000000000..fc1a262139e --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/Precedes.expected @@ -0,0 +1,12 @@ +| q_super.py:0 | Module code.q_super | q_super.py:3 | Function __init__ | +| q_super.py:0 | Module code.q_super | q_super.py:10 | Function __init__ | +| q_super.py:0 | Module code.q_super | q_super.py:16 | Function meth | +| q_super.py:0 | Module code.q_super | q_super.py:21 | Function meth | +| q_super.py:0 | Module code.q_super | q_super.py:26 | Function meth | +| q_super.py:0 | Module code.q_super | q_super.py:31 | Function meth | +| q_super.py:0 | Module code.q_super | q_super.py:37 | Function meth | +| q_super.py:0 | Module code.q_super | q_super.py:43 | Function __init__ | +| q_super.py:0 | Module code.q_super | q_super.py:50 | Function __init__ | +| q_super.py:0 | Module code.q_super | q_super.py:57 | Function __init__ | +| q_super.py:0 | Module code.q_super | q_super.py:65 | Function __init__ | +| q_super.py:0 | Module code.q_super | q_super.py:73 | Function __init__ | diff --git a/python/ql/test/library-tests/PointsTo/new/Precedes.ql b/python/ql/test/library-tests/PointsTo/new/Precedes.ql new file mode 100644 index 00000000000..959ec181f5f --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/Precedes.ql @@ -0,0 +1,8 @@ + +import python +import Util + +from Scope pre, Scope post +where pre.precedes(post) + +select locate(pre.getLocation(), "q"), pre.toString(), locate(post.getLocation(), "q"), post.toString() diff --git a/python/ql/test/library-tests/PointsTo/new/README.md b/python/ql/test/library-tests/PointsTo/new/README.md new file mode 100644 index 00000000000..0934a6cf72c --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/README.md @@ -0,0 +1,14 @@ +## Dataflow, points-to, call-graph and type-inference tests. + +Since dataflow, points-to, call-graph and type-inference are all interlinked it makes sense to test them together. + +### The test code. +The test code is all under the `code/` subdirectory and all test files are named \w_name, supporting +files do have an underscore as their second character. +This allows tests to be applied to a subset of the test data and test/data combinations to be turned on/off easily for debugging. + +Be aware that here are two `__init__.py`, so the results are interleaved. + + + + diff --git a/python/ql/test/library-tests/PointsTo/new/Reachable.expected b/python/ql/test/library-tests/PointsTo/new/Reachable.expected new file mode 100644 index 00000000000..c7dbbb816a4 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/Reachable.expected @@ -0,0 +1,80 @@ +| m_attributes.py:0 | Entry node for Module code.m_attributes | import | +| m_attributes.py:0 | Exit node for Module code.m_attributes | import | +| m_attributes.py:3 | ControlFlowNode for C | import | +| m_attributes.py:3 | ControlFlowNode for ClassExpr | import | +| m_attributes.py:3 | ControlFlowNode for object | import | +| m_attributes.py:3 | Entry node for Class C | import | +| m_attributes.py:3 | Exit node for Class C | import | +| m_attributes.py:5 | ControlFlowNode for FunctionExpr | import | +| m_attributes.py:5 | ControlFlowNode for IntegerLiteral | import | +| m_attributes.py:5 | ControlFlowNode for __init__ | import | +| m_attributes.py:5 | ControlFlowNode for a | code/m_attributes.py:12 from import | +| m_attributes.py:5 | ControlFlowNode for a | code/m_attributes.py:12 from import | +| m_attributes.py:5 | ControlFlowNode for a | code/m_attributes.py:13 from import | +| m_attributes.py:5 | ControlFlowNode for a | code/m_attributes.py:13 from import | +| m_attributes.py:5 | ControlFlowNode for a | runtime | +| m_attributes.py:5 | ControlFlowNode for self | code/m_attributes.py:12 from import | +| m_attributes.py:5 | ControlFlowNode for self | code/m_attributes.py:12 from import | +| m_attributes.py:5 | ControlFlowNode for self | code/m_attributes.py:13 from import | +| m_attributes.py:5 | ControlFlowNode for self | code/m_attributes.py:13 from import | +| m_attributes.py:5 | ControlFlowNode for self | runtime | +| m_attributes.py:5 | Entry node for Function __init__ | code/m_attributes.py:12 from import | +| m_attributes.py:5 | Entry node for Function __init__ | code/m_attributes.py:12 from import | +| m_attributes.py:5 | Entry node for Function __init__ | code/m_attributes.py:13 from import | +| m_attributes.py:5 | Entry node for Function __init__ | code/m_attributes.py:13 from import | +| m_attributes.py:5 | Entry node for Function __init__ | runtime | +| m_attributes.py:5 | Exit node for Function __init__ | code/m_attributes.py:12 from import | +| m_attributes.py:5 | Exit node for Function __init__ | code/m_attributes.py:12 from import | +| m_attributes.py:5 | Exit node for Function __init__ | code/m_attributes.py:13 from import | +| m_attributes.py:5 | Exit node for Function __init__ | code/m_attributes.py:13 from import | +| m_attributes.py:5 | Exit node for Function __init__ | runtime | +| m_attributes.py:6 | ControlFlowNode for Attribute | code/m_attributes.py:12 from import | +| m_attributes.py:6 | ControlFlowNode for Attribute | code/m_attributes.py:12 from import | +| m_attributes.py:6 | ControlFlowNode for Attribute | code/m_attributes.py:13 from import | +| m_attributes.py:6 | ControlFlowNode for Attribute | code/m_attributes.py:13 from import | +| m_attributes.py:6 | ControlFlowNode for Attribute | runtime | +| m_attributes.py:6 | ControlFlowNode for a | code/m_attributes.py:12 from import | +| m_attributes.py:6 | ControlFlowNode for a | code/m_attributes.py:12 from import | +| m_attributes.py:6 | ControlFlowNode for a | code/m_attributes.py:13 from import | +| m_attributes.py:6 | ControlFlowNode for a | code/m_attributes.py:13 from import | +| m_attributes.py:6 | ControlFlowNode for a | runtime | +| m_attributes.py:6 | ControlFlowNode for self | code/m_attributes.py:12 from import | +| m_attributes.py:6 | ControlFlowNode for self | code/m_attributes.py:12 from import | +| m_attributes.py:6 | ControlFlowNode for self | code/m_attributes.py:13 from import | +| m_attributes.py:6 | ControlFlowNode for self | code/m_attributes.py:13 from import | +| m_attributes.py:6 | ControlFlowNode for self | runtime | +| m_attributes.py:8 | ControlFlowNode for FunctionExpr | import | +| m_attributes.py:8 | ControlFlowNode for foo | import | +| m_attributes.py:8 | ControlFlowNode for other | code/m_attributes.py:12 from import | +| m_attributes.py:8 | ControlFlowNode for other | code/m_attributes.py:13 from import | +| m_attributes.py:8 | ControlFlowNode for other | runtime | +| m_attributes.py:8 | ControlFlowNode for self | code/m_attributes.py:12 from import | +| m_attributes.py:8 | ControlFlowNode for self | code/m_attributes.py:13 from import | +| m_attributes.py:8 | ControlFlowNode for self | runtime | +| m_attributes.py:8 | Entry node for Function foo | code/m_attributes.py:12 from import | +| m_attributes.py:8 | Entry node for Function foo | code/m_attributes.py:13 from import | +| m_attributes.py:8 | Entry node for Function foo | runtime | +| m_attributes.py:8 | Exit node for Function foo | code/m_attributes.py:12 from import | +| m_attributes.py:8 | Exit node for Function foo | code/m_attributes.py:13 from import | +| m_attributes.py:8 | Exit node for Function foo | runtime | +| m_attributes.py:9 | ControlFlowNode for Attribute | code/m_attributes.py:12 from import | +| m_attributes.py:9 | ControlFlowNode for Attribute | code/m_attributes.py:13 from import | +| m_attributes.py:9 | ControlFlowNode for Attribute | runtime | +| m_attributes.py:9 | ControlFlowNode for self | code/m_attributes.py:12 from import | +| m_attributes.py:9 | ControlFlowNode for self | code/m_attributes.py:13 from import | +| m_attributes.py:9 | ControlFlowNode for self | runtime | +| m_attributes.py:10 | ControlFlowNode for Attribute | code/m_attributes.py:12 from import | +| m_attributes.py:10 | ControlFlowNode for Attribute | code/m_attributes.py:13 from import | +| m_attributes.py:10 | ControlFlowNode for Attribute | runtime | +| m_attributes.py:10 | ControlFlowNode for other | code/m_attributes.py:12 from import | +| m_attributes.py:10 | ControlFlowNode for other | code/m_attributes.py:13 from import | +| m_attributes.py:10 | ControlFlowNode for other | runtime | +| m_attributes.py:12 | ControlFlowNode for Attribute | import | +| m_attributes.py:12 | ControlFlowNode for Attribute() | import | +| m_attributes.py:12 | ControlFlowNode for C | import | +| m_attributes.py:12 | ControlFlowNode for C() | import | +| m_attributes.py:13 | ControlFlowNode for Attribute | import | +| m_attributes.py:13 | ControlFlowNode for Attribute() | import | +| m_attributes.py:13 | ControlFlowNode for C | import | +| m_attributes.py:13 | ControlFlowNode for C() | import | +| m_attributes.py:13 | ControlFlowNode for IntegerLiteral | import | diff --git a/python/ql/test/library-tests/PointsTo/new/Reachable.ql b/python/ql/test/library-tests/PointsTo/new/Reachable.ql new file mode 100644 index 00000000000..60fccc308ee --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/Reachable.ql @@ -0,0 +1,8 @@ + +import python +private import semmle.python.pointsto.PointsTo +import Util + +from ControlFlowNode f, Context ctx +where PointsTo::Test::reachableBlock(f.getBasicBlock(), ctx) +select locate(f.getLocation(), "m"), f.toString(), ctx diff --git a/python/ql/test/library-tests/PointsTo/new/SSA.expected b/python/ql/test/library-tests/PointsTo/new/SSA.expected new file mode 100644 index 00000000000..18df1e455dc --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/SSA.expected @@ -0,0 +1,624 @@ +| __init__.py:0 | __name___0 = ScopeEntryDefinition | 'code' | builtin-class str | +| __init__.py:0 | __name___0 = ScopeEntryDefinition | 'code.package' | builtin-class str | +| __init__.py:0 | __name___0 = ScopeEntryDefinition | 'code.test_package' | builtin-class str | +| __init__.py:0 | __package___0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| __init__.py:0 | module2_0 = ImplicitSubModuleDefinition | Module code.package.module2 | builtin-class module | +| __init__.py:0 | moduleX_0 = ImplicitSubModuleDefinition | Module code.package.moduleX | builtin-class module | +| __init__.py:0 | sys_0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| __init__.py:1 | __name___1 = ImportStarRefinement(__name___0) | 'code.test_package' | builtin-class str | +| __init__.py:1 | __package___1 = ImportStarRefinement(__package___0) | *UNDEFINED* | *UNKNOWN TYPE* | +| __init__.py:1 | sys_1 = ImportStarRefinement(sys_0) | *UNDEFINED* | *UNKNOWN TYPE* | +| __init__.py:2 | __name___2 = ImportStarRefinement(__name___1) | 'code.test_package' | builtin-class str | +| __init__.py:2 | __package___2 = ImportStarRefinement(__package___1) | *UNDEFINED* | *UNKNOWN TYPE* | +| __init__.py:2 | module_0 = ImportMember | Function module | builtin-class function | +| __init__.py:3 | sys_2 = ImportExpr | Module sys | builtin-class module | +| __init__.py:4 | module3_0 = ImportMember | Module code.package.module2 | builtin-class module | +| __init__.py:5 | module2_1 = IntegerLiteral | int 7 | builtin-class int | +| __init__.py:6 | module4_0 = ImportMember | int 7 | builtin-class int | +| __init__.py:7 | module5_0 = ImportMember | Module code.package.module2 | builtin-class module | +| __init__.py:8 | moduleX_1 = ImportMember | Module code.package.moduleX | builtin-class module | +| a_simple.py:0 | __name___0 = ScopeEntryDefinition | 'code.a_simple' | builtin-class str | +| a_simple.py:0 | __package___0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| a_simple.py:2 | f1_0 = FloatLiteral | float 1.0 | builtin-class float | +| a_simple.py:5 | i1_0 = IntegerLiteral | int 0 | builtin-class int | +| a_simple.py:6 | s_0 = Tuple | Tuple | builtin-class tuple | +| a_simple.py:8 | func_0 = FunctionExpr | Function func | builtin-class function | +| a_simple.py:11 | C_0 = ClassExpr | class C | builtin-class type | +| a_simple.py:14 | d_0 = ParameterDefinition | d | builtin-class dict | +| a_simple.py:14 | t_0 = ParameterDefinition | t | builtin-class tuple | +| a_simple.py:14 | vararg_kwarg_0 = FunctionExpr | Function vararg_kwarg | builtin-class function | +| a_simple.py:18 | multi_loop_0 = FunctionExpr | Function multi_loop | builtin-class function | +| a_simple.py:18 | y_0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| a_simple.py:19 | x_0 = None | NoneType None | builtin-class NoneType | +| a_simple.py:20 | x_1 = phi(x_0, x_2) | NoneType None | builtin-class NoneType | +| a_simple.py:20 | y_1 = phi(y_0, y_2) | *UNDEFINED* | *UNKNOWN TYPE* | +| a_simple.py:23 | with_definition_0 = FunctionExpr | Function with_definition | builtin-class function | +| a_simple.py:27 | multi_loop_in_try_0 = FunctionExpr | Function multi_loop_in_try | builtin-class function | +| a_simple.py:27 | p_0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| a_simple.py:27 | q_0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| a_simple.py:29 | p_1 = phi(p_0, p_2) | *UNDEFINED* | *UNKNOWN TYPE* | +| a_simple.py:29 | q_1 = phi(q_0, q_2) | *UNDEFINED* | *UNKNOWN TYPE* | +| a_simple.py:34 | args_0 = ParameterDefinition | args | builtin-class tuple | +| a_simple.py:34 | f_0 = FunctionExpr | Function f | builtin-class function | +| a_simple.py:34 | kwargs_0 = ParameterDefinition | kwargs | builtin-class dict | +| b_condition.py:0 | __name___0 = ScopeEntryDefinition | 'code.b_condition' | builtin-class str | +| b_condition.py:0 | __package___0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| b_condition.py:0 | double_attr_check_0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| b_condition.py:0 | g_0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| b_condition.py:0 | h_0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| b_condition.py:0 | k_0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| b_condition.py:0 | loop_0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| b_condition.py:0 | not_or_not_0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| b_condition.py:0 | odasa6261_0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| b_condition.py:0 | split_bool1_0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| b_condition.py:0 | v2_0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| b_condition.py:4 | f_0 = FunctionExpr | Function f | builtin-class function | +| b_condition.py:5 | x_0 = IfExp | NoneType None | builtin-class NoneType | +| b_condition.py:8 | x_1 = IntegerLiteral | int 7 | builtin-class int | +| b_condition.py:9 | x_3 = phi(x_1, x_2) | int 7 | builtin-class int | +| b_condition.py:11 | x_4 = IfExp | NoneType None | builtin-class NoneType | +| b_condition.py:14 | x_5 = IntegerLiteral | int 7 | builtin-class int | +| b_condition.py:15 | x_6 = Pi(x_4) [false] | NoneType None | builtin-class NoneType | +| b_condition.py:15 | x_7 = phi(x_5, x_6) | NoneType None | builtin-class NoneType | +| b_condition.py:15 | x_7 = phi(x_5, x_6) | int 7 | builtin-class int | +| b_condition.py:17 | x_8 = IfExp | NoneType None | builtin-class NoneType | +| b_condition.py:20 | x_9 = None | NoneType None | builtin-class NoneType | +| b_condition.py:21 | x_11 = phi(x_9, x_10) | NoneType None | builtin-class NoneType | +| b_condition.py:23 | x_12 = IfExp | NoneType None | builtin-class NoneType | +| b_condition.py:25 | x_14 = IfExp | int 1 | builtin-class int | +| b_condition.py:26 | x_15 = ArgumentRefinement(x_14) | int 1 | builtin-class int | +| b_condition.py:28 | x_16 = IntegerLiteral | int 1 | builtin-class int | +| b_condition.py:29 | x_17 = phi(x_15, x_16) | int 1 | builtin-class int | +| b_condition.py:31 | x_18 = IfExp | int 1 | builtin-class int | +| b_condition.py:33 | x_19 = IntegerLiteral | int 7 | builtin-class int | +| b_condition.py:34 | x_20 = Pi(x_18) [false] | int 1 | builtin-class int | +| b_condition.py:34 | x_21 = phi(x_19, x_20) | int 1 | builtin-class int | +| b_condition.py:34 | x_21 = phi(x_19, x_20) | int 7 | builtin-class int | +| b_condition.py:34 | x_22 = ArgumentRefinement(x_21) | int 1 | builtin-class int | +| b_condition.py:34 | x_22 = ArgumentRefinement(x_21) | int 7 | builtin-class int | +| b_condition.py:36 | x_23 = ArgumentRefinement(x_22) | int 1 | builtin-class int | +| b_condition.py:36 | x_23 = ArgumentRefinement(x_22) | int 7 | builtin-class int | +| b_condition.py:36 | x_24 = Pi(x_23) [true] | int 1 | builtin-class int | +| b_condition.py:36 | x_24 = Pi(x_23) [true] | int 7 | builtin-class int | +| b_condition.py:37 | x_25 = ArgumentRefinement(x_24) | int 1 | builtin-class int | +| b_condition.py:37 | x_25 = ArgumentRefinement(x_24) | int 7 | builtin-class int | +| b_condition.py:50 | g_1 = FunctionExpr | Function g | builtin-class function | +| b_condition.py:55 | loop_1 = FunctionExpr | Function loop | builtin-class function | +| b_condition.py:55 | v_0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| b_condition.py:56 | v_2 = phi(v_0, v_1, v_5) | *UNDEFINED* | *UNKNOWN TYPE* | +| b_condition.py:61 | double_attr_check_1 = FunctionExpr | Function double_attr_check | builtin-class function | +| b_condition.py:69 | h_1 = FunctionExpr | Function h | builtin-class function | +| b_condition.py:70 | b_0 = IfExp | bool True | builtin-class bool | +| b_condition.py:72 | b_1 = IntegerLiteral | int 7 | builtin-class int | +| b_condition.py:73 | b_2 = Pi(b_0) [false] | bool True | builtin-class bool | +| b_condition.py:73 | b_3 = phi(b_1, b_2) | bool True | builtin-class bool | +| b_condition.py:73 | b_3 = phi(b_1, b_2) | int 7 | builtin-class int | +| b_condition.py:75 | k_1 = FunctionExpr | Function k | builtin-class function | +| b_condition.py:76 | t_0 = type | builtin-class type | builtin-class type | +| b_condition.py:78 | t_1 = object | builtin-class object | builtin-class type | +| b_condition.py:79 | t_3 = phi(t_1, t_2) | builtin-class object | builtin-class type | +| b_condition.py:79 | t_4 = ArgumentRefinement(t_3) | builtin-class object | builtin-class type | +| b_condition.py:81 | bar_0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| b_condition.py:81 | bar_2 = phi(bar_0, bar_1) | *UNDEFINED* | *UNKNOWN TYPE* | +| b_condition.py:81 | bar_2 = phi(bar_0, bar_1) | Function bar | builtin-class function | +| b_condition.py:81 | foo_0 = ParameterDefinition | bool True | builtin-class bool | +| b_condition.py:81 | foo_4 = Pi(foo_1) [false] | bool True | builtin-class bool | +| b_condition.py:81 | foo_5 = phi(foo_2, foo_4) | bool True | builtin-class bool | +| b_condition.py:81 | odasa6261_1 = FunctionExpr | Function odasa6261 | builtin-class function | +| b_condition.py:82 | foo_1 = ArgumentRefinement(foo_0) | bool True | builtin-class bool | +| b_condition.py:83 | bar_1 = FunctionExpr | Function bar | builtin-class function | +| b_condition.py:83 | foo_3 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| b_condition.py:87 | split_bool1_1 = FunctionExpr | Function split_bool1 | builtin-class function | +| b_condition.py:87 | x_0 = ParameterDefinition | NoneType None | builtin-class NoneType | +| b_condition.py:87 | y_0 = ParameterDefinition | NoneType None | builtin-class NoneType | +| b_condition.py:90 | x_4 = Pi(x_0) [false] | NoneType None | builtin-class NoneType | +| b_condition.py:90 | x_5 = SingleSuccessorGuard(x_4) [false] | NoneType None | builtin-class NoneType | +| b_condition.py:90 | y_4 = Pi(y_0) [false] | NoneType None | builtin-class NoneType | +| b_condition.py:92 | x_2 = SingleSuccessorGuard(x_5) [false] | NoneType None | builtin-class NoneType | +| b_condition.py:93 | y_5 = ArgumentRefinement(y_4) | NoneType None | builtin-class NoneType | +| b_condition.py:96 | y_6 = SingleSuccessorGuard(y_5) [false] | NoneType None | builtin-class NoneType | +| b_condition.py:97 | x_3 = ArgumentRefinement(x_2) | NoneType None | builtin-class NoneType | +| b_condition.py:101 | a_0 = ParameterDefinition | a | builtin-class tuple | +| b_condition.py:101 | not_or_not_1 = FunctionExpr | Function not_or_not | builtin-class function | +| b_condition.py:102 | a_1 = ArgumentRefinement(a_0) | a | builtin-class tuple | +| b_condition.py:104 | a_2 = Pi(a_1) [false] | a | builtin-class tuple | +| b_condition.py:105 | a_3 = Pi(a_2) [false] | a | builtin-class tuple | +| b_condition.py:107 | a_4 = Pi(a_3) [false] | a | builtin-class tuple | +| c_tests.py:0 | __name___0 = ScopeEntryDefinition | 'code.c_tests' | builtin-class str | +| c_tests.py:0 | __package___0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| c_tests.py:4 | f_0 = FunctionExpr | Function f | builtin-class function | +| c_tests.py:5 | x_0 = IfExp | NoneType None | builtin-class NoneType | +| c_tests.py:10 | x_1 = IfExp | int 0 | builtin-class int | +| c_tests.py:10 | x_1 = IfExp | int 1 | builtin-class int | +| c_tests.py:15 | x_2 = IfExp | int 0 | builtin-class int | +| c_tests.py:15 | x_2 = IfExp | int 1 | builtin-class int | +| c_tests.py:21 | x_3 = IfExp | List | builtin-class list | +| c_tests.py:21 | x_3 = IfExp | Tuple | builtin-class tuple | +| c_tests.py:23 | x_4 = ArgumentRefinement(x_3) | List | builtin-class list | +| c_tests.py:23 | x_4 = ArgumentRefinement(x_3) | Tuple | builtin-class tuple | +| c_tests.py:24 | x_5 = Pi(x_4) [true] | List | builtin-class list | +| c_tests.py:24 | x_5 = Pi(x_4) [true] | Tuple | builtin-class tuple | +| c_tests.py:26 | x_7 = phi(x_5, x_6) | List | builtin-class list | +| c_tests.py:26 | x_7 = phi(x_5, x_6) | Tuple | builtin-class tuple | +| c_tests.py:26 | x_8 = ArgumentRefinement(x_7) | List | builtin-class list | +| c_tests.py:26 | x_8 = ArgumentRefinement(x_7) | Tuple | builtin-class tuple | +| c_tests.py:27 | x_9 = Pi(x_8) [true] | List | builtin-class list | +| c_tests.py:27 | x_9 = Pi(x_8) [true] | Tuple | builtin-class tuple | +| c_tests.py:29 | x_10 = Pi(x_8) [false] | Tuple | builtin-class tuple | +| c_tests.py:29 | x_11 = phi(x_9, x_10) | List | builtin-class list | +| c_tests.py:29 | x_11 = phi(x_9, x_10) | Tuple | builtin-class tuple | +| c_tests.py:29 | x_12 = ArgumentRefinement(x_11) | List | builtin-class list | +| c_tests.py:29 | x_12 = ArgumentRefinement(x_11) | Tuple | builtin-class tuple | +| c_tests.py:30 | x_13 = Pi(x_12) [true] | Tuple | builtin-class tuple | +| c_tests.py:32 | x_14 = Pi(x_12) [false] | List | builtin-class list | +| c_tests.py:32 | x_15 = phi(x_13, x_14) | List | builtin-class list | +| c_tests.py:32 | x_15 = phi(x_13, x_14) | Tuple | builtin-class tuple | +| c_tests.py:56 | others_0 = FunctionExpr | Function others | builtin-class function | +| c_tests.py:56 | x_8 = Pi(x_6) [false] | int 0 | builtin-class int | +| c_tests.py:56 | x_9 = phi(x_7, x_8) | builtin-class float | builtin-class type | +| c_tests.py:56 | x_9 = phi(x_7, x_8) | int 0 | builtin-class int | +| c_tests.py:58 | x_0 = IfExp | builtin-class bool | builtin-class type | +| c_tests.py:58 | x_0 = IfExp | builtin-class type | builtin-class type | +| c_tests.py:63 | x_1 = IfExp | builtin-class float | builtin-class type | +| c_tests.py:63 | x_1 = IfExp | int 0 | builtin-class int | +| c_tests.py:65 | x_2 = ArgumentRefinement(x_1) | builtin-class float | builtin-class type | +| c_tests.py:65 | x_2 = ArgumentRefinement(x_1) | int 0 | builtin-class int | +| c_tests.py:66 | x_3 = Pi(x_2) [true] | int 0 | builtin-class int | +| c_tests.py:68 | x_4 = Pi(x_2) [false] | builtin-class float | builtin-class type | +| c_tests.py:68 | x_5 = phi(x_3, x_4) | builtin-class float | builtin-class type | +| c_tests.py:68 | x_5 = phi(x_3, x_4) | int 0 | builtin-class int | +| c_tests.py:68 | x_6 = ArgumentRefinement(x_5) | builtin-class float | builtin-class type | +| c_tests.py:68 | x_6 = ArgumentRefinement(x_5) | int 0 | builtin-class int | +| c_tests.py:69 | x_7 = Pi(x_6) [true] | builtin-class float | builtin-class type | +| c_tests.py:71 | compound_0 = FunctionExpr | Function compound | builtin-class function | +| c_tests.py:71 | x_0 = ParameterDefinition | int 1 | builtin-class int | +| c_tests.py:71 | y_0 = ParameterDefinition | int 0 | builtin-class int | +| c_tests.py:71 | y_5 = Pi(y_0) [false] | int 0 | builtin-class int | +| c_tests.py:71 | y_6 = phi(y_4, y_5) | int 0 | builtin-class int | +| c_tests.py:74 | x_2 = Pi(x_0) [true] | int 1 | builtin-class int | +| c_tests.py:76 | x_3 = SingleSuccessorGuard(x_2) [true] | int 1 | builtin-class int | +| c_tests.py:76 | y_2 = Pi(y_0) [false] | int 0 | builtin-class int | +| c_tests.py:76 | y_3 = phi(y_1, y_2) | int 0 | builtin-class int | +| c_tests.py:79 | h_0 = FunctionExpr | Function h | builtin-class function | +| c_tests.py:79 | x_4 = phi(x_2, x_3) | NoneType None | builtin-class NoneType | +| c_tests.py:80 | b_0 = IfExp | bool True | builtin-class bool | +| c_tests.py:83 | b_1 = IfExp | bool True | builtin-class bool | +| c_tests.py:87 | b_3 = Pi(b_1) [false] | bool True | builtin-class bool | +| c_tests.py:87 | b_4 = phi(b_2, b_3) | bool True | builtin-class bool | +| c_tests.py:90 | x_0 = IfExp | NoneType None | builtin-class NoneType | +| c_tests.py:94 | x_1 = IfExp | NoneType None | builtin-class NoneType | +| c_tests.py:96 | x_2 = Pi(x_1) [true] | NoneType None | builtin-class NoneType | +| c_tests.py:98 | complex_test_0 = FunctionExpr | Function complex_test | builtin-class function | +| d_globals.py:0 | D_0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:0 | Ugly_0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:0 | X_0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:0 | __name___0 = ScopeEntryDefinition | 'code.d_globals' | builtin-class str | +| d_globals.py:0 | __package___0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:0 | dict_0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:0 | g3_0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:0 | g4_0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:0 | get_g4_0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:0 | glob_0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:0 | k_0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:0 | modinit_0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:0 | outer_0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:0 | redefine_0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:0 | set_g4_0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:0 | set_g4_indirect_0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:0 | tuple_0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:0 | use_list_attribute_0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:0 | x_0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:0 | y_0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:0 | z_0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:2 | dict_2 = ScopeEntryDefinition | int 7 | builtin-class int | +| d_globals.py:2 | g1_2 = ScopeEntryDefinition | NoneType None | builtin-class NoneType | +| d_globals.py:2 | g2_2 = ScopeEntryDefinition | int 102 | builtin-class int | +| d_globals.py:2 | g3_2 = ScopeEntryDefinition | NoneType None | builtin-class NoneType | +| d_globals.py:2 | g4_1 = ScopeEntryDefinition | NoneType None | builtin-class NoneType | +| d_globals.py:2 | glob_2 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:2 | j_0 = FunctionExpr | Function j | builtin-class function | +| d_globals.py:2 | tuple_2 = ScopeEntryDefinition | builtin-class tuple | builtin-class type | +| d_globals.py:2 | z_2 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:5 | dict_1 = IntegerLiteral | int 7 | builtin-class int | +| d_globals.py:7 | tuple_1 = tuple | builtin-class tuple | builtin-class type | +| d_globals.py:14 | g1_0 = None | NoneType None | builtin-class NoneType | +| d_globals.py:16 | assign_global_0 = FunctionExpr | Function assign_global | builtin-class function | +| d_globals.py:16 | g2_3 = ScopeEntryDefinition | int 102 | builtin-class int | +| d_globals.py:16 | g3_3 = ScopeEntryDefinition | NoneType None | builtin-class NoneType | +| d_globals.py:16 | g4_2 = ScopeEntryDefinition | NoneType None | builtin-class NoneType | +| d_globals.py:16 | glob_3 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:16 | z_3 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:18 | g1_3 = IntegerLiteral | int 101 | builtin-class int | +| d_globals.py:23 | g2_0 = None | NoneType None | builtin-class NoneType | +| d_globals.py:25 | g1_4 = ScopeEntryDefinition | NoneType None | builtin-class NoneType | +| d_globals.py:25 | g3_4 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:25 | g3_4 = ScopeEntryDefinition | NoneType None | builtin-class NoneType | +| d_globals.py:25 | g4_3 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:25 | g4_3 = ScopeEntryDefinition | NoneType None | builtin-class NoneType | +| d_globals.py:25 | glob_4 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:25 | init_0 = FunctionExpr | Function init | builtin-class function | +| d_globals.py:25 | z_4 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:27 | g2_4 = IntegerLiteral | int 102 | builtin-class int | +| d_globals.py:29 | g1_1 = CallsiteRefinement(g1_0) | NoneType None | builtin-class NoneType | +| d_globals.py:29 | g2_1 = CallsiteRefinement(g2_0) | int 102 | builtin-class int | +| d_globals.py:29 | glob_1 = CallsiteRefinement(glob_0) | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:29 | z_1 = CallsiteRefinement(z_0) | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:33 | g3_1 = None | NoneType None | builtin-class NoneType | +| d_globals.py:35 | Ugly_1 = ClassExpr | class Ugly | builtin-class type | +| d_globals.py:37 | __init___0 = FunctionExpr | Function __init__ | builtin-class function | +| d_globals.py:37 | g1_5 = ScopeEntryDefinition | NoneType None | builtin-class NoneType | +| d_globals.py:37 | g2_5 = ScopeEntryDefinition | int 102 | builtin-class int | +| d_globals.py:37 | g4_4 = ScopeEntryDefinition | NoneType None | builtin-class NoneType | +| d_globals.py:37 | glob_5 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:37 | self_0 = ParameterDefinition | self | class Ugly | +| d_globals.py:37 | z_5 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:39 | g3_5 = IntegerLiteral | int 103 | builtin-class int | +| d_globals.py:41 | g1_6 = ScopeEntryDefinition | NoneType None | builtin-class NoneType | +| d_globals.py:41 | g2_6 = ScopeEntryDefinition | int 102 | builtin-class int | +| d_globals.py:41 | g3_6 = ScopeEntryDefinition | int 103 | builtin-class int | +| d_globals.py:41 | g4_5 = ScopeEntryDefinition | NoneType None | builtin-class NoneType | +| d_globals.py:41 | glob_6 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:41 | meth_0 = FunctionExpr | Function meth | builtin-class function | +| d_globals.py:41 | self_0 = ParameterDefinition | self | class Ugly | +| d_globals.py:41 | z_6 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:46 | x_1 = IntegerLiteral | int 1 | builtin-class int | +| d_globals.py:49 | x_2 = IntegerLiteral | int 3 | builtin-class int | +| d_globals.py:51 | x_3 = phi(x_1, x_2) | int 1 | builtin-class int | +| d_globals.py:51 | x_3 = phi(x_1, x_2) | int 3 | builtin-class int | +| d_globals.py:52 | y_1 = IntegerLiteral | int 1 | builtin-class int | +| d_globals.py:54 | y_2 = IntegerLiteral | int 2 | builtin-class int | +| d_globals.py:59 | y_3 = phi(y_1, y_2) | int 1 | builtin-class int | +| d_globals.py:59 | y_3 = phi(y_1, y_2) | int 2 | builtin-class int | +| d_globals.py:62 | X_1 = ClassExpr | class X | builtin-class type | +| d_globals.py:62 | X_2 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:62 | g3_7 = ScopeEntryDefinition | NoneType None | builtin-class NoneType | +| d_globals.py:62 | y_0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:62 | y_4 = ScopeEntryDefinition | int 1 | builtin-class int | +| d_globals.py:62 | y_4 = ScopeEntryDefinition | int 2 | builtin-class int | +| d_globals.py:63 | y_1 = y | int 1 | builtin-class int | +| d_globals.py:63 | y_1 = y | int 2 | builtin-class int | +| d_globals.py:70 | g1_7 = ScopeEntryDefinition | NoneType None | builtin-class NoneType | +| d_globals.py:70 | g2_7 = ScopeEntryDefinition | int 102 | builtin-class int | +| d_globals.py:70 | g3_8 = ScopeEntryDefinition | NoneType None | builtin-class NoneType | +| d_globals.py:70 | g4_7 = ScopeEntryDefinition | NoneType None | builtin-class NoneType | +| d_globals.py:70 | glob_7 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:70 | k_1 = FunctionExpr | Function k | builtin-class function | +| d_globals.py:70 | z_7 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:73 | g4_6 = None | NoneType None | builtin-class NoneType | +| d_globals.py:75 | g1_8 = ScopeEntryDefinition | NoneType None | builtin-class NoneType | +| d_globals.py:75 | g2_8 = ScopeEntryDefinition | int 102 | builtin-class int | +| d_globals.py:75 | g3_9 = ScopeEntryDefinition | NoneType None | builtin-class NoneType | +| d_globals.py:75 | g4_8 = ScopeEntryDefinition | NoneType None | builtin-class NoneType | +| d_globals.py:75 | get_g4_1 = FunctionExpr | Function get_g4 | builtin-class function | +| d_globals.py:75 | glob_8 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:75 | set_g4_2 = ScopeEntryDefinition | Function set_g4 | builtin-class function | +| d_globals.py:75 | z_8 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:77 | g1_9 = CallsiteRefinement(g1_8) | NoneType None | builtin-class NoneType | +| d_globals.py:77 | g2_9 = CallsiteRefinement(g2_8) | int 102 | builtin-class int | +| d_globals.py:77 | g3_10 = CallsiteRefinement(g3_9) | NoneType None | builtin-class NoneType | +| d_globals.py:77 | g4_9 = Pi(g4_8) [true] | NoneType None | builtin-class NoneType | +| d_globals.py:77 | g4_10 = CallsiteRefinement(g4_9) | bool False | builtin-class bool | +| d_globals.py:77 | glob_9 = CallsiteRefinement(glob_8) | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:77 | z_9 = CallsiteRefinement(z_8) | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:78 | g1_10 = phi(g1_8, g1_9) | NoneType None | builtin-class NoneType | +| d_globals.py:78 | g2_10 = phi(g2_8, g2_9) | int 102 | builtin-class int | +| d_globals.py:78 | g3_11 = phi(g3_9, g3_10) | NoneType None | builtin-class NoneType | +| d_globals.py:78 | g4_12 = phi(g4_10, g4_11) | bool False | builtin-class bool | +| d_globals.py:78 | glob_10 = phi(glob_8, glob_9) | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:78 | z_10 = phi(z_8, z_9) | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:80 | g1_11 = ScopeEntryDefinition | NoneType None | builtin-class NoneType | +| d_globals.py:80 | g2_11 = ScopeEntryDefinition | int 102 | builtin-class int | +| d_globals.py:80 | g3_12 = ScopeEntryDefinition | NoneType None | builtin-class NoneType | +| d_globals.py:80 | g4_13 = ScopeEntryDefinition | NoneType None | builtin-class NoneType | +| d_globals.py:80 | glob_11 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:80 | set_g4_1 = FunctionExpr | Function set_g4 | builtin-class function | +| d_globals.py:80 | set_g4_indirect_2 = ScopeEntryDefinition | Function set_g4_indirect | builtin-class function | +| d_globals.py:80 | z_11 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:81 | g1_12 = CallsiteRefinement(g1_11) | NoneType None | builtin-class NoneType | +| d_globals.py:81 | g2_12 = CallsiteRefinement(g2_11) | int 102 | builtin-class int | +| d_globals.py:81 | g3_13 = CallsiteRefinement(g3_12) | NoneType None | builtin-class NoneType | +| d_globals.py:81 | g4_14 = CallsiteRefinement(g4_13) | bool False | builtin-class bool | +| d_globals.py:81 | glob_12 = CallsiteRefinement(glob_11) | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:81 | z_12 = CallsiteRefinement(z_11) | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:83 | g1_13 = ScopeEntryDefinition | NoneType None | builtin-class NoneType | +| d_globals.py:83 | g2_13 = ScopeEntryDefinition | int 102 | builtin-class int | +| d_globals.py:83 | g3_14 = ScopeEntryDefinition | NoneType None | builtin-class NoneType | +| d_globals.py:83 | glob_13 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:83 | set_g4_indirect_1 = FunctionExpr | Function set_g4_indirect | builtin-class function | +| d_globals.py:83 | z_13 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:85 | g4_15 = False | bool False | builtin-class bool | +| d_globals.py:87 | modinit_1 = ClassExpr | class modinit | builtin-class type | +| d_globals.py:92 | modinit_2 = DeletionDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:95 | g1_14 = ScopeEntryDefinition | NoneType None | builtin-class NoneType | +| d_globals.py:95 | g2_14 = ScopeEntryDefinition | int 102 | builtin-class int | +| d_globals.py:95 | g3_15 = ScopeEntryDefinition | NoneType None | builtin-class NoneType | +| d_globals.py:95 | g4_16 = ScopeEntryDefinition | NoneType None | builtin-class NoneType | +| d_globals.py:95 | glob_14 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:95 | outer_1 = FunctionExpr | Function outer | builtin-class function | +| d_globals.py:95 | z_14 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:96 | g1_16 = ScopeEntryDefinition | NoneType None | builtin-class NoneType | +| d_globals.py:96 | g2_16 = ScopeEntryDefinition | int 102 | builtin-class int | +| d_globals.py:96 | g3_17 = ScopeEntryDefinition | NoneType None | builtin-class NoneType | +| d_globals.py:96 | g4_18 = ScopeEntryDefinition | NoneType None | builtin-class NoneType | +| d_globals.py:96 | inner_0 = FunctionExpr | Function inner | builtin-class function | +| d_globals.py:96 | z_16 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:98 | glob_16 = IntegerLiteral | int 100 | builtin-class int | +| d_globals.py:101 | g1_17 = ScopeEntryDefinition | NoneType None | builtin-class NoneType | +| d_globals.py:101 | g2_17 = ScopeEntryDefinition | int 102 | builtin-class int | +| d_globals.py:101 | g3_18 = ScopeEntryDefinition | NoneType None | builtin-class NoneType | +| d_globals.py:101 | g4_19 = ScopeEntryDefinition | NoneType None | builtin-class NoneType | +| d_globals.py:101 | glob_17 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:101 | otherInner_0 = FunctionExpr | Function otherInner | builtin-class function | +| d_globals.py:101 | z_17 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:104 | g1_15 = CallsiteRefinement(g1_14) | NoneType None | builtin-class NoneType | +| d_globals.py:104 | g2_15 = CallsiteRefinement(g2_14) | int 102 | builtin-class int | +| d_globals.py:104 | g3_16 = CallsiteRefinement(g3_15) | NoneType None | builtin-class NoneType | +| d_globals.py:104 | g4_17 = CallsiteRefinement(g4_16) | NoneType None | builtin-class NoneType | +| d_globals.py:104 | glob_15 = CallsiteRefinement(glob_14) | int 100 | builtin-class int | +| d_globals.py:104 | z_15 = CallsiteRefinement(z_14) | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:107 | g1_18 = ScopeEntryDefinition | NoneType None | builtin-class NoneType | +| d_globals.py:107 | g2_18 = ScopeEntryDefinition | int 102 | builtin-class int | +| d_globals.py:107 | g3_19 = ScopeEntryDefinition | NoneType None | builtin-class NoneType | +| d_globals.py:107 | g4_20 = ScopeEntryDefinition | NoneType None | builtin-class NoneType | +| d_globals.py:107 | glob_18 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:107 | redefine_1 = FunctionExpr | Function redefine | builtin-class function | +| d_globals.py:107 | z_18 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:110 | z_19 = IntegerLiteral | int 1 | builtin-class int | +| d_globals.py:113 | glob_19 = IntegerLiteral | int 50 | builtin-class int | +| d_globals.py:118 | D_1 = ClassExpr | class D | builtin-class type | +| d_globals.py:120 | __init___0 = FunctionExpr | Function __init__ | builtin-class function | +| d_globals.py:120 | g1_19 = ScopeEntryDefinition | NoneType None | builtin-class NoneType | +| d_globals.py:120 | g2_19 = ScopeEntryDefinition | int 102 | builtin-class int | +| d_globals.py:120 | g3_20 = ScopeEntryDefinition | NoneType None | builtin-class NoneType | +| d_globals.py:120 | g4_21 = ScopeEntryDefinition | NoneType None | builtin-class NoneType | +| d_globals.py:120 | glob_20 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:120 | self_0 = ParameterDefinition | self | class D | +| d_globals.py:120 | z_20 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:123 | dict_3 = ScopeEntryDefinition | int 7 | builtin-class int | +| d_globals.py:123 | foo_0 = FunctionExpr | Function foo | builtin-class function | +| d_globals.py:123 | g1_20 = ScopeEntryDefinition | NoneType None | builtin-class NoneType | +| d_globals.py:123 | g2_20 = ScopeEntryDefinition | int 102 | builtin-class int | +| d_globals.py:123 | g3_21 = ScopeEntryDefinition | NoneType None | builtin-class NoneType | +| d_globals.py:123 | g4_22 = ScopeEntryDefinition | NoneType None | builtin-class NoneType | +| d_globals.py:123 | glob_21 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:123 | self_0 = ParameterDefinition | self | class D | +| d_globals.py:123 | z_21 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:126 | g1_21 = ScopeEntryDefinition | NoneType None | builtin-class NoneType | +| d_globals.py:126 | g2_21 = ScopeEntryDefinition | int 102 | builtin-class int | +| d_globals.py:126 | g3_22 = ScopeEntryDefinition | NoneType None | builtin-class NoneType | +| d_globals.py:126 | g4_23 = ScopeEntryDefinition | NoneType None | builtin-class NoneType | +| d_globals.py:126 | glob_22 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:126 | use_list_attribute_1 = FunctionExpr | Function use_list_attribute | builtin-class function | +| d_globals.py:126 | z_22 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:127 | l_0 = List | List | builtin-class list | +| d_globals.py:128 | g1_22 = CallsiteRefinement(g1_21) | NoneType None | builtin-class NoneType | +| d_globals.py:128 | g2_22 = CallsiteRefinement(g2_21) | int 102 | builtin-class int | +| d_globals.py:128 | g3_23 = CallsiteRefinement(g3_22) | NoneType None | builtin-class NoneType | +| d_globals.py:128 | g4_24 = CallsiteRefinement(g4_23) | NoneType None | builtin-class NoneType | +| d_globals.py:128 | glob_23 = CallsiteRefinement(glob_22) | *UNDEFINED* | *UNKNOWN TYPE* | +| d_globals.py:128 | l_1 = ArgumentRefinement(l_0) | List | builtin-class list | +| d_globals.py:128 | z_23 = CallsiteRefinement(z_22) | *UNDEFINED* | *UNKNOWN TYPE* | +| e_temporal.py:0 | __name___0 = ScopeEntryDefinition | 'code.e_temporal' | builtin-class str | +| e_temporal.py:0 | __package___0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| e_temporal.py:0 | x_0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| e_temporal.py:2 | sys_0 = ImportExpr | Module sys | builtin-class module | +| e_temporal.py:4 | f_0 = FunctionExpr | Function f | builtin-class function | +| e_temporal.py:4 | sys_1 = ScopeEntryDefinition | Module sys | builtin-class module | +| e_temporal.py:9 | arg_0 = ParameterDefinition | int 1 | builtin-class int | +| e_temporal.py:9 | g_0 = FunctionExpr | Function g | builtin-class function | +| e_temporal.py:12 | x_1 = g() | int 1 | builtin-class int | +| g_class_init.py:0 | __name___0 = ScopeEntryDefinition | 'code.g_class_init' | builtin-class str | +| g_class_init.py:0 | __package___0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| g_class_init.py:3 | C_0 = ClassExpr | class C | builtin-class type | +| g_class_init.py:5 | __init___0 = FunctionExpr | Function __init__ | builtin-class function | +| g_class_init.py:5 | self_0 = ParameterDefinition | self | class C | +| g_class_init.py:6 | self_1 = SelfCallsiteRefinement(self_0) | self | class C | +| g_class_init.py:7 | self_2 = AttributeAssignment 'x'(self_1) | self | class C | +| g_class_init.py:9 | _init_0 = FunctionExpr | Function _init | builtin-class function | +| g_class_init.py:9 | self_0 = ParameterDefinition | self | class C | +| g_class_init.py:10 | self_1 = AttributeAssignment 'y'(self_0) | self | class C | +| g_class_init.py:11 | self_2 = SelfCallsiteRefinement(self_1) | self | class C | +| g_class_init.py:13 | _init2_0 = FunctionExpr | Function _init2 | builtin-class function | +| g_class_init.py:13 | self_0 = ParameterDefinition | self | class C | +| g_class_init.py:14 | self_1 = AttributeAssignment 'z'(self_0) | self | class C | +| g_class_init.py:16 | method_0 = FunctionExpr | Function method | builtin-class function | +| g_class_init.py:16 | self_0 = ParameterDefinition | self | class C | +| g_class_init.py:19 | self_1 = Pi(self_0) [true] | self | class C | +| g_class_init.py:20 | self_2 = Pi(self_0) [false] | self | class C | +| g_class_init.py:20 | self_3 = phi(self_1, self_2) | self | class C | +| g_class_init.py:24 | Oddities_0 = ClassExpr | class Oddities | builtin-class type | +| g_class_init.py:24 | float_0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| g_class_init.py:24 | int_0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| g_class_init.py:26 | int_1 = int | builtin-class int | builtin-class type | +| g_class_init.py:27 | float_1 = float | builtin-class float | builtin-class type | +| g_class_init.py:28 | l_0 = len | Builtin-function len | builtin-class builtin_function_or_method | +| g_class_init.py:29 | h_0 = hash | Builtin-function hash | builtin-class builtin_function_or_method | +| g_class_init.py:32 | D_0 = ClassExpr | class D | builtin-class type | +| g_class_init.py:34 | D_1 = ScopeEntryDefinition | class D | builtin-class type | +| g_class_init.py:34 | __init___0 = FunctionExpr | Function __init__ | builtin-class function | +| g_class_init.py:34 | self_0 = ParameterDefinition | self | class D | +| g_class_init.py:35 | D_2 = ArgumentRefinement(D_1) | class D | builtin-class type | +| g_class_init.py:42 | V2_0 = Str | 'v2' | builtin-class str | +| g_class_init.py:43 | V3_0 = Str | 'v3' | builtin-class str | +| g_class_init.py:45 | E_0 = ClassExpr | class E | builtin-class type | +| g_class_init.py:46 | V2_1 = ScopeEntryDefinition | 'v2' | builtin-class str | +| g_class_init.py:46 | V3_1 = ScopeEntryDefinition | 'v3' | builtin-class str | +| g_class_init.py:46 | __init___0 = FunctionExpr | Function __init__ | builtin-class function | +| g_class_init.py:46 | self_0 = ParameterDefinition | self | class E | +| g_class_init.py:46 | self_3 = phi(self_1, self_2) | self | class E | +| g_class_init.py:48 | self_1 = AttributeAssignment 'version'(self_0) | self | class E | +| g_class_init.py:50 | self_2 = AttributeAssignment 'version'(self_0) | self | class E | +| g_class_init.py:52 | V2_2 = ScopeEntryDefinition | 'v2' | builtin-class str | +| g_class_init.py:52 | meth_0 = FunctionExpr | Function meth | builtin-class function | +| g_class_init.py:52 | self_0 = ParameterDefinition | self | class E | +| g_class_init.py:52 | self_2 = Pi(self_0) [false] | self | class E | +| g_class_init.py:52 | self_3 = phi(self_1, self_2) | self | class E | +| g_class_init.py:54 | self_1 = Pi(self_0) [true] | self | class E | +| j_convoluted_imports.py:0 | __name___0 = ScopeEntryDefinition | 'code.j_convoluted_imports' | builtin-class str | +| j_convoluted_imports.py:0 | __package___0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| j_convoluted_imports.py:3 | module_0 = ImportMember | Function module | builtin-class function | +| j_convoluted_imports.py:6 | x_0 = ImportMember | Module code.package.x | builtin-class module | +| j_convoluted_imports.py:9 | C_0 = ClassExpr | class C | builtin-class type | +| j_convoluted_imports.py:11 | module2_0 = ImportMember | int 7 | builtin-class int | +| j_convoluted_imports.py:13 | f_0 = FunctionExpr | Function f | builtin-class function | +| j_convoluted_imports.py:13 | self_0 = ParameterDefinition | self | class C | +| j_convoluted_imports.py:14 | x_0 = ImportMember | Module code.package.x | builtin-class module | +| j_convoluted_imports.py:16 | moduleX_0 = ImportMember | Module code.package.moduleX | builtin-class module | +| m_attributes.py:0 | __name___0 = ScopeEntryDefinition | 'code.m_attributes' | builtin-class str | +| m_attributes.py:0 | __package___0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| m_attributes.py:3 | C_0 = ClassExpr | class C | builtin-class type | +| m_attributes.py:5 | __init___0 = FunctionExpr | Function __init__ | builtin-class function | +| m_attributes.py:5 | a_0 = ParameterDefinition | int 17 | builtin-class int | +| m_attributes.py:5 | a_0 = ParameterDefinition | int 100 | builtin-class int | +| m_attributes.py:5 | self_0 = ParameterDefinition | self | class C | +| m_attributes.py:6 | self_1 = AttributeAssignment 'a'(self_0) | self | class C | +| m_attributes.py:8 | foo_0 = FunctionExpr | Function foo | builtin-class function | +| m_attributes.py:8 | other_0 = ParameterDefinition | C() | class C | +| m_attributes.py:8 | self_0 = ParameterDefinition | self | class C | +| n_nesting.py:0 | D_0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| n_nesting.py:0 | __name___0 = ScopeEntryDefinition | 'code.n_nesting' | builtin-class str | +| n_nesting.py:0 | __package___0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| n_nesting.py:8 | C_0 = ScopeEntryDefinition | int 1 | builtin-class int | +| n_nesting.py:8 | compile_ops_0 = ParameterDefinition | bool True | builtin-class bool | +| n_nesting.py:8 | foo_0 = FunctionExpr | Function foo | builtin-class function | +| n_nesting.py:9 | C_1 = CallsiteRefinement(C_0) | int 1 | builtin-class int | +| n_nesting.py:9 | compile_ops_1 = ArgumentRefinement(compile_ops_0) | bool True | builtin-class bool | +| n_nesting.py:10 | C_5 = ScopeEntryDefinition | int 1 | builtin-class int | +| n_nesting.py:10 | compile_ops_3 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| n_nesting.py:10 | inner_0 = FunctionExpr | Function inner | builtin-class function | +| n_nesting.py:13 | C_7 = ScopeEntryDefinition | int 1 | builtin-class int | +| n_nesting.py:13 | compile_ops_4 = Pi(compile_ops_1) [false] | bool True | builtin-class bool | +| n_nesting.py:13 | compile_ops_5 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| n_nesting.py:13 | inner_1 = FunctionExpr | Function inner | builtin-class function | +| n_nesting.py:15 | attrs_0 = Dict | Dict | builtin-class dict | +| n_nesting.py:16 | compile_ops_6 = phi(compile_ops_2, compile_ops_4) | bool True | builtin-class bool | +| n_nesting.py:16 | inner_2 = phi(inner_0, inner_1) | Function inner | builtin-class function | +| n_nesting.py:22 | C_9 = ScopeEntryDefinition | int 1 | builtin-class int | +| n_nesting.py:22 | f1_0 = FunctionExpr | Function f1 | builtin-class function | +| n_nesting.py:23 | C_10 = AttributeAssignment 'flag'(C_9) | int 1 | builtin-class int | +| n_nesting.py:24 | C_11 = ScopeEntryDefinition | class C | builtin-class type | +| n_nesting.py:24 | C_11 = ScopeEntryDefinition | int 1 | builtin-class int | +| n_nesting.py:24 | f1_1 = ScopeEntryDefinition | Function f1 | builtin-class function | +| n_nesting.py:24 | f2_0 = FunctionExpr | Function f2 | builtin-class function | +| n_nesting.py:25 | C_12 = CallsiteRefinement(C_11) | class C | builtin-class type | +| n_nesting.py:25 | C_12 = CallsiteRefinement(C_11) | int 1 | builtin-class int | +| n_nesting.py:26 | C_13 = ScopeEntryDefinition | class C | builtin-class type | +| n_nesting.py:26 | C_13 = ScopeEntryDefinition | int 1 | builtin-class int | +| n_nesting.py:26 | f2_1 = ScopeEntryDefinition | Function f2 | builtin-class function | +| n_nesting.py:26 | f3_0 = FunctionExpr | Function f3 | builtin-class function | +| n_nesting.py:27 | C_14 = CallsiteRefinement(C_13) | class C | builtin-class type | +| n_nesting.py:27 | C_14 = CallsiteRefinement(C_13) | int 1 | builtin-class int | +| n_nesting.py:28 | C_15 = ScopeEntryDefinition | class C | builtin-class type | +| n_nesting.py:28 | C_15 = ScopeEntryDefinition | int 1 | builtin-class int | +| n_nesting.py:28 | f3_1 = ScopeEntryDefinition | Function f3 | builtin-class function | +| n_nesting.py:28 | f4_0 = FunctionExpr | Function f4 | builtin-class function | +| n_nesting.py:29 | C_16 = CallsiteRefinement(C_15) | class C | builtin-class type | +| n_nesting.py:29 | C_16 = CallsiteRefinement(C_15) | int 1 | builtin-class int | +| n_nesting.py:30 | C_2 = ClassExpr | class C | builtin-class type | +| n_nesting.py:31 | C_3 = CallsiteRefinement(C_2) | class C | builtin-class type | +| n_nesting.py:32 | D_1 = ClassExpr | class D | builtin-class type | +| n_nesting.py:34 | C_4 = IntegerLiteral | int 1 | builtin-class int | +| q_super.py:0 | __name___0 = ScopeEntryDefinition | 'code.q_super' | builtin-class str | +| q_super.py:0 | __package___0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| q_super.py:1 | Base2_0 = ClassExpr | class Base2 | builtin-class type | +| q_super.py:3 | Base2_1 = ScopeEntryDefinition | class Base2 | builtin-class type | +| q_super.py:3 | __init___0 = FunctionExpr | Function __init__ | builtin-class function | +| q_super.py:3 | self_0 = ParameterDefinition | self | class Base2 | +| q_super.py:3 | self_0 = ParameterDefinition | self | class Derived4 | +| q_super.py:8 | Derived4_0 = ClassExpr | class Derived4 | builtin-class type | +| q_super.py:10 | Base2_2 = ScopeEntryDefinition | class Base2 | builtin-class type | +| q_super.py:10 | Derived4_1 = ScopeEntryDefinition | class Derived4 | builtin-class type | +| q_super.py:10 | __init___0 = FunctionExpr | Function __init__ | builtin-class function | +| q_super.py:10 | self_0 = ParameterDefinition | self | class Derived4 | +| q_super.py:14 | Base1_0 = ClassExpr | class Base1 | builtin-class type | +| q_super.py:16 | meth_0 = FunctionExpr | Function meth | builtin-class function | +| q_super.py:16 | self_0 = ParameterDefinition | self | class Base1 | +| q_super.py:16 | self_0 = ParameterDefinition | self | class Derived1 | +| q_super.py:16 | self_0 = ParameterDefinition | self | class Derived2 | +| q_super.py:16 | self_0 = ParameterDefinition | self | class Derived5 | +| q_super.py:16 | self_0 = ParameterDefinition | self | class Wrong1 | +| q_super.py:19 | Derived1_0 = ClassExpr | class Derived1 | builtin-class type | +| q_super.py:21 | Derived1_1 = ScopeEntryDefinition | class Derived1 | builtin-class type | +| q_super.py:21 | meth_0 = FunctionExpr | Function meth | builtin-class function | +| q_super.py:21 | self_0 = ParameterDefinition | self | class Derived1 | +| q_super.py:21 | self_0 = ParameterDefinition | self | class Derived2 | +| q_super.py:21 | self_0 = ParameterDefinition | self | class Derived5 | +| q_super.py:21 | self_0 = ParameterDefinition | self | class Wrong1 | +| q_super.py:24 | Derived2_0 = ClassExpr | class Derived2 | builtin-class type | +| q_super.py:26 | Derived2_1 = ScopeEntryDefinition | class Derived2 | builtin-class type | +| q_super.py:26 | meth_0 = FunctionExpr | Function meth | builtin-class function | +| q_super.py:26 | self_0 = ParameterDefinition | self | class Derived2 | +| q_super.py:26 | self_0 = ParameterDefinition | self | class Wrong1 | +| q_super.py:29 | Derived5_0 = ClassExpr | class Derived5 | builtin-class type | +| q_super.py:31 | Derived5_1 = ScopeEntryDefinition | class Derived5 | builtin-class type | +| q_super.py:31 | meth_0 = FunctionExpr | Function meth | builtin-class function | +| q_super.py:31 | self_0 = ParameterDefinition | self | class Derived5 | +| q_super.py:35 | Wrong1_0 = ClassExpr | class Wrong1 | builtin-class type | +| q_super.py:37 | Derived5_2 = ScopeEntryDefinition | class Derived5 | builtin-class type | +| q_super.py:37 | meth_0 = FunctionExpr | Function meth | builtin-class function | +| q_super.py:37 | self_0 = ParameterDefinition | self | class Wrong1 | +| q_super.py:41 | DA_0 = ClassExpr | class DA | builtin-class type | +| q_super.py:43 | __init___0 = FunctionExpr | Function __init__ | builtin-class function | +| q_super.py:43 | self_0 = ParameterDefinition | self | class DA | +| q_super.py:43 | self_0 = ParameterDefinition | self | class DC | +| q_super.py:43 | self_0 = ParameterDefinition | self | class DD | +| q_super.py:43 | self_0 = ParameterDefinition | self | class DF | +| q_super.py:46 | DA_1 = ScopeEntryDefinition | class DA | builtin-class type | +| q_super.py:46 | DB_0 = ClassExpr | class DB | builtin-class type | +| q_super.py:48 | DC_0 = ClassExpr | class DC | builtin-class type | +| q_super.py:50 | DB_1 = ScopeEntryDefinition | class DB | builtin-class type | +| q_super.py:50 | __init___0 = FunctionExpr | Function __init__ | builtin-class function | +| q_super.py:50 | self_0 = ParameterDefinition | self | class DC | +| q_super.py:51 | sup_0 = super() | super() | builtin-class super | +| q_super.py:52 | sup_1 = MethodCallsiteRefinement(sup_0) | super() | builtin-class super | +| q_super.py:55 | DD_0 = ClassExpr | class DD | builtin-class type | +| q_super.py:57 | DD_1 = ScopeEntryDefinition | class DD | builtin-class type | +| q_super.py:57 | __init___0 = FunctionExpr | Function __init__ | builtin-class function | +| q_super.py:57 | self_0 = ParameterDefinition | self | class DD | +| q_super.py:58 | sup_0 = super() | super() | builtin-class super | +| q_super.py:59 | sup_1 = MethodCallsiteRefinement(sup_0) | super() | builtin-class super | +| q_super.py:61 | DA_2 = ScopeEntryDefinition | class DA | builtin-class type | +| q_super.py:61 | DE_0 = ClassExpr | class DE | builtin-class type | +| q_super.py:63 | DF_0 = ClassExpr | class DF | builtin-class type | +| q_super.py:65 | DE_1 = ScopeEntryDefinition | class DE | builtin-class type | +| q_super.py:65 | __init___0 = FunctionExpr | Function __init__ | builtin-class function | +| q_super.py:65 | self_0 = ParameterDefinition | self | class DF | +| q_super.py:68 | N_0 = ClassExpr | class N | builtin-class type | +| q_super.py:71 | M_0 = ClassExpr | class M | builtin-class type | +| q_super.py:73 | M_1 = ScopeEntryDefinition | class M | builtin-class type | +| q_super.py:73 | __init___0 = FunctionExpr | Function __init__ | builtin-class function | +| q_super.py:73 | self_0 = ParameterDefinition | self | class M | +| q_super.py:74 | s_0 = super() | super() | builtin-class super | +| q_super.py:75 | i_0 = Attribute | super().__init__ | builtin-class method | +| s_scopes.py:0 | __name___0 = ScopeEntryDefinition | 'code.s_scopes' | builtin-class str | +| s_scopes.py:0 | __package___0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| s_scopes.py:0 | float_0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| s_scopes.py:0 | x_0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| s_scopes.py:4 | float_1 = True | bool True | builtin-class bool | +| s_scopes.py:5 | float_2 = phi(float_0, float_1) | *UNDEFINED* | *UNKNOWN TYPE* | +| s_scopes.py:5 | float_2 = phi(float_0, float_1) | bool True | builtin-class bool | +| s_scopes.py:7 | C2_0 = ClassExpr | class C2 | builtin-class type | +| s_scopes.py:7 | float_0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| s_scopes.py:7 | float_3 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| s_scopes.py:7 | float_3 = ScopeEntryDefinition | bool True | builtin-class bool | +| s_scopes.py:7 | int_0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| s_scopes.py:7 | str_0 = ScopeEntryDefinition | *UNDEFINED* | *UNKNOWN TYPE* | +| s_scopes.py:9 | i1_0 = int | builtin-class int | builtin-class type | +| s_scopes.py:10 | f1_0 = float | bool True | builtin-class bool | +| s_scopes.py:10 | f1_0 = float | builtin-class float | builtin-class type | +| s_scopes.py:12 | int_1 = IntegerLiteral | int 0 | builtin-class int | +| s_scopes.py:15 | str_1 = FloatLiteral | float 1.0 | builtin-class float | +| s_scopes.py:17 | float_1 = None | NoneType None | builtin-class NoneType | +| s_scopes.py:18 | float_2 = phi(float_0, float_1) | *UNDEFINED* | *UNKNOWN TYPE* | +| s_scopes.py:18 | float_2 = phi(float_0, float_1) | NoneType None | builtin-class NoneType | +| s_scopes.py:18 | i2_0 = int | int 0 | builtin-class int | +| s_scopes.py:18 | str_2 = phi(str_0, str_1) | *UNDEFINED* | *UNKNOWN TYPE* | +| s_scopes.py:18 | str_2 = phi(str_0, str_1) | float 1.0 | builtin-class float | +| s_scopes.py:19 | s_0 = str | builtin-class str | builtin-class type | +| s_scopes.py:19 | s_0 = str | float 1.0 | builtin-class float | +| s_scopes.py:20 | f2_0 = float | NoneType None | builtin-class NoneType | +| s_scopes.py:20 | f2_0 = float | bool True | builtin-class bool | +| s_scopes.py:20 | f2_0 = float | builtin-class float | builtin-class type | +| s_scopes.py:23 | i_0 = int | builtin-class int | builtin-class type | +| s_scopes.py:24 | f_0 = float | bool True | builtin-class bool | +| s_scopes.py:24 | f_0 = float | builtin-class float | builtin-class type | diff --git a/python/ql/test/library-tests/PointsTo/new/SSA.ql b/python/ql/test/library-tests/PointsTo/new/SSA.ql new file mode 100644 index 00000000000..e9ed6864567 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/SSA.ql @@ -0,0 +1,10 @@ + +import python +private import semmle.python.pointsto.PointsTo +private import semmle.python.pointsto.PointsToContext +import Util + +from EssaVariable v, EssaDefinition def, Object o, ClassObject cls +where def = v.getDefinition() and +PointsTo::ssa_variable_points_to(v, _, o, cls, _) +select locate(def.getLocation(), "abcdegjqmns_"), v.getRepresentation() + " = " + def.getRepresentation(), repr(o), repr(cls) diff --git a/python/ql/test/library-tests/PointsTo/new/Sanity.expected b/python/ql/test/library-tests/PointsTo/new/Sanity.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/library-tests/PointsTo/new/Sanity.ql b/python/ql/test/library-tests/PointsTo/new/Sanity.ql new file mode 100644 index 00000000000..94c7dfa1815 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/Sanity.ql @@ -0,0 +1,121 @@ + +import python +import semmle.python.pointsto.PointsTo + +predicate ssa_sanity(string clsname, string problem, string what) { + /* Exactly one definition of each SSA variable */ + exists(EssaVariable var | + clsname = var.getAQlClass() | + /* Exactly one definition of each SSA variable */ + count(var.getDefinition()) != 1 and problem = " has " + count(var.getDefinition()) + " definitions." and + what = "SSA variable " + var.getSourceVariable().getName() + or + /* Backing variable */ + not exists(var.getSourceVariable()) and problem = "An SSA variable has no backing variable." and + what = "An SSA variable" + or + count(var.getSourceVariable()) != 1 and problem = var.getSourceVariable().getName() + " has " + count(var.getSourceVariable()) + " backing variables." and + what = "SSA variable " + var.getSourceVariable().getName() + ) + or + /* Exactly one location */ + exists(EssaDefinition def | + clsname = def.getAQlClass() and + what = "SSA Definition " + def.getSourceVariable().getName() + " in " + def.getSourceVariable().(Variable).getScope().getName() and + count(def.getLocation()) != 1 and problem = " has " + count(def.getLocation()) + " locations" + ) + or + /* Must have a source variable */ + exists(EssaDefinition def | + clsname = def.getAQlClass() and + not exists(def.getSourceVariable()) and + what = " at " + def.getLocation() and + problem = "has not source variable" + ) + or + /* Variables must have exactly one representation */ + exists(EssaVariable var | + clsname = var.getAQlClass() and + what = "SSA variable " + var.getSourceVariable().getName() + " defined at " + var.getDefinition().getLocation() and + count(var.getRepresentation()) != 1 and problem = " has " + count(var.getRepresentation()) + " representations" + ) + or + /* Definitions must have exactly one representation */ + exists(EssaDefinition def | + clsname = def.getAQlClass() and + what = "SSA definition " + def.getSourceVariable().getName() + " at " + def.getLocation() and + count(def.getRepresentation()) != 1 and problem = " has " + count(def.getRepresentation()) + " representations: " + def.getRepresentation() + ) + or + /* Refinements must have exactly one input */ + exists(EssaNodeRefinement ref | + clsname = ref.getAQlClass() and + what = "Refinement " + ref.getSourceVariable().getName() + " at " + ref.getLocation() and + count(ref.getInput()) != 1 and problem = " has " + count(ref.getInput()) + " inputs: " + ref.getInput().getRepresentation() + ) + or + /* Ideally filter nodes should have exactly one input, but it is not a big deal + * if we prune away the input, leaving it with none. */ + exists(EssaEdgeRefinement def | + clsname = def.getAQlClass() and + what = def.getSourceVariable().getName() + " at " + def.getLocation() | + count(def.getInput()) > 1 and problem =" has " + count(def.getInput()) + " inputs." + ) + or + /* Each use has only one reaching SSA variable */ + exists(ControlFlowNode use, SsaSourceVariable v, int c | + c = strictcount(EssaVariable s | s.getAUse() = use and s.getSourceVariable() = v) and + clsname = use.getAQlClass() and c != 1 and + what = use + " at " + use.getLocation() and + problem =" has " + c + " SSA variables reaching." + ) + or + /* Python-specific subclasses of EssaDefinitions should be disjoint and complete */ + exists(EssaDefinition def | + clsname = def.getAQlClass() and + what = def.getVariable().getName() + " at " + def.getLocation() and + problem = "has non-disjoint subclasses" | + strictcount(def.getAQlClass()) > 2 or + /* OK if method call and argument overlap: `x.foo(x)` */ + strictcount(def.getAQlClass()) > 1 and + not clsname = "ArgumentRefinement" and not clsname = "SelfCallsiteRefinement" + ) + or + exists(EssaDefinition def | + clsname = def.getAQlClass() and + clsname.prefix(4) = "Essa" and + what = " at " + def.getLocation() and + problem = "not covered by Python-specific subclass." + ) + or + // All modules should have __name__ + exists(Module m | + what = " at " + m.getLocation() and + clsname = "Module" | + not exists(m.getName()) and + problem = "does not have a name" + or + not exists(Variable v | v.getId() = "__name__" and v.getScope() = m) and + problem = "does not have a __name__ variable" + or + not exists(PyNodeDefinition def | + def.getDefiningNode().getScope() = m and + def.getVariable().getName() = "__name__" + ) and + problem = "does not have an ImplicitModuleNameDefinition" + ) + or + // Unknown value should always have the class unknownType + exists(ControlFlowNode f, ClassObject cls | + PointsTo::points_to(f, _, unknownValue(), cls, _) and + clsname = f.getAQlClass() and + cls != theUnknownType() and + problem = "unknownValue() has class != theUnknownType()" and + what = cls.getName() + ) +} + +from string clsname, string problem, string what +where ssa_sanity(clsname, problem, what) +select clsname, what, problem + diff --git a/python/ql/test/library-tests/PointsTo/new/SourceEdgeDefinitions.expected b/python/ql/test/library-tests/PointsTo/new/SourceEdgeDefinitions.expected new file mode 100644 index 00000000000..900b5ee9152 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/SourceEdgeDefinitions.expected @@ -0,0 +1,22 @@ +| b_condition.py:7 | Local Variable x | ControlFlowNode for x | +| b_condition.py:13 | Local Variable x | ControlFlowNode for x | +| b_condition.py:19 | Local Variable x | ControlFlowNode for x | +| b_condition.py:25 | Local Variable x | ControlFlowNode for x | +| b_condition.py:32 | Local Variable x | ControlFlowNode for x | +| b_condition.py:36 | Local Variable x | ControlFlowNode for x | +| b_condition.py:42 | Global Variable v2 | ControlFlowNode for v2 | +| b_condition.py:51 | Local Variable x | ControlFlowNode for x | +| b_condition.py:57 | Local Variable v | ControlFlowNode for v | +| b_condition.py:62 | Local Variable x | ControlFlowNode for x | +| b_condition.py:64 | Local Variable y | ControlFlowNode for y | +| b_condition.py:65 | Local Variable x | ControlFlowNode for x | +| b_condition.py:66 | Local Variable x | ControlFlowNode for x | +| b_condition.py:71 | Local Variable b | ControlFlowNode for b | +| b_condition.py:77 | Local Variable t | ControlFlowNode for t | +| b_condition.py:82 | Local Variable foo | ControlFlowNode for foo | +| b_condition.py:88 | Local Variable x | ControlFlowNode for x | +| b_condition.py:88 | Local Variable y | ControlFlowNode for y | +| b_condition.py:90 | Local Variable y | ControlFlowNode for y | +| b_condition.py:102 | Local Variable a | ControlFlowNode for a | +| b_condition.py:104 | Local Variable a | ControlFlowNode for a | +| b_condition.py:105 | Local Variable a | ControlFlowNode for a | diff --git a/python/ql/test/library-tests/PointsTo/new/SourceEdgeDefinitions.ql b/python/ql/test/library-tests/PointsTo/new/SourceEdgeDefinitions.ql new file mode 100644 index 00000000000..4feb22b31ba --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/SourceEdgeDefinitions.ql @@ -0,0 +1,10 @@ + +import python +import semmle.dataflow.SSA +import semmle.python.pointsto.PointsTo + +import Util + +from SsaSourceVariable var, ControlFlowNode use, BasicBlock pred +where var.hasRefinementEdge(use, pred, _) +select locate(pred.getLastNode().getLocation(), "ab"), var.(Variable), use.toString() diff --git a/python/ql/test/library-tests/PointsTo/new/SourceNodeDefinitions.expected b/python/ql/test/library-tests/PointsTo/new/SourceNodeDefinitions.expected new file mode 100644 index 00000000000..55363237c62 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/SourceNodeDefinitions.expected @@ -0,0 +1,121 @@ +| a_simple.py:0 | Global Variable C | Entry node for Module code.a_simple | definition | +| a_simple.py:0 | Global Variable __name__ | Entry node for Module code.a_simple | definition | +| a_simple.py:0 | Global Variable __package__ | Entry node for Module code.a_simple | definition | +| a_simple.py:0 | Global Variable f | Entry node for Module code.a_simple | definition | +| a_simple.py:0 | Global Variable f1 | Entry node for Module code.a_simple | definition | +| a_simple.py:0 | Global Variable func | Entry node for Module code.a_simple | definition | +| a_simple.py:0 | Global Variable i1 | Entry node for Module code.a_simple | definition | +| a_simple.py:0 | Global Variable multi_loop | Entry node for Module code.a_simple | definition | +| a_simple.py:0 | Global Variable multi_loop_in_try | Entry node for Module code.a_simple | definition | +| a_simple.py:0 | Global Variable s | Entry node for Module code.a_simple | definition | +| a_simple.py:0 | Global Variable vararg_kwarg | Entry node for Module code.a_simple | definition | +| a_simple.py:0 | Global Variable with_definition | Entry node for Module code.a_simple | definition | +| a_simple.py:2 | Global Variable f1 | ControlFlowNode for f1 | definition | +| a_simple.py:5 | Global Variable i1 | ControlFlowNode for i1 | definition | +| a_simple.py:6 | Global Variable s | ControlFlowNode for s | definition | +| a_simple.py:8 | Global Variable func | ControlFlowNode for func | definition | +| a_simple.py:11 | Global Variable C | ControlFlowNode for C | definition | +| a_simple.py:14 | Global Variable vararg_kwarg | ControlFlowNode for vararg_kwarg | definition | +| a_simple.py:14 | Local Variable d | ControlFlowNode for d | definition | +| a_simple.py:14 | Local Variable d | Entry node for Function vararg_kwarg | definition | +| a_simple.py:14 | Local Variable t | ControlFlowNode for t | definition | +| a_simple.py:14 | Local Variable t | Entry node for Function vararg_kwarg | definition | +| a_simple.py:18 | Global Variable multi_loop | ControlFlowNode for multi_loop | definition | +| a_simple.py:18 | Local Variable seq | ControlFlowNode for seq | definition | +| a_simple.py:18 | Local Variable x | Entry node for Function multi_loop | definition | +| a_simple.py:18 | Local Variable y | Entry node for Function multi_loop | definition | +| a_simple.py:19 | Local Variable x | ControlFlowNode for x | definition | +| a_simple.py:20 | Local Variable x | ControlFlowNode for x | definition | +| a_simple.py:20 | Local Variable y | ControlFlowNode for y | definition | +| a_simple.py:23 | Global Variable with_definition | ControlFlowNode for with_definition | definition | +| a_simple.py:23 | Local Variable x | ControlFlowNode for x | definition | +| a_simple.py:23 | Local Variable y | Entry node for Function with_definition | definition | +| a_simple.py:24 | Local Variable y | ControlFlowNode for y | definition | +| a_simple.py:27 | Global Variable multi_loop_in_try | ControlFlowNode for multi_loop_in_try | definition | +| a_simple.py:27 | Local Variable p | Entry node for Function multi_loop_in_try | definition | +| a_simple.py:27 | Local Variable q | Entry node for Function multi_loop_in_try | definition | +| a_simple.py:27 | Local Variable x | ControlFlowNode for x | definition | +| a_simple.py:29 | Local Variable p | ControlFlowNode for p | definition | +| a_simple.py:29 | Local Variable q | ControlFlowNode for q | definition | +| a_simple.py:34 | Global Variable f | ControlFlowNode for f | definition | +| a_simple.py:34 | Local Variable args | ControlFlowNode for args | definition | +| a_simple.py:34 | Local Variable args | Entry node for Function f | definition | +| a_simple.py:34 | Local Variable kwargs | ControlFlowNode for kwargs | definition | +| a_simple.py:34 | Local Variable kwargs | Entry node for Function f | definition | +| b_condition.py:0 | Global Variable __name__ | Entry node for Module code.b_condition | definition | +| b_condition.py:0 | Global Variable __package__ | Entry node for Module code.b_condition | definition | +| b_condition.py:0 | Global Variable double_attr_check | Entry node for Module code.b_condition | definition | +| b_condition.py:0 | Global Variable f | Entry node for Module code.b_condition | definition | +| b_condition.py:0 | Global Variable g | Entry node for Module code.b_condition | definition | +| b_condition.py:0 | Global Variable h | Entry node for Module code.b_condition | definition | +| b_condition.py:0 | Global Variable k | Entry node for Module code.b_condition | definition | +| b_condition.py:0 | Global Variable loop | Entry node for Module code.b_condition | definition | +| b_condition.py:0 | Global Variable not_or_not | Entry node for Module code.b_condition | definition | +| b_condition.py:0 | Global Variable odasa6261 | Entry node for Module code.b_condition | definition | +| b_condition.py:0 | Global Variable split_bool1 | Entry node for Module code.b_condition | definition | +| b_condition.py:0 | Global Variable v2 | Entry node for Module code.b_condition | definition | +| b_condition.py:4 | Global Variable f | ControlFlowNode for f | definition | +| b_condition.py:4 | Local Variable x | Entry node for Function f | definition | +| b_condition.py:4 | Local Variable y | ControlFlowNode for y | definition | +| b_condition.py:5 | Local Variable x | ControlFlowNode for x | definition | +| b_condition.py:8 | Local Variable x | ControlFlowNode for x | definition | +| b_condition.py:9 | Local Variable x | ControlFlowNode for use() | refinement | +| b_condition.py:11 | Local Variable x | ControlFlowNode for x | definition | +| b_condition.py:14 | Local Variable x | ControlFlowNode for x | definition | +| b_condition.py:15 | Local Variable x | ControlFlowNode for use() | refinement | +| b_condition.py:17 | Local Variable x | ControlFlowNode for x | definition | +| b_condition.py:20 | Local Variable x | ControlFlowNode for x | definition | +| b_condition.py:21 | Local Variable x | ControlFlowNode for use() | refinement | +| b_condition.py:23 | Local Variable x | ControlFlowNode for x | definition | +| b_condition.py:25 | Local Variable x | ControlFlowNode for x | definition | +| b_condition.py:26 | Local Variable x | ControlFlowNode for use() | refinement | +| b_condition.py:28 | Local Variable x | ControlFlowNode for x | definition | +| b_condition.py:29 | Local Variable x | ControlFlowNode for use() | refinement | +| b_condition.py:31 | Local Variable x | ControlFlowNode for x | definition | +| b_condition.py:33 | Local Variable x | ControlFlowNode for x | definition | +| b_condition.py:34 | Local Variable x | ControlFlowNode for use() | refinement | +| b_condition.py:36 | Local Variable x | ControlFlowNode for isinstance() | refinement | +| b_condition.py:37 | Local Variable x | ControlFlowNode for use() | refinement | +| b_condition.py:39 | Global Variable v2 | ControlFlowNode for v2 | definition | +| b_condition.py:41 | Global Variable v2 | ControlFlowNode for Attribute | refinement | +| b_condition.py:50 | Global Variable g | ControlFlowNode for g | definition | +| b_condition.py:50 | Local Variable x | ControlFlowNode for x | definition | +| b_condition.py:55 | Global Variable loop | ControlFlowNode for loop | definition | +| b_condition.py:55 | Local Variable seq | ControlFlowNode for seq | definition | +| b_condition.py:55 | Local Variable v | Entry node for Function loop | definition | +| b_condition.py:56 | Local Variable v | ControlFlowNode for v | definition | +| b_condition.py:58 | Local Variable v | ControlFlowNode for use() | refinement | +| b_condition.py:61 | Global Variable double_attr_check | ControlFlowNode for double_attr_check | definition | +| b_condition.py:61 | Local Variable x | ControlFlowNode for x | definition | +| b_condition.py:61 | Local Variable y | ControlFlowNode for y | definition | +| b_condition.py:69 | Global Variable h | ControlFlowNode for h | definition | +| b_condition.py:69 | Local Variable b | Entry node for Function h | definition | +| b_condition.py:70 | Local Variable b | ControlFlowNode for b | definition | +| b_condition.py:72 | Local Variable b | ControlFlowNode for b | definition | +| b_condition.py:75 | Global Variable k | ControlFlowNode for k | definition | +| b_condition.py:75 | Local Variable t | Entry node for Function k | definition | +| b_condition.py:76 | Local Variable t | ControlFlowNode for t | definition | +| b_condition.py:78 | Local Variable t | ControlFlowNode for t | definition | +| b_condition.py:79 | Local Variable t | ControlFlowNode for use() | refinement | +| b_condition.py:81 | Global Variable odasa6261 | ControlFlowNode for odasa6261 | definition | +| b_condition.py:81 | Local Variable bar | Entry node for Function odasa6261 | definition | +| b_condition.py:81 | Local Variable foo | ControlFlowNode for foo | definition | +| b_condition.py:82 | Local Variable foo | ControlFlowNode for callable() | refinement | +| b_condition.py:83 | Local Variable bar | ControlFlowNode for bar | definition | +| b_condition.py:83 | Local Variable foo | Entry node for Function bar | definition | +| b_condition.py:84 | Local Variable foo | ControlFlowNode for foo() | refinement | +| b_condition.py:87 | Global Variable split_bool1 | ControlFlowNode for split_bool1 | definition | +| b_condition.py:87 | Local Variable x | ControlFlowNode for x | definition | +| b_condition.py:87 | Local Variable y | ControlFlowNode for y | definition | +| b_condition.py:90 | Local Variable x | ControlFlowNode for UnaryExpr | refinement | +| b_condition.py:90 | Local Variable x | ControlFlowNode for x | refinement | +| b_condition.py:92 | Local Variable x | ControlFlowNode for x | refinement | +| b_condition.py:93 | Local Variable y | ControlFlowNode for use() | refinement | +| b_condition.py:95 | Local Variable y | ControlFlowNode for use() | refinement | +| b_condition.py:96 | Local Variable y | ControlFlowNode for y | refinement | +| b_condition.py:97 | Local Variable x | ControlFlowNode for use() | refinement | +| b_condition.py:99 | Local Variable x | ControlFlowNode for use() | refinement | +| b_condition.py:101 | Global Variable not_or_not | ControlFlowNode for not_or_not | definition | +| b_condition.py:101 | Local Variable a | ControlFlowNode for a | definition | +| b_condition.py:101 | Local Variable a | Entry node for Function not_or_not | definition | +| b_condition.py:102 | Local Variable a | ControlFlowNode for isinstance() | refinement | diff --git a/python/ql/test/library-tests/PointsTo/new/SourceNodeDefinitions.ql b/python/ql/test/library-tests/PointsTo/new/SourceNodeDefinitions.ql new file mode 100644 index 00000000000..95341360bf4 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/SourceNodeDefinitions.ql @@ -0,0 +1,13 @@ + +import python +import semmle.dataflow.SSA +import semmle.python.pointsto.PointsTo + +import Util + +from SsaSourceVariable var, ControlFlowNode defn, string kind +where +var.hasDefiningNode(defn) and kind = "definition" +or +var.hasRefinement(_, defn) and kind = "refinement" +select locate(defn.getLocation(), "ab"), var.(Variable), defn.toString(), kind diff --git a/python/ql/test/library-tests/PointsTo/new/SsaAttr.expected b/python/ql/test/library-tests/PointsTo/new/SsaAttr.expected new file mode 100644 index 00000000000..f518b462be1 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/SsaAttr.expected @@ -0,0 +1,91 @@ +| b_condition.py:41 | v2_2 | x | AttributeAssignment 'x'(v2_1) | int 1 | import | +| b_condition.py:43 | v2_3 | x | Pi(v2_2) [true] | int 1 | import | +| b_condition.py:47 | v2_4 | x | Pi(v2_2) [false] | int 1 | import | +| b_condition.py:47 | v2_5 | x | phi(v2_3, v2_4) | int 1 | import | +| f_finally.py:3 | self_3 | _closed | phi(self_1, self_2) | bool True | runtime | +| f_finally.py:4 | self_1 | _closed | AttributeAssignment '_closed'(self_0) | bool True | runtime | +| f_finally.py:10 | self_2 | _closed | AttributeAssignment '_close'(self_1) | bool True | runtime | +| g_class_init.py:6 | self_1 | y | SelfCallsiteRefinement(self_0) | int 2 | runtime | +| g_class_init.py:6 | self_1 | z | SelfCallsiteRefinement(self_0) | int 3 | runtime | +| g_class_init.py:7 | self_2 | x | AttributeAssignment 'x'(self_1) | int 1 | runtime | +| g_class_init.py:7 | self_2 | y | AttributeAssignment 'x'(self_1) | int 2 | runtime | +| g_class_init.py:7 | self_2 | z | AttributeAssignment 'x'(self_1) | int 3 | runtime | +| g_class_init.py:10 | self_1 | y | AttributeAssignment 'y'(self_0) | int 2 | code/g_class_init.py:6 from runtime | +| g_class_init.py:11 | self_2 | y | SelfCallsiteRefinement(self_1) | int 2 | code/g_class_init.py:6 from runtime | +| g_class_init.py:11 | self_2 | z | SelfCallsiteRefinement(self_1) | int 3 | code/g_class_init.py:6 from runtime | +| g_class_init.py:13 | self_0 | y | ParameterDefinition | int 2 | code/g_class_init.py:11 from code/g_class_init.py:6 from runtime | +| g_class_init.py:14 | self_1 | y | AttributeAssignment 'z'(self_0) | int 2 | code/g_class_init.py:11 from code/g_class_init.py:6 from runtime | +| g_class_init.py:14 | self_1 | z | AttributeAssignment 'z'(self_0) | int 3 | code/g_class_init.py:11 from code/g_class_init.py:6 from runtime | +| g_class_init.py:16 | self_0 | x | ParameterDefinition | int 1 | runtime | +| g_class_init.py:16 | self_0 | y | ParameterDefinition | int 2 | runtime | +| g_class_init.py:16 | self_0 | z | ParameterDefinition | int 3 | runtime | +| g_class_init.py:19 | self_1 | x | Pi(self_0) [true] | int 1 | runtime | +| g_class_init.py:19 | self_1 | y | Pi(self_0) [true] | int 2 | runtime | +| g_class_init.py:19 | self_1 | z | Pi(self_0) [true] | int 3 | runtime | +| g_class_init.py:20 | self_2 | x | Pi(self_0) [false] | int 1 | runtime | +| g_class_init.py:20 | self_2 | z | Pi(self_0) [false] | int 3 | runtime | +| g_class_init.py:20 | self_3 | x | phi(self_1, self_2) | int 1 | runtime | +| g_class_init.py:20 | self_3 | y | phi(self_1, self_2) | int 2 | runtime | +| g_class_init.py:20 | self_3 | z | phi(self_1, self_2) | int 3 | runtime | +| g_class_init.py:46 | self_3 | version | phi(self_1, self_2) | 'v2' | runtime | +| g_class_init.py:46 | self_3 | version | phi(self_1, self_2) | 'v3' | runtime | +| g_class_init.py:48 | self_1 | version | AttributeAssignment 'version'(self_0) | 'v2' | runtime | +| g_class_init.py:50 | self_2 | version | AttributeAssignment 'version'(self_0) | 'v3' | runtime | +| g_class_init.py:52 | self_0 | version | ParameterDefinition | 'v2' | runtime | +| g_class_init.py:52 | self_0 | version | ParameterDefinition | 'v3' | runtime | +| g_class_init.py:52 | self_2 | version | Pi(self_0) [false] | 'v3' | runtime | +| g_class_init.py:52 | self_3 | version | phi(self_1, self_2) | 'v2' | runtime | +| g_class_init.py:52 | self_3 | version | phi(self_1, self_2) | 'v3' | runtime | +| g_class_init.py:54 | self_1 | version | Pi(self_0) [true] | 'v2' | runtime | +| i_imports.py:7 | *_1 | x | ImportStarRefinement(*_0) | float 1.0 | import | +| i_imports.py:7 | *_1 | y | ImportStarRefinement(*_0) | float 2.0 | import | +| i_imports.py:27 | *_2 | module1 | ImportStarRefinement(*_1) | Module code.test_package.module1 | import | +| i_imports.py:27 | *_2 | module2 | ImportStarRefinement(*_1) | Module code.test_package.module2 | import | +| i_imports.py:27 | *_2 | p | ImportStarRefinement(*_1) | int 1 | import | +| i_imports.py:27 | *_2 | q | ImportStarRefinement(*_1) | int 2 | import | +| i_imports.py:27 | *_2 | r | ImportStarRefinement(*_1) | Dict | import | +| i_imports.py:27 | *_2 | s | ImportStarRefinement(*_1) | NoneType None | import | +| i_imports.py:27 | *_2 | x | ImportStarRefinement(*_1) | float 1.0 | import | +| i_imports.py:27 | *_2 | y | ImportStarRefinement(*_1) | float 2.0 | import | +| k_getsetattr.py:6 | self_0 | a | ParameterDefinition | float 7.0 | code/k_getsetattr.py:15 from runtime | +| k_getsetattr.py:6 | self_0 | c | ParameterDefinition | int 2 | code/k_getsetattr.py:15 from runtime | +| k_getsetattr.py:7 | self_1 | a | ArgumentRefinement(self_0) | int 0 | code/k_getsetattr.py:15 from runtime | +| k_getsetattr.py:7 | self_1 | a | ArgumentRefinement(self_0) | int 0 | runtime | +| k_getsetattr.py:7 | self_1 | c | ArgumentRefinement(self_0) | int 2 | code/k_getsetattr.py:15 from runtime | +| k_getsetattr.py:8 | self_2 | a | ArgumentRefinement(self_1) | int 0 | code/k_getsetattr.py:15 from runtime | +| k_getsetattr.py:8 | self_2 | a | ArgumentRefinement(self_1) | int 0 | runtime | +| k_getsetattr.py:8 | self_2 | b | ArgumentRefinement(self_1) | int 1 | code/k_getsetattr.py:15 from runtime | +| k_getsetattr.py:8 | self_2 | b | ArgumentRefinement(self_1) | int 1 | runtime | +| k_getsetattr.py:8 | self_2 | c | ArgumentRefinement(self_1) | int 2 | code/k_getsetattr.py:15 from runtime | +| k_getsetattr.py:9 | self_3 | a | ArgumentRefinement(self_2) | int 0 | code/k_getsetattr.py:15 from runtime | +| k_getsetattr.py:9 | self_3 | a | ArgumentRefinement(self_2) | int 0 | runtime | +| k_getsetattr.py:9 | self_3 | b | ArgumentRefinement(self_2) | int 1 | code/k_getsetattr.py:15 from runtime | +| k_getsetattr.py:9 | self_3 | b | ArgumentRefinement(self_2) | int 1 | runtime | +| k_getsetattr.py:9 | self_3 | c | ArgumentRefinement(self_2) | int 2 | code/k_getsetattr.py:15 from runtime | +| k_getsetattr.py:10 | self_4 | a | ArgumentRefinement(self_3) | int 0 | code/k_getsetattr.py:15 from runtime | +| k_getsetattr.py:10 | self_4 | a | ArgumentRefinement(self_3) | int 0 | runtime | +| k_getsetattr.py:10 | self_4 | b | ArgumentRefinement(self_3) | int 1 | code/k_getsetattr.py:15 from runtime | +| k_getsetattr.py:10 | self_4 | b | ArgumentRefinement(self_3) | int 1 | runtime | +| k_getsetattr.py:10 | self_4 | c | ArgumentRefinement(self_3) | int 2 | code/k_getsetattr.py:15 from runtime | +| k_getsetattr.py:13 | self_1 | a | ArgumentRefinement(self_0) | float 7.0 | runtime | +| k_getsetattr.py:14 | self_2 | a | ArgumentRefinement(self_1) | float 7.0 | runtime | +| k_getsetattr.py:14 | self_2 | c | ArgumentRefinement(self_1) | int 2 | runtime | +| k_getsetattr.py:15 | self_3 | a | SelfCallsiteRefinement(self_2) | int 0 | runtime | +| k_getsetattr.py:15 | self_3 | b | SelfCallsiteRefinement(self_2) | int 1 | runtime | +| k_getsetattr.py:15 | self_3 | c | SelfCallsiteRefinement(self_2) | int 2 | runtime | +| k_getsetattr.py:16 | self_4 | a | ArgumentRefinement(self_3) | int 0 | runtime | +| k_getsetattr.py:16 | self_4 | b | ArgumentRefinement(self_3) | int 1 | runtime | +| k_getsetattr.py:16 | self_4 | c | ArgumentRefinement(self_3) | int 2 | runtime | +| k_getsetattr.py:17 | self_5 | a | ArgumentRefinement(self_4) | int 0 | runtime | +| k_getsetattr.py:17 | self_5 | b | ArgumentRefinement(self_4) | int 1 | runtime | +| k_getsetattr.py:17 | self_5 | c | ArgumentRefinement(self_4) | int 2 | runtime | +| k_getsetattr.py:18 | self_6 | a | ArgumentRefinement(self_5) | int 0 | runtime | +| k_getsetattr.py:18 | self_6 | b | ArgumentRefinement(self_5) | int 1 | runtime | +| k_getsetattr.py:18 | self_6 | c | ArgumentRefinement(self_5) | int 2 | runtime | +| k_getsetattr.py:25 | c1_1 | a | AttributeAssignment 'a'(c1_0) | int 10 | runtime | +| k_getsetattr.py:27 | c2_1 | a | AttributeAssignment 'a'(c2_0) | int 20 | runtime | +| k_getsetattr.py:28 | c2_2 | a | phi(c2_0, c2_1) | int 20 | runtime | +| k_getsetattr.py:31 | c3_1 | a | AttributeAssignment 'a'(c3_0) | int 30 | runtime | +| m_attributes.py:6 | self_1 | a | AttributeAssignment 'a'(self_0) | int 17 | runtime | +| m_attributes.py:6 | self_1 | a | AttributeAssignment 'a'(self_0) | int 100 | code/m_attributes.py:13 from import | +| m_attributes.py:8 | self_0 | a | ParameterDefinition | int 17 | runtime | diff --git a/python/ql/test/library-tests/PointsTo/new/SsaAttr.ql b/python/ql/test/library-tests/PointsTo/new/SsaAttr.ql new file mode 100644 index 00000000000..4a2fac535cf --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/SsaAttr.ql @@ -0,0 +1,12 @@ + +import python +private import semmle.python.pointsto.PointsTo +private import semmle.python.pointsto.PointsToContext +import Util + +from EssaVariable var, string name, Object o, PointsToContext ctx +where PointsTo::Test::ssa_variable_named_attribute_points_to(var, ctx, name, o, _, _) +select +locate(var.getDefinition().getLocation(), "abdfgikm"), var.getRepresentation(), +name, var.getDefinition().getRepresentation(), repr(o), ctx + diff --git a/python/ql/test/library-tests/PointsTo/new/SsaUses.expected b/python/ql/test/library-tests/PointsTo/new/SsaUses.expected new file mode 100644 index 00000000000..171e9174cba --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/SsaUses.expected @@ -0,0 +1,653 @@ +| __init__.py:0 | *_2 | Exit node for Module code.test_package.__init__ | +| __init__.py:0 | __name___0 | Exit node for Module code.__init__ | +| __init__.py:0 | __name___0 | Exit node for Module code.package.__init__ | +| __init__.py:0 | __name___2 | Exit node for Module code.test_package.__init__ | +| __init__.py:0 | __package___0 | Exit node for Module code.__init__ | +| __init__.py:0 | __package___0 | Exit node for Module code.package.__init__ | +| __init__.py:0 | __package___2 | Exit node for Module code.test_package.__init__ | +| __init__.py:0 | module2_1 | Exit node for Module code.package.__init__ | +| __init__.py:0 | module3_0 | Exit node for Module code.package.__init__ | +| __init__.py:0 | module4_0 | Exit node for Module code.package.__init__ | +| __init__.py:0 | module5_0 | Exit node for Module code.package.__init__ | +| __init__.py:0 | moduleX_1 | Exit node for Module code.package.__init__ | +| __init__.py:0 | module_0 | Exit node for Module code.package.__init__ | +| __init__.py:0 | sys_2 | Exit node for Module code.test_package.__init__ | +| __init__.py:1 | *_0 | ControlFlowNode for from module1 import * | +| __init__.py:1 | __name___0 | ControlFlowNode for from module1 import * | +| __init__.py:1 | __package___0 | ControlFlowNode for from module1 import * | +| __init__.py:1 | sys_0 | ControlFlowNode for from module1 import * | +| __init__.py:2 | *_1 | ControlFlowNode for from module2 import * | +| __init__.py:2 | __name___1 | ControlFlowNode for from module2 import * | +| __init__.py:2 | __package___1 | ControlFlowNode for from module2 import * | +| __init__.py:2 | sys_1 | ControlFlowNode for from module2 import * | +| __init__.py:4 | module2_0 | ControlFlowNode for ImportMember | +| __init__.py:6 | module2_1 | ControlFlowNode for ImportMember | +| __init__.py:7 | module3_0 | ControlFlowNode for ImportMember | +| __init__.py:8 | moduleX_0 | ControlFlowNode for ImportMember | +| a_simple.py:0 | C_0 | Exit node for Module code.a_simple | +| a_simple.py:0 | __name___0 | Exit node for Module code.a_simple | +| a_simple.py:0 | __package___0 | Exit node for Module code.a_simple | +| a_simple.py:0 | f1_0 | Exit node for Module code.a_simple | +| a_simple.py:0 | f_0 | Exit node for Module code.a_simple | +| a_simple.py:0 | func_0 | Exit node for Module code.a_simple | +| a_simple.py:0 | i1_0 | Exit node for Module code.a_simple | +| a_simple.py:0 | multi_loop_0 | Exit node for Module code.a_simple | +| a_simple.py:0 | multi_loop_in_try_0 | Exit node for Module code.a_simple | +| a_simple.py:0 | s_0 | Exit node for Module code.a_simple | +| a_simple.py:0 | vararg_kwarg_0 | Exit node for Module code.a_simple | +| a_simple.py:0 | with_definition_0 | Exit node for Module code.a_simple | +| a_simple.py:14 | d_0 | Exit node for Function vararg_kwarg | +| a_simple.py:14 | t_0 | Exit node for Function vararg_kwarg | +| a_simple.py:15 | t_0 | ControlFlowNode for t | +| a_simple.py:16 | d_0 | ControlFlowNode for d | +| a_simple.py:18 | seq_0 | Exit node for Function multi_loop | +| a_simple.py:18 | x_1 | Exit node for Function multi_loop | +| a_simple.py:18 | y_1 | Exit node for Function multi_loop | +| a_simple.py:20 | seq_0 | ControlFlowNode for seq | +| a_simple.py:21 | x_2 | ControlFlowNode for x | +| a_simple.py:23 | x_0 | Exit node for Function with_definition | +| a_simple.py:23 | y_0 | Exit node for Function with_definition | +| a_simple.py:24 | x_0 | ControlFlowNode for x | +| a_simple.py:25 | y_0 | ControlFlowNode for y | +| a_simple.py:27 | p_1 | Exit node for Function multi_loop_in_try | +| a_simple.py:27 | q_1 | Exit node for Function multi_loop_in_try | +| a_simple.py:27 | x_0 | Exit node for Function multi_loop_in_try | +| a_simple.py:29 | x_0 | ControlFlowNode for x | +| a_simple.py:30 | p_2 | ControlFlowNode for p | +| a_simple.py:34 | args_0 | Exit node for Function f | +| a_simple.py:34 | kwargs_0 | Exit node for Function f | +| a_simple.py:35 | args_0 | ControlFlowNode for args | +| a_simple.py:36 | kwargs_0 | ControlFlowNode for kwargs | +| b_condition.py:0 | __name___0 | Exit node for Module code.b_condition | +| b_condition.py:0 | __package___0 | Exit node for Module code.b_condition | +| b_condition.py:0 | double_attr_check_1 | Exit node for Module code.b_condition | +| b_condition.py:0 | f_0 | Exit node for Module code.b_condition | +| b_condition.py:0 | g_1 | Exit node for Module code.b_condition | +| b_condition.py:0 | h_1 | Exit node for Module code.b_condition | +| b_condition.py:0 | k_1 | Exit node for Module code.b_condition | +| b_condition.py:0 | loop_1 | Exit node for Module code.b_condition | +| b_condition.py:0 | not_or_not_1 | Exit node for Module code.b_condition | +| b_condition.py:0 | odasa6261_1 | Exit node for Module code.b_condition | +| b_condition.py:0 | split_bool1_1 | Exit node for Module code.b_condition | +| b_condition.py:0 | v2_5 | Exit node for Module code.b_condition | +| b_condition.py:4 | x_25 | Exit node for Function f | +| b_condition.py:4 | y_0 | Exit node for Function f | +| b_condition.py:7 | x_0 | ControlFlowNode for x | +| b_condition.py:9 | x_3 | ControlFlowNode for x | +| b_condition.py:13 | x_4 | ControlFlowNode for x | +| b_condition.py:15 | x_7 | ControlFlowNode for x | +| b_condition.py:19 | x_8 | ControlFlowNode for x | +| b_condition.py:21 | x_11 | ControlFlowNode for x | +| b_condition.py:25 | x_12 | ControlFlowNode for x | +| b_condition.py:25 | x_13 | ControlFlowNode for x | +| b_condition.py:26 | x_14 | ControlFlowNode for x | +| b_condition.py:29 | x_17 | ControlFlowNode for x | +| b_condition.py:32 | x_18 | ControlFlowNode for x | +| b_condition.py:34 | x_21 | ControlFlowNode for x | +| b_condition.py:36 | x_22 | ControlFlowNode for x | +| b_condition.py:37 | x_24 | ControlFlowNode for x | +| b_condition.py:39 | __name___0 | ControlFlowNode for thing() | +| b_condition.py:39 | __package___0 | ControlFlowNode for thing() | +| b_condition.py:39 | double_attr_check_0 | ControlFlowNode for thing() | +| b_condition.py:39 | f_0 | ControlFlowNode for thing() | +| b_condition.py:39 | g_0 | ControlFlowNode for thing() | +| b_condition.py:39 | h_0 | ControlFlowNode for thing() | +| b_condition.py:39 | k_0 | ControlFlowNode for thing() | +| b_condition.py:39 | loop_0 | ControlFlowNode for thing() | +| b_condition.py:39 | not_or_not_0 | ControlFlowNode for thing() | +| b_condition.py:39 | odasa6261_0 | ControlFlowNode for thing() | +| b_condition.py:39 | split_bool1_0 | ControlFlowNode for thing() | +| b_condition.py:39 | v2_0 | ControlFlowNode for thing() | +| b_condition.py:41 | v2_1 | ControlFlowNode for v2 | +| b_condition.py:42 | v2_2 | ControlFlowNode for v2 | +| b_condition.py:43 | __name___0 | ControlFlowNode for use() | +| b_condition.py:43 | __package___0 | ControlFlowNode for use() | +| b_condition.py:43 | double_attr_check_0 | ControlFlowNode for use() | +| b_condition.py:43 | f_0 | ControlFlowNode for use() | +| b_condition.py:43 | g_0 | ControlFlowNode for use() | +| b_condition.py:43 | h_0 | ControlFlowNode for use() | +| b_condition.py:43 | k_0 | ControlFlowNode for use() | +| b_condition.py:43 | loop_0 | ControlFlowNode for use() | +| b_condition.py:43 | not_or_not_0 | ControlFlowNode for use() | +| b_condition.py:43 | odasa6261_0 | ControlFlowNode for use() | +| b_condition.py:43 | split_bool1_0 | ControlFlowNode for use() | +| b_condition.py:43 | v2_3 | ControlFlowNode for use() | +| b_condition.py:43 | v2_3 | ControlFlowNode for v2 | +| b_condition.py:44 | __name___0 | ControlFlowNode for use() | +| b_condition.py:44 | __package___0 | ControlFlowNode for use() | +| b_condition.py:44 | double_attr_check_0 | ControlFlowNode for use() | +| b_condition.py:44 | f_0 | ControlFlowNode for use() | +| b_condition.py:44 | g_0 | ControlFlowNode for use() | +| b_condition.py:44 | h_0 | ControlFlowNode for use() | +| b_condition.py:44 | k_0 | ControlFlowNode for use() | +| b_condition.py:44 | loop_0 | ControlFlowNode for use() | +| b_condition.py:44 | not_or_not_0 | ControlFlowNode for use() | +| b_condition.py:44 | odasa6261_0 | ControlFlowNode for use() | +| b_condition.py:44 | split_bool1_0 | ControlFlowNode for use() | +| b_condition.py:44 | v2_3 | ControlFlowNode for use() | +| b_condition.py:44 | v2_3 | ControlFlowNode for v2 | +| b_condition.py:50 | x_3 | Exit node for Function g | +| b_condition.py:51 | x_0 | ControlFlowNode for x | +| b_condition.py:52 | x_1 | ControlFlowNode for x | +| b_condition.py:55 | seq_0 | Exit node for Function loop | +| b_condition.py:55 | v_2 | Exit node for Function loop | +| b_condition.py:56 | seq_0 | ControlFlowNode for seq | +| b_condition.py:57 | v_3 | ControlFlowNode for v | +| b_condition.py:58 | v_4 | ControlFlowNode for v | +| b_condition.py:61 | x_7 | Exit node for Function double_attr_check | +| b_condition.py:61 | y_3 | Exit node for Function double_attr_check | +| b_condition.py:62 | x_0 | ControlFlowNode for x | +| b_condition.py:64 | y_0 | ControlFlowNode for y | +| b_condition.py:65 | x_2 | ControlFlowNode for x | +| b_condition.py:66 | x_3 | ControlFlowNode for x | +| b_condition.py:69 | b_3 | Exit node for Function h | +| b_condition.py:71 | b_0 | ControlFlowNode for b | +| b_condition.py:73 | b_3 | ControlFlowNode for b | +| b_condition.py:75 | t_4 | Exit node for Function k | +| b_condition.py:77 | t_0 | ControlFlowNode for t | +| b_condition.py:79 | t_3 | ControlFlowNode for t | +| b_condition.py:81 | bar_2 | Exit node for Function odasa6261 | +| b_condition.py:81 | foo_5 | Exit node for Function odasa6261 | +| b_condition.py:82 | foo_0 | ControlFlowNode for callable() | +| b_condition.py:82 | foo_0 | ControlFlowNode for foo | +| b_condition.py:84 | foo_3 | ControlFlowNode for foo | +| b_condition.py:84 | foo_3 | ControlFlowNode for foo() | +| b_condition.py:87 | x_3 | Exit node for Function split_bool1 | +| b_condition.py:87 | x_8 | Exit node for Function split_bool1 | +| b_condition.py:87 | y_3 | Exit node for Function split_bool1 | +| b_condition.py:87 | y_6 | Exit node for Function split_bool1 | +| b_condition.py:88 | x_0 | ControlFlowNode for x | +| b_condition.py:88 | y_0 | ControlFlowNode for y | +| b_condition.py:90 | x_1 | ControlFlowNode for x | +| b_condition.py:90 | x_4 | ControlFlowNode for x | +| b_condition.py:90 | y_0 | ControlFlowNode for y | +| b_condition.py:92 | x_5 | ControlFlowNode for x | +| b_condition.py:92 | x_6 | ControlFlowNode for x | +| b_condition.py:93 | y_4 | ControlFlowNode for y | +| b_condition.py:95 | y_1 | ControlFlowNode for y | +| b_condition.py:96 | y_2 | ControlFlowNode for y | +| b_condition.py:96 | y_5 | ControlFlowNode for y | +| b_condition.py:97 | x_2 | ControlFlowNode for x | +| b_condition.py:99 | x_7 | ControlFlowNode for x | +| b_condition.py:101 | a_4 | Exit node for Function not_or_not | +| b_condition.py:102 | a_0 | ControlFlowNode for a | +| b_condition.py:104 | a_2 | ControlFlowNode for a | +| b_condition.py:105 | a_3 | ControlFlowNode for a | +| d_globals.py:0 | D_1 | Exit node for Module code.d_globals | +| d_globals.py:0 | Ugly_1 | Exit node for Module code.d_globals | +| d_globals.py:0 | X_1 | Exit node for Module code.d_globals | +| d_globals.py:0 | __name___0 | Exit node for Module code.d_globals | +| d_globals.py:0 | __package___0 | Exit node for Module code.d_globals | +| d_globals.py:0 | assign_global_0 | Exit node for Module code.d_globals | +| d_globals.py:0 | dict_1 | Exit node for Module code.d_globals | +| d_globals.py:0 | g1_1 | Exit node for Module code.d_globals | +| d_globals.py:0 | g2_1 | Exit node for Module code.d_globals | +| d_globals.py:0 | g3_1 | Exit node for Module code.d_globals | +| d_globals.py:0 | g4_6 | Exit node for Module code.d_globals | +| d_globals.py:0 | get_g4_1 | Exit node for Module code.d_globals | +| d_globals.py:0 | glob_1 | Exit node for Module code.d_globals | +| d_globals.py:0 | init_0 | Exit node for Module code.d_globals | +| d_globals.py:0 | j_0 | Exit node for Module code.d_globals | +| d_globals.py:0 | k_1 | Exit node for Module code.d_globals | +| d_globals.py:0 | modinit_2 | Exit node for Module code.d_globals | +| d_globals.py:0 | outer_1 | Exit node for Module code.d_globals | +| d_globals.py:0 | redefine_1 | Exit node for Module code.d_globals | +| d_globals.py:0 | set_g4_1 | Exit node for Module code.d_globals | +| d_globals.py:0 | set_g4_indirect_1 | Exit node for Module code.d_globals | +| d_globals.py:0 | tuple_1 | Exit node for Module code.d_globals | +| d_globals.py:0 | use_list_attribute_1 | Exit node for Module code.d_globals | +| d_globals.py:0 | x_3 | Exit node for Module code.d_globals | +| d_globals.py:0 | y_3 | Exit node for Module code.d_globals | +| d_globals.py:0 | z_1 | Exit node for Module code.d_globals | +| d_globals.py:2 | g1_2 | Exit node for Function j | +| d_globals.py:2 | g2_2 | Exit node for Function j | +| d_globals.py:2 | g3_2 | Exit node for Function j | +| d_globals.py:2 | g4_1 | Exit node for Function j | +| d_globals.py:2 | glob_2 | Exit node for Function j | +| d_globals.py:2 | z_2 | Exit node for Function j | +| d_globals.py:3 | dict_2 | ControlFlowNode for dict | +| d_globals.py:3 | tuple_2 | ControlFlowNode for tuple | +| d_globals.py:4 | dict_0 | ControlFlowNode for dict | +| d_globals.py:6 | dict_1 | ControlFlowNode for dict | +| d_globals.py:7 | tuple_0 | ControlFlowNode for tuple | +| d_globals.py:8 | tuple_1 | ControlFlowNode for tuple | +| d_globals.py:16 | g1_3 | Exit node for Function assign_global | +| d_globals.py:16 | g2_3 | Exit node for Function assign_global | +| d_globals.py:16 | g3_3 | Exit node for Function assign_global | +| d_globals.py:16 | g4_2 | Exit node for Function assign_global | +| d_globals.py:16 | glob_3 | Exit node for Function assign_global | +| d_globals.py:16 | z_3 | Exit node for Function assign_global | +| d_globals.py:19 | g1_3 | ControlFlowNode for g1 | +| d_globals.py:25 | g1_4 | Exit node for Function init | +| d_globals.py:25 | g2_4 | Exit node for Function init | +| d_globals.py:25 | g3_4 | Exit node for Function init | +| d_globals.py:25 | g4_3 | Exit node for Function init | +| d_globals.py:25 | glob_4 | Exit node for Function init | +| d_globals.py:25 | z_4 | Exit node for Function init | +| d_globals.py:29 | D_0 | ControlFlowNode for init() | +| d_globals.py:29 | Ugly_0 | ControlFlowNode for init() | +| d_globals.py:29 | X_0 | ControlFlowNode for init() | +| d_globals.py:29 | __name___0 | ControlFlowNode for init() | +| d_globals.py:29 | __package___0 | ControlFlowNode for init() | +| d_globals.py:29 | assign_global_0 | ControlFlowNode for init() | +| d_globals.py:29 | dict_1 | ControlFlowNode for init() | +| d_globals.py:29 | g1_0 | ControlFlowNode for init() | +| d_globals.py:29 | g2_0 | ControlFlowNode for init() | +| d_globals.py:29 | g3_0 | ControlFlowNode for init() | +| d_globals.py:29 | g4_0 | ControlFlowNode for init() | +| d_globals.py:29 | get_g4_0 | ControlFlowNode for init() | +| d_globals.py:29 | glob_0 | ControlFlowNode for init() | +| d_globals.py:29 | init_0 | ControlFlowNode for init | +| d_globals.py:29 | init_0 | ControlFlowNode for init() | +| d_globals.py:29 | j_0 | ControlFlowNode for init() | +| d_globals.py:29 | k_0 | ControlFlowNode for init() | +| d_globals.py:29 | modinit_0 | ControlFlowNode for init() | +| d_globals.py:29 | outer_0 | ControlFlowNode for init() | +| d_globals.py:29 | redefine_0 | ControlFlowNode for init() | +| d_globals.py:29 | set_g4_0 | ControlFlowNode for init() | +| d_globals.py:29 | set_g4_indirect_0 | ControlFlowNode for init() | +| d_globals.py:29 | tuple_1 | ControlFlowNode for init() | +| d_globals.py:29 | use_list_attribute_0 | ControlFlowNode for init() | +| d_globals.py:29 | x_0 | ControlFlowNode for init() | +| d_globals.py:29 | y_0 | ControlFlowNode for init() | +| d_globals.py:29 | z_0 | ControlFlowNode for init() | +| d_globals.py:30 | g2_1 | ControlFlowNode for g2 | +| d_globals.py:35 | __init___0 | Exit node for Class Ugly | +| d_globals.py:35 | meth_0 | Exit node for Class Ugly | +| d_globals.py:37 | g1_5 | Exit node for Function __init__ | +| d_globals.py:37 | g2_5 | Exit node for Function __init__ | +| d_globals.py:37 | g3_5 | Exit node for Function __init__ | +| d_globals.py:37 | g4_4 | Exit node for Function __init__ | +| d_globals.py:37 | glob_5 | Exit node for Function __init__ | +| d_globals.py:37 | self_0 | Exit node for Function __init__ | +| d_globals.py:37 | z_5 | Exit node for Function __init__ | +| d_globals.py:41 | g1_6 | Exit node for Function meth | +| d_globals.py:41 | g2_6 | Exit node for Function meth | +| d_globals.py:41 | g3_6 | Exit node for Function meth | +| d_globals.py:41 | g4_5 | Exit node for Function meth | +| d_globals.py:41 | glob_6 | Exit node for Function meth | +| d_globals.py:41 | self_0 | Exit node for Function meth | +| d_globals.py:41 | z_6 | Exit node for Function meth | +| d_globals.py:42 | g3_6 | ControlFlowNode for g3 | +| d_globals.py:47 | x_1 | ControlFlowNode for x | +| d_globals.py:59 | y_3 | ControlFlowNode for y | +| d_globals.py:62 | X_0 | ControlFlowNode for ClassExpr | +| d_globals.py:62 | g3_1 | ControlFlowNode for ClassExpr | +| d_globals.py:62 | v4_0 | Exit node for Class X | +| d_globals.py:62 | y_1 | Exit node for Class X | +| d_globals.py:62 | y_3 | ControlFlowNode for ClassExpr | +| d_globals.py:63 | y_0 | ControlFlowNode for y | +| d_globals.py:63 | y_4 | ControlFlowNode for y | +| d_globals.py:65 | X_2 | ControlFlowNode for X | +| d_globals.py:66 | g3_7 | ControlFlowNode for g3 | +| d_globals.py:70 | arg_0 | Exit node for Function k | +| d_globals.py:70 | g1_7 | Exit node for Function k | +| d_globals.py:70 | g2_7 | Exit node for Function k | +| d_globals.py:70 | g3_8 | Exit node for Function k | +| d_globals.py:70 | g4_7 | Exit node for Function k | +| d_globals.py:70 | glob_7 | Exit node for Function k | +| d_globals.py:70 | z_7 | Exit node for Function k | +| d_globals.py:75 | g1_10 | Exit node for Function get_g4 | +| d_globals.py:75 | g2_10 | Exit node for Function get_g4 | +| d_globals.py:75 | g3_11 | Exit node for Function get_g4 | +| d_globals.py:75 | g4_12 | Exit node for Function get_g4 | +| d_globals.py:75 | glob_10 | Exit node for Function get_g4 | +| d_globals.py:75 | z_10 | Exit node for Function get_g4 | +| d_globals.py:76 | g4_8 | ControlFlowNode for g4 | +| d_globals.py:77 | g1_8 | ControlFlowNode for set_g4() | +| d_globals.py:77 | g2_8 | ControlFlowNode for set_g4() | +| d_globals.py:77 | g3_9 | ControlFlowNode for set_g4() | +| d_globals.py:77 | g4_9 | ControlFlowNode for set_g4() | +| d_globals.py:77 | glob_8 | ControlFlowNode for set_g4() | +| d_globals.py:77 | set_g4_2 | ControlFlowNode for set_g4 | +| d_globals.py:77 | z_8 | ControlFlowNode for set_g4() | +| d_globals.py:78 | g4_12 | ControlFlowNode for g4 | +| d_globals.py:80 | g1_12 | Exit node for Function set_g4 | +| d_globals.py:80 | g2_12 | Exit node for Function set_g4 | +| d_globals.py:80 | g3_13 | Exit node for Function set_g4 | +| d_globals.py:80 | g4_14 | Exit node for Function set_g4 | +| d_globals.py:80 | glob_12 | Exit node for Function set_g4 | +| d_globals.py:80 | z_12 | Exit node for Function set_g4 | +| d_globals.py:81 | g1_11 | ControlFlowNode for set_g4_indirect() | +| d_globals.py:81 | g2_11 | ControlFlowNode for set_g4_indirect() | +| d_globals.py:81 | g3_12 | ControlFlowNode for set_g4_indirect() | +| d_globals.py:81 | g4_13 | ControlFlowNode for set_g4_indirect() | +| d_globals.py:81 | glob_11 | ControlFlowNode for set_g4_indirect() | +| d_globals.py:81 | set_g4_indirect_2 | ControlFlowNode for set_g4_indirect | +| d_globals.py:81 | z_11 | ControlFlowNode for set_g4_indirect() | +| d_globals.py:83 | g1_13 | Exit node for Function set_g4_indirect | +| d_globals.py:83 | g2_13 | Exit node for Function set_g4_indirect | +| d_globals.py:83 | g3_14 | Exit node for Function set_g4_indirect | +| d_globals.py:83 | g4_15 | Exit node for Function set_g4_indirect | +| d_globals.py:83 | glob_13 | Exit node for Function set_g4_indirect | +| d_globals.py:83 | z_13 | Exit node for Function set_g4_indirect | +| d_globals.py:92 | modinit_1 | ControlFlowNode for modinit | +| d_globals.py:95 | g1_15 | Exit node for Function outer | +| d_globals.py:95 | g2_15 | Exit node for Function outer | +| d_globals.py:95 | g3_16 | Exit node for Function outer | +| d_globals.py:95 | g4_17 | Exit node for Function outer | +| d_globals.py:95 | glob_15 | Exit node for Function outer | +| d_globals.py:95 | inner_0 | Exit node for Function outer | +| d_globals.py:95 | otherInner_0 | Exit node for Function outer | +| d_globals.py:95 | z_15 | Exit node for Function outer | +| d_globals.py:96 | g1_16 | Exit node for Function inner | +| d_globals.py:96 | g2_16 | Exit node for Function inner | +| d_globals.py:96 | g3_17 | Exit node for Function inner | +| d_globals.py:96 | g4_18 | Exit node for Function inner | +| d_globals.py:96 | glob_16 | Exit node for Function inner | +| d_globals.py:96 | z_16 | Exit node for Function inner | +| d_globals.py:99 | glob_16 | ControlFlowNode for glob | +| d_globals.py:101 | g1_17 | Exit node for Function otherInner | +| d_globals.py:101 | g2_17 | Exit node for Function otherInner | +| d_globals.py:101 | g3_18 | Exit node for Function otherInner | +| d_globals.py:101 | g4_19 | Exit node for Function otherInner | +| d_globals.py:101 | glob_17 | Exit node for Function otherInner | +| d_globals.py:101 | z_17 | Exit node for Function otherInner | +| d_globals.py:102 | glob_17 | ControlFlowNode for glob | +| d_globals.py:104 | g1_14 | ControlFlowNode for inner() | +| d_globals.py:104 | g2_14 | ControlFlowNode for inner() | +| d_globals.py:104 | g3_15 | ControlFlowNode for inner() | +| d_globals.py:104 | g4_16 | ControlFlowNode for inner() | +| d_globals.py:104 | glob_14 | ControlFlowNode for inner() | +| d_globals.py:104 | inner_0 | ControlFlowNode for inner | +| d_globals.py:104 | z_14 | ControlFlowNode for inner() | +| d_globals.py:107 | g1_18 | Exit node for Function redefine | +| d_globals.py:107 | g2_18 | Exit node for Function redefine | +| d_globals.py:107 | g3_19 | Exit node for Function redefine | +| d_globals.py:107 | g4_20 | Exit node for Function redefine | +| d_globals.py:107 | glob_19 | Exit node for Function redefine | +| d_globals.py:107 | z_19 | Exit node for Function redefine | +| d_globals.py:109 | z_18 | ControlFlowNode for z | +| d_globals.py:111 | z_19 | ControlFlowNode for z | +| d_globals.py:112 | glob_18 | ControlFlowNode for glob | +| d_globals.py:114 | glob_19 | ControlFlowNode for glob | +| d_globals.py:118 | __init___0 | Exit node for Class D | +| d_globals.py:118 | foo_0 | Exit node for Class D | +| d_globals.py:120 | g1_19 | Exit node for Function __init__ | +| d_globals.py:120 | g2_19 | Exit node for Function __init__ | +| d_globals.py:120 | g3_20 | Exit node for Function __init__ | +| d_globals.py:120 | g4_21 | Exit node for Function __init__ | +| d_globals.py:120 | glob_20 | Exit node for Function __init__ | +| d_globals.py:120 | self_0 | Exit node for Function __init__ | +| d_globals.py:120 | z_20 | Exit node for Function __init__ | +| d_globals.py:123 | g1_20 | Exit node for Function foo | +| d_globals.py:123 | g2_20 | Exit node for Function foo | +| d_globals.py:123 | g3_21 | Exit node for Function foo | +| d_globals.py:123 | g4_22 | Exit node for Function foo | +| d_globals.py:123 | glob_21 | Exit node for Function foo | +| d_globals.py:123 | self_0 | Exit node for Function foo | +| d_globals.py:123 | z_21 | Exit node for Function foo | +| d_globals.py:124 | dict_3 | ControlFlowNode for dict | +| d_globals.py:126 | g1_22 | Exit node for Function use_list_attribute | +| d_globals.py:126 | g2_22 | Exit node for Function use_list_attribute | +| d_globals.py:126 | g3_23 | Exit node for Function use_list_attribute | +| d_globals.py:126 | g4_24 | Exit node for Function use_list_attribute | +| d_globals.py:126 | glob_23 | Exit node for Function use_list_attribute | +| d_globals.py:126 | l_1 | Exit node for Function use_list_attribute | +| d_globals.py:126 | z_23 | Exit node for Function use_list_attribute | +| d_globals.py:128 | g1_21 | ControlFlowNode for Attribute() | +| d_globals.py:128 | g2_21 | ControlFlowNode for Attribute() | +| d_globals.py:128 | g3_22 | ControlFlowNode for Attribute() | +| d_globals.py:128 | g4_23 | ControlFlowNode for Attribute() | +| d_globals.py:128 | glob_22 | ControlFlowNode for Attribute() | +| d_globals.py:128 | l_0 | ControlFlowNode for l | +| d_globals.py:128 | z_22 | ControlFlowNode for Attribute() | +| d_globals.py:129 | l_1 | ControlFlowNode for l | +| e_temporal.py:0 | __name___0 | Exit node for Module code.e_temporal | +| e_temporal.py:0 | __package___0 | Exit node for Module code.e_temporal | +| e_temporal.py:0 | f_0 | Exit node for Module code.e_temporal | +| e_temporal.py:0 | g_0 | Exit node for Module code.e_temporal | +| e_temporal.py:0 | sys_0 | Exit node for Module code.e_temporal | +| e_temporal.py:0 | x_1 | Exit node for Module code.e_temporal | +| e_temporal.py:5 | sys_1 | ControlFlowNode for sys | +| e_temporal.py:9 | arg_0 | Exit node for Function g | +| e_temporal.py:10 | arg_0 | ControlFlowNode for arg | +| e_temporal.py:12 | __name___0 | ControlFlowNode for f() | +| e_temporal.py:12 | __name___0 | ControlFlowNode for g() | +| e_temporal.py:12 | __package___0 | ControlFlowNode for f() | +| e_temporal.py:12 | __package___0 | ControlFlowNode for g() | +| e_temporal.py:12 | f_0 | ControlFlowNode for f | +| e_temporal.py:12 | f_0 | ControlFlowNode for f() | +| e_temporal.py:12 | f_0 | ControlFlowNode for g() | +| e_temporal.py:12 | g_0 | ControlFlowNode for f() | +| e_temporal.py:12 | g_0 | ControlFlowNode for g | +| e_temporal.py:12 | g_0 | ControlFlowNode for g() | +| e_temporal.py:12 | sys_0 | ControlFlowNode for f() | +| e_temporal.py:12 | sys_0 | ControlFlowNode for g() | +| e_temporal.py:12 | x_0 | ControlFlowNode for f() | +| e_temporal.py:12 | x_0 | ControlFlowNode for g() | +| g_class_init.py:0 | C_0 | Exit node for Module code.g_class_init | +| g_class_init.py:0 | D_0 | Exit node for Module code.g_class_init | +| g_class_init.py:0 | E_0 | Exit node for Module code.g_class_init | +| g_class_init.py:0 | Oddities_0 | Exit node for Module code.g_class_init | +| g_class_init.py:0 | V2_0 | Exit node for Module code.g_class_init | +| g_class_init.py:0 | V3_0 | Exit node for Module code.g_class_init | +| g_class_init.py:0 | __name___0 | Exit node for Module code.g_class_init | +| g_class_init.py:0 | __package___0 | Exit node for Module code.g_class_init | +| g_class_init.py:3 | __init___0 | Exit node for Class C | +| g_class_init.py:3 | _init2_0 | Exit node for Class C | +| g_class_init.py:3 | _init_0 | Exit node for Class C | +| g_class_init.py:3 | method_0 | Exit node for Class C | +| g_class_init.py:5 | self_2 | Exit node for Function __init__ | +| g_class_init.py:6 | self_0 | ControlFlowNode for self | +| g_class_init.py:7 | self_1 | ControlFlowNode for self | +| g_class_init.py:9 | self_2 | Exit node for Function _init | +| g_class_init.py:10 | self_0 | ControlFlowNode for self | +| g_class_init.py:11 | self_1 | ControlFlowNode for self | +| g_class_init.py:13 | self_1 | Exit node for Function _init2 | +| g_class_init.py:14 | self_0 | ControlFlowNode for self | +| g_class_init.py:16 | self_3 | Exit node for Function method | +| g_class_init.py:17 | self_0 | ControlFlowNode for self | +| g_class_init.py:18 | self_0 | ControlFlowNode for self | +| g_class_init.py:19 | self_1 | ControlFlowNode for self | +| g_class_init.py:20 | self_3 | ControlFlowNode for self | +| g_class_init.py:24 | float_1 | Exit node for Class Oddities | +| g_class_init.py:24 | h_0 | Exit node for Class Oddities | +| g_class_init.py:24 | int_1 | Exit node for Class Oddities | +| g_class_init.py:24 | l_0 | Exit node for Class Oddities | +| g_class_init.py:26 | int_0 | ControlFlowNode for int | +| g_class_init.py:27 | float_0 | ControlFlowNode for float | +| g_class_init.py:32 | __init___0 | Exit node for Class D | +| g_class_init.py:34 | self_0 | Exit node for Function __init__ | +| g_class_init.py:35 | D_1 | ControlFlowNode for D | +| g_class_init.py:35 | self_0 | ControlFlowNode for self | +| g_class_init.py:36 | D_2 | ControlFlowNode for D | +| g_class_init.py:36 | self_0 | ControlFlowNode for self | +| g_class_init.py:45 | __init___0 | Exit node for Class E | +| g_class_init.py:45 | meth_0 | Exit node for Class E | +| g_class_init.py:46 | c_3 | Exit node for Function __init__ | +| g_class_init.py:46 | self_3 | Exit node for Function __init__ | +| g_class_init.py:47 | c_0 | ControlFlowNode for c | +| g_class_init.py:48 | V2_1 | ControlFlowNode for V2 | +| g_class_init.py:48 | self_0 | ControlFlowNode for self | +| g_class_init.py:50 | V3_1 | ControlFlowNode for V3 | +| g_class_init.py:50 | self_0 | ControlFlowNode for self | +| g_class_init.py:52 | self_3 | Exit node for Function meth | +| g_class_init.py:53 | V2_2 | ControlFlowNode for V2 | +| g_class_init.py:53 | self_0 | ControlFlowNode for self | +| h_classes.py:0 | Base_1 | Exit node for Module code.h_classes | +| h_classes.py:0 | C_0 | Exit node for Module code.h_classes | +| h_classes.py:0 | D_1 | Exit node for Module code.h_classes | +| h_classes.py:0 | Derived1_1 | Exit node for Module code.h_classes | +| h_classes.py:0 | Derived2_1 | Exit node for Module code.h_classes | +| h_classes.py:0 | Derived3_1 | Exit node for Module code.h_classes | +| h_classes.py:0 | __name___0 | Exit node for Module code.h_classes | +| h_classes.py:0 | __package___0 | Exit node for Module code.h_classes | +| h_classes.py:0 | f_1 | Exit node for Module code.h_classes | +| h_classes.py:0 | k_1 | Exit node for Module code.h_classes | +| h_classes.py:0 | sys_1 | Exit node for Module code.h_classes | +| h_classes.py:0 | thing_1 | Exit node for Module code.h_classes | +| h_classes.py:3 | __init___0 | Exit node for Class C | +| h_classes.py:3 | x_0 | Exit node for Class C | +| h_classes.py:7 | self_1 | Exit node for Function __init__ | +| h_classes.py:8 | self_0 | ControlFlowNode for self | +| h_classes.py:10 | Base_0 | ControlFlowNode for C() | +| h_classes.py:10 | Base_0 | ControlFlowNode for type() | +| h_classes.py:10 | C_0 | ControlFlowNode for C | +| h_classes.py:10 | C_0 | ControlFlowNode for C() | +| h_classes.py:10 | C_0 | ControlFlowNode for type() | +| h_classes.py:10 | D_0 | ControlFlowNode for C() | +| h_classes.py:10 | D_0 | ControlFlowNode for type() | +| h_classes.py:10 | Derived1_0 | ControlFlowNode for C() | +| h_classes.py:10 | Derived1_0 | ControlFlowNode for type() | +| h_classes.py:10 | Derived2_0 | ControlFlowNode for C() | +| h_classes.py:10 | Derived2_0 | ControlFlowNode for type() | +| h_classes.py:10 | Derived3_0 | ControlFlowNode for C() | +| h_classes.py:10 | Derived3_0 | ControlFlowNode for type() | +| h_classes.py:10 | __name___0 | ControlFlowNode for C() | +| h_classes.py:10 | __name___0 | ControlFlowNode for type() | +| h_classes.py:10 | __package___0 | ControlFlowNode for C() | +| h_classes.py:10 | __package___0 | ControlFlowNode for type() | +| h_classes.py:10 | f_0 | ControlFlowNode for C() | +| h_classes.py:10 | f_0 | ControlFlowNode for type() | +| h_classes.py:10 | k_0 | ControlFlowNode for C() | +| h_classes.py:10 | k_0 | ControlFlowNode for type() | +| h_classes.py:10 | sys_0 | ControlFlowNode for C() | +| h_classes.py:10 | sys_0 | ControlFlowNode for type() | +| h_classes.py:10 | thing_0 | ControlFlowNode for C() | +| h_classes.py:10 | thing_0 | ControlFlowNode for type() | +| h_classes.py:11 | Base_0 | ControlFlowNode for type() | +| h_classes.py:11 | C_0 | ControlFlowNode for type() | +| h_classes.py:11 | D_0 | ControlFlowNode for type() | +| h_classes.py:11 | Derived1_0 | ControlFlowNode for type() | +| h_classes.py:11 | Derived2_0 | ControlFlowNode for type() | +| h_classes.py:11 | Derived3_0 | ControlFlowNode for type() | +| h_classes.py:11 | __name___0 | ControlFlowNode for type() | +| h_classes.py:11 | __package___0 | ControlFlowNode for type() | +| h_classes.py:11 | f_0 | ControlFlowNode for type() | +| h_classes.py:11 | k_0 | ControlFlowNode for type() | +| h_classes.py:11 | sys_0 | ControlFlowNode for sys | +| h_classes.py:11 | sys_0 | ControlFlowNode for type() | +| h_classes.py:11 | thing_0 | ControlFlowNode for type() | +| h_classes.py:12 | Base_0 | ControlFlowNode for type() | +| h_classes.py:12 | C_0 | ControlFlowNode for type() | +| h_classes.py:12 | D_0 | ControlFlowNode for type() | +| h_classes.py:12 | Derived1_0 | ControlFlowNode for type() | +| h_classes.py:12 | Derived2_0 | ControlFlowNode for type() | +| h_classes.py:12 | Derived3_0 | ControlFlowNode for type() | +| h_classes.py:12 | __name___0 | ControlFlowNode for type() | +| h_classes.py:12 | __package___0 | ControlFlowNode for type() | +| h_classes.py:12 | f_0 | ControlFlowNode for type() | +| h_classes.py:12 | k_0 | ControlFlowNode for type() | +| h_classes.py:12 | sys_1 | ControlFlowNode for type() | +| h_classes.py:12 | thing_0 | ControlFlowNode for type() | +| h_classes.py:14 | arg_1 | Exit node for Function k | +| h_classes.py:15 | C_1 | ControlFlowNode for C | +| h_classes.py:16 | sys_2 | ControlFlowNode for sys | +| h_classes.py:17 | arg_0 | ControlFlowNode for arg | +| h_classes.py:23 | __init___0 | Exit node for Class Base | +| h_classes.py:25 | choice_5 | Exit node for Function __init__ | +| h_classes.py:25 | self_4 | Exit node for Function __init__ | +| h_classes.py:26 | choice_0 | ControlFlowNode for choice | +| h_classes.py:27 | Derived1_2 | ControlFlowNode for Derived1 | +| h_classes.py:27 | self_0 | ControlFlowNode for self | +| h_classes.py:28 | choice_2 | ControlFlowNode for choice | +| h_classes.py:29 | Derived2_2 | ControlFlowNode for Derived2 | +| h_classes.py:29 | self_0 | ControlFlowNode for self | +| h_classes.py:31 | Derived3_2 | ControlFlowNode for Derived3 | +| h_classes.py:31 | self_0 | ControlFlowNode for self | +| h_classes.py:33 | Base_1 | ControlFlowNode for Base | +| h_classes.py:36 | Base_1 | ControlFlowNode for Base | +| h_classes.py:39 | Base_1 | ControlFlowNode for Base | +| h_classes.py:42 | Base_1 | ControlFlowNode for Base | +| h_classes.py:42 | Base_1 | ControlFlowNode for Base() | +| h_classes.py:42 | Base_1 | ControlFlowNode for unknown() | +| h_classes.py:42 | C_0 | ControlFlowNode for Base() | +| h_classes.py:42 | C_0 | ControlFlowNode for unknown() | +| h_classes.py:42 | D_0 | ControlFlowNode for Base() | +| h_classes.py:42 | D_0 | ControlFlowNode for unknown() | +| h_classes.py:42 | Derived1_1 | ControlFlowNode for Base() | +| h_classes.py:42 | Derived1_1 | ControlFlowNode for unknown() | +| h_classes.py:42 | Derived2_1 | ControlFlowNode for Base() | +| h_classes.py:42 | Derived2_1 | ControlFlowNode for unknown() | +| h_classes.py:42 | Derived3_1 | ControlFlowNode for Base() | +| h_classes.py:42 | Derived3_1 | ControlFlowNode for unknown() | +| h_classes.py:42 | __name___0 | ControlFlowNode for Base() | +| h_classes.py:42 | __name___0 | ControlFlowNode for unknown() | +| h_classes.py:42 | __package___0 | ControlFlowNode for Base() | +| h_classes.py:42 | __package___0 | ControlFlowNode for unknown() | +| h_classes.py:42 | f_0 | ControlFlowNode for Base() | +| h_classes.py:42 | f_0 | ControlFlowNode for unknown() | +| h_classes.py:42 | k_1 | ControlFlowNode for Base() | +| h_classes.py:42 | k_1 | ControlFlowNode for unknown() | +| h_classes.py:42 | sys_1 | ControlFlowNode for Base() | +| h_classes.py:42 | sys_1 | ControlFlowNode for unknown() | +| h_classes.py:42 | thing_0 | ControlFlowNode for Base() | +| h_classes.py:42 | thing_0 | ControlFlowNode for unknown() | +| h_classes.py:45 | arg0_0 | Exit node for Function f | +| h_classes.py:45 | arg1_0 | Exit node for Function f | +| h_classes.py:45 | arg2_0 | Exit node for Function f | +| h_classes.py:48 | f_1 | ControlFlowNode for ClassExpr | +| h_classes.py:48 | m_0 | Exit node for Class D | +| h_classes.py:48 | n_0 | Exit node for Class D | +| h_classes.py:50 | f_2 | ControlFlowNode for f | +| h_classes.py:52 | arg1_0 | Exit node for Function n | +| h_classes.py:52 | self_0 | Exit node for Function n | +| j_convoluted_imports.py:0 | C_0 | Exit node for Module code.j_convoluted_imports | +| j_convoluted_imports.py:0 | __name___0 | Exit node for Module code.j_convoluted_imports | +| j_convoluted_imports.py:0 | __package___0 | Exit node for Module code.j_convoluted_imports | +| j_convoluted_imports.py:0 | moduleX_0 | Exit node for Module code.j_convoluted_imports | +| j_convoluted_imports.py:0 | module_0 | Exit node for Module code.j_convoluted_imports | +| j_convoluted_imports.py:0 | x_0 | Exit node for Module code.j_convoluted_imports | +| j_convoluted_imports.py:9 | f_0 | Exit node for Class C | +| j_convoluted_imports.py:9 | module2_0 | Exit node for Class C | +| j_convoluted_imports.py:13 | self_0 | Exit node for Function f | +| j_convoluted_imports.py:13 | x_0 | Exit node for Function f | +| j_convoluted_imports.py:17 | moduleX_0 | ControlFlowNode for moduleX | +| k_getsetattr.py:0 | C_0 | Exit node for Module code.k_getsetattr | +| k_getsetattr.py:0 | __name___0 | Exit node for Module code.k_getsetattr | +| k_getsetattr.py:0 | __package___0 | Exit node for Module code.k_getsetattr | +| k_getsetattr.py:0 | k_0 | Exit node for Module code.k_getsetattr | +| k_getsetattr.py:4 | meth1_0 | Exit node for Class C | +| k_getsetattr.py:4 | meth2_0 | Exit node for Class C | +| k_getsetattr.py:6 | self_4 | Exit node for Function meth1 | +| k_getsetattr.py:7 | self_0 | ControlFlowNode for self | +| k_getsetattr.py:8 | self_1 | ControlFlowNode for self | +| k_getsetattr.py:9 | self_2 | ControlFlowNode for self | +| k_getsetattr.py:10 | self_3 | ControlFlowNode for self | +| k_getsetattr.py:12 | self_6 | Exit node for Function meth2 | +| k_getsetattr.py:13 | self_0 | ControlFlowNode for self | +| k_getsetattr.py:14 | self_1 | ControlFlowNode for self | +| k_getsetattr.py:15 | self_2 | ControlFlowNode for self | +| k_getsetattr.py:16 | self_3 | ControlFlowNode for self | +| k_getsetattr.py:17 | self_4 | ControlFlowNode for self | +| k_getsetattr.py:18 | self_5 | ControlFlowNode for self | +| k_getsetattr.py:21 | c1_1 | Exit node for Function k | +| k_getsetattr.py:21 | c2_2 | Exit node for Function k | +| k_getsetattr.py:21 | c3_1 | Exit node for Function k | +| k_getsetattr.py:21 | cond_3 | Exit node for Function k | +| k_getsetattr.py:22 | C_1 | ControlFlowNode for C | +| k_getsetattr.py:23 | C_1 | ControlFlowNode for C | +| k_getsetattr.py:24 | C_1 | ControlFlowNode for C | +| k_getsetattr.py:25 | c1_0 | ControlFlowNode for c1 | +| k_getsetattr.py:26 | cond_0 | ControlFlowNode for cond | +| k_getsetattr.py:27 | c2_0 | ControlFlowNode for c2 | +| k_getsetattr.py:28 | c1_1 | ControlFlowNode for c1 | +| k_getsetattr.py:29 | c2_2 | ControlFlowNode for c2 | +| k_getsetattr.py:30 | c3_0 | ControlFlowNode for c3 | +| k_getsetattr.py:31 | c3_0 | ControlFlowNode for c3 | +| s_scopes.py:0 | C2_0 | Exit node for Module code.s_scopes | +| s_scopes.py:0 | __name___0 | Exit node for Module code.s_scopes | +| s_scopes.py:0 | __package___0 | Exit node for Module code.s_scopes | +| s_scopes.py:0 | f_0 | Exit node for Module code.s_scopes | +| s_scopes.py:0 | float_2 | Exit node for Module code.s_scopes | +| s_scopes.py:0 | i_0 | Exit node for Module code.s_scopes | +| s_scopes.py:0 | x_1 | Exit node for Module code.s_scopes | +| s_scopes.py:7 | f1_0 | Exit node for Class C2 | +| s_scopes.py:7 | f2_0 | Exit node for Class C2 | +| s_scopes.py:7 | float_2 | ControlFlowNode for ClassExpr | +| s_scopes.py:7 | float_2 | Exit node for Class C2 | +| s_scopes.py:7 | i1_0 | Exit node for Class C2 | +| s_scopes.py:7 | i2_0 | Exit node for Class C2 | +| s_scopes.py:7 | int_1 | Exit node for Class C2 | +| s_scopes.py:7 | s_0 | Exit node for Class C2 | +| s_scopes.py:7 | str_2 | Exit node for Class C2 | +| s_scopes.py:9 | int_0 | ControlFlowNode for int | +| s_scopes.py:10 | float_0 | ControlFlowNode for float | +| s_scopes.py:10 | float_3 | ControlFlowNode for float | +| s_scopes.py:18 | int_1 | ControlFlowNode for int | +| s_scopes.py:19 | str_2 | ControlFlowNode for str | +| s_scopes.py:20 | float_2 | ControlFlowNode for float | +| s_scopes.py:20 | float_3 | ControlFlowNode for float | +| s_scopes.py:22 | x_0 | ControlFlowNode for x | +| s_scopes.py:24 | float_2 | ControlFlowNode for float | diff --git a/python/ql/test/library-tests/PointsTo/new/SsaUses.ql b/python/ql/test/library-tests/PointsTo/new/SsaUses.ql new file mode 100644 index 00000000000..681ac79bc78 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/SsaUses.ql @@ -0,0 +1,9 @@ + +import python +import semmle.dataflow.SSA +import semmle.python.pointsto.PointsTo +import Util + +from EssaVariable var, ControlFlowNode use +where use = var.getAUse() +select locate(use.getLocation(), "abdeghjks_"), var.getRepresentation(), use.toString() diff --git a/python/ql/test/library-tests/PointsTo/new/TestEvaluate.expected b/python/ql/test/library-tests/PointsTo/new/TestEvaluate.expected new file mode 100644 index 00000000000..9bdee5cf24e --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/TestEvaluate.expected @@ -0,0 +1,55 @@ +| b_condition.py:7 | Compare | true | x | NoneType None | +| b_condition.py:13 | Compare | false | x | NoneType None | +| b_condition.py:19 | UnaryExpr | true | x | NoneType None | +| b_condition.py:25 | x | false | x | NoneType None | +| b_condition.py:32 | UnaryExpr | false | x | int 1 | +| b_condition.py:36 | isinstance() | true | x | int 1 | +| b_condition.py:36 | isinstance() | true | x | int 7 | +| b_condition.py:71 | UnaryExpr | false | b | bool True | +| b_condition.py:77 | Compare | true | object | builtin-class object | +| b_condition.py:77 | Compare | true | t | builtin-class type | +| b_condition.py:82 | callable() | false | foo | bool True | +| b_condition.py:88 | x | false | x | NoneType None | +| b_condition.py:88 | y | false | y | NoneType None | +| b_condition.py:90 | x | false | x | NoneType None | +| b_condition.py:90 | y | false | y | NoneType None | +| b_condition.py:92 | x | false | x | NoneType None | +| b_condition.py:96 | y | false | y | NoneType None | +| b_condition.py:102 | UnaryExpr | false | a | a | +| b_condition.py:104 | UnaryExpr | false | a | a | +| c_tests.py:7 | Compare | true | x | NoneType None | +| c_tests.py:12 | x | false | x | int 0 | +| c_tests.py:12 | x | true | x | int 1 | +| c_tests.py:17 | Compare | false | x | int 1 | +| c_tests.py:17 | Compare | true | x | int 0 | +| c_tests.py:23 | len() | true | x | List | +| c_tests.py:23 | len() | true | x | Tuple | +| c_tests.py:26 | Compare | false | x | Tuple | +| c_tests.py:26 | Compare | true | x | List | +| c_tests.py:26 | Compare | true | x | Tuple | +| c_tests.py:29 | isinstance() | false | x | List | +| c_tests.py:29 | isinstance() | true | x | Tuple | +| c_tests.py:34 | Compare | true | Attribute | NoneType None | +| c_tests.py:39 | Attribute | false | Attribute | int 0 | +| c_tests.py:39 | Attribute | true | Attribute | int 1 | +| c_tests.py:44 | Compare | false | Attribute | int 1 | +| c_tests.py:44 | Compare | true | Attribute | int 0 | +| c_tests.py:50 | isinstance() | false | Attribute | List | +| c_tests.py:50 | isinstance() | true | Attribute | Tuple | +| c_tests.py:53 | Compare | false | Attribute | Tuple | +| c_tests.py:53 | Compare | true | Attribute | List | +| c_tests.py:53 | Compare | true | Attribute | Tuple | +| c_tests.py:60 | issubclass() | false | x | builtin-class type | +| c_tests.py:60 | issubclass() | true | x | builtin-class bool | +| c_tests.py:65 | hasattr() | false | x | builtin-class float | +| c_tests.py:65 | hasattr() | true | x | int 0 | +| c_tests.py:68 | callable() | false | x | int 0 | +| c_tests.py:68 | callable() | true | x | builtin-class float | +| c_tests.py:73 | x | true | x | int 1 | +| c_tests.py:73 | y | false | y | int 0 | +| c_tests.py:76 | x | true | x | int 1 | +| c_tests.py:76 | y | false | y | int 0 | +| c_tests.py:81 | b | true | b | bool True | +| c_tests.py:84 | UnaryExpr | false | b | bool True | +| c_tests.py:91 | x | false | x | NoneType None | +| c_tests.py:95 | UnaryExpr | true | x | NoneType None | diff --git a/python/ql/test/library-tests/PointsTo/new/TestEvaluate.ql b/python/ql/test/library-tests/PointsTo/new/TestEvaluate.ql new file mode 100644 index 00000000000..731b710d2c5 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/TestEvaluate.ql @@ -0,0 +1,14 @@ + +import python +import semmle.python.pointsto.PointsTo +import semmle.python.pointsto.PointsToContext +import Util + + +from ControlFlowNode test, ControlFlowNode use, Object val, boolean eval, ClassObject cls, PointsToContext ctx +where +not use instanceof NameConstantNode and +not use.getNode() instanceof ImmutableLiteral and +PointsTo::points_to(use, ctx, val, cls, _) and +eval = PointsTo::test_evaluates_boolean(test, use, ctx, val, cls, _) +select locate(test.getLocation(), "bc"), test.getNode().toString(), eval.toString(), use.getNode().toString(), val.toString() diff --git a/python/ql/test/library-tests/PointsTo/new/Util.qll b/python/ql/test/library-tests/PointsTo/new/Util.qll new file mode 100644 index 00000000000..8e1d317cc68 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/Util.qll @@ -0,0 +1,30 @@ +import python + +bindingset[which] +string locate(Location l, string which) { + exists(string file, int line | + file = l.getFile().getShortName() and + line = l.getStartLine() and + file.charAt(0) = which.charAt(_) and + file.charAt(1) = "_" and + result = file + ":" + line + ) +} + +string repr(Object o) { + /* Do not show `unknownValue()` to keep noise levels down. + * To show it add: + * `o = unknownValue() and result = "*UNKNOWN VALUE*"` + */ + not o instanceof StringObject and not o = undefinedVariable() and not o = theUnknownType() and + not o = theBoundMethodType() and result = o.toString() + or + o = undefinedVariable() and result = "*UNDEFINED*" + or + o = theUnknownType() and result = "*UNKNOWN TYPE*" + or + /* Work around differing names in 2/3 */ + result = "'" + o.(StringObject).getText() + "'" + or + o = theBoundMethodType() and result = "builtin-class method" +} diff --git a/python/ql/test/library-tests/PointsTo/new/VarUses.expected b/python/ql/test/library-tests/PointsTo/new/VarUses.expected new file mode 100644 index 00000000000..4fcc0a1a1dc --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/VarUses.expected @@ -0,0 +1,444 @@ +| a_simple.py:0 | C | Exit node for Module code.a_simple | +| a_simple.py:0 | KeyError | Exit node for Module code.a_simple | +| a_simple.py:0 | __name__ | Exit node for Module code.a_simple | +| a_simple.py:0 | __package__ | Exit node for Module code.a_simple | +| a_simple.py:0 | dict | Exit node for Module code.a_simple | +| a_simple.py:0 | f | Exit node for Module code.a_simple | +| a_simple.py:0 | f1 | Exit node for Module code.a_simple | +| a_simple.py:0 | func | Exit node for Module code.a_simple | +| a_simple.py:0 | i1 | Exit node for Module code.a_simple | +| a_simple.py:0 | multi_loop | Exit node for Module code.a_simple | +| a_simple.py:0 | multi_loop_in_try | Exit node for Module code.a_simple | +| a_simple.py:0 | object | Exit node for Module code.a_simple | +| a_simple.py:0 | s | Exit node for Module code.a_simple | +| a_simple.py:0 | tuple | Exit node for Module code.a_simple | +| a_simple.py:0 | vararg_kwarg | Exit node for Module code.a_simple | +| a_simple.py:0 | with_definition | Exit node for Module code.a_simple | +| a_simple.py:3 | dict | ControlFlowNode for dict | +| a_simple.py:4 | tuple | ControlFlowNode for tuple | +| a_simple.py:11 | object | ControlFlowNode for object | +| a_simple.py:14 | d | Exit node for Function vararg_kwarg | +| a_simple.py:14 | t | Exit node for Function vararg_kwarg | +| a_simple.py:15 | t | ControlFlowNode for t | +| a_simple.py:16 | d | ControlFlowNode for d | +| a_simple.py:18 | seq | Exit node for Function multi_loop | +| a_simple.py:18 | x | Exit node for Function multi_loop | +| a_simple.py:18 | y | Exit node for Function multi_loop | +| a_simple.py:20 | seq | ControlFlowNode for seq | +| a_simple.py:21 | x | ControlFlowNode for x | +| a_simple.py:23 | x | Exit node for Function with_definition | +| a_simple.py:23 | y | Exit node for Function with_definition | +| a_simple.py:24 | x | ControlFlowNode for x | +| a_simple.py:25 | y | ControlFlowNode for y | +| a_simple.py:27 | p | Exit node for Function multi_loop_in_try | +| a_simple.py:27 | q | Exit node for Function multi_loop_in_try | +| a_simple.py:27 | x | Exit node for Function multi_loop_in_try | +| a_simple.py:29 | x | ControlFlowNode for x | +| a_simple.py:30 | p | ControlFlowNode for p | +| a_simple.py:31 | KeyError | ControlFlowNode for KeyError | +| a_simple.py:34 | args | Exit node for Function f | +| a_simple.py:34 | kwargs | Exit node for Function f | +| a_simple.py:35 | args | ControlFlowNode for args | +| a_simple.py:36 | kwargs | ControlFlowNode for kwargs | +| b_condition.py:0 | Exception | Exit node for Module code.b_condition | +| b_condition.py:0 | TypeError | Exit node for Module code.b_condition | +| b_condition.py:0 | __name__ | Exit node for Module code.b_condition | +| b_condition.py:0 | __package__ | Exit node for Module code.b_condition | +| b_condition.py:0 | callable | Exit node for Module code.b_condition | +| b_condition.py:0 | cond | Exit node for Module code.b_condition | +| b_condition.py:0 | double_attr_check | Exit node for Module code.b_condition | +| b_condition.py:0 | f | Exit node for Module code.b_condition | +| b_condition.py:0 | g | Exit node for Module code.b_condition | +| b_condition.py:0 | h | Exit node for Module code.b_condition | +| b_condition.py:0 | int | Exit node for Module code.b_condition | +| b_condition.py:0 | isinstance | Exit node for Module code.b_condition | +| b_condition.py:0 | k | Exit node for Module code.b_condition | +| b_condition.py:0 | list | Exit node for Module code.b_condition | +| b_condition.py:0 | loop | Exit node for Module code.b_condition | +| b_condition.py:0 | not_or_not | Exit node for Module code.b_condition | +| b_condition.py:0 | object | Exit node for Module code.b_condition | +| b_condition.py:0 | odasa6261 | Exit node for Module code.b_condition | +| b_condition.py:0 | seq | Exit node for Module code.b_condition | +| b_condition.py:0 | split_bool1 | Exit node for Module code.b_condition | +| b_condition.py:0 | thing | Exit node for Module code.b_condition | +| b_condition.py:0 | tuple | Exit node for Module code.b_condition | +| b_condition.py:0 | type | Exit node for Module code.b_condition | +| b_condition.py:0 | unknown | Exit node for Module code.b_condition | +| b_condition.py:0 | use | Exit node for Module code.b_condition | +| b_condition.py:0 | v2 | Exit node for Module code.b_condition | +| b_condition.py:4 | x | Exit node for Function f | +| b_condition.py:4 | y | Exit node for Function f | +| b_condition.py:5 | cond | ControlFlowNode for cond | +| b_condition.py:5 | unknown | ControlFlowNode for unknown | +| b_condition.py:7 | x | ControlFlowNode for x | +| b_condition.py:9 | use | ControlFlowNode for use | +| b_condition.py:9 | x | ControlFlowNode for x | +| b_condition.py:11 | cond | ControlFlowNode for cond | +| b_condition.py:11 | unknown | ControlFlowNode for unknown | +| b_condition.py:13 | x | ControlFlowNode for x | +| b_condition.py:15 | use | ControlFlowNode for use | +| b_condition.py:15 | x | ControlFlowNode for x | +| b_condition.py:17 | cond | ControlFlowNode for cond | +| b_condition.py:17 | unknown | ControlFlowNode for unknown | +| b_condition.py:19 | x | ControlFlowNode for x | +| b_condition.py:21 | use | ControlFlowNode for use | +| b_condition.py:21 | x | ControlFlowNode for x | +| b_condition.py:23 | cond | ControlFlowNode for cond | +| b_condition.py:23 | unknown | ControlFlowNode for unknown | +| b_condition.py:25 | x | ControlFlowNode for x | +| b_condition.py:26 | use | ControlFlowNode for use | +| b_condition.py:26 | x | ControlFlowNode for x | +| b_condition.py:27 | unknown | ControlFlowNode for unknown | +| b_condition.py:29 | use | ControlFlowNode for use | +| b_condition.py:29 | x | ControlFlowNode for x | +| b_condition.py:31 | cond | ControlFlowNode for cond | +| b_condition.py:31 | unknown | ControlFlowNode for unknown | +| b_condition.py:32 | x | ControlFlowNode for x | +| b_condition.py:34 | use | ControlFlowNode for use | +| b_condition.py:34 | x | ControlFlowNode for x | +| b_condition.py:36 | int | ControlFlowNode for int | +| b_condition.py:36 | isinstance | ControlFlowNode for isinstance | +| b_condition.py:36 | x | ControlFlowNode for x | +| b_condition.py:37 | use | ControlFlowNode for use | +| b_condition.py:37 | x | ControlFlowNode for x | +| b_condition.py:39 | __name__ | ControlFlowNode for thing() | +| b_condition.py:39 | __package__ | ControlFlowNode for thing() | +| b_condition.py:39 | double_attr_check | ControlFlowNode for thing() | +| b_condition.py:39 | f | ControlFlowNode for thing() | +| b_condition.py:39 | g | ControlFlowNode for thing() | +| b_condition.py:39 | h | ControlFlowNode for thing() | +| b_condition.py:39 | k | ControlFlowNode for thing() | +| b_condition.py:39 | loop | ControlFlowNode for thing() | +| b_condition.py:39 | not_or_not | ControlFlowNode for thing() | +| b_condition.py:39 | odasa6261 | ControlFlowNode for thing() | +| b_condition.py:39 | split_bool1 | ControlFlowNode for thing() | +| b_condition.py:39 | thing | ControlFlowNode for thing | +| b_condition.py:39 | v2 | ControlFlowNode for thing() | +| b_condition.py:41 | v2 | ControlFlowNode for v2 | +| b_condition.py:42 | v2 | ControlFlowNode for v2 | +| b_condition.py:43 | __name__ | ControlFlowNode for use() | +| b_condition.py:43 | __package__ | ControlFlowNode for use() | +| b_condition.py:43 | double_attr_check | ControlFlowNode for use() | +| b_condition.py:43 | f | ControlFlowNode for use() | +| b_condition.py:43 | g | ControlFlowNode for use() | +| b_condition.py:43 | h | ControlFlowNode for use() | +| b_condition.py:43 | k | ControlFlowNode for use() | +| b_condition.py:43 | loop | ControlFlowNode for use() | +| b_condition.py:43 | not_or_not | ControlFlowNode for use() | +| b_condition.py:43 | odasa6261 | ControlFlowNode for use() | +| b_condition.py:43 | split_bool1 | ControlFlowNode for use() | +| b_condition.py:43 | use | ControlFlowNode for use | +| b_condition.py:43 | v2 | ControlFlowNode for use() | +| b_condition.py:43 | v2 | ControlFlowNode for v2 | +| b_condition.py:44 | __name__ | ControlFlowNode for use() | +| b_condition.py:44 | __package__ | ControlFlowNode for use() | +| b_condition.py:44 | double_attr_check | ControlFlowNode for use() | +| b_condition.py:44 | f | ControlFlowNode for use() | +| b_condition.py:44 | g | ControlFlowNode for use() | +| b_condition.py:44 | h | ControlFlowNode for use() | +| b_condition.py:44 | k | ControlFlowNode for use() | +| b_condition.py:44 | loop | ControlFlowNode for use() | +| b_condition.py:44 | not_or_not | ControlFlowNode for use() | +| b_condition.py:44 | odasa6261 | ControlFlowNode for use() | +| b_condition.py:44 | split_bool1 | ControlFlowNode for use() | +| b_condition.py:44 | use | ControlFlowNode for use | +| b_condition.py:44 | v2 | ControlFlowNode for use() | +| b_condition.py:44 | v2 | ControlFlowNode for v2 | +| b_condition.py:50 | x | Exit node for Function g | +| b_condition.py:51 | x | ControlFlowNode for x | +| b_condition.py:52 | x | ControlFlowNode for x | +| b_condition.py:55 | seq | Exit node for Function loop | +| b_condition.py:55 | v | Exit node for Function loop | +| b_condition.py:56 | seq | ControlFlowNode for seq | +| b_condition.py:57 | v | ControlFlowNode for v | +| b_condition.py:58 | use | ControlFlowNode for use | +| b_condition.py:58 | v | ControlFlowNode for v | +| b_condition.py:61 | x | Exit node for Function double_attr_check | +| b_condition.py:61 | y | Exit node for Function double_attr_check | +| b_condition.py:62 | x | ControlFlowNode for x | +| b_condition.py:64 | y | ControlFlowNode for y | +| b_condition.py:65 | x | ControlFlowNode for x | +| b_condition.py:66 | seq | ControlFlowNode for seq | +| b_condition.py:66 | x | ControlFlowNode for x | +| b_condition.py:69 | b | Exit node for Function h | +| b_condition.py:70 | cond | ControlFlowNode for cond | +| b_condition.py:70 | unknown | ControlFlowNode for unknown | +| b_condition.py:71 | b | ControlFlowNode for b | +| b_condition.py:73 | b | ControlFlowNode for b | +| b_condition.py:75 | t | Exit node for Function k | +| b_condition.py:76 | type | ControlFlowNode for type | +| b_condition.py:77 | object | ControlFlowNode for object | +| b_condition.py:77 | t | ControlFlowNode for t | +| b_condition.py:78 | object | ControlFlowNode for object | +| b_condition.py:79 | t | ControlFlowNode for t | +| b_condition.py:79 | use | ControlFlowNode for use | +| b_condition.py:81 | bar | Exit node for Function odasa6261 | +| b_condition.py:81 | foo | Exit node for Function odasa6261 | +| b_condition.py:82 | callable | ControlFlowNode for callable | +| b_condition.py:82 | foo | ControlFlowNode for callable() | +| b_condition.py:82 | foo | ControlFlowNode for foo | +| b_condition.py:84 | foo | ControlFlowNode for foo | +| b_condition.py:84 | foo | ControlFlowNode for foo() | +| b_condition.py:87 | x | Exit node for Function split_bool1 | +| b_condition.py:87 | y | Exit node for Function split_bool1 | +| b_condition.py:88 | x | ControlFlowNode for x | +| b_condition.py:88 | y | ControlFlowNode for y | +| b_condition.py:90 | x | ControlFlowNode for x | +| b_condition.py:90 | y | ControlFlowNode for y | +| b_condition.py:92 | x | ControlFlowNode for x | +| b_condition.py:93 | use | ControlFlowNode for use | +| b_condition.py:93 | y | ControlFlowNode for y | +| b_condition.py:95 | use | ControlFlowNode for use | +| b_condition.py:95 | y | ControlFlowNode for y | +| b_condition.py:96 | y | ControlFlowNode for y | +| b_condition.py:97 | use | ControlFlowNode for use | +| b_condition.py:97 | x | ControlFlowNode for x | +| b_condition.py:99 | use | ControlFlowNode for use | +| b_condition.py:99 | x | ControlFlowNode for x | +| b_condition.py:101 | a | Exit node for Function not_or_not | +| b_condition.py:102 | a | ControlFlowNode for a | +| b_condition.py:102 | isinstance | ControlFlowNode for isinstance | +| b_condition.py:102 | list | ControlFlowNode for list | +| b_condition.py:102 | tuple | ControlFlowNode for tuple | +| b_condition.py:103 | TypeError | ControlFlowNode for TypeError | +| b_condition.py:104 | a | ControlFlowNode for a | +| b_condition.py:105 | a | ControlFlowNode for a | +| b_condition.py:106 | Exception | ControlFlowNode for Exception | +| d_globals.py:0 | D | Exit node for Module code.d_globals | +| d_globals.py:0 | Ugly | Exit node for Module code.d_globals | +| d_globals.py:0 | X | Exit node for Module code.d_globals | +| d_globals.py:0 | __name__ | Exit node for Module code.d_globals | +| d_globals.py:0 | __package__ | Exit node for Module code.d_globals | +| d_globals.py:0 | assign_global | Exit node for Module code.d_globals | +| d_globals.py:0 | cond | Exit node for Module code.d_globals | +| d_globals.py:0 | cond3 | Exit node for Module code.d_globals | +| d_globals.py:0 | dict | Exit node for Module code.d_globals | +| d_globals.py:0 | g1 | Exit node for Module code.d_globals | +| d_globals.py:0 | g2 | Exit node for Module code.d_globals | +| d_globals.py:0 | g3 | Exit node for Module code.d_globals | +| d_globals.py:0 | g4 | Exit node for Module code.d_globals | +| d_globals.py:0 | get_g4 | Exit node for Module code.d_globals | +| d_globals.py:0 | glob | Exit node for Module code.d_globals | +| d_globals.py:0 | init | Exit node for Module code.d_globals | +| d_globals.py:0 | j | Exit node for Module code.d_globals | +| d_globals.py:0 | k | Exit node for Module code.d_globals | +| d_globals.py:0 | list | Exit node for Module code.d_globals | +| d_globals.py:0 | modinit | Exit node for Module code.d_globals | +| d_globals.py:0 | object | Exit node for Module code.d_globals | +| d_globals.py:0 | other_cond | Exit node for Module code.d_globals | +| d_globals.py:0 | outer | Exit node for Module code.d_globals | +| d_globals.py:0 | redefine | Exit node for Module code.d_globals | +| d_globals.py:0 | set_g4 | Exit node for Module code.d_globals | +| d_globals.py:0 | set_g4_indirect | Exit node for Module code.d_globals | +| d_globals.py:0 | tuple | Exit node for Module code.d_globals | +| d_globals.py:0 | type | Exit node for Module code.d_globals | +| d_globals.py:0 | use_list_attribute | Exit node for Module code.d_globals | +| d_globals.py:0 | v3 | Exit node for Module code.d_globals | +| d_globals.py:0 | x | Exit node for Module code.d_globals | +| d_globals.py:0 | y | Exit node for Module code.d_globals | +| d_globals.py:0 | z | Exit node for Module code.d_globals | +| d_globals.py:2 | g1 | Exit node for Function j | +| d_globals.py:2 | g2 | Exit node for Function j | +| d_globals.py:2 | g3 | Exit node for Function j | +| d_globals.py:2 | g4 | Exit node for Function j | +| d_globals.py:2 | glob | Exit node for Function j | +| d_globals.py:2 | z | Exit node for Function j | +| d_globals.py:3 | dict | ControlFlowNode for dict | +| d_globals.py:3 | tuple | ControlFlowNode for tuple | +| d_globals.py:4 | dict | ControlFlowNode for dict | +| d_globals.py:6 | dict | ControlFlowNode for dict | +| d_globals.py:7 | tuple | ControlFlowNode for tuple | +| d_globals.py:8 | tuple | ControlFlowNode for tuple | +| d_globals.py:16 | g1 | Exit node for Function assign_global | +| d_globals.py:16 | g2 | Exit node for Function assign_global | +| d_globals.py:16 | g3 | Exit node for Function assign_global | +| d_globals.py:16 | g4 | Exit node for Function assign_global | +| d_globals.py:16 | glob | Exit node for Function assign_global | +| d_globals.py:16 | z | Exit node for Function assign_global | +| d_globals.py:19 | g1 | ControlFlowNode for g1 | +| d_globals.py:25 | g1 | Exit node for Function init | +| d_globals.py:25 | g2 | Exit node for Function init | +| d_globals.py:25 | g3 | Exit node for Function init | +| d_globals.py:25 | g4 | Exit node for Function init | +| d_globals.py:25 | glob | Exit node for Function init | +| d_globals.py:25 | z | Exit node for Function init | +| d_globals.py:29 | D | ControlFlowNode for init() | +| d_globals.py:29 | Ugly | ControlFlowNode for init() | +| d_globals.py:29 | X | ControlFlowNode for init() | +| d_globals.py:29 | __name__ | ControlFlowNode for init() | +| d_globals.py:29 | __package__ | ControlFlowNode for init() | +| d_globals.py:29 | assign_global | ControlFlowNode for init() | +| d_globals.py:29 | dict | ControlFlowNode for init() | +| d_globals.py:29 | g1 | ControlFlowNode for init() | +| d_globals.py:29 | g2 | ControlFlowNode for init() | +| d_globals.py:29 | g3 | ControlFlowNode for init() | +| d_globals.py:29 | g4 | ControlFlowNode for init() | +| d_globals.py:29 | get_g4 | ControlFlowNode for init() | +| d_globals.py:29 | glob | ControlFlowNode for init() | +| d_globals.py:29 | init | ControlFlowNode for init | +| d_globals.py:29 | init | ControlFlowNode for init() | +| d_globals.py:29 | j | ControlFlowNode for init() | +| d_globals.py:29 | k | ControlFlowNode for init() | +| d_globals.py:29 | modinit | ControlFlowNode for init() | +| d_globals.py:29 | outer | ControlFlowNode for init() | +| d_globals.py:29 | redefine | ControlFlowNode for init() | +| d_globals.py:29 | set_g4 | ControlFlowNode for init() | +| d_globals.py:29 | set_g4_indirect | ControlFlowNode for init() | +| d_globals.py:29 | tuple | ControlFlowNode for init() | +| d_globals.py:29 | use_list_attribute | ControlFlowNode for init() | +| d_globals.py:29 | x | ControlFlowNode for init() | +| d_globals.py:29 | y | ControlFlowNode for init() | +| d_globals.py:29 | z | ControlFlowNode for init() | +| d_globals.py:30 | g2 | ControlFlowNode for g2 | +| d_globals.py:35 | __init__ | Exit node for Class Ugly | +| d_globals.py:35 | meth | Exit node for Class Ugly | +| d_globals.py:35 | object | ControlFlowNode for object | +| d_globals.py:37 | g1 | Exit node for Function __init__ | +| d_globals.py:37 | g2 | Exit node for Function __init__ | +| d_globals.py:37 | g3 | Exit node for Function __init__ | +| d_globals.py:37 | g4 | Exit node for Function __init__ | +| d_globals.py:37 | glob | Exit node for Function __init__ | +| d_globals.py:37 | self | Exit node for Function __init__ | +| d_globals.py:37 | z | Exit node for Function __init__ | +| d_globals.py:41 | g1 | Exit node for Function meth | +| d_globals.py:41 | g2 | Exit node for Function meth | +| d_globals.py:41 | g3 | Exit node for Function meth | +| d_globals.py:41 | g4 | Exit node for Function meth | +| d_globals.py:41 | glob | Exit node for Function meth | +| d_globals.py:41 | self | Exit node for Function meth | +| d_globals.py:41 | z | Exit node for Function meth | +| d_globals.py:42 | g3 | ControlFlowNode for g3 | +| d_globals.py:47 | x | ControlFlowNode for x | +| d_globals.py:48 | cond | ControlFlowNode for cond | +| d_globals.py:51 | other_cond | ControlFlowNode for other_cond | +| d_globals.py:55 | cond3 | ControlFlowNode for cond3 | +| d_globals.py:59 | y | ControlFlowNode for y | +| d_globals.py:60 | v3 | ControlFlowNode for v3 | +| d_globals.py:62 | X | ControlFlowNode for ClassExpr | +| d_globals.py:62 | g3 | ControlFlowNode for ClassExpr | +| d_globals.py:62 | object | ControlFlowNode for object | +| d_globals.py:62 | v4 | Exit node for Class X | +| d_globals.py:62 | y | ControlFlowNode for ClassExpr | +| d_globals.py:62 | y | Exit node for Class X | +| d_globals.py:63 | y | ControlFlowNode for y | +| d_globals.py:64 | v3 | ControlFlowNode for v3 | +| d_globals.py:65 | X | ControlFlowNode for X | +| d_globals.py:66 | g3 | ControlFlowNode for g3 | +| d_globals.py:68 | type | ControlFlowNode for type | +| d_globals.py:70 | arg | Exit node for Function k | +| d_globals.py:70 | g1 | Exit node for Function k | +| d_globals.py:70 | g2 | Exit node for Function k | +| d_globals.py:70 | g3 | Exit node for Function k | +| d_globals.py:70 | g4 | Exit node for Function k | +| d_globals.py:70 | glob | Exit node for Function k | +| d_globals.py:70 | z | Exit node for Function k | +| d_globals.py:71 | type | ControlFlowNode for type | +| d_globals.py:75 | g1 | Exit node for Function get_g4 | +| d_globals.py:75 | g2 | Exit node for Function get_g4 | +| d_globals.py:75 | g3 | Exit node for Function get_g4 | +| d_globals.py:75 | g4 | Exit node for Function get_g4 | +| d_globals.py:75 | glob | Exit node for Function get_g4 | +| d_globals.py:75 | z | Exit node for Function get_g4 | +| d_globals.py:76 | g4 | ControlFlowNode for g4 | +| d_globals.py:77 | g1 | ControlFlowNode for set_g4() | +| d_globals.py:77 | g2 | ControlFlowNode for set_g4() | +| d_globals.py:77 | g3 | ControlFlowNode for set_g4() | +| d_globals.py:77 | g4 | ControlFlowNode for set_g4() | +| d_globals.py:77 | glob | ControlFlowNode for set_g4() | +| d_globals.py:77 | set_g4 | ControlFlowNode for set_g4 | +| d_globals.py:77 | z | ControlFlowNode for set_g4() | +| d_globals.py:78 | g4 | ControlFlowNode for g4 | +| d_globals.py:80 | g1 | Exit node for Function set_g4 | +| d_globals.py:80 | g2 | Exit node for Function set_g4 | +| d_globals.py:80 | g3 | Exit node for Function set_g4 | +| d_globals.py:80 | g4 | Exit node for Function set_g4 | +| d_globals.py:80 | glob | Exit node for Function set_g4 | +| d_globals.py:80 | z | Exit node for Function set_g4 | +| d_globals.py:81 | g1 | ControlFlowNode for set_g4_indirect() | +| d_globals.py:81 | g2 | ControlFlowNode for set_g4_indirect() | +| d_globals.py:81 | g3 | ControlFlowNode for set_g4_indirect() | +| d_globals.py:81 | g4 | ControlFlowNode for set_g4_indirect() | +| d_globals.py:81 | glob | ControlFlowNode for set_g4_indirect() | +| d_globals.py:81 | set_g4_indirect | ControlFlowNode for set_g4_indirect | +| d_globals.py:81 | z | ControlFlowNode for set_g4_indirect() | +| d_globals.py:83 | g1 | Exit node for Function set_g4_indirect | +| d_globals.py:83 | g2 | Exit node for Function set_g4_indirect | +| d_globals.py:83 | g3 | Exit node for Function set_g4_indirect | +| d_globals.py:83 | g4 | Exit node for Function set_g4_indirect | +| d_globals.py:83 | glob | Exit node for Function set_g4_indirect | +| d_globals.py:83 | z | Exit node for Function set_g4_indirect | +| d_globals.py:87 | object | ControlFlowNode for object | +| d_globals.py:92 | modinit | ControlFlowNode for modinit | +| d_globals.py:95 | g1 | Exit node for Function outer | +| d_globals.py:95 | g2 | Exit node for Function outer | +| d_globals.py:95 | g3 | Exit node for Function outer | +| d_globals.py:95 | g4 | Exit node for Function outer | +| d_globals.py:95 | glob | Exit node for Function outer | +| d_globals.py:95 | inner | Exit node for Function outer | +| d_globals.py:95 | otherInner | Exit node for Function outer | +| d_globals.py:95 | z | Exit node for Function outer | +| d_globals.py:96 | g1 | Exit node for Function inner | +| d_globals.py:96 | g2 | Exit node for Function inner | +| d_globals.py:96 | g3 | Exit node for Function inner | +| d_globals.py:96 | g4 | Exit node for Function inner | +| d_globals.py:96 | glob | Exit node for Function inner | +| d_globals.py:96 | z | Exit node for Function inner | +| d_globals.py:99 | glob | ControlFlowNode for glob | +| d_globals.py:101 | g1 | Exit node for Function otherInner | +| d_globals.py:101 | g2 | Exit node for Function otherInner | +| d_globals.py:101 | g3 | Exit node for Function otherInner | +| d_globals.py:101 | g4 | Exit node for Function otherInner | +| d_globals.py:101 | glob | Exit node for Function otherInner | +| d_globals.py:101 | z | Exit node for Function otherInner | +| d_globals.py:102 | glob | ControlFlowNode for glob | +| d_globals.py:104 | g1 | ControlFlowNode for inner() | +| d_globals.py:104 | g2 | ControlFlowNode for inner() | +| d_globals.py:104 | g3 | ControlFlowNode for inner() | +| d_globals.py:104 | g4 | ControlFlowNode for inner() | +| d_globals.py:104 | glob | ControlFlowNode for inner() | +| d_globals.py:104 | inner | ControlFlowNode for inner | +| d_globals.py:104 | z | ControlFlowNode for inner() | +| d_globals.py:107 | g1 | Exit node for Function redefine | +| d_globals.py:107 | g2 | Exit node for Function redefine | +| d_globals.py:107 | g3 | Exit node for Function redefine | +| d_globals.py:107 | g4 | Exit node for Function redefine | +| d_globals.py:107 | glob | Exit node for Function redefine | +| d_globals.py:107 | z | Exit node for Function redefine | +| d_globals.py:109 | z | ControlFlowNode for z | +| d_globals.py:111 | z | ControlFlowNode for z | +| d_globals.py:112 | glob | ControlFlowNode for glob | +| d_globals.py:114 | glob | ControlFlowNode for glob | +| d_globals.py:118 | __init__ | Exit node for Class D | +| d_globals.py:118 | foo | Exit node for Class D | +| d_globals.py:118 | object | ControlFlowNode for object | +| d_globals.py:120 | g1 | Exit node for Function __init__ | +| d_globals.py:120 | g2 | Exit node for Function __init__ | +| d_globals.py:120 | g3 | Exit node for Function __init__ | +| d_globals.py:120 | g4 | Exit node for Function __init__ | +| d_globals.py:120 | glob | Exit node for Function __init__ | +| d_globals.py:120 | self | Exit node for Function __init__ | +| d_globals.py:120 | z | Exit node for Function __init__ | +| d_globals.py:123 | g1 | Exit node for Function foo | +| d_globals.py:123 | g2 | Exit node for Function foo | +| d_globals.py:123 | g3 | Exit node for Function foo | +| d_globals.py:123 | g4 | Exit node for Function foo | +| d_globals.py:123 | glob | Exit node for Function foo | +| d_globals.py:123 | self | Exit node for Function foo | +| d_globals.py:123 | z | Exit node for Function foo | +| d_globals.py:124 | dict | ControlFlowNode for dict | +| d_globals.py:126 | g1 | Exit node for Function use_list_attribute | +| d_globals.py:126 | g2 | Exit node for Function use_list_attribute | +| d_globals.py:126 | g3 | Exit node for Function use_list_attribute | +| d_globals.py:126 | g4 | Exit node for Function use_list_attribute | +| d_globals.py:126 | glob | Exit node for Function use_list_attribute | +| d_globals.py:126 | l | Exit node for Function use_list_attribute | +| d_globals.py:126 | z | Exit node for Function use_list_attribute | +| d_globals.py:128 | g1 | ControlFlowNode for Attribute() | +| d_globals.py:128 | g2 | ControlFlowNode for Attribute() | +| d_globals.py:128 | g3 | ControlFlowNode for Attribute() | +| d_globals.py:128 | g4 | ControlFlowNode for Attribute() | +| d_globals.py:128 | glob | ControlFlowNode for Attribute() | +| d_globals.py:128 | l | ControlFlowNode for l | +| d_globals.py:128 | list | ControlFlowNode for list | +| d_globals.py:128 | z | ControlFlowNode for Attribute() | +| d_globals.py:129 | l | ControlFlowNode for l | diff --git a/python/ql/test/library-tests/PointsTo/new/VarUses.ql b/python/ql/test/library-tests/PointsTo/new/VarUses.ql new file mode 100644 index 00000000000..a8b8b276d47 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/VarUses.ql @@ -0,0 +1,9 @@ + +import python +import semmle.dataflow.SSA +import semmle.python.pointsto.PointsTo +import Util + +from SsaSourceVariable var, ControlFlowNode use +where use = var.getAUse() or var.hasRefinement(use, _) +select locate(use.getLocation(), "abd"), var.getName(), use.toString() diff --git a/python/ql/test/library-tests/PointsTo/new/code/__init__.py b/python/ql/test/library-tests/PointsTo/new/code/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/library-tests/PointsTo/new/code/a_simple.py b/python/ql/test/library-tests/PointsTo/new/code/a_simple.py new file mode 100644 index 00000000000..e3eaf6b3f28 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/code/a_simple.py @@ -0,0 +1,36 @@ + +f1 = 1.0 +dict +tuple +i1 = 0 +s = () + +def func(): + pass + +class C(object): + pass + +def vararg_kwarg(*t, **d): + t + d + +def multi_loop(seq): + x = None + for x, y in seq: + x + +def with_definition(x): + with x as y: + y + +def multi_loop_in_try(x): + try: # This causes additional exception edges, such that: + for p, q in x: # `x` and `p` are not in the same BB. + p + except KeyError: + pass + +def f(*args, **kwargs): + not args[0] + not kwargs["x"] diff --git a/python/ql/test/library-tests/PointsTo/new/code/b_condition.py b/python/ql/test/library-tests/PointsTo/new/code/b_condition.py new file mode 100644 index 00000000000..7574955ca96 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/code/b_condition.py @@ -0,0 +1,108 @@ + +#Edge guards, aka pi-nodes. + +def f(y): + x = unknown() if cond else None + + if x is None: + x = 7 + use(x) + + x = unknown() if cond else None + + if x is not None: + x = 7 + use(x) + + x = unknown() if cond else None + + if not x: + x = None + use(x) + + x = unknown() if cond else None + + x = x if x else 1 + use(x) + if unknown(): + x = 1 + use(x) + + x = unknown() if cond else 1 + if not x: #Negation + x = 7 + use(x) + + assert isinstance(x, int) + use(x) + +v2 = thing() + +v2.x = 1 +if v2.y is not None: + use(v2.x) + use(v2.y) + +#A home for pi and phi-nodes +pass + + +def g(x): + if x: + x + +#Dead pi- and phi-nodes +def loop(seq): + for v in seq: + if v: + use(v) + +#This was causing the sanity check to fail, +def double_attr_check(x, y): + if x.b == 3: + return + if y: + if (x.a == 0 and + x.a in seq): + return + +def h(): + b = unknown() if cond else True + if not b: + b = 7 + return b + +def k(): + t = type + if t is not object: + t = object + use(t) + +def odasa6261(foo=True): + if callable(foo): + def bar(): + return foo() + +#Splittings with boolean expressions: +def split_bool1(x=None,y=None): + if x and y: + raise + if not (x or y): + raise + if x: + use(y) + else: + use(y) + if y: + use(x) + else: + use(x) + +def not_or_not(*a): + if not isinstance(a, (tuple, list)): + raise TypeError() + if (not a or + not a[0]): + raise Exception() + "Hello" + diff --git a/python/ql/test/library-tests/PointsTo/new/code/c_tests.py b/python/ql/test/library-tests/PointsTo/new/code/c_tests.py new file mode 100644 index 00000000000..206157c0c68 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/code/c_tests.py @@ -0,0 +1,101 @@ + +#Edge guards, aka pi-nodes. + +def f(y): + x = unknown() if cond else None + + if x is None: + pass + + x = 0 if cond else 1 + + if x: + pass + + x = 0 if cond else 1 + + if x == 0: + pass + + + x = ((1,2) if cond else (1,2,3)) if unknown() else [1,2] + + if len(x): + pass + + if len(x) == 2: + pass + + if isinstance(x, tuple): + pass + + y.a = unknown() if cond else None + + if y.a is None: + pass + + y.a = 0 if cond else 1 + + if y.a: + pass + + y.a = 0 if cond else 1 + + if y.a == 0: + pass + + + y.a = ((1,2) if cond else (1,2,3)) if unknown() else [1,2] + + if isinstance(y.a, tuple): + pass + + if len(y.a) == 2: + pass + +def others(x): + + x = bool if cond else type + + if issubclass(x, int): + pass + + x = 0 if cond else float + + if hasattr(x, "bit_length"): + pass + + if callable(x): + pass + +def compound(x=1, y=0): + + if x or y: + x + y + + if x and y: + x + y + +def h(): + b = unknown() if cond else True + if b: + pass + b = unknown() if cond else True + if not b: + pass + + if unknown() == 3: + pass + + x = unknown() if cond else None + if x: + pass + + x = unknown() if cond else None + if not x: + pass + +def complex_test(x): # Was failing sanity check. + if not (foo(x) and bar(x)): + use(x) + pass diff --git a/python/ql/test/library-tests/PointsTo/new/code/d_globals.py b/python/ql/test/library-tests/PointsTo/new/code/d_globals.py new file mode 100644 index 00000000000..72a063b2a75 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/code/d_globals.py @@ -0,0 +1,130 @@ + +def j(): + return tuple, dict +dict +dict = 7 +dict +tuple = tuple +tuple + + + + +#Global assignment in local scope +g1 = None + +def assign_global(): + global g1 + g1 = 101 + return g1 # Cannot be None + +#Assignment in local scope, but called from module level + +g2 = None + +def init(): + global g2 + g2 = 102 + +init() +g2 # Cannot be None + +#Global set in init method +g3 = None + +class Ugly(object): + + def __init__(self): + global g3 + g3 = 103 + + def meth(self): + return g3 # Cannot be None + +#Redefine +x = 0 +x = 1 +x +if cond: + x = 3 + +if other_cond: + y = 1 +else: + y = 2 + if cond3: + pass + else: + pass +y +v3 + +class X(object): + y = y + v4 = v3 + X # Undefined + g3 + +type + +def k(arg): + type + +g4 = None + +def get_g4(): + if not g4: + set_g4() + return g4 # Cannot be None + +def set_g4(): + set_g4_indirect() + +def set_g4_indirect(): + global g4 + g4 = False + +class modinit(object): #ODASA-5486 + + global z + z = 0 + +del modinit + +#ODASA-4688 +def outer(): + def inner(): + global glob + glob = 100 + return glob + + def otherInner(): + return glob + + inner() + + +def redefine(): + global z, glob + z + z = 1 + z + glob + glob = 50 + glob + + + +class D(object): + + def __init__(self): + pass + + def foo(self): + return dict + +def use_list_attribute(): + l = [] + list.append(l, 0) + return l + diff --git a/python/ql/test/library-tests/PointsTo/new/code/e_temporal.py b/python/ql/test/library-tests/PointsTo/new/code/e_temporal.py new file mode 100644 index 00000000000..c71154f91d9 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/code/e_temporal.py @@ -0,0 +1,12 @@ + +import sys + +def f(): + len(sys.argv) > 3 # Should be defined, as call to f() precedes import of sys. + #The return is completely unconditional, so we can safely infer that calls to f() return 1. + return 1 + +def g(arg): + return arg + +x = g(f()) diff --git a/python/ql/test/library-tests/PointsTo/new/code/f_finally.py b/python/ql/test/library-tests/PointsTo/new/code/f_finally.py new file mode 100644 index 00000000000..bfc42c08e32 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/code/f_finally.py @@ -0,0 +1,11 @@ +class Queue(object): + + def close(self): + self._closed = True + try: + self._reader.close() + finally: + close = self._close + if close: + self._close = None + close() # FP was here: None on exceptional branch diff --git a/python/ql/test/library-tests/PointsTo/new/code/g_class_init.py b/python/ql/test/library-tests/PointsTo/new/code/g_class_init.py new file mode 100644 index 00000000000..6fc385c0b24 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/code/g_class_init.py @@ -0,0 +1,54 @@ + +#Convoluted object initialisation and self attribute use. +class C(object): + + def __init__(self): + self._init() + self.x = 1 + + def _init(self): + self.y = 2 + self._init2() + + def _init2(self): + self.z = 3 + + def method(self): + use(self.x) + if isinstance(self.y, int): + use(self.y) + use(self.z) + pass # Give phi nodes a location + + +class Oddities(object): + + int = int + float = float + l = len + h = hash + + +class D(object): + + def __init__(self): + super(D, self).x + return super(D, self).__init__() + + + +#ODASA-4519 +#OK as we are using identity tests for unique objects +V2 = "v2" +V3 = "v3" + +class E(object): + def __init__(self, c): + if c: + self.version = V2 + else: + self.version = V3 + + def meth(self): + if self.version is V2: #FP here. + pass diff --git a/python/ql/test/library-tests/PointsTo/new/code/h_classes.py b/python/ql/test/library-tests/PointsTo/new/code/h_classes.py new file mode 100644 index 00000000000..c5077942c0d --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/code/h_classes.py @@ -0,0 +1,54 @@ +import sys + +class C(object): + + x = 'C_x' + + def __init__(self): + self.y = 'c_y' + +type(C()) +type(sys) +type(name, (object,), {}) + +def k(arg): + type(C()) + type(sys) + type(arg) + type(name, (object,), {}) + + +#ODASA-3263 +#Django does this +class Base(object): + + def __init__(self, choice): + if choice == 1: + self.__class__ = Derived1 + elif choice == 2: + self.__class__ = Derived2 + else: + self.__class__ = Derived3 + +class Derived1(Base): + pass + +class Derived2(Base): + pass + +class Derived3(Base): + pass + +thing = Base(unknown()) + + +def f(arg0, arg1, arg2): + pass + +class D(object): + + m = f #Use function as a method. + + def n(self, arg1): + pass + diff --git a/python/ql/test/library-tests/PointsTo/new/code/i_imports.py b/python/ql/test/library-tests/PointsTo/new/code/i_imports.py new file mode 100644 index 00000000000..5c8bc52b7b6 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/code/i_imports.py @@ -0,0 +1,38 @@ + + +a = 1 +b = 2 +c = 3 + +from .xyz import * +from . import xyz +xyz.x +z +a + +from sys import argv +#Check that points-to has inserted origin +argv + +import sys +sys.argv + + + + +import code.package.x +code.package.x + + +from code.test_package import * +# https://bugs.python.org/issue18602 +import _io +StringIO = _io.StringIO +BytesIO = _io.BytesIO + +import io +StringIO = io.StringIO +BytesIO = io.BytesIO + +import code.n_nesting +code.n_nesting.f2() diff --git a/python/ql/test/library-tests/PointsTo/new/code/j_convoluted_imports.py b/python/ql/test/library-tests/PointsTo/new/code/j_convoluted_imports.py new file mode 100644 index 00000000000..f22dd560be3 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/code/j_convoluted_imports.py @@ -0,0 +1,17 @@ + +from code.package \ +import module + +from code.package \ +import x +#Should work correctly in nested scopes as well. + +class C(object): + + from code.package import module2 + + def f(self): + from code.package import x + +from code.package import moduleX +moduleX.Y diff --git a/python/ql/test/library-tests/PointsTo/new/code/k_getsetattr.py b/python/ql/test/library-tests/PointsTo/new/code/k_getsetattr.py new file mode 100644 index 00000000000..cd9604f7c7e --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/code/k_getsetattr.py @@ -0,0 +1,31 @@ + +#Make sure that we handle getattr and setattr as well as they are needed for protobuf stubs. + +class C(object): + + def meth1(self): + setattr(self, "a", 0) + setattr(self, "b", 1) + getattr(self, "a") + getattr(self, "c") + + def meth2(self): + setattr(self, "a", 7.0) + setattr(self, "c", 2) + self.meth1() + getattr(self, "a") + getattr(self, "b") + getattr(self, "c") + +#Locally redefined attribute +def k(cond): + c1 = C() + c2 = C() + c3 = C() + c1.a = 10 + if cond: + c2.a = 20 + c1.a + c2.a + c3.a + c3.a = 30 diff --git a/python/ql/test/library-tests/PointsTo/new/code/l_calls.py b/python/ql/test/library-tests/PointsTo/new/code/l_calls.py new file mode 100644 index 00000000000..d49f373cec4 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/code/l_calls.py @@ -0,0 +1,26 @@ + + +def foo(x = []): + return x.append("x") + +def bar(x = []): + return len(x) + +foo() +bar() + +class Owner(object): + + @classmethod + def cm(cls, arg): + return cls + + @classmethod + def cm2(cls, arg): + return arg + + #Normal method + def m(self): + a = self.cm(0) + return a.cm2(1) + diff --git a/python/ql/test/library-tests/PointsTo/new/code/m_attributes.py b/python/ql/test/library-tests/PointsTo/new/code/m_attributes.py new file mode 100644 index 00000000000..1ac04de0bfd --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/code/m_attributes.py @@ -0,0 +1,13 @@ + + +class C(object): + + def __init__(self, a=17): + self.a = a + + def foo(self, other): + self.a + other.a + +C().foo(C()) +C().foo(C(100)) diff --git a/python/ql/test/library-tests/PointsTo/new/code/n_nesting.py b/python/ql/test/library-tests/PointsTo/new/code/n_nesting.py new file mode 100644 index 00000000000..c3c630e55cd --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/code/n_nesting.py @@ -0,0 +1,34 @@ + +# Guarded inner closure creation +# See ODASA-6212 +# TO DO: +# 1. Split on tests that control closure creation +# 2. Link scope-entry definition at inner scope entry +# to the corresponding exit definition. +def foo(compile_ops=True): + if callable(compile_ops): + def inner(node_def): + return compile_ops(node_def) + else: + def inner(node_def): + return compile_ops(node_def) + attrs = { + "inner": inner + } + return attrs + +#Track globals across deeply nested calls-- ODASA-6673 + +def f1(): + C.flag = 1 # Sufficiently deeply nested that we won't track `C` to here in the import context +def f2(): + f1() +def f3(): + f2() +def f4(): + f3() +class C(object): pass +f4() +class D(C): # But we should track `C` to here even though we can't track all the way down to `f1` + pass +C = 1 diff --git a/python/ql/test/library-tests/PointsTo/new/code/o_no_returns.py b/python/ql/test/library-tests/PointsTo/new/code/o_no_returns.py new file mode 100644 index 00000000000..0ca6e48c3cb --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/code/o_no_returns.py @@ -0,0 +1,26 @@ +#Test for ODASA-6418 + +import sys + +def bar(cond): + if cond: + fail("cond true") + + +def fail(message, *args): + write('Error:', message % args, file=sys.stderr) + sys.exit(1) + +def foo(cond): + bar() + +# To get the FP result reported in ODASA-6418, the following must hold: +#bar must be called directly (not transitively) from the module scope +#bar must precede fail +#The call to bar must follow fail +bar(unknown()) + +#The following do not trigger the bug +#foo(unknown()) +#pass + diff --git a/python/ql/test/library-tests/PointsTo/new/code/p_decorators.py b/python/ql/test/library-tests/PointsTo/new/code/p_decorators.py new file mode 100644 index 00000000000..d06f14f988b --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/code/p_decorators.py @@ -0,0 +1,34 @@ + + +def simple(func): + func.__annotation__ = "Hello" + return func + +@simple +def foo(): + pass + +def complex(msg): + def annotate(func): + func.__annotation__ = msg + return func + return annotate + +@complex("Hi") +def bar(): + pass + +foo +bar + +class C(object): + + @staticmethod + def smeth(arg0, arg1): + arg0 + arg1 + + @classmethod + def cmeth(cls, arg0): + cls + arg0 diff --git a/python/ql/test/library-tests/PointsTo/new/code/package/__init__.py b/python/ql/test/library-tests/PointsTo/new/code/package/__init__.py new file mode 100644 index 00000000000..6a76e9ee942 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/code/package/__init__.py @@ -0,0 +1,15 @@ +from .module \ +import module + +from . import module2 as module3 +module2 = 7 +from . import module2 as module4 +from . import module3 as module5 +from code.package import moduleX + +#We should now have: +#module2 = 7 +#module3 = package.module2 +#module4 = 7 +#module5 = package.module2 +#moduleX = package.moduleX diff --git a/python/ql/test/library-tests/PointsTo/new/code/package/module.py b/python/ql/test/library-tests/PointsTo/new/code/package/module.py new file mode 100644 index 00000000000..008b713d67e --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/code/package/module.py @@ -0,0 +1,3 @@ + +def module(args): + pass diff --git a/python/ql/test/library-tests/PointsTo/new/code/package/module2.py b/python/ql/test/library-tests/PointsTo/new/code/package/module2.py new file mode 100644 index 00000000000..3aea0c58ce5 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/code/package/module2.py @@ -0,0 +1 @@ +x = 0 diff --git a/python/ql/test/library-tests/PointsTo/new/code/package/moduleX.py b/python/ql/test/library-tests/PointsTo/new/code/package/moduleX.py new file mode 100644 index 00000000000..3b39b8c0985 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/code/package/moduleX.py @@ -0,0 +1,2 @@ +class Y(object): + pass \ No newline at end of file diff --git a/python/ql/test/library-tests/PointsTo/new/code/package/x.py b/python/ql/test/library-tests/PointsTo/new/code/package/x.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/library-tests/PointsTo/new/code/q_super.py b/python/ql/test/library-tests/PointsTo/new/code/q_super.py new file mode 100644 index 00000000000..174f3227dbb --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/code/q_super.py @@ -0,0 +1,76 @@ +class Base2(object): + + def __init__(self): + super(Base2, self).__init__() + + + +class Derived4(Base2): + + def __init__(self): + super(Base2, self) + return super(Derived4, self).__init__() + +class Base1(object): + + def meth(self): + return 7 + +class Derived1(Base1): + + def meth(self): + return super(Derived1, self).meth() + +class Derived2(Derived1): + + def meth(self): + return super(Derived2, self).meth() + +class Derived5(Derived1): + + def meth(self): + return super(Derived5, self).meth() + +#Incorrect use of super() +class Wrong1(Derived5, Derived2): + + def meth(self): + return super(Derived5, self).meth() + +#ODASA-5799 +class DA(object): + + def __init__(self): + do_something() + +class DB(DA): + + class DC(DA): + + def __init__(self): + sup = super(DB.DC, self) + sup.__init__() + +#Simpler variants +class DD(DA): + + def __init__(self): + sup = super(DD, self) + sup.__init__() + +class DE(DA): + + class DF(DA): + + def __init__(self): + super(DE.DF, self).__init__() + +class N(object): + pass + +class M(N): + + def __init__(self): + s = super(M, self) + i = s.__init__ + i() diff --git a/python/ql/test/library-tests/PointsTo/new/code/r_regressions.py b/python/ql/test/library-tests/PointsTo/new/code/r_regressions.py new file mode 100644 index 00000000000..5579de3da8e --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/code/r_regressions.py @@ -0,0 +1,98 @@ +#Assorted regressions and test cases + +# FP for None spotted during development +# in multiprocessing/queue.py +class Queue(object): + + def __init__(self): + + self._after_fork() + + def _after_fork(self): + self._closed = False + self._close = None + + def close(self): + self._closed = True + try: + self._reader.close() + finally: + close = self._close + if close: + self._close = None + close() # FP was here: None on exceptional branch + + +#ODASA-5018 +def f(x,y=None, z=0): + if ( + x + and + y + ) or ( + y + and + not + z + ): + #y cannot be None here. + use(y) + +#from Ansible +def find_library(name): + [data, _] = x() + return data + +def fail(msg): + pass + +class C(object): + + def fail(self, msg): + fail(msg) + +#The following challenge is provided for us by Django... + +# The challenge here is that the decorator returned by this functions returns a different object +# depending on whether its argument is a class or not. +def method_decorator(decorator, name=''): + # Original django comment and docstring removed. + + def _dec(obj): + is_class = isinstance(obj, type) + if is_class: + do_validation() + else: + func = obj + + def _wrapper(self, *args, **kwargs): + #Doesn't matter what this does. + pass + + if is_class: + setattr(obj, name, _wrapper) + return obj # If obj is a class, we return it. + + return _wrapper # Otherwise we return the wrapper function. + + return _dec + +def deco(func): + def _wrapper(*args, **kwargs): + return True + return _wrapper + +@method_decorator(deco, "method") +class TestFirst(object): + def method(self): + return "hello world" + +TestFirst().method() # TestFirst here should be the class, not the wrapper function... + + +import sys + +_names = sys.builtin_module_names + +if 'time' in _names: + import time as t diff --git a/python/ql/test/library-tests/PointsTo/new/code/s_scopes.py b/python/ql/test/library-tests/PointsTo/new/code/s_scopes.py new file mode 100644 index 00000000000..ca6a4796a92 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/code/s_scopes.py @@ -0,0 +1,24 @@ + +#Global or builtin +if a: + float = True +pass + +class C2(object): + + i1 = int + f1 = float + #local + int = 0 + if b: + #local or builtin + str = 1.0 + #local, global or builtin + float = None + i2 = int + s = str + f2 = float + +x = x +i = int +f = float diff --git a/python/ql/test/library-tests/PointsTo/new/code/t_type.py b/python/ql/test/library-tests/PointsTo/new/code/t_type.py new file mode 100644 index 00000000000..2cbca18846f --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/code/t_type.py @@ -0,0 +1,16 @@ +import sys + +class C(object): + pass + +type(C()) +type(sys) +from module import unknown +type(unknown) +type(name, (object,), {}) + +def k(arg): + type(C()) + type(sys) + type(arg) + type(name, (object,), {}) diff --git a/python/ql/test/library-tests/PointsTo/new/code/test_package/__init__.py b/python/ql/test/library-tests/PointsTo/new/code/test_package/__init__.py new file mode 100644 index 00000000000..0000c542f77 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/code/test_package/__init__.py @@ -0,0 +1,3 @@ +from .module1 import * +from .module2 import * +import sys \ No newline at end of file diff --git a/python/ql/test/library-tests/PointsTo/new/code/test_package/module1.py b/python/ql/test/library-tests/PointsTo/new/code/test_package/module1.py new file mode 100644 index 00000000000..19bd2408d56 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/code/test_package/module1.py @@ -0,0 +1,6 @@ +__all__ = [ 'p', 'q', 'r' ] + +p = 1 +q = 2 +r = 3 +s = 4 diff --git a/python/ql/test/library-tests/PointsTo/new/code/test_package/module2.py b/python/ql/test/library-tests/PointsTo/new/code/test_package/module2.py new file mode 100644 index 00000000000..126afeb5204 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/code/test_package/module2.py @@ -0,0 +1,6 @@ +__all__ = [ 'r', 's'] + +p = [] +q = () +r = {} +s = None diff --git a/python/ql/test/library-tests/PointsTo/new/code/u_paired_values.py b/python/ql/test/library-tests/PointsTo/new/code/u_paired_values.py new file mode 100644 index 00000000000..5c6dabea361 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/code/u_paired_values.py @@ -0,0 +1,15 @@ + +def return_if_true(cond, val): + if cond: + return val + raise Exception() + +def test(cond): + x = return_if_true(True, 1) if cond else return_if_true(False, 2) + return x + +y = test(True) +y + +z = test(False) +z diff --git a/python/ql/test/library-tests/PointsTo/new/code/xyz.py b/python/ql/test/library-tests/PointsTo/new/code/xyz.py new file mode 100644 index 00000000000..392054917df --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/code/xyz.py @@ -0,0 +1,4 @@ + +x = 1.0 +y = 2.0 +z = 3.0 diff --git a/python/ql/test/library-tests/PointsTo/new/options b/python/ql/test/library-tests/PointsTo/new/options new file mode 100644 index 00000000000..8e16f310b52 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/options @@ -0,0 +1,2 @@ +semmle-extractor-options: --max-import-depth=4 +optimize: true diff --git a/python/ql/test/library-tests/PointsTo/new/test.py b/python/ql/test/library-tests/PointsTo/new/test.py new file mode 100644 index 00000000000..04176e98a74 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/new/test.py @@ -0,0 +1 @@ +from code import * diff --git a/python/ql/test/library-tests/PointsTo/returns/Test.expected b/python/ql/test/library-tests/PointsTo/returns/Test.expected new file mode 100644 index 00000000000..1bffc0d741c --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/returns/Test.expected @@ -0,0 +1,10 @@ +| Function f | builtin-class NoneType | +| Function f | builtin-class int | +| Function g | builtin-class NoneType | +| Function g | builtin-class float | +| Function g | builtin-class int | +| Function gen | builtin-class generator | +| Function h | builtin-class NoneType | +| Function h | builtin-class float | +| Function h | builtin-class int | +| Function not_none | builtin-class bool | diff --git a/python/ql/test/library-tests/PointsTo/returns/Test.ql b/python/ql/test/library-tests/PointsTo/returns/Test.ql new file mode 100644 index 00000000000..a30d0ef1c76 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/returns/Test.ql @@ -0,0 +1,4 @@ +import python + +from PyFunctionObject f +select f.toString(), f.getAnInferredReturnType().toString() \ No newline at end of file diff --git a/python/ql/test/library-tests/PointsTo/returns/options b/python/ql/test/library-tests/PointsTo/returns/options new file mode 100644 index 00000000000..58ad829f5a8 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/returns/options @@ -0,0 +1 @@ +optimize: true diff --git a/python/ql/test/library-tests/PointsTo/returns/test.py b/python/ql/test/library-tests/PointsTo/returns/test.py new file mode 100644 index 00000000000..af38b8064a3 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/returns/test.py @@ -0,0 +1,35 @@ + + + +def f(x): + if x: + return 1 + else: + return None + +def g(x, y): + if x: + return f(y) + else: + return 0.7 + +def h(a, b, c, d): + t = f(a) + v = g(b, c) + if d: + return t + else: + return v + +h(1,2,3,4) + +def not_none(a, b): + if a: + return True + elif b: + return False + #No fall through + raise Exception() + +def gen(): + yield 0 diff --git a/python/ql/test/library-tests/PointsTo/super/SuperMethodCall.expected b/python/ql/test/library-tests/PointsTo/super/SuperMethodCall.expected new file mode 100644 index 00000000000..69843b15d9d --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/super/SuperMethodCall.expected @@ -0,0 +1,9 @@ +| 4 | ControlFlowNode for Attribute() | object.__init__ | +| 12 | ControlFlowNode for Attribute() | Base2.__init__ | +| 22 | ControlFlowNode for Attribute() | Base1.meth | +| 27 | ControlFlowNode for Attribute() | Derived1.meth | +| 32 | ControlFlowNode for Attribute() | Derived1.meth | +| 38 | ControlFlowNode for Attribute() | Derived2.meth | +| 52 | ControlFlowNode for Attribute() | DA.__init__ | +| 59 | ControlFlowNode for Attribute() | DA.__init__ | +| 66 | ControlFlowNode for Attribute() | DA.__init__ | diff --git a/python/ql/test/library-tests/PointsTo/super/SuperMethodCall.ql b/python/ql/test/library-tests/PointsTo/super/SuperMethodCall.ql new file mode 100644 index 00000000000..4df31ff0478 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/super/SuperMethodCall.ql @@ -0,0 +1,9 @@ + +import python +import semmle.python.pointsto.PointsTo +import semmle.python.pointsto.PointsToContext + +from CallNode call, FunctionObject method +where PointsTo::Test::super_method_call(_, call, _, method) +select call.getLocation().getStartLine(), call.toString(), method.getQualifiedName() + diff --git a/python/ql/test/library-tests/PointsTo/super/test.py b/python/ql/test/library-tests/PointsTo/super/test.py new file mode 100644 index 00000000000..a5e8411b28d --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/super/test.py @@ -0,0 +1,66 @@ +class Base2(object): + + def __init__(self): + super(Base2, self).__init__() + + + +class Derived4(Base2): + + def __init__(self): + super(Base2, self) + return super(Derived4, self).__init__() + +class Base1(object): + + def meth(self): + pass + +class Derived1(Base1): + + def meth(self): + return super(Derived1, self).meth() + +class Derived2(Derived1): + + def meth(self): + return super(Derived2, self).meth() + +class Derived5(Derived1): + + def meth(self): + return super(Derived5, self).meth() + +#Incorrect use of super() +class Wrong1(Derived5, Derived2): + + def meth(self): + return super(Derived5, self).meth() + +#ODASA-5799 +class DA(object): + + def __init__(self): + do_something() + +class DB(DA): + + class DC(DA): + + def __init__(self): + sup = super(DB.DC, self) + sup.__init__() + +#Simpler variants +class DD(DA): + + def __init__(self): + sup = super(DD, self) + sup.__init__() + +class DE(DA): + + class DF(DA): + + def __init__(self): + super(DE.DF, self).__init__() diff --git a/python/ql/test/library-tests/PointsTo/version/VersionGuard.expected b/python/ql/test/library-tests/PointsTo/version/VersionGuard.expected new file mode 100644 index 00000000000..0a6b31a762d --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/version/VersionGuard.expected @@ -0,0 +1,3 @@ +| 25 | BasicBlock | 2 | +| 28 | BasicBlock | 3 | +| 41 | BasicBlock | 2 | diff --git a/python/ql/test/library-tests/PointsTo/version/VersionGuard.ql b/python/ql/test/library-tests/PointsTo/version/VersionGuard.ql new file mode 100644 index 00000000000..03bfb33a3f3 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/version/VersionGuard.ql @@ -0,0 +1,9 @@ + +import python +import semmle.python.types.Version + +from VersionGuard vg, Location l, int v +where l = vg.getLastNode().getLocation() and +l.getFile().getName().matches("%test.py") +and (if vg.isTrue() then v = major_version() else v = 5-major_version()) +select l.getStartLine(), vg.toString(), v \ No newline at end of file diff --git a/python/ql/test/library-tests/PointsTo/version/VersionTest.expected b/python/ql/test/library-tests/PointsTo/version/VersionTest.expected new file mode 100644 index 00000000000..fd0c9160574 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/version/VersionTest.expected @@ -0,0 +1,15 @@ +| 15 | ControlFlowNode for Compare | 2 | +| 22 | ControlFlowNode for Compare | 2 | +| 23 | ControlFlowNode for Compare | 3 | +| 51 | ControlFlowNode for Compare | 2 | +| 52 | ControlFlowNode for Compare | 3 | +| 54 | ControlFlowNode for Compare | 2 | +| 55 | ControlFlowNode for Compare | 3 | +| 57 | ControlFlowNode for Compare | 2 | +| 58 | ControlFlowNode for Compare | 3 | +| 59 | ControlFlowNode for Compare | 3 | +| 60 | ControlFlowNode for Compare | 2 | +| 61 | ControlFlowNode for Compare | 3 | +| 62 | ControlFlowNode for Compare | 2 | +| 65 | ControlFlowNode for Compare | 2 | +| 66 | ControlFlowNode for Compare | 3 | diff --git a/python/ql/test/library-tests/PointsTo/version/VersionTest.ql b/python/ql/test/library-tests/PointsTo/version/VersionTest.ql new file mode 100644 index 00000000000..0e6ca7fdee2 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/version/VersionTest.ql @@ -0,0 +1,9 @@ + +import python +import semmle.python.types.Version + +from VersionTest vt, Location l, int v +where l = vt.getNode().getLocation() and +l.getFile().getName().matches("%test.py") +and (if vt.isTrue() then v = major_version() else v = 5-major_version()) +select l.getStartLine(), vt.(ControlFlowNode).toString(), v diff --git a/python/ql/test/library-tests/PointsTo/version/module.py b/python/ql/test/library-tests/PointsTo/version/module.py new file mode 100644 index 00000000000..9e813a38428 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/version/module.py @@ -0,0 +1,5 @@ + +import sys + +os_test = sys.platform == "linux" +version_test = sys.version_info < (3,) diff --git a/python/ql/test/library-tests/PointsTo/version/test.py b/python/ql/test/library-tests/PointsTo/version/test.py new file mode 100644 index 00000000000..ad82c5ec425 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/version/test.py @@ -0,0 +1,66 @@ +import sys + + + + + + + + + + + + +os_test = sys.platform == "linux" +version_test = sys.version_info < (3,) + +from module import os_test as t2 +from module import version_test as t3 + + +# Tests from six +PY2 = sys.version_info[0] == 2 +PY3 = sys.version_info[0] == 3 + +if PY2: + version = 2 + +if PY3: + version = 3 + +if version == 2: + print("Version 2") + +if t2: + class G: pass +else: + def G(): pass + +g = G + +if t3: + class H: pass +else: + def H(): pass + +h = H + +#Some other forms of check. + +#Hexversion check (unlikely but a valid test) +PY2a = sys.hexversion < 0x03000000 +PY3a = sys.hexversion >= 0x03000000 + +PY2b = sys.hexversion < 0x03000000 +PY3b = sys.hexversion >= 0x03000000 + +PY2c = sys.version_info < (3,) +PY3c = sys.version_info >= (3,) +Py3d = sys.version_info >= (3,4) # Specific version of Python 3, rules out Python 2 +Py2d = sys.version_info < (2,7) +Py3e = sys.version_info[:2] >= (3,3) +Py2f = sys.version_info[:2] < (2,7) + +#From problem_report +Py2g = sys.version[0] < '3' +Py3h = sys.version[0] >= '3' diff --git a/python/ql/test/library-tests/attributes/SelfAttribute.expected b/python/ql/test/library-tests/attributes/SelfAttribute.expected new file mode 100644 index 00000000000..7d5843ffbe0 --- /dev/null +++ b/python/ql/test/library-tests/attributes/SelfAttribute.expected @@ -0,0 +1,4 @@ +| 10 | a1 | defined | +| 18 | a2 | defined | +| 21 | a0 | | +| 25 | a1 | guarded | \ No newline at end of file diff --git a/python/ql/test/library-tests/attributes/SelfAttribute.ql b/python/ql/test/library-tests/attributes/SelfAttribute.ql new file mode 100644 index 00000000000..0ccfe5a397c --- /dev/null +++ b/python/ql/test/library-tests/attributes/SelfAttribute.ql @@ -0,0 +1,11 @@ + +import python +import semmle.python.SelfAttribute + +from SelfAttributeRead sa, int line, string g, string l +where +line = sa.getLocation().getStartLine() and +if sa.guardedByHasattr() then g = "guarded" else g = "" and + +if sa.locallyDefined() then l = "defined" else l = "" +select line, sa.getName(), g + l diff --git a/python/ql/test/library-tests/attributes/test.py b/python/ql/test/library-tests/attributes/test.py new file mode 100644 index 00000000000..bf29f345d8f --- /dev/null +++ b/python/ql/test/library-tests/attributes/test.py @@ -0,0 +1,25 @@ + + +class C(object): + + def __init__(self, x): + self.a0 = x + + def m1(self, y): + self.a1 = y + return self.a1 + + def m2(self, z): + self.a2 = z + if cond: + pass + else: + raise Error() + return self.a2 + + def m3(self): + return self.a0 + + def m4(self): + if hasattr(self, 'a1'): + return self.a1 \ No newline at end of file diff --git a/python/ql/test/library-tests/classes/abstract/Abstract.expected b/python/ql/test/library-tests/classes/abstract/Abstract.expected new file mode 100644 index 00000000000..1a9ca319692 --- /dev/null +++ b/python/ql/test/library-tests/classes/abstract/Abstract.expected @@ -0,0 +1,6 @@ +| class A | yes | +| class B | yes | +| class C | yes | +| class D | no | +| class E | yes | +| class F | no | diff --git a/python/ql/test/library-tests/classes/abstract/Abstract.ql b/python/ql/test/library-tests/classes/abstract/Abstract.ql new file mode 100644 index 00000000000..1117bc95790 --- /dev/null +++ b/python/ql/test/library-tests/classes/abstract/Abstract.ql @@ -0,0 +1,12 @@ + +import python + +from ClassObject cls, string abstract +where +not cls.isBuiltin() and +if cls.isAbstract() then + abstract = "yes" +else + abstract = "no" + +select cls.toString(), abstract diff --git a/python/ql/test/library-tests/classes/abstract/test.py b/python/ql/test/library-tests/classes/abstract/test.py new file mode 100644 index 00000000000..a8f5e803a92 --- /dev/null +++ b/python/ql/test/library-tests/classes/abstract/test.py @@ -0,0 +1,32 @@ + + +class A(object): + + def __init__(self): + raise NotImplementedError + + def _meth(self): + raise NotImplementedError + +class B(A): + + def _meth(self): + "Still abstract" + +class C(A): + pass + +class D(B): + + def __init__(self): + "Not abstract" + +class E(A): + + def __init__(self): + "Still abstract" + +class F(E): + + def _meth(self): + "Not abstract" diff --git a/python/ql/test/library-tests/classes/attr/class_attr.expected b/python/ql/test/library-tests/classes/attr/class_attr.expected new file mode 100644 index 00000000000..65d7b79023b --- /dev/null +++ b/python/ql/test/library-tests/classes/attr/class_attr.expected @@ -0,0 +1,32 @@ +| 5 | class OldStyle | a1 | int 1 | +| 5 | class OldStyle | a2 | List | +| 5 | class OldStyle | l | List | +| 5 | class OldStyle | meth1 | Function meth1 | +| 15 | class OldStyleDerived | a1 | int 1 | +| 15 | class OldStyleDerived | a2 | List | +| 15 | class OldStyleDerived | l | List | +| 15 | class OldStyleDerived | meth1 | Function meth1 | +| 15 | class OldStyleDerived | meth2 | Function meth2 | +| 21 | class NewStyle | a1 | int 1 | +| 21 | class NewStyle | a2 | List | +| 21 | class NewStyle | l | List | +| 21 | class NewStyle | meth3 | Function meth3 | +| 31 | class NewStyleDerived | a1 | int 1 | +| 31 | class NewStyleDerived | a2 | List | +| 31 | class NewStyleDerived | l | List | +| 31 | class NewStyleDerived | meth3 | Function meth3 | +| 31 | class NewStyleDerived | meth4 | Function meth4 | +| 41 | class Meta | meth5 | Function meth5 | +| 41 | class Meta | mro | Builtin-method mro | +| 50 | class WithMeta | a1 | int 1 | +| 50 | class WithMeta | a2 | List | +| 50 | class WithMeta | l | List | +| 50 | class WithMeta | meth6 | Function meth6 | +| 96 | class Oddities | float | builtin-class float | +| 96 | class Oddities | h | Builtin-function hash | +| 96 | class Oddities | int | builtin-class int | +| 96 | class Oddities | l | Builtin-function len | +| 103 | class Sub | float | builtin-class float | +| 103 | class Sub | h | Builtin-function hash | +| 103 | class Sub | int | builtin-class int | +| 103 | class Sub | l | Builtin-function len | \ No newline at end of file diff --git a/python/ql/test/library-tests/classes/attr/class_attr.ql b/python/ql/test/library-tests/classes/attr/class_attr.ql new file mode 100644 index 00000000000..0b283debd5d --- /dev/null +++ b/python/ql/test/library-tests/classes/attr/class_attr.ql @@ -0,0 +1,13 @@ +/** + * @name class_attr + * @kind test + * @problem.severity warning + */ + +import python + +from ClassObject cls, int line, string name, Object obj +where cls.hasLocationInfo(_, line, _, _, _) +and obj = cls.lookupAttribute(name) and +not cls.isC() and not name.matches("\\_\\_%\\_\\_") +select line, cls.toString(), name, obj.toString() \ No newline at end of file diff --git a/python/ql/test/library-tests/classes/attr/class_defined_attr.expected b/python/ql/test/library-tests/classes/attr/class_defined_attr.expected new file mode 100644 index 00000000000..26712c5f275 --- /dev/null +++ b/python/ql/test/library-tests/classes/attr/class_defined_attr.expected @@ -0,0 +1,19 @@ +| 5 | class OldStyle | a1 | int 1 | +| 5 | class OldStyle | a2 | List | +| 5 | class OldStyle | l | List | +| 5 | class OldStyle | meth1 | Function meth1 | +| 15 | class OldStyleDerived | meth2 | Function meth2 | +| 21 | class NewStyle | a1 | int 1 | +| 21 | class NewStyle | a2 | List | +| 21 | class NewStyle | l | List | +| 21 | class NewStyle | meth3 | Function meth3 | +| 31 | class NewStyleDerived | meth4 | Function meth4 | +| 41 | class Meta | meth5 | Function meth5 | +| 50 | class WithMeta | a1 | int 1 | +| 50 | class WithMeta | a2 | List | +| 50 | class WithMeta | l | List | +| 50 | class WithMeta | meth6 | Function meth6 | +| 96 | class Oddities | float | builtin-class float | +| 96 | class Oddities | h | Builtin-function hash | +| 96 | class Oddities | int | builtin-class int | +| 96 | class Oddities | l | Builtin-function len | \ No newline at end of file diff --git a/python/ql/test/library-tests/classes/attr/class_defined_attr.ql b/python/ql/test/library-tests/classes/attr/class_defined_attr.ql new file mode 100644 index 00000000000..843b1ed2b3a --- /dev/null +++ b/python/ql/test/library-tests/classes/attr/class_defined_attr.ql @@ -0,0 +1,13 @@ +/** + * @name class_attr + * @kind test + * @problem.severity warning + */ + +import python + +from ClassObject cls, int line, string name, Object obj +where cls.hasLocationInfo(_, line, _, _, _) +and obj = cls.declaredAttribute(name) and +not cls.isC() and not name.matches("\\_\\_%\\_\\_") +select line, cls.toString(), name, obj.toString() diff --git a/python/ql/test/library-tests/classes/attr/class_defines_attr.expected b/python/ql/test/library-tests/classes/attr/class_defines_attr.expected new file mode 100644 index 00000000000..88adc304ada --- /dev/null +++ b/python/ql/test/library-tests/classes/attr/class_defines_attr.expected @@ -0,0 +1,22 @@ +| 5 | class OldStyle | a1 | +| 5 | class OldStyle | a2 | +| 5 | class OldStyle | a3 | +| 5 | class OldStyle | l | +| 5 | class OldStyle | meth1 | +| 15 | class OldStyleDerived | meth2 | +| 21 | class NewStyle | a1 | +| 21 | class NewStyle | a2 | +| 21 | class NewStyle | a3 | +| 21 | class NewStyle | l | +| 21 | class NewStyle | meth3 | +| 31 | class NewStyleDerived | meth4 | +| 41 | class Meta | meth5 | +| 50 | class WithMeta | a1 | +| 50 | class WithMeta | a2 | +| 50 | class WithMeta | a3 | +| 50 | class WithMeta | l | +| 50 | class WithMeta | meth6 | +| 96 | class Oddities | float | +| 96 | class Oddities | h | +| 96 | class Oddities | int | +| 96 | class Oddities | l | \ No newline at end of file diff --git a/python/ql/test/library-tests/classes/attr/class_defines_attr.ql b/python/ql/test/library-tests/classes/attr/class_defines_attr.ql new file mode 100644 index 00000000000..e9cfdee5ccd --- /dev/null +++ b/python/ql/test/library-tests/classes/attr/class_defines_attr.ql @@ -0,0 +1,13 @@ +/** + * @name class_attr + * @kind test + * @problem.severity warning + */ + +import python + +from ClassObject cls, int line, string name +where cls.hasLocationInfo(_, line, _, _, _) +and cls.declaresAttribute(name) and +not cls.isC() and not name.matches("\\_\\_%\\_\\_") +select line, cls.toString(), name diff --git a/python/ql/test/library-tests/classes/attr/class_has_attr.expected b/python/ql/test/library-tests/classes/attr/class_has_attr.expected new file mode 100644 index 00000000000..e73ad4d1894 --- /dev/null +++ b/python/ql/test/library-tests/classes/attr/class_has_attr.expected @@ -0,0 +1,37 @@ +| 5 | class OldStyle | a1 | +| 5 | class OldStyle | a2 | +| 5 | class OldStyle | a3 | +| 5 | class OldStyle | l | +| 5 | class OldStyle | meth1 | +| 15 | class OldStyleDerived | a1 | +| 15 | class OldStyleDerived | a2 | +| 15 | class OldStyleDerived | a3 | +| 15 | class OldStyleDerived | l | +| 15 | class OldStyleDerived | meth1 | +| 15 | class OldStyleDerived | meth2 | +| 21 | class NewStyle | a1 | +| 21 | class NewStyle | a2 | +| 21 | class NewStyle | a3 | +| 21 | class NewStyle | l | +| 21 | class NewStyle | meth3 | +| 31 | class NewStyleDerived | a1 | +| 31 | class NewStyleDerived | a2 | +| 31 | class NewStyleDerived | a3 | +| 31 | class NewStyleDerived | l | +| 31 | class NewStyleDerived | meth3 | +| 31 | class NewStyleDerived | meth4 | +| 41 | class Meta | meth5 | +| 41 | class Meta | mro | +| 50 | class WithMeta | a1 | +| 50 | class WithMeta | a2 | +| 50 | class WithMeta | a3 | +| 50 | class WithMeta | l | +| 50 | class WithMeta | meth6 | +| 96 | class Oddities | float | +| 96 | class Oddities | h | +| 96 | class Oddities | int | +| 96 | class Oddities | l | +| 103 | class Sub | float | +| 103 | class Sub | h | +| 103 | class Sub | int | +| 103 | class Sub | l | \ No newline at end of file diff --git a/python/ql/test/library-tests/classes/attr/class_has_attr.ql b/python/ql/test/library-tests/classes/attr/class_has_attr.ql new file mode 100644 index 00000000000..a274a1dd95b --- /dev/null +++ b/python/ql/test/library-tests/classes/attr/class_has_attr.ql @@ -0,0 +1,13 @@ +/** + * @name class_attr + * @kind test + * @problem.severity warning + */ + +import python + +from ClassObject cls, int line, string name +where cls.hasLocationInfo(_, line, _, _, _) +and cls.hasAttribute(name) and +not cls.isC() and not name.matches("\\_\\_%\\_\\_") +select line, cls.toString(), name diff --git a/python/ql/test/library-tests/classes/attr/hash.expected b/python/ql/test/library-tests/classes/attr/hash.expected new file mode 100644 index 00000000000..a65142422a0 --- /dev/null +++ b/python/ql/test/library-tests/classes/attr/hash.expected @@ -0,0 +1,2 @@ +| 92 | class Unhashable | NoneType None | +| 103 | class Sub | NoneType None | \ No newline at end of file diff --git a/python/ql/test/library-tests/classes/attr/hash.ql b/python/ql/test/library-tests/classes/attr/hash.ql new file mode 100644 index 00000000000..b4485634cce --- /dev/null +++ b/python/ql/test/library-tests/classes/attr/hash.ql @@ -0,0 +1,15 @@ +/** + * @name class_attr + * @kind test + * @problem.severity warning + */ + +import python + +from ClassObject cls, int line, Object obj +where cls.hasLocationInfo(_, line, _, _, _) +and obj = cls.lookupAttribute("__hash__") and +not cls.isC() and +not obj = theObjectType().lookupAttribute("__hash__") and +not obj = theTypeType().lookupAttribute("__hash__") +select line, cls.toString(), obj.toString() \ No newline at end of file diff --git a/python/ql/test/library-tests/classes/attr/test.py b/python/ql/test/library-tests/classes/attr/test.py new file mode 100644 index 00000000000..37780f02d88 --- /dev/null +++ b/python/ql/test/library-tests/classes/attr/test.py @@ -0,0 +1,104 @@ +from undefined import unknown +k = 1 +l = [] + +class OldStyle: + + def meth1(self): + pass + + a1 = k + a2 = l + a3 = unknown + l = l + +class OldStyleDerived(OldStyle): + + def meth2(self): + pass + + +class NewStyle(object): + + def meth3(self): + pass + + a1 = k + a2 = l + a3 = unknown + l = l + +class NewStyleDerived(NewStyle): + + def meth4(self): + pass + + + + + + +class Meta(type): + + def __init__(cls, name, bases, dct): + type.__init__(cls, name, bases, dct) + cls.defined_in_meta = 1 + + def meth5(self): + pass + +class WithMeta(object): + + def meth6(self): + pass + + a1 = k + a2 = l + a3 = unknown + l = l + +#MRO tests + +#Inconsistent MRO + +class X(object): + pass + +class Y(X): + pass + +#Inconsistent MRO +class Z(X, Y): + pass + +#Ok +class W(Y, x): + pass + +class O: + pass + +#This is OK +class N(object, O): + pass + +# +# Assign builtin objects to class attributes + +len = len + +ord = 10 + +class Unhashable(object): + + __hash__ = None + +class Oddities(object): + + int = int + float = float + l = len + h = hash + +class Sub(Oddities, Unhashable): + pass diff --git a/python/ql/test/library-tests/classes/builtin_classes/options b/python/ql/test/library-tests/classes/builtin_classes/options new file mode 100644 index 00000000000..9a4d1ee4e64 --- /dev/null +++ b/python/ql/test/library-tests/classes/builtin_classes/options @@ -0,0 +1,2 @@ +semmle-extractor-options: --max-import-depth=2 -j +optimize: true diff --git a/python/ql/test/library-tests/classes/builtin_classes/test.expected b/python/ql/test/library-tests/classes/builtin_classes/test.expected new file mode 100644 index 00000000000..4cfd98b96bd --- /dev/null +++ b/python/ql/test/library-tests/classes/builtin_classes/test.expected @@ -0,0 +1 @@ +| builtin-class _ctypes._Pointer | builtin-class _ctypes.PyCPointerType | \ No newline at end of file diff --git a/python/ql/test/library-tests/classes/builtin_classes/test.py b/python/ql/test/library-tests/classes/builtin_classes/test.py new file mode 100644 index 00000000000..705b596bde8 --- /dev/null +++ b/python/ql/test/library-tests/classes/builtin_classes/test.py @@ -0,0 +1 @@ +from ctypes import * \ No newline at end of file diff --git a/python/ql/test/library-tests/classes/builtin_classes/test.ql b/python/ql/test/library-tests/classes/builtin_classes/test.ql new file mode 100644 index 00000000000..19a5a23b954 --- /dev/null +++ b/python/ql/test/library-tests/classes/builtin_classes/test.ql @@ -0,0 +1,5 @@ +import python + +from ClassObject c +where c.getName() = "_ctypes._Pointer" +select c.toString(), c.getAnInferredType().toString() \ No newline at end of file diff --git a/python/ql/test/library-tests/classes/mro/C3.expected b/python/ql/test/library-tests/classes/mro/C3.expected new file mode 100644 index 00000000000..306ebb807f0 --- /dev/null +++ b/python/ql/test/library-tests/classes/mro/C3.expected @@ -0,0 +1,13 @@ +| class A | [A, object] | +| class B | [B, object] | +| class C | [C, object] | +| class D | [D, object] | +| class E | [E, object] | +| class K1 | [K1, A, B, C, object] | +| class K2 | [K2, D, B, E, object] | +| class K3 | [K3, D, A, object] | +| class M | [M, K1, K2, K3, D, A, B, C, E, object] | +| class T1 | [T1, object] | +| class T2 | [T2, object] | +| class T3 | [T3, T2, object] | +| class Test | [Test, T3, T2, T1, object] | diff --git a/python/ql/test/library-tests/classes/mro/C3.ql b/python/ql/test/library-tests/classes/mro/C3.ql new file mode 100644 index 00000000000..caaa43d3d45 --- /dev/null +++ b/python/ql/test/library-tests/classes/mro/C3.ql @@ -0,0 +1,9 @@ + +import python +import semmle.python.pointsto.MRO + +from ClassObject cls +where not cls.isBuiltin() + +select cls.toString(), new_style_mro(cls) + diff --git a/python/ql/test/library-tests/classes/mro/test.py b/python/ql/test/library-tests/classes/mro/test.py new file mode 100644 index 00000000000..9e66ad55650 --- /dev/null +++ b/python/ql/test/library-tests/classes/mro/test.py @@ -0,0 +1,15 @@ + + +#Check that MRO follows C3. + + +class T1(object): pass + +class T2(object): pass + +class T3(T2): pass + +class Test(T3, T1): pass + +#>>> Test.mro() +# [Test, T3, T2, T1, object] diff --git a/python/ql/test/library-tests/classes/mro/wikipedia.py b/python/ql/test/library-tests/classes/mro/wikipedia.py new file mode 100644 index 00000000000..a606313bfdf --- /dev/null +++ b/python/ql/test/library-tests/classes/mro/wikipedia.py @@ -0,0 +1,29 @@ +#Copyright Wikipedia + +#THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). +#THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER +# THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. +#BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. +#TO THE EXTENT THIS LICENSE MAY BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE +# IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS. + +class A(object): pass + +class B(object): pass + +class C(object): pass + +class D(object): pass + +class E(object): pass + +class K1(A, B, C): pass + +class K2(D, B, E): pass + +class K3(D, A): pass + +class M(K1, K2, K3): pass + +#>>> M.mro() +# [M, K1, K2, K3, D, A, B, C, E, object] diff --git a/python/ql/test/library-tests/comments/blocks.expected b/python/ql/test/library-tests/comments/blocks.expected new file mode 100644 index 00000000000..d337745d4d4 --- /dev/null +++ b/python/ql/test/library-tests/comments/blocks.expected @@ -0,0 +1,4 @@ +| 15 | 16 | Commented out code | +| 21 | 72 | Commented out code | +| 78 | 85 | Commented out code | +| 94 | 97 | Commented out code | \ No newline at end of file diff --git a/python/ql/test/library-tests/comments/blocks.ql b/python/ql/test/library-tests/comments/blocks.ql new file mode 100644 index 00000000000..e5c5f3ec3fd --- /dev/null +++ b/python/ql/test/library-tests/comments/blocks.ql @@ -0,0 +1,13 @@ +/** + * @name commented_out_code + * @description Insert description here... + * @kind problem + * @problem.severity warning + */ + +import python +import Lexical.CommentedOutCode + +from CommentedOutCodeBlock c, int bl, int el +where c.hasLocationInfo(_, bl, _, el, _) +select bl, el, c.toString() \ No newline at end of file diff --git a/python/ql/test/library-tests/comments/blocks_not_example.expected b/python/ql/test/library-tests/comments/blocks_not_example.expected new file mode 100644 index 00000000000..7a0a7158601 --- /dev/null +++ b/python/ql/test/library-tests/comments/blocks_not_example.expected @@ -0,0 +1,3 @@ +| 15 | 16 | Commented out code | +| 21 | 72 | Commented out code | +| 78 | 85 | Commented out code | \ No newline at end of file diff --git a/python/ql/test/library-tests/comments/blocks_not_example.ql b/python/ql/test/library-tests/comments/blocks_not_example.ql new file mode 100644 index 00000000000..ccc8c0ba50b --- /dev/null +++ b/python/ql/test/library-tests/comments/blocks_not_example.ql @@ -0,0 +1,7 @@ + +import python +import Lexical.CommentedOutCode + +from CommentedOutCodeBlock c, int bl, int el +where c.hasLocationInfo(_, bl, _, el, _) and not c.maybeExampleCode() +select bl, el, c.toString() \ No newline at end of file diff --git a/python/ql/test/library-tests/comments/length.expected b/python/ql/test/library-tests/comments/length.expected new file mode 100644 index 00000000000..b9a4b9bccae --- /dev/null +++ b/python/ql/test/library-tests/comments/length.expected @@ -0,0 +1,3 @@ +| 15 | 54 | true | +| 78 | 8 | true | +| 90 | 9 | false | diff --git a/python/ql/test/library-tests/comments/length.ql b/python/ql/test/library-tests/comments/length.ql new file mode 100644 index 00000000000..53d514e6b33 --- /dev/null +++ b/python/ql/test/library-tests/comments/length.ql @@ -0,0 +1,8 @@ + +import python +import Lexical.CommentedOutCode + +from CommentBlock block, int line, boolean code +where block.hasLocationInfo(_, line, _, _, _) and +if block instanceof CommentedOutCodeBlock then code = true else code = false +select line, block.length(), code diff --git a/python/ql/test/library-tests/comments/lines.expected b/python/ql/test/library-tests/comments/lines.expected new file mode 100644 index 00000000000..7c45cf8cd11 --- /dev/null +++ b/python/ql/test/library-tests/comments/lines.expected @@ -0,0 +1,46 @@ +| 15 | Comment #else: | +| 16 | Comment # do_something_else() | +| 21 | Comment #class CommentedOut: | +| 23 | Comment # def __init__(self): | +| 25 | Comment # pass | +| 27 | Comment # def method(self): | +| 29 | Comment # pass | +| 31 | Comment #def g(y): | +| 32 | Comment # assert y | +| 33 | Comment # with y: | +| 34 | Comment # # Commented out comment | +| 35 | Comment # if y: | +| 36 | Comment # do_something() | +| 37 | Comment # else: | +| 38 | Comment # do_something_else() | +| 40 | Comment #def h(z): | +| 41 | Comment # '''Doc string | +| 42 | Comment # ''' | +| 43 | Comment # # Commented out comment | +| 45 | Comment # followed_by_space() | +| 48 | Comment # more_code() | +| 50 | Comment #def j(): | +| 51 | Comment # """ Doc string """ | +| 52 | Comment # pass | +| 54 | Comment #def k(): | +| 56 | Comment # """ Doc string """ | +| 57 | Comment # pass | +| 59 | Comment #def l(): | +| 61 | Comment # """ | +| 62 | Comment # Doc string | +| 63 | Comment # """ | +| 65 | Comment # pass | +| 71 | Comment #def m(): | +| 72 | Comment # pass | +| 78 | Comment #with x: | +| 79 | Comment # pass | +| 80 | Comment #try: | +| 81 | Comment # call() | +| 82 | Comment #except Exception: | +| 83 | Comment # pass | +| 84 | Comment #except: | +| 85 | Comment # pass | +| 94 | Comment # def f(): | +| 95 | Comment # call() | +| 96 | Comment # x.y = z | +| 97 | Comment # return x | \ No newline at end of file diff --git a/python/ql/test/library-tests/comments/lines.ql b/python/ql/test/library-tests/comments/lines.ql new file mode 100644 index 00000000000..a07d2ac1953 --- /dev/null +++ b/python/ql/test/library-tests/comments/lines.ql @@ -0,0 +1,7 @@ + +import python +import Lexical.CommentedOutCode + +from CommentedOutCodeLine c, int l +where l = c.getLocation().getStartLine() +select l, c.toString() \ No newline at end of file diff --git a/python/ql/test/library-tests/comments/lines_not_example.expected b/python/ql/test/library-tests/comments/lines_not_example.expected new file mode 100644 index 00000000000..f476f967cda --- /dev/null +++ b/python/ql/test/library-tests/comments/lines_not_example.expected @@ -0,0 +1,42 @@ +| 15 | Comment #else: | +| 16 | Comment # do_something_else() | +| 21 | Comment #class CommentedOut: | +| 23 | Comment # def __init__(self): | +| 25 | Comment # pass | +| 27 | Comment # def method(self): | +| 29 | Comment # pass | +| 31 | Comment #def g(y): | +| 32 | Comment # assert y | +| 33 | Comment # with y: | +| 34 | Comment # # Commented out comment | +| 35 | Comment # if y: | +| 36 | Comment # do_something() | +| 37 | Comment # else: | +| 38 | Comment # do_something_else() | +| 40 | Comment #def h(z): | +| 41 | Comment # '''Doc string | +| 42 | Comment # ''' | +| 43 | Comment # # Commented out comment | +| 45 | Comment # followed_by_space() | +| 48 | Comment # more_code() | +| 50 | Comment #def j(): | +| 51 | Comment # """ Doc string """ | +| 52 | Comment # pass | +| 54 | Comment #def k(): | +| 56 | Comment # """ Doc string """ | +| 57 | Comment # pass | +| 59 | Comment #def l(): | +| 61 | Comment # """ | +| 62 | Comment # Doc string | +| 63 | Comment # """ | +| 65 | Comment # pass | +| 71 | Comment #def m(): | +| 72 | Comment # pass | +| 78 | Comment #with x: | +| 79 | Comment # pass | +| 80 | Comment #try: | +| 81 | Comment # call() | +| 82 | Comment #except Exception: | +| 83 | Comment # pass | +| 84 | Comment #except: | +| 85 | Comment # pass | \ No newline at end of file diff --git a/python/ql/test/library-tests/comments/lines_not_example.ql b/python/ql/test/library-tests/comments/lines_not_example.ql new file mode 100644 index 00000000000..e6fcaab9d93 --- /dev/null +++ b/python/ql/test/library-tests/comments/lines_not_example.ql @@ -0,0 +1,7 @@ + +import python +import Lexical.CommentedOutCode + +from CommentedOutCodeLine c, int l +where l = c.getLocation().getStartLine() and not c.maybeExampleCode() +select l, c.toString() \ No newline at end of file diff --git a/python/ql/test/library-tests/comments/test.py b/python/ql/test/library-tests/comments/test.py new file mode 100644 index 00000000000..162e6af3ff6 --- /dev/null +++ b/python/ql/test/library-tests/comments/test.py @@ -0,0 +1,103 @@ + +def e(): + #A real comment + some_code() + x = y + some_more_code() + "Ignore single commented out lines as it is too difficult to tell whether they are code" + #class C(object): + a_bit_more_code() + return 1 + +def f(x): + if x: + do_something() + #else: + # do_something_else() + +# Some non-code comments. +# Space immediately after scope start and between functions. +# +#class CommentedOut: +# +# def __init__(self): + +# pass +# +# def method(self): +# +# pass +# +#def g(y): +# assert y +# with y: +# # Commented out comment +# if y: +# do_something() +# else: +# do_something_else() +# +#def h(z): +# '''Doc string +# ''' +# # Commented out comment +# +# followed_by_space() + +# +# more_code() + +#def j(): +# """ Doc string """ +# pass + +#def k(): +# +# """ Doc string """ +# pass + +#def l(): +# +# """ +# Doc string +# """ +# +# pass + +# +# +# +# +#def m(): +# pass +# +# +# +some_code_to_break_up_comments() + +#with x: +# pass +#try: +# call() +#except Exception: +# pass +#except: +# pass + +def a_function_to_break_up_comments(): + pass + +# An example explaining +# something which contains +# the following code: +# +# def f(): +# call() +# x.y = z +# return x +# + + +def foo(): + # type: () -> None + pass \ No newline at end of file diff --git a/python/ql/test/library-tests/comments/type_hint.expected b/python/ql/test/library-tests/comments/type_hint.expected new file mode 100644 index 00000000000..1043c47cb63 --- /dev/null +++ b/python/ql/test/library-tests/comments/type_hint.expected @@ -0,0 +1 @@ +| test.py:102 | # type: () -> None | diff --git a/python/ql/test/library-tests/comments/type_hint.ql b/python/ql/test/library-tests/comments/type_hint.ql new file mode 100644 index 00000000000..55ec57c0d5b --- /dev/null +++ b/python/ql/test/library-tests/comments/type_hint.ql @@ -0,0 +1,6 @@ + +import python + +from TypeHintComment c +select c.getLocation().toString(), c.getText() + diff --git a/python/ql/test/library-tests/comparisons/Compare.expected b/python/ql/test/library-tests/comparisons/Compare.expected new file mode 100644 index 00000000000..70e08a0d348 --- /dev/null +++ b/python/ql/test/library-tests/comparisons/Compare.expected @@ -0,0 +1,20 @@ +| 3 | ControlFlowNode for x == 4 | +| 5 | ControlFlowNode for x != 4 | +| 7 | ControlFlowNode for x > 4 | +| 9 | ControlFlowNode for x < 4 | +| 11 | ControlFlowNode for x >= 4 | +| 13 | ControlFlowNode for x <= 4 | +| 17 | ControlFlowNode for x < 0 | +| 17 | ControlFlowNode for z < 0 | +| 19 | ControlFlowNode for x >= 0 | +| 21 | ControlFlowNode for z >= 0 | +| 23 | ControlFlowNode for w >= 0 | +| 24 | ControlFlowNode for y < 7 | +| 26 | ControlFlowNode for y == 15 | +| 28 | ControlFlowNode for y > 10 | +| 30 | ControlFlowNode for y < 10 | +| 32 | ControlFlowNode for y < 12 | +| 34 | ControlFlowNode for y == 5 | +| 35 | ControlFlowNode for y != 5 | +| 36 | ControlFlowNode for z > 0 | +| 37 | ControlFlowNode for y < 3 | diff --git a/python/ql/test/library-tests/comparisons/Compare.ql b/python/ql/test/library-tests/comparisons/Compare.ql new file mode 100644 index 00000000000..84d97bbbbe2 --- /dev/null +++ b/python/ql/test/library-tests/comparisons/Compare.ql @@ -0,0 +1,9 @@ + +import python + +import semmle.python.Comparisons + +from Comparison c, ControlFlowNode l, CompareOp op, float k +where +c.tests(l, op, k) +select c.getLocation().getStartLine(), l + " " + op.repr() + " " + k diff --git a/python/ql/test/library-tests/comparisons/Compare2.expected b/python/ql/test/library-tests/comparisons/Compare2.expected new file mode 100644 index 00000000000..d574baf4d4e --- /dev/null +++ b/python/ql/test/library-tests/comparisons/Compare2.expected @@ -0,0 +1,28 @@ +| 40 | x == y+4 | +| 40 | y == x-4 | +| 42 | x != y+4 | +| 42 | y != x-4 | +| 44 | x > y+4 | +| 44 | y < x-4 | +| 46 | x < y+4 | +| 46 | y > x-4 | +| 48 | x >= y+4 | +| 48 | y <= x-4 | +| 50 | x <= y+4 | +| 50 | y >= x-4 | +| 54 | w < x+0 | +| 54 | x > w-0 | +| 55 | y < z+2 | +| 55 | z > y-2 | +| 57 | w >= x+0 | +| 57 | x <= w-0 | +| 59 | y < z+2 | +| 59 | z > y-2 | +| 78 | end < start+0 | +| 78 | start > end-0 | +| 80 | end == start-0 | +| 80 | start == end+0 | +| 87 | x > y+0 | +| 87 | y < x-0 | +| 94 | x > y+0 | +| 94 | y < x-0 | diff --git a/python/ql/test/library-tests/comparisons/Compare2.ql b/python/ql/test/library-tests/comparisons/Compare2.ql new file mode 100644 index 00000000000..70d954a4b0e --- /dev/null +++ b/python/ql/test/library-tests/comparisons/Compare2.ql @@ -0,0 +1,11 @@ + +import python + +import semmle.python.Comparisons + +from Comparison c, NameNode l, CompareOp op, NameNode r, float k, string add +where +c.tests(l, op, r, k) +and +(k < 0 and add = "" or k >= 0 and add = "+") +select c.getLocation().getStartLine(), l.getId() + " " + op.repr() + " " + r.getId() + add + k diff --git a/python/ql/test/library-tests/comparisons/CompareControls.expected b/python/ql/test/library-tests/comparisons/CompareControls.expected new file mode 100644 index 00000000000..c47e6d08e94 --- /dev/null +++ b/python/ql/test/library-tests/comparisons/CompareControls.expected @@ -0,0 +1,54 @@ +| 3 | x == 4 | 4 | +| 5 | x != 4 | 6 | +| 7 | x > 4 | 8 | +| 9 | x < 4 | 10 | +| 11 | x >= 4 | 12 | +| 13 | x <= 4 | 14 | +| 17 | x >= 0 | 16 | +| 17 | x >= 0 | 17 | +| 17 | x >= 0 | 19 | +| 17 | x >= 0 | 23 | +| 17 | x >= 0 | 24 | +| 17 | x >= 0 | 25 | +| 17 | x >= 0 | 28 | +| 17 | x >= 0 | 29 | +| 17 | x >= 0 | 30 | +| 17 | x >= 0 | 31 | +| 17 | x >= 0 | 33 | +| 17 | x >= 0 | 34 | +| 17 | x >= 0 | 36 | +| 17 | x >= 0 | 37 | +| 17 | z >= 0 | 16 | +| 17 | z >= 0 | 19 | +| 17 | z >= 0 | 23 | +| 17 | z >= 0 | 24 | +| 17 | z >= 0 | 25 | +| 17 | z >= 0 | 28 | +| 17 | z >= 0 | 29 | +| 17 | z >= 0 | 30 | +| 17 | z >= 0 | 31 | +| 17 | z >= 0 | 33 | +| 17 | z >= 0 | 34 | +| 17 | z >= 0 | 36 | +| 17 | z >= 0 | 37 | +| 23 | w < 0 | 16 | +| 23 | w < 0 | 30 | +| 23 | w < 0 | 31 | +| 23 | w < 0 | 33 | +| 23 | w < 0 | 34 | +| 23 | w < 0 | 36 | +| 23 | w < 0 | 37 | +| 23 | w >= 0 | 24 | +| 23 | w >= 0 | 25 | +| 23 | w >= 0 | 28 | +| 23 | w >= 0 | 29 | +| 24 | y < 7 | 25 | +| 24 | y >= 7 | 28 | +| 24 | y >= 7 | 29 | +| 28 | y > 10 | 29 | +| 30 | y < 10 | 31 | +| 30 | y < 10 | 33 | +| 32 | y < 12 | 33 | +| 34 | y == 5 | 36 | +| 34 | y == 5 | 37 | +| 36 | z > 0 | 37 | diff --git a/python/ql/test/library-tests/comparisons/CompareControls.ql b/python/ql/test/library-tests/comparisons/CompareControls.ql new file mode 100644 index 00000000000..01b35c0ffad --- /dev/null +++ b/python/ql/test/library-tests/comparisons/CompareControls.ql @@ -0,0 +1,10 @@ + +import python + +import semmle.python.Comparisons + +from ComparisonControlBlock comp, SsaVariable v, CompareOp op, float k, BasicBlock b +where +comp.controls(v.getAUse(), op, k, b) + +select comp.getTest().getLocation().getStartLine(), v.getId() + " " + op.repr() + " " + k, b.getNode(0).getLocation().getStartLine() diff --git a/python/ql/test/library-tests/comparisons/Implication.expected b/python/ql/test/library-tests/comparisons/Implication.expected new file mode 100644 index 00000000000..bb9abc1b012 --- /dev/null +++ b/python/ql/test/library-tests/comparisons/Implication.expected @@ -0,0 +1,154 @@ +| 3 | false | 3 | false | +| 3 | false | 5 | true | +| 3 | true | 3 | true | +| 3 | true | 5 | false | +| 5 | false | 3 | true | +| 5 | false | 5 | false | +| 5 | true | 3 | false | +| 5 | true | 5 | true | +| 7 | false | 7 | false | +| 7 | false | 13 | true | +| 7 | true | 3 | false | +| 7 | true | 5 | true | +| 7 | true | 7 | true | +| 7 | true | 9 | false | +| 7 | true | 11 | true | +| 7 | true | 13 | false | +| 9 | false | 9 | false | +| 9 | false | 11 | true | +| 9 | true | 3 | false | +| 9 | true | 5 | true | +| 9 | true | 7 | false | +| 9 | true | 9 | true | +| 9 | true | 11 | false | +| 9 | true | 13 | true | +| 11 | false | 3 | false | +| 11 | false | 5 | true | +| 11 | false | 7 | false | +| 11 | false | 9 | true | +| 11 | false | 11 | false | +| 11 | false | 13 | true | +| 11 | true | 9 | false | +| 11 | true | 11 | true | +| 13 | false | 3 | false | +| 13 | false | 5 | true | +| 13 | false | 7 | true | +| 13 | false | 9 | false | +| 13 | false | 11 | true | +| 13 | false | 13 | false | +| 13 | true | 7 | false | +| 13 | true | 13 | true | +| 17 | false | 17 | false | +| 17 | false | 19 | true | +| 17 | false | 21 | true | +| 17 | true | 17 | true | +| 17 | true | 19 | false | +| 17 | true | 21 | false | +| 19 | false | 17 | true | +| 19 | false | 19 | false | +| 19 | true | 17 | false | +| 19 | true | 19 | true | +| 21 | false | 17 | true | +| 21 | false | 21 | false | +| 21 | true | 17 | false | +| 21 | true | 21 | true | +| 23 | false | 23 | false | +| 23 | true | 23 | true | +| 24 | false | 24 | false | +| 24 | true | 24 | true | +| 24 | true | 26 | false | +| 24 | true | 28 | false | +| 24 | true | 30 | true | +| 26 | false | 26 | false | +| 26 | true | 26 | true | +| 28 | false | 26 | false | +| 28 | false | 28 | false | +| 28 | true | 24 | false | +| 28 | true | 28 | true | +| 28 | true | 30 | false | +| 30 | false | 24 | false | +| 30 | false | 30 | false | +| 30 | true | 26 | false | +| 30 | true | 28 | false | +| 30 | true | 30 | true | +| 32 | false | 32 | false | +| 32 | true | 32 | true | +| 34 | false | 34 | false | +| 34 | false | 35 | true | +| 34 | true | 34 | true | +| 34 | true | 35 | false | +| 35 | false | 34 | true | +| 35 | false | 35 | false | +| 35 | true | 34 | false | +| 35 | true | 35 | true | +| 36 | false | 36 | false | +| 36 | true | 36 | true | +| 37 | false | 37 | false | +| 37 | true | 34 | false | +| 37 | true | 35 | true | +| 37 | true | 37 | true | +| 40 | false | 40 | false | +| 40 | false | 42 | true | +| 40 | true | 40 | true | +| 40 | true | 42 | false | +| 42 | false | 40 | true | +| 42 | false | 42 | false | +| 42 | true | 40 | false | +| 42 | true | 42 | true | +| 44 | false | 44 | false | +| 44 | false | 50 | true | +| 44 | true | 40 | false | +| 44 | true | 42 | true | +| 44 | true | 44 | true | +| 44 | true | 46 | false | +| 44 | true | 48 | true | +| 44 | true | 50 | false | +| 46 | false | 46 | false | +| 46 | false | 48 | true | +| 46 | true | 40 | false | +| 46 | true | 42 | true | +| 46 | true | 44 | false | +| 46 | true | 46 | true | +| 46 | true | 48 | false | +| 46 | true | 50 | true | +| 48 | false | 40 | false | +| 48 | false | 42 | true | +| 48 | false | 44 | false | +| 48 | false | 46 | true | +| 48 | false | 48 | false | +| 48 | false | 50 | true | +| 48 | true | 46 | false | +| 48 | true | 48 | true | +| 50 | false | 40 | false | +| 50 | false | 42 | true | +| 50 | false | 44 | true | +| 50 | false | 46 | false | +| 50 | false | 48 | true | +| 50 | false | 50 | false | +| 50 | true | 44 | false | +| 50 | true | 50 | true | +| 54 | false | 54 | false | +| 54 | false | 57 | true | +| 54 | true | 54 | true | +| 54 | true | 57 | false | +| 55 | false | 55 | false | +| 55 | false | 59 | false | +| 55 | true | 55 | true | +| 55 | true | 59 | true | +| 57 | false | 54 | true | +| 57 | false | 57 | false | +| 57 | true | 54 | false | +| 57 | true | 57 | true | +| 59 | false | 55 | false | +| 59 | false | 59 | false | +| 59 | true | 55 | true | +| 59 | true | 59 | true | +| 78 | false | 78 | false | +| 78 | true | 78 | true | +| 78 | true | 80 | false | +| 80 | false | 80 | false | +| 80 | true | 80 | true | +| 87 | false | 87 | false | +| 87 | true | 87 | true | +| 94 | false | 94 | false | +| 94 | true | 94 | true | diff --git a/python/ql/test/library-tests/comparisons/Implication.ql b/python/ql/test/library-tests/comparisons/Implication.ql new file mode 100644 index 00000000000..f24d1d42234 --- /dev/null +++ b/python/ql/test/library-tests/comparisons/Implication.ql @@ -0,0 +1,9 @@ + +import python +import semmle.python.Comparisons + +from Comparison a, Comparison that, boolean thisIsTrue, boolean thatIsTrue + +where a.impliesThat(thisIsTrue, that, thatIsTrue) + +select a.getLocation().getStartLine(), thisIsTrue, that.getLocation().getStartLine(), thatIsTrue \ No newline at end of file diff --git a/python/ql/test/library-tests/comparisons/options b/python/ql/test/library-tests/comparisons/options new file mode 100644 index 00000000000..3e57ce3b246 --- /dev/null +++ b/python/ql/test/library-tests/comparisons/options @@ -0,0 +1 @@ +semmle-extractor-options: --dont-split-graph diff --git a/python/ql/test/library-tests/comparisons/test.py b/python/ql/test/library-tests/comparisons/test.py new file mode 100644 index 00000000000..dc2ac175d0b --- /dev/null +++ b/python/ql/test/library-tests/comparisons/test.py @@ -0,0 +1,96 @@ + +def simple_tests(x): + if x == 4: + pass + if x != 4: + pass + if x > 4: + pass + if x < 4: + pass + if x >= 4: + pass + if x <= 4: + pass + +def f(w, x, y, z): + if x < 0 or z < 0: + raise Exception() + if x >= 0: # Useless test due to x < 0 being false + y += 1 + if z >= 0: # Useless test due to z < 0 being false + y += 1 + while w >= 0: + if y < 7: + z += 1 + if y == 15: # Useless test due to y < 10 being true + z += 1 + elif y > 10: + y -= 1 + if y < 10: + y += 1 + if y < 12: #A useless test, but too complex to infer. + pass + if (not + y != 5 and + z > 0): + w = 0 if y < 3 else 1 #Useless test as y is 5 + +def simple_tests2(x, y): + if x == y+4: + pass + if x != y+4: + pass + if x > y+4: + pass + if x < y+4: + pass + if x >= y+4: + pass + if x <= y+4: + pass + +def g(w, x, y, z): + if (w < x or + y < z+2): + raise Exception() + if w >= x: # Useless test due to w < x being false + pass + if z > y-2: # Useless test due to y < z+2 being false + y += 1 + +#Complex things we can't analyse +def h(a,b,c,d): + if a < b - g(c): + pass + if a(c) < b(d): + pass + if a < 10 + b + c: + pass + if a > 20 - g(c): + pass + if a + 10 > g(c): + pass + + +#ODASA-5643 +def validate_series(start, end): + if end < start: + raise error() + if start == end: + raise error() + return start, end + +def big1(x, y): + if x + 10000000000000000 > y + 10000000000000001: + return + if x > y: + # Redundant (but cannot be sure due to FP rounding errors) + pass + +def big2(x, y): + if x + 10000000000000000 > y + 10000000000000001: + return + if x > y: + # Not redundant (but might appear to be due to FP rounding errors) + pass diff --git a/python/ql/test/library-tests/comprehensions/AST.expected b/python/ql/test/library-tests/comprehensions/AST.expected new file mode 100644 index 00000000000..0ec20fcb99a --- /dev/null +++ b/python/ql/test/library-tests/comprehensions/AST.expected @@ -0,0 +1,50 @@ +| 2 | test.py:2:1:5:1 | .0 | 2 | test.py:2:1:5:1 | For | +| 2 | test.py:2:1:5:1 | .0 | 2 | test.py:2:1:5:1 | Function listcomp | +| 2 | test.py:2:1:5:1 | ExprStmt | 0 | test.py:0:0:0:0 | Module test | +| 2 | test.py:2:1:5:1 | For | 2 | test.py:2:1:5:1 | For | +| 2 | test.py:2:1:5:1 | For | 2 | test.py:2:1:5:1 | Function listcomp | +| 2 | test.py:2:1:5:1 | Function listcomp | 2 | test.py:2:1:5:1 | ListComp | +| 2 | test.py:2:1:5:1 | ListComp | 2 | test.py:2:1:5:1 | ExprStmt | +| 2 | test.py:2:5:2:5 | i | 2 | test.py:2:5:2:7 | BinaryExpr | +| 2 | test.py:2:5:2:7 | BinaryExpr | 2 | test.py:2:5:2:7 | Yield | +| 2 | test.py:2:5:2:7 | ExprStmt | 2 | test.py:2:1:5:1 | For | +| 2 | test.py:2:5:2:7 | Yield | 2 | test.py:2:5:2:7 | ExprStmt | +| 2 | test.py:2:7:2:7 | j | 2 | test.py:2:5:2:7 | BinaryExpr | +| 3 | test.py:3:9:3:9 | i | 2 | test.py:2:1:5:1 | For | +| 3 | test.py:3:14:3:18 | range | 3 | test.py:3:14:3:21 | range() | +| 3 | test.py:3:14:3:21 | range() | 2 | test.py:2:1:5:1 | ListComp | +| 3 | test.py:3:20:3:20 | IntegerLiteral | 3 | test.py:3:14:3:21 | range() | +| 4 | test.py:4:9:4:9 | j | 2 | test.py:2:1:5:1 | For | +| 4 | test.py:4:14:4:18 | range | 4 | test.py:4:14:4:21 | range() | +| 4 | test.py:4:14:4:21 | range() | 2 | test.py:2:1:5:1 | For | +| 4 | test.py:4:20:4:20 | IntegerLiteral | 4 | test.py:4:14:4:21 | range() | +| 7 | test.py:7:1:9:1 | .0 | 7 | test.py:7:1:9:1 | For | +| 7 | test.py:7:1:9:1 | .0 | 7 | test.py:7:1:9:1 | Function setcomp | +| 7 | test.py:7:1:9:1 | ExprStmt | 0 | test.py:0:0:0:0 | Module test | +| 7 | test.py:7:1:9:1 | For | 7 | test.py:7:1:9:1 | Function setcomp | +| 7 | test.py:7:1:9:1 | Function setcomp | 7 | test.py:7:1:9:1 | SetComp | +| 7 | test.py:7:1:9:1 | SetComp | 7 | test.py:7:1:9:1 | ExprStmt | +| 8 | test.py:8:5:8:5 | x | 8 | test.py:8:5:8:9 | BinaryExpr | +| 8 | test.py:8:5:8:9 | BinaryExpr | 8 | test.py:8:5:8:9 | Yield | +| 8 | test.py:8:5:8:9 | ExprStmt | 7 | test.py:7:1:9:1 | For | +| 8 | test.py:8:5:8:9 | Yield | 8 | test.py:8:5:8:9 | ExprStmt | +| 8 | test.py:8:9:8:9 | x | 8 | test.py:8:5:8:9 | BinaryExpr | +| 8 | test.py:8:15:8:15 | x | 7 | test.py:7:1:9:1 | For | +| 8 | test.py:8:20:8:22 | seq | 7 | test.py:7:1:9:1 | SetComp | +| 11 | test.py:11:1:15:1 | .0 | 11 | test.py:11:1:15:1 | For | +| 11 | test.py:11:1:15:1 | .0 | 11 | test.py:11:1:15:1 | Function dictcomp | +| 11 | test.py:11:1:15:1 | DictComp | 11 | test.py:11:1:15:1 | ExprStmt | +| 11 | test.py:11:1:15:1 | ExprStmt | 0 | test.py:0:0:0:0 | Module test | +| 11 | test.py:11:1:15:1 | For | 11 | test.py:11:1:15:1 | Function dictcomp | +| 11 | test.py:11:1:15:1 | Function dictcomp | 11 | test.py:11:1:15:1 | DictComp | +| 12 | test.py:12:5:12:5 | y | 12 | test.py:12:5:12:10 | Attribute | +| 12 | test.py:12:5:12:10 | Attribute | 12 | test.py:12:5:12:16 | Tuple | +| 12 | test.py:12:5:12:16 | ExprStmt | 11 | test.py:11:1:15:1 | For | +| 12 | test.py:12:5:12:16 | Tuple | 12 | test.py:12:5:12:16 | Yield | +| 12 | test.py:12:5:12:16 | Yield | 12 | test.py:12:5:12:16 | ExprStmt | +| 12 | test.py:12:14:12:14 | z | 12 | test.py:12:14:12:16 | z() | +| 12 | test.py:12:14:12:16 | z() | 12 | test.py:12:5:12:16 | Tuple | +| 13 | test.py:13:9:13:9 | y | 13 | test.py:13:9:13:12 | Tuple | +| 13 | test.py:13:9:13:12 | Tuple | 11 | test.py:11:1:15:1 | For | +| 13 | test.py:13:12:13:12 | z | 13 | test.py:13:9:13:12 | Tuple | +| 14 | test.py:14:5:14:11 | mapping | 11 | test.py:11:1:15:1 | DictComp | diff --git a/python/ql/test/library-tests/comprehensions/AST.ql b/python/ql/test/library-tests/comprehensions/AST.ql new file mode 100644 index 00000000000..a0063daf0a6 --- /dev/null +++ b/python/ql/test/library-tests/comprehensions/AST.ql @@ -0,0 +1,5 @@ +import python + +from AstNode child, AstNode parent +where child.getParentNode() = parent +select child.getLocation().getStartLine(), child, parent.getLocation().getStartLine(), parent diff --git a/python/ql/test/library-tests/comprehensions/Flow.expected b/python/ql/test/library-tests/comprehensions/Flow.expected new file mode 100644 index 00000000000..efcf64bfb9f --- /dev/null +++ b/python/ql/test/library-tests/comprehensions/Flow.expected @@ -0,0 +1,48 @@ +| 0 | Entry node for Module test | 3 | ControlFlowNode for range | +| 2 | ControlFlowNode for .0 | 2 | ControlFlowNode for .0 | +| 2 | ControlFlowNode for .0 | 2 | ControlFlowNode for For | +| 2 | ControlFlowNode for BinaryExpr | 2 | ControlFlowNode for Yield | +| 2 | ControlFlowNode for For | 2 | ControlFlowNode for For | +| 2 | ControlFlowNode for For | 2 | Exit node for Function listcomp | +| 2 | ControlFlowNode for For | 3 | ControlFlowNode for i | +| 2 | ControlFlowNode for For | 4 | ControlFlowNode for j | +| 2 | ControlFlowNode for ListComp | 8 | ControlFlowNode for seq | +| 2 | ControlFlowNode for Yield | 2 | ControlFlowNode for For | +| 2 | ControlFlowNode for i | 2 | ControlFlowNode for j | +| 2 | ControlFlowNode for j | 2 | ControlFlowNode for BinaryExpr | +| 2 | Entry node for Function listcomp | 2 | ControlFlowNode for .0 | +| 3 | ControlFlowNode for IntegerLiteral | 3 | ControlFlowNode for range() | +| 3 | ControlFlowNode for i | 4 | ControlFlowNode for range | +| 3 | ControlFlowNode for range | 3 | ControlFlowNode for IntegerLiteral | +| 3 | ControlFlowNode for range() | 2 | ControlFlowNode for ListComp | +| 4 | ControlFlowNode for IntegerLiteral | 4 | ControlFlowNode for range() | +| 4 | ControlFlowNode for j | 2 | ControlFlowNode for i | +| 4 | ControlFlowNode for range | 4 | ControlFlowNode for IntegerLiteral | +| 4 | ControlFlowNode for range() | 2 | ControlFlowNode for For | +| 7 | ControlFlowNode for .0 | 7 | ControlFlowNode for .0 | +| 7 | ControlFlowNode for .0 | 7 | ControlFlowNode for For | +| 7 | ControlFlowNode for For | 7 | Exit node for Function setcomp | +| 7 | ControlFlowNode for For | 8 | ControlFlowNode for x | +| 7 | ControlFlowNode for SetComp | 14 | ControlFlowNode for mapping | +| 7 | Entry node for Function setcomp | 7 | ControlFlowNode for .0 | +| 8 | ControlFlowNode for BinaryExpr | 8 | ControlFlowNode for Yield | +| 8 | ControlFlowNode for Yield | 7 | ControlFlowNode for For | +| 8 | ControlFlowNode for seq | 7 | ControlFlowNode for SetComp | +| 8 | ControlFlowNode for x | 8 | ControlFlowNode for BinaryExpr | +| 8 | ControlFlowNode for x | 8 | ControlFlowNode for x | +| 11 | ControlFlowNode for .0 | 11 | ControlFlowNode for .0 | +| 11 | ControlFlowNode for .0 | 11 | ControlFlowNode for For | +| 11 | ControlFlowNode for DictComp | 0 | Exit node for Module test | +| 11 | ControlFlowNode for For | 11 | Exit node for Function dictcomp | +| 11 | ControlFlowNode for For | 13 | ControlFlowNode for Tuple | +| 11 | Entry node for Function dictcomp | 11 | ControlFlowNode for .0 | +| 12 | ControlFlowNode for Attribute | 12 | ControlFlowNode for Tuple | +| 12 | ControlFlowNode for Tuple | 12 | ControlFlowNode for Yield | +| 12 | ControlFlowNode for Yield | 11 | ControlFlowNode for For | +| 12 | ControlFlowNode for y | 12 | ControlFlowNode for Attribute | +| 12 | ControlFlowNode for z | 12 | ControlFlowNode for z() | +| 12 | ControlFlowNode for z() | 12 | ControlFlowNode for y | +| 13 | ControlFlowNode for Tuple | 13 | ControlFlowNode for y | +| 13 | ControlFlowNode for y | 13 | ControlFlowNode for z | +| 13 | ControlFlowNode for z | 12 | ControlFlowNode for z | +| 14 | ControlFlowNode for mapping | 11 | ControlFlowNode for DictComp | diff --git a/python/ql/test/library-tests/comprehensions/Flow.ql b/python/ql/test/library-tests/comprehensions/Flow.ql new file mode 100644 index 00000000000..e19d4d75abe --- /dev/null +++ b/python/ql/test/library-tests/comprehensions/Flow.ql @@ -0,0 +1,5 @@ +import python + +from ControlFlowNode p, ControlFlowNode s +where p.getASuccessor() = s +select p.getLocation().getStartLine(), p.toString(), s.getLocation().getStartLine(), s.toString() \ No newline at end of file diff --git a/python/ql/test/library-tests/comprehensions/test.py b/python/ql/test/library-tests/comprehensions/test.py new file mode 100644 index 00000000000..b4504f8960d --- /dev/null +++ b/python/ql/test/library-tests/comprehensions/test.py @@ -0,0 +1,15 @@ + +[ i+j + for i in range(1) + for j in range(2) +] + +{ + x * x for x in seq +} + +{ + y.attr : z() + for y, z in + mapping +} diff --git a/python/ql/test/library-tests/dependencies/ArchitectDependencies.expected b/python/ql/test/library-tests/dependencies/ArchitectDependencies.expected new file mode 100644 index 00000000000..2bb7df4b7de --- /dev/null +++ b/python/ql/test/library-tests/dependencies/ArchitectDependencies.expected @@ -0,0 +1,10 @@ +| standard/python/attribute | Module a | Class B | Attribute | +| standard/python/attribute | Module b | Class C | Attribute | +| standard/python/import | Module a | Module b | Import | +| standard/python/import | Module b | Module c | Import | +| standard/python/import | Module c | Module b | Import | +| standard/python/inheritance | Class A | Class B | ClassExpr | +| standard/python/inheritance | Class A | Class C | ClassExpr | +| standard/python/inheritance | Class B | Class C | ClassExpr | +| standard/python/use | Module a | Class B | Attribute | +| standard/python/use | Module b | Class C | Attribute | diff --git a/python/ql/test/library-tests/dependencies/ArchitectDependencies.ql b/python/ql/test/library-tests/dependencies/ArchitectDependencies.ql new file mode 100644 index 00000000000..ce33d7c7acd --- /dev/null +++ b/python/ql/test/library-tests/dependencies/ArchitectDependencies.ql @@ -0,0 +1,9 @@ + +import python +import Architect.Common.DependencyCategory +import Architect.Architect + +from DependencyCategory dk, DependencyElement source, DependencyElement target, DependencyElement cause +where dk.isADependency(source, target, cause) +select dk.toString(), source.toString(), target.toString(), cause.toString() + diff --git a/python/ql/test/library-tests/dependencies/Categories.expected b/python/ql/test/library-tests/dependencies/Categories.expected new file mode 100644 index 00000000000..9cfbbe102a8 --- /dev/null +++ b/python/ql/test/library-tests/dependencies/Categories.expected @@ -0,0 +1,4 @@ +| standard/python/attribute | +| standard/python/import | +| standard/python/inheritance | +| standard/python/use | diff --git a/python/ql/test/library-tests/dependencies/Categories.ql b/python/ql/test/library-tests/dependencies/Categories.ql new file mode 100644 index 00000000000..6866ab072ca --- /dev/null +++ b/python/ql/test/library-tests/dependencies/Categories.ql @@ -0,0 +1,13 @@ +/** + * @name Categories + * @description Insert description here... + * @kind problem + * @problem.severity warning + */ + +import python +import Architect.Common.DependencyCategory +import Architect.Architect + +from DependencyCategory dk +select dk diff --git a/python/ql/test/library-tests/dependencies/Dependencies.expected b/python/ql/test/library-tests/dependencies/Dependencies.expected new file mode 100644 index 00000000000..90839fffe55 --- /dev/null +++ b/python/ql/test/library-tests/dependencies/Dependencies.expected @@ -0,0 +1,16 @@ +| attribute | a.py | 3 | Attribute | class B | +| attribute | b.py | 3 | Attribute | class C | +| import | a.py | 1 | Import | Module b | +| import | b.py | 1 | Import | Module c | +| import | c.py | 1 | Import | Module b | +| inheritance | a.py | 3 | ClassExpr | builtin-class object | +| inheritance | a.py | 3 | ClassExpr | builtin-class type | +| inheritance | a.py | 3 | ClassExpr | class B | +| inheritance | a.py | 3 | ClassExpr | class C | +| inheritance | b.py | 3 | ClassExpr | builtin-class object | +| inheritance | b.py | 3 | ClassExpr | builtin-class type | +| inheritance | b.py | 3 | ClassExpr | class C | +| inheritance | c.py | 3 | ClassExpr | builtin-class object | +| inheritance | c.py | 3 | ClassExpr | builtin-class type | +| use | a.py | 3 | Attribute | class B | +| use | b.py | 3 | Attribute | class C | diff --git a/python/ql/test/library-tests/dependencies/Dependencies.ql b/python/ql/test/library-tests/dependencies/Dependencies.ql new file mode 100644 index 00000000000..b5bedbe7b3c --- /dev/null +++ b/python/ql/test/library-tests/dependencies/Dependencies.ql @@ -0,0 +1,8 @@ + +import python +import semmle.python.dependencies.Dependencies + +from DependencyKind dk, AstNode src, Object target +where dk.isADependency(src, target) +select dk.toString(), src.getLocation().getFile().getShortName(), src.getLocation().getStartLine(), src.toString(), target.toString() + diff --git a/python/ql/test/library-tests/dependencies/a.py b/python/ql/test/library-tests/dependencies/a.py new file mode 100644 index 00000000000..b174bff58ca --- /dev/null +++ b/python/ql/test/library-tests/dependencies/a.py @@ -0,0 +1,4 @@ +import b + +class A(b.B): + pass diff --git a/python/ql/test/library-tests/dependencies/b.py b/python/ql/test/library-tests/dependencies/b.py new file mode 100644 index 00000000000..24586e4ddc6 --- /dev/null +++ b/python/ql/test/library-tests/dependencies/b.py @@ -0,0 +1,4 @@ +import c + +class B(c.C): + pass diff --git a/python/ql/test/library-tests/dependencies/c.py b/python/ql/test/library-tests/dependencies/c.py new file mode 100644 index 00000000000..2ba0664a5b5 --- /dev/null +++ b/python/ql/test/library-tests/dependencies/c.py @@ -0,0 +1,5 @@ +import b + +class C(object): + def foo(self): + b = B() diff --git a/python/ql/test/library-tests/descriptors/Descriptors.expected b/python/ql/test/library-tests/descriptors/Descriptors.expected new file mode 100644 index 00000000000..1c9d4436a94 --- /dev/null +++ b/python/ql/test/library-tests/descriptors/Descriptors.expected @@ -0,0 +1,10 @@ +| builtin-class classmethod | non-overriding | +| builtin-class classmethod_descriptor | non-overriding | +| builtin-class function | non-overriding | +| builtin-class getset_descriptor | overriding | +| builtin-class member_descriptor | overriding | +| builtin-class method_descriptor | non-overriding | +| builtin-class property | overriding | +| builtin-class staticmethod | non-overriding | +| builtin-class super | non-overriding | +| builtin-class wrapper_descriptor | non-overriding | diff --git a/python/ql/test/library-tests/descriptors/Descriptors.ql b/python/ql/test/library-tests/descriptors/Descriptors.ql new file mode 100644 index 00000000000..658091bfe4e --- /dev/null +++ b/python/ql/test/library-tests/descriptors/Descriptors.ql @@ -0,0 +1,13 @@ + +import python + +from ClassObject cls, string kind +where cls.isDescriptorType() and +/* Exclude bound-method as its name differs between 2 and 3 */ +not cls = theBoundMethodType() and +(if cls.isOverridingDescriptorType() then + kind = "overriding" + else + kind = "non-overriding" +) +select cls.toString(), kind \ No newline at end of file diff --git a/python/ql/test/library-tests/descriptors/Methods.expected b/python/ql/test/library-tests/descriptors/Methods.expected new file mode 100644 index 00000000000..efd066e8b4c --- /dev/null +++ b/python/ql/test/library-tests/descriptors/Methods.expected @@ -0,0 +1,6 @@ +| 16 | classmethod() | 17 | Function c1 | +| 23 | classmethod() | 20 | Function c2 | +| 24 | classmethod() | 20 | Function c2 | +| 26 | staticmethod() | 27 | Function s1 | +| 33 | staticmethod() | 30 | Function s2 | +| 34 | staticmethod() | 30 | Function s2 | \ No newline at end of file diff --git a/python/ql/test/library-tests/descriptors/Methods.ql b/python/ql/test/library-tests/descriptors/Methods.ql new file mode 100644 index 00000000000..75d3092198d --- /dev/null +++ b/python/ql/test/library-tests/descriptors/Methods.ql @@ -0,0 +1,15 @@ + +import python +import semmle.python.types.Descriptors + +int lineof(Object o) { + result = o.getOrigin().getLocation().getStartLine() +} + +from Object m, FunctionObject f +where + m.(ClassMethodObject).getFunction() = f + or + m.(StaticMethodObject).getFunction() = f +select lineof(m), m.toString(), lineof(f), f.toString() + diff --git a/python/ql/test/library-tests/descriptors/Properties.expected b/python/ql/test/library-tests/descriptors/Properties.expected new file mode 100644 index 00000000000..3eb736d618b --- /dev/null +++ b/python/ql/test/library-tests/descriptors/Properties.expected @@ -0,0 +1 @@ +| 6 | Property f | 7 | Function f | 11 | Function f | diff --git a/python/ql/test/library-tests/descriptors/Properties.ql b/python/ql/test/library-tests/descriptors/Properties.ql new file mode 100644 index 00000000000..e27ca6beb3c --- /dev/null +++ b/python/ql/test/library-tests/descriptors/Properties.ql @@ -0,0 +1,13 @@ + +import python +import semmle.python.types.Descriptors + +int lineof(Object o) { + result = o.getOrigin().getLocation().getStartLine() +} + +from PropertyObject p, FunctionObject getter, FunctionObject setter +where +getter = p.getGetter() and setter = p.getSetter() +select lineof(p), p.toString(), lineof(getter), getter.toString(), lineof(setter), setter.toString() + diff --git a/python/ql/test/library-tests/descriptors/test.py b/python/ql/test/library-tests/descriptors/test.py new file mode 100644 index 00000000000..8d7f14198c7 --- /dev/null +++ b/python/ql/test/library-tests/descriptors/test.py @@ -0,0 +1,34 @@ + + + +class C(object): + + @property + def f(self): + return self._f + + @f.setter + def f(self): + return self._f + +class D(object): + + @classmethod + def c1(self): + pass + + def c2(self): + pass + + c3 = classmethod(c2) + c2 = classmethod(c2) + + @staticmethod + def s1(self): + pass + + def s2(self): + pass + + s3 = staticmethod(s2) + s2 = staticmethod(s2) diff --git a/python/ql/test/library-tests/encoding/CheckEncoding.expected b/python/ql/test/library-tests/encoding/CheckEncoding.expected new file mode 100644 index 00000000000..686ad385436 --- /dev/null +++ b/python/ql/test/library-tests/encoding/CheckEncoding.expected @@ -0,0 +1,4 @@ +| latin.py | latin1 | +| shift_jis.py | shift-jis | +| utf8.py | utf-8 | +| utf8_bom.py | none | diff --git a/python/ql/test/library-tests/encoding/CheckEncoding.ql b/python/ql/test/library-tests/encoding/CheckEncoding.ql new file mode 100644 index 00000000000..2b0af6ee84a --- /dev/null +++ b/python/ql/test/library-tests/encoding/CheckEncoding.ql @@ -0,0 +1,8 @@ +import python + +from File f, string encoding +where +encoding = f.getSpecifiedEncoding() +or +not exists(f.getSpecifiedEncoding()) and encoding = "none" +select f.getName(), encoding diff --git a/python/ql/test/library-tests/encoding/latin.py b/python/ql/test/library-tests/encoding/latin.py new file mode 100644 index 00000000000..538a7b90e93 --- /dev/null +++ b/python/ql/test/library-tests/encoding/latin.py @@ -0,0 +1,4 @@ +"Any old stuff can go here" +# -*- coding: latin1 -*- +# Günter + diff --git a/python/ql/test/library-tests/encoding/shift_jis.py b/python/ql/test/library-tests/encoding/shift_jis.py new file mode 100644 index 00000000000..89b7b91fd8c --- /dev/null +++ b/python/ql/test/library-tests/encoding/shift_jis.py @@ -0,0 +1,11 @@ +# encoding:shift-jis + +#This is copied from the Python test library copyright PSF. + +""" +Python ‚ÌŠJ”­‚ÍA1990 ”N‚²‚ë‚©‚çŠJŽn‚³‚ê‚Ä‚¢‚Ü‚·B +ŠJ”­ŽÒ‚Ì Guido van Rossum ‚Í‹³ˆç—p‚̃vƒƒOƒ‰ƒ~ƒ“ƒOŒ¾ŒêuABCv‚ÌŠJ”­‚ÉŽQ‰Á‚µ‚Ä‚¢‚Ü‚µ‚½‚ªAABC ‚ÍŽÀ—pã‚Ì–Ú“I‚ɂ͂ ‚Ü‚è“K‚µ‚Ä‚¢‚Ü‚¹‚ñ‚Å‚µ‚½B +‚±‚̂悤‚È”wŒi‚©‚綂܂ꂽ Python ‚ÌŒ¾ŒêÝŒv‚ÍAuƒVƒ“ƒvƒ‹v‚ÅuK“¾‚ª—eˆÕv‚Æ‚¢‚¤–Ú•W‚Éd“_‚ª’u‚©‚ê‚Ä‚¢‚Ü‚·B +‘½‚­‚̃XƒNƒŠƒvƒgŒnŒ¾Œê‚ł̓†[ƒU‚Ì–Úæ‚Ì—˜•Ö«‚ð—D悵‚ÄFX‚È‹@”\‚ðŒ¾Œê—v‘f‚Æ‚µ‚ÄŽæ‚è“ü‚ê‚éꇂª‘½‚¢‚̂ł·‚ªAPython ‚ł͂»‚¤‚¢‚Á‚½¬×H‚ª’ljÁ‚³‚ê‚邱‚Ƃ͂ ‚܂肠‚è‚Ü‚¹‚ñB +Œ¾ŒêŽ©‘̂̋@”\‚ÍŬŒÀ‚ɉŸ‚³‚¦A•K—v‚È‹@”\‚ÍŠg’£ƒ‚ƒWƒ…[ƒ‹‚Æ‚µ‚ĒljÁ‚·‚éA‚Æ‚¢‚¤‚Ì‚ª Python ‚̃|ƒŠƒV[‚Å‚·B +""" diff --git a/python/ql/test/library-tests/encoding/utf8.py b/python/ql/test/library-tests/encoding/utf8.py new file mode 100644 index 00000000000..f440c6944d9 --- /dev/null +++ b/python/ql/test/library-tests/encoding/utf8.py @@ -0,0 +1,2 @@ +# Some abitrary prefix with no space beforecoding: utf-8 -*- +# €€€€ diff --git a/python/ql/test/library-tests/encoding/utf8_bom.py b/python/ql/test/library-tests/encoding/utf8_bom.py new file mode 100644 index 00000000000..509f44c690e --- /dev/null +++ b/python/ql/test/library-tests/encoding/utf8_bom.py @@ -0,0 +1 @@ +#Starts with a BOM diff --git a/python/ql/test/library-tests/exceptions/Handles.expected b/python/ql/test/library-tests/exceptions/Handles.expected new file mode 100644 index 00000000000..d3f408de146 --- /dev/null +++ b/python/ql/test/library-tests/exceptions/Handles.expected @@ -0,0 +1,10 @@ +| 37 | ControlFlowNode for ExceptStmt | class Exception3 | +| 39 | ControlFlowNode for ExceptStmt | class Exception2 | +| 41 | ControlFlowNode for ExceptStmt | class Exception1 | +| 43 | ControlFlowNode for ExceptStmt | class NotException2 | +| 47 | ControlFlowNode for ExceptStmt | builtin-class BaseException | +| 58 | ControlFlowNode for ExceptStmt | class Exception3 | +| 60 | ControlFlowNode for ExceptStmt | class NotException2 | +| 62 | ControlFlowNode for ExceptStmt | class InnerException5 | +| 68 | ControlFlowNode for ExceptStmt | builtin-class IndexError | +| 70 | ControlFlowNode for ExceptStmt | class Exception1 | diff --git a/python/ql/test/library-tests/exceptions/Handles.ql b/python/ql/test/library-tests/exceptions/Handles.ql new file mode 100644 index 00000000000..b3e9f792744 --- /dev/null +++ b/python/ql/test/library-tests/exceptions/Handles.ql @@ -0,0 +1,5 @@ +import python + +from ExceptFlowNode ex, Object t +where ex.handledException(t, _, _) +select ex.getLocation().getStartLine(), ex.toString(), t.toString() \ No newline at end of file diff --git a/python/ql/test/library-tests/exceptions/Legal.expected b/python/ql/test/library-tests/exceptions/Legal.expected new file mode 100644 index 00000000000..1b6fd6ec1c4 --- /dev/null +++ b/python/ql/test/library-tests/exceptions/Legal.expected @@ -0,0 +1,12 @@ +| class Exception1 | yes | +| class Exception2 | yes | +| class Exception3 | yes | +| class InnerException1 | yes | +| class InnerException2 | yes | +| class InnerException3 | yes | +| class InnerException4 | yes | +| class InnerException5 | yes | +| class InnerNotException1 | no | +| class InnerNotException2 | no | +| class NotException1 | no | +| class NotException2 | no | \ No newline at end of file diff --git a/python/ql/test/library-tests/exceptions/Legal.ql b/python/ql/test/library-tests/exceptions/Legal.ql new file mode 100644 index 00000000000..37488eb082b --- /dev/null +++ b/python/ql/test/library-tests/exceptions/Legal.ql @@ -0,0 +1,11 @@ +import python + +from ClassObject cls, string legal +where +not cls.isC() and cls.isLegalExceptionType() and legal = "yes" and not cls.failedInference() +or +not cls.isC() and not cls.isLegalExceptionType() and legal = "no" and not cls.failedInference() +or +not cls.isC() and cls.failedInference(legal) + +select cls.toString(), legal diff --git a/python/ql/test/library-tests/exceptions/test.py b/python/ql/test/library-tests/exceptions/test.py new file mode 100644 index 00000000000..bb708a2954e --- /dev/null +++ b/python/ql/test/library-tests/exceptions/test.py @@ -0,0 +1,71 @@ + +class NotException1(object): + pass + +class NotException2(object): + pass + + +class Exception1(BaseException): + pass + +class Exception2(KeyError): + pass + +class Exception3(Exception2): + pass + +def f(): + class InnerNotException1(object): + pass + + class InnerNotException2(object): + pass + + + class InnerException1(BaseException): + pass + + class InnerException2(KeyError): + pass + + class InnerException3(Exception2): + pass + +try: + some_call() +except Exception3: + pass +except Exception2: + pass +except Exception1: + pass +except NotException2: + pass +except UndefinedSymbol: + pass +except: + pass + + +def g(): + class InnerException4(Exception): + pass + class InnerException5(InnerException4): + pass + try: + some_call() + except Exception3: + pass + except NotException2: + pass + except InnerException5: + pass + +def h(seq): + try: + [x[0] for x in seq] + except IndexError: + pass + except Exception1: + pass diff --git a/python/ql/test/library-tests/exprs/AstParent.expected b/python/ql/test/library-tests/exprs/AstParent.expected new file mode 100644 index 00000000000..f082a67fcf6 --- /dev/null +++ b/python/ql/test/library-tests/exprs/AstParent.expected @@ -0,0 +1 @@ +| 0 | diff --git a/python/ql/test/library-tests/exprs/AstParent.ql b/python/ql/test/library-tests/exprs/AstParent.ql new file mode 100644 index 00000000000..3e26f672360 --- /dev/null +++ b/python/ql/test/library-tests/exprs/AstParent.ql @@ -0,0 +1,6 @@ +import python + +select +count(AstNode c | not exists(c.getParentNode()) and not c instanceof Module) ++ +count(AstNode c | strictcount(c.getParentNode()) > 1) \ No newline at end of file diff --git a/python/ql/test/library-tests/exprs/Child.expected b/python/ql/test/library-tests/exprs/Child.expected new file mode 100644 index 00000000000..91c6e7e87d2 --- /dev/null +++ b/python/ql/test/library-tests/exprs/Child.expected @@ -0,0 +1,34 @@ +| 0 | Module exprs_test | 2 | exprs_test.py:2:1:2:1 | ExprStmt | +| 0 | Module exprs_test | 3 | exprs_test.py:3:1:3:5 | ExprStmt | +| 0 | Module exprs_test | 4 | exprs_test.py:4:1:4:6 | ExprStmt | +| 0 | Module exprs_test | 5 | exprs_test.py:5:1:5:9 | ExprStmt | +| 0 | Module exprs_test | 6 | exprs_test.py:6:1:6:5 | AssignStmt | +| 0 | Module exprs_test | 7 | exprs_test.py:7:1:7:1 | ExprStmt | +| 0 | Module exprs_test | 8 | exprs_test.py:8:1:8:12 | ExprStmt | +| 0 | Module exprs_test | 9 | exprs_test.py:9:1:9:11 | ExprStmt | +| 0 | Module exprs_test | 11 | exprs_test.py:11:1:11:11 | ExprStmt | +| 2 | ExprStmt | 2 | exprs_test.py:2:1:2:1 | IntegerLiteral | +| 3 | ExprStmt | 3 | exprs_test.py:3:2:3:4 | Tuple | +| 3 | Tuple | 3 | exprs_test.py:3:2:3:2 | IntegerLiteral | +| 3 | Tuple | 3 | exprs_test.py:3:4:3:4 | IntegerLiteral | +| 4 | ExprStmt | 4 | exprs_test.py:4:1:4:6 | List | +| 4 | List | 4 | exprs_test.py:4:2:4:2 | IntegerLiteral | +| 4 | List | 4 | exprs_test.py:4:5:4:5 | IntegerLiteral | +| 5 | ExprStmt | 5 | exprs_test.py:5:1:5:9 | __debug__ | +| 6 | AssignStmt | 6 | exprs_test.py:6:1:6:1 | x | +| 6 | AssignStmt | 6 | exprs_test.py:6:5:6:5 | IntegerLiteral | +| 7 | ExprStmt | 7 | exprs_test.py:7:1:7:1 | x | +| 8 | Attribute | 8 | exprs_test.py:8:1:8:6 | List | +| 8 | Attribute() | 8 | exprs_test.py:8:1:8:10 | Attribute | +| 8 | ExprStmt | 8 | exprs_test.py:8:1:8:12 | Attribute() | +| 8 | List | 8 | exprs_test.py:8:2:8:2 | IntegerLiteral | +| 8 | List | 8 | exprs_test.py:8:5:8:5 | IntegerLiteral | +| 9 | ExprStmt | 9 | exprs_test.py:9:1:9:11 | Subscript | +| 9 | List | 9 | exprs_test.py:9:2:9:2 | IntegerLiteral | +| 9 | List | 9 | exprs_test.py:9:5:9:6 | IntegerLiteral | +| 9 | Subscript | 9 | exprs_test.py:9:1:9:7 | List | +| 9 | Subscript | 9 | exprs_test.py:9:9:9:10 | IntegerLiteral | +| 11 | DictUnpacking | 11 | exprs_test.py:11:8:11:10 | arg | +| 11 | ExprStmt | 11 | exprs_test.py:11:1:11:11 | func() | +| 11 | func() | 11 | exprs_test.py:11:1:11:4 | func | +| 11 | func() | 11 | exprs_test.py:11:6:11:10 | DictUnpacking | diff --git a/python/ql/test/library-tests/exprs/Child.ql b/python/ql/test/library-tests/exprs/Child.ql new file mode 100644 index 00000000000..0638f6c4e22 --- /dev/null +++ b/python/ql/test/library-tests/exprs/Child.ql @@ -0,0 +1,6 @@ +import python + +from AstNode p, AstNode c +where p.getAChildNode() = c +select p.getLocation().getStartLine(), p.toString(), c.getLocation().getStartLine(), c + diff --git a/python/ql/test/library-tests/exprs/IsConstant.expected b/python/ql/test/library-tests/exprs/IsConstant.expected new file mode 100644 index 00000000000..7f61cee7a65 --- /dev/null +++ b/python/ql/test/library-tests/exprs/IsConstant.expected @@ -0,0 +1,17 @@ +| exprs_test.py:2:1:2:1 | IntegerLiteral | +| exprs_test.py:3:2:3:2 | IntegerLiteral | +| exprs_test.py:3:2:3:4 | Tuple | +| exprs_test.py:3:4:3:4 | IntegerLiteral | +| exprs_test.py:4:1:4:6 | List | +| exprs_test.py:4:2:4:2 | IntegerLiteral | +| exprs_test.py:4:5:4:5 | IntegerLiteral | +| exprs_test.py:6:5:6:5 | IntegerLiteral | +| exprs_test.py:8:1:8:6 | List | +| exprs_test.py:8:1:8:10 | Attribute | +| exprs_test.py:8:2:8:2 | IntegerLiteral | +| exprs_test.py:8:5:8:5 | IntegerLiteral | +| exprs_test.py:9:1:9:7 | List | +| exprs_test.py:9:1:9:11 | Subscript | +| exprs_test.py:9:2:9:2 | IntegerLiteral | +| exprs_test.py:9:5:9:6 | IntegerLiteral | +| exprs_test.py:9:9:9:10 | IntegerLiteral | diff --git a/python/ql/test/library-tests/exprs/IsConstant.ql b/python/ql/test/library-tests/exprs/IsConstant.ql new file mode 100644 index 00000000000..ecef17eb385 --- /dev/null +++ b/python/ql/test/library-tests/exprs/IsConstant.ql @@ -0,0 +1,5 @@ +import python + +from Expr e +where e.isConstant() +select e diff --git a/python/ql/test/library-tests/exprs/exprs_test.py b/python/ql/test/library-tests/exprs/exprs_test.py new file mode 100644 index 00000000000..b7f41ca1e27 --- /dev/null +++ b/python/ql/test/library-tests/exprs/exprs_test.py @@ -0,0 +1,11 @@ + +1 +(2,3) +[4, 5] +__debug__ +x = 6 +x +[7, 8].len() +[9, 10][11] + +func(**arg) diff --git a/python/ql/test/library-tests/filters/generated/Filter.expected b/python/ql/test/library-tests/filters/generated/Filter.expected new file mode 100644 index 00000000000..3ddcffc3d94 --- /dev/null +++ b/python/ql/test/library-tests/filters/generated/Filter.expected @@ -0,0 +1,4 @@ +| generic.py | tools/idna-data | +| sphinx.py | Sphinx | +| swig.py | SWIG | +| thrift.py | Thrift | diff --git a/python/ql/test/library-tests/filters/generated/Filter.ql b/python/ql/test/library-tests/filters/generated/Filter.ql new file mode 100644 index 00000000000..d741328d6f7 --- /dev/null +++ b/python/ql/test/library-tests/filters/generated/Filter.ql @@ -0,0 +1,6 @@ + +import python +import semmle.python.filters.GeneratedCode + +from GeneratedFile f +select f.toString(), f.getTool() diff --git a/python/ql/test/library-tests/filters/generated/generic.py b/python/ql/test/library-tests/filters/generated/generic.py new file mode 100644 index 00000000000..5cdde9b8890 --- /dev/null +++ b/python/ql/test/library-tests/filters/generated/generic.py @@ -0,0 +1 @@ +# This file is automatically generated by tools/idna-data diff --git a/python/ql/test/library-tests/filters/generated/sphinx.py b/python/ql/test/library-tests/filters/generated/sphinx.py new file mode 100644 index 00000000000..8e80f7914e3 --- /dev/null +++ b/python/ql/test/library-tests/filters/generated/sphinx.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- +# Autogenerated by Sphinx on Mon May 16 13:41:38 2016 +topics = {'assert': '\n' } diff --git a/python/ql/test/library-tests/filters/generated/swig.py b/python/ql/test/library-tests/filters/generated/swig.py new file mode 100644 index 00000000000..a8621334476 --- /dev/null +++ b/python/ql/test/library-tests/filters/generated/swig.py @@ -0,0 +1,6 @@ +# This file was automatically generated by SWIG (http://www.swig.org). +# Version 2.0.9 +# +# Do not make changes to this file unless you know what you are doing--modify +# the SWIG interface file instead. + diff --git a/python/ql/test/library-tests/filters/generated/thrift.py b/python/ql/test/library-tests/filters/generated/thrift.py new file mode 100644 index 00000000000..36b7e9e103a --- /dev/null +++ b/python/ql/test/library-tests/filters/generated/thrift.py @@ -0,0 +1,7 @@ +# +# Autogenerated by Thrift Compiler (0.9.1) +# +# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING +# +# options string: py:utf8strings +# diff --git a/python/ql/test/library-tests/filters/tests/Filter.expected b/python/ql/test/library-tests/filters/tests/Filter.expected new file mode 100644 index 00000000000..7e2143c9ac4 --- /dev/null +++ b/python/ql/test/library-tests/filters/tests/Filter.expected @@ -0,0 +1,3 @@ +| Class MyTest | +| Function test_1 | +| Function test_2 | diff --git a/python/ql/test/library-tests/filters/tests/Filter.ql b/python/ql/test/library-tests/filters/tests/Filter.ql new file mode 100644 index 00000000000..e20231ea5fa --- /dev/null +++ b/python/ql/test/library-tests/filters/tests/Filter.ql @@ -0,0 +1,6 @@ + +import python +import semmle.python.filters.Tests + +from TestScope t +select t.toString() diff --git a/python/ql/test/library-tests/filters/tests/test.py b/python/ql/test/library-tests/filters/tests/test.py new file mode 100644 index 00000000000..cfcdc56ba64 --- /dev/null +++ b/python/ql/test/library-tests/filters/tests/test.py @@ -0,0 +1,12 @@ + + +class TestCase: + pass + +class MyTest(TestCase): + + def test_1(self): + pass + + def test_2(self): + pass diff --git a/python/ql/test/library-tests/formatting/FormatArguments.expected b/python/ql/test/library-tests/formatting/FormatArguments.expected new file mode 100755 index 00000000000..0a76d0c9923 --- /dev/null +++ b/python/ql/test/library-tests/formatting/FormatArguments.expected @@ -0,0 +1,24 @@ +| 3 | {name!r}, {0} | 0 | 8 | 'name' | +| 3 | {name!r}, {0} | 10 | 13 | 0 | +| 4 | {0}, {1} | 0 | 3 | 0 | +| 4 | {0}, {1} | 5 | 8 | 1 | +| 5 | {}, {} | 0 | 2 | 0 | +| 5 | {}, {} | 4 | 6 | 1 | +| 8 | {{}}> | 10 | 12 | 0 | +| 10 | {{0}}{0} | 5 | 8 | 0 | +| 11 | {{{}}} | 2 | 4 | 0 | +| 13 | { {{ 0} }} | 0 | 7 | ' {{ 0' | +| 14 | { { { 0} }} | 4 | 8 | ' 0' | +| 15 | {{{{{} | 4 | 6 | 0 | +| 16 | {}\r{}{:<{width}} | 0 | 2 | 0 | +| 16 | {}\r{}{:<{width}} | 3 | 5 | 1 | +| 16 | {}\r{}{:<{width}} | 5 | 16 | 2 | +| 16 | {}\r{}{:<{width}} | 8 | 15 | 'width' | +| 17 | {}\r{}{:<{}} | 0 | 2 | 0 | +| 17 | {}\r{}{:<{}} | 3 | 5 | 1 | +| 17 | {}\r{}{:<{}} | 5 | 11 | 2 | +| 17 | {}\r{}{:<{}} | 8 | 10 | 3 | +| 19 | {x:0.{decimals}f} | 0 | 17 | 'x' | +| 19 | {x:0.{decimals}f} | 5 | 15 | 'decimals' | +| 21 | invalid value of type {.__name__}: {} | 22 | 33 | 0 | +| 21 | invalid value of type {.__name__}: {} | 35 | 37 | 1 | diff --git a/python/ql/test/library-tests/formatting/FormatArguments.ql b/python/ql/test/library-tests/formatting/FormatArguments.ql new file mode 100644 index 00000000000..19e47b7fc44 --- /dev/null +++ b/python/ql/test/library-tests/formatting/FormatArguments.ql @@ -0,0 +1,10 @@ + +import python +import Expressions.Formatting.AdvancedFormatting + +from AdvancedFormatString a, string name, int start, int end +where +name = "'" + a.getFieldName(start, end) + "'" +or +name = a.getFieldNumber(start, end).toString() +select a.getLocation().getStartLine(), a.getText(), start, end, name diff --git a/python/ql/test/library-tests/formatting/FormatFields.expected b/python/ql/test/library-tests/formatting/FormatFields.expected new file mode 100755 index 00000000000..a3ff555b02f --- /dev/null +++ b/python/ql/test/library-tests/formatting/FormatFields.expected @@ -0,0 +1,24 @@ +| 3 | {name!r}, {0} | 0 | 8 | {name!r} | +| 3 | {name!r}, {0} | 10 | 13 | {0} | +| 4 | {0}, {1} | 0 | 3 | {0} | +| 4 | {0}, {1} | 5 | 8 | {1} | +| 5 | {}, {} | 0 | 2 | {} | +| 5 | {}, {} | 4 | 6 | {} | +| 8 | {{}}> | 10 | 12 | {} | +| 10 | {{0}}{0} | 5 | 8 | {0} | +| 11 | {{{}}} | 2 | 4 | {} | +| 13 | { {{ 0} }} | 0 | 7 | { {{ 0} | +| 14 | { { { 0} }} | 4 | 8 | { 0} | +| 15 | {{{{{} | 4 | 6 | {} | +| 16 | {}\r{}{:<{width}} | 0 | 2 | {} | +| 16 | {}\r{}{:<{width}} | 3 | 5 | {} | +| 16 | {}\r{}{:<{width}} | 5 | 16 | {:<{width}} | +| 16 | {}\r{}{:<{width}} | 8 | 15 | {width} | +| 17 | {}\r{}{:<{}} | 0 | 2 | {} | +| 17 | {}\r{}{:<{}} | 3 | 5 | {} | +| 17 | {}\r{}{:<{}} | 5 | 11 | {:<{}} | +| 17 | {}\r{}{:<{}} | 8 | 10 | {} | +| 19 | {x:0.{decimals}f} | 0 | 17 | {x:0.{decimals}f} | +| 19 | {x:0.{decimals}f} | 5 | 15 | {decimals} | +| 21 | invalid value of type {.__name__}: {} | 22 | 33 | {.__name__} | +| 21 | invalid value of type {.__name__}: {} | 35 | 37 | {} | diff --git a/python/ql/test/library-tests/formatting/FormatFields.ql b/python/ql/test/library-tests/formatting/FormatFields.ql new file mode 100644 index 00000000000..b8a3b913355 --- /dev/null +++ b/python/ql/test/library-tests/formatting/FormatFields.ql @@ -0,0 +1,6 @@ + +import python +import Expressions.Formatting.AdvancedFormatting + +from AdvancedFormatString a, int start, int end +select a.getLocation().getStartLine(), a.getText(), start, end, a.getField(start, end) diff --git a/python/ql/test/library-tests/formatting/test.py b/python/ql/test/library-tests/formatting/test.py new file mode 100755 index 00000000000..54ca7e8e94b --- /dev/null +++ b/python/ql/test/library-tests/formatting/test.py @@ -0,0 +1,21 @@ +#Simple cases + +"{name!r}, {0}".format() +"{0}, {1}".format() +"{}, {}".format() + +#Complex cases +"{{}}>".format(html_class) + +"{{0}}{0}".format("X") +"{{{}}}".format("X") + +"{ {{ 0} }}".format("X") +"{ { { 0} }}".format("X") +"{{{{{}".format("X") +u'{}\r{}{:<{width}}'.format(1, 2, 3, width=msg_width) +u'{}\r{}{:<{}}'.format(1, 2, 3, 4) +#ODASA 6428 +'{x:0.{decimals}f}'.format(x=x, decimals=int(decimals)) + +"invalid value of type {.__name__}: {}".format(int, 1) diff --git a/python/ql/test/library-tests/imports/Alias.expected b/python/ql/test/library-tests/imports/Alias.expected new file mode 100644 index 00000000000..6ea5e16c29c --- /dev/null +++ b/python/ql/test/library-tests/imports/Alias.expected @@ -0,0 +1,3 @@ +| Alias | a | a | +| Alias | b | b | +| Alias | c | d | \ No newline at end of file diff --git a/python/ql/test/library-tests/imports/Alias.ql b/python/ql/test/library-tests/imports/Alias.ql new file mode 100644 index 00000000000..5a7c034d02a --- /dev/null +++ b/python/ql/test/library-tests/imports/Alias.ql @@ -0,0 +1,5 @@ +import python + +from Alias a, ImportMember i +where i = a.getValue() +select a.toString(), i.getName(), a.getAsname().toString() \ No newline at end of file diff --git a/python/ql/test/library-tests/imports/test.py b/python/ql/test/library-tests/imports/test.py new file mode 100644 index 00000000000..b4ef0503ff6 --- /dev/null +++ b/python/ql/test/library-tests/imports/test.py @@ -0,0 +1,6 @@ + +from x.y.z import ( + a, + b as b, + c as d +) diff --git a/python/ql/test/library-tests/jump_to_defn/Remote.expected b/python/ql/test/library-tests/jump_to_defn/Remote.expected new file mode 100755 index 00000000000..c8c85fb4428 --- /dev/null +++ b/python/ql/test/library-tests/jump_to_defn/Remote.expected @@ -0,0 +1,16 @@ +| module | +| module/C | +| module/C.m | +| module/C.sm | +| module/f | +| test | +| test/BaseClass | +| test/C | +| test/D | +| test/D.cls_attr | +| test/D.meth | +| test/DerivedClass | +| test/f | +| test/func | +| test/module | +| test/no_phi_defn | diff --git a/python/ql/test/library-tests/jump_to_defn/Remote.ql b/python/ql/test/library-tests/jump_to_defn/Remote.ql new file mode 100644 index 00000000000..18b0ebacdc0 --- /dev/null +++ b/python/ql/test/library-tests/jump_to_defn/Remote.ql @@ -0,0 +1,10 @@ + +import python +import analysis.DefinitionTracking +import analysis.CrossProjectDefinitions + +from Definition defn, Symbol s +where s.find() = defn.getAstNode() and +// Exclude dunder names as these vary from version to version. +not s.toString().regexpMatch(".+__") +select s.toString() diff --git a/python/ql/test/library-tests/jump_to_defn/Sanity.expected b/python/ql/test/library-tests/jump_to_defn/Sanity.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/library-tests/jump_to_defn/Sanity.ql b/python/ql/test/library-tests/jump_to_defn/Sanity.ql new file mode 100644 index 00000000000..0e4455ab09b --- /dev/null +++ b/python/ql/test/library-tests/jump_to_defn/Sanity.ql @@ -0,0 +1,22 @@ + +import python +import analysis.DefinitionTracking +import analysis.CrossProjectDefinitions + +predicate local_problem(Definition defn, string issue, string repr) { + not exists(defn.toString()) and issue = "no toString()" and repr = "a local definition" + or + not exists(defn.getAstNode()) and issue = "no getAstNode()" and repr = defn.toString() + or + not exists(defn.getLocation()) and issue = "no getLocation()" and repr = defn.toString() + or + count(defn.getLocation())> 1 and issue = "more than one getLocation()" and repr = defn.toString() +} + +predicate remote_problem(Symbol s, string issue, string repr) { + not exists(s.toString()) and issue = "no toString()" and repr = "a symbol" +} + +from string issue, string repr +where remote_problem(_, issue, repr) or local_problem(_, issue, repr) +select issue, repr diff --git a/python/ql/test/library-tests/jump_to_defn/Symbol.expected b/python/ql/test/library-tests/jump_to_defn/Symbol.expected new file mode 100644 index 00000000000..5e576517552 --- /dev/null +++ b/python/ql/test/library-tests/jump_to_defn/Symbol.expected @@ -0,0 +1,21 @@ +| module | module.py:0 | +| module/C | module.py:2 | +| module/C.m | module.py:8 | +| module/C.sm | module.py:4 | +| module/__name__ | module.py:0 | +| module/f | module.py:11 | +| test | test.py:0 | +| test/BaseClass | test.py:36 | +| test/BaseClass.__init__ | test.py:38 | +| test/C | module.py:2 | +| test/D | test.py:21 | +| test/D.__init__ | test.py:27 | +| test/D.cls_attr | test.py:24 | +| test/D.meth | test.py:30 | +| test/DerivedClass | test.py:41 | +| test/DerivedClass.__init__ | test.py:43 | +| test/__name__ | test.py:0 | +| test/f | module.py:11 | +| test/func | test.py:6 | +| test/module | test.py:2 | +| test/no_phi_defn | test.py:14 | diff --git a/python/ql/test/library-tests/jump_to_defn/Symbol.ql b/python/ql/test/library-tests/jump_to_defn/Symbol.ql new file mode 100644 index 00000000000..7f111863b06 --- /dev/null +++ b/python/ql/test/library-tests/jump_to_defn/Symbol.ql @@ -0,0 +1,8 @@ + +import python +import analysis.CrossProjectDefinitions + +from Symbol symbol + +select symbol.toString(), symbol.find().getLocation().toString() + diff --git a/python/ql/test/library-tests/jump_to_defn/module.py b/python/ql/test/library-tests/jump_to_defn/module.py new file mode 100644 index 00000000000..1c5102fe405 --- /dev/null +++ b/python/ql/test/library-tests/jump_to_defn/module.py @@ -0,0 +1,13 @@ + +class C(object): + + @staticmethod + def sm(arg): + pass + + def m(self, arg): + pass + +def f(arg): + pass + diff --git a/python/ql/test/library-tests/jump_to_defn/test.expected b/python/ql/test/library-tests/jump_to_defn/test.expected new file mode 100755 index 00000000000..183908d5896 --- /dev/null +++ b/python/ql/test/library-tests/jump_to_defn/test.expected @@ -0,0 +1,41 @@ +| test.py:2 | ImportExpr | Definition module.py:0 | +| test.py:3 | ImportExpr | Definition module.py:0 | +| test.py:3 | ImportMember | Definition module.py:2 | +| test.py:4 | ImportExpr | Definition module.py:0 | +| test.py:4 | ImportMember | Definition module.py:11 | +| test.py:7 | Attribute | Definition module.py:4 | +| test.py:7 | C | Definition test.py:3 | +| test.py:7 | arg | Definition test.py:6 | +| test.py:8 | Attribute | Definition module.py:8 | +| test.py:8 | C | Definition test.py:3 | +| test.py:8 | arg | Definition test.py:6 | +| test.py:9 | arg | Definition test.py:6 | +| test.py:9 | f | Definition test.py:4 | +| test.py:10 | Attribute | Definition module.py:2 | +| test.py:10 | Attribute | Definition module.py:4 | +| test.py:10 | arg | Definition test.py:6 | +| test.py:10 | module | Definition test.py:2 | +| test.py:11 | Attribute | Definition module.py:2 | +| test.py:11 | Attribute | Definition module.py:8 | +| test.py:11 | arg | Definition test.py:6 | +| test.py:11 | module | Definition test.py:2 | +| test.py:12 | Attribute | Definition module.py:11 | +| test.py:12 | arg | Definition test.py:6 | +| test.py:12 | module | Definition test.py:2 | +| test.py:15 | seq | Definition test.py:14 | +| test.py:16 | cond | Definition test.py:14 | +| test.py:17 | seq | Definition test.py:14 | +| test.py:19 | x | Definition test.py:15 | +| test.py:19 | x | Definition test.py:17 | +| test.py:31 | Attribute | Definition test.py:24 | +| test.py:31 | self | Definition test.py:30 | +| test.py:33 | Attribute | Definition test.py:24 | +| test.py:33 | D | Definition test.py:21 | +| test.py:41 | BaseClass | Definition test.py:36 | +| test.py:44 | Attribute | Definition test.py:38 | +| test.py:44 | BaseClass | Definition test.py:36 | +| test.py:44 | self | Definition test.py:43 | +| test.py:45 | Attribute | Definition test.py:38 | +| test.py:45 | DerivedClass | Definition test.py:41 | +| test.py:45 | self | Definition test.py:43 | +| test.py:46 | m | Definition test.py:45 | diff --git a/python/ql/test/library-tests/jump_to_defn/test.py b/python/ql/test/library-tests/jump_to_defn/test.py new file mode 100644 index 00000000000..c14cb6436bc --- /dev/null +++ b/python/ql/test/library-tests/jump_to_defn/test.py @@ -0,0 +1,47 @@ + +import module +from module import C +from module import f + +def func(arg): + C.sm(arg) + C().m(arg) + f(arg) + module.C.sm(arg) + module.C().m(arg) + module.f(arg) + +def no_phi_defn(seq, cond): + x = seq[0] + if cond: + x = seq[1] + pass + x + +class D(object): + + cls_attr = ( + 3 + ) + + def __init__(self): + pass + + def meth(self): + return self.cls_attr + +D.cls_attr + + +class BaseClass(object): + + def __init__(self): + pass + +class DerivedClass(BaseClass): + + def __init__(self): + BaseClass.__init__(self) + m = super(DerivedClass, self).__init__ + m() + diff --git a/python/ql/test/library-tests/jump_to_defn/test.ql b/python/ql/test/library-tests/jump_to_defn/test.ql new file mode 100644 index 00000000000..ed8bf8ab84c --- /dev/null +++ b/python/ql/test/library-tests/jump_to_defn/test.ql @@ -0,0 +1,11 @@ +/** + * @name test + */ + +import python +import analysis.DefinitionTracking + +from Expr use, Definition defn +where defn = getADefinition(use) +and use.getEnclosingModule().getName() = "test" +select use.getLocation().toString(), use.toString(), defn.toString() diff --git a/python/ql/test/library-tests/locations/elif/test.expected b/python/ql/test/library-tests/locations/elif/test.expected new file mode 100644 index 00000000000..f6682119ad1 --- /dev/null +++ b/python/ql/test/library-tests/locations/elif/test.expected @@ -0,0 +1,18 @@ +| If | 3 | 1 | 3 | 5 | +| If | 5 | 1 | 5 | 7 | +| If | 7 | 1 | 7 | 7 | +| If | 10 | 1 | 10 | 5 | +| If | 12 | 1 | 12 | 7 | +| If | 13 | 5 | 13 | 9 | +| ModuleMetrics | 0 | 0 | 0 | 0 | +| Name | 3 | 4 | 3 | 4 | +| Name | 5 | 6 | 5 | 6 | +| Name | 7 | 6 | 7 | 6 | +| Name | 10 | 4 | 10 | 4 | +| Name | 12 | 6 | 12 | 6 | +| Name | 13 | 8 | 13 | 8 | +| Pass | 4 | 5 | 4 | 8 | +| Pass | 6 | 5 | 6 | 8 | +| Pass | 8 | 5 | 8 | 8 | +| Pass | 11 | 5 | 11 | 8 | +| Pass | 14 | 9 | 14 | 12 | diff --git a/python/ql/test/library-tests/locations/elif/test.py b/python/ql/test/library-tests/locations/elif/test.py new file mode 100644 index 00000000000..eeaf2828457 --- /dev/null +++ b/python/ql/test/library-tests/locations/elif/test.py @@ -0,0 +1,14 @@ + +#Elif +if a: + pass +elif b: + pass +elif c: + pass + +if x: + pass +elif y: + if z: + pass diff --git a/python/ql/test/library-tests/locations/elif/test.ql b/python/ql/test/library-tests/locations/elif/test.ql new file mode 100644 index 00000000000..ca7177e847c --- /dev/null +++ b/python/ql/test/library-tests/locations/elif/test.ql @@ -0,0 +1,5 @@ +import python + +from AstNode ast, Location l +where ast.getLocation() = l +select ast.getAQlClass(), l.getStartLine(), l.getStartColumn(), l.getEndLine(), l.getEndColumn() \ No newline at end of file diff --git a/python/ql/test/library-tests/locations/implicit_concatenation/part_locations.expected b/python/ql/test/library-tests/locations/implicit_concatenation/part_locations.expected new file mode 100644 index 00000000000..ef11cdc0d36 --- /dev/null +++ b/python/ql/test/library-tests/locations/implicit_concatenation/part_locations.expected @@ -0,0 +1,14 @@ +| 2 | "Hello " | 1 | 8 | +| 2 | "World" | 14 | 20 | +| 5 | "Goodbye " | 1 | 10 | +| 6 | "World" | 1 | 7 | +| 9 | "a" | 3 | 5 | +| 9 | "b" | 7 | 9 | +| 12 | "c" | 2 | 4 | +| 12 | "d" | 6 | 8 | +| 16 | 'e' | 5 | 7 | +| 17 | 'f' | 5 | 7 | +| 32 | '' | 8 | 9 | +| 32 | 'word' | 1 | 6 | +| 35 | '0' | 12 | 14 | +| 35 | '\\n\\n\\n\\n' | 1 | 10 | diff --git a/python/ql/test/library-tests/locations/implicit_concatenation/part_locations.ql b/python/ql/test/library-tests/locations/implicit_concatenation/part_locations.ql new file mode 100644 index 00000000000..2687a785f1b --- /dev/null +++ b/python/ql/test/library-tests/locations/implicit_concatenation/part_locations.ql @@ -0,0 +1,12 @@ +import python + +class ImplicitConcat extends StrConst { + ImplicitConcat() { + exists(this.getAnImplicitlyConcatenatedPart()) + } +} + +from StringPart s + + +select s.getLocation().getStartLine(), s.getText(), s.getLocation().getStartColumn(), s.getLocation().getEndColumn() \ No newline at end of file diff --git a/python/ql/test/library-tests/locations/implicit_concatenation/parts.expected b/python/ql/test/library-tests/locations/implicit_concatenation/parts.expected new file mode 100644 index 00000000000..e1d59b7a32d --- /dev/null +++ b/python/ql/test/library-tests/locations/implicit_concatenation/parts.expected @@ -0,0 +1,14 @@ +| 2 | Hello World | 0 | "Hello " | +| 2 | Hello World | 1 | "World" | +| 5 | Goodbye World | 0 | "Goodbye " | +| 5 | Goodbye World | 1 | "World" | +| 9 | ab | 0 | "a" | +| 9 | ab | 1 | "b" | +| 12 | cd | 0 | "c" | +| 12 | cd | 1 | "d" | +| 16 | ef | 0 | 'e' | +| 16 | ef | 1 | 'f' | +| 32 | word | 0 | 'word' | +| 32 | word | 1 | '' | +| 35 | \n\n\n\n0 | 0 | '\\n\\n\\n\\n' | +| 35 | \n\n\n\n0 | 1 | '0' | diff --git a/python/ql/test/library-tests/locations/implicit_concatenation/parts.ql b/python/ql/test/library-tests/locations/implicit_concatenation/parts.ql new file mode 100644 index 00000000000..1b1a0d492b3 --- /dev/null +++ b/python/ql/test/library-tests/locations/implicit_concatenation/parts.ql @@ -0,0 +1,14 @@ +import python + +class ImplicitConcat extends StrConst { + ImplicitConcat() { + exists(this.getAnImplicitlyConcatenatedPart()) + } +} + +from StrConst s, StringPart part, int n +where + part = s.getImplicitlyConcatenatedPart(n) + + +select s.getLocation().getStartLine(), s.getText(), n, part.getText() \ No newline at end of file diff --git a/python/ql/test/library-tests/locations/implicit_concatenation/test.expected b/python/ql/test/library-tests/locations/implicit_concatenation/test.expected new file mode 100644 index 00000000000..ae3794a9278 --- /dev/null +++ b/python/ql/test/library-tests/locations/implicit_concatenation/test.expected @@ -0,0 +1,10 @@ +| 2 | Hello World | true | 11 | 1 | 20 | +| 5 | Goodbye World | true | 13 | 1 | 7 | +| 9 | ab | true | 2 | 3 | 9 | +| 12 | cd | true | 2 | 2 | 8 | +| 16 | ef | true | 2 | 5 | 7 | +| 21 | string | false | 6 | 1 | 8 | +| 24 | \n\n\n\n | false | 4 | 1 | 10 | +| 27 | \u0123\u1234 | false | 2 | 1 | 15 | +| 32 | word | true | 4 | 1 | 9 | +| 35 | \n\n\n\n0 | true | 5 | 1 | 14 | diff --git a/python/ql/test/library-tests/locations/implicit_concatenation/test.py b/python/ql/test/library-tests/locations/implicit_concatenation/test.py new file mode 100644 index 00000000000..76dd43add80 --- /dev/null +++ b/python/ql/test/library-tests/locations/implicit_concatenation/test.py @@ -0,0 +1,36 @@ +#Single line concat +"Hello " "World" + +#Multi line concat with line continuation +"Goodbye " \ +"World" + +#Single line concat in list +[ "a" "b" ] + +#Single line, looks like tuple, but is just parenthesized +("c" "d" ) + +#Multi line in list +[ + 'e' + 'f' +] + +#Simple String +"string" + +#String with escapes +"\n\n\n\n" + +#String with unicode escapes +u'\u0123\u1234' + +#These implicit concatenations can only be found with extractor support. + +#Concat with empty String +'word' '' + +#String with escapes and concatenation : +'\n\n\n\n' '0' + diff --git a/python/ql/test/library-tests/locations/implicit_concatenation/test.ql b/python/ql/test/library-tests/locations/implicit_concatenation/test.ql new file mode 100644 index 00000000000..5b2f6ae0a55 --- /dev/null +++ b/python/ql/test/library-tests/locations/implicit_concatenation/test.ql @@ -0,0 +1,16 @@ +import python + +class ImplicitConcat extends StrConst { + ImplicitConcat() { + exists(this.getAnImplicitlyConcatenatedPart()) + } +} + +from StrConst s, boolean isConcat +where + s instanceof ImplicitConcat and isConcat = true + or + not s instanceof ImplicitConcat and isConcat = false + + +select s.getLocation().getStartLine(), s.getText(), isConcat, s.getText().length(), s.getLocation().getStartColumn(), s.getLocation().getEndColumn() \ No newline at end of file diff --git a/python/ql/test/library-tests/locations/negative_numbers/negative.expected b/python/ql/test/library-tests/locations/negative_numbers/negative.expected new file mode 100644 index 00000000000..77c824ac91f --- /dev/null +++ b/python/ql/test/library-tests/locations/negative_numbers/negative.expected @@ -0,0 +1,26 @@ +| FloatLiteral | 6 | 2 | 6 | 4 | | +| FloatLiteral | 7 | 2 | 7 | 7 | | +| FloatLiteral | 11 | 3 | 11 | 5 | () | +| FloatLiteral | 12 | 3 | 12 | 8 | () | +| FloatLiteral | 16 | 3 | 16 | 5 | | +| FloatLiteral | 17 | 3 | 17 | 8 | | +| ImaginaryLiteral | 19 | 2 | 19 | 3 | | +| IntegerLiteral | 4 | 2 | 4 | 2 | | +| IntegerLiteral | 5 | 2 | 5 | 18 | | +| IntegerLiteral | 9 | 3 | 9 | 3 | () | +| IntegerLiteral | 10 | 3 | 10 | 19 | () | +| IntegerLiteral | 14 | 3 | 14 | 3 | | +| IntegerLiteral | 15 | 3 | 15 | 19 | | +| UnaryExpr | 4 | 1 | 4 | 2 | | +| UnaryExpr | 5 | 1 | 5 | 18 | | +| UnaryExpr | 6 | 1 | 6 | 4 | | +| UnaryExpr | 7 | 1 | 7 | 7 | | +| UnaryExpr | 9 | 1 | 9 | 4 | | +| UnaryExpr | 10 | 1 | 10 | 20 | | +| UnaryExpr | 11 | 1 | 11 | 6 | | +| UnaryExpr | 12 | 1 | 12 | 9 | | +| UnaryExpr | 14 | 2 | 14 | 3 | () | +| UnaryExpr | 15 | 2 | 15 | 19 | () | +| UnaryExpr | 16 | 2 | 16 | 5 | () | +| UnaryExpr | 17 | 2 | 17 | 8 | () | +| UnaryExpr | 19 | 1 | 19 | 3 | | \ No newline at end of file diff --git a/python/ql/test/library-tests/locations/negative_numbers/negative.py b/python/ql/test/library-tests/locations/negative_numbers/negative.py new file mode 100644 index 00000000000..92d46f37b64 --- /dev/null +++ b/python/ql/test/library-tests/locations/negative_numbers/negative.py @@ -0,0 +1,19 @@ + +#Some negative numbers + +-1 +-10000000000000000 +-1.0 +-3.0e17 + +-(1) +-(10000000000000000) +-(1.0) +-(3.0e17) + +(-1) +(-10000000000000000) +(-1.0) +(-3.0e17) + +-1j \ No newline at end of file diff --git a/python/ql/test/library-tests/locations/negative_numbers/negative.ql b/python/ql/test/library-tests/locations/negative_numbers/negative.ql new file mode 100644 index 00000000000..c423cb0532c --- /dev/null +++ b/python/ql/test/library-tests/locations/negative_numbers/negative.ql @@ -0,0 +1,13 @@ +import python + +from Expr e, int bl, int bc, int el,int ec, string p + +where + e.getLocation().hasLocationInfo(_, bl, bc, el, ec) + and + if e.isParenthesized() then + p = "()" + else + p = "" + +select e.toString(), bl, bc, el, ec, p \ No newline at end of file diff --git a/python/ql/test/library-tests/locations/nested_classes/Test.expected b/python/ql/test/library-tests/locations/nested_classes/Test.expected new file mode 100644 index 00000000000..1469ceebc74 --- /dev/null +++ b/python/ql/test/library-tests/locations/nested_classes/Test.expected @@ -0,0 +1,6 @@ +| A_Simple | 2 | 1 | 2 | 23 | +| B1_Outer | 6 | 1 | 6 | 23 | +| B2_Inner | 8 | 5 | 8 | 27 | +| C1_Outer | 12 | 1 | 12 | 15 | +| C2_Mid__ | 14 | 5 | 14 | 19 | +| C3_Inner | 16 | 9 | 16 | 23 | diff --git a/python/ql/test/library-tests/locations/nested_classes/Test.ql b/python/ql/test/library-tests/locations/nested_classes/Test.ql new file mode 100644 index 00000000000..693d6f7116f --- /dev/null +++ b/python/ql/test/library-tests/locations/nested_classes/Test.ql @@ -0,0 +1,7 @@ + +import python + +from Class cls, Location l +where l = cls.getLocation() + +select cls.getName(), l.getStartLine(), l.getStartColumn(), l.getEndLine(), l.getEndColumn() diff --git a/python/ql/test/library-tests/locations/nested_classes/test.py b/python/ql/test/library-tests/locations/nested_classes/test.py new file mode 100644 index 00000000000..af99d3a7500 --- /dev/null +++ b/python/ql/test/library-tests/locations/nested_classes/test.py @@ -0,0 +1,18 @@ + +class A_Simple(object): + + pass + +class B1_Outer(object): + + class B2_Inner(object): + + pass + +class C1_Outer: + + class C2_Mid__: + + class C3_Inner: + + pass diff --git a/python/ql/test/library-tests/modules/overlapping-paths/ModuleNames.expected b/python/ql/test/library-tests/modules/overlapping-paths/ModuleNames.expected new file mode 100644 index 00000000000..e7b43879904 --- /dev/null +++ b/python/ql/test/library-tests/modules/overlapping-paths/ModuleNames.expected @@ -0,0 +1,7 @@ +| outer/inner/imported | imported | +| outer/inner/imported/__init__.py | imported.__init__ | +| outer/inner/imported/x.py | imported.x | +| outer/inner/y.py | y | +| src/package | package | +| src/package/__init__.py | package.__init__ | +| src/package/test.py | package.test | diff --git a/python/ql/test/library-tests/modules/overlapping-paths/ModuleNames.ql b/python/ql/test/library-tests/modules/overlapping-paths/ModuleNames.ql new file mode 100644 index 00000000000..a3a54953513 --- /dev/null +++ b/python/ql/test/library-tests/modules/overlapping-paths/ModuleNames.ql @@ -0,0 +1,5 @@ + +import python + +from Module m +select m.getPath().toString(), m.getName() diff --git a/python/ql/test/library-tests/modules/overlapping-paths/options b/python/ql/test/library-tests/modules/overlapping-paths/options new file mode 100644 index 00000000000..120c64adc17 --- /dev/null +++ b/python/ql/test/library-tests/modules/overlapping-paths/options @@ -0,0 +1 @@ +semmle-extractor-options: -R src --path outer/inner --path outer diff --git a/python/ql/test/library-tests/modules/overlapping-paths/outer/inner/imported/__init__.py b/python/ql/test/library-tests/modules/overlapping-paths/outer/inner/imported/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/library-tests/modules/overlapping-paths/outer/inner/imported/x.py b/python/ql/test/library-tests/modules/overlapping-paths/outer/inner/imported/x.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/library-tests/modules/overlapping-paths/outer/inner/y.py b/python/ql/test/library-tests/modules/overlapping-paths/outer/inner/y.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/library-tests/modules/overlapping-paths/src/package/__init__.py b/python/ql/test/library-tests/modules/overlapping-paths/src/package/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/library-tests/modules/overlapping-paths/src/package/test.py b/python/ql/test/library-tests/modules/overlapping-paths/src/package/test.py new file mode 100644 index 00000000000..c085d2a5975 --- /dev/null +++ b/python/ql/test/library-tests/modules/overlapping-paths/src/package/test.py @@ -0,0 +1,2 @@ +import imported.x +import y diff --git a/python/ql/test/library-tests/modules/overlapping-paths/src/script.py b/python/ql/test/library-tests/modules/overlapping-paths/src/script.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/library-tests/modules/spurious_init/ModuleNames.expected b/python/ql/test/library-tests/modules/spurious_init/ModuleNames.expected new file mode 100644 index 00000000000..4aca8d12f07 --- /dev/null +++ b/python/ql/test/library-tests/modules/spurious_init/ModuleNames.expected @@ -0,0 +1,5 @@ +| root | root | +| root/__init__.py | root.__init__ | +| root/src-folder/package | package | +| root/src-folder/package/__init__.py | package.__init__ | +| root/src-folder/package/module.py | package.module | diff --git a/python/ql/test/library-tests/modules/spurious_init/ModuleNames.ql b/python/ql/test/library-tests/modules/spurious_init/ModuleNames.ql new file mode 100644 index 00000000000..a3a54953513 --- /dev/null +++ b/python/ql/test/library-tests/modules/spurious_init/ModuleNames.ql @@ -0,0 +1,5 @@ + +import python + +from Module m +select m.getPath().toString(), m.getName() diff --git a/python/ql/test/library-tests/modules/spurious_init/options b/python/ql/test/library-tests/modules/spurious_init/options new file mode 100644 index 00000000000..dfcf3662523 --- /dev/null +++ b/python/ql/test/library-tests/modules/spurious_init/options @@ -0,0 +1 @@ +semmle-extractor-options: -R . --filter exclude:**/src_archive/** diff --git a/python/ql/test/library-tests/modules/spurious_init/root/__init__.py b/python/ql/test/library-tests/modules/spurious_init/root/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/library-tests/modules/spurious_init/root/src-folder/package/__init__.py b/python/ql/test/library-tests/modules/spurious_init/root/src-folder/package/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/library-tests/modules/spurious_init/root/src-folder/package/module.py b/python/ql/test/library-tests/modules/spurious_init/root/src-folder/package/module.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/library-tests/objects/Literals.expected b/python/ql/test/library-tests/objects/Literals.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/library-tests/objects/Literals.ql b/python/ql/test/library-tests/objects/Literals.ql new file mode 100644 index 00000000000..f83f4e722da --- /dev/null +++ b/python/ql/test/library-tests/objects/Literals.ql @@ -0,0 +1,16 @@ + +/* Test that there are no literals that do not have a corresponding object. */ +import python + + +string repr(Expr e) { + result = e.(Num).getN() or + result = e.(Bytes).getS() or + result = e.(Unicode).getS() +} + +from ImmutableLiteral l +where +not exists(l.getLiteralObject()) + +select l.getLocation().getStartLine(), repr(l) \ No newline at end of file diff --git a/python/ql/test/library-tests/objects/Name.expected b/python/ql/test/library-tests/objects/Name.expected new file mode 100644 index 00000000000..7333ee611e8 --- /dev/null +++ b/python/ql/test/library-tests/objects/Name.expected @@ -0,0 +1,9 @@ +| sys.modules | dict object | +| test.C.cmeth | Function cmeth | +| test.C.cmeth | classmethod() | +| test.C.meth | Function meth | +| test.C.smeth | Function smeth | +| test.C.smeth | staticmethod() | +| test.d | Dict | +| test.l | List | +| test.n | NoneType None | diff --git a/python/ql/test/library-tests/objects/Name.ql b/python/ql/test/library-tests/objects/Name.ql new file mode 100644 index 00000000000..674890c01ba --- /dev/null +++ b/python/ql/test/library-tests/objects/Name.ql @@ -0,0 +1,21 @@ + +import python + +from Object o, string name +where o.hasLongName(name) +and ( + name = "sys.modules" + or + name = "test.n" + or + name = "test.l" + or + name = "test.d" + or + name = "test.C.meth" + or + name = "test.C.cmeth" + or + name = "test.C.smeth" +) +select name, o.toString() diff --git a/python/ql/test/library-tests/objects/Strings.expected b/python/ql/test/library-tests/objects/Strings.expected new file mode 100644 index 00000000000..b9d7c336d6b --- /dev/null +++ b/python/ql/test/library-tests/objects/Strings.expected @@ -0,0 +1,7 @@ +| test.py:14 | d | +| test.py:15 | | +| test.py:16 | | +| test.py:17 | ' | +| test.py:18 | efwb\nonv\n8979\n | +| test.py:22 | 0 | +| test.py:23 | None | diff --git a/python/ql/test/library-tests/objects/Strings.ql b/python/ql/test/library-tests/objects/Strings.ql new file mode 100644 index 00000000000..9fcceb58fe4 --- /dev/null +++ b/python/ql/test/library-tests/objects/Strings.ql @@ -0,0 +1,8 @@ + +import python + + +from StringObject s, ControlFlowNode f +where f.refersTo(s) +select f.getLocation().toString(), s.getText() + diff --git a/python/ql/test/library-tests/objects/test.py b/python/ql/test/library-tests/objects/test.py new file mode 100644 index 00000000000..d9bc798100a --- /dev/null +++ b/python/ql/test/library-tests/objects/test.py @@ -0,0 +1,40 @@ +0.058823529630899429 + + +1e-06 +.9999999 +0xffffff +1e10 +0o777 +1. +2.79252680 +0x0001000 +4987312561856745907287624786230562734672583763984576267 + +'''d''' +'' +"" +"'" +"""efwb +onv +8979 +""" +'0' +'None' + +n = None +l = [] +d = {} + +class C(object): + + def meth(self): + pass + + @classmethod + def cmeth(cls): + pass + + @staticmethod + def smeth(): + pass \ No newline at end of file diff --git a/python/ql/test/library-tests/options b/python/ql/test/library-tests/options new file mode 100644 index 00000000000..72e0053821f --- /dev/null +++ b/python/ql/test/library-tests/options @@ -0,0 +1,2 @@ +semmle-extractor-options: --max-import-depth=1 +automatic_locations: true diff --git a/python/ql/test/library-tests/parentheses/Parens.expected b/python/ql/test/library-tests/parentheses/Parens.expected new file mode 100644 index 00000000000..c19d295830d --- /dev/null +++ b/python/ql/test/library-tests/parentheses/Parens.expected @@ -0,0 +1,30 @@ +| 26 | a | +| 27 | Attribute | +| 28 | BinaryExpr | +| 29 | Str | +| 30 | Str | +| 31 | List | +| 32 | Dict | +| 33 | Tuple | +| 34 | Subscript | +| 35 | f() | +| 36 | f() | +| 37 | Attribute() | +| 38 | Attribute() | +| 39 | Subscript | +| 40 | Subscript | +| 41 | Yield | +| 42 | ListComp | +| 43 | SetComp | +| 44 | DictComp | +| 45 | Str | +| 46 | BinaryExpr | +| 47 | BinaryExpr | +| 48 | BinaryExpr | +| 49 | BinaryExpr | +| 50 | BinaryExpr | +| 51 | BinaryExpr | +| 52 | BinaryExpr | +| 55 | BinaryExpr | +| 56 | BinaryExpr | +| 61 | Tuple | \ No newline at end of file diff --git a/python/ql/test/library-tests/parentheses/Parens.ql b/python/ql/test/library-tests/parentheses/Parens.ql new file mode 100644 index 00000000000..9006bb9ff52 --- /dev/null +++ b/python/ql/test/library-tests/parentheses/Parens.ql @@ -0,0 +1,5 @@ +import python + +from Expr e +where e.isParenthesized() +select e.getLocation().getStartLine(), e.toString() diff --git a/python/ql/test/library-tests/parentheses/test.py b/python/ql/test/library-tests/parentheses/test.py new file mode 100644 index 00000000000..74fb2824a1e --- /dev/null +++ b/python/ql/test/library-tests/parentheses/test.py @@ -0,0 +1,64 @@ +# No +import mod +def no(): + a + a.b + 1+p + b"Hi" + u"Hi" + [x] + {} + x,y + s[9] + f() + f(a,b) + o.m() + o.m(a, b) + o.m[0] + x()[0] + yield v + [1 for a in b] + {x for x in z} + {x:y for x,y in z} + +#Yes +def yes(): + (a) + (a.b) + (1+p) + (b"Hi") + (u"Hi") + ([x]) + ({}) + (x,y) + (s[9]) + (f()) + (f(a,b)) + (o.m()) + (o.m(a, b)) + (o.m[0]) + (x()[0]) + (yield 1) + ([1 for a in b]) + ({x for x in z}) + ({x:y for x,y in z}) + (b"x") + ("x"+1) + (1+f()) + (1+2+f()) + ("Failed to parse template " + name + ": " + repr(ex)) + (1+2+3+4) + (1+2+3+4+5) + (1+2+3+4+5+6) + +def multiline(): + ( 1 + + ( 2 * 3 + * 4 ) + ) + + ( + x, + 1, + "a" + ) diff --git a/python/ql/test/library-tests/regex/Alternation.expected b/python/ql/test/library-tests/regex/Alternation.expected new file mode 100644 index 00000000000..cba6212a273 --- /dev/null +++ b/python/ql/test/library-tests/regex/Alternation.expected @@ -0,0 +1,17 @@ +| (?:(?:\n\r?)\|^)( *)\\S | 3 | 12 | (?:\n\r?)\|^ | 3 | 10 | (?:\n\r?) | +| (?:(?:\n\r?)\|^)( *)\\S | 3 | 12 | (?:\n\r?)\|^ | 11 | 12 | ^ | +| (?:[^%]\|^)?%\\((\\w*)\\)[a-z] | 3 | 9 | [^%]\|^ | 3 | 7 | [^%] | +| (?:[^%]\|^)?%\\((\\w*)\\)[a-z] | 3 | 9 | [^%]\|^ | 8 | 9 | ^ | +| (?P[\\w]+)\| | 0 | 16 | (?P[\\w]+)\| | 0 | 15 | (?P[\\w]+) | +| (?P[\\w]+)\| | 0 | 16 | (?P[\\w]+)\| | 16 | 16 | | +| (\\033\|~{) | 1 | 8 | \\033\|~{ | 1 | 5 | \\033 | +| (\\033\|~{) | 1 | 8 | \\033\|~{ | 6 | 8 | ~{ | +| \\\|\\[\\][123]\|\\{\\} | 0 | 16 | \\\|\\[\\][123]\|\\{\\} | 0 | 11 | \\\|\\[\\][123] | +| \\\|\\[\\][123]\|\\{\\} | 0 | 16 | \\\|\\[\\][123]\|\\{\\} | 12 | 16 | \\{\\} | +| ^(^y\|^z)(u$\|v$)$ | 2 | 7 | ^y\|^z | 2 | 4 | ^y | +| ^(^y\|^z)(u$\|v$)$ | 2 | 7 | ^y\|^z | 5 | 7 | ^z | +| ^(^y\|^z)(u$\|v$)$ | 9 | 14 | u$\|v$ | 9 | 11 | u$ | +| ^(^y\|^z)(u$\|v$)$ | 9 | 14 | u$\|v$ | 12 | 14 | v$ | +| x\|(?[\\w]+)\| | 10 | 12 | +| (?m)^(?!$) | 4 | 5 | +| (?m)^(?!$) | 8 | 9 | +| (\\033\|~{) | 1 | 5 | +| (\\033\|~{) | 6 | 7 | +| (\\033\|~{) | 7 | 8 | +| [\ufffd-\ufffd] | 1 | 2 | +| [\ufffd-\ufffd] | 3 | 4 | +| [\ufffd-\ufffd][\ufffd-\ufffd] | 1 | 2 | +| [\ufffd-\ufffd][\ufffd-\ufffd] | 3 | 4 | +| [\ufffd-\ufffd][\ufffd-\ufffd] | 6 | 7 | +| [\ufffd-\ufffd][\ufffd-\ufffd] | 8 | 9 | +| []] | 1 | 2 | +| [^-] | 2 | 3 | +| [^A-Z] | 2 | 3 | +| [^A-Z] | 4 | 5 | +| [^]] | 2 | 3 | +| \\A[+-]?\\d+ | 0 | 2 | +| \\A[+-]?\\d+ | 3 | 4 | +| \\A[+-]?\\d+ | 4 | 5 | +| \\A[+-]?\\d+ | 7 | 9 | +| \\\|\\[\\][123]\|\\{\\} | 0 | 2 | +| \\\|\\[\\][123]\|\\{\\} | 2 | 4 | +| \\\|\\[\\][123]\|\\{\\} | 4 | 6 | +| \\\|\\[\\][123]\|\\{\\} | 7 | 8 | +| \\\|\\[\\][123]\|\\{\\} | 8 | 9 | +| \\\|\\[\\][123]\|\\{\\} | 9 | 10 | +| \\\|\\[\\][123]\|\\{\\} | 12 | 14 | +| \\\|\\[\\][123]\|\\{\\} | 14 | 16 | +| ^(^y\|^z)(u$\|v$)$ | 0 | 1 | +| ^(^y\|^z)(u$\|v$)$ | 2 | 3 | +| ^(^y\|^z)(u$\|v$)$ | 3 | 4 | +| ^(^y\|^z)(u$\|v$)$ | 5 | 6 | +| ^(^y\|^z)(u$\|v$)$ | 6 | 7 | +| ^(^y\|^z)(u$\|v$)$ | 9 | 10 | +| ^(^y\|^z)(u$\|v$)$ | 10 | 11 | +| ^(^y\|^z)(u$\|v$)$ | 12 | 13 | +| ^(^y\|^z)(u$\|v$)$ | 13 | 14 | +| ^(^y\|^z)(u$\|v$)$ | 15 | 16 | +| ^.$ | 0 | 1 | +| ^.$ | 1 | 2 | +| ^.$ | 2 | 3 | +| ^[A-Z_]+$(?[\\w]+)\| | first | 9 | 13 | +| (?P[\\w]+)\| | first | 9 | 14 | +| (?P[\\w]+)\| | last | 9 | 13 | +| (?P[\\w]+)\| | last | 9 | 14 | +| (?m)^(?!$) | first | 4 | 5 | +| (?m)^(?!$) | first | 8 | 9 | +| (?m)^(?!$) | last | 4 | 5 | +| (?m)^(?!$) | last | 8 | 9 | +| (\\033\|~{) | first | 1 | 5 | +| (\\033\|~{) | first | 6 | 7 | +| (\\033\|~{) | last | 1 | 5 | +| (\\033\|~{) | last | 7 | 8 | +| [\ufffd-\ufffd] | first | 0 | 5 | +| [\ufffd-\ufffd] | last | 0 | 5 | +| [\ufffd-\ufffd][\ufffd-\ufffd] | first | 0 | 5 | +| [\ufffd-\ufffd][\ufffd-\ufffd] | last | 5 | 10 | +| []] | first | 0 | 3 | +| []] | last | 0 | 3 | +| [^-] | first | 0 | 4 | +| [^-] | last | 0 | 4 | +| [^A-Z] | first | 0 | 6 | +| [^A-Z] | last | 0 | 6 | +| [^]] | first | 0 | 4 | +| [^]] | last | 0 | 4 | +| \\A[+-]?\\d+ | first | 0 | 2 | +| \\A[+-]?\\d+ | last | 7 | 9 | +| \\A[+-]?\\d+ | last | 7 | 10 | +| \\\|\\[\\][123]\|\\{\\} | first | 0 | 2 | +| \\\|\\[\\][123]\|\\{\\} | first | 12 | 14 | +| \\\|\\[\\][123]\|\\{\\} | last | 6 | 11 | +| \\\|\\[\\][123]\|\\{\\} | last | 14 | 16 | +| ^(^y\|^z)(u$\|v$)$ | first | 0 | 1 | +| ^(^y\|^z)(u$\|v$)$ | first | 2 | 3 | +| ^(^y\|^z)(u$\|v$)$ | first | 3 | 4 | +| ^(^y\|^z)(u$\|v$)$ | first | 5 | 6 | +| ^(^y\|^z)(u$\|v$)$ | first | 6 | 7 | +| ^(^y\|^z)(u$\|v$)$ | last | 9 | 10 | +| ^(^y\|^z)(u$\|v$)$ | last | 10 | 11 | +| ^(^y\|^z)(u$\|v$)$ | last | 12 | 13 | +| ^(^y\|^z)(u$\|v$)$ | last | 13 | 14 | +| ^(^y\|^z)(u$\|v$)$ | last | 15 | 16 | +| ^.$ | first | 0 | 1 | +| ^.$ | first | 1 | 2 | +| ^.$ | last | 1 | 2 | +| ^.$ | last | 2 | 3 | +| ^[A-Z_]+$(?[\\w]+)\| | 0 | 15 | (?P[\\w]+) | 9 | 14 | [\\w]+ | +| (?m)^(?!$) | 5 | 10 | (?!$) | 8 | 9 | $ | +| (\\033\|~{) | 0 | 9 | (\\033\|~{) | 1 | 8 | \\033\|~{ | +| ^(^y\|^z)(u$\|v$)$ | 1 | 8 | (^y\|^z) | 2 | 7 | ^y\|^z | +| ^(^y\|^z)(u$\|v$)$ | 8 | 15 | (u$\|v$) | 9 | 14 | u$\|v$ | +| ^[A-Z_]+$(?[\\w]+)\| | 9 | 14 | false | +| \\A[+-]?\\d+ | 2 | 7 | true | +| \\A[+-]?\\d+ | 7 | 10 | false | +| ^[A-Z_]+$(?[\\w]+)\| | char | 10 | 12 | +| (?P[\\w]+)\| | char-set | 9 | 13 | +| (?P[\\w]+)\| | choice | 0 | 16 | +| (?P[\\w]+)\| | non-empty group | 0 | 15 | +| (?P[\\w]+)\| | qualified | 9 | 14 | +| (?P[\\w]+)\| | sequence | 0 | 15 | +| (?m)^(?!$) | $ | 8 | 9 | +| (?m)^(?!$) | ^ | 4 | 5 | +| (?m)^(?!$) | empty group | 0 | 4 | +| (?m)^(?!$) | empty group | 5 | 10 | +| (?m)^(?!$) | sequence | 0 | 10 | +| (?m)^(?!$) | sequence | 8 | 9 | +| (\\033\|~{) | char | 1 | 5 | +| (\\033\|~{) | char | 6 | 7 | +| (\\033\|~{) | char | 7 | 8 | +| (\\033\|~{) | choice | 1 | 8 | +| (\\033\|~{) | non-empty group | 0 | 9 | +| (\\033\|~{) | sequence | 0 | 9 | +| (\\033\|~{) | sequence | 1 | 5 | +| (\\033\|~{) | sequence | 6 | 8 | +| [\ufffd-\ufffd] | char | 1 | 2 | +| [\ufffd-\ufffd] | char | 3 | 4 | +| [\ufffd-\ufffd] | char-set | 0 | 5 | +| [\ufffd-\ufffd] | sequence | 0 | 5 | +| [\ufffd-\ufffd][\ufffd-\ufffd] | char | 1 | 2 | +| [\ufffd-\ufffd][\ufffd-\ufffd] | char | 3 | 4 | +| [\ufffd-\ufffd][\ufffd-\ufffd] | char | 6 | 7 | +| [\ufffd-\ufffd][\ufffd-\ufffd] | char | 8 | 9 | +| [\ufffd-\ufffd][\ufffd-\ufffd] | char-set | 0 | 5 | +| [\ufffd-\ufffd][\ufffd-\ufffd] | char-set | 5 | 10 | +| [\ufffd-\ufffd][\ufffd-\ufffd] | sequence | 0 | 10 | +| []] | char | 1 | 2 | +| []] | char-set | 0 | 3 | +| []] | sequence | 0 | 3 | +| [^-] | char | 2 | 3 | +| [^-] | char-set | 0 | 4 | +| [^-] | sequence | 0 | 4 | +| [^A-Z] | char | 2 | 3 | +| [^A-Z] | char | 4 | 5 | +| [^A-Z] | char-set | 0 | 6 | +| [^A-Z] | sequence | 0 | 6 | +| [^]] | char | 2 | 3 | +| [^]] | char-set | 0 | 4 | +| [^]] | sequence | 0 | 4 | +| \\A[+-]?\\d+ | char | 0 | 2 | +| \\A[+-]?\\d+ | char | 3 | 4 | +| \\A[+-]?\\d+ | char | 4 | 5 | +| \\A[+-]?\\d+ | char | 7 | 9 | +| \\A[+-]?\\d+ | char-set | 2 | 6 | +| \\A[+-]?\\d+ | qualified | 2 | 7 | +| \\A[+-]?\\d+ | qualified | 7 | 10 | +| \\A[+-]?\\d+ | sequence | 0 | 10 | +| \\\|\\[\\][123]\|\\{\\} | char | 0 | 2 | +| \\\|\\[\\][123]\|\\{\\} | char | 2 | 4 | +| \\\|\\[\\][123]\|\\{\\} | char | 4 | 6 | +| \\\|\\[\\][123]\|\\{\\} | char | 7 | 8 | +| \\\|\\[\\][123]\|\\{\\} | char | 8 | 9 | +| \\\|\\[\\][123]\|\\{\\} | char | 9 | 10 | +| \\\|\\[\\][123]\|\\{\\} | char | 12 | 14 | +| \\\|\\[\\][123]\|\\{\\} | char | 14 | 16 | +| \\\|\\[\\][123]\|\\{\\} | char-set | 6 | 11 | +| \\\|\\[\\][123]\|\\{\\} | choice | 0 | 16 | +| \\\|\\[\\][123]\|\\{\\} | sequence | 0 | 11 | +| \\\|\\[\\][123]\|\\{\\} | sequence | 12 | 16 | +| ^(^y\|^z)(u$\|v$)$ | $ | 10 | 11 | +| ^(^y\|^z)(u$\|v$)$ | $ | 13 | 14 | +| ^(^y\|^z)(u$\|v$)$ | $ | 15 | 16 | +| ^(^y\|^z)(u$\|v$)$ | ^ | 0 | 1 | +| ^(^y\|^z)(u$\|v$)$ | ^ | 2 | 3 | +| ^(^y\|^z)(u$\|v$)$ | ^ | 5 | 6 | +| ^(^y\|^z)(u$\|v$)$ | char | 3 | 4 | +| ^(^y\|^z)(u$\|v$)$ | char | 6 | 7 | +| ^(^y\|^z)(u$\|v$)$ | char | 9 | 10 | +| ^(^y\|^z)(u$\|v$)$ | char | 12 | 13 | +| ^(^y\|^z)(u$\|v$)$ | choice | 2 | 7 | +| ^(^y\|^z)(u$\|v$)$ | choice | 9 | 14 | +| ^(^y\|^z)(u$\|v$)$ | non-empty group | 1 | 8 | +| ^(^y\|^z)(u$\|v$)$ | non-empty group | 8 | 15 | +| ^(^y\|^z)(u$\|v$)$ | sequence | 0 | 16 | +| ^(^y\|^z)(u$\|v$)$ | sequence | 2 | 4 | +| ^(^y\|^z)(u$\|v$)$ | sequence | 5 | 7 | +| ^(^y\|^z)(u$\|v$)$ | sequence | 9 | 11 | +| ^(^y\|^z)(u$\|v$)$ | sequence | 12 | 14 | +| ^.$ | $ | 2 | 3 | +| ^.$ | . | 1 | 2 | +| ^.$ | ^ | 0 | 1 | +| ^.$ | sequence | 0 | 3 | +| ^[A-Z_]+$(?[\w]+)|') +re.compile(r'\|\[\][123]|\{\}') +re.compile(r'^.$') +re.compile(r'[^A-Z]') +# 0123456789ABCDEF +re.sub('(?m)^(?!$)', indent*' ', s) +re.compile("(?:(?:\n\r?)|^)( *)\S") +re.compile("[]]") +re.compile("[^]]") +re.compile("[^-]") + +#Lookbehind group +re.compile(r'x|(?= 20 and +( + state.appliesTo(f, ctx) and sense = true + or + state.mayNotApplyTo(f, ctx) and sense = false +) + +select f.getLocation().toString(), f, ctx, state, sense diff --git a/python/ql/test/library-tests/state_tracking/Violations.expected b/python/ql/test/library-tests/state_tracking/Violations.expected new file mode 100644 index 00000000000..8deeb3c651f --- /dev/null +++ b/python/ql/test/library-tests/state_tracking/Violations.expected @@ -0,0 +1,7 @@ +| global.py:23 | ControlFlowNode for frobnicate() | initialized | +| global.py:26 | ControlFlowNode for exacerbate() | frobnicated | +| test.py:42 | ControlFlowNode for frobnicate() | initialized | +| test.py:48 | ControlFlowNode for exacerbate() | frobnicated | +| test.py:51 | ControlFlowNode for exacerbate() | frobnicated | +| test.py:65 | ControlFlowNode for frobnicate() | initialized | +| test.py:75 | ControlFlowNode for exacerbate() | frobnicated | diff --git a/python/ql/test/library-tests/state_tracking/Violations.ql b/python/ql/test/library-tests/state_tracking/Violations.ql new file mode 100644 index 00000000000..8da2a0500ef --- /dev/null +++ b/python/ql/test/library-tests/state_tracking/Violations.ql @@ -0,0 +1,15 @@ + +import python +import Lib + +from ControlFlowNode f, TrackableState state +where +( + callTo(f, "exacerbate") and state = "frobnicated" + or + callTo(f, "frobnicate") and state = "initialized" +) +and +state.mayNotApplyTo(f) + +select f.getLocation().toString(), f.toString(), state.toString() diff --git a/python/ql/test/library-tests/state_tracking/global.py b/python/ql/test/library-tests/state_tracking/global.py new file mode 100644 index 00000000000..5268cae9c9a --- /dev/null +++ b/python/ql/test/library-tests/state_tracking/global.py @@ -0,0 +1,34 @@ +# We must initialize before we frobnicate and we must frobnicate before exacerbating. + +from test import initialize, frobnicate, exacerbate + + + + + + + + + + + + + + + + +#To keep test results tidy don't put any thing we want results for before line 20 + +def bad1(): + frobnicate() + +def bad2(): + exacerbate() + +def good(): + exacerbate() + +bad2() +bad1() +initialize() +good() \ No newline at end of file diff --git a/python/ql/test/library-tests/state_tracking/test.py b/python/ql/test/library-tests/state_tracking/test.py new file mode 100644 index 00000000000..227d09f0b42 --- /dev/null +++ b/python/ql/test/library-tests/state_tracking/test.py @@ -0,0 +1,75 @@ +# We must initialize before we frobnicate and we must frobnicate before exacerbating. + +#Keep these functions at low line numbers to keep test results tidy. +def initialize(): + pass + +def frobnicate(): + pass + +def exacerbate(): + pass + +def defrobnicate(): + pass + + + + + +#Actual code of interest after line 20 +def good1(): + initialize() + frobnicate() + exacerbate() + +def good2(test): + if test: + initialize() + if test: + frobnicate() + +def init_and_frob(): + initialize() + frobnicate() + +def good3(): + init_and_frob() + exacerbate() + +def bad1(): + #No init + frobnicate() + exacerbate() + +def bad2(): + initialize() + #No frobnicate + exacerbate() + +def bad3(): + exacerbate() + +def good4(frob): + initialized = False + if frob: + initialize() + initialized = True + if initialized: + frobnicate() + exacerbate() + +def bad4(frob): + if frob: + initialize() + frobnicate() + exacerbate() + +def on_off(): + initialize() + frobnicate() + exacerbate() + defrobnicate() + frobnicate() + defrobnicate() + exacerbate() diff --git a/python/ql/test/library-tests/stmts/general/AstParent.expected b/python/ql/test/library-tests/stmts/general/AstParent.expected new file mode 100644 index 00000000000..f082a67fcf6 --- /dev/null +++ b/python/ql/test/library-tests/stmts/general/AstParent.expected @@ -0,0 +1 @@ +| 0 | diff --git a/python/ql/test/library-tests/stmts/general/AstParent.ql b/python/ql/test/library-tests/stmts/general/AstParent.ql new file mode 100644 index 00000000000..b7ea6f44ac3 --- /dev/null +++ b/python/ql/test/library-tests/stmts/general/AstParent.ql @@ -0,0 +1,8 @@ +import python + +/* The result of this query should always be 0, *regardless* of the database. */ + +select +count(AstNode c | not exists(c.getParentNode()) and not c instanceof Module) ++ +count(AstNode c | strictcount(c.getParentNode()) > 1) diff --git a/python/ql/test/library-tests/stmts/general/SubExpressions.expected b/python/ql/test/library-tests/stmts/general/SubExpressions.expected new file mode 100644 index 00000000000..e40356ab46b --- /dev/null +++ b/python/ql/test/library-tests/stmts/general/SubExpressions.expected @@ -0,0 +1,6 @@ +| Delete | Attribute | Attribute | 4 | +| Delete | Attribute | a | 4 | +| Delete | Subscript | Subscript | 2 | +| Delete | Subscript | a | 2 | +| Delete | Subscript | b | 2 | +| Delete | x | x | 3 | \ No newline at end of file diff --git a/python/ql/test/library-tests/stmts/general/SubExpressions.ql b/python/ql/test/library-tests/stmts/general/SubExpressions.ql new file mode 100644 index 00000000000..deaff1e9610 --- /dev/null +++ b/python/ql/test/library-tests/stmts/general/SubExpressions.ql @@ -0,0 +1,5 @@ + +import python + +from Stmt s +select s.toString(), s.getASubExpression().toString(), s.getASubExpression().getASubExpression*().toString(), s.getLocation().getStartLine() \ No newline at end of file diff --git a/python/ql/test/library-tests/stmts/general/subexpr_test.py b/python/ql/test/library-tests/stmts/general/subexpr_test.py new file mode 100644 index 00000000000..14332d14229 --- /dev/null +++ b/python/ql/test/library-tests/stmts/general/subexpr_test.py @@ -0,0 +1,4 @@ + +del a[b] +del x +del a.b diff --git a/python/ql/test/library-tests/stmts/raise_stmt/AST.expected b/python/ql/test/library-tests/stmts/raise_stmt/AST.expected new file mode 100644 index 00000000000..655013b4592 --- /dev/null +++ b/python/ql/test/library-tests/stmts/raise_stmt/AST.expected @@ -0,0 +1,7 @@ +| 0 | Module test | 2 | FunctionDef | +| 2 | Function f | 3 | Raise | +| 2 | Function f | 4 | Raise | +| 2 | FunctionDef | 2 | FunctionExpr | +| 2 | FunctionDef | 2 | f | +| 2 | FunctionExpr | 2 | Function f | +| 4 | Raise | 4 | Exception | \ No newline at end of file diff --git a/python/ql/test/library-tests/stmts/raise_stmt/AST.ql b/python/ql/test/library-tests/stmts/raise_stmt/AST.ql new file mode 100644 index 00000000000..d9daaa8514b --- /dev/null +++ b/python/ql/test/library-tests/stmts/raise_stmt/AST.ql @@ -0,0 +1,7 @@ + + +import python + +from AstNode parent, AstNode child +where child.getParentNode() = parent +select parent.getLocation().getStartLine(), parent.toString(), child.getLocation().getStartLine(), child.toString() \ No newline at end of file diff --git a/python/ql/test/library-tests/stmts/raise_stmt/test.py b/python/ql/test/library-tests/stmts/raise_stmt/test.py new file mode 100644 index 00000000000..26d38df54a1 --- /dev/null +++ b/python/ql/test/library-tests/stmts/raise_stmt/test.py @@ -0,0 +1,4 @@ + +def f(): + raise + raise Exception diff --git a/python/ql/test/library-tests/stmts/try_stmt/AST.expected b/python/ql/test/library-tests/stmts/try_stmt/AST.expected new file mode 100644 index 00000000000..a8c2778fc99 --- /dev/null +++ b/python/ql/test/library-tests/stmts/try_stmt/AST.expected @@ -0,0 +1,34 @@ +| 0 | Module test | 2 | FunctionDef | +| 2 | Function f | 3 | Try | +| 2 | Function f | 12 | Try | +| 2 | Function f | 17 | Try | +| 2 | FunctionDef | 2 | FunctionExpr | +| 2 | FunctionDef | 2 | f | +| 2 | FunctionExpr | 2 | Function f | +| 3 | Try | 4 | ExprStmt | +| 3 | Try | 5 | Try | +| 3 | Try | 9 | ExceptStmt | +| 4 | ExprStmt | 4 | call() | +| 4 | call() | 4 | call | +| 5 | Try | 6 | ExprStmt | +| 5 | Try | 7 | ExceptStmt | +| 6 | ExprStmt | 6 | nested() | +| 6 | nested() | 6 | nested | +| 7 | ExceptStmt | 7 | Exception | +| 7 | ExceptStmt | 8 | Return | +| 8 | Return | 8 | IntegerLiteral | +| 9 | ExceptStmt | 10 | Return | +| 10 | Return | 10 | IntegerLiteral | +| 12 | Try | 13 | ExprStmt | +| 12 | Try | 14 | ExceptStmt | +| 13 | ExprStmt | 13 | call2() | +| 13 | call2() | 13 | call2 | +| 14 | ExceptStmt | 14 | Exception | +| 14 | ExceptStmt | 15 | Return | +| 15 | Return | 15 | IntegerLiteral | +| 17 | Try | 18 | ExprStmt | +| 17 | Try | 20 | ExprStmt | +| 18 | ExprStmt | 18 | call3a() | +| 18 | call3a() | 18 | call3a | +| 20 | ExprStmt | 20 | call3b() | +| 20 | call3b() | 20 | call3b | \ No newline at end of file diff --git a/python/ql/test/library-tests/stmts/try_stmt/AST.ql b/python/ql/test/library-tests/stmts/try_stmt/AST.ql new file mode 100644 index 00000000000..d9daaa8514b --- /dev/null +++ b/python/ql/test/library-tests/stmts/try_stmt/AST.ql @@ -0,0 +1,7 @@ + + +import python + +from AstNode parent, AstNode child +where child.getParentNode() = parent +select parent.getLocation().getStartLine(), parent.toString(), child.getLocation().getStartLine(), child.toString() \ No newline at end of file diff --git a/python/ql/test/library-tests/stmts/try_stmt/test.py b/python/ql/test/library-tests/stmts/try_stmt/test.py new file mode 100644 index 00000000000..f7d5b124c6d --- /dev/null +++ b/python/ql/test/library-tests/stmts/try_stmt/test.py @@ -0,0 +1,20 @@ + +def f(): + try: + call() + try: + nested() + except Exception: + return 1 + except: + return 2 + + try: + call2() + except Exception: + return 2 + + try: + call3a() + finally: + call3b() \ No newline at end of file diff --git a/python/ql/test/library-tests/stmts/with_stmt/AST.expected b/python/ql/test/library-tests/stmts/with_stmt/AST.expected new file mode 100644 index 00000000000..acae99eab4c --- /dev/null +++ b/python/ql/test/library-tests/stmts/with_stmt/AST.expected @@ -0,0 +1,20 @@ +| 0 | Module test | 2 | FunctionDef | +| 0 | Module test | 6 | FunctionDef | +| 2 | Function f | 3 | With | +| 2 | FunctionDef | 2 | FunctionExpr | +| 2 | FunctionDef | 2 | f | +| 2 | FunctionExpr | 2 | Function f | +| 3 | With | 3 | a | +| 3 | With | 4 | ExprStmt | +| 4 | ExprStmt | 4 | call() | +| 4 | call() | 4 | call | +| 6 | Function g | 7 | With | +| 6 | FunctionDef | 6 | FunctionExpr | +| 6 | FunctionDef | 6 | g | +| 6 | FunctionExpr | 6 | Function g | +| 7 | With | 7 | x | +| 7 | With | 8 | With | +| 8 | With | 8 | y | +| 8 | With | 9 | ExprStmt | +| 9 | ExprStmt | 9 | call() | +| 9 | call() | 9 | call | \ No newline at end of file diff --git a/python/ql/test/library-tests/stmts/with_stmt/AST.ql b/python/ql/test/library-tests/stmts/with_stmt/AST.ql new file mode 100644 index 00000000000..d9daaa8514b --- /dev/null +++ b/python/ql/test/library-tests/stmts/with_stmt/AST.ql @@ -0,0 +1,7 @@ + + +import python + +from AstNode parent, AstNode child +where child.getParentNode() = parent +select parent.getLocation().getStartLine(), parent.toString(), child.getLocation().getStartLine(), child.toString() \ No newline at end of file diff --git a/python/ql/test/library-tests/stmts/with_stmt/test.py b/python/ql/test/library-tests/stmts/with_stmt/test.py new file mode 100644 index 00000000000..4a19af00c05 --- /dev/null +++ b/python/ql/test/library-tests/stmts/with_stmt/test.py @@ -0,0 +1,9 @@ + +def f(): + with a: + call() + +def g(): + with x: + with y: + call() \ No newline at end of file diff --git a/python/ql/test/library-tests/taint/exception_traceback/TestNode.expected b/python/ql/test/library-tests/taint/exception_traceback/TestNode.expected new file mode 100644 index 00000000000..b0b2a23b14b --- /dev/null +++ b/python/ql/test/library-tests/taint/exception_traceback/TestNode.expected @@ -0,0 +1,27 @@ +| test.py:10:11:10:47 | test.py:10 | MyException() | exception.kind | +| test.py:15:25:15:25 | test.py:15 | e | exception.kind | +| test.py:16:13:16:34 | test.py:16 | Attribute() | exception.info | +| test.py:17:15:17:15 | test.py:17 | s | exception.info | +| test.py:19:13:19:36 | test.py:19 | Attribute() | [exception.info] | +| test.py:20:13:20:37 | test.py:20 | Attribute() | [exception.info] | +| test.py:21:13:21:36 | test.py:21 | Attribute() | [exception.info] | +| test.py:21:35:21:35 | test.py:21 | t | [exception.info] | +| test.py:22:13:22:58 | test.py:22 | Attribute() | [exception.info] | +| test.py:23:13:23:57 | test.py:23 | Attribute() | [exception.info] | +| test.py:24:13:24:35 | test.py:24 | Attribute() | [exception.info] | +| test.py:25:13:25:36 | test.py:25 | Attribute() | [exception.info] | +| test.py:26:25:26:25 | test.py:26 | e | exception.kind | +| test.py:26:25:26:33 | test.py:26 | Attribute | exception.info | +| test.py:26:25:26:41 | test.py:26 | Tuple | [[exception.info]] | +| test.py:26:25:26:41 | test.py:26 | Tuple | [exception.info] | +| test.py:26:36:26:36 | test.py:26 | e | exception.kind | +| test.py:26:36:26:41 | test.py:26 | Attribute | [exception.info] | +| test.py:27:19:27:19 | test.py:27 | t | [exception.info] | +| test.py:27:22:27:22 | test.py:27 | u | [exception.info] | +| test.py:27:25:27:25 | test.py:27 | v | [exception.info] | +| test.py:27:28:27:28 | test.py:27 | w | [exception.info] | +| test.py:27:31:27:31 | test.py:27 | x | [exception.info] | +| test.py:27:34:27:34 | test.py:27 | y | [exception.info] | +| test.py:27:37:27:37 | test.py:27 | z | [exception.info] | +| test.py:27:40:27:46 | test.py:27 | message | exception.info | +| test.py:27:49:27:52 | test.py:27 | args | [exception.info] | diff --git a/python/ql/test/library-tests/taint/exception_traceback/TestNode.ql b/python/ql/test/library-tests/taint/exception_traceback/TestNode.ql new file mode 100644 index 00000000000..b9ec3c2ff3e --- /dev/null +++ b/python/ql/test/library-tests/taint/exception_traceback/TestNode.ql @@ -0,0 +1,8 @@ +import python + +import semmle.python.security.Exceptions +import semmle.python.web.HttpResponse + +from TaintedNode node +where not node.getLocation().getFile().inStdlib() +select node.getLocation(), node.getNode().getNode().toString(), node.getTaintKind() \ No newline at end of file diff --git a/python/ql/test/library-tests/taint/exception_traceback/TestSource.expected b/python/ql/test/library-tests/taint/exception_traceback/TestSource.expected new file mode 100644 index 00000000000..e8b2074bc28 --- /dev/null +++ b/python/ql/test/library-tests/taint/exception_traceback/TestSource.expected @@ -0,0 +1,10 @@ +| test.py:10 | MyException() | exception.kind | +| test.py:15 | e | exception.kind | +| test.py:16 | Attribute() | exception.info | +| test.py:19 | Attribute() | [exception.info] | +| test.py:20 | Attribute() | [exception.info] | +| test.py:21 | Attribute() | [exception.info] | +| test.py:22 | Attribute() | [exception.info] | +| test.py:23 | Attribute() | [exception.info] | +| test.py:24 | Attribute() | [exception.info] | +| test.py:25 | Attribute() | [exception.info] | diff --git a/python/ql/test/library-tests/taint/exception_traceback/TestSource.ql b/python/ql/test/library-tests/taint/exception_traceback/TestSource.ql new file mode 100644 index 00000000000..8e625641b77 --- /dev/null +++ b/python/ql/test/library-tests/taint/exception_traceback/TestSource.ql @@ -0,0 +1,11 @@ +import python + +import semmle.python.security.Exceptions +import semmle.python.web.HttpResponse + + +from TaintSource src, TaintKind kind +where + src.isSourceOf(kind) and + not src.getLocation().getFile().inStdlib() +select src.getLocation().toString(), src.(ControlFlowNode).getNode().toString(), kind \ No newline at end of file diff --git a/python/ql/test/library-tests/taint/exception_traceback/TestStep.expected b/python/ql/test/library-tests/taint/exception_traceback/TestStep.expected new file mode 100644 index 00000000000..196c1e92c2c --- /dev/null +++ b/python/ql/test/library-tests/taint/exception_traceback/TestStep.expected @@ -0,0 +1,16 @@ +| Taint [exception.info] | test.py:19 | Attribute() | | --> | Taint [exception.info] | test.py:21 | t | | +| Taint [exception.info] | test.py:19 | Attribute() | | --> | Taint [exception.info] | test.py:27 | t | | +| Taint [exception.info] | test.py:20 | Attribute() | | --> | Taint [exception.info] | test.py:27 | u | | +| Taint [exception.info] | test.py:21 | Attribute() | | --> | Taint [exception.info] | test.py:27 | v | | +| Taint [exception.info] | test.py:22 | Attribute() | | --> | Taint [exception.info] | test.py:27 | w | | +| Taint [exception.info] | test.py:23 | Attribute() | | --> | Taint [exception.info] | test.py:27 | x | | +| Taint [exception.info] | test.py:24 | Attribute() | | --> | Taint [exception.info] | test.py:27 | y | | +| Taint [exception.info] | test.py:25 | Attribute() | | --> | Taint [exception.info] | test.py:27 | z | | +| Taint [exception.info] | test.py:26 | Attribute | | --> | Taint [[exception.info]] | test.py:26 | Tuple | | +| Taint [exception.info] | test.py:26 | Attribute | | --> | Taint [exception.info] | test.py:27 | args | | +| Taint exception.info | test.py:16 | Attribute() | | --> | Taint exception.info | test.py:17 | s | | +| Taint exception.info | test.py:26 | Attribute | | --> | Taint [exception.info] | test.py:26 | Tuple | | +| Taint exception.info | test.py:26 | Attribute | | --> | Taint exception.info | test.py:27 | message | | +| Taint exception.kind | test.py:15 | e | | --> | Taint exception.kind | test.py:26 | e | | +| Taint exception.kind | test.py:26 | e | | --> | Taint [exception.info] | test.py:26 | Attribute | | +| Taint exception.kind | test.py:26 | e | | --> | Taint exception.info | test.py:26 | Attribute | | diff --git a/python/ql/test/library-tests/taint/exception_traceback/TestStep.ql b/python/ql/test/library-tests/taint/exception_traceback/TestStep.ql new file mode 100644 index 00000000000..227cba3c293 --- /dev/null +++ b/python/ql/test/library-tests/taint/exception_traceback/TestStep.ql @@ -0,0 +1,14 @@ +import python + +import semmle.python.security.Exceptions +import semmle.python.web.HttpResponse + +from TaintedNode n, TaintedNode s +where + s = n.getASuccessor() and + not n.getLocation().getFile().inStdlib() and + not s.getLocation().getFile().inStdlib() +select + n.getTrackedValue(), n.getLocation().toString(), n.getNode().getNode().toString(), n.getContext(), + " --> ", + s.getTrackedValue(), s.getLocation().toString(), s.getNode().getNode().toString(), s.getContext() diff --git a/python/ql/test/library-tests/taint/exception_traceback/test.py b/python/ql/test/library-tests/taint/exception_traceback/test.py new file mode 100644 index 00000000000..37479bc63db --- /dev/null +++ b/python/ql/test/library-tests/taint/exception_traceback/test.py @@ -0,0 +1,30 @@ +from __future__ import print_function + +import traceback +import sys + +class MyException(Exception): + pass + +def raise_secret_exception(): + raise MyException("Message", "secret info") + +def foo(): + try: + raise_secret_exception() + except Exception as e: + s = traceback.format_exc() + print(s) + etype, evalue, tb = sys.exc_info() + t = traceback.extract_tb(tb) + u = traceback.extract_stack() + v = traceback.format_list(t) + w = traceback.format_exception_only(etype, evalue) + x = traceback.format_exception(etype, evalue, tb) + y = traceback.format_tb(tb) + z = traceback.format_stack() + message, args = e.message, e.args + print(tb, t, u, v, w, x, y, z, message, args) + + +foo() diff --git a/python/ql/test/library-tests/taint/extensions/ExtensionsLib.qll b/python/ql/test/library-tests/taint/extensions/ExtensionsLib.qll new file mode 100644 index 00000000000..9cbbc6f9e2d --- /dev/null +++ b/python/ql/test/library-tests/taint/extensions/ExtensionsLib.qll @@ -0,0 +1,94 @@ +import python + +import semmle.python.security.TaintTracking + +class SimpleTest extends TaintKind { + + SimpleTest() { + this = "simple.test" + } + +} + +class SimpleSink extends TaintSink { + + override string toString() { result = "Simple sink" } + + SimpleSink() { + exists(CallNode call | + call.getFunction().(NameNode).getId() = "SINK" and + this = call.getAnArg() + ) + } + + override predicate sinks(TaintKind taint) { + taint instanceof SimpleTest + } + +} + +class SimpleSource extends TaintSource { + + SimpleSource() { this.(NameNode).getId() = "SOURCE" } + + override predicate isSourceOf(TaintKind kind) { + kind instanceof SimpleTest + } + + override string toString() { + result = "simple.source" + } + +} + + +predicate visit_call(CallNode call, FunctionObject func) { + exists(AttrNode attr, ClassObject cls, string name | + name.prefix(6) = "visit_" and + func = cls.lookupAttribute(name) and + attr.getObject("visit").refersTo(_, cls, _) and + attr = call.getFunction() + ) +} + +/* Test call extensions by tracking taint through visitor methods */ + +class TestCallReturnExtension extends DataFlowExtension::DataFlowNode { + + TestCallReturnExtension() { + exists(PyFunctionObject func | + visit_call(_, func) and + this = func.getAReturnedNode() + ) + } + + override ControlFlowNode getAReturnSuccessorNode(CallNode call) { + exists(PyFunctionObject func | + visit_call(call, func) and + this = func.getAReturnedNode() and + result = call + ) + } + +} + +class TestCallParameterExtension extends DataFlowExtension::DataFlowNode { + + TestCallParameterExtension() { + exists(PyFunctionObject func, CallNode call | + visit_call(call, func) and + this = call.getAnArg() + ) + } + + override ControlFlowNode getACalleeSuccessorNode(CallNode call) { + exists(PyFunctionObject func | + visit_call(call, func) and + exists(int n | + this = call.getArg(n) and + result.getNode() = func.getFunction().getArg(n+1) + ) + ) + } + +} diff --git a/python/ql/test/library-tests/taint/extensions/TestNode.expected b/python/ql/test/library-tests/taint/extensions/TestNode.expected new file mode 100644 index 00000000000..3c0912519d2 --- /dev/null +++ b/python/ql/test/library-tests/taint/extensions/TestNode.expected @@ -0,0 +1,8 @@ +| Taint simple.test | visitor.py:10 | arg | visitor.py:26 | +| Taint simple.test | visitor.py:13 | arg | visitor.py:26 | +| Taint simple.test | visitor.py:18 | arg | visitor.py:26 | +| Taint simple.test | visitor.py:19 | arg | visitor.py:26 | +| Taint simple.test | visitor.py:21 | arg | visitor.py:26 | +| Taint simple.test | visitor.py:26 | Attribute() | | +| Taint simple.test | visitor.py:26 | SOURCE | | +| Taint simple.test | visitor.py:27 | x | | diff --git a/python/ql/test/library-tests/taint/extensions/TestNode.ql b/python/ql/test/library-tests/taint/extensions/TestNode.ql new file mode 100644 index 00000000000..11f697a8bfe --- /dev/null +++ b/python/ql/test/library-tests/taint/extensions/TestNode.ql @@ -0,0 +1,8 @@ +import python + +import ExtensionsLib + + +from TaintedNode n +select n.getTrackedValue(), n.getLocation().toString(), n.getNode().getNode().toString(), n.getContext() + diff --git a/python/ql/test/library-tests/taint/extensions/TestStep.expected b/python/ql/test/library-tests/taint/extensions/TestStep.expected new file mode 100644 index 00000000000..382aabc3ae7 --- /dev/null +++ b/python/ql/test/library-tests/taint/extensions/TestStep.expected @@ -0,0 +1,7 @@ +| Taint simple.test | visitor.py:10 | arg | visitor.py:26 | --> | Taint simple.test | visitor.py:13 | arg | visitor.py:26 | +| Taint simple.test | visitor.py:18 | arg | visitor.py:26 | --> | Taint simple.test | visitor.py:19 | arg | visitor.py:26 | +| Taint simple.test | visitor.py:19 | arg | visitor.py:26 | --> | Taint simple.test | visitor.py:26 | Attribute() | | +| Taint simple.test | visitor.py:26 | Attribute() | | --> | Taint simple.test | visitor.py:27 | x | | +| Taint simple.test | visitor.py:26 | SOURCE | | --> | Taint simple.test | visitor.py:10 | arg | visitor.py:26 | +| Taint simple.test | visitor.py:26 | SOURCE | | --> | Taint simple.test | visitor.py:18 | arg | visitor.py:26 | +| Taint simple.test | visitor.py:26 | SOURCE | | --> | Taint simple.test | visitor.py:21 | arg | visitor.py:26 | diff --git a/python/ql/test/library-tests/taint/extensions/TestStep.ql b/python/ql/test/library-tests/taint/extensions/TestStep.ql new file mode 100644 index 00000000000..4623101a957 --- /dev/null +++ b/python/ql/test/library-tests/taint/extensions/TestStep.ql @@ -0,0 +1,11 @@ +import python + +import ExtensionsLib + + +from TaintedNode n, TaintedNode s +where s = n.getASuccessor() +select + n.getTrackedValue(), n.getLocation().toString(), n.getNode().getNode().toString(), n.getContext(), + " --> ", + s.getTrackedValue(), s.getLocation().toString(), s.getNode().getNode().toString(), s.getContext() diff --git a/python/ql/test/library-tests/taint/extensions/visitor.py b/python/ql/test/library-tests/taint/extensions/visitor.py new file mode 100644 index 00000000000..c68867319ef --- /dev/null +++ b/python/ql/test/library-tests/taint/extensions/visitor.py @@ -0,0 +1,27 @@ + + +class Visitor(object): + '''Visitor pattern ''' + + def __init__(self, labels): + self.labels = labels + self.priority = 0 + + def visit(self, node, arg): + """Visit a node.""" + method = 'visit_' + node.__class__.__name__ + getattr(self, method, self.generic_visit)(node, arg) + + def generic_visit(self, node, arg): + pass + + def visit_Class(self, node, arg): + return arg + + def visit_Function(self, func, arg): + pass + +v = Visitor() + +x = v.visit(dont_care, SOURCE) +x diff --git a/python/ql/test/library-tests/taint/general/Contexts.expected b/python/ql/test/library-tests/taint/general/Contexts.expected new file mode 100644 index 00000000000..e78a0d94abd --- /dev/null +++ b/python/ql/test/library-tests/taint/general/Contexts.expected @@ -0,0 +1,31 @@ +| carrier.py:17 | Function __init__ | +| carrier.py:25 | Function __init__ | +| carrier.py:25 | Function hub | +| carrier.py:29 | Function hub | +| carrier.py:33 | Function __init__ | +| deep.py:6 from deep.py:9 from deep.py:12 from deep.py:15 from deep.py:18 from deep.py:20 | Function f1 | +| deep.py:9 from deep.py:12 from deep.py:15 from deep.py:18 from deep.py:20 | Function f2 | +| deep.py:12 from deep.py:15 from deep.py:18 from deep.py:20 | Function f3 | +| deep.py:15 from deep.py:18 from deep.py:20 | Function f4 | +| deep.py:18 from deep.py:20 | Function f5 | +| deep.py:20 | Function f6 | +| rockpaperscissors.py:13 | Function rock | +| rockpaperscissors.py:16 | Function paper | +| rockpaperscissors.py:21 | Function scissors | +| rockpaperscissors.py:26 | Function scissors | +| rockpaperscissors.py:31 | Function paper | +| rockpaperscissors.py:32 | Function paper | +| sanitizer.py:10 | Function isEscapedSql | +| sanitizer.py:17 | Function isValidCommand | +| test.py:21 | Function sink | +| test.py:25 | Function sink | +| test.py:47 from test.py:55 | Function sink | +| test.py:51 from test.py:63 | Function sink | +| test.py:51 from test.py:70 | Function sink | +| test.py:55 | Function sink2 | +| test.py:63 | Function sink3 | +| test.py:70 | Function sink3 | +| test.py:77 | Function hub | +| test.py:116 | Function hub | +| test.py:117 | Function x_sink | +| test.py:121 | Function hub | diff --git a/python/ql/test/library-tests/taint/general/Contexts.ql b/python/ql/test/library-tests/taint/general/Contexts.ql new file mode 100644 index 00000000000..c0a63c5f228 --- /dev/null +++ b/python/ql/test/library-tests/taint/general/Contexts.ql @@ -0,0 +1,9 @@ + +import python +import semmle.python.security.TaintTest +import TaintLib + +from CallContext context, Scope s +where exists(CallContext caller | caller.getCallee(_) = context) and context.appliesToScope(s) +select context, s.toString() + diff --git a/python/ql/test/library-tests/taint/general/ModuleAttribute.expected b/python/ql/test/library-tests/taint/general/ModuleAttribute.expected new file mode 100644 index 00000000000..b13f01db429 --- /dev/null +++ b/python/ql/test/library-tests/taint/general/ModuleAttribute.expected @@ -0,0 +1,4 @@ +| Module deep | x | Taint simple.test | | deep.py:20 | +| Module module | dangerous | Taint simple.test | | module.py:3 | +| Module test | module | Attribute 'dangerous' taint simple.test | | test.py:85 | +| Module test | unsafe | Taint simple.test | | test.py:155 | diff --git a/python/ql/test/library-tests/taint/general/ModuleAttribute.ql b/python/ql/test/library-tests/taint/general/ModuleAttribute.ql new file mode 100644 index 00000000000..6daca6cda1b --- /dev/null +++ b/python/ql/test/library-tests/taint/general/ModuleAttribute.ql @@ -0,0 +1,10 @@ +import python +import semmle.python.security.TaintTest +import TaintLib + + +from ModuleObject m, string name, TaintedNode origin + +where TaintFlowTest::module_attribute_tainted(m, name, origin) + +select m.toString(), name, origin.getTrackedValue(), origin.getContext(), origin.getLocation().toString() diff --git a/python/ql/test/library-tests/taint/general/ParamSource.expected b/python/ql/test/library-tests/taint/general/ParamSource.expected new file mode 100644 index 00000000000..d085cd7d178 --- /dev/null +++ b/python/ql/test/library-tests/taint/general/ParamSource.expected @@ -0,0 +1,6 @@ +| test | carrier.py:4 | 18 | Attribute | test | +| test | test.py:12 | 13 | arg | test | +| test | test.py:46 | 13 | arg | test | +| test | test.py:49 | 13 | arg | test | +| test | test.py:72 | 78 | t | test | +| test | test.py:72 | 83 | t | test | diff --git a/python/ql/test/library-tests/taint/general/ParamSource.ql b/python/ql/test/library-tests/taint/general/ParamSource.ql new file mode 100644 index 00000000000..664fd8b77e5 --- /dev/null +++ b/python/ql/test/library-tests/taint/general/ParamSource.ql @@ -0,0 +1,53 @@ +import python +import semmle.python.security.TaintTracking + +/* Standard library sink */ +import semmle.python.security.injection.Command + +class TestKind extends TaintKind { + TestKind() { + this = "test" + } + +} + +class CustomSource extends TaintSource { + + CustomSource() { + exists(Parameter p | + p.asName().getId() = "arg" and + this.(ControlFlowNode).getNode() = p + ) + } + + override predicate isSourceOf(TaintKind kind) { + kind instanceof TestKind + } + + override string toString() { + result = "Source of untrusted input" + } + +} + +class SimpleSink extends TaintSink { + + override string toString() { result = "Simple sink" } + + SimpleSink() { + exists(CallNode call | + call.getFunction().(NameNode).getId() = "SINK" and + this = call.getAnArg() + ) + } + + override predicate sinks(TaintKind taint) { + taint instanceof TestKind + } + +} + +from TaintSource src, TaintSink sink, TaintKind srckind, TaintKind sinkkind + +where src.flowsToSink(srckind, sink) and sink.sinks(sinkkind) +select srckind, src.getLocation().toString(), sink.getLocation().getStartLine(), sink.(ControlFlowNode).getNode().toString(), sinkkind diff --git a/python/ql/test/library-tests/taint/general/TaintLib.qll b/python/ql/test/library-tests/taint/general/TaintLib.qll new file mode 100644 index 00000000000..6eae51f8c48 --- /dev/null +++ b/python/ql/test/library-tests/taint/general/TaintLib.qll @@ -0,0 +1,336 @@ +import python +import semmle.python.security.TaintTracking + + +class SimpleTest extends TaintKind { + + SimpleTest() { + this = "simple.test" + } + +} + +class SimpleSink extends TaintSink { + + override string toString() { result = "Simple sink" } + + SimpleSink() { + exists(CallNode call | + call.getFunction().(NameNode).getId() = "SINK" and + this = call.getAnArg() + ) + } + + override predicate sinks(TaintKind taint) { + taint instanceof SimpleTest + } + +} + +class SimpleSource extends TaintSource { + + SimpleSource() { this.(NameNode).getId() = "SOURCE" } + + override predicate isSourceOf(TaintKind kind) { + kind instanceof SimpleTest + } + + override string toString() { + result = "simple.source" + } + +} + +class SimpleSanitizer extends Sanitizer { + + SimpleSanitizer() { this = "Simple sanitizer" } + + override predicate sanitizingNode(TaintKind taint, ControlFlowNode node) { + node.(CallNode).getFunction().(NameNode).getId() = "SANITIZE" and + taint instanceof SimpleTest + } + +} + +class BasicCustomTaint extends TaintKind { + + BasicCustomTaint() { + this = "basic.custom" + } + + override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { + tonode.(CallNode).getAnArg() = fromnode and + tonode.(CallNode).getFunction().(NameNode).getId() = "TAINT_FROM_ARG" and + result = this + } + +} + +class BasicCustomSink extends TaintSink { + + override string toString() { result = "Basic custom sink" } + + BasicCustomSink() { + exists(CallNode call | + call.getFunction().(NameNode).getId() = "CUSTOM_SINK" and + this = call.getAnArg() + ) + } + + override predicate sinks(TaintKind taint) { + taint instanceof BasicCustomTaint + } + +} + + +class BasicCustomSource extends TaintSource { + + BasicCustomSource() { this.(NameNode).getId() = "CUSTOM_SOURCE" } + + override predicate isSourceOf(TaintKind kind) { + kind instanceof BasicCustomTaint + } + + override string toString() { + result = "basic.custom.source" + } + +} + +class Rock extends TaintKind { + + Rock() { this = "rock" } + + override TaintKind getTaintOfMethodResult(string name) { + name = "prev" and result instanceof Scissors + } + + predicate isSink(ControlFlowNode sink) { + exists(CallNode call | + call.getArg(0) = sink and + call.getFunction().(NameNode).getId() = "paper" + ) + } + +} + +class Paper extends TaintKind { + + Paper() { this = "paper" } + + override TaintKind getTaintOfMethodResult(string name) { + name = "prev" and result instanceof Rock + } + + predicate isSink(ControlFlowNode sink) { + exists(CallNode call | + call.getArg(0) = sink and + call.getFunction().(NameNode).getId() = "scissors" + ) + } + +} + +class Scissors extends TaintKind { + + Scissors() { this = "scissors" } + + override TaintKind getTaintOfMethodResult(string name) { + name = "prev" and result instanceof Paper + } + + predicate isSink(ControlFlowNode sink) { + exists(CallNode call | + call.getArg(0) = sink and + call.getFunction().(NameNode).getId() = "rock" + ) + } + +} + +class RockPaperScissorSource extends TaintSource { + + RockPaperScissorSource() { + exists(string name | + this.(NameNode).getId() = name | + name = "ROCK" or name = "PAPER" or name = "SCISSORS" + ) + } + + override predicate isSourceOf(TaintKind kind) { + kind = this.(NameNode).getId().toLowerCase() + } + + override string toString() { + result = "rock.paper.scissors.source" + } + +} + +private predicate function_param(string funcname, ControlFlowNode arg) { + exists(FunctionObject f | + f.getName() = funcname and + arg = f.getArgumentForCall(_, _) + ) +} + +class RockPaperScissorSink extends TaintSink { + + RockPaperScissorSink() { + exists(string name | + function_param(name, this) | + name = "rock" or name = "paper" or name = "scissors" + ) + } + + override predicate sinks(TaintKind taint) { + exists(string name | + function_param(name, this) | + name = "paper" and taint = "rock" + or + name = "rock" and taint = "scissors" + or + name = "scissors" and taint = "paper" + ) + } + + override string toString() { + result = "rock.paper.scissors.sink" + } + +} + +class TaintCarrier extends TaintKind { + + TaintCarrier() { this = "explicit.carrier" } + + override TaintKind getTaintOfMethodResult(string name) { + name = "get_taint" and result instanceof SimpleTest + } + + +} + +/* There is no sink for `TaintCarrier`. It is not "dangerous" in itself; it merely holds a `SimpleTest`. */ +class TaintCarrierSource extends TaintSource { + + TaintCarrierSource() { + this.(NameNode).getId() = "TAINT_CARRIER_SOURCE" + } + + override predicate isSourceOf(TaintKind kind) { + kind instanceof TaintCarrier + } + + override string toString() { + result = "taint.carrier.source" + } +} + + +/* Some more realistic examples */ + +abstract class UserInput extends TaintKind { + + bindingset[this] + UserInput() { any() } + +} + +class UserInputSource extends TaintSource { + + UserInputSource() { + this.(CallNode).getFunction().(NameNode).getId() = "user_input" + } + + override predicate isSourceOf(TaintKind kind) { + kind instanceof UserInput + } + + override string toString() { + result = "user.input.source" + } + +} + +class SqlInjectionTaint extends UserInput { + + SqlInjectionTaint() { this = "SQL injection" } + +} + +class CommandInjectionTaint extends UserInput { + + CommandInjectionTaint() { this = "Command injection" } + +} + +class SqlSanitizer extends Sanitizer { + + SqlSanitizer() { this = "SQL sanitizer" } + + /** Holds if `test` shows value to be untainted with `taint` */ + override predicate sanitizingEdge(TaintKind taint, PyEdgeRefinement test) { + exists(FunctionObject f, CallNode call | + f.getName() = "isEscapedSql" and + test.getTest() = call and + call.getAnArg() = test.getSourceVariable().getAUse() and + f.getACall() = call and + test.getSense() = true + ) and + taint instanceof SqlInjectionTaint + } + +} + +class CommandSanitizer extends Sanitizer { + + CommandSanitizer() { this = "Command sanitizer" } + + /** Holds if `test` shows value to be untainted with `taint` */ + override predicate sanitizingEdge(TaintKind taint, PyEdgeRefinement test) { + exists(FunctionObject f | + f.getName() = "isValidCommand" and + f.getACall().(CallNode).getAnArg() = test.getSourceVariable().getAUse() and + test.getSense() = true + ) and + taint instanceof CommandInjectionTaint + } + +} + +class SqlQuery extends TaintSink { + + SqlQuery() { + exists(CallNode call | + call.getFunction().(NameNode).getId() = "sql_query" and + call.getAnArg() = this + ) + } + + override string toString() { result = "SQL query" } + + override predicate sinks(TaintKind taint) { + taint instanceof SqlInjectionTaint + } + +} + + +class OsCommand extends TaintSink { + + OsCommand() { + exists(CallNode call | + call.getFunction().(NameNode).getId() = "os_command" and + call.getAnArg() = this + ) + } + + override string toString() { result = "OS command" } + + override predicate sinks(TaintKind taint) { + taint instanceof CommandInjectionTaint + } + +} diff --git a/python/ql/test/library-tests/taint/general/TaintSanity.expected b/python/ql/test/library-tests/taint/general/TaintSanity.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/library-tests/taint/general/TaintSanity.ql b/python/ql/test/library-tests/taint/general/TaintSanity.ql new file mode 100644 index 00000000000..394c39ce491 --- /dev/null +++ b/python/ql/test/library-tests/taint/general/TaintSanity.ql @@ -0,0 +1,26 @@ +import python +import semmle.python.security.TaintTest +import TaintLib + +from TaintFlowTest::TrackedValue taint, CallContext c, ControlFlowNode n, string what +where +not exists(TaintedNode t | t.getTrackedValue() = taint and t.getNode() = n and t.getContext() = c) and +( + TaintFlowTest::step(_, taint, c, n) and what = "missing node at end of step" + or + n.(TaintSource).isSourceOf(taint.(TaintFlowTest::TrackedTaint).getKind(), c) and what = "missing node for source" + +) +or +exists(TaintedNode t | t.getTrackedValue() = taint and t.getNode() = n and t.getContext() = c + | + not TaintFlowTest::step(_, taint, c, n) and + not n.(TaintSource).isSourceOf(taint.(TaintFlowTest::TrackedTaint).getKind(), c) and what = "TaintedNode with no reason" + or + TaintFlowTest::step(t, taint, c, n) and what = "step ends where it starts" + or + TaintFlowTest::step(t, _, _, _) and not TaintFlowTest::step(_, taint, c, n) and + not n.(TaintSource).isSourceOf(taint.(TaintFlowTest::TrackedTaint).getKind(), c) and what = "No predecessor and not a source" +) + +select n.getLocation(), taint, c, n.toString(), what diff --git a/python/ql/test/library-tests/taint/general/TestNode.expected b/python/ql/test/library-tests/taint/general/TestNode.expected new file mode 100644 index 00000000000..c7ae50289a0 --- /dev/null +++ b/python/ql/test/library-tests/taint/general/TestNode.expected @@ -0,0 +1,222 @@ +| Attribute 'attr' taint explicit.carrier | carrier.py:5 | self | carrier.py:33 | +| Attribute 'attr' taint explicit.carrier | carrier.py:33 | ImplicitCarrier() | | +| Attribute 'attr' taint explicit.carrier | carrier.py:34 | c | | +| Attribute 'attr' taint simple.test | carrier.py:5 | self | carrier.py:17 | +| Attribute 'attr' taint simple.test | carrier.py:5 | self | carrier.py:25 | +| Attribute 'attr' taint simple.test | carrier.py:13 | arg | carrier.py:25 | +| Attribute 'attr' taint simple.test | carrier.py:14 | arg | carrier.py:25 | +| Attribute 'attr' taint simple.test | carrier.py:17 | ImplicitCarrier() | | +| Attribute 'attr' taint simple.test | carrier.py:18 | c | | +| Attribute 'attr' taint simple.test | carrier.py:25 | ImplicitCarrier() | | +| Attribute 'attr' taint simple.test | carrier.py:25 | hub() | | +| Attribute 'attr' taint simple.test | carrier.py:26 | c | | +| Attribute 'dangerous' taint simple.test | test.py:85 | ImportExpr | | +| Attribute 'dangerous' taint simple.test | test.py:88 | module | | +| Attribute 'dangerous' taint simple.test | test.py:92 | module | | +| Attribute 'dangerous' taint simple.test | test.py:96 | module | | +| Attribute 'dangerous' taint simple.test | test.py:100 | module | | +| Attribute 'dangerous' taint simple.test | test.py:110 | module | | +| Attribute 'dangerous' taint simple.test | test.py:115 | module | | +| Attribute 'dangerous' taint simple.test | test.py:155 | ImportExpr | | +| Attribute 'x' taint simple.test | test.py:72 | arg | test.py:116 | +| Attribute 'x' taint simple.test | test.py:73 | arg | test.py:116 | +| Attribute 'x' taint simple.test | test.py:105 | arg | test.py:117 | +| Attribute 'x' taint simple.test | test.py:106 | arg | test.py:117 | +| Attribute 'x' taint simple.test | test.py:110 | t | | +| Attribute 'x' taint simple.test | test.py:111 | t | | +| Attribute 'x' taint simple.test | test.py:115 | t | | +| Attribute 'x' taint simple.test | test.py:116 | hub() | | +| Attribute 'x' taint simple.test | test.py:116 | t | | +| Attribute 'x' taint simple.test | test.py:117 | t | | +| Taint Command injection | sanitizer.py:3 | arg | sanitizer.py:10 | +| Taint Command injection | sanitizer.py:5 | arg | sanitizer.py:17 | +| Taint Command injection | sanitizer.py:9 | user_input() | | +| Taint Command injection | sanitizer.py:10 | x | | +| Taint Command injection | sanitizer.py:11 | x | | +| Taint Command injection | sanitizer.py:13 | x | | +| Taint Command injection | sanitizer.py:16 | user_input() | | +| Taint Command injection | sanitizer.py:17 | x | | +| Taint Command injection | sanitizer.py:20 | x | | +| Taint Command injection | sanitizer.py:24 | user_input() | | +| Taint Command injection | sanitizer.py:25 | x | | +| Taint Command injection | sanitizer.py:26 | x | | +| Taint Command injection | sanitizer.py:28 | x | | +| Taint Command injection | sanitizer.py:31 | user_input() | | +| Taint Command injection | sanitizer.py:32 | x | | +| Taint Command injection | sanitizer.py:33 | x | | +| Taint Command injection | sanitizer.py:35 | x | | +| Taint SQL injection | sanitizer.py:3 | arg | sanitizer.py:10 | +| Taint SQL injection | sanitizer.py:5 | arg | sanitizer.py:17 | +| Taint SQL injection | sanitizer.py:9 | user_input() | | +| Taint SQL injection | sanitizer.py:10 | x | | +| Taint SQL injection | sanitizer.py:13 | x | | +| Taint SQL injection | sanitizer.py:16 | user_input() | | +| Taint SQL injection | sanitizer.py:17 | x | | +| Taint SQL injection | sanitizer.py:18 | x | | +| Taint SQL injection | sanitizer.py:20 | x | | +| Taint SQL injection | sanitizer.py:24 | user_input() | | +| Taint SQL injection | sanitizer.py:25 | x | | +| Taint SQL injection | sanitizer.py:26 | x | | +| Taint SQL injection | sanitizer.py:28 | x | | +| Taint SQL injection | sanitizer.py:31 | user_input() | | +| Taint SQL injection | sanitizer.py:32 | x | | +| Taint SQL injection | sanitizer.py:33 | x | | +| Taint SQL injection | sanitizer.py:35 | x | | +| Taint [simple.test] | test.py:168 | List | | +| Taint [simple.test] | test.py:170 | l | | +| Taint [simple.test] | test.py:172 | x | | +| Taint [simple.test] | test.py:174 | l | | +| Taint [simple.test] | test.py:174 | list() | | +| Taint basic.custom | test.py:72 | arg | test.py:121 | +| Taint basic.custom | test.py:73 | arg | test.py:121 | +| Taint basic.custom | test.py:120 | CUSTOM_SOURCE | | +| Taint basic.custom | test.py:121 | TAINT_FROM_ARG() | | +| Taint basic.custom | test.py:121 | hub() | | +| Taint basic.custom | test.py:121 | t | | +| Taint basic.custom | test.py:122 | t | | +| Taint basic.custom | test.py:126 | CUSTOM_SOURCE | | +| Taint basic.custom | test.py:130 | t | | +| Taint basic.custom | test.py:136 | CUSTOM_SOURCE | | +| Taint basic.custom | test.py:142 | t | | +| Taint basic.custom | test.py:146 | CUSTOM_SOURCE | | +| Taint basic.custom | test.py:149 | TAINT_FROM_ARG() | | +| Taint basic.custom | test.py:149 | t | | +| Taint basic.custom | test.py:151 | t | | +| Taint explicit.carrier | carrier.py:4 | arg | carrier.py:33 | +| Taint explicit.carrier | carrier.py:5 | arg | carrier.py:33 | +| Taint explicit.carrier | carrier.py:13 | arg | carrier.py:29 | +| Taint explicit.carrier | carrier.py:14 | arg | carrier.py:29 | +| Taint explicit.carrier | carrier.py:21 | TAINT_CARRIER_SOURCE | | +| Taint explicit.carrier | carrier.py:22 | c | | +| Taint explicit.carrier | carrier.py:29 | TAINT_CARRIER_SOURCE | | +| Taint explicit.carrier | carrier.py:29 | hub() | | +| Taint explicit.carrier | carrier.py:30 | c | | +| Taint explicit.carrier | carrier.py:33 | TAINT_CARRIER_SOURCE | | +| Taint explicit.carrier | carrier.py:34 | Attribute | | +| Taint explicit.carrier | carrier.py:35 | x | | +| Taint paper | rockpaperscissors.py:6 | arg | rockpaperscissors.py:32 | +| Taint paper | rockpaperscissors.py:9 | arg | rockpaperscissors.py:26 | +| Taint paper | rockpaperscissors.py:25 | Attribute() | | +| Taint paper | rockpaperscissors.py:26 | y | | +| Taint paper | rockpaperscissors.py:30 | Attribute() | | +| Taint paper | rockpaperscissors.py:32 | y | | +| Taint rock | rockpaperscissors.py:6 | arg | rockpaperscissors.py:16 | +| Taint rock | rockpaperscissors.py:16 | ROCK | | +| Taint rock | rockpaperscissors.py:19 | ROCK | | +| Taint rock | rockpaperscissors.py:20 | x | | +| Taint rock | rockpaperscissors.py:24 | ROCK | | +| Taint rock | rockpaperscissors.py:25 | x | | +| Taint scissors | rockpaperscissors.py:3 | arg | rockpaperscissors.py:13 | +| Taint scissors | rockpaperscissors.py:6 | arg | rockpaperscissors.py:31 | +| Taint scissors | rockpaperscissors.py:9 | arg | rockpaperscissors.py:21 | +| Taint scissors | rockpaperscissors.py:13 | SCISSORS | | +| Taint scissors | rockpaperscissors.py:20 | Attribute() | | +| Taint scissors | rockpaperscissors.py:21 | y | | +| Taint scissors | rockpaperscissors.py:25 | Attribute() | | +| Taint scissors | rockpaperscissors.py:29 | SCISSORS | | +| Taint scissors | rockpaperscissors.py:30 | x | | +| Taint scissors | rockpaperscissors.py:31 | x | | +| Taint simple.test | carrier.py:4 | arg | carrier.py:17 | +| Taint simple.test | carrier.py:4 | arg | carrier.py:25 | +| Taint simple.test | carrier.py:5 | arg | carrier.py:17 | +| Taint simple.test | carrier.py:5 | arg | carrier.py:25 | +| Taint simple.test | carrier.py:17 | SOURCE | | +| Taint simple.test | carrier.py:18 | Attribute | | +| Taint simple.test | carrier.py:22 | Attribute() | | +| Taint simple.test | carrier.py:25 | SOURCE | | +| Taint simple.test | carrier.py:30 | Attribute() | | +| Taint simple.test | carrier.py:35 | Attribute() | | +| Taint simple.test | deep.py:2 | arg | deep.py:6 from deep.py:9 from deep.py:12 from deep.py:15 from deep.py:18 from deep.py:20 | +| Taint simple.test | deep.py:3 | arg | deep.py:6 from deep.py:9 from deep.py:12 from deep.py:15 from deep.py:18 from deep.py:20 | +| Taint simple.test | deep.py:5 | arg | deep.py:9 from deep.py:12 from deep.py:15 from deep.py:18 from deep.py:20 | +| Taint simple.test | deep.py:6 | arg | deep.py:9 from deep.py:12 from deep.py:15 from deep.py:18 from deep.py:20 | +| Taint simple.test | deep.py:6 | f1() | deep.py:9 from deep.py:12 from deep.py:15 from deep.py:18 from deep.py:20 | +| Taint simple.test | deep.py:8 | arg | deep.py:12 from deep.py:15 from deep.py:18 from deep.py:20 | +| Taint simple.test | deep.py:9 | arg | deep.py:12 from deep.py:15 from deep.py:18 from deep.py:20 | +| Taint simple.test | deep.py:9 | f2() | deep.py:12 from deep.py:15 from deep.py:18 from deep.py:20 | +| Taint simple.test | deep.py:11 | arg | deep.py:15 from deep.py:18 from deep.py:20 | +| Taint simple.test | deep.py:12 | arg | deep.py:15 from deep.py:18 from deep.py:20 | +| Taint simple.test | deep.py:12 | f3() | deep.py:15 from deep.py:18 from deep.py:20 | +| Taint simple.test | deep.py:14 | arg | deep.py:18 from deep.py:20 | +| Taint simple.test | deep.py:15 | arg | deep.py:18 from deep.py:20 | +| Taint simple.test | deep.py:15 | f4() | deep.py:18 from deep.py:20 | +| Taint simple.test | deep.py:17 | arg | deep.py:20 | +| Taint simple.test | deep.py:18 | arg | deep.py:20 | +| Taint simple.test | deep.py:18 | f5() | deep.py:20 | +| Taint simple.test | deep.py:20 | SOURCE | | +| Taint simple.test | deep.py:20 | f6() | | +| Taint simple.test | deep.py:22 | x | | +| Taint simple.test | module.py:3 | SOURCE | | +| Taint simple.test | module.py:7 | SOURCE | | +| Taint simple.test | module.py:10 | SOURCE | | +| Taint simple.test | test.py:3 | SOURCE | | +| Taint simple.test | test.py:6 | SOURCE | | +| Taint simple.test | test.py:7 | s | | +| Taint simple.test | test.py:10 | SOURCE | | +| Taint simple.test | test.py:12 | arg | test.py:21 | +| Taint simple.test | test.py:12 | arg | test.py:25 | +| Taint simple.test | test.py:12 | arg | test.py:47 from test.py:55 | +| Taint simple.test | test.py:12 | arg | test.py:51 from test.py:63 | +| Taint simple.test | test.py:12 | arg | test.py:51 from test.py:70 | +| Taint simple.test | test.py:13 | arg | test.py:21 | +| Taint simple.test | test.py:13 | arg | test.py:25 | +| Taint simple.test | test.py:13 | arg | test.py:47 from test.py:55 | +| Taint simple.test | test.py:13 | arg | test.py:51 from test.py:63 | +| Taint simple.test | test.py:13 | arg | test.py:51 from test.py:70 | +| Taint simple.test | test.py:16 | source() | | +| Taint simple.test | test.py:17 | t | | +| Taint simple.test | test.py:20 | SOURCE | | +| Taint simple.test | test.py:21 | t | | +| Taint simple.test | test.py:24 | source() | | +| Taint simple.test | test.py:25 | t | | +| Taint simple.test | test.py:31 | SOURCE | | +| Taint simple.test | test.py:37 | SOURCE | | +| Taint simple.test | test.py:41 | t | | +| Taint simple.test | test.py:44 | source() | | +| Taint simple.test | test.py:46 | arg | test.py:55 | +| Taint simple.test | test.py:47 | arg | test.py:55 | +| Taint simple.test | test.py:49 | arg | test.py:63 | +| Taint simple.test | test.py:49 | arg | test.py:70 | +| Taint simple.test | test.py:51 | arg | test.py:63 | +| Taint simple.test | test.py:51 | arg | test.py:70 | +| Taint simple.test | test.py:54 | source2() | | +| Taint simple.test | test.py:55 | t | | +| Taint simple.test | test.py:62 | SOURCE | | +| Taint simple.test | test.py:63 | t | | +| Taint simple.test | test.py:67 | SOURCE | | +| Taint simple.test | test.py:70 | t | | +| Taint simple.test | test.py:72 | arg | test.py:77 | +| Taint simple.test | test.py:73 | arg | test.py:77 | +| Taint simple.test | test.py:76 | SOURCE | | +| Taint simple.test | test.py:77 | hub() | | +| Taint simple.test | test.py:77 | t | | +| Taint simple.test | test.py:78 | t | | +| Taint simple.test | test.py:88 | Attribute | | +| Taint simple.test | test.py:89 | t | | +| Taint simple.test | test.py:100 | Attribute() | | +| Taint simple.test | test.py:101 | t | | +| Taint simple.test | test.py:106 | Attribute | test.py:117 | +| Taint simple.test | test.py:110 | Attribute | | +| Taint simple.test | test.py:111 | Attribute | | +| Taint simple.test | test.py:115 | Attribute | | +| Taint simple.test | test.py:128 | SOURCE | | +| Taint simple.test | test.py:132 | t | | +| Taint simple.test | test.py:138 | SOURCE | | +| Taint simple.test | test.py:140 | t | | +| Taint simple.test | test.py:148 | SOURCE | | +| Taint simple.test | test.py:149 | t | | +| Taint simple.test | test.py:155 | ImportMember | | +| Taint simple.test | test.py:156 | unsafe | | +| Taint simple.test | test.py:159 | SOURCE | | +| Taint simple.test | test.py:160 | t | | +| Taint simple.test | test.py:163 | SOURCE | | +| Taint simple.test | test.py:164 | s | | +| Taint simple.test | test.py:168 | SOURCE | | +| Taint simple.test | test.py:169 | SOURCE | | +| Taint simple.test | test.py:172 | Subscript | | +| Taint simple.test | test.py:173 | Subscript | | +| Taint {simple.test} | test.py:169 | Dict | | +| Taint {simple.test} | test.py:171 | d | | +| Taint {simple.test} | test.py:173 | y | | +| Taint {simple.test} | test.py:175 | d | | +| Taint {simple.test} | test.py:175 | dict() | | diff --git a/python/ql/test/library-tests/taint/general/TestNode.ql b/python/ql/test/library-tests/taint/general/TestNode.ql new file mode 100644 index 00000000000..967d70e51c1 --- /dev/null +++ b/python/ql/test/library-tests/taint/general/TestNode.ql @@ -0,0 +1,8 @@ +import python +import semmle.python.security.TaintTracking +import TaintLib + + +from TaintedNode n +select n.getTrackedValue(), n.getLocation().toString(), n.getNode().getNode().toString(), n.getContext() + diff --git a/python/ql/test/library-tests/taint/general/TestSanitizers.expected b/python/ql/test/library-tests/taint/general/TestSanitizers.expected new file mode 100644 index 00000000000..2e5b0e4a75e --- /dev/null +++ b/python/ql/test/library-tests/taint/general/TestSanitizers.expected @@ -0,0 +1,2 @@ +| Command sanitizer | Command injection | sanitizer.py:18 | Pi(x_1) [true] | +| SQL sanitizer | SQL injection | sanitizer.py:11 | Pi(x_1) [true] | diff --git a/python/ql/test/library-tests/taint/general/TestSanitizers.ql b/python/ql/test/library-tests/taint/general/TestSanitizers.ql new file mode 100644 index 00000000000..3dca04d581e --- /dev/null +++ b/python/ql/test/library-tests/taint/general/TestSanitizers.ql @@ -0,0 +1,10 @@ + +import python +import semmle.python.security.TaintTracking +import TaintLib + +from Sanitizer s, TaintKind taint, PyEdgeRefinement test +where s.sanitizingEdge(taint, test) +select s, taint, test.getLocation().toString(), test.getRepresentation() + + diff --git a/python/ql/test/library-tests/taint/general/TestSink.expected b/python/ql/test/library-tests/taint/general/TestSink.expected new file mode 100644 index 00000000000..dd169d78f03 --- /dev/null +++ b/python/ql/test/library-tests/taint/general/TestSink.expected @@ -0,0 +1,34 @@ +| Command injection | sanitizer.py:16 | 20 | x | Command injection | +| Command injection | sanitizer.py:31 | 33 | x | Command injection | +| Command injection | sanitizer.py:31 | 35 | x | Command injection | +| SQL injection | sanitizer.py:9 | 13 | x | SQL injection | +| SQL injection | sanitizer.py:24 | 26 | x | SQL injection | +| SQL injection | sanitizer.py:24 | 28 | x | SQL injection | +| basic.custom | test.py:120 | 122 | t | basic.custom | +| basic.custom | test.py:126 | 130 | t | basic.custom | +| basic.custom | test.py:146 | 151 | t | basic.custom | +| explicit.carrier | carrier.py:21 | 22 | Attribute() | simple.test | +| explicit.carrier | carrier.py:29 | 30 | Attribute() | simple.test | +| explicit.carrier | carrier.py:33 | 35 | Attribute() | simple.test | +| rock | rockpaperscissors.py:16 | 16 | ROCK | rock | +| rock | rockpaperscissors.py:24 | 26 | y | paper | +| scissors | rockpaperscissors.py:13 | 13 | SCISSORS | scissors | +| simple.test | carrier.py:17 | 18 | Attribute | simple.test | +| simple.test | module.py:3 | 89 | t | simple.test | +| simple.test | module.py:3 | 106 | Attribute | simple.test | +| simple.test | module.py:3 | 111 | Attribute | simple.test | +| simple.test | module.py:3 | 156 | unsafe | simple.test | +| simple.test | module.py:7 | 101 | t | simple.test | +| simple.test | test.py:3 | 3 | SOURCE | simple.test | +| simple.test | test.py:6 | 7 | s | simple.test | +| simple.test | test.py:10 | 13 | arg | simple.test | +| simple.test | test.py:10 | 17 | t | simple.test | +| simple.test | test.py:20 | 13 | arg | simple.test | +| simple.test | test.py:37 | 41 | t | simple.test | +| simple.test | test.py:62 | 13 | arg | simple.test | +| simple.test | test.py:67 | 13 | arg | simple.test | +| simple.test | test.py:76 | 78 | t | simple.test | +| simple.test | test.py:128 | 132 | t | simple.test | +| simple.test | test.py:159 | 160 | t | simple.test | +| simple.test | test.py:168 | 172 | Subscript | simple.test | +| simple.test | test.py:169 | 173 | Subscript | simple.test | diff --git a/python/ql/test/library-tests/taint/general/TestSink.ql b/python/ql/test/library-tests/taint/general/TestSink.ql new file mode 100644 index 00000000000..d0361cc204a --- /dev/null +++ b/python/ql/test/library-tests/taint/general/TestSink.ql @@ -0,0 +1,8 @@ +import python +import semmle.python.security.TaintTracking +import TaintLib + +from TaintSource src, TaintSink sink, TaintKind srckind, TaintKind sinkkind + +where src.flowsToSink(srckind, sink) and sink.sinks(sinkkind) +select srckind, src.getLocation().toString(), sink.getLocation().getStartLine(), sink.(ControlFlowNode).getNode().toString(), sinkkind diff --git a/python/ql/test/library-tests/taint/general/TestSource.expected b/python/ql/test/library-tests/taint/general/TestSource.expected new file mode 100644 index 00000000000..ea9012b7735 --- /dev/null +++ b/python/ql/test/library-tests/taint/general/TestSource.expected @@ -0,0 +1,42 @@ +| carrier.py:17 | SOURCE | simple.test | +| carrier.py:21 | TAINT_CARRIER_SOURCE | explicit.carrier | +| carrier.py:25 | SOURCE | simple.test | +| carrier.py:29 | TAINT_CARRIER_SOURCE | explicit.carrier | +| carrier.py:33 | TAINT_CARRIER_SOURCE | explicit.carrier | +| deep.py:20 | SOURCE | simple.test | +| module.py:3 | SOURCE | simple.test | +| module.py:7 | SOURCE | simple.test | +| module.py:10 | SOURCE | simple.test | +| rockpaperscissors.py:13 | SCISSORS | scissors | +| rockpaperscissors.py:16 | ROCK | rock | +| rockpaperscissors.py:19 | ROCK | rock | +| rockpaperscissors.py:24 | ROCK | rock | +| rockpaperscissors.py:29 | SCISSORS | scissors | +| sanitizer.py:9 | user_input() | Command injection | +| sanitizer.py:9 | user_input() | SQL injection | +| sanitizer.py:16 | user_input() | Command injection | +| sanitizer.py:16 | user_input() | SQL injection | +| sanitizer.py:24 | user_input() | Command injection | +| sanitizer.py:24 | user_input() | SQL injection | +| sanitizer.py:31 | user_input() | Command injection | +| sanitizer.py:31 | user_input() | SQL injection | +| test.py:3 | SOURCE | simple.test | +| test.py:6 | SOURCE | simple.test | +| test.py:10 | SOURCE | simple.test | +| test.py:20 | SOURCE | simple.test | +| test.py:31 | SOURCE | simple.test | +| test.py:37 | SOURCE | simple.test | +| test.py:62 | SOURCE | simple.test | +| test.py:67 | SOURCE | simple.test | +| test.py:76 | SOURCE | simple.test | +| test.py:120 | CUSTOM_SOURCE | basic.custom | +| test.py:126 | CUSTOM_SOURCE | basic.custom | +| test.py:128 | SOURCE | simple.test | +| test.py:136 | CUSTOM_SOURCE | basic.custom | +| test.py:138 | SOURCE | simple.test | +| test.py:146 | CUSTOM_SOURCE | basic.custom | +| test.py:148 | SOURCE | simple.test | +| test.py:159 | SOURCE | simple.test | +| test.py:163 | SOURCE | simple.test | +| test.py:168 | SOURCE | simple.test | +| test.py:169 | SOURCE | simple.test | diff --git a/python/ql/test/library-tests/taint/general/TestSource.ql b/python/ql/test/library-tests/taint/general/TestSource.ql new file mode 100644 index 00000000000..ba064220bfb --- /dev/null +++ b/python/ql/test/library-tests/taint/general/TestSource.ql @@ -0,0 +1,8 @@ +import python +import semmle.python.security.TaintTracking +import TaintLib + + +from TaintSource src, TaintKind kind +where src.isSourceOf(kind) +select src.getLocation().toString(), src.(ControlFlowNode).getNode().toString(), kind diff --git a/python/ql/test/library-tests/taint/general/TestStep.expected b/python/ql/test/library-tests/taint/general/TestStep.expected new file mode 100644 index 00000000000..a4c72fd6b0c --- /dev/null +++ b/python/ql/test/library-tests/taint/general/TestStep.expected @@ -0,0 +1,180 @@ +| Attribute 'attr' taint explicit.carrier | carrier.py:5 | self | carrier.py:33 | --> | Attribute 'attr' taint explicit.carrier | carrier.py:33 | ImplicitCarrier() | | +| Attribute 'attr' taint explicit.carrier | carrier.py:33 | ImplicitCarrier() | | --> | Attribute 'attr' taint explicit.carrier | carrier.py:34 | c | | +| Attribute 'attr' taint explicit.carrier | carrier.py:34 | c | | --> | Taint explicit.carrier | carrier.py:34 | Attribute | | +| Attribute 'attr' taint simple.test | carrier.py:5 | self | carrier.py:17 | --> | Attribute 'attr' taint simple.test | carrier.py:17 | ImplicitCarrier() | | +| Attribute 'attr' taint simple.test | carrier.py:5 | self | carrier.py:25 | --> | Attribute 'attr' taint simple.test | carrier.py:25 | ImplicitCarrier() | | +| Attribute 'attr' taint simple.test | carrier.py:13 | arg | carrier.py:25 | --> | Attribute 'attr' taint simple.test | carrier.py:14 | arg | carrier.py:25 | +| Attribute 'attr' taint simple.test | carrier.py:14 | arg | carrier.py:25 | --> | Attribute 'attr' taint simple.test | carrier.py:25 | hub() | | +| Attribute 'attr' taint simple.test | carrier.py:17 | ImplicitCarrier() | | --> | Attribute 'attr' taint simple.test | carrier.py:18 | c | | +| Attribute 'attr' taint simple.test | carrier.py:18 | c | | --> | Taint simple.test | carrier.py:18 | Attribute | | +| Attribute 'attr' taint simple.test | carrier.py:25 | ImplicitCarrier() | | --> | Attribute 'attr' taint simple.test | carrier.py:13 | arg | carrier.py:25 | +| Attribute 'attr' taint simple.test | carrier.py:25 | hub() | | --> | Attribute 'attr' taint simple.test | carrier.py:26 | c | | +| Attribute 'dangerous' taint simple.test | test.py:85 | ImportExpr | | --> | Attribute 'dangerous' taint simple.test | test.py:88 | module | | +| Attribute 'dangerous' taint simple.test | test.py:85 | ImportExpr | | --> | Attribute 'dangerous' taint simple.test | test.py:92 | module | | +| Attribute 'dangerous' taint simple.test | test.py:85 | ImportExpr | | --> | Attribute 'dangerous' taint simple.test | test.py:96 | module | | +| Attribute 'dangerous' taint simple.test | test.py:85 | ImportExpr | | --> | Attribute 'dangerous' taint simple.test | test.py:100 | module | | +| Attribute 'dangerous' taint simple.test | test.py:85 | ImportExpr | | --> | Attribute 'dangerous' taint simple.test | test.py:110 | module | | +| Attribute 'dangerous' taint simple.test | test.py:85 | ImportExpr | | --> | Attribute 'dangerous' taint simple.test | test.py:115 | module | | +| Attribute 'dangerous' taint simple.test | test.py:88 | module | | --> | Taint simple.test | test.py:88 | Attribute | | +| Attribute 'dangerous' taint simple.test | test.py:110 | module | | --> | Taint simple.test | test.py:110 | Attribute | | +| Attribute 'dangerous' taint simple.test | test.py:115 | module | | --> | Taint simple.test | test.py:115 | Attribute | | +| Attribute 'x' taint simple.test | test.py:72 | arg | test.py:116 | --> | Attribute 'x' taint simple.test | test.py:73 | arg | test.py:116 | +| Attribute 'x' taint simple.test | test.py:73 | arg | test.py:116 | --> | Attribute 'x' taint simple.test | test.py:116 | hub() | | +| Attribute 'x' taint simple.test | test.py:105 | arg | test.py:117 | --> | Attribute 'x' taint simple.test | test.py:106 | arg | test.py:117 | +| Attribute 'x' taint simple.test | test.py:106 | arg | test.py:117 | --> | Taint simple.test | test.py:106 | Attribute | test.py:117 | +| Attribute 'x' taint simple.test | test.py:110 | t | | --> | Attribute 'x' taint simple.test | test.py:111 | t | | +| Attribute 'x' taint simple.test | test.py:111 | t | | --> | Taint simple.test | test.py:111 | Attribute | | +| Attribute 'x' taint simple.test | test.py:115 | t | | --> | Attribute 'x' taint simple.test | test.py:116 | t | | +| Attribute 'x' taint simple.test | test.py:116 | hub() | | --> | Attribute 'x' taint simple.test | test.py:117 | t | | +| Attribute 'x' taint simple.test | test.py:116 | t | | --> | Attribute 'x' taint simple.test | test.py:72 | arg | test.py:116 | +| Attribute 'x' taint simple.test | test.py:117 | t | | --> | Attribute 'x' taint simple.test | test.py:105 | arg | test.py:117 | +| Taint Command injection | sanitizer.py:9 | user_input() | | --> | Taint Command injection | sanitizer.py:10 | x | | +| Taint Command injection | sanitizer.py:9 | user_input() | | --> | Taint Command injection | sanitizer.py:11 | x | | +| Taint Command injection | sanitizer.py:9 | user_input() | | --> | Taint Command injection | sanitizer.py:13 | x | | +| Taint Command injection | sanitizer.py:10 | x | | --> | Taint Command injection | sanitizer.py:3 | arg | sanitizer.py:10 | +| Taint Command injection | sanitizer.py:16 | user_input() | | --> | Taint Command injection | sanitizer.py:17 | x | | +| Taint Command injection | sanitizer.py:16 | user_input() | | --> | Taint Command injection | sanitizer.py:20 | x | | +| Taint Command injection | sanitizer.py:17 | x | | --> | Taint Command injection | sanitizer.py:5 | arg | sanitizer.py:17 | +| Taint Command injection | sanitizer.py:24 | user_input() | | --> | Taint Command injection | sanitizer.py:25 | x | | +| Taint Command injection | sanitizer.py:24 | user_input() | | --> | Taint Command injection | sanitizer.py:26 | x | | +| Taint Command injection | sanitizer.py:24 | user_input() | | --> | Taint Command injection | sanitizer.py:28 | x | | +| Taint Command injection | sanitizer.py:31 | user_input() | | --> | Taint Command injection | sanitizer.py:32 | x | | +| Taint Command injection | sanitizer.py:31 | user_input() | | --> | Taint Command injection | sanitizer.py:33 | x | | +| Taint Command injection | sanitizer.py:31 | user_input() | | --> | Taint Command injection | sanitizer.py:35 | x | | +| Taint SQL injection | sanitizer.py:9 | user_input() | | --> | Taint SQL injection | sanitizer.py:10 | x | | +| Taint SQL injection | sanitizer.py:9 | user_input() | | --> | Taint SQL injection | sanitizer.py:13 | x | | +| Taint SQL injection | sanitizer.py:10 | x | | --> | Taint SQL injection | sanitizer.py:3 | arg | sanitizer.py:10 | +| Taint SQL injection | sanitizer.py:16 | user_input() | | --> | Taint SQL injection | sanitizer.py:17 | x | | +| Taint SQL injection | sanitizer.py:16 | user_input() | | --> | Taint SQL injection | sanitizer.py:18 | x | | +| Taint SQL injection | sanitizer.py:16 | user_input() | | --> | Taint SQL injection | sanitizer.py:20 | x | | +| Taint SQL injection | sanitizer.py:17 | x | | --> | Taint SQL injection | sanitizer.py:5 | arg | sanitizer.py:17 | +| Taint SQL injection | sanitizer.py:24 | user_input() | | --> | Taint SQL injection | sanitizer.py:25 | x | | +| Taint SQL injection | sanitizer.py:24 | user_input() | | --> | Taint SQL injection | sanitizer.py:26 | x | | +| Taint SQL injection | sanitizer.py:24 | user_input() | | --> | Taint SQL injection | sanitizer.py:28 | x | | +| Taint SQL injection | sanitizer.py:31 | user_input() | | --> | Taint SQL injection | sanitizer.py:32 | x | | +| Taint SQL injection | sanitizer.py:31 | user_input() | | --> | Taint SQL injection | sanitizer.py:33 | x | | +| Taint SQL injection | sanitizer.py:31 | user_input() | | --> | Taint SQL injection | sanitizer.py:35 | x | | +| Taint [simple.test] | test.py:168 | List | | --> | Taint [simple.test] | test.py:170 | l | | +| Taint [simple.test] | test.py:168 | List | | --> | Taint [simple.test] | test.py:174 | l | | +| Taint [simple.test] | test.py:170 | l | | --> | Taint [simple.test] | test.py:172 | x | | +| Taint [simple.test] | test.py:172 | x | | --> | Taint simple.test | test.py:172 | Subscript | | +| Taint [simple.test] | test.py:174 | l | | --> | Taint [simple.test] | test.py:174 | list() | | +| Taint basic.custom | test.py:72 | arg | test.py:121 | --> | Taint basic.custom | test.py:73 | arg | test.py:121 | +| Taint basic.custom | test.py:73 | arg | test.py:121 | --> | Taint basic.custom | test.py:121 | hub() | | +| Taint basic.custom | test.py:120 | CUSTOM_SOURCE | | --> | Taint basic.custom | test.py:121 | t | | +| Taint basic.custom | test.py:121 | TAINT_FROM_ARG() | | --> | Taint basic.custom | test.py:72 | arg | test.py:121 | +| Taint basic.custom | test.py:121 | hub() | | --> | Taint basic.custom | test.py:122 | t | | +| Taint basic.custom | test.py:121 | t | | --> | Taint basic.custom | test.py:121 | TAINT_FROM_ARG() | | +| Taint basic.custom | test.py:126 | CUSTOM_SOURCE | | --> | Taint basic.custom | test.py:130 | t | | +| Taint basic.custom | test.py:136 | CUSTOM_SOURCE | | --> | Taint basic.custom | test.py:142 | t | | +| Taint basic.custom | test.py:146 | CUSTOM_SOURCE | | --> | Taint basic.custom | test.py:149 | t | | +| Taint basic.custom | test.py:149 | TAINT_FROM_ARG() | | --> | Taint basic.custom | test.py:151 | t | | +| Taint basic.custom | test.py:149 | t | | --> | Taint basic.custom | test.py:149 | TAINT_FROM_ARG() | | +| Taint explicit.carrier | carrier.py:4 | arg | carrier.py:33 | --> | Taint explicit.carrier | carrier.py:5 | arg | carrier.py:33 | +| Taint explicit.carrier | carrier.py:5 | arg | carrier.py:33 | --> | Attribute 'attr' taint explicit.carrier | carrier.py:5 | self | carrier.py:33 | +| Taint explicit.carrier | carrier.py:13 | arg | carrier.py:29 | --> | Taint explicit.carrier | carrier.py:14 | arg | carrier.py:29 | +| Taint explicit.carrier | carrier.py:14 | arg | carrier.py:29 | --> | Taint explicit.carrier | carrier.py:29 | hub() | | +| Taint explicit.carrier | carrier.py:21 | TAINT_CARRIER_SOURCE | | --> | Taint explicit.carrier | carrier.py:22 | c | | +| Taint explicit.carrier | carrier.py:22 | c | | --> | Taint simple.test | carrier.py:22 | Attribute() | | +| Taint explicit.carrier | carrier.py:29 | TAINT_CARRIER_SOURCE | | --> | Taint explicit.carrier | carrier.py:13 | arg | carrier.py:29 | +| Taint explicit.carrier | carrier.py:29 | hub() | | --> | Taint explicit.carrier | carrier.py:30 | c | | +| Taint explicit.carrier | carrier.py:30 | c | | --> | Taint simple.test | carrier.py:30 | Attribute() | | +| Taint explicit.carrier | carrier.py:33 | TAINT_CARRIER_SOURCE | | --> | Taint explicit.carrier | carrier.py:4 | arg | carrier.py:33 | +| Taint explicit.carrier | carrier.py:34 | Attribute | | --> | Taint explicit.carrier | carrier.py:35 | x | | +| Taint explicit.carrier | carrier.py:35 | x | | --> | Taint simple.test | carrier.py:35 | Attribute() | | +| Taint paper | rockpaperscissors.py:25 | Attribute() | | --> | Taint paper | rockpaperscissors.py:26 | y | | +| Taint paper | rockpaperscissors.py:26 | y | | --> | Taint paper | rockpaperscissors.py:9 | arg | rockpaperscissors.py:26 | +| Taint paper | rockpaperscissors.py:30 | Attribute() | | --> | Taint paper | rockpaperscissors.py:32 | y | | +| Taint paper | rockpaperscissors.py:32 | y | | --> | Taint paper | rockpaperscissors.py:6 | arg | rockpaperscissors.py:32 | +| Taint rock | rockpaperscissors.py:16 | ROCK | | --> | Taint rock | rockpaperscissors.py:6 | arg | rockpaperscissors.py:16 | +| Taint rock | rockpaperscissors.py:19 | ROCK | | --> | Taint rock | rockpaperscissors.py:20 | x | | +| Taint rock | rockpaperscissors.py:20 | x | | --> | Taint scissors | rockpaperscissors.py:20 | Attribute() | | +| Taint rock | rockpaperscissors.py:24 | ROCK | | --> | Taint rock | rockpaperscissors.py:25 | x | | +| Taint rock | rockpaperscissors.py:25 | x | | --> | Taint scissors | rockpaperscissors.py:25 | Attribute() | | +| Taint scissors | rockpaperscissors.py:13 | SCISSORS | | --> | Taint scissors | rockpaperscissors.py:3 | arg | rockpaperscissors.py:13 | +| Taint scissors | rockpaperscissors.py:20 | Attribute() | | --> | Taint scissors | rockpaperscissors.py:21 | y | | +| Taint scissors | rockpaperscissors.py:21 | y | | --> | Taint scissors | rockpaperscissors.py:9 | arg | rockpaperscissors.py:21 | +| Taint scissors | rockpaperscissors.py:25 | Attribute() | | --> | Taint paper | rockpaperscissors.py:25 | Attribute() | | +| Taint scissors | rockpaperscissors.py:29 | SCISSORS | | --> | Taint scissors | rockpaperscissors.py:30 | x | | +| Taint scissors | rockpaperscissors.py:29 | SCISSORS | | --> | Taint scissors | rockpaperscissors.py:31 | x | | +| Taint scissors | rockpaperscissors.py:30 | x | | --> | Taint paper | rockpaperscissors.py:30 | Attribute() | | +| Taint scissors | rockpaperscissors.py:31 | x | | --> | Taint scissors | rockpaperscissors.py:6 | arg | rockpaperscissors.py:31 | +| Taint simple.test | carrier.py:4 | arg | carrier.py:17 | --> | Taint simple.test | carrier.py:5 | arg | carrier.py:17 | +| Taint simple.test | carrier.py:4 | arg | carrier.py:25 | --> | Taint simple.test | carrier.py:5 | arg | carrier.py:25 | +| Taint simple.test | carrier.py:5 | arg | carrier.py:17 | --> | Attribute 'attr' taint simple.test | carrier.py:5 | self | carrier.py:17 | +| Taint simple.test | carrier.py:5 | arg | carrier.py:25 | --> | Attribute 'attr' taint simple.test | carrier.py:5 | self | carrier.py:25 | +| Taint simple.test | carrier.py:17 | SOURCE | | --> | Taint simple.test | carrier.py:4 | arg | carrier.py:17 | +| Taint simple.test | carrier.py:25 | SOURCE | | --> | Taint simple.test | carrier.py:4 | arg | carrier.py:25 | +| Taint simple.test | deep.py:2 | arg | deep.py:6 from deep.py:9 from deep.py:12 from deep.py:15 from deep.py:18 from deep.py:20 | --> | Taint simple.test | deep.py:3 | arg | deep.py:6 from deep.py:9 from deep.py:12 from deep.py:15 from deep.py:18 from deep.py:20 | +| Taint simple.test | deep.py:3 | arg | deep.py:6 from deep.py:9 from deep.py:12 from deep.py:15 from deep.py:18 from deep.py:20 | --> | Taint simple.test | deep.py:6 | f1() | deep.py:9 from deep.py:12 from deep.py:15 from deep.py:18 from deep.py:20 | +| Taint simple.test | deep.py:5 | arg | deep.py:9 from deep.py:12 from deep.py:15 from deep.py:18 from deep.py:20 | --> | Taint simple.test | deep.py:6 | arg | deep.py:9 from deep.py:12 from deep.py:15 from deep.py:18 from deep.py:20 | +| Taint simple.test | deep.py:6 | arg | deep.py:9 from deep.py:12 from deep.py:15 from deep.py:18 from deep.py:20 | --> | Taint simple.test | deep.py:2 | arg | deep.py:6 from deep.py:9 from deep.py:12 from deep.py:15 from deep.py:18 from deep.py:20 | +| Taint simple.test | deep.py:6 | f1() | deep.py:9 from deep.py:12 from deep.py:15 from deep.py:18 from deep.py:20 | --> | Taint simple.test | deep.py:9 | f2() | deep.py:12 from deep.py:15 from deep.py:18 from deep.py:20 | +| Taint simple.test | deep.py:8 | arg | deep.py:12 from deep.py:15 from deep.py:18 from deep.py:20 | --> | Taint simple.test | deep.py:9 | arg | deep.py:12 from deep.py:15 from deep.py:18 from deep.py:20 | +| Taint simple.test | deep.py:9 | arg | deep.py:12 from deep.py:15 from deep.py:18 from deep.py:20 | --> | Taint simple.test | deep.py:5 | arg | deep.py:9 from deep.py:12 from deep.py:15 from deep.py:18 from deep.py:20 | +| Taint simple.test | deep.py:9 | f2() | deep.py:12 from deep.py:15 from deep.py:18 from deep.py:20 | --> | Taint simple.test | deep.py:12 | f3() | deep.py:15 from deep.py:18 from deep.py:20 | +| Taint simple.test | deep.py:11 | arg | deep.py:15 from deep.py:18 from deep.py:20 | --> | Taint simple.test | deep.py:12 | arg | deep.py:15 from deep.py:18 from deep.py:20 | +| Taint simple.test | deep.py:12 | arg | deep.py:15 from deep.py:18 from deep.py:20 | --> | Taint simple.test | deep.py:8 | arg | deep.py:12 from deep.py:15 from deep.py:18 from deep.py:20 | +| Taint simple.test | deep.py:12 | f3() | deep.py:15 from deep.py:18 from deep.py:20 | --> | Taint simple.test | deep.py:15 | f4() | deep.py:18 from deep.py:20 | +| Taint simple.test | deep.py:14 | arg | deep.py:18 from deep.py:20 | --> | Taint simple.test | deep.py:15 | arg | deep.py:18 from deep.py:20 | +| Taint simple.test | deep.py:15 | arg | deep.py:18 from deep.py:20 | --> | Taint simple.test | deep.py:11 | arg | deep.py:15 from deep.py:18 from deep.py:20 | +| Taint simple.test | deep.py:15 | f4() | deep.py:18 from deep.py:20 | --> | Taint simple.test | deep.py:18 | f5() | deep.py:20 | +| Taint simple.test | deep.py:17 | arg | deep.py:20 | --> | Taint simple.test | deep.py:18 | arg | deep.py:20 | +| Taint simple.test | deep.py:18 | arg | deep.py:20 | --> | Taint simple.test | deep.py:14 | arg | deep.py:18 from deep.py:20 | +| Taint simple.test | deep.py:18 | f5() | deep.py:20 | --> | Taint simple.test | deep.py:20 | f6() | | +| Taint simple.test | deep.py:20 | SOURCE | | --> | Taint simple.test | deep.py:17 | arg | deep.py:20 | +| Taint simple.test | deep.py:20 | f6() | | --> | Taint simple.test | deep.py:22 | x | | +| Taint simple.test | module.py:3 | SOURCE | | --> | Attribute 'dangerous' taint simple.test | test.py:85 | ImportExpr | | +| Taint simple.test | module.py:3 | SOURCE | | --> | Attribute 'dangerous' taint simple.test | test.py:155 | ImportExpr | | +| Taint simple.test | module.py:3 | SOURCE | | --> | Taint simple.test | test.py:155 | ImportMember | | +| Taint simple.test | module.py:7 | SOURCE | | --> | Taint simple.test | test.py:100 | Attribute() | | +| Taint simple.test | test.py:6 | SOURCE | | --> | Taint simple.test | test.py:7 | s | | +| Taint simple.test | test.py:10 | SOURCE | | --> | Taint simple.test | test.py:16 | source() | | +| Taint simple.test | test.py:10 | SOURCE | | --> | Taint simple.test | test.py:24 | source() | | +| Taint simple.test | test.py:10 | SOURCE | | --> | Taint simple.test | test.py:44 | source() | | +| Taint simple.test | test.py:12 | arg | test.py:21 | --> | Taint simple.test | test.py:13 | arg | test.py:21 | +| Taint simple.test | test.py:12 | arg | test.py:25 | --> | Taint simple.test | test.py:13 | arg | test.py:25 | +| Taint simple.test | test.py:12 | arg | test.py:47 from test.py:55 | --> | Taint simple.test | test.py:13 | arg | test.py:47 from test.py:55 | +| Taint simple.test | test.py:12 | arg | test.py:51 from test.py:63 | --> | Taint simple.test | test.py:13 | arg | test.py:51 from test.py:63 | +| Taint simple.test | test.py:12 | arg | test.py:51 from test.py:70 | --> | Taint simple.test | test.py:13 | arg | test.py:51 from test.py:70 | +| Taint simple.test | test.py:16 | source() | | --> | Taint simple.test | test.py:17 | t | | +| Taint simple.test | test.py:20 | SOURCE | | --> | Taint simple.test | test.py:21 | t | | +| Taint simple.test | test.py:21 | t | | --> | Taint simple.test | test.py:12 | arg | test.py:21 | +| Taint simple.test | test.py:24 | source() | | --> | Taint simple.test | test.py:25 | t | | +| Taint simple.test | test.py:25 | t | | --> | Taint simple.test | test.py:12 | arg | test.py:25 | +| Taint simple.test | test.py:37 | SOURCE | | --> | Taint simple.test | test.py:41 | t | | +| Taint simple.test | test.py:44 | source() | | --> | Taint simple.test | test.py:54 | source2() | | +| Taint simple.test | test.py:46 | arg | test.py:55 | --> | Taint simple.test | test.py:47 | arg | test.py:55 | +| Taint simple.test | test.py:47 | arg | test.py:55 | --> | Taint simple.test | test.py:12 | arg | test.py:47 from test.py:55 | +| Taint simple.test | test.py:49 | arg | test.py:63 | --> | Taint simple.test | test.py:51 | arg | test.py:63 | +| Taint simple.test | test.py:49 | arg | test.py:70 | --> | Taint simple.test | test.py:51 | arg | test.py:70 | +| Taint simple.test | test.py:51 | arg | test.py:63 | --> | Taint simple.test | test.py:12 | arg | test.py:51 from test.py:63 | +| Taint simple.test | test.py:51 | arg | test.py:70 | --> | Taint simple.test | test.py:12 | arg | test.py:51 from test.py:70 | +| Taint simple.test | test.py:54 | source2() | | --> | Taint simple.test | test.py:55 | t | | +| Taint simple.test | test.py:55 | t | | --> | Taint simple.test | test.py:46 | arg | test.py:55 | +| Taint simple.test | test.py:62 | SOURCE | | --> | Taint simple.test | test.py:63 | t | | +| Taint simple.test | test.py:63 | t | | --> | Taint simple.test | test.py:49 | arg | test.py:63 | +| Taint simple.test | test.py:67 | SOURCE | | --> | Taint simple.test | test.py:70 | t | | +| Taint simple.test | test.py:70 | t | | --> | Taint simple.test | test.py:49 | arg | test.py:70 | +| Taint simple.test | test.py:72 | arg | test.py:77 | --> | Taint simple.test | test.py:73 | arg | test.py:77 | +| Taint simple.test | test.py:73 | arg | test.py:77 | --> | Taint simple.test | test.py:77 | hub() | | +| Taint simple.test | test.py:76 | SOURCE | | --> | Taint simple.test | test.py:77 | t | | +| Taint simple.test | test.py:77 | hub() | | --> | Taint simple.test | test.py:78 | t | | +| Taint simple.test | test.py:77 | t | | --> | Taint simple.test | test.py:72 | arg | test.py:77 | +| Taint simple.test | test.py:88 | Attribute | | --> | Taint simple.test | test.py:89 | t | | +| Taint simple.test | test.py:100 | Attribute() | | --> | Taint simple.test | test.py:101 | t | | +| Taint simple.test | test.py:110 | Attribute | | --> | Attribute 'x' taint simple.test | test.py:110 | t | | +| Taint simple.test | test.py:115 | Attribute | | --> | Attribute 'x' taint simple.test | test.py:115 | t | | +| Taint simple.test | test.py:128 | SOURCE | | --> | Taint simple.test | test.py:132 | t | | +| Taint simple.test | test.py:138 | SOURCE | | --> | Taint simple.test | test.py:140 | t | | +| Taint simple.test | test.py:148 | SOURCE | | --> | Taint simple.test | test.py:149 | t | | +| Taint simple.test | test.py:155 | ImportMember | | --> | Taint simple.test | test.py:156 | unsafe | | +| Taint simple.test | test.py:159 | SOURCE | | --> | Taint simple.test | test.py:160 | t | | +| Taint simple.test | test.py:163 | SOURCE | | --> | Taint simple.test | test.py:164 | s | | +| Taint simple.test | test.py:168 | SOURCE | | --> | Taint [simple.test] | test.py:168 | List | | +| Taint simple.test | test.py:169 | SOURCE | | --> | Taint {simple.test} | test.py:169 | Dict | | +| Taint {simple.test} | test.py:169 | Dict | | --> | Taint {simple.test} | test.py:171 | d | | +| Taint {simple.test} | test.py:169 | Dict | | --> | Taint {simple.test} | test.py:175 | d | | +| Taint {simple.test} | test.py:171 | d | | --> | Taint {simple.test} | test.py:173 | y | | +| Taint {simple.test} | test.py:173 | y | | --> | Taint simple.test | test.py:173 | Subscript | | +| Taint {simple.test} | test.py:175 | d | | --> | Taint {simple.test} | test.py:175 | dict() | | diff --git a/python/ql/test/library-tests/taint/general/TestStep.ql b/python/ql/test/library-tests/taint/general/TestStep.ql new file mode 100644 index 00000000000..191ab6b1483 --- /dev/null +++ b/python/ql/test/library-tests/taint/general/TestStep.ql @@ -0,0 +1,11 @@ +import python +import semmle.python.security.TaintTracking +import TaintLib + + +from TaintedNode n, TaintedNode s +where s = n.getASuccessor() +select + n.getTrackedValue(), n.getLocation().toString(), n.getNode().getNode().toString(), n.getContext(), + " --> ", + s.getTrackedValue(), s.getLocation().toString(), s.getNode().getNode().toString(), s.getContext() diff --git a/python/ql/test/library-tests/taint/general/TestVar.expected b/python/ql/test/library-tests/taint/general/TestVar.expected new file mode 100644 index 00000000000..5aad11fb547 --- /dev/null +++ b/python/ql/test/library-tests/taint/general/TestVar.expected @@ -0,0 +1,179 @@ +| carrier.py:4 | arg_0 | carrier.py:4 | Taint explicit.carrier | arg | +| carrier.py:4 | arg_0 | carrier.py:4 | Taint simple.test | arg | +| carrier.py:5 | self_1 | carrier.py:5 | Attribute 'attr' taint explicit.carrier | self | +| carrier.py:5 | self_1 | carrier.py:5 | Attribute 'attr' taint simple.test | self | +| carrier.py:13 | arg_0 | carrier.py:13 | Attribute 'attr' taint simple.test | arg | +| carrier.py:13 | arg_0 | carrier.py:13 | Taint explicit.carrier | arg | +| carrier.py:17 | c_0 | carrier.py:17 | Attribute 'attr' taint simple.test | ImplicitCarrier() | +| carrier.py:21 | c_0 | carrier.py:21 | Taint explicit.carrier | TAINT_CARRIER_SOURCE | +| carrier.py:22 | c_1 | carrier.py:21 | Taint explicit.carrier | TAINT_CARRIER_SOURCE | +| carrier.py:25 | c_0 | carrier.py:25 | Attribute 'attr' taint simple.test | hub() | +| carrier.py:29 | c_0 | carrier.py:29 | Taint explicit.carrier | hub() | +| carrier.py:30 | c_1 | carrier.py:29 | Taint explicit.carrier | hub() | +| carrier.py:33 | c_0 | carrier.py:33 | Attribute 'attr' taint explicit.carrier | ImplicitCarrier() | +| carrier.py:34 | x_0 | carrier.py:34 | Taint explicit.carrier | Attribute | +| carrier.py:35 | x_1 | carrier.py:34 | Taint explicit.carrier | Attribute | +| deep.py:2 | arg_0 | deep.py:2 | Taint simple.test | arg | +| deep.py:5 | arg_0 | deep.py:5 | Taint simple.test | arg | +| deep.py:6 | arg_1 | deep.py:5 | Taint simple.test | arg | +| deep.py:8 | arg_0 | deep.py:8 | Taint simple.test | arg | +| deep.py:9 | arg_1 | deep.py:8 | Taint simple.test | arg | +| deep.py:11 | arg_0 | deep.py:11 | Taint simple.test | arg | +| deep.py:12 | arg_1 | deep.py:11 | Taint simple.test | arg | +| deep.py:14 | arg_0 | deep.py:14 | Taint simple.test | arg | +| deep.py:15 | arg_1 | deep.py:14 | Taint simple.test | arg | +| deep.py:17 | arg_0 | deep.py:17 | Taint simple.test | arg | +| deep.py:18 | arg_1 | deep.py:17 | Taint simple.test | arg | +| deep.py:20 | x_1 | deep.py:20 | Taint simple.test | f6() | +| module.py:3 | dangerous_0 | module.py:3 | Taint simple.test | SOURCE | +| rockpaperscissors.py:3 | arg_0 | rockpaperscissors.py:3 | Taint scissors | arg | +| rockpaperscissors.py:6 | arg_0 | rockpaperscissors.py:6 | Taint paper | arg | +| rockpaperscissors.py:6 | arg_0 | rockpaperscissors.py:6 | Taint rock | arg | +| rockpaperscissors.py:6 | arg_0 | rockpaperscissors.py:6 | Taint scissors | arg | +| rockpaperscissors.py:9 | arg_0 | rockpaperscissors.py:9 | Taint paper | arg | +| rockpaperscissors.py:9 | arg_0 | rockpaperscissors.py:9 | Taint scissors | arg | +| rockpaperscissors.py:19 | x_0 | rockpaperscissors.py:19 | Taint rock | ROCK | +| rockpaperscissors.py:20 | x_1 | rockpaperscissors.py:19 | Taint rock | ROCK | +| rockpaperscissors.py:20 | y_0 | rockpaperscissors.py:20 | Taint scissors | Attribute() | +| rockpaperscissors.py:21 | y_1 | rockpaperscissors.py:20 | Taint scissors | Attribute() | +| rockpaperscissors.py:24 | x_0 | rockpaperscissors.py:24 | Taint rock | ROCK | +| rockpaperscissors.py:25 | x_1 | rockpaperscissors.py:24 | Taint rock | ROCK | +| rockpaperscissors.py:25 | y_0 | rockpaperscissors.py:25 | Taint paper | Attribute() | +| rockpaperscissors.py:26 | y_1 | rockpaperscissors.py:25 | Taint paper | Attribute() | +| rockpaperscissors.py:29 | x_0 | rockpaperscissors.py:29 | Taint scissors | SCISSORS | +| rockpaperscissors.py:30 | x_1 | rockpaperscissors.py:29 | Taint scissors | SCISSORS | +| rockpaperscissors.py:30 | y_0 | rockpaperscissors.py:30 | Taint paper | Attribute() | +| rockpaperscissors.py:31 | x_2 | rockpaperscissors.py:29 | Taint scissors | SCISSORS | +| rockpaperscissors.py:32 | y_1 | rockpaperscissors.py:30 | Taint paper | Attribute() | +| sanitizer.py:3 | arg_0 | sanitizer.py:3 | Taint Command injection | arg | +| sanitizer.py:3 | arg_0 | sanitizer.py:3 | Taint SQL injection | arg | +| sanitizer.py:5 | arg_0 | sanitizer.py:5 | Taint Command injection | arg | +| sanitizer.py:5 | arg_0 | sanitizer.py:5 | Taint SQL injection | arg | +| sanitizer.py:8 | x_6 | sanitizer.py:9 | Taint Command injection | user_input() | +| sanitizer.py:8 | x_6 | sanitizer.py:9 | Taint SQL injection | user_input() | +| sanitizer.py:9 | x_0 | sanitizer.py:9 | Taint Command injection | user_input() | +| sanitizer.py:9 | x_0 | sanitizer.py:9 | Taint SQL injection | user_input() | +| sanitizer.py:10 | x_1 | sanitizer.py:9 | Taint Command injection | user_input() | +| sanitizer.py:10 | x_1 | sanitizer.py:9 | Taint SQL injection | user_input() | +| sanitizer.py:11 | x_2 | sanitizer.py:9 | Taint Command injection | user_input() | +| sanitizer.py:11 | x_3 | sanitizer.py:9 | Taint Command injection | user_input() | +| sanitizer.py:13 | x_4 | sanitizer.py:9 | Taint Command injection | user_input() | +| sanitizer.py:13 | x_4 | sanitizer.py:9 | Taint SQL injection | user_input() | +| sanitizer.py:13 | x_5 | sanitizer.py:9 | Taint Command injection | user_input() | +| sanitizer.py:13 | x_5 | sanitizer.py:9 | Taint SQL injection | user_input() | +| sanitizer.py:15 | x_6 | sanitizer.py:16 | Taint Command injection | user_input() | +| sanitizer.py:15 | x_6 | sanitizer.py:16 | Taint SQL injection | user_input() | +| sanitizer.py:16 | x_0 | sanitizer.py:16 | Taint Command injection | user_input() | +| sanitizer.py:16 | x_0 | sanitizer.py:16 | Taint SQL injection | user_input() | +| sanitizer.py:17 | x_1 | sanitizer.py:16 | Taint Command injection | user_input() | +| sanitizer.py:17 | x_1 | sanitizer.py:16 | Taint SQL injection | user_input() | +| sanitizer.py:18 | x_2 | sanitizer.py:16 | Taint SQL injection | user_input() | +| sanitizer.py:18 | x_3 | sanitizer.py:16 | Taint SQL injection | user_input() | +| sanitizer.py:20 | x_4 | sanitizer.py:16 | Taint Command injection | user_input() | +| sanitizer.py:20 | x_4 | sanitizer.py:16 | Taint SQL injection | user_input() | +| sanitizer.py:20 | x_5 | sanitizer.py:16 | Taint Command injection | user_input() | +| sanitizer.py:20 | x_5 | sanitizer.py:16 | Taint SQL injection | user_input() | +| sanitizer.py:23 | x_6 | sanitizer.py:24 | Taint Command injection | user_input() | +| sanitizer.py:23 | x_6 | sanitizer.py:24 | Taint SQL injection | user_input() | +| sanitizer.py:24 | x_0 | sanitizer.py:24 | Taint Command injection | user_input() | +| sanitizer.py:24 | x_0 | sanitizer.py:24 | Taint SQL injection | user_input() | +| sanitizer.py:25 | x_1 | sanitizer.py:24 | Taint Command injection | user_input() | +| sanitizer.py:25 | x_1 | sanitizer.py:24 | Taint SQL injection | user_input() | +| sanitizer.py:26 | x_2 | sanitizer.py:24 | Taint Command injection | user_input() | +| sanitizer.py:26 | x_2 | sanitizer.py:24 | Taint SQL injection | user_input() | +| sanitizer.py:26 | x_3 | sanitizer.py:24 | Taint Command injection | user_input() | +| sanitizer.py:26 | x_3 | sanitizer.py:24 | Taint SQL injection | user_input() | +| sanitizer.py:28 | x_4 | sanitizer.py:24 | Taint Command injection | user_input() | +| sanitizer.py:28 | x_4 | sanitizer.py:24 | Taint SQL injection | user_input() | +| sanitizer.py:28 | x_5 | sanitizer.py:24 | Taint Command injection | user_input() | +| sanitizer.py:28 | x_5 | sanitizer.py:24 | Taint SQL injection | user_input() | +| sanitizer.py:30 | x_6 | sanitizer.py:31 | Taint Command injection | user_input() | +| sanitizer.py:30 | x_6 | sanitizer.py:31 | Taint SQL injection | user_input() | +| sanitizer.py:31 | x_0 | sanitizer.py:31 | Taint Command injection | user_input() | +| sanitizer.py:31 | x_0 | sanitizer.py:31 | Taint SQL injection | user_input() | +| sanitizer.py:32 | x_1 | sanitizer.py:31 | Taint Command injection | user_input() | +| sanitizer.py:32 | x_1 | sanitizer.py:31 | Taint SQL injection | user_input() | +| sanitizer.py:33 | x_2 | sanitizer.py:31 | Taint Command injection | user_input() | +| sanitizer.py:33 | x_2 | sanitizer.py:31 | Taint SQL injection | user_input() | +| sanitizer.py:33 | x_3 | sanitizer.py:31 | Taint Command injection | user_input() | +| sanitizer.py:33 | x_3 | sanitizer.py:31 | Taint SQL injection | user_input() | +| sanitizer.py:35 | x_4 | sanitizer.py:31 | Taint Command injection | user_input() | +| sanitizer.py:35 | x_4 | sanitizer.py:31 | Taint SQL injection | user_input() | +| sanitizer.py:35 | x_5 | sanitizer.py:31 | Taint Command injection | user_input() | +| sanitizer.py:35 | x_5 | sanitizer.py:31 | Taint SQL injection | user_input() | +| test.py:6 | s_0 | test.py:6 | Taint simple.test | SOURCE | +| test.py:7 | s_1 | test.py:6 | Taint simple.test | SOURCE | +| test.py:12 | arg_0 | test.py:12 | Taint simple.test | arg | +| test.py:13 | arg_1 | test.py:12 | Taint simple.test | arg | +| test.py:16 | t_0 | test.py:16 | Taint simple.test | source() | +| test.py:17 | t_1 | test.py:16 | Taint simple.test | source() | +| test.py:20 | t_0 | test.py:20 | Taint simple.test | SOURCE | +| test.py:21 | t_1 | test.py:20 | Taint simple.test | SOURCE | +| test.py:24 | t_0 | test.py:24 | Taint simple.test | source() | +| test.py:25 | t_1 | test.py:24 | Taint simple.test | source() | +| test.py:31 | t_2 | test.py:31 | Taint simple.test | SOURCE | +| test.py:37 | t_0 | test.py:37 | Taint simple.test | SOURCE | +| test.py:41 | t_1 | test.py:37 | Taint simple.test | SOURCE | +| test.py:46 | arg_0 | test.py:46 | Taint simple.test | arg | +| test.py:47 | arg_1 | test.py:46 | Taint simple.test | arg | +| test.py:49 | arg_0 | test.py:49 | Taint simple.test | arg | +| test.py:49 | arg_2 | test.py:49 | Taint simple.test | arg | +| test.py:51 | arg_1 | test.py:49 | Taint simple.test | arg | +| test.py:54 | t_0 | test.py:54 | Taint simple.test | source2() | +| test.py:55 | t_1 | test.py:54 | Taint simple.test | source2() | +| test.py:62 | t_1 | test.py:62 | Taint simple.test | SOURCE | +| test.py:63 | t_2 | test.py:62 | Taint simple.test | SOURCE | +| test.py:67 | t_0 | test.py:67 | Taint simple.test | SOURCE | +| test.py:70 | t_2 | test.py:67 | Taint simple.test | SOURCE | +| test.py:72 | arg_0 | test.py:72 | Attribute 'x' taint simple.test | arg | +| test.py:72 | arg_0 | test.py:72 | Taint basic.custom | arg | +| test.py:72 | arg_0 | test.py:72 | Taint simple.test | arg | +| test.py:76 | t_0 | test.py:76 | Taint simple.test | SOURCE | +| test.py:77 | t_1 | test.py:77 | Taint simple.test | hub() | +| test.py:78 | t_2 | test.py:77 | Taint simple.test | hub() | +| test.py:85 | module_0 | test.py:85 | Attribute 'dangerous' taint simple.test | ImportExpr | +| test.py:87 | module_1 | test.py:85 | Attribute 'dangerous' taint simple.test | ImportExpr | +| test.py:88 | t_0 | test.py:88 | Taint simple.test | Attribute | +| test.py:89 | t_1 | test.py:88 | Taint simple.test | Attribute | +| test.py:91 | module_2 | test.py:85 | Attribute 'dangerous' taint simple.test | ImportExpr | +| test.py:95 | module_3 | test.py:85 | Attribute 'dangerous' taint simple.test | ImportExpr | +| test.py:99 | module_4 | test.py:85 | Attribute 'dangerous' taint simple.test | ImportExpr | +| test.py:100 | t_0 | test.py:100 | Taint simple.test | Attribute() | +| test.py:101 | t_1 | test.py:100 | Taint simple.test | Attribute() | +| test.py:105 | arg_0 | test.py:105 | Attribute 'x' taint simple.test | arg | +| test.py:108 | module_5 | test.py:85 | Attribute 'dangerous' taint simple.test | ImportExpr | +| test.py:110 | t_1 | test.py:110 | Attribute 'x' taint simple.test | t | +| test.py:113 | module_6 | test.py:85 | Attribute 'dangerous' taint simple.test | ImportExpr | +| test.py:115 | t_1 | test.py:115 | Attribute 'x' taint simple.test | t | +| test.py:116 | t_2 | test.py:116 | Attribute 'x' taint simple.test | hub() | +| test.py:117 | t_3 | test.py:116 | Attribute 'x' taint simple.test | hub() | +| test.py:120 | t_0 | test.py:120 | Taint basic.custom | CUSTOM_SOURCE | +| test.py:121 | t_1 | test.py:121 | Taint basic.custom | hub() | +| test.py:122 | t_2 | test.py:121 | Taint basic.custom | hub() | +| test.py:126 | t_0 | test.py:126 | Taint basic.custom | CUSTOM_SOURCE | +| test.py:128 | t_2 | test.py:128 | Taint simple.test | SOURCE | +| test.py:130 | t_1 | test.py:126 | Taint basic.custom | CUSTOM_SOURCE | +| test.py:132 | t_3 | test.py:128 | Taint simple.test | SOURCE | +| test.py:136 | t_0 | test.py:136 | Taint basic.custom | CUSTOM_SOURCE | +| test.py:138 | t_2 | test.py:138 | Taint simple.test | SOURCE | +| test.py:140 | t_3 | test.py:138 | Taint simple.test | SOURCE | +| test.py:142 | t_1 | test.py:136 | Taint basic.custom | CUSTOM_SOURCE | +| test.py:146 | t_0 | test.py:146 | Taint basic.custom | CUSTOM_SOURCE | +| test.py:148 | t_3 | test.py:148 | Taint simple.test | SOURCE | +| test.py:149 | t_1 | test.py:149 | Taint basic.custom | TAINT_FROM_ARG() | +| test.py:151 | t_2 | test.py:149 | Taint basic.custom | TAINT_FROM_ARG() | +| test.py:155 | unsafe_0 | test.py:155 | Taint simple.test | ImportMember | +| test.py:156 | unsafe_1 | test.py:155 | Taint simple.test | ImportMember | +| test.py:159 | t_0 | test.py:159 | Taint simple.test | SOURCE | +| test.py:160 | t_1 | test.py:159 | Taint simple.test | SOURCE | +| test.py:163 | s_0 | test.py:163 | Taint simple.test | SOURCE | +| test.py:168 | l_0 | test.py:168 | Taint [simple.test] | List | +| test.py:169 | d_0 | test.py:169 | Taint {simple.test} | Dict | +| test.py:170 | l_1 | test.py:168 | Taint [simple.test] | List | +| test.py:170 | x_1 | test.py:170 | Taint [simple.test] | l | +| test.py:171 | d_1 | test.py:169 | Taint {simple.test} | Dict | +| test.py:171 | y_1 | test.py:171 | Taint {simple.test} | d | +| test.py:174 | l2_0 | test.py:174 | Taint [simple.test] | list() | +| test.py:174 | l_2 | test.py:168 | Taint [simple.test] | List | +| test.py:175 | d2_0 | test.py:175 | Taint {simple.test} | dict() | +| test.py:175 | d_2 | test.py:169 | Taint {simple.test} | Dict | diff --git a/python/ql/test/library-tests/taint/general/TestVar.ql b/python/ql/test/library-tests/taint/general/TestVar.ql new file mode 100644 index 00000000000..93a90e7bd76 --- /dev/null +++ b/python/ql/test/library-tests/taint/general/TestVar.ql @@ -0,0 +1,9 @@ +import python +import semmle.python.security.TaintTest +import TaintLib + + +from EssaVariable var, TaintedNode n +where TaintFlowTest::tainted_var(var, _, n) +select + var.getDefinition().getLocation().toString(), var.getRepresentation(), n.getLocation().toString(), n.getTrackedValue(), n.getNode().getNode().toString() diff --git a/python/ql/test/library-tests/taint/general/carrier.py b/python/ql/test/library-tests/taint/general/carrier.py new file mode 100644 index 00000000000..10e70e41a93 --- /dev/null +++ b/python/ql/test/library-tests/taint/general/carrier.py @@ -0,0 +1,35 @@ + +class ImplicitCarrier(object): + + def __init__(self, arg): + self.attr = arg + + def set_attr(self, arg): + self.attr = arg + + def get_attr(self): + return self.attr + +def hub(arg): + return arg + +def test1(): + c = ImplicitCarrier(SOURCE) + SINK(c.attr) + +def test2(): + c = TAINT_CARRIER_SOURCE + SINK(c.get_taint()) + +def test3(): + c = hub(ImplicitCarrier(SOURCE)) + SINK(c.get_attr()) + +def test4(): + c = hub(TAINT_CARRIER_SOURCE) + SINK(c.get_taint()) + +def test5(): + c = ImplicitCarrier(TAINT_CARRIER_SOURCE) + x = c.attr + SINK(x.get_taint()) diff --git a/python/ql/test/library-tests/taint/general/deep.py b/python/ql/test/library-tests/taint/general/deep.py new file mode 100644 index 00000000000..022cf403f7a --- /dev/null +++ b/python/ql/test/library-tests/taint/general/deep.py @@ -0,0 +1,24 @@ + +def f1(arg): + return arg + +def f2(arg): + return f1(arg) + +def f3(arg): + return f2(arg) + +def f4(arg): + return f3(arg) + +def f5(arg): + return f4(arg) + +def f6(arg): + return f5(arg) + +x = f6(SOURCE) + +x + + diff --git a/python/ql/test/library-tests/taint/general/module.py b/python/ql/test/library-tests/taint/general/module.py new file mode 100644 index 00000000000..437ef3bb239 --- /dev/null +++ b/python/ql/test/library-tests/taint/general/module.py @@ -0,0 +1,11 @@ + + +dangerous = SOURCE +safe = "safe" + +def dangerous_func(): + return SOURCE + + +safe2 = SOURCE +safe2 = "safe" diff --git a/python/ql/test/library-tests/taint/general/rockpaperscissors.py b/python/ql/test/library-tests/taint/general/rockpaperscissors.py new file mode 100644 index 00000000000..8d73e090e33 --- /dev/null +++ b/python/ql/test/library-tests/taint/general/rockpaperscissors.py @@ -0,0 +1,32 @@ + + +def rock(arg): + "SCISSORS are vulnerable" + +def paper(arg): + "ROCK is vulnerable" + +def scissors(arg): + "PAPER is vulnerable" + +def test1(): + rock(SCISSORS) + +def test2(): + paper(ROCK) + +def test3(): + x = ROCK + y = x.prev() #scissors + scissors(y) + +def test4(): + x = ROCK + y = x.prev().prev() # paper + scissors(y) + +def test5(): + x = SCISSORS + y = x.prev() # paper + paper(x) + paper(y) diff --git a/python/ql/test/library-tests/taint/general/sanitizer.py b/python/ql/test/library-tests/taint/general/sanitizer.py new file mode 100644 index 00000000000..9238f66fb32 --- /dev/null +++ b/python/ql/test/library-tests/taint/general/sanitizer.py @@ -0,0 +1,36 @@ + +#Sanitizer functions +def isEscapedSql(arg): pass + +def isValidCommand(arg): pass + + +def sql_inject1(): + x = user_input() + if isEscapedSql(x): + sql_query(x) # Safe + else: + sql_query(x) # DANGEROUS + +def command_inject1(): + x = user_input() + if isValidCommand(x): + os_command(x) # Safe + else: + os_command(x) # DANGEROUS + + +def sql_inject2(): + x = user_input() + if notASanitizer(x): + sql_query(x) # DANGEROUS + else: + sql_query(x) # DANGEROUS + +def command_inject2(): + x = user_input() + if notASanitizer(x): + os_command(x) # DANGEROUS + else: + os_command(x) # DANGEROUS + diff --git a/python/ql/test/library-tests/taint/general/test.py b/python/ql/test/library-tests/taint/general/test.py new file mode 100644 index 00000000000..5a6fc1e2900 --- /dev/null +++ b/python/ql/test/library-tests/taint/general/test.py @@ -0,0 +1,175 @@ + +def test1(): + SINK(SOURCE) + +def test2(): + s = SOURCE + SINK(s) + +def source(): + return SOURCE + +def sink(arg): + SINK(arg) + +def test3(): + t = source() + SINK(t) + +def test4(): + t = SOURCE + sink(t) + +def test5(): + t = source() + sink(t) + +def test6(cond): + if cond: + t = "Safe" + else: + t = SOURCE + if cond: + SINK(t) + +def test7(cond): + if cond: + t = SOURCE + else: + t = "Safe" + if cond: + SINK(t) + +def source2(arg): + return source(arg) + +def sink2(arg): + sink(arg) + +def sink3(cond, arg): + if cond: + sink(arg) + +def test8(cond): + t = source2() + sink2(t) + +#False positive +def test9(cond): + if cond: + t = "Safe" + else: + t = SOURCE + sink3(cond, t) + +def test10(cond): + if cond: + t = SOURCE + else: + t = "Safe" + sink3(cond, t) + +def hub(arg): + return arg + +def test11(): + t = SOURCE + t = hub(t) + SINK(t) + +def test12(): + t = "safe" + t = hub(t) + SINK(t) + +import module + +def test13(): + t = module.dangerous + SINK(t) + +def test14(): + t = module.safe + SINK(t) + +def test15(): + t = module.safe2 + SINK(t) + +def test16(): + t = module.dangerous_func() + SINK(t) + +class C(object): pass + +def x_sink(arg): + SINK(arg.x) + +def test17(): + t = C() + t.x = module.dangerous + SINK(t.x) + +def test18(): + t = C() + t.x = module.dangerous + t = hub(t) + x_sink(t) + +def test19(): + t = CUSTOM_SOURCE + t = hub(TAINT_FROM_ARG(t)) + CUSTOM_SINK(t) + +def test20(cond): + if cond: + t = CUSTOM_SOURCE + else: + t = SOURCE + if cond: + CUSTOM_SINK(t) + else: + SINK(t) + +def test21(cond): + if cond: + t = CUSTOM_SOURCE + else: + t = SOURCE + if not cond: + CUSTOM_SINK(t) + else: + SINK(t) + +def test22(cond): + if cond: + t = CUSTOM_SOURCE + else: + t = SOURCE + t = TAINT_FROM_ARG(t) + if cond: + CUSTOM_SINK(t) + else: + SINK(t) + +from module import dangerous as unsafe +SINK(unsafe) + +def test23(): + with SOURCE as t: + SINK(t) + +def test24(): + s = SOURCE + SANITIZE(s) + SINK(s) + +def test_update_extend(x, y): + l = [SOURCE] + d = {"key" : SOURCE} + x.extend(l) + y.update(d) + SINK(x[0]) + SINK(y["key"]) + l2 = list(l) + d2 = dict(d) diff --git a/python/ql/test/library-tests/taint/invalid/NoSink.expected b/python/ql/test/library-tests/taint/invalid/NoSink.expected new file mode 100644 index 00000000000..566c01caa9b --- /dev/null +++ b/python/ql/test/library-tests/taint/invalid/NoSink.expected @@ -0,0 +1 @@ +| No sinks defined | This message wouldn't appear if the query were complete $@ | No sinks defined | nor this | diff --git a/python/ql/test/library-tests/taint/invalid/NoSink.ql b/python/ql/test/library-tests/taint/invalid/NoSink.ql new file mode 100644 index 00000000000..822de8a622a --- /dev/null +++ b/python/ql/test/library-tests/taint/invalid/NoSink.ql @@ -0,0 +1,25 @@ + +import python + +import semmle.python.security.TaintTracking + +/* Sources */ + +class AnySource extends TaintSource { + + AnySource() { + this instanceof ControlFlowNode + } + + override predicate isSourceOf(TaintKind kind) { any() } + +} +/* Flow */ +import semmle.python.security.strings.Untrusted + +from TaintSource src, TaintSink sink +where src.flowsToSink(sink) + +select sink.toString(), "This message wouldn't appear if the query were complete $@", + src.toString(), "nor this" + diff --git a/python/ql/test/library-tests/taint/invalid/NoSource.expected b/python/ql/test/library-tests/taint/invalid/NoSource.expected new file mode 100644 index 00000000000..1d8515200e9 --- /dev/null +++ b/python/ql/test/library-tests/taint/invalid/NoSource.expected @@ -0,0 +1 @@ +| No sources defined | This message wouldn't appear if the query were complete $@ | No sources defined | nor this | diff --git a/python/ql/test/library-tests/taint/invalid/NoSource.ql b/python/ql/test/library-tests/taint/invalid/NoSource.ql new file mode 100644 index 00000000000..1b7f2067a08 --- /dev/null +++ b/python/ql/test/library-tests/taint/invalid/NoSource.ql @@ -0,0 +1,26 @@ + +import python + +import semmle.python.security.TaintTracking + +/* Flow */ +import semmle.python.security.strings.Untrusted + +/* Sinks */ + +class AnySink extends TaintSink{ + + AnySink() { + this instanceof ControlFlowNode + } + + override predicate sinks(TaintKind kind) { any() } + +} + +from TaintSource src, TaintSink sink +where src.flowsToSink(sink) + +select sink.toString(), "This message wouldn't appear if the query were complete $@", + src.toString(), "nor this" + diff --git a/python/ql/test/library-tests/taint/invalid/test.py b/python/ql/test/library-tests/taint/invalid/test.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/library-tests/taint/strings/DistinctStringKinds.expected b/python/ql/test/library-tests/taint/strings/DistinctStringKinds.expected new file mode 100644 index 00000000000..684c12a3746 --- /dev/null +++ b/python/ql/test/library-tests/taint/strings/DistinctStringKinds.expected @@ -0,0 +1,16 @@ +| Taint exception.info | test.py:54 | test.py:54:22:54:26 | taint | test.py:59 | +| Taint exception.info | test.py:55 | test.py:55:12:55:22 | func() | test.py:59 | +| Taint exception.info | test.py:55 | test.py:55:17:55:21 | taint | test.py:59 | +| Taint exception.info | test.py:58 | test.py:58:12:58:33 | TAINTED_EXCEPTION_INFO | | +| Taint exception.info | test.py:59 | test.py:59:11:59:41 | cross_over() | | +| Taint exception.info | test.py:59 | test.py:59:37:59:40 | info | | +| Taint exception.info | test.py:61 | test.py:61:19:61:21 | arg | test.py:55 from test.py:59 | +| Taint exception.info | test.py:62 | test.py:62:12:62:14 | arg | test.py:55 from test.py:59 | +| Taint externally controlled string | test.py:54 | test.py:54:22:54:26 | taint | test.py:66 | +| Taint externally controlled string | test.py:55 | test.py:55:12:55:22 | func() | test.py:66 | +| Taint externally controlled string | test.py:55 | test.py:55:17:55:21 | taint | test.py:66 | +| Taint externally controlled string | test.py:61 | test.py:61:19:61:21 | arg | test.py:55 from test.py:66 | +| Taint externally controlled string | test.py:62 | test.py:62:12:62:14 | arg | test.py:55 from test.py:66 | +| Taint externally controlled string | test.py:65 | test.py:65:11:65:33 | TAINTED_EXTERNAL_STRING | | +| Taint externally controlled string | test.py:66 | test.py:66:11:66:41 | cross_over() | | +| Taint externally controlled string | test.py:66 | test.py:66:38:66:40 | ext | | diff --git a/python/ql/test/library-tests/taint/strings/DistinctStringKinds.ql b/python/ql/test/library-tests/taint/strings/DistinctStringKinds.ql new file mode 100644 index 00000000000..4165154b4aa --- /dev/null +++ b/python/ql/test/library-tests/taint/strings/DistinctStringKinds.ql @@ -0,0 +1,39 @@ +import python +import semmle.python.security.TaintTracking + +import semmle.python.security.Exceptions +import semmle.python.security.strings.Untrusted + + +class ExceptionInfoSource extends TaintSource { + + ExceptionInfoSource() { this.(NameNode).getId() = "TAINTED_EXCEPTION_INFO" } + + override predicate isSourceOf(TaintKind kind) { + kind instanceof ExceptionInfo + } + + override string toString() { + result = "Exception info source" + } + +} + +class ExternalStringSource extends TaintSource { + + ExternalStringSource() { this.(NameNode).getId() = "TAINTED_EXTERNAL_STRING" } + + override predicate isSourceOf(TaintKind kind) { + kind instanceof ExternalStringKind + } + + override string toString() { + result = "Untrusted string source" + } + +} + +from TaintedNode n +where n.getLocation().getFile().getName().matches("%test.py") +select n.getTrackedValue(), n.getLocation().toString(), n.getNode().getNode(), n.getContext() + diff --git a/python/ql/test/library-tests/taint/strings/Taint.qll b/python/ql/test/library-tests/taint/strings/Taint.qll new file mode 100644 index 00000000000..d39487b5ad3 --- /dev/null +++ b/python/ql/test/library-tests/taint/strings/Taint.qll @@ -0,0 +1,47 @@ +import python +import semmle.python.security.TaintTracking +import semmle.python.security.strings.Untrusted + + +class SimpleSource extends TaintSource { + + SimpleSource() { this.(NameNode).getId() = "TAINTED" } + + override predicate isSourceOf(TaintKind kind) { + kind instanceof ExternalStringKind + } + + string toString() { + result = "taint source" + } + +} + +class ListSource extends TaintSource { + + ListSource() { this.(NameNode).getId() = "TAINTED_LIST" } + + override predicate isSourceOf(TaintKind kind) { + kind instanceof ExternalStringSequenceKind + } + + string toString() { + result = "list taint source" + } + +} + +class DictSource extends TaintSource { + + DictSource() { this.(NameNode).getId() = "TAINTED_DICT" } + + override predicate isSourceOf(TaintKind kind) { + kind instanceof ExternalStringDictKind + } + + string toString() { + result = "dict taint source" + } + +} + diff --git a/python/ql/test/library-tests/taint/strings/TestNode.expected b/python/ql/test/library-tests/taint/strings/TestNode.expected new file mode 100644 index 00000000000..033bdf81d17 --- /dev/null +++ b/python/ql/test/library-tests/taint/strings/TestNode.expected @@ -0,0 +1,59 @@ +| Taint [externally controlled string] | test.py:12 | test.py:12:20:12:31 | TAINTED_LIST | | +| Taint [externally controlled string] | test.py:13 | test.py:13:9:13:20 | tainted_list | | +| Taint [externally controlled string] | test.py:14 | test.py:14:9:14:20 | tainted_list | | +| Taint [externally controlled string] | test.py:15 | test.py:15:9:15:20 | tainted_list | | +| Taint [externally controlled string] | test.py:15 | test.py:15:9:15:25 | Subscript | | +| Taint [externally controlled string] | test.py:16 | test.py:16:9:16:20 | tainted_list | | +| Taint [externally controlled string] | test.py:16 | test.py:16:9:16:27 | Attribute() | | +| Taint externally controlled string | test.py:5 | test.py:5:22:5:28 | TAINTED | | +| Taint externally controlled string | test.py:6 | test.py:6:31:6:44 | tainted_string | | +| Taint externally controlled string | test.py:7 | test.py:7:9:7:25 | Subscript | | +| Taint externally controlled string | test.py:8 | test.py:8:9:8:9 | a | | +| Taint externally controlled string | test.py:8 | test.py:8:9:8:18 | Attribute() | | +| Taint externally controlled string | test.py:9 | test.py:9:9:9:9 | b | | +| Taint externally controlled string | test.py:9 | test.py:9:9:9:14 | Subscript | | +| Taint externally controlled string | test.py:13 | test.py:13:9:13:23 | Subscript | | +| Taint externally controlled string | test.py:14 | test.py:14:9:14:23 | Subscript | | +| Taint externally controlled string | test.py:20 | test.py:20:9:20:28 | Subscript | | +| Taint externally controlled string | test.py:21 | test.py:21:9:21:23 | Subscript | | +| Taint externally controlled string | test.py:25 | test.py:25:22:25:28 | TAINTED | | +| Taint externally controlled string | test.py:26 | test.py:26:9:26:22 | tainted_string | | +| Taint externally controlled string | test.py:26 | test.py:26:9:26:31 | Attribute() | | +| Taint externally controlled string | test.py:27 | test.py:27:9:27:22 | tainted_string | | +| Taint externally controlled string | test.py:27 | test.py:27:9:27:29 | Attribute() | | +| Taint externally controlled string | test.py:28 | test.py:28:9:28:22 | tainted_string | | +| Taint externally controlled string | test.py:28 | test.py:28:9:28:25 | Subscript | | +| Taint externally controlled string | test.py:29 | test.py:29:9:29:22 | tainted_string | | +| Taint externally controlled string | test.py:29 | test.py:29:9:29:27 | Subscript | | +| Taint externally controlled string | test.py:30 | test.py:30:9:30:32 | reversed() | | +| Taint externally controlled string | test.py:30 | test.py:30:18:30:31 | tainted_string | | +| Taint externally controlled string | test.py:31 | test.py:31:9:31:28 | copy() | | +| Taint externally controlled string | test.py:31 | test.py:31:14:31:27 | tainted_string | | +| Taint externally controlled string | test.py:32 | test.py:32:9:32:22 | tainted_string | | +| Taint externally controlled string | test.py:32 | test.py:32:9:32:30 | Attribute() | | +| Taint externally controlled string | test.py:35 | test.py:35:22:35:28 | TAINTED | | +| Taint externally controlled string | test.py:36 | test.py:36:8:36:21 | tainted_string | | +| Taint externally controlled string | test.py:39 | test.py:39:23:39:36 | tainted_string | | +| Taint externally controlled string | test.py:42 | test.py:42:22:42:28 | TAINTED | | +| Taint externally controlled string | test.py:43 | test.py:43:8:43:21 | tainted_string | | +| Taint externally controlled string | test.py:43 | test.py:43:34:43:47 | tainted_string | | +| Taint externally controlled string | test.py:46 | test.py:46:23:46:36 | tainted_string | | +| Taint externally controlled string | test.py:49 | test.py:49:22:49:28 | TAINTED | | +| Taint externally controlled string | test.py:50 | test.py:50:9:50:27 | str() | | +| Taint externally controlled string | test.py:50 | test.py:50:13:50:26 | tainted_string | | +| Taint externally controlled string | test.py:51 | test.py:51:9:51:29 | bytes() | | +| Taint externally controlled string | test.py:51 | test.py:51:15:51:28 | tainted_string | | +| Taint externally controlled string | test.py:52 | test.py:52:9:52:46 | bytes() | | +| Taint externally controlled string | test.py:52 | test.py:52:15:52:28 | tainted_string | | +| Taint json[externally controlled string] | test.py:6 | test.py:6:20:6:45 | Attribute() | | +| Taint json[externally controlled string] | test.py:7 | test.py:7:9:7:20 | tainted_json | | +| Taint json[externally controlled string] | test.py:7 | test.py:7:9:7:25 | Subscript | | +| Taint json[externally controlled string] | test.py:8 | test.py:8:9:8:9 | a | | +| Taint json[externally controlled string] | test.py:8 | test.py:8:9:8:18 | Attribute() | | +| Taint json[externally controlled string] | test.py:9 | test.py:9:9:9:9 | b | | +| Taint json[externally controlled string] | test.py:9 | test.py:9:9:9:14 | Subscript | | +| Taint {externally controlled string} | test.py:19 | test.py:19:20:19:31 | TAINTED_DICT | | +| Taint {externally controlled string} | test.py:20 | test.py:20:9:20:20 | tainted_dict | | +| Taint {externally controlled string} | test.py:21 | test.py:21:9:21:20 | tainted_dict | | +| Taint {externally controlled string} | test.py:22 | test.py:22:9:22:20 | tainted_dict | | +| Taint {externally controlled string} | test.py:22 | test.py:22:9:22:27 | Attribute() | | diff --git a/python/ql/test/library-tests/taint/strings/TestNode.ql b/python/ql/test/library-tests/taint/strings/TestNode.ql new file mode 100644 index 00000000000..1210189a6a0 --- /dev/null +++ b/python/ql/test/library-tests/taint/strings/TestNode.ql @@ -0,0 +1,9 @@ +import python +import semmle.python.security.TaintTracking +import Taint + + +from TaintedNode n +where n.getLocation().getFile().getName().matches("%test.py") +select n.getTrackedValue(), n.getLocation().toString(), n.getNode().getNode(), n.getContext() + diff --git a/python/ql/test/library-tests/taint/strings/TestStep.expected b/python/ql/test/library-tests/taint/strings/TestStep.expected new file mode 100644 index 00000000000..87ca159c2af --- /dev/null +++ b/python/ql/test/library-tests/taint/strings/TestStep.expected @@ -0,0 +1,52 @@ +| Taint [externally controlled string] | test.py:12 | test.py:12:20:12:31 | TAINTED_LIST | | --> | Taint [externally controlled string] | test.py:13 | test.py:13:9:13:20 | tainted_list | | +| Taint [externally controlled string] | test.py:12 | test.py:12:20:12:31 | TAINTED_LIST | | --> | Taint [externally controlled string] | test.py:14 | test.py:14:9:14:20 | tainted_list | | +| Taint [externally controlled string] | test.py:12 | test.py:12:20:12:31 | TAINTED_LIST | | --> | Taint [externally controlled string] | test.py:15 | test.py:15:9:15:20 | tainted_list | | +| Taint [externally controlled string] | test.py:12 | test.py:12:20:12:31 | TAINTED_LIST | | --> | Taint [externally controlled string] | test.py:16 | test.py:16:9:16:20 | tainted_list | | +| Taint [externally controlled string] | test.py:13 | test.py:13:9:13:20 | tainted_list | | --> | Taint externally controlled string | test.py:13 | test.py:13:9:13:23 | Subscript | | +| Taint [externally controlled string] | test.py:14 | test.py:14:9:14:20 | tainted_list | | --> | Taint externally controlled string | test.py:14 | test.py:14:9:14:23 | Subscript | | +| Taint [externally controlled string] | test.py:15 | test.py:15:9:15:20 | tainted_list | | --> | Taint [externally controlled string] | test.py:15 | test.py:15:9:15:25 | Subscript | | +| Taint [externally controlled string] | test.py:16 | test.py:16:9:16:20 | tainted_list | | --> | Taint [externally controlled string] | test.py:16 | test.py:16:9:16:27 | Attribute() | | +| Taint externally controlled string | test.py:5 | test.py:5:22:5:28 | TAINTED | | --> | Taint externally controlled string | test.py:6 | test.py:6:31:6:44 | tainted_string | | +| Taint externally controlled string | test.py:6 | test.py:6:31:6:44 | tainted_string | | --> | Taint json[externally controlled string] | test.py:6 | test.py:6:20:6:45 | Attribute() | | +| Taint externally controlled string | test.py:7 | test.py:7:9:7:25 | Subscript | | --> | Taint externally controlled string | test.py:8 | test.py:8:9:8:9 | a | | +| Taint externally controlled string | test.py:8 | test.py:8:9:8:18 | Attribute() | | --> | Taint externally controlled string | test.py:9 | test.py:9:9:9:9 | b | | +| Taint externally controlled string | test.py:25 | test.py:25:22:25:28 | TAINTED | | --> | Taint externally controlled string | test.py:26 | test.py:26:9:26:22 | tainted_string | | +| Taint externally controlled string | test.py:25 | test.py:25:22:25:28 | TAINTED | | --> | Taint externally controlled string | test.py:27 | test.py:27:9:27:22 | tainted_string | | +| Taint externally controlled string | test.py:25 | test.py:25:22:25:28 | TAINTED | | --> | Taint externally controlled string | test.py:28 | test.py:28:9:28:22 | tainted_string | | +| Taint externally controlled string | test.py:25 | test.py:25:22:25:28 | TAINTED | | --> | Taint externally controlled string | test.py:29 | test.py:29:9:29:22 | tainted_string | | +| Taint externally controlled string | test.py:25 | test.py:25:22:25:28 | TAINTED | | --> | Taint externally controlled string | test.py:30 | test.py:30:18:30:31 | tainted_string | | +| Taint externally controlled string | test.py:25 | test.py:25:22:25:28 | TAINTED | | --> | Taint externally controlled string | test.py:31 | test.py:31:14:31:27 | tainted_string | | +| Taint externally controlled string | test.py:25 | test.py:25:22:25:28 | TAINTED | | --> | Taint externally controlled string | test.py:32 | test.py:32:9:32:22 | tainted_string | | +| Taint externally controlled string | test.py:26 | test.py:26:9:26:22 | tainted_string | | --> | Taint externally controlled string | test.py:26 | test.py:26:9:26:31 | Attribute() | | +| Taint externally controlled string | test.py:27 | test.py:27:9:27:22 | tainted_string | | --> | Taint externally controlled string | test.py:27 | test.py:27:9:27:29 | Attribute() | | +| Taint externally controlled string | test.py:28 | test.py:28:9:28:22 | tainted_string | | --> | Taint externally controlled string | test.py:28 | test.py:28:9:28:25 | Subscript | | +| Taint externally controlled string | test.py:29 | test.py:29:9:29:22 | tainted_string | | --> | Taint externally controlled string | test.py:29 | test.py:29:9:29:27 | Subscript | | +| Taint externally controlled string | test.py:30 | test.py:30:18:30:31 | tainted_string | | --> | Taint externally controlled string | test.py:30 | test.py:30:9:30:32 | reversed() | | +| Taint externally controlled string | test.py:31 | test.py:31:14:31:27 | tainted_string | | --> | Taint externally controlled string | test.py:31 | test.py:31:9:31:28 | copy() | | +| Taint externally controlled string | test.py:32 | test.py:32:9:32:22 | tainted_string | | --> | Taint externally controlled string | test.py:32 | test.py:32:9:32:30 | Attribute() | | +| Taint externally controlled string | test.py:35 | test.py:35:22:35:28 | TAINTED | | --> | Taint externally controlled string | test.py:36 | test.py:36:8:36:21 | tainted_string | | +| Taint externally controlled string | test.py:35 | test.py:35:22:35:28 | TAINTED | | --> | Taint externally controlled string | test.py:39 | test.py:39:23:39:36 | tainted_string | | +| Taint externally controlled string | test.py:42 | test.py:42:22:42:28 | TAINTED | | --> | Taint externally controlled string | test.py:43 | test.py:43:8:43:21 | tainted_string | | +| Taint externally controlled string | test.py:42 | test.py:42:22:42:28 | TAINTED | | --> | Taint externally controlled string | test.py:43 | test.py:43:34:43:47 | tainted_string | | +| Taint externally controlled string | test.py:42 | test.py:42:22:42:28 | TAINTED | | --> | Taint externally controlled string | test.py:46 | test.py:46:23:46:36 | tainted_string | | +| Taint externally controlled string | test.py:49 | test.py:49:22:49:28 | TAINTED | | --> | Taint externally controlled string | test.py:50 | test.py:50:13:50:26 | tainted_string | | +| Taint externally controlled string | test.py:49 | test.py:49:22:49:28 | TAINTED | | --> | Taint externally controlled string | test.py:51 | test.py:51:15:51:28 | tainted_string | | +| Taint externally controlled string | test.py:49 | test.py:49:22:49:28 | TAINTED | | --> | Taint externally controlled string | test.py:52 | test.py:52:15:52:28 | tainted_string | | +| Taint externally controlled string | test.py:50 | test.py:50:13:50:26 | tainted_string | | --> | Taint externally controlled string | test.py:50 | test.py:50:9:50:27 | str() | | +| Taint externally controlled string | test.py:51 | test.py:51:15:51:28 | tainted_string | | --> | Taint externally controlled string | test.py:51 | test.py:51:9:51:29 | bytes() | | +| Taint externally controlled string | test.py:52 | test.py:52:15:52:28 | tainted_string | | --> | Taint externally controlled string | test.py:52 | test.py:52:9:52:46 | bytes() | | +| Taint json[externally controlled string] | test.py:6 | test.py:6:20:6:45 | Attribute() | | --> | Taint json[externally controlled string] | test.py:7 | test.py:7:9:7:20 | tainted_json | | +| Taint json[externally controlled string] | test.py:7 | test.py:7:9:7:20 | tainted_json | | --> | Taint externally controlled string | test.py:7 | test.py:7:9:7:25 | Subscript | | +| Taint json[externally controlled string] | test.py:7 | test.py:7:9:7:20 | tainted_json | | --> | Taint json[externally controlled string] | test.py:7 | test.py:7:9:7:25 | Subscript | | +| Taint json[externally controlled string] | test.py:7 | test.py:7:9:7:25 | Subscript | | --> | Taint json[externally controlled string] | test.py:8 | test.py:8:9:8:9 | a | | +| Taint json[externally controlled string] | test.py:8 | test.py:8:9:8:9 | a | | --> | Taint externally controlled string | test.py:8 | test.py:8:9:8:18 | Attribute() | | +| Taint json[externally controlled string] | test.py:8 | test.py:8:9:8:9 | a | | --> | Taint json[externally controlled string] | test.py:8 | test.py:8:9:8:18 | Attribute() | | +| Taint json[externally controlled string] | test.py:8 | test.py:8:9:8:18 | Attribute() | | --> | Taint json[externally controlled string] | test.py:9 | test.py:9:9:9:9 | b | | +| Taint json[externally controlled string] | test.py:9 | test.py:9:9:9:9 | b | | --> | Taint externally controlled string | test.py:9 | test.py:9:9:9:14 | Subscript | | +| Taint json[externally controlled string] | test.py:9 | test.py:9:9:9:9 | b | | --> | Taint json[externally controlled string] | test.py:9 | test.py:9:9:9:14 | Subscript | | +| Taint {externally controlled string} | test.py:19 | test.py:19:20:19:31 | TAINTED_DICT | | --> | Taint {externally controlled string} | test.py:20 | test.py:20:9:20:20 | tainted_dict | | +| Taint {externally controlled string} | test.py:19 | test.py:19:20:19:31 | TAINTED_DICT | | --> | Taint {externally controlled string} | test.py:21 | test.py:21:9:21:20 | tainted_dict | | +| Taint {externally controlled string} | test.py:19 | test.py:19:20:19:31 | TAINTED_DICT | | --> | Taint {externally controlled string} | test.py:22 | test.py:22:9:22:20 | tainted_dict | | +| Taint {externally controlled string} | test.py:20 | test.py:20:9:20:20 | tainted_dict | | --> | Taint externally controlled string | test.py:20 | test.py:20:9:20:28 | Subscript | | +| Taint {externally controlled string} | test.py:21 | test.py:21:9:21:20 | tainted_dict | | --> | Taint externally controlled string | test.py:21 | test.py:21:9:21:23 | Subscript | | +| Taint {externally controlled string} | test.py:22 | test.py:22:9:22:20 | tainted_dict | | --> | Taint {externally controlled string} | test.py:22 | test.py:22:9:22:27 | Attribute() | | diff --git a/python/ql/test/library-tests/taint/strings/TestStep.ql b/python/ql/test/library-tests/taint/strings/TestStep.ql new file mode 100644 index 00000000000..90a4f5b4c3e --- /dev/null +++ b/python/ql/test/library-tests/taint/strings/TestStep.ql @@ -0,0 +1,13 @@ +import python +import semmle.python.security.TaintTracking +import Taint + + +from TaintedNode n, TaintedNode s +where n.getLocation().getFile().getName().matches("%test.py") and +s.getLocation().getFile().getName().matches("%test.py") and +s = n.getASuccessor() +select + n.getTrackedValue(), n.getLocation().toString(), n.getNode().getNode(), n.getContext(), + " --> ", + s.getTrackedValue(), s.getLocation().toString(), s.getNode().getNode(), s.getContext() diff --git a/python/ql/test/library-tests/taint/strings/test.py b/python/ql/test/library-tests/taint/strings/test.py new file mode 100644 index 00000000000..3e359bf663f --- /dev/null +++ b/python/ql/test/library-tests/taint/strings/test.py @@ -0,0 +1,69 @@ +import json +from copy import copy + +def test_json(): + tainted_string = TAINTED + tainted_json = json.loads(tainted_string) + a = tainted_json["x"] + b = a.get("y") + c = b["z"] + +def test_list(x, y, z): + tainted_list = TAINTED_LIST + a = tainted_list[0] + b = tainted_list[x] + c = tainted_list[y:z] + d = tainted_list.copy() + +def test_dict(x): + tainted_dict = TAINTED_DICT + a = tainted_dict["name"] + b = tainted_dict[x] + c = tainted_dict.copy() + +def test_str(): + tainted_string = TAINTED + a = tainted_string.ljust(8) + b = tainted_string.copy() + c = tainted_string[:] + d = tainted_string[::2] + e = reversed(tainted_string) + f = copy(tainted_string) + h = tainted_string.strip() + +def test_const_sanitizer1(): + tainted_string = TAINTED + if tainted_string == "OK": + not_tainted(tainted_string) + else: + still_tainted(tainted_string) + +def test_const_sanitizer2(): + tainted_string = TAINTED + if tainted_string == "OK" or tainted_string == "ALSO_OK": + not_tainted(tainted_string) + else: + still_tainted(tainted_string) + +def test_str2(): + tainted_string = TAINTED + a = str(tainted_string) + b = bytes(tainted_string) # This is an error in Python 3 + c = bytes(tainted_string, encoding="utf8") # This is an error in Python 2 + +def cross_over(func, taint): + return func(taint) + +def test_exc_info(): + info = TAINTED_EXCEPTION_INFO + res = cross_over(exc_info_call, info) + +def exc_info_call(arg): + return arg + +def test_untrusted(): + ext = TAINTED_EXTERNAL_STRING + res = cross_over(untrusted_call, ext) + +def exc_untrusted_call(arg): + return arg diff --git a/python/ql/test/library-tests/thrift/Child.expected b/python/ql/test/library-tests/thrift/Child.expected new file mode 100644 index 00000000000..2a844932a86 --- /dev/null +++ b/python/ql/test/library-tests/thrift/Child.expected @@ -0,0 +1,571 @@ +| extended.thrift:3:8:3:11 | definition | 0 | extended.thrift:3:8:3:11 | struct User | +| extended.thrift:3:8:3:11 | name | 0 | extended.thrift:3:8:3:11 | IDENTIFIER User | +| extended.thrift:3:8:3:11 | struct User | 0 | extended.thrift:3:8:3:11 | name | +| extended.thrift:3:8:3:11 | struct User | 1 | extended.thrift:4:3:4:16 | field name | +| extended.thrift:3:8:3:11 | struct User | 2 | file://:0:0:0:0 | type_annotations | +| extended.thrift:3:8:48:15 | document | 0 | extended.thrift:3:8:3:11 | definition | +| extended.thrift:3:8:48:15 | document | 1 | extended.thrift:7:11:7:15 | definition | +| extended.thrift:3:8:48:15 | document | 2 | extended.thrift:12:9:12:16 | definition | +| extended.thrift:3:8:48:15 | document | 3 | extended.thrift:19:9:19:15 | definition | +| extended.thrift:3:8:48:15 | document | 4 | extended.thrift:21:9:21:40 | definition | +| extended.thrift:3:8:48:15 | document | 5 | extended.thrift:23:8:23:23 | definition | +| extended.thrift:3:8:48:15 | document | 6 | extended.thrift:31:6:31:12 | definition | +| extended.thrift:3:8:48:15 | document | 7 | extended.thrift:37:9:37:19 | definition | +| extended.thrift:3:8:48:15 | document | 8 | extended.thrift:46:14:46:30 | definition | +| extended.thrift:3:8:48:15 | document | 9 | extended.thrift:48:9:48:15 | definition | +| extended.thrift:3:8:48:15 | start | 0 | extended.thrift:3:8:48:15 | document | +| extended.thrift:4:3:4:3 | fieldid | 0 | extended.thrift:4:3:4:3 | INTCONSTANT 1 | +| extended.thrift:4:3:4:16 | field name | 0 | extended.thrift:4:3:4:3 | fieldid | +| extended.thrift:4:3:4:16 | field name | 2 | extended.thrift:4:6:4:11 | type string | +| extended.thrift:4:3:4:16 | field name | 3 | file://:0:0:0:0 | type_annotations | +| extended.thrift:4:3:4:16 | field name | 4 | extended.thrift:4:13:4:16 | IDENTIFIER name | +| extended.thrift:4:3:4:16 | field name | 5 | file://:0:0:0:0 | fieldvalue | +| extended.thrift:4:3:4:16 | field name | 6 | file://:0:0:0:0 | xsdfieldoptions | +| extended.thrift:4:3:4:16 | field name | 7 | file://:0:0:0:0 | type_annotations | +| extended.thrift:4:6:4:11 | type string | 0 | extended.thrift:4:6:4:11 | STRING string | +| extended.thrift:4:6:4:11 | type string | 0 | extended.thrift:4:6:4:11 | type string | +| extended.thrift:7:11:7:15 | definition | 0 | extended.thrift:7:11:7:15 | exception Error | +| extended.thrift:7:11:7:15 | exception Error | 0 | extended.thrift:7:11:7:15 | name | +| extended.thrift:7:11:7:15 | exception Error | 1 | extended.thrift:8:3:8:13 | field what | +| extended.thrift:7:11:7:15 | exception Error | 2 | extended.thrift:9:3:9:15 | field why | +| extended.thrift:7:11:7:15 | name | 0 | extended.thrift:7:11:7:15 | IDENTIFIER Error | +| extended.thrift:8:3:8:3 | fieldid | 0 | extended.thrift:8:3:8:3 | INTCONSTANT 1 | +| extended.thrift:8:3:8:13 | field what | 0 | extended.thrift:8:3:8:3 | fieldid | +| extended.thrift:8:3:8:13 | field what | 2 | extended.thrift:8:6:8:8 | type i32 | +| extended.thrift:8:3:8:13 | field what | 3 | file://:0:0:0:0 | type_annotations | +| extended.thrift:8:3:8:13 | field what | 4 | extended.thrift:8:10:8:13 | IDENTIFIER what | +| extended.thrift:8:3:8:13 | field what | 5 | file://:0:0:0:0 | fieldvalue | +| extended.thrift:8:3:8:13 | field what | 6 | file://:0:0:0:0 | xsdfieldoptions | +| extended.thrift:8:3:8:13 | field what | 7 | file://:0:0:0:0 | type_annotations | +| extended.thrift:8:6:8:8 | type i32 | 0 | extended.thrift:8:6:8:8 | I32 i32 | +| extended.thrift:8:6:8:8 | type i32 | 0 | extended.thrift:8:6:8:8 | type i32 | +| extended.thrift:9:3:9:3 | fieldid | 0 | extended.thrift:9:3:9:3 | INTCONSTANT 2 | +| extended.thrift:9:3:9:15 | field why | 0 | extended.thrift:9:3:9:3 | fieldid | +| extended.thrift:9:3:9:15 | field why | 2 | extended.thrift:9:6:9:11 | type string | +| extended.thrift:9:3:9:15 | field why | 3 | file://:0:0:0:0 | type_annotations | +| extended.thrift:9:3:9:15 | field why | 4 | extended.thrift:9:13:9:15 | IDENTIFIER why | +| extended.thrift:9:3:9:15 | field why | 5 | file://:0:0:0:0 | fieldvalue | +| extended.thrift:9:3:9:15 | field why | 6 | file://:0:0:0:0 | xsdfieldoptions | +| extended.thrift:9:3:9:15 | field why | 7 | file://:0:0:0:0 | type_annotations | +| extended.thrift:9:6:9:11 | type string | 0 | extended.thrift:9:6:9:11 | STRING string | +| extended.thrift:9:6:9:11 | type string | 0 | extended.thrift:9:6:9:11 | type string | +| extended.thrift:12:9:12:16 | definition | 0 | extended.thrift:12:9:12:16 | service Extended | +| extended.thrift:12:9:12:16 | name | 0 | extended.thrift:12:9:12:16 | IDENTIFIER Extended | +| extended.thrift:12:9:12:16 | service Extended | 0 | extended.thrift:12:9:12:16 | name | +| extended.thrift:12:9:12:16 | service Extended | 1 | extended.thrift:14:4:14:15 | function getUser | +| extended.thrift:12:9:12:16 | service Extended | 2 | file://:0:0:0:0 | type_annotations | +| extended.thrift:14:4:14:7 | type User | 0 | extended.thrift:14:4:14:7 | IDENTIFIER User | +| extended.thrift:14:4:14:7 | type User | 0 | extended.thrift:14:4:14:7 | type User | +| extended.thrift:14:4:14:15 | function getUser | 0 | file://:0:0:0:0 | oneway | +| extended.thrift:14:4:14:15 | function getUser | 1 | extended.thrift:14:4:14:7 | type User | +| extended.thrift:14:4:14:15 | function getUser | 2 | extended.thrift:14:9:14:15 | name | +| extended.thrift:14:4:14:15 | function getUser | 3 | extended.thrift:14:17:14:24 | field id | +| extended.thrift:14:4:14:15 | function getUser | 4 | extended.thrift:14:35:14:47 | throws | +| extended.thrift:14:4:14:15 | function getUser | 5 | extended.thrift:15:5:15:47 | type_annotations | +| extended.thrift:14:9:14:15 | name | 0 | extended.thrift:14:9:14:15 | IDENTIFIER getUser | +| extended.thrift:14:17:14:17 | fieldid | 0 | extended.thrift:14:17:14:17 | INTCONSTANT 1 | +| extended.thrift:14:17:14:24 | field id | 0 | extended.thrift:14:17:14:17 | fieldid | +| extended.thrift:14:17:14:24 | field id | 2 | extended.thrift:14:19:14:21 | type i32 | +| extended.thrift:14:17:14:24 | field id | 3 | file://:0:0:0:0 | type_annotations | +| extended.thrift:14:17:14:24 | field id | 4 | extended.thrift:14:23:14:24 | IDENTIFIER id | +| extended.thrift:14:17:14:24 | field id | 5 | file://:0:0:0:0 | fieldvalue | +| extended.thrift:14:17:14:24 | field id | 6 | file://:0:0:0:0 | xsdfieldoptions | +| extended.thrift:14:17:14:24 | field id | 7 | file://:0:0:0:0 | type_annotations | +| extended.thrift:14:19:14:21 | type i32 | 0 | extended.thrift:14:19:14:21 | I32 i32 | +| extended.thrift:14:19:14:21 | type i32 | 0 | extended.thrift:14:19:14:21 | type i32 | +| extended.thrift:14:35:14:35 | fieldid | 0 | extended.thrift:14:35:14:35 | INTCONSTANT 1 | +| extended.thrift:14:35:14:47 | field error | 0 | extended.thrift:14:35:14:35 | fieldid | +| extended.thrift:14:35:14:47 | field error | 2 | extended.thrift:14:37:14:41 | type Error | +| extended.thrift:14:35:14:47 | field error | 3 | file://:0:0:0:0 | type_annotations | +| extended.thrift:14:35:14:47 | field error | 4 | extended.thrift:14:43:14:47 | IDENTIFIER error | +| extended.thrift:14:35:14:47 | field error | 5 | file://:0:0:0:0 | fieldvalue | +| extended.thrift:14:35:14:47 | field error | 6 | file://:0:0:0:0 | xsdfieldoptions | +| extended.thrift:14:35:14:47 | field error | 7 | file://:0:0:0:0 | type_annotations | +| extended.thrift:14:35:14:47 | throws | 0 | extended.thrift:14:35:14:47 | field error | +| extended.thrift:14:37:14:41 | type Error | 0 | extended.thrift:14:37:14:41 | IDENTIFIER Error | +| extended.thrift:15:5:15:16 | name | 0 | extended.thrift:15:5:15:16 | IDENTIFIER doggy.window | +| extended.thrift:15:5:15:25 | type_annotation | 0 | extended.thrift:15:5:15:16 | name | +| extended.thrift:15:5:15:25 | type_annotation | 1 | extended.thrift:15:20:15:25 | constvalue | +| extended.thrift:15:5:15:47 | type_annotations | 0 | extended.thrift:15:5:15:25 | type_annotation | +| extended.thrift:15:5:15:47 | type_annotations | 1 | extended.thrift:15:28:15:47 | type_annotation | +| extended.thrift:15:20:15:25 | constvalue | 0 | extended.thrift:15:20:15:25 | LITERAL "true" | +| extended.thrift:15:28:15:40 | name | 0 | extended.thrift:15:28:15:40 | IDENTIFIER doggy.howmuch | +| extended.thrift:15:28:15:47 | type_annotation | 0 | extended.thrift:15:28:15:40 | name | +| extended.thrift:15:28:15:47 | type_annotation | 1 | extended.thrift:15:44:15:47 | constvalue | +| extended.thrift:15:44:15:47 | constvalue | 0 | extended.thrift:15:44:15:47 | INTCONSTANT 1000 | +| extended.thrift:19:9:19:11 | type i32 | 0 | extended.thrift:19:9:19:11 | I32 i32 | +| extended.thrift:19:9:19:11 | type i32 | 0 | extended.thrift:19:9:19:11 | type i32 | +| extended.thrift:19:9:19:15 | definition | 0 | extended.thrift:19:9:19:15 | typedef int | +| extended.thrift:19:9:19:15 | typedef int | 0 | extended.thrift:19:9:19:11 | type i32 | +| extended.thrift:19:9:19:15 | typedef int | 1 | file://:0:0:0:0 | type_annotations | +| extended.thrift:19:9:19:15 | typedef int | 2 | extended.thrift:19:13:19:15 | name | +| extended.thrift:19:9:19:15 | typedef int | 3 | file://:0:0:0:0 | type_annotations | +| extended.thrift:19:13:19:15 | name | 0 | extended.thrift:19:13:19:15 | IDENTIFIER int | +| extended.thrift:21:9:21:11 | type i64 | 0 | extended.thrift:21:9:21:11 | I64 i64 | +| extended.thrift:21:9:21:11 | type i64 | 0 | extended.thrift:21:9:21:11 | type i64 | +| extended.thrift:21:9:21:40 | definition | 0 | extended.thrift:21:9:21:40 | typedef shrubbery | +| extended.thrift:21:9:21:40 | typedef shrubbery | 0 | extended.thrift:21:9:21:11 | type i64 | +| extended.thrift:21:9:21:40 | typedef shrubbery | 1 | extended.thrift:21:13:21:29 | type_annotations | +| extended.thrift:21:9:21:40 | typedef shrubbery | 2 | extended.thrift:21:32:21:40 | name | +| extended.thrift:21:9:21:40 | typedef shrubbery | 3 | file://:0:0:0:0 | type_annotations | +| extended.thrift:21:13:21:19 | name | 0 | extended.thrift:21:13:21:19 | IDENTIFIER foo.bar | +| extended.thrift:21:13:21:29 | type_annotation | 0 | extended.thrift:21:13:21:19 | name | +| extended.thrift:21:13:21:29 | type_annotation | 1 | extended.thrift:21:23:21:29 | constvalue | +| extended.thrift:21:13:21:29 | type_annotations | 0 | extended.thrift:21:13:21:29 | type_annotation | +| extended.thrift:21:23:21:29 | constvalue | 0 | extended.thrift:21:23:21:29 | LITERAL "hello" | +| extended.thrift:21:32:21:40 | name | 0 | extended.thrift:21:32:21:40 | IDENTIFIER shrubbery | +| extended.thrift:23:8:23:23 | definition | 0 | extended.thrift:23:8:23:23 | struct with_annotations | +| extended.thrift:23:8:23:23 | name | 0 | extended.thrift:23:8:23:23 | IDENTIFIER with_annotations | +| extended.thrift:23:8:23:23 | struct with_annotations | 0 | extended.thrift:23:8:23:23 | name | +| extended.thrift:23:8:23:23 | struct with_annotations | 1 | extended.thrift:25:5:25:22 | field i1 | +| extended.thrift:23:8:23:23 | struct with_annotations | 2 | extended.thrift:26:5:26:37 | field i2 | +| extended.thrift:23:8:23:23 | struct with_annotations | 3 | extended.thrift:27:5:27:20 | field nice | +| extended.thrift:23:8:23:23 | struct with_annotations | 4 | extended.thrift:29:5:29:21 | type_annotations | +| extended.thrift:25:5:25:5 | fieldid | 0 | extended.thrift:25:5:25:5 | INTCONSTANT 1 | +| extended.thrift:25:5:25:22 | field i1 | 0 | extended.thrift:25:5:25:5 | fieldid | +| extended.thrift:25:5:25:22 | field i1 | 2 | extended.thrift:25:17:25:19 | type int | +| extended.thrift:25:5:25:22 | field i1 | 3 | file://:0:0:0:0 | type_annotations | +| extended.thrift:25:5:25:22 | field i1 | 4 | extended.thrift:25:21:25:22 | IDENTIFIER i1 | +| extended.thrift:25:5:25:22 | field i1 | 5 | file://:0:0:0:0 | fieldvalue | +| extended.thrift:25:5:25:22 | field i1 | 6 | file://:0:0:0:0 | xsdfieldoptions | +| extended.thrift:25:5:25:22 | field i1 | 7 | file://:0:0:0:0 | type_annotations | +| extended.thrift:25:17:25:19 | type int | 0 | extended.thrift:25:17:25:19 | IDENTIFIER int | +| extended.thrift:26:5:26:5 | fieldid | 0 | extended.thrift:26:5:26:5 | INTCONSTANT 2 | +| extended.thrift:26:5:26:37 | field i2 | 0 | extended.thrift:26:5:26:5 | fieldid | +| extended.thrift:26:5:26:37 | field i2 | 2 | extended.thrift:26:8:26:10 | type int | +| extended.thrift:26:5:26:37 | field i2 | 3 | extended.thrift:26:13:26:33 | type_annotations | +| extended.thrift:26:5:26:37 | field i2 | 4 | extended.thrift:26:36:26:37 | IDENTIFIER i2 | +| extended.thrift:26:5:26:37 | field i2 | 5 | file://:0:0:0:0 | fieldvalue | +| extended.thrift:26:5:26:37 | field i2 | 6 | file://:0:0:0:0 | xsdfieldoptions | +| extended.thrift:26:5:26:37 | field i2 | 7 | file://:0:0:0:0 | type_annotations | +| extended.thrift:26:8:26:10 | type int | 0 | extended.thrift:26:8:26:10 | IDENTIFIER int | +| extended.thrift:26:13:26:25 | name | 0 | extended.thrift:26:13:26:25 | IDENTIFIER type.annotate | +| extended.thrift:26:13:26:33 | type_annotation | 0 | extended.thrift:26:13:26:25 | name | +| extended.thrift:26:13:26:33 | type_annotation | 1 | extended.thrift:26:29:26:33 | constvalue | +| extended.thrift:26:13:26:33 | type_annotations | 0 | extended.thrift:26:13:26:33 | type_annotation | +| extended.thrift:26:29:26:33 | constvalue | 0 | extended.thrift:26:29:26:33 | LITERAL "foo" | +| extended.thrift:27:5:27:5 | fieldid | 0 | extended.thrift:27:5:27:5 | INTCONSTANT 3 | +| extended.thrift:27:5:27:20 | field nice | 0 | extended.thrift:27:5:27:5 | fieldid | +| extended.thrift:27:5:27:20 | field nice | 2 | extended.thrift:27:8:27:15 | type shubbery | +| extended.thrift:27:5:27:20 | field nice | 3 | file://:0:0:0:0 | type_annotations | +| extended.thrift:27:5:27:20 | field nice | 4 | extended.thrift:27:17:27:20 | IDENTIFIER nice | +| extended.thrift:27:5:27:20 | field nice | 5 | file://:0:0:0:0 | fieldvalue | +| extended.thrift:27:5:27:20 | field nice | 6 | file://:0:0:0:0 | xsdfieldoptions | +| extended.thrift:27:5:27:20 | field nice | 7 | extended.thrift:27:23:27:44 | type_annotations | +| extended.thrift:27:8:27:15 | type shubbery | 0 | extended.thrift:27:8:27:15 | IDENTIFIER shubbery | +| extended.thrift:27:23:27:37 | name | 0 | extended.thrift:27:23:27:37 | IDENTIFIER knights.who.say | +| extended.thrift:27:23:27:44 | type_annotation | 0 | extended.thrift:27:23:27:37 | name | +| extended.thrift:27:23:27:44 | type_annotation | 1 | extended.thrift:27:41:27:44 | constvalue | +| extended.thrift:27:23:27:44 | type_annotations | 0 | extended.thrift:27:23:27:44 | type_annotation | +| extended.thrift:27:41:27:44 | constvalue | 0 | extended.thrift:27:41:27:44 | LITERAL "ni" | +| extended.thrift:29:5:29:15 | name | 0 | extended.thrift:29:5:29:15 | IDENTIFIER struct.anno | +| extended.thrift:29:5:29:21 | type_annotation | 0 | extended.thrift:29:5:29:15 | name | +| extended.thrift:29:5:29:21 | type_annotation | 1 | extended.thrift:29:19:29:21 | constvalue | +| extended.thrift:29:5:29:21 | type_annotations | 0 | extended.thrift:29:5:29:21 | type_annotation | +| extended.thrift:29:19:29:21 | constvalue | 0 | extended.thrift:29:19:29:21 | LITERAL "y" | +| extended.thrift:31:6:31:12 | definition | 0 | extended.thrift:31:6:31:12 | enum Animals | +| extended.thrift:31:6:31:12 | enum Animals | 0 | extended.thrift:31:6:31:12 | name | +| extended.thrift:31:6:31:12 | enum Animals | 1 | extended.thrift:32:5:32:7 | enumfield cat | +| extended.thrift:31:6:31:12 | enum Animals | 2 | extended.thrift:33:5:33:9 | enumfield mouse | +| extended.thrift:31:6:31:12 | enum Animals | 3 | extended.thrift:34:5:34:7 | enumfield dog | +| extended.thrift:31:6:31:12 | enum Animals | 4 | extended.thrift:35:5:35:19 | type_annotations | +| extended.thrift:31:6:31:12 | name | 0 | extended.thrift:31:6:31:12 | IDENTIFIER Animals | +| extended.thrift:32:5:32:7 | enumfield cat | 0 | extended.thrift:32:5:32:7 | name | +| extended.thrift:32:5:32:7 | enumfield cat | 1 | extended.thrift:32:11:32:11 | enumvalue | +| extended.thrift:32:5:32:7 | enumfield cat | 2 | file://:0:0:0:0 | type_annotations | +| extended.thrift:32:5:32:7 | name | 0 | extended.thrift:32:5:32:7 | IDENTIFIER cat | +| extended.thrift:32:11:32:11 | enumvalue | 0 | extended.thrift:32:11:32:11 | INTCONSTANT 1 | +| extended.thrift:33:5:33:9 | enumfield mouse | 0 | extended.thrift:33:5:33:9 | name | +| extended.thrift:33:5:33:9 | enumfield mouse | 1 | extended.thrift:33:13:33:13 | enumvalue | +| extended.thrift:33:5:33:9 | enumfield mouse | 2 | file://:0:0:0:0 | type_annotations | +| extended.thrift:33:5:33:9 | name | 0 | extended.thrift:33:5:33:9 | IDENTIFIER mouse | +| extended.thrift:33:13:33:13 | enumvalue | 0 | extended.thrift:33:13:33:13 | INTCONSTANT 2 | +| extended.thrift:34:5:34:7 | enumfield dog | 0 | extended.thrift:34:5:34:7 | name | +| extended.thrift:34:5:34:7 | enumfield dog | 1 | file://:0:0:0:0 | enumvalue | +| extended.thrift:34:5:34:7 | enumfield dog | 2 | file://:0:0:0:0 | type_annotations | +| extended.thrift:34:5:34:7 | name | 0 | extended.thrift:34:5:34:7 | IDENTIFIER dog | +| extended.thrift:35:5:35:13 | name | 0 | extended.thrift:35:5:35:13 | IDENTIFIER enum.anno | +| extended.thrift:35:5:35:19 | type_annotation | 0 | extended.thrift:35:5:35:13 | name | +| extended.thrift:35:5:35:19 | type_annotation | 1 | extended.thrift:35:17:35:19 | constvalue | +| extended.thrift:35:5:35:19 | type_annotations | 0 | extended.thrift:35:5:35:19 | type_annotation | +| extended.thrift:35:17:35:19 | constvalue | 0 | extended.thrift:35:17:35:19 | LITERAL "x" | +| extended.thrift:37:9:37:19 | definition | 0 | extended.thrift:37:9:37:19 | service with_throws | +| extended.thrift:37:9:37:19 | name | 0 | extended.thrift:37:9:37:19 | IDENTIFIER with_throws | +| extended.thrift:37:9:37:19 | service with_throws | 0 | extended.thrift:37:9:37:19 | name | +| extended.thrift:37:9:37:19 | service with_throws | 1 | extended.thrift:39:4:39:12 | function foo | +| extended.thrift:37:9:37:19 | service with_throws | 2 | file://:0:0:0:0 | type_annotations | +| extended.thrift:39:4:39:8 | type int32 | 0 | extended.thrift:39:4:39:8 | IDENTIFIER int32 | +| extended.thrift:39:4:39:8 | type int32 | 0 | extended.thrift:39:4:39:8 | type int32 | +| extended.thrift:39:4:39:12 | function foo | 0 | file://:0:0:0:0 | oneway | +| extended.thrift:39:4:39:12 | function foo | 1 | extended.thrift:39:4:39:8 | type int32 | +| extended.thrift:39:4:39:12 | function foo | 2 | extended.thrift:39:10:39:12 | name | +| extended.thrift:39:4:39:12 | function foo | 3 | extended.thrift:39:14:39:21 | field id | +| extended.thrift:39:4:39:12 | function foo | 4 | extended.thrift:40:9:41:22 | throws | +| extended.thrift:39:4:39:12 | function foo | 5 | file://:0:0:0:0 | type_annotations | +| extended.thrift:39:10:39:12 | name | 0 | extended.thrift:39:10:39:12 | IDENTIFIER foo | +| extended.thrift:39:14:39:14 | fieldid | 0 | extended.thrift:39:14:39:14 | INTCONSTANT 1 | +| extended.thrift:39:14:39:21 | field id | 0 | extended.thrift:39:14:39:14 | fieldid | +| extended.thrift:39:14:39:21 | field id | 2 | extended.thrift:39:16:39:18 | type i32 | +| extended.thrift:39:14:39:21 | field id | 3 | file://:0:0:0:0 | type_annotations | +| extended.thrift:39:14:39:21 | field id | 4 | extended.thrift:39:20:39:21 | IDENTIFIER id | +| extended.thrift:39:14:39:21 | field id | 5 | file://:0:0:0:0 | fieldvalue | +| extended.thrift:39:14:39:21 | field id | 6 | file://:0:0:0:0 | xsdfieldoptions | +| extended.thrift:39:14:39:21 | field id | 7 | file://:0:0:0:0 | type_annotations | +| extended.thrift:39:16:39:18 | type i32 | 0 | extended.thrift:39:16:39:18 | I32 i32 | +| extended.thrift:39:16:39:18 | type i32 | 0 | extended.thrift:39:16:39:18 | type i32 | +| extended.thrift:40:9:40:9 | fieldid | 0 | extended.thrift:40:9:40:9 | INTCONSTANT 1 | +| extended.thrift:40:9:40:21 | field error | 0 | extended.thrift:40:9:40:9 | fieldid | +| extended.thrift:40:9:40:21 | field error | 2 | extended.thrift:40:11:40:15 | type Error | +| extended.thrift:40:9:40:21 | field error | 3 | file://:0:0:0:0 | type_annotations | +| extended.thrift:40:9:40:21 | field error | 4 | extended.thrift:40:17:40:21 | IDENTIFIER error | +| extended.thrift:40:9:40:21 | field error | 5 | file://:0:0:0:0 | fieldvalue | +| extended.thrift:40:9:40:21 | field error | 6 | file://:0:0:0:0 | xsdfieldoptions | +| extended.thrift:40:9:40:21 | field error | 7 | file://:0:0:0:0 | type_annotations | +| extended.thrift:40:9:41:22 | throws | 0 | extended.thrift:40:9:40:21 | field error | +| extended.thrift:40:9:41:22 | throws | 1 | extended.thrift:41:9:41:22 | field cause | +| extended.thrift:40:11:40:15 | type Error | 0 | extended.thrift:40:11:40:15 | IDENTIFIER Error | +| extended.thrift:41:9:41:9 | fieldid | 0 | extended.thrift:41:9:41:9 | INTCONSTANT 3 | +| extended.thrift:41:9:41:22 | field cause | 0 | extended.thrift:41:9:41:9 | fieldid | +| extended.thrift:41:9:41:22 | field cause | 2 | extended.thrift:41:11:41:16 | type string | +| extended.thrift:41:9:41:22 | field cause | 3 | file://:0:0:0:0 | type_annotations | +| extended.thrift:41:9:41:22 | field cause | 4 | extended.thrift:41:18:41:22 | IDENTIFIER cause | +| extended.thrift:41:9:41:22 | field cause | 5 | file://:0:0:0:0 | fieldvalue | +| extended.thrift:41:9:41:22 | field cause | 6 | file://:0:0:0:0 | xsdfieldoptions | +| extended.thrift:41:9:41:22 | field cause | 7 | file://:0:0:0:0 | type_annotations | +| extended.thrift:41:11:41:16 | type string | 0 | extended.thrift:41:11:41:16 | STRING string | +| extended.thrift:41:11:41:16 | type string | 0 | extended.thrift:41:11:41:16 | type string | +| extended.thrift:46:14:46:22 | type shrubbery | 0 | extended.thrift:46:14:46:22 | IDENTIFIER shrubbery | +| extended.thrift:46:14:46:22 | type shrubbery | 0 | extended.thrift:46:14:46:22 | type shrubbery | +| extended.thrift:46:14:46:22 | type shrubbery | 0 | extended.thrift:46:14:46:22 | type shrubbery | +| extended.thrift:46:14:46:22 | type shrubbery | 0 | extended.thrift:46:14:46:22 | type shrubbery | +| extended.thrift:46:14:46:30 | definition | 0 | extended.thrift:46:14:46:30 | typedef border | +| extended.thrift:46:14:46:30 | typedef border | 0 | extended.thrift:46:14:46:22 | type shrubbery | +| extended.thrift:46:14:46:30 | typedef border | 1 | file://:0:0:0:0 | type_annotations | +| extended.thrift:46:14:46:30 | typedef border | 2 | extended.thrift:46:25:46:30 | name | +| extended.thrift:46:14:46:30 | typedef border | 3 | extended.thrift:46:34:46:45 | type_annotations | +| extended.thrift:46:25:46:30 | name | 0 | extended.thrift:46:25:46:30 | IDENTIFIER border | +| extended.thrift:46:34:46:35 | name | 0 | extended.thrift:46:34:46:35 | IDENTIFIER ni | +| extended.thrift:46:34:46:45 | type_annotation | 0 | extended.thrift:46:34:46:35 | name | +| extended.thrift:46:34:46:45 | type_annotation | 1 | extended.thrift:46:39:46:45 | constvalue | +| extended.thrift:46:34:46:45 | type_annotations | 0 | extended.thrift:46:34:46:45 | type_annotation | +| extended.thrift:46:39:46:45 | constvalue | 0 | extended.thrift:46:39:46:45 | LITERAL "false" | +| extended.thrift:48:9:48:15 | definition | 0 | extended.thrift:48:9:48:15 | service TheShop | +| extended.thrift:48:9:48:15 | name | 0 | extended.thrift:48:9:48:15 | IDENTIFIER TheShop | +| extended.thrift:48:9:48:15 | service TheShop | 0 | extended.thrift:48:9:48:15 | name | +| extended.thrift:48:9:48:15 | service TheShop | 1 | extended.thrift:50:5:50:18 | function getPet | +| extended.thrift:48:9:48:15 | service TheShop | 2 | extended.thrift:59:5:59:32 | type_annotations | +| extended.thrift:50:5:50:11 | type Animals | 0 | extended.thrift:50:5:50:11 | IDENTIFIER Animals | +| extended.thrift:50:5:50:11 | type Animals | 0 | extended.thrift:50:5:50:11 | type Animals | +| extended.thrift:50:5:50:18 | function getPet | 0 | file://:0:0:0:0 | oneway | +| extended.thrift:50:5:50:18 | function getPet | 1 | extended.thrift:50:5:50:11 | type Animals | +| extended.thrift:50:5:50:18 | function getPet | 2 | extended.thrift:50:13:50:18 | name | +| extended.thrift:50:5:50:18 | function getPet | 3 | extended.thrift:51:9:51:30 | field owner | +| extended.thrift:50:5:50:18 | function getPet | 4 | extended.thrift:53:9:56:21 | throws | +| extended.thrift:50:5:50:18 | function getPet | 5 | file://:0:0:0:0 | type_annotations | +| extended.thrift:50:13:50:18 | name | 0 | extended.thrift:50:13:50:18 | IDENTIFIER getPet | +| extended.thrift:51:9:51:9 | fieldid | 0 | extended.thrift:51:9:51:9 | INTCONSTANT 1 | +| extended.thrift:51:9:51:30 | field owner | 0 | extended.thrift:51:9:51:9 | fieldid | +| extended.thrift:51:9:51:30 | field owner | 2 | extended.thrift:51:21:51:24 | type User | +| extended.thrift:51:9:51:30 | field owner | 3 | file://:0:0:0:0 | type_annotations | +| extended.thrift:51:9:51:30 | field owner | 4 | extended.thrift:51:26:51:30 | IDENTIFIER owner | +| extended.thrift:51:9:51:30 | field owner | 5 | file://:0:0:0:0 | fieldvalue | +| extended.thrift:51:9:51:30 | field owner | 6 | file://:0:0:0:0 | xsdfieldoptions | +| extended.thrift:51:9:51:30 | field owner | 7 | file://:0:0:0:0 | type_annotations | +| extended.thrift:51:21:51:24 | type User | 0 | extended.thrift:51:21:51:24 | IDENTIFIER User | +| extended.thrift:53:9:53:9 | fieldid | 0 | extended.thrift:53:9:53:9 | INTCONSTANT 1 | +| extended.thrift:53:9:53:24 | field napping | 0 | extended.thrift:53:9:53:9 | fieldid | +| extended.thrift:53:9:53:24 | field napping | 2 | extended.thrift:53:12:53:16 | type Error | +| extended.thrift:53:9:53:24 | field napping | 3 | file://:0:0:0:0 | type_annotations | +| extended.thrift:53:9:53:24 | field napping | 4 | extended.thrift:53:18:53:24 | IDENTIFIER napping | +| extended.thrift:53:9:53:24 | field napping | 5 | file://:0:0:0:0 | fieldvalue | +| extended.thrift:53:9:53:24 | field napping | 6 | file://:0:0:0:0 | xsdfieldoptions | +| extended.thrift:53:9:53:24 | field napping | 7 | file://:0:0:0:0 | type_annotations | +| extended.thrift:53:9:56:21 | throws | 0 | extended.thrift:53:9:53:24 | field napping | +| extended.thrift:53:9:56:21 | throws | 1 | extended.thrift:54:9:54:30 | field pining | +| extended.thrift:53:9:56:21 | throws | 2 | extended.thrift:55:9:55:35 | field resting | +| extended.thrift:53:9:56:21 | throws | 3 | extended.thrift:56:9:56:21 | field deaf | +| extended.thrift:53:12:53:16 | type Error | 0 | extended.thrift:53:12:53:16 | IDENTIFIER Error | +| extended.thrift:54:9:54:9 | fieldid | 0 | extended.thrift:54:9:54:9 | INTCONSTANT 2 | +| extended.thrift:54:9:54:30 | field pining | 0 | extended.thrift:54:9:54:9 | fieldid | +| extended.thrift:54:9:54:30 | field pining | 2 | extended.thrift:54:12:54:23 | type AnotherError | +| extended.thrift:54:9:54:30 | field pining | 3 | file://:0:0:0:0 | type_annotations | +| extended.thrift:54:9:54:30 | field pining | 4 | extended.thrift:54:25:54:30 | IDENTIFIER pining | +| extended.thrift:54:9:54:30 | field pining | 5 | file://:0:0:0:0 | fieldvalue | +| extended.thrift:54:9:54:30 | field pining | 6 | file://:0:0:0:0 | xsdfieldoptions | +| extended.thrift:54:9:54:30 | field pining | 7 | file://:0:0:0:0 | type_annotations | +| extended.thrift:54:12:54:23 | type AnotherError | 0 | extended.thrift:54:12:54:23 | IDENTIFIER AnotherError | +| extended.thrift:55:9:55:9 | fieldid | 0 | extended.thrift:55:9:55:9 | INTCONSTANT 3 | +| extended.thrift:55:9:55:35 | field resting | 0 | extended.thrift:55:9:55:9 | fieldid | +| extended.thrift:55:9:55:35 | field resting | 2 | extended.thrift:55:12:55:27 | type ThirdKindOfError | +| extended.thrift:55:9:55:35 | field resting | 3 | file://:0:0:0:0 | type_annotations | +| extended.thrift:55:9:55:35 | field resting | 4 | extended.thrift:55:29:55:35 | IDENTIFIER resting | +| extended.thrift:55:9:55:35 | field resting | 5 | file://:0:0:0:0 | fieldvalue | +| extended.thrift:55:9:55:35 | field resting | 6 | file://:0:0:0:0 | xsdfieldoptions | +| extended.thrift:55:9:55:35 | field resting | 7 | file://:0:0:0:0 | type_annotations | +| extended.thrift:55:12:55:27 | type ThirdKindOfError | 0 | extended.thrift:55:12:55:27 | IDENTIFIER ThirdKindOfError | +| extended.thrift:56:9:56:9 | fieldid | 0 | extended.thrift:56:9:56:9 | INTCONSTANT 4 | +| extended.thrift:56:9:56:21 | field deaf | 0 | extended.thrift:56:9:56:9 | fieldid | +| extended.thrift:56:9:56:21 | field deaf | 2 | extended.thrift:56:12:56:16 | type Error | +| extended.thrift:56:9:56:21 | field deaf | 3 | file://:0:0:0:0 | type_annotations | +| extended.thrift:56:9:56:21 | field deaf | 4 | extended.thrift:56:18:56:21 | IDENTIFIER deaf | +| extended.thrift:56:9:56:21 | field deaf | 5 | file://:0:0:0:0 | fieldvalue | +| extended.thrift:56:9:56:21 | field deaf | 6 | file://:0:0:0:0 | xsdfieldoptions | +| extended.thrift:56:9:56:21 | field deaf | 7 | file://:0:0:0:0 | type_annotations | +| extended.thrift:56:12:56:16 | type Error | 0 | extended.thrift:56:12:56:16 | IDENTIFIER Error | +| extended.thrift:59:5:59:22 | name | 0 | extended.thrift:59:5:59:22 | IDENTIFIER service.annotation | +| extended.thrift:59:5:59:32 | type_annotation | 0 | extended.thrift:59:5:59:22 | name | +| extended.thrift:59:5:59:32 | type_annotation | 1 | extended.thrift:59:26:59:32 | constvalue | +| extended.thrift:59:5:59:32 | type_annotations | 0 | extended.thrift:59:5:59:32 | type_annotation | +| extended.thrift:59:26:59:32 | constvalue | 0 | extended.thrift:59:26:59:32 | LITERAL "thing" | +| test.thrift:3:9:3:23 | header | 0 | test.thrift:3:9:3:23 | include | +| test.thrift:3:9:3:23 | include | 0 | test.thrift:3:9:3:23 | LITERAL "shared.thrift" | +| test.thrift:3:9:83:17 | document | 0 | test.thrift:3:9:3:23 | header | +| test.thrift:3:9:83:17 | document | 1 | file://:0:0:0:0 | header | +| test.thrift:3:9:83:17 | document | 2 | file://:0:0:0:0 | header | +| test.thrift:3:9:83:17 | document | 3 | file://:0:0:0:0 | header | +| test.thrift:3:9:83:17 | document | 4 | file://:0:0:0:0 | header | +| test.thrift:3:9:83:17 | document | 5 | file://:0:0:0:0 | header | +| test.thrift:3:9:83:17 | document | 6 | test.thrift:15:7:15:30 | definition | +| test.thrift:3:9:83:17 | document | 7 | test.thrift:16:11:16:75 | definition | +| test.thrift:3:9:83:17 | document | 8 | test.thrift:22:6:22:14 | definition | +| test.thrift:3:9:83:17 | document | 9 | test.thrift:38:8:38:11 | definition | +| test.thrift:3:9:83:17 | document | 10 | test.thrift:48:11:48:26 | definition | +| test.thrift:3:9:83:17 | document | 11 | test.thrift:57:9:57:18 | definition | +| test.thrift:3:9:83:17 | document | 12 | test.thrift:83:9:83:17 | definition | +| test.thrift:3:9:83:17 | start | 0 | test.thrift:3:9:83:17 | document | +| test.thrift:15:7:15:9 | type i32 | 0 | test.thrift:15:7:15:9 | I32 i32 | +| test.thrift:15:7:15:9 | type i32 | 0 | test.thrift:15:7:15:9 | type i32 | +| test.thrift:15:7:15:30 | const | 0 | test.thrift:15:7:15:9 | type i32 | +| test.thrift:15:7:15:30 | const | 1 | test.thrift:15:11:15:23 | name | +| test.thrift:15:7:15:30 | const | 2 | test.thrift:15:27:15:30 | constvalue | +| test.thrift:15:7:15:30 | definition | 0 | test.thrift:15:7:15:30 | const | +| test.thrift:15:11:15:23 | name | 0 | test.thrift:15:11:15:23 | IDENTIFIER INT32CONSTANT | +| test.thrift:15:27:15:30 | constvalue | 0 | test.thrift:15:27:15:30 | INTCONSTANT 9853 | +| test.thrift:16:11:16:16 | type string | 0 | test.thrift:16:11:16:16 | STRING string | +| test.thrift:16:11:16:16 | type string | 0 | test.thrift:16:11:16:16 | type string | +| test.thrift:16:11:16:16 | type string | 0 | test.thrift:16:11:16:16 | type string | +| test.thrift:16:11:16:16 | type string | 0 | test.thrift:16:11:16:16 | type string | +| test.thrift:16:11:16:16 | type string | 0 | test.thrift:16:11:16:16 | type string | +| test.thrift:16:11:16:16 | type string | 1 | test.thrift:16:18:16:23 | type string | +| test.thrift:16:11:16:75 | const | 0 | test.thrift:16:11:16:16 | type string | +| test.thrift:16:11:16:75 | const | 1 | test.thrift:16:26:16:36 | name | +| test.thrift:16:11:16:75 | const | 2 | test.thrift:16:41:16:75 | constvalue | +| test.thrift:16:11:16:75 | definition | 0 | test.thrift:16:11:16:75 | const | +| test.thrift:16:18:16:23 | type string | 0 | test.thrift:16:18:16:23 | STRING string | +| test.thrift:16:18:16:23 | type string | 0 | test.thrift:16:18:16:23 | type string | +| test.thrift:16:26:16:36 | name | 0 | test.thrift:16:26:16:36 | IDENTIFIER MAPCONSTANT | +| test.thrift:16:41:16:47 | constvalue | 0 | test.thrift:16:41:16:47 | LITERAL 'hello' | +| test.thrift:16:41:16:55 | constmapelt | 0 | test.thrift:16:41:16:47 | constvalue | +| test.thrift:16:41:16:55 | constmapelt | 1 | test.thrift:16:49:16:55 | constvalue | +| test.thrift:16:41:16:75 | constmap | 0 | test.thrift:16:41:16:55 | constmapelt | +| test.thrift:16:41:16:75 | constmap | 1 | test.thrift:16:58:16:75 | constmapelt | +| test.thrift:16:41:16:75 | constvalue | 0 | test.thrift:16:41:16:75 | constmap | +| test.thrift:16:49:16:55 | constvalue | 0 | test.thrift:16:49:16:55 | LITERAL 'world' | +| test.thrift:16:58:16:68 | constvalue | 0 | test.thrift:16:58:16:68 | LITERAL 'goodnight' | +| test.thrift:16:58:16:75 | constmapelt | 0 | test.thrift:16:58:16:68 | constvalue | +| test.thrift:16:58:16:75 | constmapelt | 1 | test.thrift:16:70:16:75 | constvalue | +| test.thrift:16:70:16:75 | constvalue | 0 | test.thrift:16:70:16:75 | LITERAL 'moon' | +| test.thrift:22:6:22:14 | definition | 0 | test.thrift:22:6:22:14 | enum Operation | +| test.thrift:22:6:22:14 | enum Operation | 0 | test.thrift:22:6:22:14 | name | +| test.thrift:22:6:22:14 | enum Operation | 1 | test.thrift:23:3:23:5 | enumfield ADD | +| test.thrift:22:6:22:14 | enum Operation | 2 | test.thrift:24:3:24:10 | enumfield SUBTRACT | +| test.thrift:22:6:22:14 | enum Operation | 3 | test.thrift:25:3:25:10 | enumfield MULTIPLY | +| test.thrift:22:6:22:14 | enum Operation | 4 | test.thrift:26:3:26:8 | enumfield DIVIDE | +| test.thrift:22:6:22:14 | enum Operation | 5 | file://:0:0:0:0 | type_annotations | +| test.thrift:22:6:22:14 | name | 0 | test.thrift:22:6:22:14 | IDENTIFIER Operation | +| test.thrift:23:3:23:5 | enumfield ADD | 0 | test.thrift:23:3:23:5 | name | +| test.thrift:23:3:23:5 | enumfield ADD | 1 | test.thrift:23:9:23:9 | enumvalue | +| test.thrift:23:3:23:5 | enumfield ADD | 2 | file://:0:0:0:0 | type_annotations | +| test.thrift:23:3:23:5 | name | 0 | test.thrift:23:3:23:5 | IDENTIFIER ADD | +| test.thrift:23:9:23:9 | enumvalue | 0 | test.thrift:23:9:23:9 | INTCONSTANT 1 | +| test.thrift:24:3:24:10 | enumfield SUBTRACT | 0 | test.thrift:24:3:24:10 | name | +| test.thrift:24:3:24:10 | enumfield SUBTRACT | 1 | test.thrift:24:14:24:14 | enumvalue | +| test.thrift:24:3:24:10 | enumfield SUBTRACT | 2 | file://:0:0:0:0 | type_annotations | +| test.thrift:24:3:24:10 | name | 0 | test.thrift:24:3:24:10 | IDENTIFIER SUBTRACT | +| test.thrift:24:14:24:14 | enumvalue | 0 | test.thrift:24:14:24:14 | INTCONSTANT 2 | +| test.thrift:25:3:25:10 | enumfield MULTIPLY | 0 | test.thrift:25:3:25:10 | name | +| test.thrift:25:3:25:10 | enumfield MULTIPLY | 1 | test.thrift:25:14:25:14 | enumvalue | +| test.thrift:25:3:25:10 | enumfield MULTIPLY | 2 | file://:0:0:0:0 | type_annotations | +| test.thrift:25:3:25:10 | name | 0 | test.thrift:25:3:25:10 | IDENTIFIER MULTIPLY | +| test.thrift:25:14:25:14 | enumvalue | 0 | test.thrift:25:14:25:14 | INTCONSTANT 3 | +| test.thrift:26:3:26:8 | enumfield DIVIDE | 0 | test.thrift:26:3:26:8 | name | +| test.thrift:26:3:26:8 | enumfield DIVIDE | 1 | test.thrift:26:12:26:12 | enumvalue | +| test.thrift:26:3:26:8 | enumfield DIVIDE | 2 | file://:0:0:0:0 | type_annotations | +| test.thrift:26:3:26:8 | name | 0 | test.thrift:26:3:26:8 | IDENTIFIER DIVIDE | +| test.thrift:26:12:26:12 | enumvalue | 0 | test.thrift:26:12:26:12 | INTCONSTANT 4 | +| test.thrift:38:8:38:11 | definition | 0 | test.thrift:38:8:38:11 | struct Work | +| test.thrift:38:8:38:11 | name | 0 | test.thrift:38:8:38:11 | IDENTIFIER Work | +| test.thrift:38:8:38:11 | struct Work | 0 | test.thrift:38:8:38:11 | name | +| test.thrift:38:8:38:11 | struct Work | 1 | test.thrift:39:3:39:13 | field num1 | +| test.thrift:38:8:38:11 | struct Work | 2 | test.thrift:40:3:40:13 | field num2 | +| test.thrift:38:8:38:11 | struct Work | 3 | test.thrift:41:3:41:17 | field op | +| test.thrift:38:8:38:11 | struct Work | 4 | test.thrift:42:3:42:28 | field comment | +| test.thrift:38:8:38:11 | struct Work | 5 | file://:0:0:0:0 | type_annotations | +| test.thrift:39:3:39:3 | fieldid | 0 | test.thrift:39:3:39:3 | INTCONSTANT 1 | +| test.thrift:39:3:39:13 | field num1 | 0 | test.thrift:39:3:39:3 | fieldid | +| test.thrift:39:3:39:13 | field num1 | 2 | test.thrift:39:6:39:8 | type i32 | +| test.thrift:39:3:39:13 | field num1 | 3 | file://:0:0:0:0 | type_annotations | +| test.thrift:39:3:39:13 | field num1 | 4 | test.thrift:39:10:39:13 | IDENTIFIER num1 | +| test.thrift:39:3:39:13 | field num1 | 5 | test.thrift:39:17:39:17 | fieldvalue | +| test.thrift:39:3:39:13 | field num1 | 6 | file://:0:0:0:0 | xsdfieldoptions | +| test.thrift:39:3:39:13 | field num1 | 7 | file://:0:0:0:0 | type_annotations | +| test.thrift:39:6:39:8 | type i32 | 0 | test.thrift:39:6:39:8 | I32 i32 | +| test.thrift:39:6:39:8 | type i32 | 0 | test.thrift:39:6:39:8 | type i32 | +| test.thrift:39:17:39:17 | constvalue | 0 | test.thrift:39:17:39:17 | INTCONSTANT 0 | +| test.thrift:39:17:39:17 | fieldvalue | 0 | test.thrift:39:17:39:17 | constvalue | +| test.thrift:40:3:40:3 | fieldid | 0 | test.thrift:40:3:40:3 | INTCONSTANT 2 | +| test.thrift:40:3:40:13 | field num2 | 0 | test.thrift:40:3:40:3 | fieldid | +| test.thrift:40:3:40:13 | field num2 | 2 | test.thrift:40:6:40:8 | type i32 | +| test.thrift:40:3:40:13 | field num2 | 3 | file://:0:0:0:0 | type_annotations | +| test.thrift:40:3:40:13 | field num2 | 4 | test.thrift:40:10:40:13 | IDENTIFIER num2 | +| test.thrift:40:3:40:13 | field num2 | 5 | file://:0:0:0:0 | fieldvalue | +| test.thrift:40:3:40:13 | field num2 | 6 | file://:0:0:0:0 | xsdfieldoptions | +| test.thrift:40:3:40:13 | field num2 | 7 | file://:0:0:0:0 | type_annotations | +| test.thrift:40:6:40:8 | type i32 | 0 | test.thrift:40:6:40:8 | I32 i32 | +| test.thrift:40:6:40:8 | type i32 | 0 | test.thrift:40:6:40:8 | type i32 | +| test.thrift:41:3:41:3 | fieldid | 0 | test.thrift:41:3:41:3 | INTCONSTANT 3 | +| test.thrift:41:3:41:17 | field op | 0 | test.thrift:41:3:41:3 | fieldid | +| test.thrift:41:3:41:17 | field op | 2 | test.thrift:41:6:41:14 | type Operation | +| test.thrift:41:3:41:17 | field op | 3 | file://:0:0:0:0 | type_annotations | +| test.thrift:41:3:41:17 | field op | 4 | test.thrift:41:16:41:17 | IDENTIFIER op | +| test.thrift:41:3:41:17 | field op | 5 | file://:0:0:0:0 | fieldvalue | +| test.thrift:41:3:41:17 | field op | 6 | file://:0:0:0:0 | xsdfieldoptions | +| test.thrift:41:3:41:17 | field op | 7 | file://:0:0:0:0 | type_annotations | +| test.thrift:41:6:41:14 | type Operation | 0 | test.thrift:41:6:41:14 | IDENTIFIER Operation | +| test.thrift:42:3:42:3 | fieldid | 0 | test.thrift:42:3:42:3 | INTCONSTANT 4 | +| test.thrift:42:3:42:28 | field comment | 0 | test.thrift:42:3:42:3 | fieldid | +| test.thrift:42:3:42:28 | field comment | 2 | test.thrift:42:15:42:20 | type string | +| test.thrift:42:3:42:28 | field comment | 3 | file://:0:0:0:0 | type_annotations | +| test.thrift:42:3:42:28 | field comment | 4 | test.thrift:42:22:42:28 | IDENTIFIER comment | +| test.thrift:42:3:42:28 | field comment | 5 | file://:0:0:0:0 | fieldvalue | +| test.thrift:42:3:42:28 | field comment | 6 | file://:0:0:0:0 | xsdfieldoptions | +| test.thrift:42:3:42:28 | field comment | 7 | file://:0:0:0:0 | type_annotations | +| test.thrift:42:15:42:20 | type string | 0 | test.thrift:42:15:42:20 | STRING string | +| test.thrift:42:15:42:20 | type string | 0 | test.thrift:42:15:42:20 | type string | +| test.thrift:48:11:48:26 | definition | 0 | test.thrift:48:11:48:26 | exception InvalidOperation | +| test.thrift:48:11:48:26 | exception InvalidOperation | 0 | test.thrift:48:11:48:26 | name | +| test.thrift:48:11:48:26 | exception InvalidOperation | 1 | test.thrift:49:3:49:13 | field what | +| test.thrift:48:11:48:26 | exception InvalidOperation | 2 | test.thrift:50:3:50:15 | field why | +| test.thrift:48:11:48:26 | name | 0 | test.thrift:48:11:48:26 | IDENTIFIER InvalidOperation | +| test.thrift:49:3:49:3 | fieldid | 0 | test.thrift:49:3:49:3 | INTCONSTANT 1 | +| test.thrift:49:3:49:13 | field what | 0 | test.thrift:49:3:49:3 | fieldid | +| test.thrift:49:3:49:13 | field what | 2 | test.thrift:49:6:49:8 | type i32 | +| test.thrift:49:3:49:13 | field what | 3 | file://:0:0:0:0 | type_annotations | +| test.thrift:49:3:49:13 | field what | 4 | test.thrift:49:10:49:13 | IDENTIFIER what | +| test.thrift:49:3:49:13 | field what | 5 | file://:0:0:0:0 | fieldvalue | +| test.thrift:49:3:49:13 | field what | 6 | file://:0:0:0:0 | xsdfieldoptions | +| test.thrift:49:3:49:13 | field what | 7 | file://:0:0:0:0 | type_annotations | +| test.thrift:49:6:49:8 | type i32 | 0 | test.thrift:49:6:49:8 | I32 i32 | +| test.thrift:49:6:49:8 | type i32 | 0 | test.thrift:49:6:49:8 | type i32 | +| test.thrift:50:3:50:3 | fieldid | 0 | test.thrift:50:3:50:3 | INTCONSTANT 2 | +| test.thrift:50:3:50:15 | field why | 0 | test.thrift:50:3:50:3 | fieldid | +| test.thrift:50:3:50:15 | field why | 2 | test.thrift:50:6:50:11 | type string | +| test.thrift:50:3:50:15 | field why | 3 | file://:0:0:0:0 | type_annotations | +| test.thrift:50:3:50:15 | field why | 4 | test.thrift:50:13:50:15 | IDENTIFIER why | +| test.thrift:50:3:50:15 | field why | 5 | file://:0:0:0:0 | fieldvalue | +| test.thrift:50:3:50:15 | field why | 6 | file://:0:0:0:0 | xsdfieldoptions | +| test.thrift:50:3:50:15 | field why | 7 | file://:0:0:0:0 | type_annotations | +| test.thrift:50:6:50:11 | type string | 0 | test.thrift:50:6:50:11 | STRING string | +| test.thrift:50:6:50:11 | type string | 0 | test.thrift:50:6:50:11 | type string | +| test.thrift:57:9:57:18 | definition | 0 | test.thrift:57:9:57:18 | service Calculator | +| test.thrift:57:9:57:18 | name | 0 | test.thrift:57:9:57:18 | IDENTIFIER Calculator | +| test.thrift:57:9:57:18 | service Calculator | 0 | test.thrift:57:9:57:18 | name | +| test.thrift:57:9:57:18 | service Calculator | 1 | test.thrift:57:28:57:47 | extends | +| test.thrift:57:9:57:18 | service Calculator | 2 | test.thrift:66:4:66:12 | function ping | +| test.thrift:57:9:57:18 | service Calculator | 3 | test.thrift:68:4:68:10 | function add | +| test.thrift:57:9:57:18 | service Calculator | 4 | test.thrift:70:4:70:16 | function calculate | +| test.thrift:57:9:57:18 | service Calculator | 5 | test.thrift:77:11:77:18 | function zip | +| test.thrift:57:9:57:18 | service Calculator | 6 | file://:0:0:0:0 | type_annotations | +| test.thrift:57:28:57:47 | extends | 0 | test.thrift:57:28:57:47 | IDENTIFIER shared.SharedService | +| test.thrift:66:4:66:7 | type void | 0 | test.thrift:66:4:66:7 | VOID void | +| test.thrift:66:4:66:12 | function ping | 0 | file://:0:0:0:0 | oneway | +| test.thrift:66:4:66:12 | function ping | 1 | test.thrift:66:4:66:7 | type void | +| test.thrift:66:4:66:12 | function ping | 2 | test.thrift:66:9:66:12 | name | +| test.thrift:66:4:66:12 | function ping | 3 | file://:0:0:0:0 | throws | +| test.thrift:66:4:66:12 | function ping | 4 | file://:0:0:0:0 | type_annotations | +| test.thrift:66:9:66:12 | name | 0 | test.thrift:66:9:66:12 | IDENTIFIER ping | +| test.thrift:68:4:68:6 | type i32 | 0 | test.thrift:68:4:68:6 | I32 i32 | +| test.thrift:68:4:68:6 | type i32 | 0 | test.thrift:68:4:68:6 | type i32 | +| test.thrift:68:4:68:6 | type i32 | 0 | test.thrift:68:4:68:6 | type i32 | +| test.thrift:68:4:68:10 | function add | 0 | file://:0:0:0:0 | oneway | +| test.thrift:68:4:68:10 | function add | 1 | test.thrift:68:4:68:6 | type i32 | +| test.thrift:68:4:68:10 | function add | 2 | test.thrift:68:8:68:10 | name | +| test.thrift:68:4:68:10 | function add | 3 | test.thrift:68:12:68:21 | field num1 | +| test.thrift:68:4:68:10 | function add | 4 | test.thrift:68:24:68:33 | field num2 | +| test.thrift:68:4:68:10 | function add | 5 | file://:0:0:0:0 | throws | +| test.thrift:68:4:68:10 | function add | 6 | file://:0:0:0:0 | type_annotations | +| test.thrift:68:8:68:10 | name | 0 | test.thrift:68:8:68:10 | IDENTIFIER add | +| test.thrift:68:12:68:12 | fieldid | 0 | test.thrift:68:12:68:12 | INTCONSTANT 1 | +| test.thrift:68:12:68:21 | field num1 | 0 | test.thrift:68:12:68:12 | fieldid | +| test.thrift:68:12:68:21 | field num1 | 2 | test.thrift:68:14:68:16 | type i32 | +| test.thrift:68:12:68:21 | field num1 | 3 | file://:0:0:0:0 | type_annotations | +| test.thrift:68:12:68:21 | field num1 | 4 | test.thrift:68:18:68:21 | IDENTIFIER num1 | +| test.thrift:68:12:68:21 | field num1 | 5 | file://:0:0:0:0 | fieldvalue | +| test.thrift:68:12:68:21 | field num1 | 6 | file://:0:0:0:0 | xsdfieldoptions | +| test.thrift:68:12:68:21 | field num1 | 7 | file://:0:0:0:0 | type_annotations | +| test.thrift:68:14:68:16 | type i32 | 0 | test.thrift:68:14:68:16 | I32 i32 | +| test.thrift:68:14:68:16 | type i32 | 0 | test.thrift:68:14:68:16 | type i32 | +| test.thrift:68:24:68:24 | fieldid | 0 | test.thrift:68:24:68:24 | INTCONSTANT 2 | +| test.thrift:68:24:68:33 | field num2 | 0 | test.thrift:68:24:68:24 | fieldid | +| test.thrift:68:24:68:33 | field num2 | 2 | test.thrift:68:26:68:28 | type i32 | +| test.thrift:68:24:68:33 | field num2 | 3 | file://:0:0:0:0 | type_annotations | +| test.thrift:68:24:68:33 | field num2 | 4 | test.thrift:68:30:68:33 | IDENTIFIER num2 | +| test.thrift:68:24:68:33 | field num2 | 5 | file://:0:0:0:0 | fieldvalue | +| test.thrift:68:24:68:33 | field num2 | 6 | file://:0:0:0:0 | xsdfieldoptions | +| test.thrift:68:24:68:33 | field num2 | 7 | file://:0:0:0:0 | type_annotations | +| test.thrift:68:26:68:28 | type i32 | 0 | test.thrift:68:26:68:28 | I32 i32 | +| test.thrift:68:26:68:28 | type i32 | 0 | test.thrift:68:26:68:28 | type i32 | +| test.thrift:70:4:70:6 | type i32 | 0 | test.thrift:70:4:70:6 | I32 i32 | +| test.thrift:70:4:70:6 | type i32 | 0 | test.thrift:70:4:70:6 | type i32 | +| test.thrift:70:4:70:6 | type i32 | 0 | test.thrift:70:4:70:6 | type i32 | +| test.thrift:70:4:70:16 | function calculate | 0 | file://:0:0:0:0 | oneway | +| test.thrift:70:4:70:16 | function calculate | 1 | test.thrift:70:4:70:6 | type i32 | +| test.thrift:70:4:70:16 | function calculate | 2 | test.thrift:70:8:70:16 | name | +| test.thrift:70:4:70:16 | function calculate | 3 | test.thrift:70:18:70:28 | field logid | +| test.thrift:70:4:70:16 | function calculate | 4 | test.thrift:70:31:70:38 | field w | +| test.thrift:70:4:70:16 | function calculate | 5 | test.thrift:70:49:70:71 | throws | +| test.thrift:70:4:70:16 | function calculate | 6 | file://:0:0:0:0 | type_annotations | +| test.thrift:70:8:70:16 | name | 0 | test.thrift:70:8:70:16 | IDENTIFIER calculate | +| test.thrift:70:18:70:18 | fieldid | 0 | test.thrift:70:18:70:18 | INTCONSTANT 1 | +| test.thrift:70:18:70:28 | field logid | 0 | test.thrift:70:18:70:18 | fieldid | +| test.thrift:70:18:70:28 | field logid | 2 | test.thrift:70:20:70:22 | type i32 | +| test.thrift:70:18:70:28 | field logid | 3 | file://:0:0:0:0 | type_annotations | +| test.thrift:70:18:70:28 | field logid | 4 | test.thrift:70:24:70:28 | IDENTIFIER logid | +| test.thrift:70:18:70:28 | field logid | 5 | file://:0:0:0:0 | fieldvalue | +| test.thrift:70:18:70:28 | field logid | 6 | file://:0:0:0:0 | xsdfieldoptions | +| test.thrift:70:18:70:28 | field logid | 7 | file://:0:0:0:0 | type_annotations | +| test.thrift:70:20:70:22 | type i32 | 0 | test.thrift:70:20:70:22 | I32 i32 | +| test.thrift:70:20:70:22 | type i32 | 0 | test.thrift:70:20:70:22 | type i32 | +| test.thrift:70:31:70:31 | fieldid | 0 | test.thrift:70:31:70:31 | INTCONSTANT 2 | +| test.thrift:70:31:70:38 | field w | 0 | test.thrift:70:31:70:31 | fieldid | +| test.thrift:70:31:70:38 | field w | 2 | test.thrift:70:33:70:36 | type Work | +| test.thrift:70:31:70:38 | field w | 3 | file://:0:0:0:0 | type_annotations | +| test.thrift:70:31:70:38 | field w | 4 | test.thrift:70:38:70:38 | IDENTIFIER w | +| test.thrift:70:31:70:38 | field w | 5 | file://:0:0:0:0 | fieldvalue | +| test.thrift:70:31:70:38 | field w | 6 | file://:0:0:0:0 | xsdfieldoptions | +| test.thrift:70:31:70:38 | field w | 7 | file://:0:0:0:0 | type_annotations | +| test.thrift:70:33:70:36 | type Work | 0 | test.thrift:70:33:70:36 | IDENTIFIER Work | +| test.thrift:70:49:70:49 | fieldid | 0 | test.thrift:70:49:70:49 | INTCONSTANT 1 | +| test.thrift:70:49:70:71 | field ouch | 0 | test.thrift:70:49:70:49 | fieldid | +| test.thrift:70:49:70:71 | field ouch | 2 | test.thrift:70:51:70:66 | type InvalidOperation | +| test.thrift:70:49:70:71 | field ouch | 3 | file://:0:0:0:0 | type_annotations | +| test.thrift:70:49:70:71 | field ouch | 4 | test.thrift:70:68:70:71 | IDENTIFIER ouch | +| test.thrift:70:49:70:71 | field ouch | 5 | file://:0:0:0:0 | fieldvalue | +| test.thrift:70:49:70:71 | field ouch | 6 | file://:0:0:0:0 | xsdfieldoptions | +| test.thrift:70:49:70:71 | field ouch | 7 | file://:0:0:0:0 | type_annotations | +| test.thrift:70:49:70:71 | throws | 0 | test.thrift:70:49:70:71 | field ouch | +| test.thrift:70:51:70:66 | type InvalidOperation | 0 | test.thrift:70:51:70:66 | IDENTIFIER InvalidOperation | +| test.thrift:77:11:77:14 | type void | 0 | test.thrift:77:11:77:14 | VOID void | +| test.thrift:77:11:77:18 | function zip | 0 | file://:0:0:0:0 | oneway | +| test.thrift:77:11:77:18 | function zip | 1 | test.thrift:77:11:77:14 | type void | +| test.thrift:77:11:77:18 | function zip | 2 | test.thrift:77:16:77:18 | name | +| test.thrift:77:11:77:18 | function zip | 3 | file://:0:0:0:0 | throws | +| test.thrift:77:11:77:18 | function zip | 4 | file://:0:0:0:0 | type_annotations | +| test.thrift:77:16:77:18 | name | 0 | test.thrift:77:16:77:18 | IDENTIFIER zip | +| test.thrift:83:9:83:12 | type wood | 0 | test.thrift:83:9:83:12 | IDENTIFIER wood | +| test.thrift:83:9:83:17 | definition | 0 | test.thrift:83:9:83:17 | typedef duck | +| test.thrift:83:9:83:17 | typedef duck | 0 | test.thrift:83:9:83:12 | type wood | +| test.thrift:83:9:83:17 | typedef duck | 1 | file://:0:0:0:0 | type_annotations | +| test.thrift:83:9:83:17 | typedef duck | 2 | test.thrift:83:14:83:17 | name | +| test.thrift:83:9:83:17 | typedef duck | 3 | file://:0:0:0:0 | type_annotations | +| test.thrift:83:14:83:17 | name | 0 | test.thrift:83:14:83:17 | IDENTIFIER duck | diff --git a/python/ql/test/library-tests/thrift/Child.ql b/python/ql/test/library-tests/thrift/Child.ql new file mode 100644 index 00000000000..5645c53ddb0 --- /dev/null +++ b/python/ql/test/library-tests/thrift/Child.ql @@ -0,0 +1,5 @@ + +import external.Thrift + +from ThriftElement t, int n +select t, n, t.getChild(n) diff --git a/python/ql/test/library-tests/thrift/File.expected b/python/ql/test/library-tests/thrift/File.expected new file mode 100644 index 00000000000..501035c79c4 --- /dev/null +++ b/python/ql/test/library-tests/thrift/File.expected @@ -0,0 +1,63 @@ +| ADD | test.thrift | +| Animals | extended.thrift | +| AnotherError | extended.thrift | +| Calculator | test.thrift | +| DIVIDE | test.thrift | +| Error | extended.thrift | +| Extended | extended.thrift | +| InvalidOperation | test.thrift | +| MULTIPLY | test.thrift | +| Operation | test.thrift | +| SUBTRACT | test.thrift | +| TheShop | extended.thrift | +| ThirdKindOfError | extended.thrift | +| User | extended.thrift | +| Work | test.thrift | +| add | test.thrift | +| border | extended.thrift | +| calculate | test.thrift | +| cat | extended.thrift | +| cause | extended.thrift | +| comment | test.thrift | +| deaf | extended.thrift | +| dog | extended.thrift | +| duck | test.thrift | +| error | extended.thrift | +| foo | extended.thrift | +| getPet | extended.thrift | +| getUser | extended.thrift | +| i1 | extended.thrift | +| i2 | extended.thrift | +| i32 | extended.thrift | +| i32 | test.thrift | +| i64 | extended.thrift | +| id | extended.thrift | +| int | extended.thrift | +| int32 | extended.thrift | +| logid | test.thrift | +| mouse | extended.thrift | +| name | extended.thrift | +| napping | extended.thrift | +| nice | extended.thrift | +| num1 | test.thrift | +| num2 | test.thrift | +| op | test.thrift | +| ouch | test.thrift | +| owner | extended.thrift | +| ping | test.thrift | +| pining | extended.thrift | +| resting | extended.thrift | +| shrubbery | extended.thrift | +| shubbery | extended.thrift | +| string | extended.thrift | +| string | test.thrift | +| void | test.thrift | +| w | test.thrift | +| what | extended.thrift | +| what | test.thrift | +| why | extended.thrift | +| why | test.thrift | +| with_annotations | extended.thrift | +| with_throws | extended.thrift | +| wood | test.thrift | +| zip | test.thrift | diff --git a/python/ql/test/library-tests/thrift/File.ql b/python/ql/test/library-tests/thrift/File.ql new file mode 100644 index 00000000000..e4f497dbd01 --- /dev/null +++ b/python/ql/test/library-tests/thrift/File.ql @@ -0,0 +1,7 @@ + +import external.Thrift + + +from ThriftNamedElement t + +select t.getName(), t.getFile().getBaseName() \ No newline at end of file diff --git a/python/ql/test/library-tests/thrift/Function.expected b/python/ql/test/library-tests/thrift/Function.expected new file mode 100644 index 00000000000..7c05f8fb671 --- /dev/null +++ b/python/ql/test/library-tests/thrift/Function.expected @@ -0,0 +1,20 @@ +| extended.thrift:14:4:14:15 | function getUser | 0 | extended.thrift:14:17:14:24 | field id | +| extended.thrift:14:4:14:15 | function getUser | returns | extended.thrift:14:4:14:7 | type User | +| extended.thrift:14:4:14:15 | function getUser | throws | extended.thrift:14:35:14:47 | field error | +| extended.thrift:39:4:39:12 | function foo | 0 | extended.thrift:39:14:39:21 | field id | +| extended.thrift:39:4:39:12 | function foo | returns | extended.thrift:39:4:39:8 | type int32 | +| extended.thrift:39:4:39:12 | function foo | throws | extended.thrift:40:9:40:21 | field error | +| extended.thrift:39:4:39:12 | function foo | throws | extended.thrift:41:9:41:22 | field cause | +| extended.thrift:50:5:50:18 | function getPet | 0 | extended.thrift:51:9:51:30 | field owner | +| extended.thrift:50:5:50:18 | function getPet | returns | extended.thrift:50:5:50:11 | type Animals | +| extended.thrift:50:5:50:18 | function getPet | throws | extended.thrift:53:9:53:24 | field napping | +| extended.thrift:50:5:50:18 | function getPet | throws | extended.thrift:54:9:54:30 | field pining | +| extended.thrift:50:5:50:18 | function getPet | throws | extended.thrift:55:9:55:35 | field resting | +| extended.thrift:50:5:50:18 | function getPet | throws | extended.thrift:56:9:56:21 | field deaf | +| test.thrift:68:4:68:10 | function add | 0 | test.thrift:68:12:68:21 | field num1 | +| test.thrift:68:4:68:10 | function add | 1 | test.thrift:68:24:68:33 | field num2 | +| test.thrift:68:4:68:10 | function add | returns | test.thrift:68:4:68:6 | type i32 | +| test.thrift:70:4:70:16 | function calculate | 0 | test.thrift:70:18:70:28 | field logid | +| test.thrift:70:4:70:16 | function calculate | 1 | test.thrift:70:31:70:38 | field w | +| test.thrift:70:4:70:16 | function calculate | returns | test.thrift:70:4:70:6 | type i32 | +| test.thrift:70:4:70:16 | function calculate | throws | test.thrift:70:49:70:71 | field ouch | diff --git a/python/ql/test/library-tests/thrift/Function.ql b/python/ql/test/library-tests/thrift/Function.ql new file mode 100644 index 00000000000..ff891bd5ece --- /dev/null +++ b/python/ql/test/library-tests/thrift/Function.ql @@ -0,0 +1,12 @@ + +import external.Thrift + +from ThriftFunction t, string n, ThriftElement x +where +exists(int i | x = t.getArgument(i) and n = i.toString()) +or +x = t.getAThrows() and n = "throws" +or +x = t.getReturnType() and n = "returns" + +select t, n, x \ No newline at end of file diff --git a/python/ql/test/library-tests/thrift/References.expected b/python/ql/test/library-tests/thrift/References.expected new file mode 100644 index 00000000000..add320353f8 --- /dev/null +++ b/python/ql/test/library-tests/thrift/References.expected @@ -0,0 +1,4 @@ +| extended.thrift:14:4:14:7 | type User | extended.thrift:3:8:3:11 | struct User | +| extended.thrift:14:4:14:7 | type User | extended.thrift:3:8:3:11 | struct User | +| extended.thrift:51:21:51:24 | type User | extended.thrift:3:8:3:11 | struct User | +| test.thrift:70:33:70:36 | type Work | test.thrift:38:8:38:11 | struct Work | diff --git a/python/ql/test/library-tests/thrift/References.ql b/python/ql/test/library-tests/thrift/References.ql new file mode 100644 index 00000000000..c6621b44e95 --- /dev/null +++ b/python/ql/test/library-tests/thrift/References.ql @@ -0,0 +1,7 @@ + +import python +import external.Thrift + +from ThriftType t, ThriftStruct s +where t.references(s) +select t, s diff --git a/python/ql/test/library-tests/thrift/Service.expected b/python/ql/test/library-tests/thrift/Service.expected new file mode 100644 index 00000000000..60d57f5d581 --- /dev/null +++ b/python/ql/test/library-tests/thrift/Service.expected @@ -0,0 +1,7 @@ +| extended.thrift:12:9:12:16 | service Extended | getUser | extended.thrift:14:4:14:15 | function getUser | +| extended.thrift:37:9:37:19 | service with_throws | foo | extended.thrift:39:4:39:12 | function foo | +| extended.thrift:48:9:48:15 | service TheShop | getPet | extended.thrift:50:5:50:18 | function getPet | +| test.thrift:57:9:57:18 | service Calculator | add | test.thrift:68:4:68:10 | function add | +| test.thrift:57:9:57:18 | service Calculator | calculate | test.thrift:70:4:70:16 | function calculate | +| test.thrift:57:9:57:18 | service Calculator | ping | test.thrift:66:4:66:12 | function ping | +| test.thrift:57:9:57:18 | service Calculator | zip | test.thrift:77:11:77:18 | function zip | diff --git a/python/ql/test/library-tests/thrift/Service.ql b/python/ql/test/library-tests/thrift/Service.ql new file mode 100644 index 00000000000..801379c6a2e --- /dev/null +++ b/python/ql/test/library-tests/thrift/Service.ql @@ -0,0 +1,6 @@ + +import external.Thrift + + +from ThriftService service, string name +select service, name, service.getFunction(name) diff --git a/python/ql/test/library-tests/thrift/Test.expected b/python/ql/test/library-tests/thrift/Test.expected new file mode 100644 index 00000000000..8b1717cf09b --- /dev/null +++ b/python/ql/test/library-tests/thrift/Test.expected @@ -0,0 +1 @@ +| Thrift | diff --git a/python/ql/test/library-tests/thrift/Test.ql b/python/ql/test/library-tests/thrift/Test.ql new file mode 100644 index 00000000000..735b9ad0eae --- /dev/null +++ b/python/ql/test/library-tests/thrift/Test.ql @@ -0,0 +1,7 @@ + +import external.Thrift + +from string cls +where any(ThriftElement t).getAQlClass() = cls +select cls.prefix(6) + diff --git a/python/ql/test/library-tests/thrift/Value.expected b/python/ql/test/library-tests/thrift/Value.expected new file mode 100644 index 00000000000..4e0a78ffdc9 --- /dev/null +++ b/python/ql/test/library-tests/thrift/Value.expected @@ -0,0 +1,158 @@ +| extended.thrift:3:8:3:11 | IDENTIFIER User | User | +| extended.thrift:4:3:4:3 | INTCONSTANT 1 | 1 | +| extended.thrift:4:6:4:11 | STRING string | string | +| extended.thrift:4:13:4:16 | IDENTIFIER name | name | +| extended.thrift:7:11:7:15 | IDENTIFIER Error | Error | +| extended.thrift:8:3:8:3 | INTCONSTANT 1 | 1 | +| extended.thrift:8:6:8:8 | I32 i32 | i32 | +| extended.thrift:8:10:8:13 | IDENTIFIER what | what | +| extended.thrift:9:3:9:3 | INTCONSTANT 2 | 2 | +| extended.thrift:9:6:9:11 | STRING string | string | +| extended.thrift:9:13:9:15 | IDENTIFIER why | why | +| extended.thrift:12:9:12:16 | IDENTIFIER Extended | Extended | +| extended.thrift:14:4:14:7 | IDENTIFIER User | User | +| extended.thrift:14:9:14:15 | IDENTIFIER getUser | getUser | +| extended.thrift:14:17:14:17 | INTCONSTANT 1 | 1 | +| extended.thrift:14:19:14:21 | I32 i32 | i32 | +| extended.thrift:14:23:14:24 | IDENTIFIER id | id | +| extended.thrift:14:35:14:35 | INTCONSTANT 1 | 1 | +| extended.thrift:14:37:14:41 | IDENTIFIER Error | Error | +| extended.thrift:14:43:14:47 | IDENTIFIER error | error | +| extended.thrift:15:5:15:16 | IDENTIFIER doggy.window | doggy.window | +| extended.thrift:15:20:15:25 | LITERAL "true" | "true" | +| extended.thrift:15:28:15:40 | IDENTIFIER doggy.howmuch | doggy.howmuch | +| extended.thrift:15:44:15:47 | INTCONSTANT 1000 | 1000 | +| extended.thrift:19:9:19:11 | I32 i32 | i32 | +| extended.thrift:19:13:19:15 | IDENTIFIER int | int | +| extended.thrift:21:9:21:11 | I64 i64 | i64 | +| extended.thrift:21:13:21:19 | IDENTIFIER foo.bar | foo.bar | +| extended.thrift:21:23:21:29 | LITERAL "hello" | "hello" | +| extended.thrift:21:32:21:40 | IDENTIFIER shrubbery | shrubbery | +| extended.thrift:23:8:23:23 | IDENTIFIER with_annotations | with_annotations | +| extended.thrift:25:5:25:5 | INTCONSTANT 1 | 1 | +| extended.thrift:25:17:25:19 | IDENTIFIER int | int | +| extended.thrift:25:21:25:22 | IDENTIFIER i1 | i1 | +| extended.thrift:26:5:26:5 | INTCONSTANT 2 | 2 | +| extended.thrift:26:8:26:10 | IDENTIFIER int | int | +| extended.thrift:26:13:26:25 | IDENTIFIER type.annotate | type.annotate | +| extended.thrift:26:29:26:33 | LITERAL "foo" | "foo" | +| extended.thrift:26:36:26:37 | IDENTIFIER i2 | i2 | +| extended.thrift:27:5:27:5 | INTCONSTANT 3 | 3 | +| extended.thrift:27:8:27:15 | IDENTIFIER shubbery | shubbery | +| extended.thrift:27:17:27:20 | IDENTIFIER nice | nice | +| extended.thrift:27:23:27:37 | IDENTIFIER knights.who.say | knights.who.say | +| extended.thrift:27:41:27:44 | LITERAL "ni" | "ni" | +| extended.thrift:29:5:29:15 | IDENTIFIER struct.anno | struct.anno | +| extended.thrift:29:19:29:21 | LITERAL "y" | "y" | +| extended.thrift:31:6:31:12 | IDENTIFIER Animals | Animals | +| extended.thrift:32:5:32:7 | IDENTIFIER cat | cat | +| extended.thrift:32:11:32:11 | INTCONSTANT 1 | 1 | +| extended.thrift:33:5:33:9 | IDENTIFIER mouse | mouse | +| extended.thrift:33:13:33:13 | INTCONSTANT 2 | 2 | +| extended.thrift:34:5:34:7 | IDENTIFIER dog | dog | +| extended.thrift:35:5:35:13 | IDENTIFIER enum.anno | enum.anno | +| extended.thrift:35:17:35:19 | LITERAL "x" | "x" | +| extended.thrift:37:9:37:19 | IDENTIFIER with_throws | with_throws | +| extended.thrift:39:4:39:8 | IDENTIFIER int32 | int32 | +| extended.thrift:39:10:39:12 | IDENTIFIER foo | foo | +| extended.thrift:39:14:39:14 | INTCONSTANT 1 | 1 | +| extended.thrift:39:16:39:18 | I32 i32 | i32 | +| extended.thrift:39:20:39:21 | IDENTIFIER id | id | +| extended.thrift:40:9:40:9 | INTCONSTANT 1 | 1 | +| extended.thrift:40:11:40:15 | IDENTIFIER Error | Error | +| extended.thrift:40:17:40:21 | IDENTIFIER error | error | +| extended.thrift:41:9:41:9 | INTCONSTANT 3 | 3 | +| extended.thrift:41:11:41:16 | STRING string | string | +| extended.thrift:41:18:41:22 | IDENTIFIER cause | cause | +| extended.thrift:46:14:46:22 | IDENTIFIER shrubbery | shrubbery | +| extended.thrift:46:25:46:30 | IDENTIFIER border | border | +| extended.thrift:46:34:46:35 | IDENTIFIER ni | ni | +| extended.thrift:46:39:46:45 | LITERAL "false" | "false" | +| extended.thrift:48:9:48:15 | IDENTIFIER TheShop | TheShop | +| extended.thrift:50:5:50:11 | IDENTIFIER Animals | Animals | +| extended.thrift:50:13:50:18 | IDENTIFIER getPet | getPet | +| extended.thrift:51:9:51:9 | INTCONSTANT 1 | 1 | +| extended.thrift:51:21:51:24 | IDENTIFIER User | User | +| extended.thrift:51:26:51:30 | IDENTIFIER owner | owner | +| extended.thrift:53:9:53:9 | INTCONSTANT 1 | 1 | +| extended.thrift:53:12:53:16 | IDENTIFIER Error | Error | +| extended.thrift:53:18:53:24 | IDENTIFIER napping | napping | +| extended.thrift:54:9:54:9 | INTCONSTANT 2 | 2 | +| extended.thrift:54:12:54:23 | IDENTIFIER AnotherError | AnotherError | +| extended.thrift:54:25:54:30 | IDENTIFIER pining | pining | +| extended.thrift:55:9:55:9 | INTCONSTANT 3 | 3 | +| extended.thrift:55:12:55:27 | IDENTIFIER ThirdKindOfError | ThirdKindOfError | +| extended.thrift:55:29:55:35 | IDENTIFIER resting | resting | +| extended.thrift:56:9:56:9 | INTCONSTANT 4 | 4 | +| extended.thrift:56:12:56:16 | IDENTIFIER Error | Error | +| extended.thrift:56:18:56:21 | IDENTIFIER deaf | deaf | +| extended.thrift:59:5:59:22 | IDENTIFIER service.annotation | service.annotation | +| extended.thrift:59:26:59:32 | LITERAL "thing" | "thing" | +| test.thrift:3:9:3:23 | LITERAL "shared.thrift" | "shared.thrift" | +| test.thrift:15:7:15:9 | I32 i32 | i32 | +| test.thrift:15:11:15:23 | IDENTIFIER INT32CONSTANT | INT32CONSTANT | +| test.thrift:15:27:15:30 | INTCONSTANT 9853 | 9853 | +| test.thrift:16:11:16:16 | STRING string | string | +| test.thrift:16:18:16:23 | STRING string | string | +| test.thrift:16:26:16:36 | IDENTIFIER MAPCONSTANT | MAPCONSTANT | +| test.thrift:16:41:16:47 | LITERAL 'hello' | 'hello' | +| test.thrift:16:49:16:55 | LITERAL 'world' | 'world' | +| test.thrift:16:58:16:68 | LITERAL 'goodnight' | 'goodnight' | +| test.thrift:16:70:16:75 | LITERAL 'moon' | 'moon' | +| test.thrift:22:6:22:14 | IDENTIFIER Operation | Operation | +| test.thrift:23:3:23:5 | IDENTIFIER ADD | ADD | +| test.thrift:23:9:23:9 | INTCONSTANT 1 | 1 | +| test.thrift:24:3:24:10 | IDENTIFIER SUBTRACT | SUBTRACT | +| test.thrift:24:14:24:14 | INTCONSTANT 2 | 2 | +| test.thrift:25:3:25:10 | IDENTIFIER MULTIPLY | MULTIPLY | +| test.thrift:25:14:25:14 | INTCONSTANT 3 | 3 | +| test.thrift:26:3:26:8 | IDENTIFIER DIVIDE | DIVIDE | +| test.thrift:26:12:26:12 | INTCONSTANT 4 | 4 | +| test.thrift:38:8:38:11 | IDENTIFIER Work | Work | +| test.thrift:39:3:39:3 | INTCONSTANT 1 | 1 | +| test.thrift:39:6:39:8 | I32 i32 | i32 | +| test.thrift:39:10:39:13 | IDENTIFIER num1 | num1 | +| test.thrift:39:17:39:17 | INTCONSTANT 0 | 0 | +| test.thrift:40:3:40:3 | INTCONSTANT 2 | 2 | +| test.thrift:40:6:40:8 | I32 i32 | i32 | +| test.thrift:40:10:40:13 | IDENTIFIER num2 | num2 | +| test.thrift:41:3:41:3 | INTCONSTANT 3 | 3 | +| test.thrift:41:6:41:14 | IDENTIFIER Operation | Operation | +| test.thrift:41:16:41:17 | IDENTIFIER op | op | +| test.thrift:42:3:42:3 | INTCONSTANT 4 | 4 | +| test.thrift:42:15:42:20 | STRING string | string | +| test.thrift:42:22:42:28 | IDENTIFIER comment | comment | +| test.thrift:48:11:48:26 | IDENTIFIER InvalidOperation | InvalidOperation | +| test.thrift:49:3:49:3 | INTCONSTANT 1 | 1 | +| test.thrift:49:6:49:8 | I32 i32 | i32 | +| test.thrift:49:10:49:13 | IDENTIFIER what | what | +| test.thrift:50:3:50:3 | INTCONSTANT 2 | 2 | +| test.thrift:50:6:50:11 | STRING string | string | +| test.thrift:50:13:50:15 | IDENTIFIER why | why | +| test.thrift:57:9:57:18 | IDENTIFIER Calculator | Calculator | +| test.thrift:57:28:57:47 | IDENTIFIER shared.SharedService | shared.SharedService | +| test.thrift:66:4:66:7 | VOID void | void | +| test.thrift:66:9:66:12 | IDENTIFIER ping | ping | +| test.thrift:68:4:68:6 | I32 i32 | i32 | +| test.thrift:68:8:68:10 | IDENTIFIER add | add | +| test.thrift:68:12:68:12 | INTCONSTANT 1 | 1 | +| test.thrift:68:14:68:16 | I32 i32 | i32 | +| test.thrift:68:18:68:21 | IDENTIFIER num1 | num1 | +| test.thrift:68:24:68:24 | INTCONSTANT 2 | 2 | +| test.thrift:68:26:68:28 | I32 i32 | i32 | +| test.thrift:68:30:68:33 | IDENTIFIER num2 | num2 | +| test.thrift:70:4:70:6 | I32 i32 | i32 | +| test.thrift:70:8:70:16 | IDENTIFIER calculate | calculate | +| test.thrift:70:18:70:18 | INTCONSTANT 1 | 1 | +| test.thrift:70:20:70:22 | I32 i32 | i32 | +| test.thrift:70:24:70:28 | IDENTIFIER logid | logid | +| test.thrift:70:31:70:31 | INTCONSTANT 2 | 2 | +| test.thrift:70:33:70:36 | IDENTIFIER Work | Work | +| test.thrift:70:38:70:38 | IDENTIFIER w | w | +| test.thrift:70:49:70:49 | INTCONSTANT 1 | 1 | +| test.thrift:70:51:70:66 | IDENTIFIER InvalidOperation | InvalidOperation | +| test.thrift:70:68:70:71 | IDENTIFIER ouch | ouch | +| test.thrift:77:11:77:14 | VOID void | void | +| test.thrift:77:16:77:18 | IDENTIFIER zip | zip | +| test.thrift:83:9:83:12 | IDENTIFIER wood | wood | +| test.thrift:83:14:83:17 | IDENTIFIER duck | duck | diff --git a/python/ql/test/library-tests/thrift/Value.ql b/python/ql/test/library-tests/thrift/Value.ql new file mode 100644 index 00000000000..7cf83b1df65 --- /dev/null +++ b/python/ql/test/library-tests/thrift/Value.ql @@ -0,0 +1,5 @@ + +import external.Thrift + +from ThriftElement t +select t, t.getValue() \ No newline at end of file diff --git a/python/ql/test/library-tests/thrift/extended.thrift b/python/ql/test/library-tests/thrift/extended.thrift new file mode 100644 index 00000000000..7b17155c6a4 --- /dev/null +++ b/python/ql/test/library-tests/thrift/extended.thrift @@ -0,0 +1,60 @@ + + +struct User { + 1: string name +} + +exception Error { + 1: i32 what, + 2: string why +} + +service Extended { + + User getUser(1:i32 id) throws (1:Error error) + (doggy.window = "true", doggy.howmuch = 1000) + +} + +typedef i32 int; + +typedef i64(foo.bar = "hello") shrubbery; + +struct with_annotations { + + 1: optional int i1; + 2: int (type.annotate = "foo") i2; + 3: shubbery nice (knights.who.say = "ni"); + +} ( struct.anno = "y" ) + +enum Animals { + cat = 1, + mouse = 2, + dog +} ( enum.anno = "x" ) + +service with_throws { + + int32 foo(1:i32 id) throws ( + 1:Error error + 3:string cause + ) + +} + +typedef list border ( ni = "false" ) + +service TheShop { + + Animals getPet( + 1: required User owner + ) throws ( + 1: Error napping + 2: AnotherError pining + 3: ThirdKindOfError resting + 4: Error deaf + ) +} ( + service.annotation = "thing" +) diff --git a/python/ql/test/library-tests/thrift/options b/python/ql/test/library-tests/thrift/options new file mode 100644 index 00000000000..3eeb07bd643 --- /dev/null +++ b/python/ql/test/library-tests/thrift/options @@ -0,0 +1,2 @@ +semmle-extractor-options: -R . --filter=include:**/*.thrift --filter exclude:**/src_archive/** +automatic_locations: true diff --git a/python/ql/test/library-tests/thrift/test.py b/python/ql/test/library-tests/thrift/test.py new file mode 100644 index 00000000000..73d0ccb3630 --- /dev/null +++ b/python/ql/test/library-tests/thrift/test.py @@ -0,0 +1 @@ +#Check that thrift extractor works when there is a Python file with the same stem \ No newline at end of file diff --git a/python/ql/test/library-tests/thrift/test.thrift b/python/ql/test/library-tests/thrift/test.thrift new file mode 100644 index 00000000000..73a78b6c979 --- /dev/null +++ b/python/ql/test/library-tests/thrift/test.thrift @@ -0,0 +1,84 @@ + + +include "shared.thrift" + +namespace cpp tutorial +namespace d d +namespace java a.b.c.d.com +namespace php tutorial +namespace go xxxx + +/** + * Thrift also lets you define constants for use across languages. Complex + * types and structs are specified using JSON notation. + */ +const i32 INT32CONSTANT = 9853 +const map MAPCONSTANT = {'hello':'world', 'goodnight':'moon'} + +/** + * You can define enums, which are just 32 bit integers. Values are optional + * and start at 1 if not supplied, C style again. + */ +enum Operation { + ADD = 1, + SUBTRACT = 2, + MULTIPLY = 3, + DIVIDE = 4 +} + +/** + * Structs are the basic complex data structures. They are comprised of fields + * which each have an integer identifier, a type, a symbolic name, and an + * optional default value. + * + * Fields can be declared "optional", which ensures they will not be included + * in the serialized output if they aren't set. Note that this requires some + * manual management in some languages. + */ +struct Work { + 1: i32 num1 = 0, + 2: i32 num2, + 3: Operation op, + 4: optional string comment, +} + +/** + * Structs can also be exceptions, if they are nasty. + */ +exception InvalidOperation { + 1: i32 what, + 2: string why +} + +/** + * Ahh, now onto the cool part, defining a service. Services just need a name + * and can optionally inherit from another service using the extends keyword. + */ +service Calculator extends shared.SharedService { + + /** + * A method definition looks like C code. It has a return type, arguments, + * and optionally a list of exceptions that it may throw. Note that argument + * lists and exception lists are specified using the exact same syntax as + * field lists in struct or exception definitions. + */ + + void ping(), + + i32 add(1:i32 num1, 2:i32 num2), + + i32 calculate(1:i32 logid, 2:Work w) throws (1:InvalidOperation ouch), + + /** + * This method has a oneway modifier. That means the client only makes + * a request and does not listen for any response at all. Oneway methods + * must be void. + */ + oneway void zip() + +} + +#Python-style comments are allowed + +typedef wood duck + diff --git a/python/ql/test/library-tests/types/attributes/Test.expected b/python/ql/test/library-tests/types/attributes/Test.expected new file mode 100644 index 00000000000..d0d7283d4cd --- /dev/null +++ b/python/ql/test/library-tests/types/attributes/Test.expected @@ -0,0 +1,10 @@ +| 3 | class Base | class Base | C | class C | 5 | +| 3 | class Base | class Base | meth | Function meth | 7 | +| 10 | class Derived | class Base | C | class C | 5 | +| 10 | class Derived | class Base | meth | Function meth | 7 | +| 10 | class Derived | class Derived | C | class C | 5 | +| 10 | class Derived | class Derived | meth | Function meth | 12 | +| 16 | class Derived2 | class Base | C | class C | 5 | +| 16 | class Derived2 | class Base | meth | Function meth | 7 | +| 16 | class Derived2 | class Derived2 | C | class C | 21 | +| 16 | class Derived2 | class Derived2 | meth | Function meth | 18 | diff --git a/python/ql/test/library-tests/types/attributes/Test.ql b/python/ql/test/library-tests/types/attributes/Test.ql new file mode 100644 index 00000000000..a92064a2551 --- /dev/null +++ b/python/ql/test/library-tests/types/attributes/Test.ql @@ -0,0 +1,6 @@ +import python + +from ClassObject cls, ClassObject start, string name, Object val +where not name.substring(0, 2) = "__" and val = cls.lookupMro(start, name) +select +cls.getOrigin().getLocation().getStartLine(), cls.toString(), start.toString(), name, val.toString(), val.getOrigin().getLocation().getStartLine() \ No newline at end of file diff --git a/python/ql/test/library-tests/types/attributes/test.py b/python/ql/test/library-tests/types/attributes/test.py new file mode 100644 index 00000000000..1f3ba3def1b --- /dev/null +++ b/python/ql/test/library-tests/types/attributes/test.py @@ -0,0 +1,21 @@ + + +class Base(object): + + class C(object): pass + + def meth(self): + pass + +class Derived(Base): + + def meth(self): + super(Derived, self).meth() + super(Derived, self).x + +class Derived2(Base): + + def meth(self): + pass + + class C(object): pass diff --git a/python/ql/test/library-tests/types/classattr/ClassAttribute.expected b/python/ql/test/library-tests/types/classattr/ClassAttribute.expected new file mode 100644 index 00000000000..6dad8a5b12c --- /dev/null +++ b/python/ql/test/library-tests/types/classattr/ClassAttribute.expected @@ -0,0 +1,45 @@ +| class Base | declares | x | +| class Base | has | x | +| class Base2 | declares | x | +| class Base2 | has | x | +| class D1 | has | x | +| class D2 | has | x | +| class D3 | has | x | +| class Diamond | has | x | +| class New | declares | a1 | +| class New | declares | a2 | +| class New | declares | i1 | +| class New | declares | i2 | +| class New | declares | u1 | +| class New | declares | u2 | +| class New | has | a1 | +| class New | has | a2 | +| class New | has | i1 | +| class New | has | i2 | +| class New | has | u1 | +| class New | has | u2 | +| class NewDerived | has | a1 | +| class NewDerived | has | a2 | +| class NewDerived | has | i1 | +| class NewDerived | has | i2 | +| class NewDerived | has | u1 | +| class NewDerived | has | u2 | +| class Old | declares | a1 | +| class Old | declares | a2 | +| class Old | declares | i1 | +| class Old | declares | i2 | +| class Old | declares | u1 | +| class Old | declares | u2 | +| class Old | has | a1 | +| class Old | has | a2 | +| class Old | has | i1 | +| class Old | has | i2 | +| class Old | has | u1 | +| class Old | has | u2 | +| class OldDerived | has | a1 | +| class OldDerived | has | a2 | +| class OldDerived | has | i1 | +| class OldDerived | has | i2 | +| class OldDerived | has | u1 | +| class OldDerived | has | u2 | +| class Tree | has | x | diff --git a/python/ql/test/library-tests/types/classattr/ClassAttribute.ql b/python/ql/test/library-tests/types/classattr/ClassAttribute.ql new file mode 100644 index 00000000000..6895020718e --- /dev/null +++ b/python/ql/test/library-tests/types/classattr/ClassAttribute.ql @@ -0,0 +1,19 @@ +/** + * @name ClassAttribute + * @description Test for Class attributes + * @kind test + */ + +import python + +from ClassObject cls, string name, string kind +where +not cls.isC() and +not name.matches("\\_\\_%\\_\\_") and +( + cls.hasAttribute(name) and kind = "has" + or + cls.declaresAttribute(name) and kind = "declares" +) +select cls.toString(), kind ,name + diff --git a/python/ql/test/library-tests/types/classattr/ClassMember.expected b/python/ql/test/library-tests/types/classattr/ClassMember.expected new file mode 100644 index 00000000000..24d4faa2871 --- /dev/null +++ b/python/ql/test/library-tests/types/classattr/ClassMember.expected @@ -0,0 +1,27 @@ +| class Base | declares | x | int 1 | +| class Base | has | x | int 1 | +| class Base2 | declares | x | int 2 | +| class Base2 | has | x | int 2 | +| class D1 | has | x | int 1 | +| class D2 | has | x | int 1 | +| class D3 | has | x | int 2 | +| class Diamond | has | x | int 1 | +| class New | declares | a2 | int 7 | +| class New | declares | i1 | int 5 | +| class New | declares | i2 | int 5 | +| class New | has | a2 | int 7 | +| class New | has | i1 | int 5 | +| class New | has | i2 | int 5 | +| class NewDerived | has | a2 | int 7 | +| class NewDerived | has | i1 | int 5 | +| class NewDerived | has | i2 | int 5 | +| class Old | declares | a2 | int 7 | +| class Old | declares | i1 | int 5 | +| class Old | declares | i2 | int 5 | +| class Old | has | a2 | int 7 | +| class Old | has | i1 | int 5 | +| class Old | has | i2 | int 5 | +| class OldDerived | has | a2 | int 7 | +| class OldDerived | has | i1 | int 5 | +| class OldDerived | has | i2 | int 5 | +| class Tree | has | x | int 1 | diff --git a/python/ql/test/library-tests/types/classattr/ClassMember.ql b/python/ql/test/library-tests/types/classattr/ClassMember.ql new file mode 100644 index 00000000000..b76851dd43d --- /dev/null +++ b/python/ql/test/library-tests/types/classattr/ClassMember.ql @@ -0,0 +1,18 @@ +/** + * @name ClassAttribute + * @description Test for Class attributes + * @kind test + */ + +import python + +from ClassObject cls, string name, string kind, Object o +where +not cls.isC() and +not name.matches("\\_\\_%\\_\\_") and +( + o = cls.lookupAttribute(name) and kind = "has" + or + o = cls.declaredAttribute(name) and kind = "declares" +) +select cls.toString(), kind, name, o.toString() diff --git a/python/ql/test/library-tests/types/classattr/SpecialAttribute.expected b/python/ql/test/library-tests/types/classattr/SpecialAttribute.expected new file mode 100644 index 00000000000..c27c4e9c83f --- /dev/null +++ b/python/ql/test/library-tests/types/classattr/SpecialAttribute.expected @@ -0,0 +1,6 @@ +| class Special1 | declares | __add__ | int 1 | +| class Special1 | has | __add__ | int 1 | +| class Special2 | declares | __float__ | int 2 | +| class Special2 | has | __float__ | int 2 | +| class Special3 | has | __add__ | int 1 | +| class Special3 | has | __float__ | int 2 | diff --git a/python/ql/test/library-tests/types/classattr/SpecialAttribute.ql b/python/ql/test/library-tests/types/classattr/SpecialAttribute.ql new file mode 100644 index 00000000000..cdfd29b8d91 --- /dev/null +++ b/python/ql/test/library-tests/types/classattr/SpecialAttribute.ql @@ -0,0 +1,14 @@ + +import python + +from ClassObject cls, string name, string kind, Object o +where +not cls.isC() and +name.matches("\\_\\_%\\_\\_") and +not o = theObjectType().lookupAttribute(name) and +( + o = cls.lookupAttribute(name) and kind = "has" + or + o = cls.declaredAttribute(name) and kind = "declares" +) +select cls.toString(), kind, name, o.toString() diff --git a/python/ql/test/library-tests/types/classattr/classattr.py b/python/ql/test/library-tests/types/classattr/classattr.py new file mode 100644 index 00000000000..23dc24499f7 --- /dev/null +++ b/python/ql/test/library-tests/types/classattr/classattr.py @@ -0,0 +1,64 @@ +#Test various permutations of known and unknown values, old and new style class and shadowed and unshadowed names. + +from unknown import u1 +i1 = 5 +from unknown import g1 +g2 = 7 + + +class Old: + + a1 = g1 + a2 = g2 + u2 = u1 + u1 = u1 + i2 = i1 + i1 = i1 + +class New(object): + + a1 = g1 + a2 = g2 + u2 = u1 + u1 = u1 + i2 = i1 + i1 = i1 + +class OldDerived(Old): + pass + +class NewDerived(New): + pass + +class Base(object): + x = 1 + +class D1(Base): + pass + +class D2(Base): + pass + +class Diamond(D1, D2): + pass + +class Base2(object): + x = 2 + +class D3(Base2): + pass + + +class Tree(D1, D3): + pass + +class Special1(object): + __add__ = 1 + +class Special2(object): + __float__ = 2 + +class Special3(Special1, Special2): + pass + + diff --git a/python/ql/test/library-tests/types/classes/FailedInference.expected b/python/ql/test/library-tests/types/classes/FailedInference.expected new file mode 100644 index 00000000000..916075a656c --- /dev/null +++ b/python/ql/test/library-tests/types/classes/FailedInference.expected @@ -0,0 +1,25 @@ +| circular_inheritance.py:33:1:33:11 | class A | Missing base 0 | +| circular_inheritance.py:37:1:37:11 | class B | Missing base 0 | +| circular_inheritance.py:40:1:40:72 | class D | Duplicate bases classes | +| circular_inheritance.py:43:1:43:41 | class E | Duplicate bases classes | +| circular_inheritance.py:43:1:43:41 | class E | Failed inference for base class at position 0 | +| circular_inheritance.py:43:1:43:41 | class E | Failed inference for base class at position 1 | +| circular_inheritance.py:43:1:43:41 | class E | Failed inference for base class at position 2 | +| circular_inheritance.py:43:1:43:41 | class E | Failed inference for base class at position 3 | +| circular_inheritance.py:43:1:43:41 | class E | Failed inference for base class at position 4 | +| circular_inheritance.py:43:1:43:41 | class E | Failed inference for base class at position 5 | +| circular_inheritance.py:43:1:43:41 | class E | Failed inference for base class at position 6 | +| circular_inheritance.py:43:1:43:41 | class E | Failed inference for base class at position 7 | +| circular_inheritance.py:43:1:43:41 | class E | Failed inference for base class at position 8 | +| circular_inheritance.py:43:1:43:41 | class E | Failed inference for base class at position 9 | +| circular_inheritance.py:43:1:43:41 | class E | Failed inference for base class at position 10 | +| circular_inheritance.py:47:1:47:19 | class G | Missing base 0 | +| circular_inheritance.py:50:1:50:19 | class J | Missing base 0 | +| circular_inheritance.py:54:1:54:11 | class M | Missing base 0 | +| circular_inheritance.py:57:1:57:11 | class L | Missing base 0 | +| circular_inheritance.py:61:1:61:19 | class S | Missing base 0 | +| circular_inheritance.py:64:1:64:19 | class R | Missing base 0 | +| mutual_inheritance.py:4:1:4:11 | class C | Missing base 0 | +| mutual_inheritance.py:8:1:8:19 | class H | Missing base 0 | +| mutual_inheritance.py:12:1:12:11 | class N | Missing base 0 | +| mutual_inheritance.py:15:1:15:19 | class T | Missing base 0 | diff --git a/python/ql/test/library-tests/types/classes/FailedInference.ql b/python/ql/test/library-tests/types/classes/FailedInference.ql new file mode 100644 index 00000000000..129c17ffd9d --- /dev/null +++ b/python/ql/test/library-tests/types/classes/FailedInference.ql @@ -0,0 +1,11 @@ + +import python +import semmle.python.pointsto.PointsTo + +from ClassObject cls, string reason + +where +PointsTo::Types::failed_inference(cls, reason) + +select cls, reason + diff --git a/python/ql/test/library-tests/types/classes/c_inheritance.py b/python/ql/test/library-tests/types/classes/c_inheritance.py new file mode 100644 index 00000000000..92656455660 --- /dev/null +++ b/python/ql/test/library-tests/types/classes/c_inheritance.py @@ -0,0 +1,6 @@ + +class MyList(list): + pass + +class MyDict(dict): + pass diff --git a/python/ql/test/library-tests/types/classes/circular_inheritance.py b/python/ql/test/library-tests/types/classes/circular_inheritance.py new file mode 100644 index 00000000000..5c23f152f1b --- /dev/null +++ b/python/ql/test/library-tests/types/classes/circular_inheritance.py @@ -0,0 +1,67 @@ +from mutual_inheritance import C, H, N, T + +#Good newstyle classes + +class W(object): + pass + +class X(W): + pass + +class Y(X): + pass + +class Z(Y, X): + pass + +#Good oldstyle classes + +class O1: + pass + +class O2(O1): + pass + +class O3(O1): + pass + +class O4(O2, O3): + pass + +#Bad classes -- Illegal and designed to break MRO computation + +class A(A): + pass + +#Two way cycle +class B(C): + pass + +class D(object, object, object, object, object, object, object, object): + pass + +class E(D, D, D, D, D, D, D, D, D, D, D): + pass + +#Two way cycle with object +class G(H, object): + pass + +class J(J, object): + pass + +#Three way cycle +class M(N): + pass + +class L(M): + pass + +#Three way cycle with object +class S(T, object): + pass + +class R(S, object): + pass + + diff --git a/python/ql/test/library-tests/types/classes/duplicate_base.expected b/python/ql/test/library-tests/types/classes/duplicate_base.expected new file mode 100644 index 00000000000..7f41c6bbe8a --- /dev/null +++ b/python/ql/test/library-tests/types/classes/duplicate_base.expected @@ -0,0 +1,2 @@ +| class D | +| class E | diff --git a/python/ql/test/library-tests/types/classes/duplicate_base.ql b/python/ql/test/library-tests/types/classes/duplicate_base.ql new file mode 100644 index 00000000000..4f865754088 --- /dev/null +++ b/python/ql/test/library-tests/types/classes/duplicate_base.ql @@ -0,0 +1,7 @@ + +import python + +from ClassObject cls +where cls.hasDuplicateBases() +select cls.toString() + diff --git a/python/ql/test/library-tests/types/classes/mutual_inheritance.py b/python/ql/test/library-tests/types/classes/mutual_inheritance.py new file mode 100644 index 00000000000..4852bace9be --- /dev/null +++ b/python/ql/test/library-tests/types/classes/mutual_inheritance.py @@ -0,0 +1,17 @@ +from circular_inheritance import B, G, L, R + +#Two way cycle +class C(B): + pass + +#Two way cycle with object +class H(G, object): + pass + +#Three way cycle +class N(L): + pass + +class T(R, object): + pass + diff --git a/python/ql/test/library-tests/types/exceptions/ExitRaises.expected b/python/ql/test/library-tests/types/exceptions/ExitRaises.expected new file mode 100644 index 00000000000..1c54a818dbb --- /dev/null +++ b/python/ql/test/library-tests/types/exceptions/ExitRaises.expected @@ -0,0 +1,28 @@ +| 16 | test.py:16:5:16:22 | ControlFlowNode for Raise | Function f2 | test.py:3:1:3:28 | class ExceptionA | +| 22 | test.py:22:5:22:8 | ControlFlowNode for f2() | Function f5 | test.py:3:1:3:28 | class ExceptionA | +| 25 | test.py:25:5:25:22 | ControlFlowNode for Raise | Function f6 | test.py:6:1:6:28 | class ExceptionB | +| 30 | test.py:30:9:30:26 | ControlFlowNode for Raise | Function f7 | test.py:3:1:3:28 | class ExceptionA | +| 32 | test.py:32:9:32:26 | ControlFlowNode for Raise | Function f7 | test.py:6:1:6:28 | class ExceptionB | +| 36 | test.py:36:9:36:12 | ControlFlowNode for f7() | Function f8 | test.py:3:1:3:28 | class ExceptionA | +| 44 | test.py:44:9:44:12 | ControlFlowNode for Pass | Function f8a | test.py:3:1:3:28 | class ExceptionA | +| 44 | test.py:44:9:44:12 | ControlFlowNode for Pass | Function f8a | test.py:6:1:6:28 | class ExceptionB | +| 53 | test.py:53:9:53:12 | ControlFlowNode for Pass | Function f9 | test.py:3:1:3:28 | class ExceptionA | +| 71 | test.py:71:9:71:26 | ControlFlowNode for Raise | Function f11 | test.py:9:1:9:28 | class ExceptionC | +| 71 | test.py:71:9:71:26 | ControlFlowNode for Raise | Function f11 | test.py:9:1:9:28 | class ExceptionC | +| 74 | test.py:74:5:74:14 | ControlFlowNode for Subscript | Function f12 | file://:Compiled Code:0:0:0:0 | builtin-class LookupError | +| 107 | test.py:107:9:107:12 | ControlFlowNode for Pass | Function f18 | file://:Compiled Code:0:0:0:0 | builtin-class LookupError | +| 110 | test.py:110:5:110:22 | ControlFlowNode for Raise | Function f19 | file://:Compiled Code:0:0:0:0 | builtin-class IndexError | +| 120 | test.py:120:9:120:13 | ControlFlowNode for f19() | Function f21 | file://:Compiled Code:0:0:0:0 | builtin-class IndexError | +| 128 | test.py:128:9:128:12 | ControlFlowNode for Pass | Function f22 | file://:Compiled Code:0:0:0:0 | builtin-class IndexError | +| 138 | test.py:138:13:138:16 | ControlFlowNode for Pass | Function f23 | test.py:3:1:3:28 | class ExceptionA | +| 138 | test.py:138:13:138:16 | ControlFlowNode for Pass | Function f23 | test.py:6:1:6:28 | class ExceptionB | +| 138 | test.py:138:13:138:16 | ControlFlowNode for Pass | Function f23 | test.py:9:1:9:28 | class ExceptionC | +| 138 | test.py:138:13:138:16 | ControlFlowNode for Pass | Function f23 | test.py:9:1:9:28 | class ExceptionC | +| 152 | test.py:152:9:152:12 | ControlFlowNode for Pass | Function f24 | test.py:3:1:3:28 | class ExceptionA | +| 152 | test.py:152:9:152:12 | ControlFlowNode for Pass | Function f24 | test.py:6:1:6:28 | class ExceptionB | +| 171 | test.py:171:13:171:16 | ControlFlowNode for Pass | Function f25 | test.py:9:1:9:28 | class ExceptionC | +| 171 | test.py:171:13:171:16 | ControlFlowNode for Pass | Function f25 | test.py:9:1:9:28 | class ExceptionC | +| 172 | test.py:172:9:172:12 | ControlFlowNode for Pass | Function f25 | test.py:3:1:3:28 | class ExceptionA | +| 172 | test.py:172:9:172:12 | ControlFlowNode for Pass | Function f25 | test.py:6:1:6:28 | class ExceptionB | +| 178 | test.py:178:9:178:12 | ControlFlowNode for f7() | Function f26 | test.py:6:1:6:28 | class ExceptionB | +| 183 | test.py:183:9:183:26 | ControlFlowNode for Raise | Function f26 | test.py:9:1:9:28 | class ExceptionC | diff --git a/python/ql/test/library-tests/types/exceptions/ExitRaises.ql b/python/ql/test/library-tests/types/exceptions/ExitRaises.ql new file mode 100644 index 00000000000..efa1f66b8d8 --- /dev/null +++ b/python/ql/test/library-tests/types/exceptions/ExitRaises.ql @@ -0,0 +1,6 @@ +import python + +from RaisingNode r, Scope s, ClassObject cls +where r.viableExceptionalExit(s, cls) + +select r.getLocation().getStartLine(), r, s.toString(), cls diff --git a/python/ql/test/library-tests/types/exceptions/Handles.expected b/python/ql/test/library-tests/types/exceptions/Handles.expected new file mode 100644 index 00000000000..4fa3c5505c5 --- /dev/null +++ b/python/ql/test/library-tests/types/exceptions/Handles.expected @@ -0,0 +1,16 @@ +| 37 | class ExceptionB | +| 50 | class ExceptionB | +| 59 | class ExceptionB | +| 68 | class ExceptionB | +| 82 | builtin-class KeyError | +| 88 | builtin-class IndexError | +| 94 | builtin-class AttributeError | +| 100 | class ExceptionA | +| 115 | builtin-class IndexError | +| 121 | builtin-class KeyError | +| 181 | class ExceptionA | +| 191 | class A | +| 197 | class ExceptionA | +| 197 | class ExceptionB | +| 201 | builtin-class KeyError | +| 201 | class ExceptionC | diff --git a/python/ql/test/library-tests/types/exceptions/Handles.ql b/python/ql/test/library-tests/types/exceptions/Handles.ql new file mode 100644 index 00000000000..51ceba1a6fb --- /dev/null +++ b/python/ql/test/library-tests/types/exceptions/Handles.ql @@ -0,0 +1,7 @@ + + +import python + +from ExceptFlowNode n, ClassObject cls +where n.handles(cls) +select n.getLocation().getStartLine(), cls.toString() diff --git a/python/ql/test/library-tests/types/exceptions/Impossible.expected b/python/ql/test/library-tests/types/exceptions/Impossible.expected new file mode 100644 index 00000000000..6df55b7bd7e --- /dev/null +++ b/python/ql/test/library-tests/types/exceptions/Impossible.expected @@ -0,0 +1,47 @@ +| 22 | 21 | f2() | Function f5 | normal | +| 36 | 34 | f7() | Function f8 | normal | +| 36 | 37 | f7 | ExceptStmt | exceptional | +| 42 | 44 | f7 | Pass | exceptional | +| 42 | 44 | f7() | Pass | normal | +| 49 | 50 | f7 | ExceptStmt | exceptional | +| 49 | 53 | f7 | Pass | exceptional | +| 49 | 53 | f7() | Pass | normal | +| 50 | 53 | ExceptionB | Pass | exceptional | +| 58 | 59 | f7 | ExceptStmt | exceptional | +| 58 | 62 | f7 | Return | exceptional | +| 58 | 62 | f7() | Return | normal | +| 59 | 62 | ExceptionB | Return | exceptional | +| 67 | 68 | f7 | ExceptStmt | exceptional | +| 67 | 71 | f7 | ExceptionC | exceptional | +| 67 | 71 | f7() | ExceptionC | normal | +| 68 | 71 | ExceptionB | ExceptionC | exceptional | +| 81 | 82 | x | ExceptStmt | exceptional | +| 87 | 88 | x | ExceptStmt | exceptional | +| 93 | 94 | x | ExceptStmt | exceptional | +| 99 | 100 | Attribute | ExceptStmt | exceptional | +| 99 | 100 | x | ExceptStmt | exceptional | +| 105 | 107 | x | Pass | exceptional | +| 114 | 112 | f19() | Function f20 | normal | +| 114 | 115 | f19 | ExceptStmt | exceptional | +| 120 | 118 | f19() | Function f21 | normal | +| 120 | 121 | f19 | ExceptStmt | exceptional | +| 120 | 121 | f19() | ExceptStmt | exceptional | +| 126 | 128 | f19 | Pass | exceptional | +| 126 | 128 | f19() | Pass | normal | +| 132 | 134 | f7 | Try | exceptional | +| 132 | 134 | f7() | Try | normal | +| 135 | 138 | x | Pass | exceptional | +| 136 | 138 | ExceptionC | Pass | exceptional | +| 136 | 138 | ExceptionC() | Pass | exceptional | +| 146 | 147 | f7() | Pass | normal | +| 146 | 150 | f7 | Pass | exceptional | +| 158 | 159 | f7() | Pass | normal | +| 158 | 162 | f7 | Try | exceptional | +| 164 | 169 | x | Pass | exceptional | +| 166 | 169 | ExceptionC | Pass | exceptional | +| 166 | 169 | ExceptionC() | Pass | exceptional | +| 178 | 179 | f7() | Pass | normal | +| 178 | 181 | f7 | ExceptStmt | exceptional | +| 189 | 191 | A() | ExceptStmt | exceptional | +| 196 | 197 | func | ExceptStmt | exceptional | +| 200 | 201 | func | ExceptStmt | exceptional | diff --git a/python/ql/test/library-tests/types/exceptions/Impossible.ql b/python/ql/test/library-tests/types/exceptions/Impossible.ql new file mode 100644 index 00000000000..e215a7e96ca --- /dev/null +++ b/python/ql/test/library-tests/types/exceptions/Impossible.ql @@ -0,0 +1,20 @@ + + +import python + +from RaisingNode r, ControlFlowNode n, string kind +where r.unlikelySuccessor(n) and +( + r.getATrueSuccessor() = n and kind = "true" + or + r.getAFalseSuccessor() = n and kind = "false" + or + r.getAnExceptionalSuccessor() = n and kind = "exceptional" + or + not r.getATrueSuccessor() = n and + not r.getAFalseSuccessor() = n and + not r.getAnExceptionalSuccessor() = n and + kind = "normal" + +) +select r.getLocation().getStartLine(), n.getLocation().getStartLine(), r.getNode().toString(), n.getNode().toString(), kind diff --git a/python/ql/test/library-tests/types/exceptions/LineRaises.expected b/python/ql/test/library-tests/types/exceptions/LineRaises.expected new file mode 100644 index 00000000000..fc08cde2a53 --- /dev/null +++ b/python/ql/test/library-tests/types/exceptions/LineRaises.expected @@ -0,0 +1,93 @@ +| 3 | None | +| 6 | None | +| 9 | None | +| 16 | None | +| 16 | class ExceptionA | +| 22 | class ExceptionA | +| 25 | None | +| 25 | class ExceptionB | +| 30 | None | +| 30 | class ExceptionA | +| 32 | None | +| 32 | class ExceptionB | +| 36 | None | +| 36 | class ExceptionA | +| 36 | class ExceptionB | +| 42 | None | +| 42 | class ExceptionA | +| 42 | class ExceptionB | +| 44 | class ExceptionA | +| 44 | class ExceptionB | +| 49 | None | +| 49 | class ExceptionA | +| 49 | class ExceptionB | +| 50 | None | +| 53 | class ExceptionA | +| 58 | None | +| 58 | class ExceptionA | +| 58 | class ExceptionB | +| 59 | None | +| 67 | None | +| 67 | class ExceptionA | +| 67 | class ExceptionB | +| 68 | None | +| 71 | None | +| 71 | class ExceptionC | +| 74 | builtin-class LookupError | +| 81 | None | +| 81 | builtin-class KeyError | +| 87 | None | +| 87 | builtin-class IndexError | +| 93 | None | +| 93 | builtin-class AttributeError | +| 99 | None | +| 105 | None | +| 105 | builtin-class LookupError | +| 107 | builtin-class LookupError | +| 110 | None | +| 110 | builtin-class IndexError | +| 114 | None | +| 114 | builtin-class IndexError | +| 120 | None | +| 120 | builtin-class IndexError | +| 126 | None | +| 126 | builtin-class IndexError | +| 128 | builtin-class IndexError | +| 132 | None | +| 132 | class ExceptionA | +| 132 | class ExceptionB | +| 135 | None | +| 136 | None | +| 136 | class ExceptionC | +| 138 | class ExceptionA | +| 138 | class ExceptionB | +| 138 | class ExceptionC | +| 146 | None | +| 146 | class ExceptionA | +| 146 | class ExceptionB | +| 152 | class ExceptionA | +| 152 | class ExceptionB | +| 158 | None | +| 158 | class ExceptionA | +| 158 | class ExceptionB | +| 164 | None | +| 166 | None | +| 166 | class ExceptionC | +| 171 | class ExceptionC | +| 172 | class ExceptionA | +| 172 | class ExceptionB | +| 178 | None | +| 178 | class ExceptionA | +| 178 | class ExceptionB | +| 183 | None | +| 183 | class ExceptionC | +| 186 | None | +| 189 | None | +| 190 | class A | +| 196 | None | +| 196 | Unknown | +| 200 | None | +| 200 | Unknown | +| 206 | None | +| 206 | Unknown | +| 209 | Unknown | diff --git a/python/ql/test/library-tests/types/exceptions/LineRaises.ql b/python/ql/test/library-tests/types/exceptions/LineRaises.ql new file mode 100644 index 00000000000..f1f51952d00 --- /dev/null +++ b/python/ql/test/library-tests/types/exceptions/LineRaises.ql @@ -0,0 +1,13 @@ + +import python + +from RaisingNode r, string type +where + type = r.getARaisedType().toString() + or + type = "Unknown" and r.raisesUnknownType() + or + not exists(r.getARaisedType()) and + not r.raisesUnknownType() and type = "None" + +select r.getNode().getLocation().getStartLine(), type diff --git a/python/ql/test/library-tests/types/exceptions/Raises.expected b/python/ql/test/library-tests/types/exceptions/Raises.expected new file mode 100644 index 00000000000..bc0ff2e0e3f --- /dev/null +++ b/python/ql/test/library-tests/types/exceptions/Raises.expected @@ -0,0 +1,37 @@ +| Function coro | Unknown | +| Function f1 | None | +| Function f2 | class ExceptionA | +| Function f5 | class ExceptionA | +| Function f6 | class ExceptionB | +| Function f7 | class ExceptionA | +| Function f7 | class ExceptionB | +| Function f8 | class ExceptionA | +| Function f8a | class ExceptionA | +| Function f8a | class ExceptionB | +| Function f9 | class ExceptionA | +| Function f10 | None | +| Function f11 | class ExceptionC | +| Function f12 | builtin-class LookupError | +| Function f13 | None | +| Function f14 | None | +| Function f15 | None | +| Function f16 | None | +| Function f17 | None | +| Function f18 | builtin-class LookupError | +| Function f19 | builtin-class IndexError | +| Function f20 | None | +| Function f21 | builtin-class IndexError | +| Function f22 | builtin-class IndexError | +| Function f23 | class ExceptionA | +| Function f23 | class ExceptionB | +| Function f23 | class ExceptionC | +| Function f24 | class ExceptionA | +| Function f24 | class ExceptionB | +| Function f25 | class ExceptionA | +| Function f25 | class ExceptionB | +| Function f25 | class ExceptionC | +| Function f26 | class ExceptionB | +| Function f26 | class ExceptionC | +| Function f27 | None | +| Function test_handled | Unknown | +| Function use_coro | Unknown | diff --git a/python/ql/test/library-tests/types/exceptions/Raises.ql b/python/ql/test/library-tests/types/exceptions/Raises.ql new file mode 100644 index 00000000000..b003fd03dfa --- /dev/null +++ b/python/ql/test/library-tests/types/exceptions/Raises.ql @@ -0,0 +1,13 @@ + +import python + +from PyFunctionObject f, string type +where + type = f.getARaisedType().toString() + or + type = "Unknown" and f.raisesUnknownType() + or + not exists(f.getARaisedType()) and + not f.raisesUnknownType() and type = "None" + +select f.toString(), type \ No newline at end of file diff --git a/python/ql/test/library-tests/types/exceptions/Reraises.expected b/python/ql/test/library-tests/types/exceptions/Reraises.expected new file mode 100644 index 00000000000..48bf8be907f --- /dev/null +++ b/python/ql/test/library-tests/types/exceptions/Reraises.expected @@ -0,0 +1,15 @@ +| 44 | test.py:44:9:44:12 | ControlFlowNode for Pass | class ExceptionA | +| 44 | test.py:44:9:44:12 | ControlFlowNode for Pass | class ExceptionB | +| 53 | test.py:53:9:53:12 | ControlFlowNode for Pass | class ExceptionA | +| 107 | test.py:107:9:107:12 | ControlFlowNode for Pass | builtin-class LookupError | +| 128 | test.py:128:9:128:12 | ControlFlowNode for Pass | builtin-class IndexError | +| 138 | test.py:138:13:138:16 | ControlFlowNode for Pass | class ExceptionA | +| 138 | test.py:138:13:138:16 | ControlFlowNode for Pass | class ExceptionB | +| 138 | test.py:138:13:138:16 | ControlFlowNode for Pass | class ExceptionC | +| 138 | test.py:138:13:138:16 | ControlFlowNode for Pass | class ExceptionC | +| 152 | test.py:152:9:152:12 | ControlFlowNode for Pass | class ExceptionA | +| 152 | test.py:152:9:152:12 | ControlFlowNode for Pass | class ExceptionB | +| 171 | test.py:171:13:171:16 | ControlFlowNode for Pass | class ExceptionC | +| 171 | test.py:171:13:171:16 | ControlFlowNode for Pass | class ExceptionC | +| 172 | test.py:172:9:172:12 | ControlFlowNode for Pass | class ExceptionA | +| 172 | test.py:172:9:172:12 | ControlFlowNode for Pass | class ExceptionB | diff --git a/python/ql/test/library-tests/types/exceptions/Reraises.ql b/python/ql/test/library-tests/types/exceptions/Reraises.ql new file mode 100644 index 00000000000..9edcdf57b4b --- /dev/null +++ b/python/ql/test/library-tests/types/exceptions/Reraises.ql @@ -0,0 +1,6 @@ + +import python + +from ReraisingNode r + +select r.getLocation().getStartLine(), r, r.getARaisedType().toString() \ No newline at end of file diff --git a/python/ql/test/library-tests/types/exceptions/Viable.expected b/python/ql/test/library-tests/types/exceptions/Viable.expected new file mode 100644 index 00000000000..11e0cbd0ef3 --- /dev/null +++ b/python/ql/test/library-tests/types/exceptions/Viable.expected @@ -0,0 +1,25 @@ +| 36 | 37 | f7() | ExceptStmt | class ExceptionB | +| 42 | 44 | f7() | Pass | class ExceptionA | +| 42 | 44 | f7() | Pass | class ExceptionB | +| 49 | 50 | f7() | ExceptStmt | class ExceptionB | +| 49 | 53 | f7() | Pass | class ExceptionA | +| 58 | 59 | f7() | ExceptStmt | class ExceptionB | +| 58 | 62 | f7() | Return | class ExceptionA | +| 67 | 68 | f7() | ExceptStmt | class ExceptionB | +| 67 | 71 | f7() | ExceptionC | class ExceptionA | +| 81 | 82 | Subscript | ExceptStmt | builtin-class KeyError | +| 87 | 88 | Subscript | ExceptStmt | builtin-class IndexError | +| 93 | 94 | Attribute | ExceptStmt | builtin-class AttributeError | +| 105 | 107 | Subscript | Pass | builtin-class LookupError | +| 114 | 115 | f19() | ExceptStmt | builtin-class IndexError | +| 126 | 128 | f19() | Pass | builtin-class IndexError | +| 132 | 134 | f7() | Try | class ExceptionA | +| 132 | 134 | f7() | Try | class ExceptionB | +| 136 | 138 | Raise | Pass | class ExceptionC | +| 146 | 150 | f7() | Pass | class ExceptionA | +| 146 | 150 | f7() | Pass | class ExceptionB | +| 158 | 162 | f7() | Try | class ExceptionA | +| 158 | 162 | f7() | Try | class ExceptionB | +| 166 | 169 | Raise | Pass | class ExceptionC | +| 178 | 181 | f7() | ExceptStmt | class ExceptionA | +| 190 | 191 | Raise | ExceptStmt | class A | diff --git a/python/ql/test/library-tests/types/exceptions/Viable.ql b/python/ql/test/library-tests/types/exceptions/Viable.ql new file mode 100644 index 00000000000..544b0a0d0b6 --- /dev/null +++ b/python/ql/test/library-tests/types/exceptions/Viable.ql @@ -0,0 +1,7 @@ + + +import python + +from RaisingNode r, ControlFlowNode n, ClassObject ex +where r.viableExceptionEdge(n, ex) +select r.getLocation().getStartLine(), n.getLocation().getStartLine(), r.getNode().toString(), n.getNode().toString(), ex.toString() diff --git a/python/ql/test/library-tests/types/exceptions/test.py b/python/ql/test/library-tests/types/exceptions/test.py new file mode 100644 index 00000000000..d6b19ca987a --- /dev/null +++ b/python/ql/test/library-tests/types/exceptions/test.py @@ -0,0 +1,211 @@ + + +class ExceptionA(Exception): + pass + +class ExceptionB(Exception): + pass + +class ExceptionC(Exception): + pass + +def f1(): + pass + +def f2(): + raise ExceptionA() + + + + +def f5(): + f2() + +def f6(): + raise ExceptionB() + raise IOError() + +def f7(): + if x: + raise ExceptionA() + else: + raise ExceptionB() + +def f8(): + try: + f7() + except ExceptionB: + pass + +def f8a(): + try: + f7() + finally: + pass + +def f9(): + try: + try: + f7() + except ExceptionB: + pass + finally: + pass + +def f10(): + try: + try: + f7() + except ExceptionB: + pass + finally: + return + +def f11(): + try: + try: + f7() + except ExceptionB: + pass + finally: + raise ExceptionC() + +def f12(): + x["Hello"] + +def f13(): + x.attr + +def f14(): + try: + x["Hello"] + except KeyError: + pass + +def f15(): + try: + x[1] + except IndexError: + pass + +def f16(): + try: + x.attr + except AttributeError: + pass + +def f17(): + try: + x.attr + except ExceptionA: + pass + +def f18(): + try: + x["Hello"] + finally: + pass + +def f19(): + raise IndexError() + +def f20(): + try: + f19() + except IndexError: + pass + +def f21(): + try: + f19() + except KeyError: + pass + +def f22(): + try: + f19() + finally: + pass + +def f23(): + try: + f7() + finally: + try: + if x: + raise ExceptionC() + finally: + pass + +#Longer basic blocks + +def f24(): + try: + pass + pass + f7() + pass + pass + finally: + pass + pass + pass + +def f25(): + try: + pass + pass + f7() + pass + pass + finally: + try: + pass + if x: + pass + raise ExceptionC() + pass + finally: + pass + pass + pass + pass + +def f26(): + try: + pass + pass + f7() + pass + pass + except ExceptionA: + pass + raise ExceptionC() + +def f27(): + class A(BaseException): + pass + try: + a = A() + raise a + except A: + pass + +def test_handled(): + try: + func() + except (ExceptionA, ExceptionB): + pass + try: + func() + except (ExceptionC, KeyError) as ex: + pass + +def coro(): + yield 0 + raise SpecialException() + +def use_coro(): + yield coro() + reachable + diff --git a/python/ql/test/library-tests/types/functions/Zope.expected b/python/ql/test/library-tests/types/functions/Zope.expected new file mode 100644 index 00000000000..339baf4798a --- /dev/null +++ b/python/ql/test/library-tests/types/functions/Zope.expected @@ -0,0 +1 @@ +| Function yes | diff --git a/python/ql/test/library-tests/types/functions/Zope.ql b/python/ql/test/library-tests/types/functions/Zope.ql new file mode 100644 index 00000000000..d3143778b2b --- /dev/null +++ b/python/ql/test/library-tests/types/functions/Zope.ql @@ -0,0 +1,6 @@ + +import python +import semmle.python.libraries.Zope + +from ZopeInterfaceMethod f +select f.toString() diff --git a/python/ql/test/library-tests/types/functions/test.py b/python/ql/test/library-tests/types/functions/test.py new file mode 100644 index 00000000000..7e2b24607be --- /dev/null +++ b/python/ql/test/library-tests/types/functions/test.py @@ -0,0 +1,12 @@ +import zope.interface + +#ODASA-6062 +class Z(zope.interface.Interface): + + def yes(arg): + pass + +class NotZ(object): + + def no(self): + pass diff --git a/python/ql/test/library-tests/types/functions/zope/__init__.py b/python/ql/test/library-tests/types/functions/zope/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/library-tests/types/functions/zope/interface.py b/python/ql/test/library-tests/types/functions/zope/interface.py new file mode 100644 index 00000000000..0bad91e9620 --- /dev/null +++ b/python/ql/test/library-tests/types/functions/zope/interface.py @@ -0,0 +1,6 @@ +#Fake zope.interface Module + +class InterfaceClass(object): + pass + +Interface = InterfaceClass() diff --git a/python/ql/test/library-tests/types/properties/Deleters.expected b/python/ql/test/library-tests/types/properties/Deleters.expected new file mode 100644 index 00000000000..1fb91ed794b --- /dev/null +++ b/python/ql/test/library-tests/types/properties/Deleters.expected @@ -0,0 +1 @@ +| Property p2 | Function p2 | \ No newline at end of file diff --git a/python/ql/test/library-tests/types/properties/Deleters.ql b/python/ql/test/library-tests/types/properties/Deleters.ql new file mode 100644 index 00000000000..e57f5917e6e --- /dev/null +++ b/python/ql/test/library-tests/types/properties/Deleters.ql @@ -0,0 +1,5 @@ +import python + +from PythonPropertyObject p + +select p.toString(), p.getDeleter().toString() diff --git a/python/ql/test/library-tests/types/properties/Getters.expected b/python/ql/test/library-tests/types/properties/Getters.expected new file mode 100644 index 00000000000..c451d9c1f38 --- /dev/null +++ b/python/ql/test/library-tests/types/properties/Getters.expected @@ -0,0 +1,3 @@ +| Property p1 | Function p1 | +| Property p2 | Function p2 | +| Property p3 | Function p3 | \ No newline at end of file diff --git a/python/ql/test/library-tests/types/properties/Getters.ql b/python/ql/test/library-tests/types/properties/Getters.ql new file mode 100644 index 00000000000..2d495ccfc2f --- /dev/null +++ b/python/ql/test/library-tests/types/properties/Getters.ql @@ -0,0 +1,5 @@ +import python + +from PythonPropertyObject p + +select p.toString(), p.getGetter().toString() diff --git a/python/ql/test/library-tests/types/properties/PythonProperties.expected b/python/ql/test/library-tests/types/properties/PythonProperties.expected new file mode 100644 index 00000000000..4bb0de96c31 --- /dev/null +++ b/python/ql/test/library-tests/types/properties/PythonProperties.expected @@ -0,0 +1,3 @@ +| Property p1 | +| Property p2 | +| Property p3 | \ No newline at end of file diff --git a/python/ql/test/library-tests/types/properties/PythonProperties.ql b/python/ql/test/library-tests/types/properties/PythonProperties.ql new file mode 100644 index 00000000000..91281c321a0 --- /dev/null +++ b/python/ql/test/library-tests/types/properties/PythonProperties.ql @@ -0,0 +1,5 @@ +import python + +from PythonPropertyObject p + +select p.toString() diff --git a/python/ql/test/library-tests/types/properties/Setters.expected b/python/ql/test/library-tests/types/properties/Setters.expected new file mode 100644 index 00000000000..852998fd746 --- /dev/null +++ b/python/ql/test/library-tests/types/properties/Setters.expected @@ -0,0 +1,2 @@ +| Property p1 | Function p1 | +| Property p3 | Function p3_set | \ No newline at end of file diff --git a/python/ql/test/library-tests/types/properties/Setters.ql b/python/ql/test/library-tests/types/properties/Setters.ql new file mode 100644 index 00000000000..4e13e54db63 --- /dev/null +++ b/python/ql/test/library-tests/types/properties/Setters.ql @@ -0,0 +1,5 @@ +import python + +from PythonPropertyObject p + +select p.toString(), p.getSetter().toString() diff --git a/python/ql/test/library-tests/types/properties/properties.py b/python/ql/test/library-tests/types/properties/properties.py new file mode 100644 index 00000000000..4f092454ac1 --- /dev/null +++ b/python/ql/test/library-tests/types/properties/properties.py @@ -0,0 +1,29 @@ +class C(object): + + @property + def p1(self): + return 1 + + @p1.setter + def p1(self, val): + pass + + @property + def p2(self): + return 1 + + @p2.deleter + def p2(self, val): + pass + + def p3(self): + return 1 + + p3 = property(p3) + + def p3_set(self, val): + pass + + p3 = p3.setter(p3_set) + + \ No newline at end of file diff --git a/python/ql/test/library-tests/variables/definitions/test.expected b/python/ql/test/library-tests/variables/definitions/test.expected new file mode 100644 index 00000000000..dc853ee7f2f --- /dev/null +++ b/python/ql/test/library-tests/variables/definitions/test.expected @@ -0,0 +1,4 @@ +| 3 | 5 | ControlFlowNode for fail5 | +| 4 | 5 | ControlFlowNode for Tuple | +| 4 | 5 | ControlFlowNode for x | +| 4 | 8 | ControlFlowNode for y | \ No newline at end of file diff --git a/python/ql/test/library-tests/variables/definitions/test.py b/python/ql/test/library-tests/variables/definitions/test.py new file mode 100644 index 00000000000..0695a275b3c --- /dev/null +++ b/python/ql/test/library-tests/variables/definitions/test.py @@ -0,0 +1,5 @@ + +#ODASA-4153 +def fail5(t): + x, y = t + return x diff --git a/python/ql/test/library-tests/variables/definitions/test.ql b/python/ql/test/library-tests/variables/definitions/test.ql new file mode 100644 index 00000000000..9abee816b3a --- /dev/null +++ b/python/ql/test/library-tests/variables/definitions/test.ql @@ -0,0 +1,5 @@ +import python + +from DefinitionNode d + +select d.getLocation().getStartLine(), d.getLocation().getStartColumn(), d.toString() diff --git a/python/ql/test/library-tests/variables/scopes/free.expected b/python/ql/test/library-tests/variables/scopes/free.expected new file mode 100644 index 00000000000..3277eb55dd6 --- /dev/null +++ b/python/ql/test/library-tests/variables/scopes/free.expected @@ -0,0 +1,9 @@ +| Local Variable local2 | Function func2 | Function inner1 | +| Local Variable local4 | Function func3 | Function inner2 | +| Local Variable local4 | Function func3 | Function inner_outer | +| Local Variable local5 | Function inner_outer | Function inner2 | +| Local Variable param4 | Function func3 | Function inner2 | +| Local Variable param4 | Function func3 | Function inner_outer | +| Local Variable param5 | Function func3 | Function inner_outer | +| Local Variable param6 | Function func4 | Function meth_inner | +| Local Variable z | Function func6 | Function listcomp | diff --git a/python/ql/test/library-tests/variables/scopes/free.ql b/python/ql/test/library-tests/variables/scopes/free.ql new file mode 100644 index 00000000000..1e15bb3a312 --- /dev/null +++ b/python/ql/test/library-tests/variables/scopes/free.ql @@ -0,0 +1,7 @@ +import python + +from LocalVariable v, Scope inner +where v.escapes() and inner = v.getAnAccess().getScope() and +inner != v.getScope() +select v.toString(), v.getScope().toString(), inner.toString() + diff --git a/python/ql/test/library-tests/variables/scopes/globals.expected b/python/ql/test/library-tests/variables/scopes/globals.expected new file mode 100644 index 00000000000..c0ed16f7582 --- /dev/null +++ b/python/ql/test/library-tests/variables/scopes/globals.expected @@ -0,0 +1,17 @@ +| Global Variable C | Module test | +| Global Variable __name__ | Module test | +| Global Variable __package__ | Module test | +| Global Variable base | Module test | +| Global Variable func0 | Module test | +| Global Variable func1 | Module test | +| Global Variable func2 | Module test | +| Global Variable func3 | Module test | +| Global Variable func4 | Module test | +| Global Variable func5 | Module test | +| Global Variable func6 | Module test | +| Global Variable global0 | Module test | +| Global Variable global1 | Module test | +| Global Variable global_local | Module test | +| Global Variable range | Module test | +| Global Variable seq | Module test | +| Global Variable use_in_loop | Module test | diff --git a/python/ql/test/library-tests/variables/scopes/globals.ql b/python/ql/test/library-tests/variables/scopes/globals.ql new file mode 100644 index 00000000000..8d200aa81b0 --- /dev/null +++ b/python/ql/test/library-tests/variables/scopes/globals.ql @@ -0,0 +1,5 @@ +import python + +from GlobalVariable l +select l.toString(), l.getScope().toString() + diff --git a/python/ql/test/library-tests/variables/scopes/locals.expected b/python/ql/test/library-tests/variables/scopes/locals.expected new file mode 100644 index 00000000000..1a662bdb671 --- /dev/null +++ b/python/ql/test/library-tests/variables/scopes/locals.expected @@ -0,0 +1,34 @@ +| Local Variable .0 | test.py:45:12:45:27 | Function listcomp | fast | +| Local Variable .0 | test.py:48:12:48:29 | Function listcomp | fast | +| Local Variable .0 | test.py:52:5:52:25 | Function listcomp | fast | +| Local Variable Local | test.py:38:1:38:18 | Function func4 | fast | +| Local Variable class_local | test.py:30:1:30:14 | Class C | name | +| Local Variable inner1 | test.py:15:1:15:12 | Function func2 | fast | +| Local Variable inner2 | test.py:24:5:24:22 | Function inner_outer | fast | +| Local Variable inner_outer | test.py:22:1:22:26 | Function func3 | fast | +| Local Variable local0 | test.py:8:1:8:12 | Function func1 | fast | +| Local Variable local1 | test.py:8:1:8:12 | Function func1 | fast | +| Local Variable local2 | test.py:15:1:15:12 | Function func2 | fast | +| Local Variable local3 | test.py:17:5:17:23 | Function inner1 | fast | +| Local Variable local4 | test.py:22:1:22:26 | Function func3 | fast | +| Local Variable local5 | test.py:24:5:24:22 | Function inner_outer | fast | +| Local Variable meth | test.py:30:1:30:14 | Class C | name | +| Local Variable meth_inner | test.py:39:5:39:16 | Class Local | name | +| Local Variable mlocal | test.py:34:5:34:19 | Function meth | fast | +| Local Variable param0 | test.py:5:1:5:26 | Function func0 | fast | +| Local Variable param1 | test.py:5:1:5:26 | Function func0 | fast | +| Local Variable param2 | test.py:17:5:17:23 | Function inner1 | fast | +| Local Variable param3 | test.py:25:9:25:27 | Function inner2 | fast | +| Local Variable param4 | test.py:22:1:22:26 | Function func3 | fast | +| Local Variable param5 | test.py:22:1:22:26 | Function func3 | fast | +| Local Variable param6 | test.py:38:1:38:18 | Function func4 | fast | +| Local Variable self | test.py:34:5:34:19 | Function meth | fast | +| Local Variable self | test.py:40:9:40:29 | Function meth_inner | fast | +| Local Variable seq | test.py:44:1:44:15 | Function func5 | fast | +| Local Variable seq | test.py:51:1:51:21 | Function use_in_loop | fast | +| Local Variable v | test.py:51:1:51:21 | Function use_in_loop | fast | +| Local Variable v | test.py:52:5:52:25 | Function listcomp | fast | +| Local Variable x | test.py:45:12:45:27 | Function listcomp | fast | +| Local Variable y | test.py:47:1:47:16 | Function func6 | fast | +| Local Variable y | test.py:48:12:48:29 | Function listcomp | fast | +| Local Variable z | test.py:47:1:47:16 | Function func6 | fast | diff --git a/python/ql/test/library-tests/variables/scopes/locals.ql b/python/ql/test/library-tests/variables/scopes/locals.ql new file mode 100644 index 00000000000..264c5e9b7d1 --- /dev/null +++ b/python/ql/test/library-tests/variables/scopes/locals.ql @@ -0,0 +1,10 @@ +import python + +from LocalVariable l, string kind +where +l instanceof FastLocalVariable and kind = "fast" +or +l instanceof NameLocalVariable and kind = "name" + +select l, l.getScope(), kind + diff --git a/python/ql/test/library-tests/variables/scopes/lookup.expected b/python/ql/test/library-tests/variables/scopes/lookup.expected new file mode 100644 index 00000000000..2418f1d9283 --- /dev/null +++ b/python/ql/test/library-tests/variables/scopes/lookup.expected @@ -0,0 +1,34 @@ +| 6 | ControlFlowNode for param0 | local | +| 6 | ControlFlowNode for param1 | local | +| 12 | ControlFlowNode for global_local | global | +| 13 | ControlFlowNode for global1 | global | +| 13 | ControlFlowNode for local0 | local | +| 13 | ControlFlowNode for local1 | local | +| 18 | ControlFlowNode for local2 | non-local | +| 19 | ControlFlowNode for local3 | local | +| 20 | ControlFlowNode for inner1 | local | +| 26 | ControlFlowNode for local4 | non-local | +| 26 | ControlFlowNode for local5 | non-local | +| 26 | ControlFlowNode for param3 | local | +| 26 | ControlFlowNode for param4 | non-local | +| 28 | ControlFlowNode for inner2 | local | +| 28 | ControlFlowNode for local4 | non-local | +| 28 | ControlFlowNode for param4 | non-local | +| 28 | ControlFlowNode for param5 | non-local | +| 30 | ControlFlowNode for base | global | +| 35 | ControlFlowNode for self | local | +| 36 | ControlFlowNode for mlocal | local | +| 41 | ControlFlowNode for param6 | non-local | +| 42 | ControlFlowNode for Local | local | +| 45 | ControlFlowNode for .0 | local | +| 45 | ControlFlowNode for seq | local | +| 45 | ControlFlowNode for x | local | +| 48 | ControlFlowNode for .0 | local | +| 48 | ControlFlowNode for seq | global | +| 48 | ControlFlowNode for y | local | +| 48 | ControlFlowNode for z | non-local | +| 52 | ControlFlowNode for .0 | local | +| 52 | ControlFlowNode for range | global | +| 52 | ControlFlowNode for v | local | +| 53 | ControlFlowNode for seq | local | +| 54 | ControlFlowNode for v | local | diff --git a/python/ql/test/library-tests/variables/scopes/lookup.ql b/python/ql/test/library-tests/variables/scopes/lookup.ql new file mode 100644 index 00000000000..c7a776c7caa --- /dev/null +++ b/python/ql/test/library-tests/variables/scopes/lookup.ql @@ -0,0 +1,16 @@ +import python + +from NameNode n, string l +where +n.isLoad() and ( + n.isGlobal() and l = "global" + or + n.isLocal() and l = "local" + or + n.isNonLocal() and l = "non-local" + or + not n.isGlobal() and not n.isLocal() and + not n.isNonLocal() and + l = "none" +) +select n.getLocation().getStartLine(), n.toString(), l diff --git a/python/ql/test/library-tests/variables/scopes/scopes.expected b/python/ql/test/library-tests/variables/scopes/scopes.expected new file mode 100644 index 00000000000..cf4a6edbfbb --- /dev/null +++ b/python/ql/test/library-tests/variables/scopes/scopes.expected @@ -0,0 +1,51 @@ +| Global Variable C | test.py:0:0:0:0 | Module test | +| Global Variable __name__ | test.py:0:0:0:0 | Module test | +| Global Variable __package__ | test.py:0:0:0:0 | Module test | +| Global Variable base | test.py:0:0:0:0 | Module test | +| Global Variable func0 | test.py:0:0:0:0 | Module test | +| Global Variable func1 | test.py:0:0:0:0 | Module test | +| Global Variable func2 | test.py:0:0:0:0 | Module test | +| Global Variable func3 | test.py:0:0:0:0 | Module test | +| Global Variable func4 | test.py:0:0:0:0 | Module test | +| Global Variable func5 | test.py:0:0:0:0 | Module test | +| Global Variable func6 | test.py:0:0:0:0 | Module test | +| Global Variable global0 | test.py:0:0:0:0 | Module test | +| Global Variable global1 | test.py:0:0:0:0 | Module test | +| Global Variable global_local | test.py:0:0:0:0 | Module test | +| Global Variable range | test.py:0:0:0:0 | Module test | +| Global Variable seq | test.py:0:0:0:0 | Module test | +| Global Variable use_in_loop | test.py:0:0:0:0 | Module test | +| Local Variable .0 | test.py:45:12:45:27 | Function listcomp | +| Local Variable .0 | test.py:48:12:48:29 | Function listcomp | +| Local Variable .0 | test.py:52:5:52:25 | Function listcomp | +| Local Variable Local | test.py:38:1:38:18 | Function func4 | +| Local Variable class_local | test.py:30:1:30:14 | Class C | +| Local Variable inner1 | test.py:15:1:15:12 | Function func2 | +| Local Variable inner2 | test.py:24:5:24:22 | Function inner_outer | +| Local Variable inner_outer | test.py:22:1:22:26 | Function func3 | +| Local Variable local0 | test.py:8:1:8:12 | Function func1 | +| Local Variable local1 | test.py:8:1:8:12 | Function func1 | +| Local Variable local2 | test.py:15:1:15:12 | Function func2 | +| Local Variable local3 | test.py:17:5:17:23 | Function inner1 | +| Local Variable local4 | test.py:22:1:22:26 | Function func3 | +| Local Variable local5 | test.py:24:5:24:22 | Function inner_outer | +| Local Variable meth | test.py:30:1:30:14 | Class C | +| Local Variable meth_inner | test.py:39:5:39:16 | Class Local | +| Local Variable mlocal | test.py:34:5:34:19 | Function meth | +| Local Variable param0 | test.py:5:1:5:26 | Function func0 | +| Local Variable param1 | test.py:5:1:5:26 | Function func0 | +| Local Variable param2 | test.py:17:5:17:23 | Function inner1 | +| Local Variable param3 | test.py:25:9:25:27 | Function inner2 | +| Local Variable param4 | test.py:22:1:22:26 | Function func3 | +| Local Variable param5 | test.py:22:1:22:26 | Function func3 | +| Local Variable param6 | test.py:38:1:38:18 | Function func4 | +| Local Variable self | test.py:34:5:34:19 | Function meth | +| Local Variable self | test.py:40:9:40:29 | Function meth_inner | +| Local Variable seq | test.py:44:1:44:15 | Function func5 | +| Local Variable seq | test.py:51:1:51:21 | Function use_in_loop | +| Local Variable v | test.py:51:1:51:21 | Function use_in_loop | +| Local Variable v | test.py:52:5:52:25 | Function listcomp | +| Local Variable x | test.py:45:12:45:27 | Function listcomp | +| Local Variable y | test.py:47:1:47:16 | Function func6 | +| Local Variable y | test.py:48:12:48:29 | Function listcomp | +| Local Variable z | test.py:47:1:47:16 | Function func6 | diff --git a/python/ql/test/library-tests/variables/scopes/scopes.ql b/python/ql/test/library-tests/variables/scopes/scopes.ql new file mode 100644 index 00000000000..b87a45c9939 --- /dev/null +++ b/python/ql/test/library-tests/variables/scopes/scopes.ql @@ -0,0 +1,6 @@ + +import python + +from Variable v, Scope s +where v.getScope() = s +select v, s diff --git a/python/ql/test/library-tests/variables/scopes/test.py b/python/ql/test/library-tests/variables/scopes/test.py new file mode 100644 index 00000000000..940576d44df --- /dev/null +++ b/python/ql/test/library-tests/variables/scopes/test.py @@ -0,0 +1,54 @@ + +global0 = 0 +global1 = 1 + +def func0(param0, param1): + return param0 + param1 + +def func1(): + global global0, global_local + local0 = 0 + local1 = 1 + global_local + global0 = local0 + local1 + global1 + +def func2(): + local2 = 2 + def inner1(param2): + local3 = local2 + return local3 + return inner1 + +def func3(param4, param5): + local4 = 4 + def inner_outer(): + def inner2(param3): + return local5 + local4 + param3 + param4 + local5 = 3 + return inner2(local4 + param4 + param5) + +class C(base): + + class_local = 7 + + def meth(self): + mlocal = self + return mlocal + +def func4(param6): + class Local: + def meth_inner(self): + return param6 + return Local() + +def func5(seq): + return [x for x in seq] + +def func6(y, z): + return [y+z for y in seq] + +#FP observed in sembuild +def use_in_loop(seq): + [v for v in range(3)] + for v in seq: + v #x redefined -- fine in 2 and 3. diff --git a/python/ql/test/query-tests/Classes/Arguments/WrongNameForArgumentInClassInstantiation.expected b/python/ql/test/query-tests/Classes/Arguments/WrongNameForArgumentInClassInstantiation.expected new file mode 100644 index 00000000000..cf89ddfc44f --- /dev/null +++ b/python/ql/test/query-tests/Classes/Arguments/WrongNameForArgumentInClassInstantiation.expected @@ -0,0 +1,4 @@ +| wrong_arguments.py:65:1:65:7 | F0() | Keyword argument 'y' is not a supported parameter name of $@. | wrong_arguments.py:4:5:4:26 | Function __init__ | F0.__init__ | +| wrong_arguments.py:66:1:66:7 | F1() | Keyword argument 'z' is not a supported parameter name of $@. | wrong_arguments.py:8:5:8:36 | Function __init__ | F1.__init__ | +| wrong_arguments.py:67:1:67:12 | F2() | Keyword argument 'y' is not a supported parameter name of $@. | wrong_arguments.py:12:5:12:30 | Function __init__ | F2.__init__ | +| wrong_arguments.py:92:1:92:27 | F6() | Keyword argument 'z' is not a supported parameter name of $@. | wrong_arguments.py:28:5:28:30 | Function __init__ | F6.__init__ | diff --git a/python/ql/test/query-tests/Classes/Arguments/WrongNameForArgumentInClassInstantiation.qlref b/python/ql/test/query-tests/Classes/Arguments/WrongNameForArgumentInClassInstantiation.qlref new file mode 100644 index 00000000000..408766dcbf4 --- /dev/null +++ b/python/ql/test/query-tests/Classes/Arguments/WrongNameForArgumentInClassInstantiation.qlref @@ -0,0 +1 @@ +Classes/WrongNameForArgumentInClassInstantiation.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Classes/Arguments/WrongNumberArgumentsInClassInstantiation.expected b/python/ql/test/query-tests/Classes/Arguments/WrongNumberArgumentsInClassInstantiation.expected new file mode 100644 index 00000000000..b0c156dc867 --- /dev/null +++ b/python/ql/test/query-tests/Classes/Arguments/WrongNumberArgumentsInClassInstantiation.expected @@ -0,0 +1,15 @@ +| wrong_arguments.py:37:1:37:4 | F0() | Call to $@ with too few arguments; should be no fewer than 1. | wrong_arguments.py:4:5:4:26 | Function __init__ | F0.__init__ | +| wrong_arguments.py:38:1:38:4 | F1() | Call to $@ with too few arguments; should be no fewer than 1. | wrong_arguments.py:8:5:8:36 | Function __init__ | F1.__init__ | +| wrong_arguments.py:39:1:39:4 | F2() | Call to $@ with too few arguments; should be no fewer than 1. | wrong_arguments.py:12:5:12:30 | Function __init__ | F2.__init__ | +| wrong_arguments.py:40:1:40:4 | F3() | Call to $@ with too few arguments; should be no fewer than 1. | wrong_arguments.py:16:5:16:40 | Function __init__ | F3.__init__ | +| wrong_arguments.py:41:1:41:4 | F4() | Call to $@ with too few arguments; should be no fewer than 1. | wrong_arguments.py:20:5:20:31 | Function __init__ | F4.__init__ | +| wrong_arguments.py:42:1:42:4 | F5() | Call to $@ with too few arguments; should be no fewer than 1. | wrong_arguments.py:24:5:24:42 | Function __init__ | F5.__init__ | +| wrong_arguments.py:43:1:43:5 | F6() | Call to $@ with too few arguments; should be no fewer than 2. | wrong_arguments.py:28:5:28:30 | Function __init__ | F6.__init__ | +| wrong_arguments.py:44:1:44:7 | F7() | Call to $@ with too few arguments; should be no fewer than 3. | wrong_arguments.py:32:5:32:33 | Function __init__ | F7.__init__ | +| wrong_arguments.py:48:1:48:7 | F0() | Call to $@ with too many arguments; should be no more than 1. | wrong_arguments.py:4:5:4:26 | Function __init__ | F0.__init__ | +| wrong_arguments.py:49:1:49:9 | F1() | Call to $@ with too many arguments; should be no more than 2. | wrong_arguments.py:8:5:8:36 | Function __init__ | F1.__init__ | +| wrong_arguments.py:50:1:50:9 | F5() | Call to $@ with too many arguments; should be no more than 2. | wrong_arguments.py:24:5:24:42 | Function __init__ | F5.__init__ | +| wrong_arguments.py:51:1:51:9 | F6() | Call to $@ with too many arguments; should be no more than 2. | wrong_arguments.py:28:5:28:30 | Function __init__ | F6.__init__ | +| wrong_arguments.py:52:1:52:11 | F6() | Call to $@ with too many arguments; should be no more than 2. | wrong_arguments.py:28:5:28:30 | Function __init__ | F6.__init__ | +| wrong_arguments.py:85:1:85:12 | F6() | Call to $@ with too many arguments; should be no more than 2. | wrong_arguments.py:28:5:28:30 | Function __init__ | F6.__init__ | +| wrong_arguments.py:86:1:86:7 | F6() | Call to $@ with too many arguments; should be no more than 2. | wrong_arguments.py:28:5:28:30 | Function __init__ | F6.__init__ | diff --git a/python/ql/test/query-tests/Classes/Arguments/WrongNumberArgumentsInClassInstantiation.qlref b/python/ql/test/query-tests/Classes/Arguments/WrongNumberArgumentsInClassInstantiation.qlref new file mode 100644 index 00000000000..4fdda20e163 --- /dev/null +++ b/python/ql/test/query-tests/Classes/Arguments/WrongNumberArgumentsInClassInstantiation.qlref @@ -0,0 +1 @@ +Classes/WrongNumberArgumentsInClassInstantiation.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Classes/Arguments/wrong_arguments.py b/python/ql/test/query-tests/Classes/Arguments/wrong_arguments.py new file mode 100644 index 00000000000..7363fdebef4 --- /dev/null +++ b/python/ql/test/query-tests/Classes/Arguments/wrong_arguments.py @@ -0,0 +1,93 @@ +# Test cases corresponding to /Expressions/Arguments/wrong_arguments.py + +class F0(object): + def __init__(self, x): + pass + +class F1(object): + def __init__(self, x, y = None): + pass + +class F2(object): + def __init__(self, x, *y): + pass + +class F3(object): + def __init__(self, x, y = None, *z): + pass + +class F4(object): + def __init__(self, x, **y): + pass + +class F5(object): + def __init__(self, x, y = None, **z): + pass + +class F6(object): + def __init__(self, x, y): + pass + +class F7(object): + def __init__(self, x, y, z): + pass + +# Too few arguments + +F0() +F1() +F2() +F3() +F4() +F5() +F6(1) +F7(1,2) + +#Too many arguments + +F0(1,2) +F1(1,2,3) +F5(1,2,3) +F6(1,2,3) +F6(1,2,3,4) + +#OK + +#Not too few +F7(*t) + +#Not too many + +F2(1,2,3,4,5,6) + + +#Illegal name +F0(y=1) +F1(z=1) +F2(x=0, y=1) + + +#Ok name +F0(x=0) +F1(x=0, y=1) +F4(q=4) + +#This is correct, but a bit weird. +F6(**{'x':1, 'y':2}) + +t2 = (1,2) +t3 = (1,2,3) + +#Ok +f(*t2) + +#Too many +F6(*(1,2,3)) +F6(*t3) + +#Ok +F6(**{'x':1, 'y':2}) + +#Illegal name +F6(**{'x':1, 'y':2, 'z':3}) + diff --git a/python/ql/test/query-tests/Classes/conflicting/ConflictingAttributesInBaseClasses.expected b/python/ql/test/query-tests/Classes/conflicting/ConflictingAttributesInBaseClasses.expected new file mode 100644 index 00000000000..6aca2a29c46 --- /dev/null +++ b/python/ql/test/query-tests/Classes/conflicting/ConflictingAttributesInBaseClasses.expected @@ -0,0 +1,2 @@ +| test.py:26:1:26:25 | class Conflict | Base classes have conflicting values for attribute 'attr': $@ and $@. | file://:Compiled Code:0:0:0:0 | int 1 | int 1 | test.py:20:13:20:16 | Tuple | Tuple | +| test.py:26:1:26:25 | class Conflict | Base classes have conflicting values for attribute 'meth': $@ and $@. | test.py:14:5:14:19 | Function meth | Function meth | test.py:22:5:22:19 | Function meth | Function meth | diff --git a/python/ql/test/query-tests/Classes/conflicting/ConflictingAttributesInBaseClasses.qlref b/python/ql/test/query-tests/Classes/conflicting/ConflictingAttributesInBaseClasses.qlref new file mode 100644 index 00000000000..3d6fa6534c5 --- /dev/null +++ b/python/ql/test/query-tests/Classes/conflicting/ConflictingAttributesInBaseClasses.qlref @@ -0,0 +1 @@ +Classes/ConflictingAttributesInBaseClasses.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Classes/conflicting/odasa6643.py b/python/ql/test/query-tests/Classes/conflicting/odasa6643.py new file mode 100644 index 00000000000..30efea5df35 --- /dev/null +++ b/python/ql/test/query-tests/Classes/conflicting/odasa6643.py @@ -0,0 +1,17 @@ +#This code has conflicting attributes, +#but the documentation in the standard library tells you do it this way :( + +#See https://discuss.lgtm.com/t/warning-on-normal-use-of-python-socketserver-mixins/677 + +class ThreadingMixIn(object): + + def process_request(selfself, req): + pass + +class HTTPServer(object): + + def process_request(selfself, req): + pass + +class _ThreadingSimpleServer(ThreadingMixIn, HTTPServer): + pass diff --git a/python/ql/test/query-tests/Classes/conflicting/test.py b/python/ql/test/query-tests/Classes/conflicting/test.py new file mode 100644 index 00000000000..624cea77ce5 --- /dev/null +++ b/python/ql/test/query-tests/Classes/conflicting/test.py @@ -0,0 +1,52 @@ + + +#Conflicting attributes in base classes + +class Common(object): + ok1 = None + + def ok2(self): + return None + +class CB1(Common): + attr = 1 + + def meth(self): + pass + + +class CB2(Common): + + attr = (x, y) + + def meth(self): + return 0 + + +class Conflict(CB1, CB2): + pass + +class Override1(Common): + + def ok2(self): + return 1 + +class Override2(Common): + + def ok2(self): + return 2 + +class OK1(Override1, Override2): + + def ok2(self): + return 3 + + +class Override3(Override2): + pass + +class OK2(Override1, Override3): + + def ok2(self): + return 4 + diff --git a/python/ql/test/query-tests/Classes/descriptors/MutatingDescriptor.expected b/python/ql/test/query-tests/Classes/descriptors/MutatingDescriptor.expected new file mode 100644 index 00000000000..ae4d733f7ad --- /dev/null +++ b/python/ql/test/query-tests/Classes/descriptors/MutatingDescriptor.expected @@ -0,0 +1 @@ +| test.py:10:9:10:19 | Attribute | Mutation of descriptor $@ object may lead to action-at-a-distance effects or race conditions for properties. | test.py:3:1:3:33 | class MutatingDescriptor | MutatingDescriptor | diff --git a/python/ql/test/query-tests/Classes/descriptors/MutatingDescriptor.qlref b/python/ql/test/query-tests/Classes/descriptors/MutatingDescriptor.qlref new file mode 100644 index 00000000000..08449405ad6 --- /dev/null +++ b/python/ql/test/query-tests/Classes/descriptors/MutatingDescriptor.qlref @@ -0,0 +1 @@ +Classes/MutatingDescriptor.ql diff --git a/python/ql/test/query-tests/Classes/descriptors/test.py b/python/ql/test/query-tests/Classes/descriptors/test.py new file mode 100644 index 00000000000..ba8da34839e --- /dev/null +++ b/python/ql/test/query-tests/Classes/descriptors/test.py @@ -0,0 +1,14 @@ + +#This is prone to strange side effects and race conditions. +class MutatingDescriptor(object): + + def __init__(self, func): + self.my_func = func + + def __get__(self, obj, obj_type): + #Modified state is visible to all instances of C that might call "show". + self.my_obj = obj + return self + + def __call__(self, *args): + return self.my_func(self.my_obj, *args) \ No newline at end of file diff --git a/python/ql/test/query-tests/Classes/equals-attr/DefineEqualsWhenAddingAttributes.expected b/python/ql/test/query-tests/Classes/equals-attr/DefineEqualsWhenAddingAttributes.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/query-tests/Classes/equals-attr/DefineEqualsWhenAddingAttributes.qlref b/python/ql/test/query-tests/Classes/equals-attr/DefineEqualsWhenAddingAttributes.qlref new file mode 100644 index 00000000000..e542a6176ad --- /dev/null +++ b/python/ql/test/query-tests/Classes/equals-attr/DefineEqualsWhenAddingAttributes.qlref @@ -0,0 +1 @@ +Classes/DefineEqualsWhenAddingAttributes.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Classes/equals-attr/test.py b/python/ql/test/query-tests/Classes/equals-attr/test.py new file mode 100644 index 00000000000..148459d0871 --- /dev/null +++ b/python/ql/test/query-tests/Classes/equals-attr/test.py @@ -0,0 +1,16 @@ + +class GenericEquality(object): + + def __eq__(self, other): + if type(other) is not type(self): + return False + for attr in self.__dict__: + if getattr(other, attr) != getattr(self, attr): + return False + return True + + +class AddAttributes(GenericEquality): + + def __init__(self, args): + self.a, self.b = args diff --git a/python/ql/test/query-tests/Classes/equals-hash/DefineEqualsWhenAddingFields.expected b/python/ql/test/query-tests/Classes/equals-hash/DefineEqualsWhenAddingFields.expected new file mode 100644 index 00000000000..dcdb8992b18 --- /dev/null +++ b/python/ql/test/query-tests/Classes/equals-hash/DefineEqualsWhenAddingFields.expected @@ -0,0 +1 @@ +| attr_eq_test.py:21:1:21:27 | class BadColorPoint | The class 'BadColorPoint' does not override $@, but adds the new attribute $@. | attr_eq_test.py:10:5:10:28 | Function __eq__ | '__eq__' | attr_eq_test.py:25:9:25:19 | Attribute | _color | diff --git a/python/ql/test/query-tests/Classes/equals-hash/DefineEqualsWhenAddingFields.qlref b/python/ql/test/query-tests/Classes/equals-hash/DefineEqualsWhenAddingFields.qlref new file mode 100644 index 00000000000..e542a6176ad --- /dev/null +++ b/python/ql/test/query-tests/Classes/equals-hash/DefineEqualsWhenAddingFields.qlref @@ -0,0 +1 @@ +Classes/DefineEqualsWhenAddingAttributes.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Classes/equals-hash/attr_eq_test.py b/python/ql/test/query-tests/Classes/equals-hash/attr_eq_test.py new file mode 100644 index 00000000000..e1e545fe9ef --- /dev/null +++ b/python/ql/test/query-tests/Classes/equals-hash/attr_eq_test.py @@ -0,0 +1,107 @@ +class Point(object): + + def __init__(self, x, y): + self._x = x + self._y = y + + def __repr__(self): + return 'Point(%r, %r)' % (self._x, self._y) + + def __eq__(self, other): + if not isinstance(other, Point): + return False + return self._x == other._x and self._y == other._y + + def __ne__(self, other): + return not self.__eq__(other) + + def __hash__(self): + return hash((self._x, self._y)) + +class BadColorPoint(Point): + + def __init__(self, x, y, color): + Point.__init__(self, x, y) + self._color = color + + def __repr__(self): + return 'ColorPoint(%r, %r)' % (self._x, self._y, self._color) + +class GoodColorPoint(Point): + + def __init__(self, x, y, color): + Point.__init__(self, x, y) + self._color = color + + def __repr__(self): + return 'ColorPoint(%r, %r)' % (self._x, self._y, self._color) + + def __eq__(self, other): + if not isinstance(other, GoodColorPoint): + return False + return Point.__eq__(self, other) and self._color == other._color + + def __ne__(self, other): + return not self.__eq__(other) + + def __hash__(self): + return hash((self._x, self._y, self._color)) + +class GenericPoint(object): + + def __init__(self, x, y): + self._x = x + self._y = y + + def __repr__(self): + return 'Point(%r, %r)' % (self._x, self._y) + + def __eq__(self, other): + return self.__class__ == other.__class__ and self.__dict__ == other.__dict__ + + def __ne__(self, other): + return not self.__eq__(other) + + def __hash__(self): + return hash((self._x, self._y)) + +class GoodGenericColorPoint(GenericPoint): + + def __init__(self, x, y, color): + GenericPoint.__init__(self, x, y) + self._color = color + +class RedefineEq(object): + + def __init__(self, x, y): + self._x = x + self._y = y + + def __eq__(self, other): + return self is other + +class OK1(RedefineEq): + + def __init__(self, x, y, z): + RedefineEq.__init__(self, x, y) + self.z = z + +class OK2(GenericPoint): + + def __init__(self, x, y, color): + GenericPoint.__init__(self, x, y) + self._color = color + + def __eq__(self, other): + return self is other + +class ExpectingAttribute(object): + + def __eq__(self, other): + return self.x == other.x + +class OK3(ExpectingAttribute): + + def __init__(self): + self.x = 4 + diff --git a/python/ql/test/query-tests/Classes/incomplete-ordering/IncompleteOrdering.expected b/python/ql/test/query-tests/Classes/incomplete-ordering/IncompleteOrdering.expected new file mode 100644 index 00000000000..cac33e836a9 --- /dev/null +++ b/python/ql/test/query-tests/Classes/incomplete-ordering/IncompleteOrdering.expected @@ -0,0 +1 @@ +| incomplete_ordering.py:3:1:3:26 | class PartOrdered | Class PartOrdered implements $@, but does not implement __le__ or __gt__ or __ge__. | incomplete_ordering.py:13:5:13:28 | Function __lt__ | __lt__ | diff --git a/python/ql/test/query-tests/Classes/incomplete-ordering/IncompleteOrdering.qlref b/python/ql/test/query-tests/Classes/incomplete-ordering/IncompleteOrdering.qlref new file mode 100644 index 00000000000..3387dad807a --- /dev/null +++ b/python/ql/test/query-tests/Classes/incomplete-ordering/IncompleteOrdering.qlref @@ -0,0 +1 @@ +Classes/IncompleteOrdering.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Classes/incomplete-ordering/incomplete_ordering.py b/python/ql/test/query-tests/Classes/incomplete-ordering/incomplete_ordering.py new file mode 100644 index 00000000000..3c7514d7a83 --- /dev/null +++ b/python/ql/test/query-tests/Classes/incomplete-ordering/incomplete_ordering.py @@ -0,0 +1,18 @@ +#Incomplete ordering + +class PartOrdered(object): + def __eq__(self, other): + return self is other + + def __ne__(self, other): + return self is not other + + def __hash__(self): + return id(self) + + def __lt__(self, other): + return False + +#Don't blame a sub-class for super-class's sins. +class DerivedPartOrdered(PartOrdered): + pass \ No newline at end of file diff --git a/python/ql/test/query-tests/Classes/init-calls-subclass-method/InitCallsSubclassMethod.expected b/python/ql/test/query-tests/Classes/init-calls-subclass-method/InitCallsSubclassMethod.expected new file mode 100644 index 00000000000..d3cde45c1ff --- /dev/null +++ b/python/ql/test/query-tests/Classes/init-calls-subclass-method/InitCallsSubclassMethod.expected @@ -0,0 +1 @@ +| init_calls_subclass.py:7:9:7:24 | Attribute() | Call to self.$@ in __init__ method, which is overridden by $@. | init_calls_subclass.py:10:5:10:26 | Function set_up | set_up | init_calls_subclass.py:19:5:19:26 | Function set_up | method Sub.set_up | diff --git a/python/ql/test/query-tests/Classes/init-calls-subclass-method/InitCallsSubclassMethod.qlref b/python/ql/test/query-tests/Classes/init-calls-subclass-method/InitCallsSubclassMethod.qlref new file mode 100644 index 00000000000..f820a30b11a --- /dev/null +++ b/python/ql/test/query-tests/Classes/init-calls-subclass-method/InitCallsSubclassMethod.qlref @@ -0,0 +1 @@ +Classes/InitCallsSubclassMethod.ql diff --git a/python/ql/test/query-tests/Classes/init-calls-subclass-method/init_calls_subclass.py b/python/ql/test/query-tests/Classes/init-calls-subclass-method/init_calls_subclass.py new file mode 100644 index 00000000000..3248f8d8303 --- /dev/null +++ b/python/ql/test/query-tests/Classes/init-calls-subclass-method/init_calls_subclass.py @@ -0,0 +1,22 @@ +#Superclass __init__ calls subclass method + +class Super(object): + + def __init__(self, arg): + self._state = "Not OK" + self.set_up(arg) + self._state = "OK" + + def set_up(self, arg): + "Do some set up" + +class Sub(Super): + + def __init__(self, arg): + Super.__init__(self, arg) + self.important_state = "OK" + + def set_up(self, arg): + Super.set_up(self, arg) + "Do some more set up" # Dangerous as self._state is "Not OK" and + # self.important_state is uninitialized \ No newline at end of file diff --git a/python/ql/test/query-tests/Classes/missing-del/MissingCallToDel.expected b/python/ql/test/query-tests/Classes/missing-del/MissingCallToDel.expected new file mode 100644 index 00000000000..7f080b1d729 --- /dev/null +++ b/python/ql/test/query-tests/Classes/missing-del/MissingCallToDel.expected @@ -0,0 +1 @@ +| missing_del.py:12:1:12:13 | class X3 | Class X3 may not be cleaned up properly as $@ is not called during deletion. | missing_del.py:9:5:9:22 | Function __del__ | method X2.__del__ | diff --git a/python/ql/test/query-tests/Classes/missing-del/MissingCallToDel.qlref b/python/ql/test/query-tests/Classes/missing-del/MissingCallToDel.qlref new file mode 100644 index 00000000000..8bf1811d0fa --- /dev/null +++ b/python/ql/test/query-tests/Classes/missing-del/MissingCallToDel.qlref @@ -0,0 +1 @@ +Classes/MissingCallToDel.ql diff --git a/python/ql/test/query-tests/Classes/missing-del/missing_del.py b/python/ql/test/query-tests/Classes/missing-del/missing_del.py new file mode 100644 index 00000000000..5d4e30e681d --- /dev/null +++ b/python/ql/test/query-tests/Classes/missing-del/missing_del.py @@ -0,0 +1,15 @@ +#Not calling an __del__ method: +class X1(object): + + def __del__(self): + pass + +class X2(X1): + + def __del__(self): + X1.__del__(self) + +class X3(X2): + + def __del__(self): + X1.__del__(self) diff --git a/python/ql/test/query-tests/Classes/missing-init/MissingCallToInit.expected b/python/ql/test/query-tests/Classes/missing-init/MissingCallToInit.expected new file mode 100644 index 00000000000..6cb92041a63 --- /dev/null +++ b/python/ql/test/query-tests/Classes/missing-init/MissingCallToInit.expected @@ -0,0 +1,3 @@ +| missing_init.py:12:1:12:13 | class B3 | Class B3 may not be initialized properly as $@ is not called from its $@. | missing_init.py:9:5:9:23 | Function __init__ | method B2.__init__ | missing_init.py:14:5:14:23 | Function __init__ | __init__ method | +| missing_init.py:39:1:39:21 | class IUVT | Class IUVT may not be initialized properly as $@ is not called from its $@. | missing_init.py:30:5:30:23 | Function __init__ | method UT.__init__ | missing_init.py:26:5:26:23 | Function __init__ | __init__ method | +| missing_init.py:72:1:72:13 | class AB | Class AB may not be initialized properly as $@ is not called from its $@. | missing_init.py:69:5:69:23 | Function __init__ | method AA.__init__ | missing_init.py:75:5:75:23 | Function __init__ | __init__ method | diff --git a/python/ql/test/query-tests/Classes/missing-init/MissingCallToInit.qlref b/python/ql/test/query-tests/Classes/missing-init/MissingCallToInit.qlref new file mode 100644 index 00000000000..b8635a5f8d9 --- /dev/null +++ b/python/ql/test/query-tests/Classes/missing-init/MissingCallToInit.qlref @@ -0,0 +1 @@ +Classes/MissingCallToInit.ql diff --git a/python/ql/test/query-tests/Classes/missing-init/missing_init.py b/python/ql/test/query-tests/Classes/missing-init/missing_init.py new file mode 100644 index 00000000000..20909805004 --- /dev/null +++ b/python/ql/test/query-tests/Classes/missing-init/missing_init.py @@ -0,0 +1,185 @@ +#Not calling an __init__ method: +class B1(object): + + def __init__(self): + do_something() + +class B2(B1): + + def __init__(self): + B1.__init__(self) + +class B3(B2): + + def __init__(self): + B1.__init__(self) + +#OK if superclass __init__ is builtin as +#builtin classes tend to rely on __new__ +class MyException(Exception): + + def __init__(self): + self.message = "Uninformative" + +#ODASA-4107 +class IUT(object): + def __init__(self): + print("IUT init") + +class UT(object): + def __init__(self): + print("UT init") + +class PU(object): + pass + +class UVT(UT, PU): + pass + +class IUVT(IUT, UVT): + pass + +#False positive observed on LGTM +class M1(object): + def __init__(self): + print("A") + +class M2(object): + pass + +class Mult(M2, M1): + def __init__(self): + super(Mult, self).__init__() # Calls M1.__init__ + +class X: + def __init__(self): + do_something() + +class Y(X): + @decorated + def __init__(self): + X.__init__(self) + +class Z(Y): + def __init__(self): + Y.__init__(self) + +class AA(object): + + def __init__(self): + do_something() + +class AB(AA): + + #Don't call super class init + def __init__(self): + do_something() + +class AC(AB): + + def __init__(self): + #Missing call to AA.__init__ but not AC's fault. + super(AC, self).__init__() + +import six +import abc + +class BA(object): + + def __init__(self): + do_something() + +@six.add_metaclass(abc.ABCMeta) +class BB(BA): + + def __init__(self): + super(BB,self).__init__() + + +@six.add_metaclass(abc.ABCMeta) +class CA(object): + + def __init__(self): + do_something() + +class CB(BA): + + def __init__(self): + super(CB,self).__init__() + +#ODASA-5799 +class DA(object): + + def __init__(self): + do_something() + +class DB(DA): + + class DC(DA): + + def __init__(self): + sup = super(DB.DC, self) + sup.__init__() + +#Simpler variants +class DD(DA): + + def __init__(self): + sup = super(DD, self) + sup.__init__() + +class DE(DA): + + class DF(DA): + + def __init__(self): + sup = super(DE.DF, self).__init__() + +class FA(object): + + def __init__(self): + pass + +class FB(object): + + def __init__(self): + do_something() + +class FC(FA, FB): + + def __init__(self): + #OK to skip call to FA.__init__ as that does nothing. + FB.__init__(self) + +#Potential false positives. + +class ConfusingInit(B1): + + def __init__(self): + super_call = super(ConfusingInit, self).__init__ + super_call() + + +# Library class +import collections + +class G1(collections.Counter): + + def __init__(self): + collections.Counter.__init__(self) + +class G2(G1): + + def __init__(self): + super(G2, self).__init__() + +class G3(collections.Counter): + + def __init__(self): + super(G3, self).__init__() + +class G4(G3): + + def __init__(self): + G3.__init__(self) + diff --git a/python/ql/test/query-tests/Classes/multiple/SuperclassDelCalledMultipleTimes.expected b/python/ql/test/query-tests/Classes/multiple/SuperclassDelCalledMultipleTimes.expected new file mode 100644 index 00000000000..210f24c7525 --- /dev/null +++ b/python/ql/test/query-tests/Classes/multiple/SuperclassDelCalledMultipleTimes.expected @@ -0,0 +1,2 @@ +| multiple_del.py:17:1:17:17 | class Y3 | Class Y3 may not be cleaned up properly as $@ may be called multiple times during destruction. | multiple_del.py:9:5:9:22 | Function __del__ | method Y1.__del__ | +| multiple_del.py:34:1:34:17 | class Z3 | Class Z3 may not be cleaned up properly as $@ may be called multiple times during destruction. | multiple_del.py:26:5:26:22 | Function __del__ | method Z1.__del__ | diff --git a/python/ql/test/query-tests/Classes/multiple/SuperclassDelCalledMultipleTimes.qlref b/python/ql/test/query-tests/Classes/multiple/SuperclassDelCalledMultipleTimes.qlref new file mode 100644 index 00000000000..560d7b7dc41 --- /dev/null +++ b/python/ql/test/query-tests/Classes/multiple/SuperclassDelCalledMultipleTimes.qlref @@ -0,0 +1 @@ +Classes/SuperclassDelCalledMultipleTimes.ql diff --git a/python/ql/test/query-tests/Classes/multiple/SuperclassInitCalledMultipleTimes.expected b/python/ql/test/query-tests/Classes/multiple/SuperclassInitCalledMultipleTimes.expected new file mode 100644 index 00000000000..04ce8c0f373 --- /dev/null +++ b/python/ql/test/query-tests/Classes/multiple/SuperclassInitCalledMultipleTimes.expected @@ -0,0 +1,2 @@ +| multiple_init.py:17:1:17:17 | class C3 | Class C3 may not be initialized properly as $@ may be called multiple times during initialization. | multiple_init.py:9:5:9:23 | Function __init__ | method C1.__init__ | +| multiple_init.py:34:1:34:17 | class D3 | Class D3 may not be initialized properly as $@ may be called multiple times during initialization. | multiple_init.py:26:5:26:23 | Function __init__ | method D1.__init__ | diff --git a/python/ql/test/query-tests/Classes/multiple/SuperclassInitCalledMultipleTimes.qlref b/python/ql/test/query-tests/Classes/multiple/SuperclassInitCalledMultipleTimes.qlref new file mode 100644 index 00000000000..042ddb76904 --- /dev/null +++ b/python/ql/test/query-tests/Classes/multiple/SuperclassInitCalledMultipleTimes.qlref @@ -0,0 +1 @@ +Classes/SuperclassInitCalledMultipleTimes.ql diff --git a/python/ql/test/query-tests/Classes/multiple/multiple_del.py b/python/ql/test/query-tests/Classes/multiple/multiple_del.py new file mode 100644 index 00000000000..284f6bf6969 --- /dev/null +++ b/python/ql/test/query-tests/Classes/multiple/multiple_del.py @@ -0,0 +1,38 @@ +#Calling a method multiple times by using explicit calls when a base uses super() +class Base(object): + + def __del__(self): + pass + +class Y1(Base): + + def __del__(self): + super(Y1, self).__del__() + +class Y2(Base): + + def __del__(self): + super(Y2, self).__del__() #When `type(self) == Y3` this calls `Y1.__del__` + +class Y3(Y2, Y1): + + def __del__(self): + Y1.__del__(self) + Y2.__del__(self) + +#Calling a method multiple times by using explicit calls when a base inherits from other base +class Z1(object): + + def __del__(self): + pass + +class Z2(Z1): + + def __del__(self): + Z1.__del__(self) + +class Z3(Z2, Z1): + + def __del__(self): + Z1.__del__(self) + Z2.__del__(self) diff --git a/python/ql/test/query-tests/Classes/multiple/multiple_init.py b/python/ql/test/query-tests/Classes/multiple/multiple_init.py new file mode 100644 index 00000000000..6a97ef67f6c --- /dev/null +++ b/python/ql/test/query-tests/Classes/multiple/multiple_init.py @@ -0,0 +1,76 @@ +#Calling a method multiple times by using explicit calls when a base uses super() +class Base(object): + + def __init__(self): + pass + +class C1(Base): + + def __init__(self): + super(C1, self).__init__() + +class C2(Base): + + def __init__(self): + super(C2, self).__init__() #When `type(self) == C3` this calls `C1.__init__` + +class C3(C2, C1): + + def __init__(self): + C1.__init__(self) + C2.__init__(self) + +#Calling a method multiple times by using explicit calls when a base inherits from other base +class D1(object): + + def __init__(self): + pass + +class D2(D1): + + def __init__(self): + D1.__init__(self) + +class D3(D2, D1): + + def __init__(self): + D1.__init__(self) + D2.__init__(self) + +#OK to call object.__init__ multiple times +class E1(object): + + def __init__(self): + super(E1, self).__init__() + +class E2(object): + + def __init__(self): + object.__init__(self) + +class E3(E2, E1): + + def __init__(self): + E1.__init__(self) + E2.__init__(self) + +#Two invocations, but can only be called once +class F1(Base): + + def __init__(self, cond): + if cond: + Base.__init__(self) + else: + Base.__init__(self) + +#Single call, splitting causes what seems to be multiple invocations. +class F2(Base): + + def __init__(self, cond): + if cond: + pass + if cond: + pass + Base.__init__(self) + + diff --git a/python/ql/test/query-tests/Classes/overwriting-attribute/OverwritingAttributeInSuperClass.expected b/python/ql/test/query-tests/Classes/overwriting-attribute/OverwritingAttributeInSuperClass.expected new file mode 100644 index 00000000000..a396d393db1 --- /dev/null +++ b/python/ql/test/query-tests/Classes/overwriting-attribute/OverwritingAttributeInSuperClass.expected @@ -0,0 +1,2 @@ +| overwriting_attribute.py:5:9:5:20 | AssignStmt | Assignment overwrites attribute var, which was previously defined in subclass $@. | overwriting_attribute.py:10:9:10:20 | AssignStmt | D | +| overwriting_attribute.py:23:9:23:20 | AssignStmt | Assignment overwrites attribute var, which was previously defined in superclass $@. | overwriting_attribute.py:17:9:17:20 | AssignStmt | E | diff --git a/python/ql/test/query-tests/Classes/overwriting-attribute/OverwritingAttributeInSuperClass.qlref b/python/ql/test/query-tests/Classes/overwriting-attribute/OverwritingAttributeInSuperClass.qlref new file mode 100644 index 00000000000..b29c4d25025 --- /dev/null +++ b/python/ql/test/query-tests/Classes/overwriting-attribute/OverwritingAttributeInSuperClass.qlref @@ -0,0 +1 @@ +Classes/OverwritingAttributeInSuperClass.ql diff --git a/python/ql/test/query-tests/Classes/overwriting-attribute/overwriting_attribute.py b/python/ql/test/query-tests/Classes/overwriting-attribute/overwriting_attribute.py new file mode 100644 index 00000000000..0372db0b215 --- /dev/null +++ b/python/ql/test/query-tests/Classes/overwriting-attribute/overwriting_attribute.py @@ -0,0 +1,23 @@ +#Attribute set in both superclass and subclass +class C(object): + + def __init__(self): + self.var = 0 + +class D(C): + + def __init__(self): + self.var = 1 # self.var will be overwritten + C.__init__(self) + +#Attribute set in both superclass and subclass +class E(object): + + def __init__(self): + self.var = 0 # self.var will be overwritten + +class F(E): + + def __init__(self): + E.__init__(self) + self.var = 1 diff --git a/python/ql/test/query-tests/Classes/should-be-context-manager/ShouldBeContextManager.expected b/python/ql/test/query-tests/Classes/should-be-context-manager/ShouldBeContextManager.expected new file mode 100644 index 00000000000..47c773804ae --- /dev/null +++ b/python/ql/test/query-tests/Classes/should-be-context-manager/ShouldBeContextManager.expected @@ -0,0 +1,2 @@ +| should_be_context_manager.py:3:1:3:22 | class MegaDel | Class MegaDel implements __del__ (presumably to release some resource). Consider making it a context manager. | +| should_be_context_manager.py:16:1:16:22 | class MiniDel | Class MiniDel implements __del__ (presumably to release some resource). Consider making it a context manager. | diff --git a/python/ql/test/query-tests/Classes/should-be-context-manager/ShouldBeContextManager.qlref b/python/ql/test/query-tests/Classes/should-be-context-manager/ShouldBeContextManager.qlref new file mode 100644 index 00000000000..f555b0af07a --- /dev/null +++ b/python/ql/test/query-tests/Classes/should-be-context-manager/ShouldBeContextManager.qlref @@ -0,0 +1 @@ +Classes/ShouldBeContextManager.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Classes/should-be-context-manager/should_be_context_manager.py b/python/ql/test/query-tests/Classes/should-be-context-manager/should_be_context_manager.py new file mode 100644 index 00000000000..68fc81206a3 --- /dev/null +++ b/python/ql/test/query-tests/Classes/should-be-context-manager/should_be_context_manager.py @@ -0,0 +1,22 @@ +#Should be context manager + +class MegaDel(object): + + def __del__(self): + a = self.x + self.y + if a: + print(a) + if sys._getframe().f_lineno > 100: + print("Hello") + sum = 0 + for a in range(100): + sum += a + print(sum) + +class MiniDel(object): + + def close(self): + pass + + def __del__(self): + self.close() \ No newline at end of file diff --git a/python/ql/test/query-tests/Classes/subclass-shadowing/SubclassShadowing.expected b/python/ql/test/query-tests/Classes/subclass-shadowing/SubclassShadowing.expected new file mode 100644 index 00000000000..ae922ef5264 --- /dev/null +++ b/python/ql/test/query-tests/Classes/subclass-shadowing/SubclassShadowing.expected @@ -0,0 +1 @@ +| subclass_shadowing.py:10:5:10:21 | FunctionExpr | Method shadow is shadowed by $@ in super class 'Base'. | subclass_shadowing.py:6:9:6:23 | AssignStmt | an attribute | diff --git a/python/ql/test/query-tests/Classes/subclass-shadowing/SubclassShadowing.qlref b/python/ql/test/query-tests/Classes/subclass-shadowing/SubclassShadowing.qlref new file mode 100644 index 00000000000..5fed3f9f8fc --- /dev/null +++ b/python/ql/test/query-tests/Classes/subclass-shadowing/SubclassShadowing.qlref @@ -0,0 +1 @@ +Classes/SubclassShadowing.ql diff --git a/python/ql/test/query-tests/Classes/subclass-shadowing/subclass_shadowing.py b/python/ql/test/query-tests/Classes/subclass-shadowing/subclass_shadowing.py new file mode 100644 index 00000000000..98e7f992e84 --- /dev/null +++ b/python/ql/test/query-tests/Classes/subclass-shadowing/subclass_shadowing.py @@ -0,0 +1,30 @@ +#Subclass shadowing + +class Base(object): + + def __init__(self): + self.shadow = 4 + +class Derived(Base): + + def shadow(self): + pass + + +#OK if the super class defines the method as well. +#Since the original method must exist for some reason. +#See JSONEncoder.default for real example + +class Base2(object): + + def __init__(self, shadowy=None): + if shadowy: + self.shadow = shadowy + + def shadow(self): + pass + +class Derived2(Base2): + + def shadow(self): + return 0 diff --git a/python/ql/test/query-tests/Classes/undefined-attribute/MaybeUndefinedClassAttribute.expected b/python/ql/test/query-tests/Classes/undefined-attribute/MaybeUndefinedClassAttribute.expected new file mode 100644 index 00000000000..1aebf13f2bc --- /dev/null +++ b/python/ql/test/query-tests/Classes/undefined-attribute/MaybeUndefinedClassAttribute.expected @@ -0,0 +1,4 @@ +| undefined_attribute.py:27:16:27:29 | Attribute | Attribute 'may_exist' is not defined in the class body nor in the __init__() method, but it is defined $@ | undefined_attribute.py:11:9:11:22 | Attribute | here | +| undefined_attribute.py:184:16:184:32 | Attribute | Attribute 'return_queue' is not defined in the class body nor in the __init__() method, but it is defined $@ | undefined_attribute.py:181:13:181:29 | Attribute | here | +| undefined_attribute.py:257:16:257:31 | Attribute | Attribute 'glance_host' is not defined in the class body nor in the __init__() method, but it is defined $@ | undefined_attribute.py:262:13:262:28 | Attribute | here | +| undefined_attribute.py:258:16:258:31 | Attribute | Attribute 'glance_port' is not defined in the class body nor in the __init__() method, but it is defined $@ | undefined_attribute.py:263:10:263:25 | Attribute | here | diff --git a/python/ql/test/query-tests/Classes/undefined-attribute/MaybeUndefinedClassAttribute.qlref b/python/ql/test/query-tests/Classes/undefined-attribute/MaybeUndefinedClassAttribute.qlref new file mode 100644 index 00000000000..d4986ffc84c --- /dev/null +++ b/python/ql/test/query-tests/Classes/undefined-attribute/MaybeUndefinedClassAttribute.qlref @@ -0,0 +1 @@ +Classes/MaybeUndefinedClassAttribute.ql diff --git a/python/ql/test/query-tests/Classes/undefined-attribute/UndefinedClassAttribute.expected b/python/ql/test/query-tests/Classes/undefined-attribute/UndefinedClassAttribute.expected new file mode 100644 index 00000000000..deb82710cf5 --- /dev/null +++ b/python/ql/test/query-tests/Classes/undefined-attribute/UndefinedClassAttribute.expected @@ -0,0 +1,4 @@ +| undefined_attribute.py:24:16:24:30 | Attribute | Attribute 'not_exists' is not defined in either the class body or in any method | +| undefined_attribute.py:109:16:109:21 | Attribute | Attribute 'y' is not defined in either the class body or in any method | +| undefined_attribute.py:250:16:250:31 | Attribute | Attribute 'glance_host' is not defined in either the class body or in any method | +| undefined_attribute.py:251:16:251:31 | Attribute | Attribute 'glance_port' is not defined in either the class body or in any method | diff --git a/python/ql/test/query-tests/Classes/undefined-attribute/UndefinedClassAttribute.qlref b/python/ql/test/query-tests/Classes/undefined-attribute/UndefinedClassAttribute.qlref new file mode 100644 index 00000000000..7ac0a3b18b7 --- /dev/null +++ b/python/ql/test/query-tests/Classes/undefined-attribute/UndefinedClassAttribute.qlref @@ -0,0 +1 @@ +Classes/UndefinedClassAttribute.ql diff --git a/python/ql/test/query-tests/Classes/undefined-attribute/undefined_attribute.py b/python/ql/test/query-tests/Classes/undefined-attribute/undefined_attribute.py new file mode 100644 index 00000000000..0eec9974ef1 --- /dev/null +++ b/python/ql/test/query-tests/Classes/undefined-attribute/undefined_attribute.py @@ -0,0 +1,263 @@ +#Non existent class attribute + +class Attributes(object): + + exists1 = 1 + + def __init__(self): + self.exists2 = 2 + + def method(self): + self.may_exist = 3 + + def ok1(self): + print (self.exists1) + + def ok2(self): + print (self.exists2) + + def ok3(self): + self.local_exists = 4 + print (self.local_exists) + + def neca1(self): + print (self.not_exists) + + def neca2(self): + print (self.may_exist) + +#This is OK +class SetViaDict(object): + + def __init__(self, x): + self.__dict__['x'] = x + + def use_x(self): + return self.x + + +#This is also OK +class SetLocally(object): + + def use_x(self): + self.x = 1 + return self.x + + +class UsesSetattr(object): + + def __init__(self, vals): + for k, v in vals.items(): + setattr(self, k, v) + + def use_values(self): + return self.x, self.y, self.z + +#OK +class GuardedByHasAttr(object): + + def ok4(self): + if hasattr(self, "x"): + return self.x + else: + return None + +class HasGetAttr(object): + + def __getattr__(self, name): + return name + + def use_values(self): + return self.x, self.y, self.z + +class HasGetAttribute(object): + + def __getattribute__(self, name): + return name + + def use_values(self): + return self.x, self.y, self.z + + + + + + + + + + + + + + + + +class DecoratedInit(object): + + @decorator + def __init__(self): + self.x = x + + def use(self): + return self.x + +#This is not OK +class NoInit(object): + + def use_y(self): + return self.y + +#This is also OK +class SetLocally2(object): + + def __init__(self): + pass + + def use_y(self): + self.x = 0 + self.y = 1 + if cond: + print(self.y) + else: + return False + return self.y + +#Guarded +class Guarded(object): + + def __init__(self): + self.guard = False + + def set_x(self): + self.guard = True + self.x = 1 + + def use_x(self): + if self.guard: + return self.x + else: + return 0 + +#ODASA-2034 +class ODASA2034A(object): + + def __init__(self, data): + d = self.__dict__ + d['data'] = data + + def use_data(self): + return self.data + +class ODASA2034B(object): + + def __init__(self, key, value): + d = self.__dict__ + d[key] = value + + def use_data(self): + return self.data + + +class Test5(object): + + def readFromStream(stream): + word = stream.read(4) + if word == "true": + return BooleanObject(True) + elif word == "fals": + stream.read(1) + return BooleanObject(False) + assert False + readFromStream = staticmethod(readFromStream) + + +class Test1(object): + + def __init__(self, application): + self.rabbitmq_channel = None + + def queue_declared(frame): # called in callback + self.return_queue = frame.method.queue + + def use_it(self): + return self.return_queue + + +#Check for FPs when overriding builtin methods + +class PrintingDict(dict): + + def pop(self): + print ("pop") + return dict.pop(self) + + def __setitem__(self, key, value): + print("__setitem__") + return dict.__setitem__(self, key, value) + +#Locally set by Call +#ODASA-4612 +class WSGIContext(object): + + def _app_call(self, env): + self._response_headers = None + + +class Odasa4612(WSGIContext): + + def meth1(self, arg): + val = self._app_call(arg) + if self._response_headers is None: + self._response_headers = [] + + + +class OK9(object): + cls_attr = 0 + def __init__(self): + self.attr = self.cls_attr + + + +class Foo1(object): + pass + +foo = Foo1() +setattr(foo, 'a', 1) +assert foo.a == 1 + +class Foo2(object): + pass + +setattr(Foo2, 'a', 1) +assert Foo2.a == 1 + +# False positive observed at customer + +class Customer1(object): + + def x(self): + if not hasattr(self, "attr"): + return None + else: + return self.attr + +#ODASA-4619 +class Odasa4619a(object): + + def call(self): + host = self.glance_host + port = self.glance_port + + +class Odasa4619b(object): + + def call(self): + host = self.glance_host + port = self.glance_port + + @decorator + def foo(self): + (x, self.glance_host, + self.glance_port, y) = bar() diff --git a/python/ql/test/query-tests/Classes/useless/UselessClass.expected b/python/ql/test/query-tests/Classes/useless/UselessClass.expected new file mode 100644 index 00000000000..f4f62cd80c7 --- /dev/null +++ b/python/ql/test/query-tests/Classes/useless/UselessClass.expected @@ -0,0 +1,2 @@ +| test.py:28:1:28:23 | Class Useless1 | Class Useless1 defines only one public method, which should be replaced by a function. | +| test.py:37:1:37:23 | Class Useless2 | Class Useless2 defines only one public method, which should be replaced by a function. | diff --git a/python/ql/test/query-tests/Classes/useless/UselessClass.qlref b/python/ql/test/query-tests/Classes/useless/UselessClass.qlref new file mode 100644 index 00000000000..9c8e87e962c --- /dev/null +++ b/python/ql/test/query-tests/Classes/useless/UselessClass.qlref @@ -0,0 +1 @@ +Classes/UselessClass.ql diff --git a/python/ql/test/query-tests/Classes/useless/test.py b/python/ql/test/query-tests/Classes/useless/test.py new file mode 100644 index 00000000000..40c9e56e117 --- /dev/null +++ b/python/ql/test/query-tests/Classes/useless/test.py @@ -0,0 +1,65 @@ + +#Useless class + +class Useful1(object): + + def __init__(self): + pass + + def do_something(self): + pass + + def do_something_else(self): + pass + + def do_yet_another_thing(self): + pass + + +class Useful2(object): + + def do_something(self): + pass + + def do_something_else(self): + pass + + +class Useless1(object): + + def __init__(self): + pass + + def do_something(self): + pass + + +class Useless2(object): + + def do_something(self): + pass + +class Stateful1(object): + + def __init__(self): + self.data = [] + + def do_something(self, x): + self.data.append(x) + + +class Stateful2(object): + + def __init__(self): + self.data = None + + def do_something(self, x): + self.data = x + +class Inherited(object): + pass + +class Inherits(Inherited): + + def do_something(self): + pass diff --git a/python/ql/test/query-tests/Exceptions/general/CatchingBaseException.expected b/python/ql/test/query-tests/Exceptions/general/CatchingBaseException.expected new file mode 100644 index 00000000000..8cbb6d9c961 --- /dev/null +++ b/python/ql/test/query-tests/Exceptions/general/CatchingBaseException.expected @@ -0,0 +1,2 @@ +| exceptions_test.py:7:5:7:11 | ExceptStmt | Except block directly handles BaseException. | +| exceptions_test.py:71:5:71:25 | ExceptStmt | Except block directly handles BaseException. | diff --git a/python/ql/test/query-tests/Exceptions/general/CatchingBaseException.qlref b/python/ql/test/query-tests/Exceptions/general/CatchingBaseException.qlref new file mode 100644 index 00000000000..5588dbf2c7b --- /dev/null +++ b/python/ql/test/query-tests/Exceptions/general/CatchingBaseException.qlref @@ -0,0 +1 @@ +Exceptions/CatchingBaseException.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Exceptions/general/EmptyExcept.expected b/python/ql/test/query-tests/Exceptions/general/EmptyExcept.expected new file mode 100755 index 00000000000..57c50449af8 --- /dev/null +++ b/python/ql/test/query-tests/Exceptions/general/EmptyExcept.expected @@ -0,0 +1,2 @@ +| exceptions_test.py:7:5:7:11 | ExceptStmt | 'except' clause does nothing but pass and there is no explanatory comment. | +| exceptions_test.py:13:5:13:21 | ExceptStmt | 'except' clause does nothing but pass and there is no explanatory comment. | diff --git a/python/ql/test/query-tests/Exceptions/general/EmptyExcept.qlref b/python/ql/test/query-tests/Exceptions/general/EmptyExcept.qlref new file mode 100644 index 00000000000..3f4987046b1 --- /dev/null +++ b/python/ql/test/query-tests/Exceptions/general/EmptyExcept.qlref @@ -0,0 +1 @@ +Exceptions/EmptyExcept.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Exceptions/general/IllegalExceptionHandlerType.expected b/python/ql/test/query-tests/Exceptions/general/IllegalExceptionHandlerType.expected new file mode 100644 index 00000000000..0864dd0fe30 --- /dev/null +++ b/python/ql/test/query-tests/Exceptions/general/IllegalExceptionHandlerType.expected @@ -0,0 +1,4 @@ +| exceptions_test.py:51:5:51:25 | ExceptStmt | Non-exception $@ in exception handler which will never match raised exception. | exceptions_test.py:33:1:33:28 | ControlFlowNode for ClassExpr | class 'NotException1' | +| exceptions_test.py:54:5:54:25 | ExceptStmt | Non-exception $@ in exception handler which will never match raised exception. | exceptions_test.py:36:1:36:28 | ControlFlowNode for ClassExpr | class 'NotException2' | +| exceptions_test.py:112:5:112:22 | ExceptStmt | Non-exception $@ in exception handler which will never match raised exception. | exceptions_test.py:107:12:107:14 | ControlFlowNode for FloatLiteral | instance of 'float' | +| pypy_test.py:14:5:14:14 | ExceptStmt | Non-exception $@ in exception handler which will never match raised exception. | pypy_test.py:14:12:14:13 | ControlFlowNode for IntegerLiteral | instance of 'int' | diff --git a/python/ql/test/query-tests/Exceptions/general/IllegalExceptionHandlerType.qlref b/python/ql/test/query-tests/Exceptions/general/IllegalExceptionHandlerType.qlref new file mode 100644 index 00000000000..6d49710a759 --- /dev/null +++ b/python/ql/test/query-tests/Exceptions/general/IllegalExceptionHandlerType.qlref @@ -0,0 +1 @@ +Exceptions/IllegalExceptionHandlerType.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Exceptions/general/IllegalRaise.expected b/python/ql/test/query-tests/Exceptions/general/IllegalRaise.expected new file mode 100644 index 00000000000..2625bb14a96 --- /dev/null +++ b/python/ql/test/query-tests/Exceptions/general/IllegalRaise.expected @@ -0,0 +1,3 @@ +| exceptions_test.py:40:5:40:23 | Raise | Illegal class 'NotException1' raised; will result in a TypeError being raised instead. | +| exceptions_test.py:43:5:43:21 | Raise | Illegal class 'str' raised; will result in a TypeError being raised instead. | +| exceptions_test.py:46:5:46:25 | Raise | Illegal class 'NotException2' raised; will result in a TypeError being raised instead. | diff --git a/python/ql/test/query-tests/Exceptions/general/IllegalRaise.qlref b/python/ql/test/query-tests/Exceptions/general/IllegalRaise.qlref new file mode 100644 index 00000000000..5a515d5656d --- /dev/null +++ b/python/ql/test/query-tests/Exceptions/general/IllegalRaise.qlref @@ -0,0 +1 @@ +Exceptions/IllegalRaise.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Exceptions/general/IncorrectExceptOrder.expected b/python/ql/test/query-tests/Exceptions/general/IncorrectExceptOrder.expected new file mode 100644 index 00000000000..21494493acb --- /dev/null +++ b/python/ql/test/query-tests/Exceptions/general/IncorrectExceptOrder.expected @@ -0,0 +1 @@ +| exceptions_test.py:64:1:64:22 | ExceptStmt | Except block for $@ is unreachable; the more general $@ for $@ will always be executed in preference. | file://:Compiled Code:0:0:0:0 | builtin-class AttributeError | AttributeError | exceptions_test.py:62:1:62:17 | ExceptStmt | except block | file://:Compiled Code:0:0:0:0 | builtin-class Exception | Exception | diff --git a/python/ql/test/query-tests/Exceptions/general/IncorrectExceptOrder.qlref b/python/ql/test/query-tests/Exceptions/general/IncorrectExceptOrder.qlref new file mode 100644 index 00000000000..bc4c3a07081 --- /dev/null +++ b/python/ql/test/query-tests/Exceptions/general/IncorrectExceptOrder.qlref @@ -0,0 +1 @@ +Exceptions/IncorrectExceptOrder.ql diff --git a/python/ql/test/query-tests/Exceptions/general/NotImplementedIsNotAnException.expected b/python/ql/test/query-tests/Exceptions/general/NotImplementedIsNotAnException.expected new file mode 100644 index 00000000000..c9fa73e7c12 --- /dev/null +++ b/python/ql/test/query-tests/Exceptions/general/NotImplementedIsNotAnException.expected @@ -0,0 +1,2 @@ +| exceptions_test.py:170:11:170:24 | NotImplemented | NotImplemented is not an Exception. Did you mean NotImplementedError? | +| exceptions_test.py:173:11:173:24 | NotImplemented | NotImplemented is not an Exception. Did you mean NotImplementedError? | diff --git a/python/ql/test/query-tests/Exceptions/general/NotImplementedIsNotAnException.qlref b/python/ql/test/query-tests/Exceptions/general/NotImplementedIsNotAnException.qlref new file mode 100644 index 00000000000..61ac527ffb9 --- /dev/null +++ b/python/ql/test/query-tests/Exceptions/general/NotImplementedIsNotAnException.qlref @@ -0,0 +1 @@ +Exceptions/NotImplementedIsNotAnException.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Exceptions/general/exceptions_test.py b/python/ql/test/query-tests/Exceptions/general/exceptions_test.py new file mode 100644 index 00000000000..d3f782f874f --- /dev/null +++ b/python/ql/test/query-tests/Exceptions/general/exceptions_test.py @@ -0,0 +1,173 @@ + +#Empty Except + +def ee1(val): + try: + val.attr + except: + pass + +def ee1(val): + try: + val.attr() + except TypeError: + pass + +def ee2(val): + try: + val.attr + except Error: + #But it is OK if there is a comment + pass + +#OK with an else clause as well... + +def ee3(val): + try: + val.attr + except Error: + pass + else: + return 42 + +class NotException1(object): + pass + +class NotException2(object): + pass + +def illegal_raise_type(): + raise NotException1 + +def illegal_raise_value1(): + raise "Exception" + +def illegal_raise_value2(): + raise NotException2() + +def illegal_handler(): + try: + illegal_raise() + except NotException1: + #Must do something + print("NotException1") + except NotException2: + #Must do something + print("NotException2") + + +#Incorrect except order +try: + val.attr +except Exception: + print (2) +except AttributeError: + print (3) + +#Catch BaseException +def catch_base_exception(): + try: + illegal_raise() + except BaseException: + #Consumes KeyboardInterrupt + pass + +def catch_base_exception_ok(): + try: + illegal_raise() + except BaseException: + raise + +def legal_handler1(): + try: + illegal_raise() + except (IOError, KeyError): + print ("Caught exception") + +pair = IOError, KeyError +triple = pair, AttributeError + +def legal_handler2(): + try: + illegal_raise() + except pair: + print ("Caught exception") + try: + illegal_raise() + except triple: + print ("Caught exception") + +def legal_handler3(): + try: + illegal_raise() + except could_be_anything(): + print ("Caught exception") + +def a_number(): + return 4.0 + +def illegal_handler2(): + try: + illegal_raise() + except a_number(): + print ("Caught exception") + +def stop_iter_ok(seq): + try: + next(seq) + except StopIteration: + pass + +#Guarded None in nested function +def f(x=None): + def inner(arg): + if x: + raise x + +#ODASA-4705 +def g(cond): + try: + if cond: + return may_raise_io_error() + else: + raise KeyError + except IOError: + pass # This is OK, as it is just passing to the following statement which handles the exception. + return 0 + +def ee4(x): + try: + del x.attr + except AttributeError: + pass + +def ee5(x): + try: + x[0] + except IndexError: + pass + +def ee6(x): + try: + del x[0] + except IndexError: + pass + +def ee7(x): + try: + delattr(x, "attr") + except AttributeError: + pass + +def ee8(x): + try: + x.encode("martian-18") + except UnicodeEncodeError: + pass + + #These are so common, we give warnings not errors. +def foo(): + raise NotImplemented + +def bar(): + raise NotImplemented() diff --git a/python/ql/test/query-tests/Exceptions/general/pypy_test.py b/python/ql/test/query-tests/Exceptions/general/pypy_test.py new file mode 100644 index 00000000000..857e78d6d94 --- /dev/null +++ b/python/ql/test/query-tests/Exceptions/general/pypy_test.py @@ -0,0 +1,20 @@ + +def test(): + class A(BaseException): + class __metaclass__(type): + def __getattribute__(self, name): + if flag and name == '__bases__': + fail("someone read bases attr") + else: + return type.__getattribute__(self, name) + + try: + a = A() + raise a + except 42: + #Some comment + pass + except A: + #Another comment + pass + diff --git a/python/ql/test/query-tests/Exceptions/generators/UnguardedNextInGenerator.expected b/python/ql/test/query-tests/Exceptions/generators/UnguardedNextInGenerator.expected new file mode 100644 index 00000000000..289b8fb5a0d --- /dev/null +++ b/python/ql/test/query-tests/Exceptions/generators/UnguardedNextInGenerator.expected @@ -0,0 +1,2 @@ +| test.py:5:15:5:22 | ControlFlowNode for next() | Call to next() in a generator | +| test.py:10:20:10:27 | ControlFlowNode for next() | Call to next() in a generator | diff --git a/python/ql/test/query-tests/Exceptions/generators/UnguardedNextInGenerator.qlref b/python/ql/test/query-tests/Exceptions/generators/UnguardedNextInGenerator.qlref new file mode 100644 index 00000000000..7fe5d609705 --- /dev/null +++ b/python/ql/test/query-tests/Exceptions/generators/UnguardedNextInGenerator.qlref @@ -0,0 +1 @@ +Exceptions/UnguardedNextInGenerator.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Exceptions/generators/test.py b/python/ql/test/query-tests/Exceptions/generators/test.py new file mode 100644 index 00000000000..e8fe159a559 --- /dev/null +++ b/python/ql/test/query-tests/Exceptions/generators/test.py @@ -0,0 +1,49 @@ +#Unguarded calls to next() + +def bad1(it): + while True: + yield next(it) + +def bad2(seq): + it = iter(seq) + #Not OK as seq may be empty + raise KeyError(next(it)) + yield 0 + +def ok1(seq): + #Not a generator + it = iter(seq) + #Not OK as seq may be empty + raise KeyError(next(it)) + +def ok2(seq): + if seq: + it = iter(seq) + #OK seq is non-empty so next(it) will not raise StopIteration + raise KeyError(next(it)) + yield 0 + +def explicit_raise_stop_iter(seq): + for i in seq: + yield seq + raise StopIteration() + +def ok3(seq): + it = iter(seq) + try: + yield next(iter) + except StopIteration: + return + +def ok4(seq, ctx): + try: + with ctx: + yield next(iter) + except StopIteration: + return + +#ODASA-6536 +def next_in_comp(seq, fields): + seq_iter = iter(seq) + values = [ next(seq_iter) if f.attname in NAMES else DEFAULT for f in fields ] + return values diff --git a/python/ql/test/query-tests/Expressions/Arguments/WrongNameForArgumentInCall.expected b/python/ql/test/query-tests/Expressions/Arguments/WrongNameForArgumentInCall.expected new file mode 100644 index 00000000000..dc88cf8496e --- /dev/null +++ b/python/ql/test/query-tests/Expressions/Arguments/WrongNameForArgumentInCall.expected @@ -0,0 +1,5 @@ +| wrong_arguments.py:57:1:57:7 | f0() | Keyword argument 'y' is not a supported parameter name of $@. | wrong_arguments.py:3:1:3:10 | Function f0 | function f0 | +| wrong_arguments.py:58:1:58:7 | f1() | Keyword argument 'z' is not a supported parameter name of $@. | wrong_arguments.py:6:1:6:20 | Function f1 | function f1 | +| wrong_arguments.py:59:1:59:12 | f2() | Keyword argument 'y' is not a supported parameter name of $@. | wrong_arguments.py:9:1:9:14 | Function f2 | function f2 | +| wrong_arguments.py:103:1:103:27 | f6() | Keyword argument 'z' is not a supported parameter name of $@. | wrong_arguments.py:21:1:21:13 | Function f6 | function f6 | +| wrong_arguments.py:115:1:115:13 | f1() | Keyword argument 'z' is not a supported parameter name of $@. | wrong_arguments.py:6:1:6:20 | Function f1 | function f1 | diff --git a/python/ql/test/query-tests/Expressions/Arguments/WrongNameForArgumentInCall.qlref b/python/ql/test/query-tests/Expressions/Arguments/WrongNameForArgumentInCall.qlref new file mode 100644 index 00000000000..3599f204f55 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/Arguments/WrongNameForArgumentInCall.qlref @@ -0,0 +1 @@ +Expressions/WrongNameForArgumentInCall.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Expressions/Arguments/WrongNumberArgumentsInCall.expected b/python/ql/test/query-tests/Expressions/Arguments/WrongNumberArgumentsInCall.expected new file mode 100644 index 00000000000..c23418acd45 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/Arguments/WrongNumberArgumentsInCall.expected @@ -0,0 +1,25 @@ +| use_mox.py:28:1:28:4 | f0() | Call to $@ with too few arguments; should be no fewer than 1. | use_mox.py:7:1:7:10 | Function f0 | function f0 | +| use_mox.py:29:1:29:5 | f1() | Call to $@ with too few arguments; should be no fewer than 2. | use_mox.py:10:1:10:13 | Function f1 | function f1 | +| use_mox.py:32:1:32:8 | Attribute() | Call to $@ with too few arguments; should be no fewer than 1. | use_mox.py:15:5:15:20 | Function m0 | method C.m0 | +| use_mox.py:33:1:33:9 | Attribute() | Call to $@ with too few arguments; should be no fewer than 2. | use_mox.py:18:5:18:23 | Function m1 | method C.m1 | +| wrong_arguments.py:29:1:29:4 | f0() | Call to $@ with too few arguments; should be no fewer than 1. | wrong_arguments.py:3:1:3:10 | Function f0 | function f0 | +| wrong_arguments.py:30:1:30:4 | f1() | Call to $@ with too few arguments; should be no fewer than 1. | wrong_arguments.py:6:1:6:20 | Function f1 | function f1 | +| wrong_arguments.py:31:1:31:4 | f2() | Call to $@ with too few arguments; should be no fewer than 1. | wrong_arguments.py:9:1:9:14 | Function f2 | function f2 | +| wrong_arguments.py:32:1:32:4 | f3() | Call to $@ with too few arguments; should be no fewer than 1. | wrong_arguments.py:12:1:12:24 | Function f3 | function f3 | +| wrong_arguments.py:33:1:33:4 | f4() | Call to $@ with too few arguments; should be no fewer than 1. | wrong_arguments.py:15:1:15:15 | Function f4 | function f4 | +| wrong_arguments.py:34:1:34:4 | f5() | Call to $@ with too few arguments; should be no fewer than 1. | wrong_arguments.py:18:1:18:25 | Function f5 | function f5 | +| wrong_arguments.py:35:1:35:5 | f6() | Call to $@ with too few arguments; should be no fewer than 2. | wrong_arguments.py:21:1:21:13 | Function f6 | function f6 | +| wrong_arguments.py:36:1:36:7 | f7() | Call to $@ with too few arguments; should be no fewer than 3. | wrong_arguments.py:24:1:24:16 | Function f7 | function f7 | +| wrong_arguments.py:40:1:40:7 | f0() | Call to $@ with too many arguments; should be no more than 1. | wrong_arguments.py:3:1:3:10 | Function f0 | function f0 | +| wrong_arguments.py:41:1:41:9 | f1() | Call to $@ with too many arguments; should be no more than 2. | wrong_arguments.py:6:1:6:20 | Function f1 | function f1 | +| wrong_arguments.py:42:1:42:9 | f5() | Call to $@ with too many arguments; should be no more than 2. | wrong_arguments.py:18:1:18:25 | Function f5 | function f5 | +| wrong_arguments.py:43:1:43:9 | f6() | Call to $@ with too many arguments; should be no more than 2. | wrong_arguments.py:21:1:21:13 | Function f6 | function f6 | +| wrong_arguments.py:44:1:44:11 | f6() | Call to $@ with too many arguments; should be no more than 2. | wrong_arguments.py:21:1:21:13 | Function f6 | function f6 | +| wrong_arguments.py:81:1:81:5 | l0() | Call to $@ with too many arguments; should be no more than 0. | wrong_arguments.py:70:6:70:15 | Function lambda | function lambda | +| wrong_arguments.py:82:1:82:7 | l1() | Call to $@ with too many arguments; should be no more than 1. | wrong_arguments.py:71:6:71:21 | Function lambda | function lambda | +| wrong_arguments.py:83:1:83:8 | l1d() | Call to $@ with too many arguments; should be no more than 1. | wrong_arguments.py:72:7:72:25 | Function lambda | function lambda | +| wrong_arguments.py:86:1:86:4 | l1() | Call to $@ with too few arguments; should be no fewer than 1. | wrong_arguments.py:71:6:71:21 | Function lambda | function lambda | +| wrong_arguments.py:96:1:96:12 | f6() | Call to $@ with too many arguments; should be no more than 2. | wrong_arguments.py:21:1:21:13 | Function f6 | function f6 | +| wrong_arguments.py:97:1:97:7 | f6() | Call to $@ with too many arguments; should be no more than 2. | wrong_arguments.py:21:1:21:13 | Function f6 | function f6 | +| wrong_arguments.py:130:1:130:9 | Attribute() | Call to $@ with too few arguments; should be no fewer than 2. | wrong_arguments.py:126:5:126:31 | Function spam | method Eggs2.spam | +| wrong_arguments.py:130:1:130:9 | Attribute() | Call to $@ with too many arguments; should be no more than 0. | wrong_arguments.py:121:5:121:19 | Function spam | method Eggs1.spam | diff --git a/python/ql/test/query-tests/Expressions/Arguments/WrongNumberArgumentsInCall.qlref b/python/ql/test/query-tests/Expressions/Arguments/WrongNumberArgumentsInCall.qlref new file mode 100644 index 00000000000..1bffe8f1cad --- /dev/null +++ b/python/ql/test/query-tests/Expressions/Arguments/WrongNumberArgumentsInCall.qlref @@ -0,0 +1 @@ +Expressions/WrongNumberArgumentsInCall.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Expressions/Arguments/mox.py b/python/ql/test/query-tests/Expressions/Arguments/mox.py new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/Arguments/mox.py @@ -0,0 +1 @@ + diff --git a/python/ql/test/query-tests/Expressions/Arguments/use_mox.py b/python/ql/test/query-tests/Expressions/Arguments/use_mox.py new file mode 100644 index 00000000000..35d35574895 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/Arguments/use_mox.py @@ -0,0 +1,33 @@ + +import mox + +#Use it +mox + +def f0(x): + pass + +def f1(x, y): + pass + +class C(object): + + def m0(self, x): + pass + + def m1(self, x, y): + pass + +# These are treated as magically OK since we are using mox + +C.m0(1) +C.m1(1,2) + +#But normal functions are treated normally + +f0() +f1(1) + +#As are normal methods +C().m0() +C().m1(1) diff --git a/python/ql/test/query-tests/Expressions/Arguments/wrong_arguments.py b/python/ql/test/query-tests/Expressions/Arguments/wrong_arguments.py new file mode 100644 index 00000000000..284d1d19bc3 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/Arguments/wrong_arguments.py @@ -0,0 +1,131 @@ +#!/usr/bin/env python + +def f0(x): + pass + +def f1(x, y = None): + pass + +def f2(x, *y): + pass + +def f3(x, y = None, *z): + pass + +def f4(x, **y): + pass + +def f5(x, y = None, **z): + pass + +def f6(x, y): + pass + +def f7(x, y, z): + pass + +# Too few arguments + +f0() +f1() +f2() +f3() +f4() +f5() +f6(1) +f7(1,2) + +#Too many arguments + +f0(1,2) +f1(1,2,3) +f5(1,2,3) +f6(1,2,3) +f6(1,2,3,4) + +#OK + +#Not too few +f7(*t) + +#Not too many + +f2(1,2,3,4,5,6) + + +#Illegal name +f0(y=1) +f1(z=1) +f2(x=0, y=1) + + +#Ok name +f0(x=0) +f1(x=0, y=1) +f4(q=4) + +#This is correct, but a bit weird. +f6(**{'x':1, 'y':2}) + +l0 = lambda : 0 +l1 = lambda x : 2 * x +l1d = lambda x = 0 : 2 *x + +#OK +l0() +l1(1) +l1d() +l1d(1) + +#Too many +l0(1) +l1(1,2) +l1d(1,2) + +#Too few +l1() + + +t2 = (1,2) +t3 = (1,2,3) + +#Ok +f(*t2) + +#Too many +f6(*(1,2,3)) +f6(*t3) + +#Ok +f6(**{'x':1, 'y':2}) + +#Illegal name +f6(**{'x':1, 'y':2, 'z':3}) + +#Theoretically -1 arguments required. Don't report +class C(object): + + def f(): + pass + +C().f() + + +#Too many and wrong name -- check only wrong name is flagged. +f1(x, y, z=1) + + +#Overriding and call is wrong. +class Eggs1(object): + + def spam(self): + pass + +class Eggs2(Eggs1): + + def spam(self, arg0, arg1): + pass + +e = Eggs1() if cond else Eggs2() +e.spam(0) + diff --git a/python/ql/test/query-tests/Expressions/Formatting/MixedExplicitImplicitIn3101Format.expected b/python/ql/test/query-tests/Expressions/Formatting/MixedExplicitImplicitIn3101Format.expected new file mode 100644 index 00000000000..d055082fe46 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/Formatting/MixedExplicitImplicitIn3101Format.expected @@ -0,0 +1,2 @@ +| test.py:3:17:3:23 | Str | Formatting string mixes implicitly and explicitly numbered fields. | +| test.py:8:17:8:23 | Str | Formatting string mixes implicitly and explicitly numbered fields. | diff --git a/python/ql/test/query-tests/Expressions/Formatting/MixedExplicitImplicitIn3101Format.qlref b/python/ql/test/query-tests/Expressions/Formatting/MixedExplicitImplicitIn3101Format.qlref new file mode 100644 index 00000000000..3b9a8dc0ccf --- /dev/null +++ b/python/ql/test/query-tests/Expressions/Formatting/MixedExplicitImplicitIn3101Format.qlref @@ -0,0 +1 @@ +Expressions/Formatting/MixedExplicitImplicitIn3101Format.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Expressions/Formatting/UnusedArgumentIn3101Format.expected b/python/ql/test/query-tests/Expressions/Formatting/UnusedArgumentIn3101Format.expected new file mode 100644 index 00000000000..5dc11d99643 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/Formatting/UnusedArgumentIn3101Format.expected @@ -0,0 +1,4 @@ +| test.py:29:1:29:50 | Attribute() | Too many arguments for string format. Format $@ requires only 2, but 3 are provided. | test.py:5:20:5:29 | Str | "{0}, {1}" | +| test.py:30:1:30:51 | format() | Too many arguments for string format. Format $@ requires only 2, but 3 are provided. | test.py:10:20:10:29 | Str | "{0}, {1}" | +| test.py:32:1:32:50 | Attribute() | Too many arguments for string format. Format $@ requires only 2, but 3 are provided. | test.py:6:20:6:27 | Str | "{}, {}" | +| test.py:33:1:33:51 | format() | Too many arguments for string format. Format $@ requires only 2, but 3 are provided. | test.py:11:20:11:27 | Str | "{}, {}" | diff --git a/python/ql/test/query-tests/Expressions/Formatting/UnusedArgumentIn3101Format.qlref b/python/ql/test/query-tests/Expressions/Formatting/UnusedArgumentIn3101Format.qlref new file mode 100644 index 00000000000..b3e654ad052 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/Formatting/UnusedArgumentIn3101Format.qlref @@ -0,0 +1 @@ +Expressions/Formatting/UnusedArgumentIn3101Format.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Expressions/Formatting/UnusedNamedArgumentIn3101Format.expected b/python/ql/test/query-tests/Expressions/Formatting/UnusedNamedArgumentIn3101Format.expected new file mode 100644 index 00000000000..849920f8c07 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/Formatting/UnusedNamedArgumentIn3101Format.expected @@ -0,0 +1,8 @@ +| test.py:17:1:17:44 | Attribute() | Surplus named argument for string format. An argument named 'world' is provided, but it is not required by $@. | test.py:4:17:4:31 | Str | format "{name!r}, {0}" | +| test.py:18:1:18:45 | format() | Surplus named argument for string format. An argument named 'world' is provided, but it is not required by $@. | test.py:9:17:9:31 | Str | format "{name!r}, {0}" | +| test.py:20:1:20:49 | Attribute() | Surplus named argument for string format. An argument named 'world' is provided, but it is not required by $@. | test.py:4:17:4:31 | Str | format "{name!r}, {0}" | +| test.py:21:1:21:50 | format() | Surplus named argument for string format. An argument named 'world' is provided, but it is not required by $@. | test.py:9:17:9:31 | Str | format "{name!r}, {0}" | +| test.py:45:1:45:35 | format() | Surplus named argument for string format. An argument named 'z' is provided, but it is not required by $@. | test.py:37:14:37:18 | Str | any format used. | +| test.py:45:1:45:35 | format() | Surplus named argument for string format. An argument named 'z' is provided, but it is not required by $@. | test.py:39:14:39:18 | Str | any format used. | +| test.py:46:1:46:34 | Attribute() | Surplus named argument for string format. An argument named 'z' is provided, but it is not required by $@. | test.py:37:14:37:18 | Str | any format used. | +| test.py:46:1:46:34 | Attribute() | Surplus named argument for string format. An argument named 'z' is provided, but it is not required by $@. | test.py:39:14:39:18 | Str | any format used. | diff --git a/python/ql/test/query-tests/Expressions/Formatting/UnusedNamedArgumentIn3101Format.qlref b/python/ql/test/query-tests/Expressions/Formatting/UnusedNamedArgumentIn3101Format.qlref new file mode 100644 index 00000000000..6a77d891079 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/Formatting/UnusedNamedArgumentIn3101Format.qlref @@ -0,0 +1 @@ +Expressions/Formatting/UnusedNamedArgumentIn3101Format.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Expressions/Formatting/WrongNameInArgumentsFor3101Format.expected b/python/ql/test/query-tests/Expressions/Formatting/WrongNameInArgumentsFor3101Format.expected new file mode 100644 index 00000000000..4daa9bfa12c --- /dev/null +++ b/python/ql/test/query-tests/Expressions/Formatting/WrongNameInArgumentsFor3101Format.expected @@ -0,0 +1,2 @@ +| test.py:17:1:17:44 | Attribute() | Missing named argument for string format. Format $@ requires 'name', but it is omitted. | test.py:4:17:4:31 | Str | "{name!r}, {0}" | +| test.py:18:1:18:45 | format() | Missing named argument for string format. Format $@ requires 'name', but it is omitted. | test.py:9:17:9:31 | Str | "{name!r}, {0}" | diff --git a/python/ql/test/query-tests/Expressions/Formatting/WrongNameInArgumentsFor3101Format.qlref b/python/ql/test/query-tests/Expressions/Formatting/WrongNameInArgumentsFor3101Format.qlref new file mode 100644 index 00000000000..e0b30887034 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/Formatting/WrongNameInArgumentsFor3101Format.qlref @@ -0,0 +1 @@ +Expressions/Formatting/WrongNameInArgumentsFor3101Format.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Expressions/Formatting/WrongNumberArgumentsFor3101Format.expected b/python/ql/test/query-tests/Expressions/Formatting/WrongNumberArgumentsFor3101Format.expected new file mode 100644 index 00000000000..188ee7c4da1 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/Formatting/WrongNumberArgumentsFor3101Format.expected @@ -0,0 +1,6 @@ +| test.py:20:1:20:49 | Attribute() | Too few arguments for string format. Format $@ requires at least 1, but 0 are provided. | test.py:4:17:4:31 | Str | "{name!r}, {0}" | +| test.py:21:1:21:50 | format() | Too few arguments for string format. Format $@ requires at least 1, but 0 are provided. | test.py:9:17:9:31 | Str | "{name!r}, {0}" | +| test.py:23:1:23:32 | Attribute() | Too few arguments for string format. Format $@ requires at least 2, but 1 is provided. | test.py:5:20:5:29 | Str | "{0}, {1}" | +| test.py:24:1:24:33 | format() | Too few arguments for string format. Format $@ requires at least 2, but 1 is provided. | test.py:10:20:10:29 | Str | "{0}, {1}" | +| test.py:26:1:26:32 | Attribute() | Too few arguments for string format. Format $@ requires at least 2, but 1 is provided. | test.py:6:20:6:27 | Str | "{}, {}" | +| test.py:27:1:27:33 | format() | Too few arguments for string format. Format $@ requires at least 2, but 1 is provided. | test.py:11:20:11:27 | Str | "{}, {}" | diff --git a/python/ql/test/query-tests/Expressions/Formatting/WrongNumberArgumentsFor3101Format.qlref b/python/ql/test/query-tests/Expressions/Formatting/WrongNumberArgumentsFor3101Format.qlref new file mode 100644 index 00000000000..130a6525a90 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/Formatting/WrongNumberArgumentsFor3101Format.qlref @@ -0,0 +1 @@ +Expressions/Formatting/WrongNumberArgumentsFor3101Format.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Expressions/Formatting/test.py b/python/ql/test/query-tests/Expressions/Formatting/test.py new file mode 100755 index 00000000000..e9fd23c8aad --- /dev/null +++ b/python/ql/test/query-tests/Expressions/Formatting/test.py @@ -0,0 +1,108 @@ +from __future__ import unicode_literals + +mixed_format1 = "{}{1}" +named_format1 = "{name!r}, {0}" +explicit_format1 = "{0}, {1}" +implicit_format1 = "{}, {}" + +mixed_format2 = "{}{1}" +named_format2 = "{name!r}, {0}" +explicit_format2 = "{0}, {1}" +implicit_format2 = "{}, {}" + + +mixed_format1.format("Hello", "World") +format(mixed_format2, "Hello", "World") + +named_format1.format("Hello", world="World") +format(named_format2, "Hello", world="World") + +named_format1.format(name="Hello", world="World") +format(named_format2, name="Hello", world="World") + +explicit_format1.format("Hello") +format(explicit_format2, "Hello") + +implicit_format1.format("Hello") +format(implicit_format2, "Hello") + +explicit_format1.format("Hello", "World", "Extra") +format(explicit_format2, "Hello", "World", "Extra") + +implicit_format1.format("Hello", "World", "Extra") +format(implicit_format2, "Hello", "World", "Extra") + +#OK ODASA-3197 +if cond: + x_or_y = "{x}" +else: + x_or_y = "{y}" + +format(x_or_y, x="x", y="y") +x_or_y.format(x="x", y="y") + +#Still fail for multiple formats +format(x_or_y, x="x", y="y", z="z") +x_or_y.format(x="x", y="y", z="z") + +#False positive reported by customer. -- Verify fix. +"{{}}>".format(html_class) + +"{{0}}{0}".format("X") +"{{{}}}".format("X") + +#Crash JDK regex engine -- unless possessive quantifiers are used. +( + "{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{" + "{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{" + "{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{" + "{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{" + "{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{" + "{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{" + "{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{" + "{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{" + "{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{" + "{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{" + "{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{" + "{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{" + "{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{" + "{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{" + "{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{" + "{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{" + "{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{" + "{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{" + "{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{" + "{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{" + "{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{" + "{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{" + "{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{" + "{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{" + "{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{" + "{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{" + "{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{" + "{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{" + "{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{" + "{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{" + "{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{" + "{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{" + "{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{" + "{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{" + "{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{" + "{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{" + "{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{" + "{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{}" +) + +#Make sure nested braces are handled properly: +"ANS_{}=${{{}}}".format(x, xID) + +def foo(msg_width): + stdout.write(u'{}\r{}{:<{}}'.format(1, 2, 3, 4)) + stdout.write(u'{}\r{}{:<{width}}'.format(1, 2, 3, width=msg_width)) + +#Check parsing with punctuation. +"invalid value of type {.__name__}: {}".format(int, 1) + +def varying_format(cond): + fmt = "{}" if cond else "{}, {}" + return fmt.format("hello", "world") diff --git a/python/ql/test/query-tests/Expressions/Regex/BackspaceEscape.expected b/python/ql/test/query-tests/Expressions/Regex/BackspaceEscape.expected new file mode 100644 index 00000000000..1f9bf778bd3 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/Regex/BackspaceEscape.expected @@ -0,0 +1,2 @@ +| test.py:17:12:17:22 | Str | Backspace escape in regular expression at offset 1. | +| test.py:19:12:19:28 | Str | Backspace escape in regular expression at offset 8. | diff --git a/python/ql/test/query-tests/Expressions/Regex/BackspaceEscape.qlref b/python/ql/test/query-tests/Expressions/Regex/BackspaceEscape.qlref new file mode 100644 index 00000000000..2bf85f8a45a --- /dev/null +++ b/python/ql/test/query-tests/Expressions/Regex/BackspaceEscape.qlref @@ -0,0 +1 @@ +Expressions/Regex/BackspaceEscape.ql diff --git a/python/ql/test/query-tests/Expressions/Regex/DuplicateCharacterInSet.expected b/python/ql/test/query-tests/Expressions/Regex/DuplicateCharacterInSet.expected new file mode 100644 index 00000000000..c79c219256c --- /dev/null +++ b/python/ql/test/query-tests/Expressions/Regex/DuplicateCharacterInSet.expected @@ -0,0 +1,3 @@ +| test.py:41:12:41:18 | Str | This regular expression includes duplicate character 'A' in a set of characters. | +| test.py:42:12:42:19 | Str | This regular expression includes duplicate character '0' in a set of characters. | +| test.py:43:12:43:21 | Str | This regular expression includes duplicate character '-' in a set of characters. | diff --git a/python/ql/test/query-tests/Expressions/Regex/DuplicateCharacterInSet.qlref b/python/ql/test/query-tests/Expressions/Regex/DuplicateCharacterInSet.qlref new file mode 100644 index 00000000000..f0fc83c214e --- /dev/null +++ b/python/ql/test/query-tests/Expressions/Regex/DuplicateCharacterInSet.qlref @@ -0,0 +1 @@ +Expressions/Regex/DuplicateCharacterInSet.ql diff --git a/python/ql/test/query-tests/Expressions/Regex/MissingPartSpecialGroup.expected b/python/ql/test/query-tests/Expressions/Regex/MissingPartSpecialGroup.expected new file mode 100644 index 00000000000..e7bbad23899 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/Regex/MissingPartSpecialGroup.expected @@ -0,0 +1,2 @@ +| test.py:22:12:22:29 | Str | Regular expression is missing '?' in named group. | +| test.py:23:12:23:33 | Str | Regular expression is missing '?' in named group. | diff --git a/python/ql/test/query-tests/Expressions/Regex/MissingPartSpecialGroup.qlref b/python/ql/test/query-tests/Expressions/Regex/MissingPartSpecialGroup.qlref new file mode 100644 index 00000000000..faf8f31ad4d --- /dev/null +++ b/python/ql/test/query-tests/Expressions/Regex/MissingPartSpecialGroup.qlref @@ -0,0 +1 @@ +Expressions/Regex/MissingPartSpecialGroup.ql diff --git a/python/ql/test/query-tests/Expressions/Regex/UnmatchableCaret.expected b/python/ql/test/query-tests/Expressions/Regex/UnmatchableCaret.expected new file mode 100644 index 00000000000..1d6cabfafdc --- /dev/null +++ b/python/ql/test/query-tests/Expressions/Regex/UnmatchableCaret.expected @@ -0,0 +1,4 @@ +| test.py:4:12:4:19 | Str | This regular expression includes an unmatchable caret at offset 1. | +| test.py:5:12:5:23 | Str | This regular expression includes an unmatchable caret at offset 5. | +| test.py:6:12:6:21 | Str | This regular expression includes an unmatchable caret at offset 2. | +| test.py:74:12:74:27 | Str | This regular expression includes an unmatchable caret at offset 8. | diff --git a/python/ql/test/query-tests/Expressions/Regex/UnmatchableCaret.qlref b/python/ql/test/query-tests/Expressions/Regex/UnmatchableCaret.qlref new file mode 100644 index 00000000000..161fd59f7f2 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/Regex/UnmatchableCaret.qlref @@ -0,0 +1 @@ +Expressions/Regex/UnmatchableCaret.ql diff --git a/python/ql/test/query-tests/Expressions/Regex/UnmatchableDollar.expected b/python/ql/test/query-tests/Expressions/Regex/UnmatchableDollar.expected new file mode 100644 index 00000000000..7771654c79b --- /dev/null +++ b/python/ql/test/query-tests/Expressions/Regex/UnmatchableDollar.expected @@ -0,0 +1,4 @@ +| test.py:29:12:29:19 | Str | This regular expression includes an unmatchable dollar at offset 3. | +| test.py:30:12:30:23 | Str | This regular expression includes an unmatchable dollar at offset 3. | +| test.py:31:12:31:20 | Str | This regular expression includes an unmatchable dollar at offset 2. | +| test.py:75:12:75:26 | Str | This regular expression includes an unmatchable dollar at offset 3. | diff --git a/python/ql/test/query-tests/Expressions/Regex/UnmatchableDollar.qlref b/python/ql/test/query-tests/Expressions/Regex/UnmatchableDollar.qlref new file mode 100644 index 00000000000..b162342922c --- /dev/null +++ b/python/ql/test/query-tests/Expressions/Regex/UnmatchableDollar.qlref @@ -0,0 +1 @@ +Expressions/Regex/UnmatchableDollar.ql diff --git a/python/ql/test/query-tests/Expressions/Regex/options b/python/ql/test/query-tests/Expressions/Regex/options new file mode 100644 index 00000000000..b91afde0767 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/Regex/options @@ -0,0 +1 @@ +semmle-extractor-options: --max-import-depth=2 diff --git a/python/ql/test/query-tests/Expressions/Regex/test.py b/python/ql/test/query-tests/Expressions/Regex/test.py new file mode 100644 index 00000000000..6a5742a8613 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/Regex/test.py @@ -0,0 +1,135 @@ +import re + +#Unmatchable caret +re.compile(b' ^abc') +re.compile(b"(?s) ^abc") +re.compile(b"\[^123]") + +#Likely false positives for unmatchable caret +re.compile(b"[^123]") +re.compile(b"[123^]") +re.sub(b'(?m)^(?!$)', indent*' ', s) +re.compile(b"()^abc") +re.compile(b"(?:(?:\n\r?)|^)( *)\S") +re.compile(b"^diff (?:-r [0-9a-f]+ ){1,2}(.*)$") + +#Backspace escape +re.compile(br"[\b\t ]") # Should warn +re.compile(br"E\d+\b.*") # Fine +re.compile(br"E\d+\b[ \b\t]") #Both + +#Missing part in named group +re.compile(br'(P[\w]+)') +re.compile(br'(_(P[\w]+)|)') +#This is OK... +re.compile(br'(?P\w+)') + + +#Unmatchable dollar +re.compile(b"abc$ ") +re.compile(b"abc$ (?s)") +re.compile(b"\[$] ") + +#Likely false positives for unmatchable dollar +re.compile(b"[$] ") +re.compile(b"\$ ") +re.compile(b"abc$(?m)") +re.compile(b"abc$()") + + +#Duplicate character in set +re.compile(b"[AA]") +re.compile(b"[000]") +re.compile(b"[-0-9-]") + +#Possible false positives +re.compile(b"[S\S]") +re.compile(b"[0\000]") +re.compile(b"[\0000]") +re.compile(b"[^^]") +re.compile(b"[-0-9]") +re.compile(b"[]]") +re.compile(b"^^^x.*") +re.compile(b".*x$$$") +re.compile(b"x*^y") +re.compile(b"x$y*") + +# False positive for unmatchable caret +re.compile(br'(?!DEFAULT_PREFS)(?!CAN_SET_ANON)^[A-Z_]+$') + +#Equivalent for unmatchable dollar +re.compile(br'^[A-Z_]+(?!DEFAULT_PREFS)(?!CAN_SET_ANON)$') + +#And for negative look-behind assertions +re.compile(br'(?[+-]?) + (?: (?P \d+ (?:\.\d*)? ) \s* [wW] )? \s* + (?: (?P \d+ (?:\.\d*)? ) \s* [dD] )? \s* + (?: (?P \d+ (?:\.\d*)? ) \s* [hH] )? \s* + (?: (?P \d+ (?:\.\d*)? ) \s* [mM] )? \s* + (?: (?P \d+ (?:\.\d*)? ) \s* [sS] )? \s* + $ + ''', + flags=re.VERBOSE) + +REGEX3 = re.compile(r''' + ^\s* + (?P[+-]?) + (?: (?P \d+ (?:\.\d*)? ) \s* [wW] )? \s* + (?: (?P \d+ (?:\.\d*)? ) \s* [dD] )? \s* + (?: (?P \d+ (?:\.\d*)? ) \s* [hH] )? \s* + (?: (?P \d+ (?:\.\d*)? ) \s* [mM] )? \s* + (?: (?P \d+ (?:\.\d*)? ) \s* [sS] )? \s* + $ + ''', + re.VERBOSE) + +#ODASA-6780 +DYLIB_RE = re.compile(r"""(?x) +(?P^.*)(?:^|/) +(?P + (?P\w+?) + (?:\.(?P[^._]+))? + (?:_(?P[^._]+))? + \.dylib$ +) +""") + +#ODASA-6786 +VERBOSE_REGEX = r""" + \[ # [ + (?P
[^]]+) # very permissive! + \] # ] + """ + +# Compiled regular expression marking it as verbose +ODASA_6786 = re.compile(VERBOSE_REGEX, re.VERBOSE) diff --git a/python/ql/test/query-tests/Expressions/callable/NonCallableCalled.expected b/python/ql/test/query-tests/Expressions/callable/NonCallableCalled.expected new file mode 100644 index 00000000000..b7fb4e56b43 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/callable/NonCallableCalled.expected @@ -0,0 +1,5 @@ +| test.py:16:5:16:12 | non() | Call to a $@ of $@. | test.py:15:11:15:23 | NonCallable() | non-callable | test.py:3:1:3:26 | class NonCallable | class NonCallable | +| test.py:17:5:17:8 | Tuple() | Call to a $@ of $@. | test.py:17:5:17:6 | Tuple | non-callable | file://:Compiled Code:0:0:0:0 | builtin-class tuple | builtin-class tuple | +| test.py:18:5:18:8 | List() | Call to a $@ of $@. | test.py:18:5:18:6 | List | non-callable | file://:Compiled Code:0:0:0:0 | builtin-class list | builtin-class list | +| test.py:26:9:26:16 | non() | Call to a $@ of $@. | test.py:15:11:15:23 | NonCallable() | non-callable | test.py:3:1:3:26 | class NonCallable | class NonCallable | +| test.py:47:12:47:27 | NotImplemented() | Call to a $@ of $@. | test.py:47:12:47:25 | NotImplemented | non-callable | file://:Compiled Code:0:0:0:0 | builtin-class NotImplementedType | builtin-class NotImplementedType | diff --git a/python/ql/test/query-tests/Expressions/callable/NonCallableCalled.qlref b/python/ql/test/query-tests/Expressions/callable/NonCallableCalled.qlref new file mode 100644 index 00000000000..ea8577e6f9f --- /dev/null +++ b/python/ql/test/query-tests/Expressions/callable/NonCallableCalled.qlref @@ -0,0 +1 @@ +Expressions/NonCallableCalled.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Expressions/callable/test.py b/python/ql/test/query-tests/Expressions/callable/test.py new file mode 100644 index 00000000000..6ab04558064 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/callable/test.py @@ -0,0 +1,48 @@ + +#Non-callable called +class NonCallable(object): + pass + +class MaybeCallable(Unknown, object): + pass + +class IsCallable(object): + + def __call__(self): + pass + +def call_non_callable(arg): + non = NonCallable() + non(arg) + ()() + []() + dont_know = MaybeCallable() + dont_know() # Not a violation + ok = IsCallable() + ok() + if hasattr(non, "__call__"): + non(arg) # OK due to guard + if hasattr(non, "__init__"): + non(arg) # Not OK due to wrong guard + +import six + +#ODASA-4812 +def call_six_guarded(arg=None): + # If it's a callable, call it + if six.callable(arg): + arg = arg() + +#ODASA-6261 +def experimental_jit_scope(compile_ops=True, separate_compiled_gradients=False): + if callable(compile_ops): + def xla_compile(node_def): + return attr_value_pb2.AttrValue(b=compile_ops(node_def)) + +def foo(): + #This is so common, we have a different query for it + raise NotImplemented() + +def bar(): + return NotImplemented() + diff --git a/python/ql/test/query-tests/Expressions/comparisons/UselessComparisonTest.expected b/python/ql/test/query-tests/Expressions/comparisons/UselessComparisonTest.expected new file mode 100644 index 00000000000..f2f9a79a657 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/comparisons/UselessComparisonTest.expected @@ -0,0 +1,10 @@ +| test.py:6:8:6:13 | Compare | Test is always true, because of $@ | test.py:4:8:4:12 | Compare | this condition | +| test.py:8:8:8:13 | Compare | Test is always true, because of $@ | test.py:4:17:4:21 | Compare | this condition | +| test.py:13:16:13:22 | Compare | Test is always false, because of $@ | test.py:11:12:11:17 | Compare | this condition | +| test.py:15:14:15:18 | Compare | Test is always true, because of $@ | test.py:11:12:11:17 | Compare | this condition | +| test.py:27:8:27:13 | Compare | Test is always true, because of $@ | test.py:25:8:25:12 | Compare | this condition | +| test.py:30:12:30:18 | Compare | Test is always false, because of $@ | test.py:25:17:25:23 | Compare | this condition | +| test.py:49:8:49:12 | Compare | Test is always false, because of $@ | test.py:47:8:47:50 | Compare | this condition | +| test.py:73:14:73:26 | Compare | Test is always true, because of $@ | test.py:71:8:71:19 | Compare | this condition | +| test.py:79:14:79:46 | Compare | Test is always true, because of $@ | test.py:77:8:77:19 | Compare | this condition | +| test.py:85:10:85:42 | Compare | Test is always true, because of $@ | test.py:83:8:83:19 | Compare | this condition | diff --git a/python/ql/test/query-tests/Expressions/comparisons/UselessComparisonTest.qlref b/python/ql/test/query-tests/Expressions/comparisons/UselessComparisonTest.qlref new file mode 100644 index 00000000000..fb7f75f9f61 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/comparisons/UselessComparisonTest.qlref @@ -0,0 +1 @@ +Expressions/Comparisons/UselessComparisonTest.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Expressions/comparisons/test.py b/python/ql/test/query-tests/Expressions/comparisons/test.py new file mode 100644 index 00000000000..b0bb709e2c3 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/comparisons/test.py @@ -0,0 +1,88 @@ + + +def f(w, x, y, z): + if x < 0 or z < 0: + raise Exception() + if x >= 0: # Useless test due to x < 0 being false + y += 1 + if z >= 0: # Useless test due to z < 0 being false + y += 1 + while w >= 0: + if y < 10: + z += 1 + if y == 15: # Useless test due to y < 10 being true + z += 1 + elif y > 7: # Useless test + y -= 1 + if y < 10: + y += 1 + if y < 12: #A useless test, but too complex to infer. + pass + if not y != 5 and z > 0: + w = 0 if y < 3 else 1 #Useless test as y is 5 + +def g(w, x, y, z): + if w < x or y < z+2: + raise Exception() + if w >= x: # Useless test due to w < x being false + pass + if cond: + if z > y-2: # Useless test due to y < z+2 being false + y += 1 + else: + if z >= y-2: # Not a useless test. + y += 1 + +#ODASA-5643 +def validate_series(start, end): + # Check that the values 'make sense' + if end < start: + raise click.BadParameter('The start value must be less than the end value.') + if start == end: + raise click.BadParameter('The start value and the end value most not be the same.') + return start, end + +#Overflow +def medium1(x, y): + if x + 1000000000000000 > y + 1000000000000000: + return + if x > y: # Redundant + pass + +def medium2(x, y): + if x + 1000000000000000 > y + 1000000000000001: + return + if x > y: # Not redundant + pass + +def big1(x, y): + if x + 10000000000000000 > y + 10000000000000000: + return + if x > y: # Redundant (but cannot be sure due to FP rounding errors) + pass + +def big2(x, y): + if x + 10000000000000000 > y + 10000000000000001: + return + if x > y: # Not redundant (but might appear to be due to FP rounding errors) + pass + +def odasa6782_v1(protocol): + if protocol < 0: + protocol = HIGHEST_PROTOCOL + elif not 0 <= protocol: + raise ValueError() + +def odasa6782_v2(protocol): + if protocol < 0: + protocol = HIGHEST_PROTOCOL + elif not 0 <= protocol <= HIGHEST_PROTOCOL: + raise ValueError() + +def odasa6782_v3(protocol): + if protocol < 0: + protocol = HIGHEST_PROTOCOL + elif 0 <= protocol <= HIGHEST_PROTOCOL: + pass + else: + raise ValueError() diff --git a/python/ql/test/query-tests/Expressions/eq/IncorrectComparisonUsingIs.expected b/python/ql/test/query-tests/Expressions/eq/IncorrectComparisonUsingIs.expected new file mode 100644 index 00000000000..6138c2efb68 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/eq/IncorrectComparisonUsingIs.expected @@ -0,0 +1 @@ +| expressions_test.py:46:4:46:21 | Compare | Values compared using 'is' when equivalence is not the same as identity. Use '==' instead. | diff --git a/python/ql/test/query-tests/Expressions/eq/IncorrectComparisonUsingIs.qlref b/python/ql/test/query-tests/Expressions/eq/IncorrectComparisonUsingIs.qlref new file mode 100644 index 00000000000..73123cf7628 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/eq/IncorrectComparisonUsingIs.qlref @@ -0,0 +1 @@ +Expressions/IncorrectComparisonUsingIs.ql diff --git a/python/ql/test/query-tests/Expressions/eq/NonPortableComparisonUsingIs.expected b/python/ql/test/query-tests/Expressions/eq/NonPortableComparisonUsingIs.expected new file mode 100644 index 00000000000..bf7e29279e2 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/eq/NonPortableComparisonUsingIs.expected @@ -0,0 +1,2 @@ +| expressions_test.py:51:4:51:11 | Compare | The result of this comparison with 'is' may differ between implementations of Python. | +| expressions_test.py:56:4:56:16 | Compare | The result of this comparison with 'is' may differ between implementations of Python. | diff --git a/python/ql/test/query-tests/Expressions/eq/NonPortableComparisonUsingIs.qlref b/python/ql/test/query-tests/Expressions/eq/NonPortableComparisonUsingIs.qlref new file mode 100644 index 00000000000..13c08534293 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/eq/NonPortableComparisonUsingIs.qlref @@ -0,0 +1 @@ +Expressions/NonPortableComparisonUsingIs.ql diff --git a/python/ql/test/query-tests/Expressions/eq/expressions_test.py b/python/ql/test/query-tests/Expressions/eq/expressions_test.py new file mode 100644 index 00000000000..2ffac276553 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/eq/expressions_test.py @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + +#ODASA-4519 +#OK as we are using identity tests for unique objects +V2 = "v2" +V3 = "v3" + +class C: + def __init__(self, c): + if c: + self.version = V2 + else: + self.version = V3 + + def meth(self): + if self.version is V2: #FP here. + pass + + +#Using 'is' when should be using '==' +s = "Hello " + "World" +if "Hello World" is s: + print ("OK") + +#This is OK in CPython, but may not be portable +s = str(7) +if "7" is s: + print ("OK") + +#And some data flow +CONSTANT = 20 +if x is CONSTANT: + print ("OK") + +#This is OK +x = object() +y = object() +if x is y: + print ("Very surprising!") + +#This is also OK +if s is None: + print ("Also surprising") + +#Portable is comparisons +def f(arg): + arg is () + arg is 0 + +class C(object): + def __eq__(self, other): + ''' + 'is' must be fine here. + ''' + return self is other + +#Was FP -- https://github.com/lgtmhq/lgtm-queries/issues/13 +def both_sides_known(zero_based="auto", query_id=False): + if query_id and zero_based == "auto": + zero_based = True + if zero_based is False: # False positive here + pass + diff --git a/python/ql/test/query-tests/Expressions/general/CompareConstants.expected b/python/ql/test/query-tests/Expressions/general/CompareConstants.expected new file mode 100644 index 00000000000..ea8645f523c --- /dev/null +++ b/python/ql/test/query-tests/Expressions/general/CompareConstants.expected @@ -0,0 +1,2 @@ +| compare.py:12:1:12:6 | Compare | Comparison of constants; use 'True' or 'False' instead. | +| compare.py:13:1:13:6 | Compare | Comparison of constants; use 'True' or 'False' instead. | diff --git a/python/ql/test/query-tests/Expressions/general/CompareConstants.qlref b/python/ql/test/query-tests/Expressions/general/CompareConstants.qlref new file mode 100644 index 00000000000..0e2ab115eee --- /dev/null +++ b/python/ql/test/query-tests/Expressions/general/CompareConstants.qlref @@ -0,0 +1 @@ +Expressions/CompareConstants.ql diff --git a/python/ql/test/query-tests/Expressions/general/CompareIdenticalValues.expected b/python/ql/test/query-tests/Expressions/general/CompareIdenticalValues.expected new file mode 100644 index 00000000000..9132b5db786 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/general/CompareIdenticalValues.expected @@ -0,0 +1,2 @@ +| compare.py:8:1:8:6 | Compare | Comparison of identical values; use cmath.isnan() if testing for not-a-number. | +| compare.py:9:1:9:10 | Compare | Comparison of identical values; use cmath.isnan() if testing for not-a-number. | diff --git a/python/ql/test/query-tests/Expressions/general/CompareIdenticalValues.qlref b/python/ql/test/query-tests/Expressions/general/CompareIdenticalValues.qlref new file mode 100644 index 00000000000..4bc0ec69fc0 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/general/CompareIdenticalValues.qlref @@ -0,0 +1 @@ +Expressions/CompareIdenticalValues.ql diff --git a/python/ql/test/query-tests/Expressions/general/CompareIdenticalValuesMissingSelf.expected b/python/ql/test/query-tests/Expressions/general/CompareIdenticalValuesMissingSelf.expected new file mode 100644 index 00000000000..331f591b2d4 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/general/CompareIdenticalValuesMissingSelf.expected @@ -0,0 +1 @@ +| compare.py:22:12:22:17 | Compare | Comparison of identical values; may be missing 'self'. | diff --git a/python/ql/test/query-tests/Expressions/general/CompareIdenticalValuesMissingSelf.qlref b/python/ql/test/query-tests/Expressions/general/CompareIdenticalValuesMissingSelf.qlref new file mode 100644 index 00000000000..f19a0dee436 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/general/CompareIdenticalValuesMissingSelf.qlref @@ -0,0 +1 @@ +Expressions/CompareIdenticalValuesMissingSelf.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Expressions/general/ContainsNonContainer.expected b/python/ql/test/query-tests/Expressions/general/ContainsNonContainer.expected new file mode 100644 index 00000000000..cf6d78d0d36 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/general/ContainsNonContainer.expected @@ -0,0 +1,2 @@ +| expressions_test.py:89:8:89:15 | Compare | This test may raise an Exception as the $@ may be of non-container class $@. | expressions_test.py:88:11:88:17 | ControlFlowNode for XIter() | target | expressions_test.py:77:1:77:20 | class XIter | XIter | +| expressions_test.py:91:8:91:19 | Compare | This test may raise an Exception as the $@ may be of non-container class $@. | expressions_test.py:88:11:88:17 | ControlFlowNode for XIter() | target | expressions_test.py:77:1:77:20 | class XIter | XIter | diff --git a/python/ql/test/query-tests/Expressions/general/ContainsNonContainer.qlref b/python/ql/test/query-tests/Expressions/general/ContainsNonContainer.qlref new file mode 100644 index 00000000000..71df405e72c --- /dev/null +++ b/python/ql/test/query-tests/Expressions/general/ContainsNonContainer.qlref @@ -0,0 +1 @@ +Expressions/ContainsNonContainer.ql diff --git a/python/ql/test/query-tests/Expressions/general/DuplicateKeyInDictionaryLiteral.expected b/python/ql/test/query-tests/Expressions/general/DuplicateKeyInDictionaryLiteral.expected new file mode 100644 index 00000000000..70673ebc7c7 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/general/DuplicateKeyInDictionaryLiteral.expected @@ -0,0 +1,2 @@ +| expressions_test.py:3:14:3:14 | IntegerLiteral | Dictionary key 1 is subsequently $@. | expressions_test.py:4:14:4:14 | IntegerLiteral | overwritten | +| expressions_test.py:5:14:5:17 | Str | Dictionary key 'a' is subsequently $@. | expressions_test.py:6:14:6:17 | Str | overwritten | diff --git a/python/ql/test/query-tests/Expressions/general/DuplicateKeyInDictionaryLiteral.qlref b/python/ql/test/query-tests/Expressions/general/DuplicateKeyInDictionaryLiteral.qlref new file mode 100644 index 00000000000..a1bb7109882 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/general/DuplicateKeyInDictionaryLiteral.qlref @@ -0,0 +1 @@ +Expressions/DuplicateKeyInDictionaryLiteral.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Expressions/general/EqualsNone.expected b/python/ql/test/query-tests/Expressions/general/EqualsNone.expected new file mode 100644 index 00000000000..b3802afa0c7 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/general/EqualsNone.expected @@ -0,0 +1 @@ +| expressions_test.py:115:12:115:22 | Compare | Testing for None should use the 'is' operator. | diff --git a/python/ql/test/query-tests/Expressions/general/EqualsNone.qlref b/python/ql/test/query-tests/Expressions/general/EqualsNone.qlref new file mode 100644 index 00000000000..8d9699258e2 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/general/EqualsNone.qlref @@ -0,0 +1 @@ +Expressions/EqualsNone.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Expressions/general/ExpectedMappingForFormatString.expected b/python/ql/test/query-tests/Expressions/general/ExpectedMappingForFormatString.expected new file mode 100644 index 00000000000..ab1ab1a7915 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/general/ExpectedMappingForFormatString.expected @@ -0,0 +1 @@ +| str_fmt_test.py:5:26:5:26 | x | Right hand side of a % operator must be a mapping, not class $@. | file://:Compiled Code:0:0:0:0 | builtin-class list | list | diff --git a/python/ql/test/query-tests/Expressions/general/ExpectedMappingForFormatString.qlref b/python/ql/test/query-tests/Expressions/general/ExpectedMappingForFormatString.qlref new file mode 100644 index 00000000000..83e92584ef2 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/general/ExpectedMappingForFormatString.qlref @@ -0,0 +1 @@ +Expressions/ExpectedMappingForFormatString.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Expressions/general/ExplcitCallToDel.expected b/python/ql/test/query-tests/Expressions/general/ExplcitCallToDel.expected new file mode 100644 index 00000000000..909c9d8ccc8 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/general/ExplcitCallToDel.expected @@ -0,0 +1 @@ +Failure \ No newline at end of file diff --git a/python/ql/test/query-tests/Expressions/general/ExplicitCallToDel.expected b/python/ql/test/query-tests/Expressions/general/ExplicitCallToDel.expected new file mode 100644 index 00000000000..cd1c27f10e0 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/general/ExplicitCallToDel.expected @@ -0,0 +1,2 @@ +| expressions_test.py:37:1:37:11 | Attribute() | The __del__ special method is called explicitly. | +| expressions_test.py:133:9:133:22 | Attribute() | The __del__ special method is called explicitly. | diff --git a/python/ql/test/query-tests/Expressions/general/ExplicitCallToDel.qlref b/python/ql/test/query-tests/Expressions/general/ExplicitCallToDel.qlref new file mode 100644 index 00000000000..932f1a3d366 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/general/ExplicitCallToDel.qlref @@ -0,0 +1 @@ +Expressions/ExplicitCallToDel.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Expressions/general/HashedButNoHash.expected b/python/ql/test/query-tests/Expressions/general/HashedButNoHash.expected new file mode 100644 index 00000000000..69bc7a7db39 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/general/HashedButNoHash.expected @@ -0,0 +1 @@ +| expressions_test.py:42:20:42:25 | unhash | This $@ of $@ is unhashable. | expressions_test.py:41:32:41:37 | ControlFlowNode for list() | instance | file://:Compiled Code:0:0:0:0 | builtin-class list | list | diff --git a/python/ql/test/query-tests/Expressions/general/HashedButNoHash.qlref b/python/ql/test/query-tests/Expressions/general/HashedButNoHash.qlref new file mode 100644 index 00000000000..ee53e367499 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/general/HashedButNoHash.qlref @@ -0,0 +1 @@ +Expressions/HashedButNoHash.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Expressions/general/UnnecessaryLambda.expected b/python/ql/test/query-tests/Expressions/general/UnnecessaryLambda.expected new file mode 100644 index 00000000000..dd8db3d4154 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/general/UnnecessaryLambda.expected @@ -0,0 +1,6 @@ +| expressions_test.py:11:1:11:42 | Lambda | This 'lambda' is just a simple wrapper around a callable object. Use that object directly. | +| expressions_test.py:12:1:12:44 | Lambda | This 'lambda' is just a simple wrapper around a callable object. Use that object directly. | +| expressions_test.py:13:1:13:46 | Lambda | This 'lambda' is just a simple wrapper around a callable object. Use that object directly. | +| expressions_test.py:141:1:141:22 | Lambda | This 'lambda' is just a simple wrapper around a callable object. Use that object directly. | +| expressions_test.py:142:1:142:29 | Lambda | This 'lambda' is just a simple wrapper around a callable object. Use that object directly. | +| expressions_test.py:149:16:149:34 | Lambda | This 'lambda' is just a simple wrapper around a callable object. Use that object directly. | diff --git a/python/ql/test/query-tests/Expressions/general/UnnecessaryLambda.qlref b/python/ql/test/query-tests/Expressions/general/UnnecessaryLambda.qlref new file mode 100644 index 00000000000..49b3873f83c --- /dev/null +++ b/python/ql/test/query-tests/Expressions/general/UnnecessaryLambda.qlref @@ -0,0 +1 @@ +Expressions/UnnecessaryLambda.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Expressions/general/UnsupportedFormatCharacter.expected b/python/ql/test/query-tests/Expressions/general/UnsupportedFormatCharacter.expected new file mode 100644 index 00000000000..0e4fdb3d565 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/general/UnsupportedFormatCharacter.expected @@ -0,0 +1 @@ +| str_fmt_test.py:8:12:8:16 | Str | Invalid conversion specifier at index 0 of '%Z'. | diff --git a/python/ql/test/query-tests/Expressions/general/UnsupportedFormatCharacter.qlref b/python/ql/test/query-tests/Expressions/general/UnsupportedFormatCharacter.qlref new file mode 100644 index 00000000000..3cb459229e4 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/general/UnsupportedFormatCharacter.qlref @@ -0,0 +1 @@ +Expressions/UnsupportedFormatCharacter.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Expressions/general/WrongNumberArgumentsForFormat.expected b/python/ql/test/query-tests/Expressions/general/WrongNumberArgumentsForFormat.expected new file mode 100644 index 00000000000..3e83aa4bb0d --- /dev/null +++ b/python/ql/test/query-tests/Expressions/general/WrongNumberArgumentsForFormat.expected @@ -0,0 +1,2 @@ +| str_fmt_test.py:11:11:11:34 | BinaryExpr | Wrong number of $@ for string format. Format $@ takes 2, but 3 are provided. | str_fmt_test.py:11:23:11:33 | Tuple | arguments | str_fmt_test.py:11:11:11:18 | Str | %s %s | +| str_fmt_test.py:14:11:14:23 | BinaryExpr | Wrong number of $@ for string format. Format $@ takes 1, but 2 are provided. | str_fmt_test.py:13:13:13:21 | Tuple | arguments | str_fmt_test.py:12:14:12:19 | Str | %hd | diff --git a/python/ql/test/query-tests/Expressions/general/WrongNumberArgumentsForFormat.qlref b/python/ql/test/query-tests/Expressions/general/WrongNumberArgumentsForFormat.qlref new file mode 100644 index 00000000000..0d127e1b618 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/general/WrongNumberArgumentsForFormat.qlref @@ -0,0 +1 @@ +Expressions/WrongNumberArgumentsForFormat.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Expressions/general/_private.py b/python/ql/test/query-tests/Expressions/general/_private.py new file mode 100644 index 00000000000..f7d0e50ba20 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/general/_private.py @@ -0,0 +1,4 @@ +#Private modules, still needs docstrings + +def f(x, y): + 'Doc string' diff --git a/python/ql/test/query-tests/Expressions/general/compare.py b/python/ql/test/query-tests/Expressions/general/compare.py new file mode 100644 index 00000000000..141b5e6a028 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/general/compare.py @@ -0,0 +1,26 @@ + +#OK +a = b = 1 +a == b +a.x == b.x + +#Same variables +a == a +a.x == a.x + +#Compare constants +1 == 1 +1 == 2 + +#Maybe missing self +class X(object): + + def __init__(self, x): + self.x = x + + def missing_self(self, x): + if x == x: + print ("Yes") + +#Compare constants in assert -- ok +assert(1 == 1) diff --git a/python/ql/test/query-tests/Expressions/general/expressions_test.py b/python/ql/test/query-tests/Expressions/general/expressions_test.py new file mode 100644 index 00000000000..7770e326e2c --- /dev/null +++ b/python/ql/test/query-tests/Expressions/general/expressions_test.py @@ -0,0 +1,218 @@ +#encoding: utf-8 +def dup_key(): + return { 1: -1, + 1: -2, + u'a' : u'A', + u'a' : u'B' + } + +def simple_func(*args, **kwrgs): pass +#Unnecessary lambdas +lambda arg0, arg1: simple_func(arg0, arg1) +lambda arg0, *arg1: simple_func(arg0, *arg1) +lambda arg0, **arg1: simple_func(arg0, **arg1) +# these lambdas are_ necessary +lambda arg0, arg1=1: simple_func(arg0, arg1) +lambda arg0, arg1: simple_func(arg0, *arg1) +lambda arg0, arg1: simple_func(arg0, **arg1) +lambda arg0, *arg1: simple_func(arg0, arg1) +lambda arg0, **arg1: simple_func(arg0, arg1) + +#Non-callable called +class NonCallable(object): + pass + +class MaybeCallable(Unknown, object): + pass + +def call_non_callable(arg): + non = NonCallable() + non(arg) + ()() + []() + dont_know = MaybeCallable() + dont_know() # Not a violation + +#Explicit call to __del__ +x.__del__() + +#Unhashable object +def func(): + mapping = dict(); unhash = list() + return mapping[unhash] + +#Using 'is' when should be using '==' +s = "Hello " + "World" +if "Hello World" is s: + print ("OK") + +#This is OK in CPython, but may not be portable +s = str(7) +if "7" is s: + print ("OK") + +#And some data flow +CONSTANT = 20 +if x is CONSTANT: + print ("OK") + +#This is OK +x = object() +y = object() +if x is y: + print ("Very surprising!") + +#This is also OK +if s is None: + print ("Also surprising") + +#Portable is comparisons +def f(arg): + arg is () + arg is 0 + arg is '' + +#Non-container + +class XIter(object): + #Support both 2 and 3 form of next, but omit __iter__ method + + def __next__(self): + pass + + def next(self): + pass + +def non_container(): + + seq = XIter() + if 1 in seq: + pass + if 1 not in seq: + pass + +#Container inheriting from builtin +class MyDict(dict): + pass + +class MySequence(UnresolvablebaseClass): + pass + +def is_container(): + mapping = MyDict() + if 1 in mapping: + pass + seq = MySequence() + if 1 in seq: + pass + seq = None + if seq is not None and 1 in seq: + pass + +#Equals none + +def x(arg): + return arg == None + +class NotMyDict(object): + + def f(self): + super(MyDict, self).f() + +# class defining __del__ +class Test(object): + def __del__(self): + pass + +# subclass +class SubTest(Test): + def __del__(self): + # This is permitted and required. + Test.__del__(self) + # This is a violation. + self.__del__() + # This is an alternate syntax for the super() call, and hence OK. + super(SubTest, self).__del__() + # This is the Python 3 spelling of the same. + super().__del__() + +#Some more lambdas +#Unnecessary lambdas +lambda arg0: len(arg0) +lambda arg0: XIter.next(arg0) +class UL(object): + + def f(self, x): + pass + + def g(self): + return lambda x: self.f(x) + +# these lambdas are necessary +lambda arg0: XIter.next(arg0, arg1) +lambda arg0: func()(arg0) +lambda arg0, arg1: arg0.meth(arg0, arg1) + +#Cannot flag lists as unhashable if the object +#we are subscripting may be a numpy array +def func(maybe_numpy): + unhash = list() + return maybe_numpy[unhash] + +#Guarded non-callable called +def guarded_non_callable(cond): + if cond: + val = [] + else: + val = func + if hasattr(val, "__call__"): + x(1) + + +#ODASA-4056 +def format_string(s, formatter='minimal'): + """Format the given string using the given formatter.""" + if not callable(formatter): + formatter = get_formatter_for_name(formatter) + if formatter is None: + output = s + else: + output = formatter(s) + return output + +#ODASA-4614 +def f(x): + d = {} + d['one'] = {} + d['two'] = 0 + return x[d['two']] + +#ODASA-4055 +class C: + + def _internal(arg): + # arg is not a C + def wrapper(args): + return arg(args) + return wrapper + + @_internal + def method(self, *args): + pass + +#ODASA-4689 +class StrangeIndex: + def __getitem__(self,index): + return 1 + +x = StrangeIndex(); +print(x[{'a': 'b'}]) + +def not_dup_key(): + return { u'a' : 0, + b'a' : 0, + u"😄" : 1, + u"😅" : 2, + u"😆" : 3 + } + diff --git a/python/ql/test/query-tests/Expressions/general/str_fmt_test.py b/python/ql/test/query-tests/Expressions/general/str_fmt_test.py new file mode 100644 index 00000000000..e941b842c31 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/general/str_fmt_test.py @@ -0,0 +1,55 @@ + + +def expected_mapping_for_fmt_string(): + x = [ u'list', u'not', u'mapping' ] + print (u"%(name)s" % x) + +def unsupported_format_char(arg): + print (u"%Z" % arg) + +def wrong_arg_count_format(arg): + print(u"%s %s" % (arg, arg, 0)) + format = u"%hd" + args = (1, u'foo') + print(format % args) + + +def ok(): + # allowable length modifiers + print(u"%hd %ld %Ld" % (1,2,3)) + + # multiple adjacent % characters + print(u"%%%s" % u"(foo)s") + + # '.' without trailing digits + print(u"%2.d" % 3) + + # a list is OK as an argument to %s + print(u"%s is a list" % [1,2,3,4]) + + # pretty much everything + print(u"%(var)#0+- 8.4hd" % dict(var=44)) + + #This one from PyPy tests + print(u"%()s" % { u'' : u'Hi' }) + +#ODASA 6401 +out = '\n' +out+= ' \n' + +light = out % (az, al) + +#Example from CPython +def f(k, v): + print(' %-40s%a,' % ('%a:' % k, v)) + +#Context sensitive +def g(a, b): + return a % b + +g("%s", 1) +g("%s %s", (1, 2)) + +#Make sure we handle all format characters +"%b %d %i %o %u %x %X %e %E %f %F %g %G %c %r %s" % t() + diff --git a/python/ql/test/query-tests/Expressions/strings/UnintentionalImplicitStringConcatenation.expected b/python/ql/test/query-tests/Expressions/strings/UnintentionalImplicitStringConcatenation.expected new file mode 100644 index 00000000000..1b8b1421f80 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/strings/UnintentionalImplicitStringConcatenation.expected @@ -0,0 +1,4 @@ +| test.py:17:9:18:18 | Str | Implicit string concatenation. Maybe missing a comma? | +| test.py:23:9:24:18 | Str | Implicit string concatenation. Maybe missing a comma? | +| test.py:33:9:34:30 | Str | Implicit string concatenation. Maybe missing a comma? | +| test.py:35:9:36:18 | Str | Implicit string concatenation. Maybe missing a comma? | diff --git a/python/ql/test/query-tests/Expressions/strings/UnintentionalImplicitStringConcatenation.qlref b/python/ql/test/query-tests/Expressions/strings/UnintentionalImplicitStringConcatenation.qlref new file mode 100644 index 00000000000..c305fd129f8 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/strings/UnintentionalImplicitStringConcatenation.qlref @@ -0,0 +1 @@ +Expressions/UnintentionalImplicitStringConcatenation.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Expressions/strings/test.py b/python/ql/test/query-tests/Expressions/strings/test.py new file mode 100644 index 00000000000..15b3c9216e3 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/strings/test.py @@ -0,0 +1,46 @@ + +def test(): + single_string = [ + "foo" + "bar" + "/usr/local" + "/usr/bin" + ] + explict_concat = [ + "foo" + + "bar", + "/usr/local", + "/usr/bin" + ] + error1 = [ + "foo", + "/usr/local" + "/usr/bin" + ] + error2 = [ + "foo" + + "bar", + "/usr/local" + "/usr/bin" + ] + +#Examples from documentation + +def unclear(): + # Returns [ "first part of long string and the second part", "/usr/local/usr/bin" ] + return [ + + "first part of long string" + " and the second part", + "/usr/local" + "/usr/bin" + ] + +def clarified(): + # Returns [ "first part of long string and the second part", "/usr/local", "/usr/bin" ] + return [ + "first part of long string" + + " and the second part", + "/usr/local", + "/usr/bin" + ] diff --git a/python/ql/test/query-tests/Expressions/super/CallToSuperWrongClass.expected b/python/ql/test/query-tests/Expressions/super/CallToSuperWrongClass.expected new file mode 100644 index 00000000000..66508e08d70 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/super/CallToSuperWrongClass.expected @@ -0,0 +1 @@ +| test.py:10:9:10:27 | super() | First argument to super() should be NotMyDict. | diff --git a/python/ql/test/query-tests/Expressions/super/CallToSuperWrongClass.qlref b/python/ql/test/query-tests/Expressions/super/CallToSuperWrongClass.qlref new file mode 100644 index 00000000000..c3beeaede04 --- /dev/null +++ b/python/ql/test/query-tests/Expressions/super/CallToSuperWrongClass.qlref @@ -0,0 +1 @@ +Expressions/CallToSuperWrongClass.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Expressions/super/test.py b/python/ql/test/query-tests/Expressions/super/test.py new file mode 100644 index 00000000000..e2e667cd25d --- /dev/null +++ b/python/ql/test/query-tests/Expressions/super/test.py @@ -0,0 +1,25 @@ +import sys + +#Container inheriting from builtin +class MyDict(dict): + pass + +class NotMyDict(object): + + def f(self): + super(MyDict, self).f() + +#Splitting +PY2 = sys.version_info[0] == 2 + +if PY2: + pass + + +class InSplit(MyDict): + + def __init__(self): + super(InSplit, self).f() + +if PY2: + pass diff --git a/python/ql/test/query-tests/Expressions/super/test_except.py b/python/ql/test/query-tests/Expressions/super/test_except.py new file mode 100644 index 00000000000..22935563a6e --- /dev/null +++ b/python/ql/test/query-tests/Expressions/super/test_except.py @@ -0,0 +1,13 @@ + +try: + + @decorator + class S(object): + + def __init__(self, *args, **kwargs): + super(S, self).__init__(*args, **kwargs) + +except Exception: + + class S(object): + pass diff --git a/python/ql/test/query-tests/ForbiddenDependency/explicitdisallow/ForbiddenDependency.expected b/python/ql/test/query-tests/ForbiddenDependency/explicitdisallow/ForbiddenDependency.expected new file mode 100644 index 00000000000..d60f4a5832d --- /dev/null +++ b/python/ql/test/query-tests/ForbiddenDependency/explicitdisallow/ForbiddenDependency.expected @@ -0,0 +1 @@ +| a.py:1:1:1:8 | Import | $@ imports $@. This violates the explicit rule against dependencies from "G2" to "G3". | a.py:0:0:0:0 | Module a | a | b.py:0:0:0:0 | Module b | b | diff --git a/python/ql/test/query-tests/ForbiddenDependency/explicitdisallow/ForbiddenDependency.qlref b/python/ql/test/query-tests/ForbiddenDependency/explicitdisallow/ForbiddenDependency.qlref new file mode 100644 index 00000000000..6470516326d --- /dev/null +++ b/python/ql/test/query-tests/ForbiddenDependency/explicitdisallow/ForbiddenDependency.qlref @@ -0,0 +1 @@ +Architect/ForbiddenDependency.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/ForbiddenDependency/explicitdisallow/a.py b/python/ql/test/query-tests/ForbiddenDependency/explicitdisallow/a.py new file mode 100644 index 00000000000..0f9577fbb6f --- /dev/null +++ b/python/ql/test/query-tests/ForbiddenDependency/explicitdisallow/a.py @@ -0,0 +1,4 @@ +import b + +class A(B): + pass \ No newline at end of file diff --git a/python/ql/test/query-tests/ForbiddenDependency/explicitdisallow/b.py b/python/ql/test/query-tests/ForbiddenDependency/explicitdisallow/b.py new file mode 100644 index 00000000000..f67f07f628d --- /dev/null +++ b/python/ql/test/query-tests/ForbiddenDependency/explicitdisallow/b.py @@ -0,0 +1,4 @@ +import c + +class B(C): + pass \ No newline at end of file diff --git a/python/ql/test/query-tests/ForbiddenDependency/explicitdisallow/c.py b/python/ql/test/query-tests/ForbiddenDependency/explicitdisallow/c.py new file mode 100644 index 00000000000..e6086862614 --- /dev/null +++ b/python/ql/test/query-tests/ForbiddenDependency/explicitdisallow/c.py @@ -0,0 +1,5 @@ +import b + +class C: + def foo(self): + b = B() \ No newline at end of file diff --git a/python/ql/test/query-tests/ForbiddenDependency/explicitdisallow/specification.arcspec b/python/ql/test/query-tests/ForbiddenDependency/explicitdisallow/specification.arcspec new file mode 100644 index 00000000000..086f01368ec --- /dev/null +++ b/python/ql/test/query-tests/ForbiddenDependency/explicitdisallow/specification.arcspec @@ -0,0 +1,11 @@ + + + regex + + + + + + + + diff --git a/python/ql/test/query-tests/ForbiddenDependency/independent/ForbiddenDependency.expected b/python/ql/test/query-tests/ForbiddenDependency/independent/ForbiddenDependency.expected new file mode 100644 index 00000000000..a4d81517ae0 --- /dev/null +++ b/python/ql/test/query-tests/ForbiddenDependency/independent/ForbiddenDependency.expected @@ -0,0 +1,2 @@ +| b.py:1:1:1:8 | Import | $@ imports $@. This violates the "independent" group rule on "G1", which disallows dependencies from "G3" to "G4. | b.py:0:0:0:0 | Module b | b | c.py:0:0:0:0 | Module c | c | +| c.py:1:1:1:8 | Import | $@ imports $@. This violates the "independent" group rule on "G1", which disallows dependencies from "G4" to "G3. | c.py:0:0:0:0 | Module c | c | b.py:0:0:0:0 | Module b | b | diff --git a/python/ql/test/query-tests/ForbiddenDependency/independent/ForbiddenDependency.qlref b/python/ql/test/query-tests/ForbiddenDependency/independent/ForbiddenDependency.qlref new file mode 100644 index 00000000000..6470516326d --- /dev/null +++ b/python/ql/test/query-tests/ForbiddenDependency/independent/ForbiddenDependency.qlref @@ -0,0 +1 @@ +Architect/ForbiddenDependency.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/ForbiddenDependency/independent/a.py b/python/ql/test/query-tests/ForbiddenDependency/independent/a.py new file mode 100644 index 00000000000..0f9577fbb6f --- /dev/null +++ b/python/ql/test/query-tests/ForbiddenDependency/independent/a.py @@ -0,0 +1,4 @@ +import b + +class A(B): + pass \ No newline at end of file diff --git a/python/ql/test/query-tests/ForbiddenDependency/independent/b.py b/python/ql/test/query-tests/ForbiddenDependency/independent/b.py new file mode 100644 index 00000000000..f67f07f628d --- /dev/null +++ b/python/ql/test/query-tests/ForbiddenDependency/independent/b.py @@ -0,0 +1,4 @@ +import c + +class B(C): + pass \ No newline at end of file diff --git a/python/ql/test/query-tests/ForbiddenDependency/independent/c.py b/python/ql/test/query-tests/ForbiddenDependency/independent/c.py new file mode 100644 index 00000000000..e6086862614 --- /dev/null +++ b/python/ql/test/query-tests/ForbiddenDependency/independent/c.py @@ -0,0 +1,5 @@ +import b + +class C: + def foo(self): + b = B() \ No newline at end of file diff --git a/python/ql/test/query-tests/ForbiddenDependency/independent/specification.arcspec b/python/ql/test/query-tests/ForbiddenDependency/independent/specification.arcspec new file mode 100644 index 00000000000..a8c0fc14713 --- /dev/null +++ b/python/ql/test/query-tests/ForbiddenDependency/independent/specification.arcspec @@ -0,0 +1,11 @@ + + + regex + + + + + + + + diff --git a/python/ql/test/query-tests/ForbiddenDependency/ordered/ForbiddenDependency.expected b/python/ql/test/query-tests/ForbiddenDependency/ordered/ForbiddenDependency.expected new file mode 100644 index 00000000000..44b3baad942 --- /dev/null +++ b/python/ql/test/query-tests/ForbiddenDependency/ordered/ForbiddenDependency.expected @@ -0,0 +1,2 @@ +| a.py:1:1:1:8 | Import | $@ imports $@. This violates the explicit rule against dependencies from "G2" to "G3". | a.py:0:0:0:0 | Module a | a | b.py:0:0:0:0 | Module b | b | +| c.py:1:1:1:8 | Import | $@ imports $@. This violates the "ordered" group rule on "G1", which disallows dependencies from "G4" to "G3. | c.py:0:0:0:0 | Module c | c | b.py:0:0:0:0 | Module b | b | diff --git a/python/ql/test/query-tests/ForbiddenDependency/ordered/ForbiddenDependency.qlref b/python/ql/test/query-tests/ForbiddenDependency/ordered/ForbiddenDependency.qlref new file mode 100644 index 00000000000..6470516326d --- /dev/null +++ b/python/ql/test/query-tests/ForbiddenDependency/ordered/ForbiddenDependency.qlref @@ -0,0 +1 @@ +Architect/ForbiddenDependency.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/ForbiddenDependency/ordered/a.py b/python/ql/test/query-tests/ForbiddenDependency/ordered/a.py new file mode 100644 index 00000000000..0f9577fbb6f --- /dev/null +++ b/python/ql/test/query-tests/ForbiddenDependency/ordered/a.py @@ -0,0 +1,4 @@ +import b + +class A(B): + pass \ No newline at end of file diff --git a/python/ql/test/query-tests/ForbiddenDependency/ordered/b.py b/python/ql/test/query-tests/ForbiddenDependency/ordered/b.py new file mode 100644 index 00000000000..f67f07f628d --- /dev/null +++ b/python/ql/test/query-tests/ForbiddenDependency/ordered/b.py @@ -0,0 +1,4 @@ +import c + +class B(C): + pass \ No newline at end of file diff --git a/python/ql/test/query-tests/ForbiddenDependency/ordered/c.py b/python/ql/test/query-tests/ForbiddenDependency/ordered/c.py new file mode 100644 index 00000000000..e6086862614 --- /dev/null +++ b/python/ql/test/query-tests/ForbiddenDependency/ordered/c.py @@ -0,0 +1,5 @@ +import b + +class C: + def foo(self): + b = B() \ No newline at end of file diff --git a/python/ql/test/query-tests/ForbiddenDependency/ordered/specification.arcspec b/python/ql/test/query-tests/ForbiddenDependency/ordered/specification.arcspec new file mode 100644 index 00000000000..db867cf446a --- /dev/null +++ b/python/ql/test/query-tests/ForbiddenDependency/ordered/specification.arcspec @@ -0,0 +1,10 @@ + + + regex + + + + + + + diff --git a/python/ql/test/query-tests/ForbiddenDependency/private/ForbiddenDependency.expected b/python/ql/test/query-tests/ForbiddenDependency/private/ForbiddenDependency.expected new file mode 100644 index 00000000000..4c804cbe72f --- /dev/null +++ b/python/ql/test/query-tests/ForbiddenDependency/private/ForbiddenDependency.expected @@ -0,0 +1 @@ +| a.py:1:1:1:8 | Import | $@ imports $@. This violates the "private" group rule on "G5", which disallows dependencies from "G2" to "G5. | a.py:0:0:0:0 | Module a | a | b.py:0:0:0:0 | Module b | b | diff --git a/python/ql/test/query-tests/ForbiddenDependency/private/ForbiddenDependency.qlref b/python/ql/test/query-tests/ForbiddenDependency/private/ForbiddenDependency.qlref new file mode 100644 index 00000000000..6470516326d --- /dev/null +++ b/python/ql/test/query-tests/ForbiddenDependency/private/ForbiddenDependency.qlref @@ -0,0 +1 @@ +Architect/ForbiddenDependency.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/ForbiddenDependency/private/a.py b/python/ql/test/query-tests/ForbiddenDependency/private/a.py new file mode 100644 index 00000000000..0f9577fbb6f --- /dev/null +++ b/python/ql/test/query-tests/ForbiddenDependency/private/a.py @@ -0,0 +1,4 @@ +import b + +class A(B): + pass \ No newline at end of file diff --git a/python/ql/test/query-tests/ForbiddenDependency/private/b.py b/python/ql/test/query-tests/ForbiddenDependency/private/b.py new file mode 100644 index 00000000000..f67f07f628d --- /dev/null +++ b/python/ql/test/query-tests/ForbiddenDependency/private/b.py @@ -0,0 +1,4 @@ +import c + +class B(C): + pass \ No newline at end of file diff --git a/python/ql/test/query-tests/ForbiddenDependency/private/c.py b/python/ql/test/query-tests/ForbiddenDependency/private/c.py new file mode 100644 index 00000000000..e6086862614 --- /dev/null +++ b/python/ql/test/query-tests/ForbiddenDependency/private/c.py @@ -0,0 +1,5 @@ +import b + +class C: + def foo(self): + b = B() \ No newline at end of file diff --git a/python/ql/test/query-tests/ForbiddenDependency/private/specification.arcspec b/python/ql/test/query-tests/ForbiddenDependency/private/specification.arcspec new file mode 100644 index 00000000000..2cd2699f89d --- /dev/null +++ b/python/ql/test/query-tests/ForbiddenDependency/private/specification.arcspec @@ -0,0 +1,15 @@ + + + regex + + + + + + + + + + + + diff --git a/python/ql/test/query-tests/Functions/general/DeprecatedSliceMethod.expected b/python/ql/test/query-tests/Functions/general/DeprecatedSliceMethod.expected new file mode 100644 index 00000000000..8d89bff1f23 --- /dev/null +++ b/python/ql/test/query-tests/Functions/general/DeprecatedSliceMethod.expected @@ -0,0 +1,3 @@ +| functions_test.py:200:5:200:40 | Function __getslice__ | __getslice__ method has been deprecated since Python 2.0 | +| functions_test.py:203:5:203:47 | Function __setslice__ | __setslice__ method has been deprecated since Python 2.0 | +| functions_test.py:206:5:206:40 | Function __delslice__ | __delslice__ method has been deprecated since Python 2.0 | diff --git a/python/ql/test/query-tests/Functions/general/DeprecatedSliceMethod.qlref b/python/ql/test/query-tests/Functions/general/DeprecatedSliceMethod.qlref new file mode 100644 index 00000000000..c38b8d1f761 --- /dev/null +++ b/python/ql/test/query-tests/Functions/general/DeprecatedSliceMethod.qlref @@ -0,0 +1 @@ +Functions/DeprecatedSliceMethod.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Functions/general/ExplicitReturnInInit.expected b/python/ql/test/query-tests/Functions/general/ExplicitReturnInInit.expected new file mode 100644 index 00000000000..e695c7d0030 --- /dev/null +++ b/python/ql/test/query-tests/Functions/general/ExplicitReturnInInit.expected @@ -0,0 +1 @@ +| functions_test.py:45:9:45:19 | Return | Explicit return in __init__ method. | diff --git a/python/ql/test/query-tests/Functions/general/ExplicitReturnInInit.qlref b/python/ql/test/query-tests/Functions/general/ExplicitReturnInInit.qlref new file mode 100644 index 00000000000..a23550c4865 --- /dev/null +++ b/python/ql/test/query-tests/Functions/general/ExplicitReturnInInit.qlref @@ -0,0 +1 @@ +Functions/ExplicitReturnInInit.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Functions/general/IncorrectRaiseInSpecialMethod.expected b/python/ql/test/query-tests/Functions/general/IncorrectRaiseInSpecialMethod.expected new file mode 100644 index 00000000000..a5049d58046 --- /dev/null +++ b/python/ql/test/query-tests/Functions/general/IncorrectRaiseInSpecialMethod.expected @@ -0,0 +1,2 @@ +| protocols.py:66:5:66:33 | Function __getitem__ | Function always raises $@; raise LookupError instead | file://:Compiled Code:0:0:0:0 | builtin-class ZeroDivisionError | builtin-class ZeroDivisionError | +| protocols.py:69:5:69:26 | Function __getattr__ | Function always raises $@; raise AttributeError instead | file://:Compiled Code:0:0:0:0 | builtin-class ZeroDivisionError | builtin-class ZeroDivisionError | diff --git a/python/ql/test/query-tests/Functions/general/IncorrectRaiseInSpecialMethod.qlref b/python/ql/test/query-tests/Functions/general/IncorrectRaiseInSpecialMethod.qlref new file mode 100644 index 00000000000..07fd22a9376 --- /dev/null +++ b/python/ql/test/query-tests/Functions/general/IncorrectRaiseInSpecialMethod.qlref @@ -0,0 +1 @@ +Functions/IncorrectRaiseInSpecialMethod.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Functions/general/InitIsGenerator.expected b/python/ql/test/query-tests/Functions/general/InitIsGenerator.expected new file mode 100644 index 00000000000..ec18b839c48 --- /dev/null +++ b/python/ql/test/query-tests/Functions/general/InitIsGenerator.expected @@ -0,0 +1 @@ +| functions_test.py:73:5:73:23 | Function __init__ | __init__ method is a generator. | diff --git a/python/ql/test/query-tests/Functions/general/InitIsGenerator.qlref b/python/ql/test/query-tests/Functions/general/InitIsGenerator.qlref new file mode 100644 index 00000000000..a3df140ff1e --- /dev/null +++ b/python/ql/test/query-tests/Functions/general/InitIsGenerator.qlref @@ -0,0 +1 @@ +Functions/InitIsGenerator.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Functions/general/IterReturnsNonIterator.expected b/python/ql/test/query-tests/Functions/general/IterReturnsNonIterator.expected new file mode 100644 index 00000000000..0fbb62b7aa8 --- /dev/null +++ b/python/ql/test/query-tests/Functions/general/IterReturnsNonIterator.expected @@ -0,0 +1 @@ +| protocols.py:16:5:16:23 | Function __iter__ | The '__iter__' method of iterable class $@ does not return an iterator. | protocols.py:14:1:14:16 | class X | X | diff --git a/python/ql/test/query-tests/Functions/general/IterReturnsNonIterator.qlref b/python/ql/test/query-tests/Functions/general/IterReturnsNonIterator.qlref new file mode 100644 index 00000000000..3d0965f7b11 --- /dev/null +++ b/python/ql/test/query-tests/Functions/general/IterReturnsNonIterator.qlref @@ -0,0 +1 @@ +Functions/IterReturnsNonIterator.ql diff --git a/python/ql/test/query-tests/Functions/general/IterReturnsNonSelf.expected b/python/ql/test/query-tests/Functions/general/IterReturnsNonSelf.expected new file mode 100644 index 00000000000..88c2e672db8 --- /dev/null +++ b/python/ql/test/query-tests/Functions/general/IterReturnsNonSelf.expected @@ -0,0 +1 @@ +| protocols.py:22:1:22:29 | class AlmostIterator | Class AlmostIterator is an iterator but its $@ method does not return 'self'. | protocols.py:30:5:30:23 | Function __iter__ | __iter__ | diff --git a/python/ql/test/query-tests/Functions/general/IterReturnsNonSelf.qlref b/python/ql/test/query-tests/Functions/general/IterReturnsNonSelf.qlref new file mode 100644 index 00000000000..b806215d26c --- /dev/null +++ b/python/ql/test/query-tests/Functions/general/IterReturnsNonSelf.qlref @@ -0,0 +1 @@ +Functions/IterReturnsNonSelf.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Functions/general/ModificationOfParameterWithDefault.expected b/python/ql/test/query-tests/Functions/general/ModificationOfParameterWithDefault.expected new file mode 100644 index 00000000000..520b55ea3c2 --- /dev/null +++ b/python/ql/test/query-tests/Functions/general/ModificationOfParameterWithDefault.expected @@ -0,0 +1,2 @@ +| functions_test.py:40:5:40:17 | Attribute() | Modification of parameter $@, which has mutable default value. | functions_test.py:39:9:39:9 | Parameter | x | +| functions_test.py:239:5:239:14 | AugAssign | Modification of parameter $@, which has mutable default value. | functions_test.py:238:15:238:15 | Parameter | x | diff --git a/python/ql/test/query-tests/Functions/general/ModificationOfParameterWithDefault.qlref b/python/ql/test/query-tests/Functions/general/ModificationOfParameterWithDefault.qlref new file mode 100644 index 00000000000..8c4044e8fee --- /dev/null +++ b/python/ql/test/query-tests/Functions/general/ModificationOfParameterWithDefault.qlref @@ -0,0 +1 @@ +Functions/ModificationOfParameterWithDefault.ql diff --git a/python/ql/test/query-tests/Functions/general/NonCls.expected b/python/ql/test/query-tests/Functions/general/NonCls.expected new file mode 100644 index 00000000000..da955e6f353 --- /dev/null +++ b/python/ql/test/query-tests/Functions/general/NonCls.expected @@ -0,0 +1,2 @@ +| functions_test.py:100:5:100:24 | Function n_cmethod | Class methods or methods of a type deriving from type should have 'cls', rather than 'self', as their first argument. | +| functions_test.py:114:5:114:20 | Function c_method | Class methods or methods of a type deriving from type should have 'cls', rather than 'y', as their first argument. | diff --git a/python/ql/test/query-tests/Functions/general/NonCls.qlref b/python/ql/test/query-tests/Functions/general/NonCls.qlref new file mode 100644 index 00000000000..b3525b101df --- /dev/null +++ b/python/ql/test/query-tests/Functions/general/NonCls.qlref @@ -0,0 +1 @@ +Functions/NonCls.ql diff --git a/python/ql/test/query-tests/Functions/general/NonSelf.expected b/python/ql/test/query-tests/Functions/general/NonSelf.expected new file mode 100644 index 00000000000..1bb0993593d --- /dev/null +++ b/python/ql/test/query-tests/Functions/general/NonSelf.expected @@ -0,0 +1,3 @@ +| functions_test.py:130:5:130:20 | Function __init__ | Normal methods should have 'self', rather than 'x', as their first parameter. | +| functions_test.py:133:5:133:20 | Function s_method | Normal methods should have 'self', rather than 'y', as their first parameter. | +| om_test.py:71:5:71:19 | Function __repr__ | Normal methods should have at least one parameter (the first of which should be 'self'). | diff --git a/python/ql/test/query-tests/Functions/general/NonSelf.qlref b/python/ql/test/query-tests/Functions/general/NonSelf.qlref new file mode 100644 index 00000000000..2629570c2a1 --- /dev/null +++ b/python/ql/test/query-tests/Functions/general/NonSelf.qlref @@ -0,0 +1 @@ +Functions/NonSelf.ql diff --git a/python/ql/test/query-tests/Functions/general/OverlyComplexDelMethod.expected b/python/ql/test/query-tests/Functions/general/OverlyComplexDelMethod.expected new file mode 100644 index 00000000000..9eb184f57ba --- /dev/null +++ b/python/ql/test/query-tests/Functions/general/OverlyComplexDelMethod.expected @@ -0,0 +1 @@ +| protocols.py:42:5:42:22 | Function __del__ | Overly complex '__del__' method. | diff --git a/python/ql/test/query-tests/Functions/general/OverlyComplexDelMethod.qlref b/python/ql/test/query-tests/Functions/general/OverlyComplexDelMethod.qlref new file mode 100644 index 00000000000..601501aac30 --- /dev/null +++ b/python/ql/test/query-tests/Functions/general/OverlyComplexDelMethod.qlref @@ -0,0 +1 @@ +Functions/OverlyComplexDelMethod.ql diff --git a/python/ql/test/query-tests/Functions/general/SignatureOverriddenMethod.expected b/python/ql/test/query-tests/Functions/general/SignatureOverriddenMethod.expected new file mode 100644 index 00000000000..f23936e6a42 --- /dev/null +++ b/python/ql/test/query-tests/Functions/general/SignatureOverriddenMethod.expected @@ -0,0 +1,2 @@ +| om_test.py:32:5:32:35 | Function grossly_wrong1 | Overriding method 'grossly_wrong1' has signature mismatch with $@. | om_test.py:12:5:12:41 | Function grossly_wrong1 | overridden method | +| om_test.py:35:5:35:47 | Function grossly_wrong2 | Overriding method 'grossly_wrong2' has signature mismatch with $@. | om_test.py:15:5:15:41 | Function grossly_wrong2 | overridden method | diff --git a/python/ql/test/query-tests/Functions/general/SignatureOverriddenMethod.qlref b/python/ql/test/query-tests/Functions/general/SignatureOverriddenMethod.qlref new file mode 100644 index 00000000000..a306477b3b4 --- /dev/null +++ b/python/ql/test/query-tests/Functions/general/SignatureOverriddenMethod.qlref @@ -0,0 +1 @@ +Functions/SignatureOverriddenMethod.ql diff --git a/python/ql/test/query-tests/Functions/general/SignatureSpecialMethods.expected b/python/ql/test/query-tests/Functions/general/SignatureSpecialMethods.expected new file mode 100644 index 00000000000..d26ae70958e --- /dev/null +++ b/python/ql/test/query-tests/Functions/general/SignatureSpecialMethods.expected @@ -0,0 +1,9 @@ +| om_test.py:59:5:59:28 | Function __div__ | Too many parameters for special method __div__, which has 3 parameters, but should have 2, in class $@. | om_test.py:57:1:57:28 | class WrongSpecials | WrongSpecials | +| om_test.py:62:5:62:22 | Function __mul__ | Too few parameters for special method __mul__, which has 1 parameter, but should have 2, in class $@. | om_test.py:57:1:57:28 | class WrongSpecials | WrongSpecials | +| om_test.py:65:5:65:29 | Function __neg__ | Too many parameters for special method __neg__, which has 2 parameters, but should have 1, in class $@. | om_test.py:57:1:57:28 | class WrongSpecials | WrongSpecials | +| om_test.py:68:5:68:35 | Function __exit__ | Too few parameters for special method __exit__, which has 3 parameters, but should have 4, in class $@. | om_test.py:57:1:57:28 | class WrongSpecials | WrongSpecials | +| om_test.py:71:5:71:19 | Function __repr__ | Too few parameters for special method __repr__, which has no parameters, but should have 1, in class $@. | om_test.py:57:1:57:28 | class WrongSpecials | WrongSpecials | +| om_test.py:74:5:74:46 | Function __add__ | 1 default values(s) will never be used for special method __add__, in class $@. | om_test.py:57:1:57:28 | class WrongSpecials | WrongSpecials | +| om_test.py:97:15:97:34 | Function lambda | Too few parameters for special method __sub__, which has 1 parameter, but should have 2, in class $@. | om_test.py:95:1:95:28 | class NotOKSpecials | NotOKSpecials | +| protocols.py:72:1:72:12 | Function f | Too few parameters for special method __add__, which has 1 parameter, but should have 2, in class $@. | protocols.py:75:1:75:29 | class MissingMethods | MissingMethods | +| protocols.py:72:1:72:12 | Function f | Too few parameters for special method __set__, which has 1 parameter, but should have 3, in class $@. | protocols.py:75:1:75:29 | class MissingMethods | MissingMethods | diff --git a/python/ql/test/query-tests/Functions/general/SignatureSpecialMethods.qlref b/python/ql/test/query-tests/Functions/general/SignatureSpecialMethods.qlref new file mode 100644 index 00000000000..bc1b29b6c0d --- /dev/null +++ b/python/ql/test/query-tests/Functions/general/SignatureSpecialMethods.qlref @@ -0,0 +1 @@ +Functions/SignatureSpecialMethods.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Functions/general/functions_test.py b/python/ql/test/query-tests/Functions/general/functions_test.py new file mode 100644 index 00000000000..71fea62a737 --- /dev/null +++ b/python/ql/test/query-tests/Functions/general/functions_test.py @@ -0,0 +1,288 @@ + +#Consistent Returns + +__all__ = [ '' ] + +def ok1(x): + if x: + return None + else: + return + +def ok2(x): + if x: + return 4 + else: + return "Hi" + +def cr1(x): + if x: + return 4 + +def cr2(x): + if x: + return 4 + else: + return + +def ok3(x): + try: + return + finally: + do_something() + +#Modification of parameter with default + +def ok4(x = []): + return len(x) + +def mpd(x = []): + x.append("x") + +class ExplicitReturnInInit(object): + + def __init__(self): + return self + +#These are OK +class ExplicitReturnNoneInInit(object): + + def __init__(self): + return None + +class PlainReturnInInit(object): + + def __init__(self): + return + +def error(): + raise Exception() + +class InitCallsError(object): + + def __init__(self): + return error() + +class InitCallsInit(InitCallsError): + + def __init__(self): + return InitCallsError.__init__(self) + +class InitIsGenerator(object): + + def __init__(self): + yield self + +def use_implicit_return_value(arg): + x = do_nothing() + return call_non_callable(arg) + +#The return in the lambda is OK as it is auto-generated +y = lambda x : do_nothing() + +def do_nothing(): + pass + +#Using name other than 'cls' for first parameter in methods. +# This shouldn't apply to classmethods (first parameter should be 'cls' or similar) +# or static methods (first parameter can be anything) + +class Normal(object): + + def n_ok(self): + pass + + @staticmethod + def n_smethod(ok): + pass + + @classmethod + def n_cmethod(self): + pass + + # this is allowed because it has a decorator other than @classmethod + @classmethod + @id + def n_suppress(any_name): + pass + +class Class(type): + + def __init__(cls): + pass + + def c_method(y): + pass + + def c_ok(cls): + pass + + @id + def c_suppress(any_name): + pass + +#Using name other than 'self' for first parameter in methods. +# This shouldn't apply to classmethods (first parameter should be 'cls' or similar) +# or static methods (first parameter can be anything) + +class NonSelf(object): + + def __init__(x): + pass + + def s_method(y): + pass + + def s_ok(self): + pass + + @staticmethod + def s_smethod(ok): + pass + + @classmethod + def s_cmethod(cls): + pass + + def s_smethod2(ok): + pass + s_smethod2 = staticmethod(s_smethod2) + + def s_cmethod2(cls): + pass + s_cmethod2 = classmethod(s_cmethod2) + +def returns_self(self): + return self + +def return_value_ignored(): + ok2() + ok4() + sorted([1,2]) + +d = {} + +def use_return_values(): + x = ok2() + x = ok2() + x = ok3() + x = ok3() + x = ok4() + x = ok4() + x = y() + x = y() + x = returns_self() + x = returns_self() + x = sorted(x) + x = sorted(x) + x = ok2() + x = ok2() + x = ok3() + x = ok3() + x = ok4() + x = ok4() + x = y() + x = y() + x = returns_self() + x = returns_self() + x = sorted(x) + x = sorted(x) + +def ok_to_ignore(): + ok1 + do_nothing() + returns_self() + ok3() + y() + +class DeprecatedSliceMethods(object): + + def __getslice__(self, start, stop): + pass + + def __setslice__(self, start, stop, value): + pass + + def __delslice__(self, start, stop): + pass + + + +@decorator +def nested_call_implicit_return_func_ok(arg): + do_nothing() + + + + + + +#OK as it returns result of a call to super().__init__() +class InitCallsInit(InitCallsError): + + def __init__(self): + return super(InitCallsInit, self).__init__() + +#Harmless, so we allow it. +def use_implicit_return_value_ok(arg): + return do_nothing() + +def mutli_return(arg): + if arg: + return do_something() + else: + return do_nothing() + +#Modification of parameter with default + +def augassign(x = []): + x += ["x"] + + +#Possible FPs for non-self. ODASA-2439 + +class C(object): + def _func(f): + return f + + _func(x) + + #or + @_func + def meth(self): + pass + + +def dont_care(arg): + pass + +class C(object): + + meth = dont_care + +class Meta(type): + + #__new__ is an implicit class method, so the first arg is the metaclass + def __new__(metacls, name, bases, cls_dict): + return super(Meta, metacls).__new__(metacls, name, bases, cls_dict) + +#ODASA 3658 +from sys import exit +#Consistent returns +def ok5(): + try: + may_raise() + return 0 + except ValueError as e: + print(e) + exit(EXIT_ERROR) + +#ODASA-6062 +import zope.interface +class Z(zope.interface.Interface): + + def meth(arg): + pass + +Z().meth(0) + diff --git a/python/ql/test/query-tests/Functions/general/mox.py b/python/ql/test/query-tests/Functions/general/mox.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/query-tests/Functions/general/om_test.py b/python/ql/test/query-tests/Functions/general/om_test.py new file mode 100644 index 00000000000..cbee20625aa --- /dev/null +++ b/python/ql/test/query-tests/Functions/general/om_test.py @@ -0,0 +1,107 @@ + +#Signature overridden wrong + +class Base(object): + + def ok1(self, arg1, arg2 = 2): + return arg1, arg2 + + def ok2(self, arg1, arg2 = 2): + return arg1, arg2 + + def grossly_wrong1(self, arg1, arg2): + return arg1, arg2 + + def grossly_wrong2(self, arg1, arg2): + return arg1, arg2 + + def strictly_wrong1(self, arg1, arg2 = 2): + return arg1, arg2 + + def strictly_wrong2(self, arg1, arg2 = 2): + return arg1, arg2 + +class Derived(Base): + + def ok1(self, arg1, arg2 = 2): + return arg1, arg2 + + def ok2(self, arg1, arg2 = 2, arg3 = 3): + return arg1, arg2, arg3 + + def grossly_wrong1(self, arg1): + return arg1 + + def grossly_wrong2(self, arg1, arg2, arg3): + return arg1, arg2, arg3 + + def strictly_wrong1(self, arg1): + return arg1 + + def strictly_wrong2(self, arg1, arg2, arg3 = 3): + return arg1, arg2, arg3 + +#Special method signatures + +class Special(object): + + def __add__(self, x): + return self, x + + def __pos__(self): + return self + + def __str__(self): + return repr(self) + +class WrongSpecials(object): + + def __div__(self, x, y): + return self, x, y + + def __mul__(self): + return self + + def __neg__(self, other): + return self, other + + def __exit__(self, arg0, arg1): + return arg0 == arg1 + + def __repr__(): + pass + + def __add__(self, other="Unused default"): + pass + + @staticmethod + def __abs__(): + return 42 + +class OKSpecials(object): + + def __del__(): + state = some_state() + + def __del__(self): + use_the_state(state) + + return __del__ + + __del__ = __del__() + + __add__ = lambda x, y : do_add(x, y) + +class NotOKSpecials(object): + + __sub__ = lambda x : do_neg(x) + +#Correctly overridden builtin method +class LoggingDict(dict): + + def pop(self): + print("pop") + return dict.pop(self) + + + diff --git a/python/ql/test/query-tests/Functions/general/protocols.py b/python/ql/test/query-tests/Functions/general/protocols.py new file mode 100644 index 00000000000..739dda00e45 --- /dev/null +++ b/python/ql/test/query-tests/Functions/general/protocols.py @@ -0,0 +1,90 @@ + +class Iterator: + #Support both 2 and 3 protocol + + def __next__(self): + pass + + def next(self): + pass + + def __iter__(self): + return self + +class X(object): + + def __iter__(self): + return object() + + +#Iterator not returning self + +class AlmostIterator(object): + + def __next__(self): + pass + + def next(self): + pass + + def __iter__(self): + return X.Xiter(X()) + +class AlmostIterable(object): + + def __iter__(self): + return AlmostIterator() + +#Overly complex __del__ method + +class MegaDel(object): + + def __del__(self): + a = self.x + self.y + if a: + print(a) + if sys._getframe().f_lineno > 100: + print("Hello") + sum = 0 + for a in range(100): + sum += a + print(sum) + +class MiniDel(object): + + def close(self): + pass + + def __del__(self): + self.close() + +class IncorrectSpecialMethods(object): + + def __add__(self, other): + raise NotImplementedError() + + def __getitem__(self, index): + raise ZeroDivisionError() + + def __getattr__(self): + raise ZeroDivisionError() + +def f(self): + pass + +class MissingMethods(object): + + __repr__ = f # This should be OK + __add__ = f # But not this + __set__ = f # or this + +#OK Special method +class OK(object): + + def __call__(self): + yield 0 + raise StopIteration + + + + diff --git a/python/ql/test/query-tests/Functions/general/special.py b/python/ql/test/query-tests/Functions/general/special.py new file mode 100644 index 00000000000..e555e392316 --- /dev/null +++ b/python/ql/test/query-tests/Functions/general/special.py @@ -0,0 +1,15 @@ + +#Special +class C(object): + + def __init__(self): + pass + + def __enter__(self): + pass + + def __exit__(self, *args): + pass + + def __get__(self, *args): + pass \ No newline at end of file diff --git a/python/ql/test/query-tests/Functions/general/use_mox.py b/python/ql/test/query-tests/Functions/general/use_mox.py new file mode 100644 index 00000000000..cc150120504 --- /dev/null +++ b/python/ql/test/query-tests/Functions/general/use_mox.py @@ -0,0 +1,11 @@ +import mox + +#Use mox +mox + +def f(): + pass + +#This may be OK as it might be mocked + +f().AndReturns("Something") diff --git a/python/ql/test/query-tests/Functions/general/zope/__init__.py b/python/ql/test/query-tests/Functions/general/zope/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/query-tests/Functions/general/zope/interface.py b/python/ql/test/query-tests/Functions/general/zope/interface.py new file mode 100644 index 00000000000..05def283197 --- /dev/null +++ b/python/ql/test/query-tests/Functions/general/zope/interface.py @@ -0,0 +1,6 @@ +#Fake zope.interface Module + +class InterfaceClass(type): + pass + +Interface = InterfaceClass() diff --git a/python/ql/test/query-tests/Functions/overriding/IncorrectlyOverriddenMethod.expected b/python/ql/test/query-tests/Functions/overriding/IncorrectlyOverriddenMethod.expected new file mode 100644 index 00000000000..92276ba22f0 --- /dev/null +++ b/python/ql/test/query-tests/Functions/overriding/IncorrectlyOverriddenMethod.expected @@ -0,0 +1,6 @@ +| test.py:24:5:24:26 | Function meth1 | Overriding method signature does not match $@, where it is passed too few. Overridden method $@ is correctly specified. | test.py:15:9:15:20 | Attribute() | here | test.py:5:5:5:20 | Function meth1 | method Base.meth1 | +| test.py:24:5:24:26 | Function meth1 | Overriding method signature does not match $@, where it is passed too few. Overridden method $@ is correctly specified. | test.py:34:9:34:20 | Attribute() | here | test.py:5:5:5:20 | Function meth1 | method Base.meth1 | +| test.py:27:5:27:20 | Function meth2 | Overriding method signature does not match $@, where it is passed an argument named 'spam'. Overridden method $@ is correctly specified. | test.py:20:9:20:31 | Attribute() | here | test.py:8:5:8:26 | Function meth2 | method Base.meth2 | +| test.py:27:5:27:20 | Function meth2 | Overriding method signature does not match $@, where it is passed an argument named 'spam'. Overridden method $@ is correctly specified. | test.py:39:9:39:31 | Attribute() | here | test.py:8:5:8:26 | Function meth2 | method Base.meth2 | +| test.py:27:5:27:20 | Function meth2 | Overriding method signature does not match $@, where it is passed too many. Overridden method $@ is correctly specified. | test.py:18:9:18:21 | Attribute() | here | test.py:8:5:8:26 | Function meth2 | method Base.meth2 | +| test.py:27:5:27:20 | Function meth2 | Overriding method signature does not match $@, where it is passed too many. Overridden method $@ is correctly specified. | test.py:37:9:37:21 | Attribute() | here | test.py:8:5:8:26 | Function meth2 | method Base.meth2 | diff --git a/python/ql/test/query-tests/Functions/overriding/IncorrectlyOverriddenMethod.qlref b/python/ql/test/query-tests/Functions/overriding/IncorrectlyOverriddenMethod.qlref new file mode 100644 index 00000000000..d1637c1f1d3 --- /dev/null +++ b/python/ql/test/query-tests/Functions/overriding/IncorrectlyOverriddenMethod.qlref @@ -0,0 +1 @@ +Functions/IncorrectlyOverriddenMethod.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Functions/overriding/IncorrectlySpecifiedOverriddenMethod.expected b/python/ql/test/query-tests/Functions/overriding/IncorrectlySpecifiedOverriddenMethod.expected new file mode 100644 index 00000000000..527ad805604 --- /dev/null +++ b/python/ql/test/query-tests/Functions/overriding/IncorrectlySpecifiedOverriddenMethod.expected @@ -0,0 +1,9 @@ +| test.py:5:5:5:20 | Function meth1 | Overridden method signature does not match $@, where it is passed an argument named 'spam'. Overriding method $@ matches the call. | test.py:19:9:19:31 | Attribute() | call | test.py:24:5:24:26 | Function meth1 | method Derived.meth1 | +| test.py:5:5:5:20 | Function meth1 | Overridden method signature does not match $@, where it is passed an argument named 'spam'. Overriding method $@ matches the call. | test.py:38:9:38:31 | Attribute() | call | test.py:24:5:24:26 | Function meth1 | method Derived.meth1 | +| test.py:5:5:5:20 | Function meth1 | Overridden method signature does not match $@, where it is passed too many arguments. Overriding method $@ matches the call. | test.py:16:9:16:21 | Attribute() | call | test.py:24:5:24:26 | Function meth1 | method Derived.meth1 | +| test.py:5:5:5:20 | Function meth1 | Overridden method signature does not match $@, where it is passed too many arguments. Overriding method $@ matches the call. | test.py:19:9:19:31 | Attribute() | call | test.py:24:5:24:26 | Function meth1 | method Derived.meth1 | +| test.py:5:5:5:20 | Function meth1 | Overridden method signature does not match $@, where it is passed too many arguments. Overriding method $@ matches the call. | test.py:35:9:35:21 | Attribute() | call | test.py:24:5:24:26 | Function meth1 | method Derived.meth1 | +| test.py:5:5:5:20 | Function meth1 | Overridden method signature does not match $@, where it is passed too many arguments. Overriding method $@ matches the call. | test.py:38:9:38:31 | Attribute() | call | test.py:24:5:24:26 | Function meth1 | method Derived.meth1 | +| test.py:8:5:8:26 | Function meth2 | Overridden method signature does not match $@, where it is passed too few arguments. Overriding method $@ matches the call. | test.py:17:9:17:20 | Attribute() | call | test.py:27:5:27:20 | Function meth2 | method Derived.meth2 | +| test.py:8:5:8:26 | Function meth2 | Overridden method signature does not match $@, where it is passed too few arguments. Overriding method $@ matches the call. | test.py:36:9:36:20 | Attribute() | call | test.py:27:5:27:20 | Function meth2 | method Derived.meth2 | +| test.py:64:5:64:19 | Function meth | Overridden method signature does not match $@, where it is passed too many arguments. Overriding method $@ matches the call. | test.py:78:1:78:12 | Attribute() | call | test.py:74:5:74:24 | Function meth | method Correct2.meth | diff --git a/python/ql/test/query-tests/Functions/overriding/IncorrectlySpecifiedOverriddenMethod.qlref b/python/ql/test/query-tests/Functions/overriding/IncorrectlySpecifiedOverriddenMethod.qlref new file mode 100644 index 00000000000..8a07cb1297e --- /dev/null +++ b/python/ql/test/query-tests/Functions/overriding/IncorrectlySpecifiedOverriddenMethod.qlref @@ -0,0 +1 @@ +Functions/IncorrectlySpecifiedOverriddenMethod.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Functions/overriding/SignatureOverriddenMethod.expected b/python/ql/test/query-tests/Functions/overriding/SignatureOverriddenMethod.expected new file mode 100644 index 00000000000..99f0fb667d6 --- /dev/null +++ b/python/ql/test/query-tests/Functions/overriding/SignatureOverriddenMethod.expected @@ -0,0 +1 @@ +| test.py:30:5:30:26 | Function meth3 | Overriding method 'meth3' has signature mismatch with $@. | test.py:11:5:11:20 | Function meth3 | overridden method | diff --git a/python/ql/test/query-tests/Functions/overriding/SignatureOverriddenMethod.qlref b/python/ql/test/query-tests/Functions/overriding/SignatureOverriddenMethod.qlref new file mode 100644 index 00000000000..a306477b3b4 --- /dev/null +++ b/python/ql/test/query-tests/Functions/overriding/SignatureOverriddenMethod.qlref @@ -0,0 +1 @@ +Functions/SignatureOverriddenMethod.ql diff --git a/python/ql/test/query-tests/Functions/overriding/WrongNameForArgumentInCall.expected b/python/ql/test/query-tests/Functions/overriding/WrongNameForArgumentInCall.expected new file mode 100644 index 00000000000..d2fc2ef6784 --- /dev/null +++ b/python/ql/test/query-tests/Functions/overriding/WrongNameForArgumentInCall.expected @@ -0,0 +1 @@ +| test.py:19:9:19:31 | Attribute() | Keyword argument 'spam' is not a supported parameter name of $@. | test.py:5:5:5:20 | Function meth1 | method Base.meth1 | diff --git a/python/ql/test/query-tests/Functions/overriding/WrongNameForArgumentInCall.qlref b/python/ql/test/query-tests/Functions/overriding/WrongNameForArgumentInCall.qlref new file mode 100644 index 00000000000..3599f204f55 --- /dev/null +++ b/python/ql/test/query-tests/Functions/overriding/WrongNameForArgumentInCall.qlref @@ -0,0 +1 @@ +Expressions/WrongNameForArgumentInCall.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Functions/overriding/WrongNumberArgumentsInCall.expected b/python/ql/test/query-tests/Functions/overriding/WrongNumberArgumentsInCall.expected new file mode 100644 index 00000000000..4f29401ce5b --- /dev/null +++ b/python/ql/test/query-tests/Functions/overriding/WrongNumberArgumentsInCall.expected @@ -0,0 +1,2 @@ +| test.py:16:9:16:21 | Attribute() | Call to $@ with too many arguments; should be no more than 0. | test.py:5:5:5:20 | Function meth1 | method Base.meth1 | +| test.py:17:9:17:20 | Attribute() | Call to $@ with too few arguments; should be no fewer than 1. | test.py:8:5:8:26 | Function meth2 | method Base.meth2 | diff --git a/python/ql/test/query-tests/Functions/overriding/WrongNumberArgumentsInCall.qlref b/python/ql/test/query-tests/Functions/overriding/WrongNumberArgumentsInCall.qlref new file mode 100644 index 00000000000..1bffe8f1cad --- /dev/null +++ b/python/ql/test/query-tests/Functions/overriding/WrongNumberArgumentsInCall.qlref @@ -0,0 +1 @@ +Expressions/WrongNumberArgumentsInCall.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Functions/overriding/test.py b/python/ql/test/query-tests/Functions/overriding/test.py new file mode 100644 index 00000000000..c4c7caaa1aa --- /dev/null +++ b/python/ql/test/query-tests/Functions/overriding/test.py @@ -0,0 +1,78 @@ + + +class Base(object): + + def meth1(self): + pass + + def meth2(self, spam): + pass + + def meth3(self): + pass + + def foo(self): + self.meth1() + self.meth1(0) + self.meth2() + self.meth2(0) + self.meth1(spam="eggs") + self.meth2(spam="eggs") + +class Derived(Base): + + def meth1(self, spam): + pass + + def meth2(self): + pass + + def meth3(self, eggs): #Incorrectly overridden and not called. + pass + + def bar(self): + self.meth1() # Can only call Derived.meth1 so report as incorrect number of arguments + self.meth1(0) + self.meth2() + self.meth2(0) # Can only call Derived.meth2 so report as incorrect number of arguments + self.meth1(spam="eggs") + self.meth2(spam="eggs") + self.foo() + +d = Derived() +d.meth1 + +class Abstract(object): + + def meth(self): + raise NotImplementedError() + + +class Concrete(object): + + def meth(self, arg): + pass + + +#Attempt to fool analysis +x = Abstract() if cond else Concrete() +x.meth("hi") + + +class BlameBase(object): + + def meth(self): + pass + +class Correct1(BlameBase): + + def meth(self, arg): + pass + +class Correct2(BlameBase): + + def meth(self, arg): + pass + +c = Correct2() +c.meth("hi") diff --git a/python/ql/test/query-tests/Functions/return_values/ConsistentReturns.expected b/python/ql/test/query-tests/Functions/return_values/ConsistentReturns.expected new file mode 100644 index 00000000000..7c0bad373b3 --- /dev/null +++ b/python/ql/test/query-tests/Functions/return_values/ConsistentReturns.expected @@ -0,0 +1,2 @@ +| functions_test.py:18:1:18:11 | Function cr1 | Mixing implicit and explicit returns may indicate an error as implicit returns always return None. | +| functions_test.py:22:1:22:11 | Function cr2 | Mixing implicit and explicit returns may indicate an error as implicit returns always return None. | diff --git a/python/ql/test/query-tests/Functions/return_values/ConsistentReturns.qlref b/python/ql/test/query-tests/Functions/return_values/ConsistentReturns.qlref new file mode 100644 index 00000000000..0904074f25b --- /dev/null +++ b/python/ql/test/query-tests/Functions/return_values/ConsistentReturns.qlref @@ -0,0 +1 @@ +Functions/ConsistentReturns.ql diff --git a/python/ql/test/query-tests/Functions/return_values/ReturnConsistentTupleSizes.expected b/python/ql/test/query-tests/Functions/return_values/ReturnConsistentTupleSizes.expected new file mode 100644 index 00000000000..fd4f1ee2dd7 --- /dev/null +++ b/python/ql/test/query-tests/Functions/return_values/ReturnConsistentTupleSizes.expected @@ -0,0 +1,2 @@ +| functions_test.py:306:1:306:39 | Function returning_different_tuple_sizes | returning_different_tuple_sizes returns $@ and $@. | functions_test.py:308:16:308:18 | Tuple | tuple of size 2 | functions_test.py:310:16:310:20 | Tuple | tuple of size 3 | +| functions_test.py:324:1:324:50 | Function indirectly_returning_different_tuple_sizes | indirectly_returning_different_tuple_sizes returns $@ and $@. | functions_test.py:319:12:319:14 | Tuple | tuple of size 2 | functions_test.py:322:12:322:16 | Tuple | tuple of size 3 | diff --git a/python/ql/test/query-tests/Functions/return_values/ReturnConsistentTupleSizes.qlref b/python/ql/test/query-tests/Functions/return_values/ReturnConsistentTupleSizes.qlref new file mode 100644 index 00000000000..c91661b33cf --- /dev/null +++ b/python/ql/test/query-tests/Functions/return_values/ReturnConsistentTupleSizes.qlref @@ -0,0 +1 @@ +Functions/ReturnConsistentTupleSizes.ql diff --git a/python/ql/test/query-tests/Functions/return_values/ReturnValueIgnored.expected b/python/ql/test/query-tests/Functions/return_values/ReturnValueIgnored.expected new file mode 100644 index 00000000000..60640bb96ba --- /dev/null +++ b/python/ql/test/query-tests/Functions/return_values/ReturnValueIgnored.expected @@ -0,0 +1,3 @@ +| functions_test.py:159:5:159:9 | ExprStmt | Call discards return value of function $@. The result is used in 80% of calls. | functions_test.py:12:1:12:11 | Function ok2 | ok2 | +| functions_test.py:160:5:160:9 | ExprStmt | Call discards return value of function $@. The result is used in 80% of calls. | functions_test.py:36:1:36:11 | Function ok4 | ok4 | +| functions_test.py:161:5:161:17 | ExprStmt | Call discards return value of function $@. The result is used in 80% of calls. | file://:Compiled Code:0:0:0:0 | Builtin-function sorted | sorted | diff --git a/python/ql/test/query-tests/Functions/return_values/ReturnValueIgnored.qlref b/python/ql/test/query-tests/Functions/return_values/ReturnValueIgnored.qlref new file mode 100644 index 00000000000..61002533ef4 --- /dev/null +++ b/python/ql/test/query-tests/Functions/return_values/ReturnValueIgnored.qlref @@ -0,0 +1 @@ +Functions/ReturnValueIgnored.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Functions/return_values/UseImplicitNoneReturnValue.expected b/python/ql/test/query-tests/Functions/return_values/UseImplicitNoneReturnValue.expected new file mode 100644 index 00000000000..54a74971d37 --- /dev/null +++ b/python/ql/test/query-tests/Functions/return_values/UseImplicitNoneReturnValue.expected @@ -0,0 +1,2 @@ +| functions_test.py:77:9:77:20 | do_nothing() | The result of '$@' is used even though it is always None. | functions_test.py:83:1:83:17 | Function do_nothing | do_nothing | +| functions_test.py:234:16:234:27 | do_nothing() | The result of '$@' is used even though it is always None. | functions_test.py:83:1:83:17 | Function do_nothing | do_nothing | diff --git a/python/ql/test/query-tests/Functions/return_values/UseImplicitNoneReturnValue.qlref b/python/ql/test/query-tests/Functions/return_values/UseImplicitNoneReturnValue.qlref new file mode 100644 index 00000000000..b23115e8950 --- /dev/null +++ b/python/ql/test/query-tests/Functions/return_values/UseImplicitNoneReturnValue.qlref @@ -0,0 +1 @@ +Functions/UseImplicitNoneReturnValue.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Functions/return_values/functions_test.py b/python/ql/test/query-tests/Functions/return_values/functions_test.py new file mode 100644 index 00000000000..c8a7cf37734 --- /dev/null +++ b/python/ql/test/query-tests/Functions/return_values/functions_test.py @@ -0,0 +1,333 @@ + +#Consistent Returns + +__all__ = [ '' ] + +def ok1(x): + if x: + return None + else: + return + +def ok2(x): + if x: + return 4 + else: + return "Hi" + +def cr1(x): + if x: + return 4 + +def cr2(x): + if x: + return 4 + else: + return + +def ok3(x): + try: + return + finally: + do_something() + + + +def ok4(x): + return len(x) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +def use_implicit_return_value(arg): + x = do_nothing() + return call_non_callable(arg) + +#The return in the lambda is OK as it is auto-generated +y = lambda x : do_nothing() + +def do_nothing(): + pass + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +def return_value_ignored(): + ok2() + ok4() + sorted([1,2]) + +d = {} + +def use_return_values(): + x = ok2() + x = ok2() + x = ok3() + x = ok3() + x = ok4() + x = ok4() + x = y() + x = y() + x = returns_self() + x = returns_self() + x = sorted(x) + x = sorted(x) + x = ok2() + x = ok2() + x = ok3() + x = ok3() + x = ok4() + x = ok4() + x = y() + x = y() + x = returns_self() + x = returns_self() + x = sorted(x) + x = sorted(x) + +def ok_to_ignore(): + ok1 + do_nothing() + returns_self() + ok3() + y() + + + + + + + + + + + + + + +@decorator +def nested_call_implicit_return_func_ok(arg): + do_nothing() + + + + + + +#OK as it returns result of a call to super().__init__() +class InitCallsInit(InitCallsError): + + def __init__(self): + return super(InitCallsInit, self).__init__() + +#Harmless, so we allow it. +def use_implicit_return_value_ok(arg): + return do_nothing() + +def mutli_return(arg): + if arg: + return do_something() + else: + return do_nothing() + +#Modification of parameter with default + +def augassign(x = []): + x += ["x"] + + +#Possible FPs for non-self. ODASA-2439 + +class C(object): + def _func(f): + return f + + _func(x) + + #or + @_func + def meth(self): + pass + + +def dont_care(arg): + pass + +class C(object): + + meth = dont_care + +class Meta(type): + + #__new__ is an implicit class method, so the first arg is the metaclass + def __new__(metacls, name, bases, cls_dict): + return super(Meta, metacls).__new__(metacls, name, bases, cls_dict) + +#ODASA 3658 +from sys import exit +#Consistent returns +def ok5(): + try: + may_raise() + return 0 + except ValueError as e: + print(e) + exit(EXIT_ERROR) + + + +#ODASA-6514 +if unknown(): + def foo(x): + pass +else: + def foo(x): + return x+1 + +#This is OK since at least one of the `foo`s returns a value. +y = foo() + + + + + + + + + + + + +# Returning tuples with different sizes + +def returning_different_tuple_sizes(x): + if x: + return 1,2 + else: + return 1,2,3 + +def ok_tuple_sizes(x): + if x: + return 1,2 + else: + return 2,3 + +def function_returning_2_tuple(): + return 1,2 + +def function_returning_3_tuple(): + return 1,2,3 + +def indirectly_returning_different_tuple_sizes(x): + if x: + return function_returning_2_tuple() + else: + return function_returning_3_tuple() + + +def mismatched_multi_assign(x): + a,b = returning_different_tuple_sizes(x) + return a,b \ No newline at end of file diff --git a/python/ql/test/query-tests/Imports/PyCheckerTests/ImportandImportFrom.expected b/python/ql/test/query-tests/Imports/PyCheckerTests/ImportandImportFrom.expected new file mode 100644 index 00000000000..ca3e04150e2 --- /dev/null +++ b/python/ql/test/query-tests/Imports/PyCheckerTests/ImportandImportFrom.expected @@ -0,0 +1 @@ +| imports_test.py:4:1:4:19 | Import | Module 'test_module2' is imported with both 'import' and 'import from' | diff --git a/python/ql/test/query-tests/Imports/PyCheckerTests/ImportandImportFrom.qlref b/python/ql/test/query-tests/Imports/PyCheckerTests/ImportandImportFrom.qlref new file mode 100644 index 00000000000..3d50843db7e --- /dev/null +++ b/python/ql/test/query-tests/Imports/PyCheckerTests/ImportandImportFrom.qlref @@ -0,0 +1 @@ +Imports/ImportandImportFrom.ql diff --git a/python/ql/test/query-tests/Imports/PyCheckerTests/ModuleImportsItself.expected b/python/ql/test/query-tests/Imports/PyCheckerTests/ModuleImportsItself.expected new file mode 100644 index 00000000000..497c729b8ad --- /dev/null +++ b/python/ql/test/query-tests/Imports/PyCheckerTests/ModuleImportsItself.expected @@ -0,0 +1 @@ +| imports_test.py:8:1:8:19 | Import | The module 'imports_test' imports itself. | diff --git a/python/ql/test/query-tests/Imports/PyCheckerTests/ModuleImportsItself.qlref b/python/ql/test/query-tests/Imports/PyCheckerTests/ModuleImportsItself.qlref new file mode 100644 index 00000000000..e6bc27b3065 --- /dev/null +++ b/python/ql/test/query-tests/Imports/PyCheckerTests/ModuleImportsItself.qlref @@ -0,0 +1 @@ +Imports/ModuleImportsItself.ql diff --git a/python/ql/test/query-tests/Imports/PyCheckerTests/imports_test.py b/python/ql/test/query-tests/Imports/PyCheckerTests/imports_test.py new file mode 100644 index 00000000000..81ebbccd9d5 --- /dev/null +++ b/python/ql/test/query-tests/Imports/PyCheckerTests/imports_test.py @@ -0,0 +1,9 @@ + +#Import and import from + +import test_module2 +from test_module2 import func + +#Module imports itself +import imports_test + diff --git a/python/ql/test/query-tests/Imports/PyCheckerTests/test_module.py b/python/ql/test/query-tests/Imports/PyCheckerTests/test_module.py new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/python/ql/test/query-tests/Imports/PyCheckerTests/test_module.py @@ -0,0 +1 @@ + diff --git a/python/ql/test/query-tests/Imports/PyCheckerTests/test_module2.py b/python/ql/test/query-tests/Imports/PyCheckerTests/test_module2.py new file mode 100644 index 00000000000..94e8b95ac1f --- /dev/null +++ b/python/ql/test/query-tests/Imports/PyCheckerTests/test_module2.py @@ -0,0 +1,4 @@ + +def func(): + pass + diff --git a/python/ql/test/query-tests/Imports/cyclic-module/CyclicImport.expected b/python/ql/test/query-tests/Imports/cyclic-module/CyclicImport.expected new file mode 100644 index 00000000000..e5449848fdc --- /dev/null +++ b/python/ql/test/query-tests/Imports/cyclic-module/CyclicImport.expected @@ -0,0 +1,11 @@ +| module1.py:3:1:3:14 | Import | Import of module $@ begins an import cycle. | module3.py:0:0:0:0 | Module module3 | module3 | +| module1.py:9:1:9:14 | Import | Import of module $@ begins an import cycle. | module4.py:0:0:0:0 | Module module4 | module4 | +| module1.py:11:5:11:18 | Import | Import of module $@ begins an import cycle. | module5.py:0:0:0:0 | Module module5 | module5 | +| module1.py:14:1:14:14 | Import | Import of module $@ begins an import cycle. | module6.py:0:0:0:0 | Module module6 | module6 | +| module1.py:17:1:17:14 | Import | Import of module $@ begins an import cycle. | module8.py:0:0:0:0 | Module module8 | module8 | +| module4.py:1:1:1:14 | Import | Import of module $@ begins an import cycle. | module1.py:0:0:0:0 | Module module1 | module1 | +| module5.py:1:1:1:14 | Import | Import of module $@ begins an import cycle. | module1.py:0:0:0:0 | Module module1 | module1 | +| module6.py:2:5:2:18 | Import | Import of module $@ begins an import cycle. | module7.py:0:0:0:0 | Module module7 | module7 | +| module7.py:1:1:1:22 | Import | Import of module $@ begins an import cycle. | module1.py:0:0:0:0 | Module module1 | module1 | +| module8.py:1:1:1:14 | Import | Import of module $@ begins an import cycle. | module1.py:0:0:0:0 | Module module1 | module1 | +| module9.py:4:1:4:11 | Import | Import of module $@ begins an import cycle. | main.py:0:0:0:0 | Module main | main | diff --git a/python/ql/test/query-tests/Imports/cyclic-module/CyclicImport.qlref b/python/ql/test/query-tests/Imports/cyclic-module/CyclicImport.qlref new file mode 100644 index 00000000000..814bba9fad6 --- /dev/null +++ b/python/ql/test/query-tests/Imports/cyclic-module/CyclicImport.qlref @@ -0,0 +1 @@ +Imports/CyclicImport.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Imports/cyclic-module/ModuleLevelCyclicImport.expected b/python/ql/test/query-tests/Imports/cyclic-module/ModuleLevelCyclicImport.expected new file mode 100644 index 00000000000..dbdc671c385 --- /dev/null +++ b/python/ql/test/query-tests/Imports/cyclic-module/ModuleLevelCyclicImport.expected @@ -0,0 +1,3 @@ +| module1.py:5:6:5:15 | Attribute | 'a2' may not be defined if module $@ is imported before module $@, as the $@ of a2 occurs after the cyclic $@ of module1. | module2.py:0:0:0:0 | Module module2 | module2 | module1.py:0:0:0:0 | Module module1 | module1 | module2.py:4:1:4:2 | ControlFlowNode for a2 | definition | module2.py:1:1:1:14 | Import | import | +| module2.py:4:6:4:15 | Attribute | 'a1' may not be defined if module $@ is imported before module $@, as the $@ of a1 occurs after the cyclic $@ of module2. | module1.py:0:0:0:0 | Module module1 | module1 | module2.py:0:0:0:0 | Module module2 | module2 | module1.py:5:1:5:2 | ControlFlowNode for a1 | definition | module1.py:2:1:2:14 | Import | import | +| module3.py:2:21:2:22 | ImportMember | 'a1' may not be defined if module $@ is imported before module $@, as the $@ of a1 occurs after the cyclic $@ of module3. | module1.py:0:0:0:0 | Module module1 | module1 | module3.py:0:0:0:0 | Module module3 | module3 | module1.py:5:1:5:2 | ControlFlowNode for a1 | definition | module1.py:3:1:3:14 | Import | import | diff --git a/python/ql/test/query-tests/Imports/cyclic-module/ModuleLevelCyclicImport.qlref b/python/ql/test/query-tests/Imports/cyclic-module/ModuleLevelCyclicImport.qlref new file mode 100644 index 00000000000..5119f8fdaae --- /dev/null +++ b/python/ql/test/query-tests/Imports/cyclic-module/ModuleLevelCyclicImport.qlref @@ -0,0 +1 @@ +Imports/ModuleLevelCyclicImport.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Imports/cyclic-module/main.py b/python/ql/test/query-tests/Imports/cyclic-module/main.py new file mode 100644 index 00000000000..8da504e0406 --- /dev/null +++ b/python/ql/test/query-tests/Imports/cyclic-module/main.py @@ -0,0 +1,7 @@ + +a = 1 +b = 2 + +if __name__ == '__main__': + import module9 + print(module9.y) diff --git a/python/ql/test/query-tests/Imports/cyclic-module/module1.py b/python/ql/test/query-tests/Imports/cyclic-module/module1.py new file mode 100644 index 00000000000..55ef075e9e6 --- /dev/null +++ b/python/ql/test/query-tests/Imports/cyclic-module/module1.py @@ -0,0 +1,22 @@ +# potentially crashing cycles +import module2 +import module3 + +a1 = module2.a2 +b1 = 2 + +# bad style cycles +import module4 +def foo(): + import module5 + +# okay, because some of the cycle is not top level +import module6 + +# OK because this import occurs after relevant definition (a1) +import module8 + +#OK because cycle is guarded by `if False:` +from module10 import x + + diff --git a/python/ql/test/query-tests/Imports/cyclic-module/module10.py b/python/ql/test/query-tests/Imports/cyclic-module/module10.py new file mode 100644 index 00000000000..68127cc21fd --- /dev/null +++ b/python/ql/test/query-tests/Imports/cyclic-module/module10.py @@ -0,0 +1,5 @@ + +if False: + import module1 + +x = 1 diff --git a/python/ql/test/query-tests/Imports/cyclic-module/module2.py b/python/ql/test/query-tests/Imports/cyclic-module/module2.py new file mode 100644 index 00000000000..333b8516adb --- /dev/null +++ b/python/ql/test/query-tests/Imports/cyclic-module/module2.py @@ -0,0 +1,4 @@ +import module1 + +# direct use +a2 = module1.a1 \ No newline at end of file diff --git a/python/ql/test/query-tests/Imports/cyclic-module/module3.py b/python/ql/test/query-tests/Imports/cyclic-module/module3.py new file mode 100644 index 00000000000..2180fb54a28 --- /dev/null +++ b/python/ql/test/query-tests/Imports/cyclic-module/module3.py @@ -0,0 +1,2 @@ +# use via import member +from module1 import a1 \ No newline at end of file diff --git a/python/ql/test/query-tests/Imports/cyclic-module/module4.py b/python/ql/test/query-tests/Imports/cyclic-module/module4.py new file mode 100644 index 00000000000..65db406bb45 --- /dev/null +++ b/python/ql/test/query-tests/Imports/cyclic-module/module4.py @@ -0,0 +1 @@ +import module1 \ No newline at end of file diff --git a/python/ql/test/query-tests/Imports/cyclic-module/module5.py b/python/ql/test/query-tests/Imports/cyclic-module/module5.py new file mode 100644 index 00000000000..65db406bb45 --- /dev/null +++ b/python/ql/test/query-tests/Imports/cyclic-module/module5.py @@ -0,0 +1 @@ +import module1 \ No newline at end of file diff --git a/python/ql/test/query-tests/Imports/cyclic-module/module6.py b/python/ql/test/query-tests/Imports/cyclic-module/module6.py new file mode 100644 index 00000000000..5a5fcd149ac --- /dev/null +++ b/python/ql/test/query-tests/Imports/cyclic-module/module6.py @@ -0,0 +1,2 @@ +def foo(): + import module7 \ No newline at end of file diff --git a/python/ql/test/query-tests/Imports/cyclic-module/module7.py b/python/ql/test/query-tests/Imports/cyclic-module/module7.py new file mode 100644 index 00000000000..d0b18ba5894 --- /dev/null +++ b/python/ql/test/query-tests/Imports/cyclic-module/module7.py @@ -0,0 +1 @@ +from module1 import a1 \ No newline at end of file diff --git a/python/ql/test/query-tests/Imports/cyclic-module/module8.py b/python/ql/test/query-tests/Imports/cyclic-module/module8.py new file mode 100644 index 00000000000..185ee214da8 --- /dev/null +++ b/python/ql/test/query-tests/Imports/cyclic-module/module8.py @@ -0,0 +1,4 @@ +import module1 + +class Foo(object): + a = module1.a1 \ No newline at end of file diff --git a/python/ql/test/query-tests/Imports/cyclic-module/module9.py b/python/ql/test/query-tests/Imports/cyclic-module/module9.py new file mode 100644 index 00000000000..06ab5b93305 --- /dev/null +++ b/python/ql/test/query-tests/Imports/cyclic-module/module9.py @@ -0,0 +1,6 @@ + +x = 1 + +import main + +y = 2 \ No newline at end of file diff --git a/python/ql/test/query-tests/Imports/deprecated/DeprecatedModule.expected b/python/ql/test/query-tests/Imports/deprecated/DeprecatedModule.expected new file mode 100644 index 00000000000..11905b13d9c --- /dev/null +++ b/python/ql/test/query-tests/Imports/deprecated/DeprecatedModule.expected @@ -0,0 +1,2 @@ +| test.py:5:1:5:13 | Import | The rfc822 module was deprecated in version 2.3. Use email module instead. | +| test.py:6:1:6:16 | Import | The posixfile module was deprecated in version 1.5. Use email module instead. | diff --git a/python/ql/test/query-tests/Imports/deprecated/DeprecatedModule.qlref b/python/ql/test/query-tests/Imports/deprecated/DeprecatedModule.qlref new file mode 100644 index 00000000000..3444aa9d6f6 --- /dev/null +++ b/python/ql/test/query-tests/Imports/deprecated/DeprecatedModule.qlref @@ -0,0 +1 @@ +Imports/DeprecatedModule.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Imports/deprecated/test.py b/python/ql/test/query-tests/Imports/deprecated/test.py new file mode 100644 index 00000000000..ece57bb1855 --- /dev/null +++ b/python/ql/test/query-tests/Imports/deprecated/test.py @@ -0,0 +1,6 @@ + + + +#Some deprecated modules +import rfc822 +import posixfile diff --git a/python/ql/test/query-tests/Imports/general/FromImportOfMutableAttribute.expected b/python/ql/test/query-tests/Imports/general/FromImportOfMutableAttribute.expected new file mode 100644 index 00000000000..aa785201f24 --- /dev/null +++ b/python/ql/test/query-tests/Imports/general/FromImportOfMutableAttribute.expected @@ -0,0 +1 @@ +| imports_mutable.py:1:26:1:26 | ImportMember | Importing the value of 'x' from $@ means that any change made to $@ will be not be observed locally. | mutable_attr.py:0:0:0:0 | Module mutable_attr | module mutable_attr | mutates.py:4:5:4:18 | ControlFlowNode for Attribute | mutable_attr.x | diff --git a/python/ql/test/query-tests/Imports/general/FromImportOfMutableAttribute.qlref b/python/ql/test/query-tests/Imports/general/FromImportOfMutableAttribute.qlref new file mode 100644 index 00000000000..9353115309f --- /dev/null +++ b/python/ql/test/query-tests/Imports/general/FromImportOfMutableAttribute.qlref @@ -0,0 +1 @@ +Imports/FromImportOfMutableAttribute.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Imports/general/ImportShadowedByLoopVar.expected b/python/ql/test/query-tests/Imports/general/ImportShadowedByLoopVar.expected new file mode 100644 index 00000000000..562cc12c51e --- /dev/null +++ b/python/ql/test/query-tests/Imports/general/ImportShadowedByLoopVar.expected @@ -0,0 +1 @@ +| imports_test.py:16:5:16:10 | module | Loop variable 'module' shadows an import | diff --git a/python/ql/test/query-tests/Imports/general/ImportShadowedByLoopVar.qlref b/python/ql/test/query-tests/Imports/general/ImportShadowedByLoopVar.qlref new file mode 100644 index 00000000000..3844f21922f --- /dev/null +++ b/python/ql/test/query-tests/Imports/general/ImportShadowedByLoopVar.qlref @@ -0,0 +1 @@ +Imports/ImportShadowedByLoopVar.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Imports/general/ImportStarUsed.expected b/python/ql/test/query-tests/Imports/general/ImportStarUsed.expected new file mode 100644 index 00000000000..9aa101edbca --- /dev/null +++ b/python/ql/test/query-tests/Imports/general/ImportStarUsed.expected @@ -0,0 +1,2 @@ +| imports_test.py:21:1:21:20 | from module import * | Using 'from ... import *' pollutes the namespace | +| imports_test.py:22:1:22:32 | from module_without_all import * | Using 'from ... import *' pollutes the namespace | diff --git a/python/ql/test/query-tests/Imports/general/ImportStarUsed.qlref b/python/ql/test/query-tests/Imports/general/ImportStarUsed.qlref new file mode 100644 index 00000000000..35f8bff3e5f --- /dev/null +++ b/python/ql/test/query-tests/Imports/general/ImportStarUsed.qlref @@ -0,0 +1 @@ +Imports/ImportStarUsed.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Imports/general/Imports.expected b/python/ql/test/query-tests/Imports/general/Imports.expected new file mode 100644 index 00000000000..59f5437fea3 --- /dev/null +++ b/python/ql/test/query-tests/Imports/general/Imports.expected @@ -0,0 +1 @@ +| imports_test.py:2:1:2:23 | Import | Multiple imports on one line. | diff --git a/python/ql/test/query-tests/Imports/general/Imports.qlref b/python/ql/test/query-tests/Imports/general/Imports.qlref new file mode 100644 index 00000000000..6bcdb2d9b5f --- /dev/null +++ b/python/ql/test/query-tests/Imports/general/Imports.qlref @@ -0,0 +1 @@ +Imports/Imports.ql diff --git a/python/ql/test/query-tests/Imports/general/MultipleImport.expected b/python/ql/test/query-tests/Imports/general/MultipleImport.expected new file mode 100644 index 00000000000..6e3938a67f5 --- /dev/null +++ b/python/ql/test/query-tests/Imports/general/MultipleImport.expected @@ -0,0 +1,2 @@ +| imports_test.py:33:1:33:14 | Import | This import of module module1 is redundant, as it was previously imported $@. | imports_test.py:2:1:2:23 | Import | on line 2 | +| imports_test.py:34:1:34:14 | Import | This import of module module2 is redundant, as it was previously imported $@. | imports_test.py:2:1:2:23 | Import | on line 2 | diff --git a/python/ql/test/query-tests/Imports/general/MultipleImport.qlref b/python/ql/test/query-tests/Imports/general/MultipleImport.qlref new file mode 100644 index 00000000000..a4d2195b688 --- /dev/null +++ b/python/ql/test/query-tests/Imports/general/MultipleImport.qlref @@ -0,0 +1 @@ +Imports/MultipleImports.ql diff --git a/python/ql/test/query-tests/Imports/general/UnintentionalImport.expected b/python/ql/test/query-tests/Imports/general/UnintentionalImport.expected new file mode 100644 index 00000000000..89e48e2f071 --- /dev/null +++ b/python/ql/test/query-tests/Imports/general/UnintentionalImport.expected @@ -0,0 +1 @@ +| imports_test.py:22:1:22:32 | from module_without_all import * | Import pollutes the enclosing namespace, as the imported module $@ does not define '__all__'. | module_without_all.py:0:0:0:0 | Module module_without_all | module_without_all | diff --git a/python/ql/test/query-tests/Imports/general/UnintentionalImport.qlref b/python/ql/test/query-tests/Imports/general/UnintentionalImport.qlref new file mode 100644 index 00000000000..4f1b985d5c2 --- /dev/null +++ b/python/ql/test/query-tests/Imports/general/UnintentionalImport.qlref @@ -0,0 +1 @@ +Imports/UnintentionalImport.ql diff --git a/python/ql/test/query-tests/Imports/general/imports_mutable.py b/python/ql/test/query-tests/Imports/general/imports_mutable.py new file mode 100644 index 00000000000..0519a2071d8 --- /dev/null +++ b/python/ql/test/query-tests/Imports/general/imports_mutable.py @@ -0,0 +1,5 @@ +from mutable_attr import x, y + +def f(): + print(x) + print(y) diff --git a/python/ql/test/query-tests/Imports/general/imports_test.py b/python/ql/test/query-tests/Imports/general/imports_test.py new file mode 100644 index 00000000000..5e5184b78c7 --- /dev/null +++ b/python/ql/test/query-tests/Imports/general/imports_test.py @@ -0,0 +1,63 @@ +#Multiple imports on a single line +import module1, module2 + +#Cyclic import + +import cycle + +#Top level cyclic import + +import top_level_cycle + +#Import shadowed by loop variable + +import module + +for module in range(10): + print(module) + +#Import * used + +from module import * +from module_without_all import * + +#Unused import + +from module2 import func1 +from module2 import func2 + +module1.func +func1 + +#Duplicate import +import module1 +import module2 + +#OK -- Import used in epytext documentation. +import used_in_docs + +# L{used_in_docs} + +#OK -- Used in class. +import used_in_class + +class C(object): + + used_in_class = used_in_class + +#OK unused imports -- ODASA-3978 +from module2 import func3 as _ +from module2 import func3 as unused_but_ok +from module2 import func3 as _________ + +class Foo(object): + from bar import baz + def __init__(self): + self.foo = self.baz() + +#OK duplicate import -- Different name +import module1 as different + +#Use it +different + diff --git a/python/ql/test/query-tests/Imports/general/module.py b/python/ql/test/query-tests/Imports/general/module.py new file mode 100644 index 00000000000..7004607618a --- /dev/null +++ b/python/ql/test/query-tests/Imports/general/module.py @@ -0,0 +1,4 @@ +#Ignore from __future__ imports when considering unused imports +from __future__ import division, print_function + +__all__ = [] diff --git a/python/ql/test/query-tests/Imports/general/module1.py b/python/ql/test/query-tests/Imports/general/module1.py new file mode 100644 index 00000000000..b9bfa6f1233 --- /dev/null +++ b/python/ql/test/query-tests/Imports/general/module1.py @@ -0,0 +1,2 @@ +def func(): + pass diff --git a/python/ql/test/query-tests/Imports/general/module2.py b/python/ql/test/query-tests/Imports/general/module2.py new file mode 100644 index 00000000000..4b0947ab6b7 --- /dev/null +++ b/python/ql/test/query-tests/Imports/general/module2.py @@ -0,0 +1,8 @@ +def func1(): + pass + +def func2(): + pass + +def func3(): + pass \ No newline at end of file diff --git a/python/ql/test/query-tests/Imports/general/module_without_all.py b/python/ql/test/query-tests/Imports/general/module_without_all.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/query-tests/Imports/general/mutable_attr.py b/python/ql/test/query-tests/Imports/general/mutable_attr.py new file mode 100644 index 00000000000..2c1854573a4 --- /dev/null +++ b/python/ql/test/query-tests/Imports/general/mutable_attr.py @@ -0,0 +1,2 @@ +x = 1 +y = 2 diff --git a/python/ql/test/query-tests/Imports/general/mutates.py b/python/ql/test/query-tests/Imports/general/mutates.py new file mode 100644 index 00000000000..5a99a43b7ad --- /dev/null +++ b/python/ql/test/query-tests/Imports/general/mutates.py @@ -0,0 +1,4 @@ +import mutable_attr + +def f(): + mutable_attr.x = 2 diff --git a/python/ql/test/query-tests/Imports/general/mutates_in_test.py b/python/ql/test/query-tests/Imports/general/mutates_in_test.py new file mode 100644 index 00000000000..60e6ef553c2 --- /dev/null +++ b/python/ql/test/query-tests/Imports/general/mutates_in_test.py @@ -0,0 +1,7 @@ +import mutable_attr +import unittest + +class T(unittest.TestCase): + + def test_foo(self): + mutable_attr.y = 3 diff --git a/python/ql/test/query-tests/Imports/general/options b/python/ql/test/query-tests/Imports/general/options new file mode 100644 index 00000000000..b91afde0767 --- /dev/null +++ b/python/ql/test/query-tests/Imports/general/options @@ -0,0 +1 @@ +semmle-extractor-options: --max-import-depth=2 diff --git a/python/ql/test/query-tests/Imports/general/unittest/__init__.py b/python/ql/test/query-tests/Imports/general/unittest/__init__.py new file mode 100644 index 00000000000..083edc397d0 --- /dev/null +++ b/python/ql/test/query-tests/Imports/general/unittest/__init__.py @@ -0,0 +1,4 @@ +#Fake unittest module + +class TestCase(object): + pass diff --git a/python/ql/test/query-tests/Imports/unused/UnusedImport.expected b/python/ql/test/query-tests/Imports/unused/UnusedImport.expected new file mode 100644 index 00000000000..163bcab7b3d --- /dev/null +++ b/python/ql/test/query-tests/Imports/unused/UnusedImport.expected @@ -0,0 +1,5 @@ +| imports_test.py:2:1:2:23 | Import | Import of 'module2' is not used. | +| imports_test.py:6:1:6:12 | Import | Import of 'cycle' is not used. | +| imports_test.py:10:1:10:22 | Import | Import of 'top_level_cycle' is not used. | +| imports_test.py:27:1:27:25 | Import | Import of 'func2' is not used. | +| imports_test.py:34:1:34:14 | Import | Import of 'module2' is not used. | diff --git a/python/ql/test/query-tests/Imports/unused/UnusedImport.qlref b/python/ql/test/query-tests/Imports/unused/UnusedImport.qlref new file mode 100644 index 00000000000..e6bb7ab44cb --- /dev/null +++ b/python/ql/test/query-tests/Imports/unused/UnusedImport.qlref @@ -0,0 +1 @@ +Imports/UnusedImport.ql diff --git a/python/ql/test/query-tests/Imports/unused/imports_test.py b/python/ql/test/query-tests/Imports/unused/imports_test.py new file mode 100644 index 00000000000..5e5184b78c7 --- /dev/null +++ b/python/ql/test/query-tests/Imports/unused/imports_test.py @@ -0,0 +1,63 @@ +#Multiple imports on a single line +import module1, module2 + +#Cyclic import + +import cycle + +#Top level cyclic import + +import top_level_cycle + +#Import shadowed by loop variable + +import module + +for module in range(10): + print(module) + +#Import * used + +from module import * +from module_without_all import * + +#Unused import + +from module2 import func1 +from module2 import func2 + +module1.func +func1 + +#Duplicate import +import module1 +import module2 + +#OK -- Import used in epytext documentation. +import used_in_docs + +# L{used_in_docs} + +#OK -- Used in class. +import used_in_class + +class C(object): + + used_in_class = used_in_class + +#OK unused imports -- ODASA-3978 +from module2 import func3 as _ +from module2 import func3 as unused_but_ok +from module2 import func3 as _________ + +class Foo(object): + from bar import baz + def __init__(self): + self.foo = self.baz() + +#OK duplicate import -- Different name +import module1 as different + +#Use it +different + diff --git a/python/ql/test/query-tests/Lexical/ToDoComment/ToDoComment.expected b/python/ql/test/query-tests/Lexical/ToDoComment/ToDoComment.expected new file mode 100644 index 00000000000..c6cc8fc1ae2 --- /dev/null +++ b/python/ql/test/query-tests/Lexical/ToDoComment/ToDoComment.expected @@ -0,0 +1 @@ +| todo.py:1:1:1:65 | Comment # TO DO -- (Nothing "to do" -- this is a test for TO DO comments) | # TO DO -- (Nothing "to do" -- this is a test for TO DO comments) | diff --git a/python/ql/test/query-tests/Lexical/ToDoComment/ToDoComment.qlref b/python/ql/test/query-tests/Lexical/ToDoComment/ToDoComment.qlref new file mode 100644 index 00000000000..4568a99f388 --- /dev/null +++ b/python/ql/test/query-tests/Lexical/ToDoComment/ToDoComment.qlref @@ -0,0 +1 @@ +Lexical/ToDoComment.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Lexical/ToDoComment/lexical_test.py b/python/ql/test/query-tests/Lexical/ToDoComment/lexical_test.py new file mode 100644 index 00000000000..a9917fd6aaa --- /dev/null +++ b/python/ql/test/query-tests/Lexical/ToDoComment/lexical_test.py @@ -0,0 +1,6 @@ + +#1 line that is the maximum length +print(" ") +# 2 lines that are too long +len(" ") +print(" ") diff --git a/python/ql/test/query-tests/Lexical/ToDoComment/todo.py b/python/ql/test/query-tests/Lexical/ToDoComment/todo.py new file mode 100644 index 00000000000..5e02882924b --- /dev/null +++ b/python/ql/test/query-tests/Lexical/ToDoComment/todo.py @@ -0,0 +1 @@ +# TO DO -- (Nothing "to do" -- this is a test for TO DO comments) diff --git a/python/ql/test/query-tests/Lexical/commented_out_code/CommentedOutCode.expected b/python/ql/test/query-tests/Lexical/commented_out_code/CommentedOutCode.expected new file mode 100644 index 00000000000..ac6b27d1a22 --- /dev/null +++ b/python/ql/test/query-tests/Lexical/commented_out_code/CommentedOutCode.expected @@ -0,0 +1,3 @@ +| test.py:15:5:16:28 | Commented out code | These comments appear to contain commented-out code. | +| test.py:21:1:72:9 | Commented out code | These comments appear to contain commented-out code. | +| test.py:78:1:85:9 | Commented out code | These comments appear to contain commented-out code. | diff --git a/python/ql/test/query-tests/Lexical/commented_out_code/CommentedOutCode.qlref b/python/ql/test/query-tests/Lexical/commented_out_code/CommentedOutCode.qlref new file mode 100644 index 00000000000..6fe55e0fa94 --- /dev/null +++ b/python/ql/test/query-tests/Lexical/commented_out_code/CommentedOutCode.qlref @@ -0,0 +1 @@ +Lexical/CommentedOutCode.ql diff --git a/python/ql/test/query-tests/Lexical/commented_out_code/FCommentedOutCode.expected b/python/ql/test/query-tests/Lexical/commented_out_code/FCommentedOutCode.expected new file mode 100644 index 00000000000..4aeac6a5d6b --- /dev/null +++ b/python/ql/test/query-tests/Lexical/commented_out_code/FCommentedOutCode.expected @@ -0,0 +1 @@ +| test.py:0:0:0:0 | test.py | 42 | diff --git a/python/ql/test/query-tests/Lexical/commented_out_code/FCommentedOutCode.qlref b/python/ql/test/query-tests/Lexical/commented_out_code/FCommentedOutCode.qlref new file mode 100644 index 00000000000..2776efbcfd3 --- /dev/null +++ b/python/ql/test/query-tests/Lexical/commented_out_code/FCommentedOutCode.qlref @@ -0,0 +1 @@ +Lexical/FCommentedOutCode.ql diff --git a/python/ql/test/query-tests/Lexical/commented_out_code/test.py b/python/ql/test/query-tests/Lexical/commented_out_code/test.py new file mode 100644 index 00000000000..067855b6744 --- /dev/null +++ b/python/ql/test/query-tests/Lexical/commented_out_code/test.py @@ -0,0 +1,100 @@ + +def e(): + #A real comment + some_code() + x = y + some_more_code() + "Ignore single commented out lines as it is too difficult to tell whether they are code" + #class C(object): + a_bit_more_code() + return 1 + +def f(x): + if x: + do_something() + #else: + # do_something_else() + +# Some non-code comments. +# Space immediately after scope start and between functions. +# +#class CommentedOut: +# +# def __init__(self): + +# pass +# +# def method(self): +# +# pass +# +#def g(y): +# assert y +# with y: +# # Commented out comment +# if y: +# do_something() +# else: +# do_something_else() +# +#def h(z): +# '''Doc string +# ''' +# # Commented out comment +# +# followed_by_space() + +# +# more_code() + +#def j(): +# """ Doc string """ +# pass + +#def k(): +# +# """ Doc string """ +# pass + +#def l(): +# +# """ +# Doc string +# """ +# +# pass + +# +# +# +# +#def m(): +# pass +# +# +# +some_code_to_break_up_comments() + +#with x: +# pass +#try: +# call() +#except Exception: +# pass +#except: +# pass + +def a_function_to_break_up_comments(): + pass + +# An example explaining +# something which contains +# the following code: +# +# def f(): +# call() +# x.y = z +# return x +# + + \ No newline at end of file diff --git a/python/ql/test/query-tests/Metrics/cyclo/CyclomaticComplexity.expected b/python/ql/test/query-tests/Metrics/cyclo/CyclomaticComplexity.expected new file mode 100644 index 00000000000..fd69f810c21 --- /dev/null +++ b/python/ql/test/query-tests/Metrics/cyclo/CyclomaticComplexity.expected @@ -0,0 +1,6 @@ +| code.py:23:1:23:17 | Function nested | 4 | +| code.py:12:1:12:21 | Function two_branch | 3 | +| code.py:6:1:6:18 | Function one_branch | 2 | +| code.py:35:1:35:21 | Function exceptions | 2 | +| code.py:1:1:1:16 | Function f_linear | 1 | +| code.py:45:1:45:39 | Function must_be_positive | 1 | diff --git a/python/ql/test/query-tests/Metrics/cyclo/CyclomaticComplexity.qlref b/python/ql/test/query-tests/Metrics/cyclo/CyclomaticComplexity.qlref new file mode 100644 index 00000000000..c74ae215bb4 --- /dev/null +++ b/python/ql/test/query-tests/Metrics/cyclo/CyclomaticComplexity.qlref @@ -0,0 +1 @@ +Metrics/CyclomaticComplexity.ql diff --git a/python/ql/test/query-tests/Metrics/cyclo/code.py b/python/ql/test/query-tests/Metrics/cyclo/code.py new file mode 100644 index 00000000000..8ca6507b3be --- /dev/null +++ b/python/ql/test/query-tests/Metrics/cyclo/code.py @@ -0,0 +1,49 @@ +def f_linear(x): + y = x + z = y + return z + +def one_branch(x): + if x: + return 1 + else: + return 2 + +def two_branch(x, y): + if x: + y += 1 + else: + y += 2 + if y: + return 1 + else: + return 2 + + +def nested(x, y): + if x: + if y: + return 0 + else: + return 1 + else: + if y: + return 2 + else: + return 3 + +def exceptions(x, y): + try: + x.attr + x + y + x[y] + read() + except IOError: + pass + +#ODASA-5114 +def must_be_positive(self, obj, value): + try: + return int(value) + except: + self.error(obj, value) diff --git a/python/ql/test/query-tests/Metrics/duplicate/FLinesOfDuplicatedCode.expected b/python/ql/test/query-tests/Metrics/duplicate/FLinesOfDuplicatedCode.expected new file mode 100644 index 00000000000..51e43af9a60 --- /dev/null +++ b/python/ql/test/query-tests/Metrics/duplicate/FLinesOfDuplicatedCode.expected @@ -0,0 +1,4 @@ +| duplicate_test.py:0:0:0:0 | duplicate_test.py | 228 | +| similar.py:0:0:0:0 | similar.py | 59 | +| with_import1.py:0:0:0:0 | with_import1.py | 30 | +| with_import2.py:0:0:0:0 | with_import2.py | 30 | diff --git a/python/ql/test/query-tests/Metrics/duplicate/FLinesOfDuplicatedCode.qlref b/python/ql/test/query-tests/Metrics/duplicate/FLinesOfDuplicatedCode.qlref new file mode 100644 index 00000000000..74833a9789d --- /dev/null +++ b/python/ql/test/query-tests/Metrics/duplicate/FLinesOfDuplicatedCode.qlref @@ -0,0 +1 @@ +Metrics/FLinesOfDuplicatedCode.ql diff --git a/python/ql/test/query-tests/Metrics/duplicate/FLinesOfSimilarCode.expected b/python/ql/test/query-tests/Metrics/duplicate/FLinesOfSimilarCode.expected new file mode 100644 index 00000000000..a69317fed4e --- /dev/null +++ b/python/ql/test/query-tests/Metrics/duplicate/FLinesOfSimilarCode.expected @@ -0,0 +1,4 @@ +| duplicate_test.py:0:0:0:0 | duplicate_test.py | 310 | +| similar.py:0:0:0:0 | similar.py | 61 | +| with_import1.py:0:0:0:0 | with_import1.py | 30 | +| with_import2.py:0:0:0:0 | with_import2.py | 30 | diff --git a/python/ql/test/query-tests/Metrics/duplicate/FLinesOfSimilarCode.qlref b/python/ql/test/query-tests/Metrics/duplicate/FLinesOfSimilarCode.qlref new file mode 100644 index 00000000000..a2c60374e1d --- /dev/null +++ b/python/ql/test/query-tests/Metrics/duplicate/FLinesOfSimilarCode.qlref @@ -0,0 +1 @@ +Metrics/FLinesOfSimilarCode.ql diff --git a/python/ql/test/query-tests/Metrics/duplicate/duplicate_test.py b/python/ql/test/query-tests/Metrics/duplicate/duplicate_test.py new file mode 100644 index 00000000000..1faf919ca96 --- /dev/null +++ b/python/ql/test/query-tests/Metrics/duplicate/duplicate_test.py @@ -0,0 +1,321 @@ +#Code Duplication + + +#Exact duplication of function + +#Code copied from stdlib, copyright PSF. +#See http://www.python.org/download/releases/2.7/license/ + +def dis(x=None): + """Disassemble classes, methods, functions, or code. + + With no argument, disassemble the last traceback. + + """ + if x is None: + distb() + return + if isinstance(x, types.InstanceType): + x = x.__class__ + if hasattr(x, 'im_func'): + x = x.im_func + if hasattr(x, 'func_code'): + x = x.func_code + if hasattr(x, '__dict__'): + items = x.__dict__.items() + items.sort() + for name, x1 in items: + if isinstance(x1, _have_code): + print("Disassembly of %s:" % name) + try: + dis(x1) + except TypeError as msg: + print("Sorry:", msg) + print() + elif hasattr(x, 'co_code'): + disassemble(x) + elif isinstance(x, str): + disassemble_string(x) + else: + raise TypeError, \ + "don't know how to disassemble %s objects" % \ + type(x).__name__ + + +#And duplicate version + +def dis2(x=None): + """Disassemble classes, methods, functions, or code. + + With no argument, disassemble the last traceback. + + """ + if x is None: + distb() + return + if isinstance(x, types.InstanceType): + x = x.__class__ + if hasattr(x, 'im_func'): + x = x.im_func + if hasattr(x, 'func_code'): + x = x.func_code + if hasattr(x, '__dict__'): + items = x.__dict__.items() + items.sort() + for name, x1 in items: + if isinstance(x1, _have_code): + print("Disassembly of %s:" % name) + try: + dis(x1) + except TypeError as msg: + print("Sorry:", msg) + print() + elif hasattr(x, 'co_code'): + disassemble(x) + elif isinstance(x, str): + disassemble_string(x) + else: + raise TypeError, \ + "don't know how to disassemble %s objects" % \ + type(x).__name__ + +#Exactly duplicate class + +class Popen3: + """Class representing a child process. Normally, instances are created + internally by the functions popen2() and popen3().""" + + sts = -1 # Child not completed yet + + def __init__(self, cmd, capturestderr=False, bufsize=-1): + """The parameter 'cmd' is the shell command to execute in a + sub-process. On UNIX, 'cmd' may be a sequence, in which case arguments + will be passed directly to the program without shell intervention (as + with os.spawnv()). If 'cmd' is a string it will be passed to the shell + (as with os.system()). The 'capturestderr' flag, if true, specifies + that the object should capture standard error output of the child + process. The default is false. If the 'bufsize' parameter is + specified, it specifies the size of the I/O buffers to/from the child + process.""" + _cleanup() + self.cmd = cmd + p2cread, p2cwrite = os.pipe() + c2pread, c2pwrite = os.pipe() + if capturestderr: + errout, errin = os.pipe() + self.pid = os.fork() + if self.pid == 0: + # Child + os.dup2(p2cread, 0) + os.dup2(c2pwrite, 1) + if capturestderr: + os.dup2(errin, 2) + self._run_child(cmd) + os.close(p2cread) + self.tochild = os.fdopen(p2cwrite, 'w', bufsize) + os.close(c2pwrite) + self.fromchild = os.fdopen(c2pread, 'r', bufsize) + if capturestderr: + os.close(errin) + self.childerr = os.fdopen(errout, 'r', bufsize) + else: + self.childerr = None + + def __del__(self): + # In case the child hasn't been waited on, check if it's done. + self.poll(_deadstate=sys.maxint) + if self.sts < 0: + if _active is not None: + # Child is still running, keep us alive until we can wait on it. + _active.append(self) + + def _run_child(self, cmd): + if isinstance(cmd, basestring): + cmd = ['/bin/sh', '-c', cmd] + os.closerange(3, MAXFD) + try: + os.execvp(cmd[0], cmd) + finally: + os._exit(1) + + def poll(self, _deadstate=None): + """Return the exit status of the child process if it has finished, + or -1 if it hasn't finished yet.""" + if self.sts < 0: + try: + pid, sts = os.waitpid(self.pid, os.WNOHANG) + # pid will be 0 if self.pid hasn't terminated + if pid == self.pid: + self.sts = sts + except os.error: + if _deadstate is not None: + self.sts = _deadstate + return self.sts + + def wait(self): + """Wait for and return the exit status of the child process.""" + if self.sts < 0: + pid, sts = os.waitpid(self.pid, 0) + # This used to be a test, but it is believed to be + # always true, so I changed it to an assertion - mvl + assert pid == self.pid + self.sts = sts + return self.sts + + +class Popen3Again: + """Class representing a child process. Normally, instances are created + internally by the functions popen2() and popen3().""" + + sts = -1 # Child not completed yet + + def __init__(self, cmd, capturestderr=False, bufsize=-1): + """The parameter 'cmd' is the shell command to execute in a + sub-process. On UNIX, 'cmd' may be a sequence, in which case arguments + will be passed directly to the program without shell intervention (as + with os.spawnv()). If 'cmd' is a string it will be passed to the shell + (as with os.system()). The 'capturestderr' flag, if true, specifies + that the object should capture standard error output of the child + process. The default is false. If the 'bufsize' parameter is + specified, it specifies the size of the I/O buffers to/from the child + process.""" + _cleanup() + self.cmd = cmd + p2cread, p2cwrite = os.pipe() + c2pread, c2pwrite = os.pipe() + if capturestderr: + errout, errin = os.pipe() + self.pid = os.fork() + if self.pid == 0: + # Child + os.dup2(p2cread, 0) + os.dup2(c2pwrite, 1) + if capturestderr: + os.dup2(errin, 2) + self._run_child(cmd) + os.close(p2cread) + self.tochild = os.fdopen(p2cwrite, 'w', bufsize) + os.close(c2pwrite) + self.fromchild = os.fdopen(c2pread, 'r', bufsize) + if capturestderr: + os.close(errin) + self.childerr = os.fdopen(errout, 'r', bufsize) + else: + self.childerr = None + + def __del__(self): + # In case the child hasn't been waited on, check if it's done. + self.poll(_deadstate=sys.maxint) + if self.sts < 0: + if _active is not None: + # Child is still running, keep us alive until we can wait on it. + _active.append(self) + + def _run_child(self, cmd): + if isinstance(cmd, basestring): + cmd = ['/bin/sh', '-c', cmd] + os.closerange(3, MAXFD) + try: + os.execvp(cmd[0], cmd) + finally: + os._exit(1) + + def poll(self, _deadstate=None): + """Return the exit status of the child process if it has finished, + or -1 if it hasn't finished yet.""" + if self.sts < 0: + try: + pid, sts = os.waitpid(self.pid, os.WNOHANG) + # pid will be 0 if self.pid hasn't terminated + if pid == self.pid: + self.sts = sts + except os.error: + if _deadstate is not None: + self.sts = _deadstate + return self.sts + + def wait(self): + """Wait for and return the exit status of the child process.""" + if self.sts < 0: + pid, sts = os.waitpid(self.pid, 0) + # This used to be a test, but it is believed to be + # always true, so I changed it to an assertion - mvl + assert pid == self.pid + self.sts = sts + return self.sts + +#Duplicate function with identifiers changed + +def dis3(y=None): + """frobnicate classes, methods, functions, or code. + + With no argument, frobnicate the last traceback. + + """ + if y is None: + distb() + return + if isinstance(y, types.InstanceType): + y = y.__class__ + if hasattr(y, 'im_func'): + y = y.im_func + if hasattr(y, 'func_code'): + y = y.func_code + if hasattr(y, '__dict__'): + items = y.__dict__.items() + items.sort() + for name, y1 in items: + if isinstance(y1, _have_code): + print("Disassembly of %s:" % name) + try: + dis(y1) + except TypeError as msg: + print("Sorry:", msg) + print() + elif hasattr(y, 'co_code'): + frobnicate(y) + elif isinstance(y, str): + frobnicate_string(y) + else: + raise TypeError, \ + "don't know how to frobnicate %s objects" % \ + type(y).__name__ + + +#Mostly similar function with changed identifiers + +def dis5(z=None): + """splat classes, methods, functions, or code. + + With no argument, splat the last traceback. + + """ + if z is None: + distb() + return + if isinstance(z, types.InstanceType): + z = z.__class__ + if hasattr(y, 'func_code'): + y = y.func_code + if hasattr(z, '__dict__'): + items = z.__dict__.items() + items.sort() + for name, z1 in items: + if isinstance(z1, _have_code): + print("Disassembly of %s:" % name) + try: + dis(z1) + except TypeError as msg: + print("Sorry:", msg) + print() + elif hasattr(z, 'co_code'): + splat(z) + elif isinstance(z, str): + splat_string(z) + else: + raise TypeError, \ + "don't know how to splat %s objects" % \ + type(z).__name__ + + + diff --git a/python/ql/test/query-tests/Metrics/duplicate/similar.py b/python/ql/test/query-tests/Metrics/duplicate/similar.py new file mode 100644 index 00000000000..8f36c5e65ed --- /dev/null +++ b/python/ql/test/query-tests/Metrics/duplicate/similar.py @@ -0,0 +1,63 @@ + + +def original(the_ast): + def walk(node, in_function, in_name_main): + def flags(): + return in_function * 2 + in_name_main + if isinstance(node, ast.Module): + for import_node in walk(node.body, in_function, in_name_main): + yield import_node + elif isinstance(node, ast.ImportFrom): + aliases = [ Alias(a.name, a.asname) for a in node.names] + yield FromImport(node.level, node.module, aliases, flags()) + elif isinstance(node, ast.Import): + aliases = [ Alias(a.name, a.asname) for a in node.names] + yield Import(aliases, flags()) + elif isinstance(node, ast.FunctionDef): + for _, child in ast.iter_fields(node): + for import_node in walk(child, True, in_name_main): + yield import_node + elif isinstance(node, list): + for n in node: + for import_node in walk(n, in_function, in_name_main): + yield import_node + return list(walk(the_ast, False, False)) + +def similar_1(the_ast): + def walk(node, in_function, in_name_main): + def flags(): + return in_function * 2 + in_name_main + if isinstance(node, ast.Module): + for import_node in walk(node.body, in_function, in_name_main): + yield import_node + elif isinstance(node, ast.ImportFrom): + aliases = [ Alias(a.name, a.asname) for a in node.names] + yield FromImport(node.level, node.module, aliases, flags()) + elif isinstance(node, ast.Import): + aliases = [ Alias(a.name, a.asname) for a in node.names] + yield Import(aliases, flags()) + elif isinstance(node, ast.FunctionDef): + for _, child in ast.iter_fields(node): + for import_node in walk(child, True, in_name_main): + yield import_node + return list(walk(the_ast, False, False)) + +def similar_2(the_ast): + def walk(node, in_function, in_name_main): + def flags(): + return in_function * 2 + in_name_main + if isinstance(node, ast.Module): + for import_node in walk(node.body, in_function, in_name_main): + yield import_node + elif isinstance(node, ast.Import): + aliases = [ Alias(a.name, a.asname) for a in node.names] + yield Import(aliases, flags()) + elif isinstance(node, ast.FunctionDef): + for _, child in ast.iter_fields(node): + for import_node in walk(child, True, in_name_main): + yield import_node + elif isinstance(node, list): + for n in node: + for import_node in walk(n, in_function, in_name_main): + yield import_node + return list(walk(the_ast, False, False)) diff --git a/python/ql/test/query-tests/Metrics/duplicate/with_import1.py b/python/ql/test/query-tests/Metrics/duplicate/with_import1.py new file mode 100644 index 00000000000..e6fa77a005f --- /dev/null +++ b/python/ql/test/query-tests/Metrics/duplicate/with_import1.py @@ -0,0 +1,37 @@ +import a +import b +import c +import d +import e +import f + +# Colours +if platform.system() == 'Windows': + col_default = 0x07 + col_red = 0x0C + col_green = 0x0A +else: + col_default = '\033[0m' + col_red = '\033[91m' + col_green = '\033[92m' +col_current = None + +def set_text_colour(col): + global col_current + if col_current is None or col_current != col: + if not sys.stdout.isatty(): + pass # not on a terminal (e.g. output is being piped to file) + elif (platform.system() == 'Windows'): + # set the text colour using the Win32 API + handle = ctypes.windll.kernel32.GetStdHandle(-11) # STD_OUTPUT_HANDLE + ctypes.windll.kernel32.SetConsoleTextAttribute(handle, col) + else: + # set the text colour using a character code + sys.stdout.write(col) + col_current = col + +def report(text, col = col_default): + set_text_colour(col) + print(text) + set_text_colour(col_default) + diff --git a/python/ql/test/query-tests/Metrics/duplicate/with_import2.py b/python/ql/test/query-tests/Metrics/duplicate/with_import2.py new file mode 100644 index 00000000000..e6fa77a005f --- /dev/null +++ b/python/ql/test/query-tests/Metrics/duplicate/with_import2.py @@ -0,0 +1,37 @@ +import a +import b +import c +import d +import e +import f + +# Colours +if platform.system() == 'Windows': + col_default = 0x07 + col_red = 0x0C + col_green = 0x0A +else: + col_default = '\033[0m' + col_red = '\033[91m' + col_green = '\033[92m' +col_current = None + +def set_text_colour(col): + global col_current + if col_current is None or col_current != col: + if not sys.stdout.isatty(): + pass # not on a terminal (e.g. output is being piped to file) + elif (platform.system() == 'Windows'): + # set the text colour using the Win32 API + handle = ctypes.windll.kernel32.GetStdHandle(-11) # STD_OUTPUT_HANDLE + ctypes.windll.kernel32.SetConsoleTextAttribute(handle, col) + else: + # set the text colour using a character code + sys.stdout.write(col) + col_current = col + +def report(text, col = col_default): + set_text_colour(col) + print(text) + set_text_colour(col_default) + diff --git a/python/ql/test/query-tests/Metrics/functions/FunctionStatementNestingDepth.expected b/python/ql/test/query-tests/Metrics/functions/FunctionStatementNestingDepth.expected new file mode 100644 index 00000000000..1eb36f9f4e2 --- /dev/null +++ b/python/ql/test/query-tests/Metrics/functions/FunctionStatementNestingDepth.expected @@ -0,0 +1,9 @@ +| test.py:20:1:20:12 | Function f4 | 4 | +| test.py:50:5:50:23 | Function f4 | 4 | +| test.py:13:1:13:13 | Function f3 | 3 | +| test.py:43:5:43:23 | Function f3 | 3 | +| test.py:5:1:5:16 | Function f2 | 2 | +| test.py:35:5:35:23 | Function f2 | 2 | +| test.py:60:1:60:8 | Function g | 2 | +| test.py:2:1:2:9 | Function f1 | 1 | +| test.py:32:5:32:17 | Function f1 | 1 | diff --git a/python/ql/test/query-tests/Metrics/functions/FunctionStatementNestingDepth.qlref b/python/ql/test/query-tests/Metrics/functions/FunctionStatementNestingDepth.qlref new file mode 100644 index 00000000000..797f223792f --- /dev/null +++ b/python/ql/test/query-tests/Metrics/functions/FunctionStatementNestingDepth.qlref @@ -0,0 +1 @@ +Metrics/FunctionStatementNestingDepth.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Metrics/functions/test.py b/python/ql/test/query-tests/Metrics/functions/test.py new file mode 100644 index 00000000000..ebb4c9fdfdc --- /dev/null +++ b/python/ql/test/query-tests/Metrics/functions/test.py @@ -0,0 +1,63 @@ + +def f1(): + pass + +def f2(x, y, z): + if x: + pass + elif y: + yield 0 + elif z: + raise z + +def f3(a, b): + if a: + pass + else: + if b: + return 0 + +def f4(a,b): + while True: + if a: + pass + elif b: + try: + call() + except: + raise + +class C: + + def f1(self): + pass + + def f2(self, x, y): + if x: + pass + elif y: + yield 0 + elif z: + raise z + + def f3(self, a, b): + if a: + pass + else: + if b: + return 0 + + def f4(self, a, b): + while True: + if a: + pass + elif b: + try: + call() + except: + raise + +def g(): + if x: a if y else b + + diff --git a/python/ql/test/query-tests/Metrics/imports/DirectImports.expected b/python/ql/test/query-tests/Metrics/imports/DirectImports.expected new file mode 100644 index 00000000000..dd6236a1e0a --- /dev/null +++ b/python/ql/test/query-tests/Metrics/imports/DirectImports.expected @@ -0,0 +1,5 @@ +| entry.py:0:0:0:0 | Module entry | 2 | +| module1.py:0:0:0:0 | Module module1 | 1 | +| module2.py:0:0:0:0 | Module module2 | 2 | +| module3.py:0:0:0:0 | Module module3 | 1 | +| module4.py:0:0:0:0 | Module module4 | 0 | diff --git a/python/ql/test/query-tests/Metrics/imports/DirectImports.qlref b/python/ql/test/query-tests/Metrics/imports/DirectImports.qlref new file mode 100644 index 00000000000..84fe2dc5805 --- /dev/null +++ b/python/ql/test/query-tests/Metrics/imports/DirectImports.qlref @@ -0,0 +1 @@ +Metrics/DirectImports.ql diff --git a/python/ql/test/query-tests/Metrics/imports/TransitiveImports.expected b/python/ql/test/query-tests/Metrics/imports/TransitiveImports.expected new file mode 100644 index 00000000000..fa9d79a6e78 --- /dev/null +++ b/python/ql/test/query-tests/Metrics/imports/TransitiveImports.expected @@ -0,0 +1,5 @@ +| entry.py:0:0:0:0 | Module entry | 4 | +| module1.py:0:0:0:0 | Module module1 | 3 | +| module2.py:0:0:0:0 | Module module2 | 2 | +| module3.py:0:0:0:0 | Module module3 | 1 | +| module4.py:0:0:0:0 | Module module4 | 0 | diff --git a/python/ql/test/query-tests/Metrics/imports/TransitiveImports.qlref b/python/ql/test/query-tests/Metrics/imports/TransitiveImports.qlref new file mode 100644 index 00000000000..1bacdce45c2 --- /dev/null +++ b/python/ql/test/query-tests/Metrics/imports/TransitiveImports.qlref @@ -0,0 +1 @@ +Metrics/TransitiveImports.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Metrics/imports/entry.py b/python/ql/test/query-tests/Metrics/imports/entry.py new file mode 100644 index 00000000000..b2477d61fe2 --- /dev/null +++ b/python/ql/test/query-tests/Metrics/imports/entry.py @@ -0,0 +1,2 @@ +import module1 +import module2 \ No newline at end of file diff --git a/python/ql/test/query-tests/Metrics/imports/module1.py b/python/ql/test/query-tests/Metrics/imports/module1.py new file mode 100644 index 00000000000..1d4ff55ce87 --- /dev/null +++ b/python/ql/test/query-tests/Metrics/imports/module1.py @@ -0,0 +1 @@ +import module2 diff --git a/python/ql/test/query-tests/Metrics/imports/module2.py b/python/ql/test/query-tests/Metrics/imports/module2.py new file mode 100644 index 00000000000..6542b8234f5 --- /dev/null +++ b/python/ql/test/query-tests/Metrics/imports/module2.py @@ -0,0 +1,2 @@ +import module3 +import module4 diff --git a/python/ql/test/query-tests/Metrics/imports/module3.py b/python/ql/test/query-tests/Metrics/imports/module3.py new file mode 100644 index 00000000000..285f88ecdb3 --- /dev/null +++ b/python/ql/test/query-tests/Metrics/imports/module3.py @@ -0,0 +1 @@ +import module4 \ No newline at end of file diff --git a/python/ql/test/query-tests/Metrics/imports/module4.py b/python/ql/test/query-tests/Metrics/imports/module4.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/query-tests/Metrics/lines/CommentRatio.expected b/python/ql/test/query-tests/Metrics/lines/CommentRatio.expected new file mode 100644 index 00000000000..068a7d0c594 --- /dev/null +++ b/python/ql/test/query-tests/Metrics/lines/CommentRatio.expected @@ -0,0 +1 @@ +| lines.py:0:0:0:0 | Module lines | 15.0 | diff --git a/python/ql/test/query-tests/Metrics/lines/CommentRatio.qlref b/python/ql/test/query-tests/Metrics/lines/CommentRatio.qlref new file mode 100644 index 00000000000..9c3179ac503 --- /dev/null +++ b/python/ql/test/query-tests/Metrics/lines/CommentRatio.qlref @@ -0,0 +1 @@ +Metrics/CommentRatio.ql diff --git a/python/ql/test/query-tests/Metrics/lines/FLinesOfCode.expected b/python/ql/test/query-tests/Metrics/lines/FLinesOfCode.expected new file mode 100644 index 00000000000..d01931b5a0f --- /dev/null +++ b/python/ql/test/query-tests/Metrics/lines/FLinesOfCode.expected @@ -0,0 +1 @@ +| lines.py:0:0:0:0 | Module lines | 750 | diff --git a/python/ql/test/query-tests/Metrics/lines/FLinesOfCode.qlref b/python/ql/test/query-tests/Metrics/lines/FLinesOfCode.qlref new file mode 100644 index 00000000000..2ac69b8f67a --- /dev/null +++ b/python/ql/test/query-tests/Metrics/lines/FLinesOfCode.qlref @@ -0,0 +1 @@ +Metrics/FLinesOfCode.ql diff --git a/python/ql/test/query-tests/Metrics/lines/lines.py b/python/ql/test/query-tests/Metrics/lines/lines.py new file mode 100644 index 00000000000..81d922e84d3 --- /dev/null +++ b/python/ql/test/query-tests/Metrics/lines/lines.py @@ -0,0 +1,1200 @@ +line = 1 + +line = 2 +line = 3 + +line = 4 +line = 5 +line = 6 +line = 7 + +line = 8 +line = 9 + + +line = 10 +line = 11 +line = 12 + +line = 13 +#comment 1 +line = 14 +line = 15 +line = 16 +line = 17 + +line = 18 +line = 19 +line = 20 +line = 21 +line = 22 +#comment 2 +#comment 3 +#comment 4 + +line = 23 +line = 24 +line = 25 +line = 26 + +line = 27 +line = 28 +line = 29 +line = 30 +line = 31 +line = 32 +#comment 5 +line = 33 +line = 34 +line = 35 + +line = 36 + + +line = 37 +line = 38 +line = 39 +#comment 6 +line = 40 +line = 41 + + +line = 42 +line = 43 + +line = 44 +#comment 7 +line = 45 +#comment 8 + +line = 46 +line = 47 +line = 48 + +line = 49 +line = 50 +line = 51 +line = 52 +line = 53 +#comment 9 +line = 54 +line = 55 +line = 56 +line = 57 +line = 58 +#comment 10 +line = 59 +#comment 11 + +#comment 12 +line = 60 +line = 61 +#comment 13 +line = 62 +line = 63 +#comment 14 +line = 64 +line = 65 +line = 66 +#comment 15 +#comment 16 +line = 67 +#comment 17 + +line = 68 +line = 69 +line = 70 +line = 71 +line = 72 +line = 73 +#comment 18 +line = 74 + +line = 75 +#comment 19 +#comment 20 +line = 76 +line = 77 +#comment 21 +line = 78 +line = 79 +line = 80 + +line = 81 +line = 82 +line = 83 +#comment 22 +line = 84 +line = 85 +#comment 23 +line = 86 +#comment 24 +line = 87 +#comment 25 +line = 88 +line = 89 +#comment 26 +line = 90 + +line = 91 +line = 92 +line = 93 +line = 94 +line = 95 +#comment 27 +#comment 28 +#comment 29 +line = 96 +line = 97 +#comment 30 +line = 98 +line = 99 +line = 100 +line = 101 +line = 102 + +line = 103 +line = 104 + +line = 105 +line = 106 +line = 107 + + +line = 108 +line = 109 + +line = 110 +#comment 31 +line = 111 +line = 112 +line = 113 + +line = 114 +line = 115 + +line = 116 +#comment 32 +line = 117 + +line = 118 +line = 119 + +line = 120 +line = 121 +line = 122 +line = 123 +line = 124 +line = 125 + +#comment 33 + +#comment 34 + +line = 126 +line = 127 + +line = 128 +line = 129 + +line = 130 +line = 131 + +line = 132 + +line = 133 +line = 134 +line = 135 +#comment 35 +line = 136 +#comment 36 + + +#comment 37 +#comment 38 +line = 137 +line = 138 +line = 139 +line = 140 +line = 141 +line = 142 +line = 143 +line = 144 +line = 145 +line = 146 +line = 147 +line = 148 +line = 149 +line = 150 + + +line = 151 + +line = 152 +line = 153 +line = 154 +line = 155 + +#comment 39 +#comment 40 + +line = 156 +line = 157 +line = 158 +#comment 41 +line = 159 + +line = 160 +line = 161 +line = 162 + +#comment 42 +line = 163 +line = 164 +#comment 43 +line = 165 +line = 166 +line = 167 + +line = 168 +line = 169 +line = 170 +#comment 44 +line = 171 +line = 172 + + +line = 173 +line = 174 + +line = 175 + +#comment 45 +line = 176 + +#comment 46 +line = 177 +line = 178 + +line = 179 +line = 180 +#comment 47 + +line = 181 +line = 182 + +line = 183 +#comment 48 +line = 184 +line = 185 +line = 186 +line = 187 +line = 188 +line = 189 +line = 190 + +line = 191 + +line = 192 +line = 193 +#comment 49 +line = 194 +line = 195 +#comment 50 +line = 196 +line = 197 + +line = 198 +line = 199 +line = 200 + + + + +line = 201 +#comment 51 +line = 202 +line = 203 +line = 204 + +line = 205 + +#comment 52 +line = 206 +line = 207 +line = 208 +line = 209 +#comment 53 +line = 210 +line = 211 + +line = 212 +line = 213 +#comment 54 +line = 214 +line = 215 +line = 216 +line = 217 +#comment 55 +line = 218 + +line = 219 +line = 220 + +line = 221 + +line = 222 +line = 223 +line = 224 +line = 225 +line = 226 + + +line = 227 +line = 228 +line = 229 + +line = 230 +line = 231 + + +line = 232 + +line = 233 + +line = 234 + + +line = 235 +line = 236 +line = 237 +line = 238 +line = 239 + +line = 240 +line = 241 +#comment 56 +line = 242 +line = 243 +line = 244 +#comment 57 +line = 245 + +line = 246 + +line = 247 + +line = 248 +line = 249 + +line = 250 +line = 251 +line = 252 +line = 253 +line = 254 + +line = 255 + +line = 256 +#comment 58 +line = 257 +line = 258 +line = 259 +line = 260 +line = 261 +line = 262 +line = 263 +line = 264 +line = 265 +line = 266 +line = 267 +line = 268 +line = 269 +line = 270 + + + +#comment 59 + +line = 271 +#comment 60 +line = 272 + +line = 273 +line = 274 + + +line = 275 +line = 276 +line = 277 +#comment 61 +#comment 62 +line = 278 +line = 279 +#comment 63 +line = 280 +line = 281 +line = 282 + +line = 283 +line = 284 +line = 285 + +#comment 64 +line = 286 + + +line = 287 +line = 288 + +line = 289 +#comment 65 +line = 290 +line = 291 +line = 292 +line = 293 +line = 294 +line = 295 +#comment 66 + +#comment 67 + +line = 296 +line = 297 + +line = 298 +line = 299 +#comment 68 +line = 300 +line = 301 +line = 302 +#comment 69 + +line = 303 +line = 304 +line = 305 +line = 306 +line = 307 +line = 308 +line = 309 +line = 310 +line = 311 +line = 312 +line = 313 +line = 314 + +#comment 70 +#comment 71 +line = 315 + +line = 316 + +line = 317 +line = 318 + +line = 319 +line = 320 +line = 321 +line = 322 + +line = 323 + +line = 324 + +line = 325 +line = 326 +line = 327 +line = 328 +line = 329 +#comment 72 + + + +line = 330 +line = 331 + +line = 332 +line = 333 + +line = 334 + +line = 335 +#comment 73 +line = 336 +line = 337 +line = 338 +#comment 74 +line = 339 +line = 340 +#comment 75 + +line = 341 +line = 342 +line = 343 +line = 344 +#comment 76 +#comment 77 + +#comment 78 +#comment 79 +line = 345 +line = 346 +line = 347 +line = 348 +#comment 80 +line = 349 +line = 350 +line = 351 +#comment 81 +line = 352 +line = 353 +#comment 82 +#comment 83 + +line = 354 + +line = 355 +line = 356 + +line = 357 + + +line = 358 +line = 359 +line = 360 + +line = 361 +line = 362 + +line = 363 +#comment 84 +line = 364 +line = 365 +line = 366 +line = 367 + + +line = 368 +line = 369 +line = 370 + +#comment 85 +line = 371 +line = 372 +line = 373 +line = 374 +line = 375 + +line = 376 +line = 377 +line = 378 +#comment 86 +#comment 87 +#comment 88 +line = 379 + +line = 380 +line = 381 + + +line = 382 +line = 383 +line = 384 +line = 385 + +line = 386 +#comment 89 +line = 387 +line = 388 +#comment 90 +line = 389 +line = 390 +line = 391 + + +line = 392 +line = 393 +line = 394 +line = 395 + +line = 396 +line = 397 + + +#comment 91 +line = 398 +line = 399 +line = 400 +line = 401 + +#comment 92 +line = 402 +line = 403 +line = 404 +line = 405 + +line = 406 + + +#comment 93 +line = 407 +line = 408 +#comment 94 +line = 409 +line = 410 + + +#comment 95 +#comment 96 +#comment 97 +line = 411 +line = 412 +line = 413 + +line = 414 +line = 415 +line = 416 +line = 417 + +line = 418 +line = 419 +#comment 98 +line = 420 +line = 421 + +#comment 99 +line = 422 + + +line = 423 + +line = 424 +line = 425 +line = 426 +#comment 100 +line = 427 + + +line = 428 +line = 429 +line = 430 +line = 431 + +line = 432 +line = 433 + +line = 434 +line = 435 +line = 436 + +line = 437 +#comment 101 +#comment 102 +line = 438 +line = 439 +line = 440 +line = 441 + +line = 442 + +line = 443 +line = 444 +line = 445 + +#comment 103 +line = 446 +line = 447 + +line = 448 + +line = 449 + +line = 450 +line = 451 +line = 452 +line = 453 +line = 454 +line = 455 +line = 456 +line = 457 + + +#comment 104 +line = 458 +#comment 105 +line = 459 +line = 460 +#comment 106 +#comment 107 +line = 461 +#comment 108 +#comment 109 +line = 462 +line = 463 +line = 464 +#comment 110 +line = 465 +line = 466 +line = 467 +line = 468 +line = 469 +#comment 111 +line = 470 +line = 471 + +line = 472 + +line = 473 + + +line = 474 +line = 475 +line = 476 +line = 477 + +line = 478 +line = 479 + + +line = 480 + +line = 481 +line = 482 + +line = 483 +line = 484 +line = 485 +line = 486 +line = 487 +line = 488 +#comment 112 +#comment 113 +line = 489 +line = 490 +line = 491 +#comment 114 +line = 492 +line = 493 +line = 494 +#comment 115 +line = 495 +line = 496 +line = 497 + +line = 498 + +line = 499 + +line = 500 +line = 501 +#comment 116 + + +#comment 117 +#comment 118 +#comment 119 +line = 502 +line = 503 +line = 504 +line = 505 +line = 506 + +line = 507 +line = 508 +line = 509 + +line = 510 +#comment 120 +line = 511 + +#comment 121 +#comment 122 +#comment 123 + +#comment 124 +line = 512 +line = 513 +line = 514 +line = 515 +line = 516 +line = 517 + + + +line = 518 +line = 519 +line = 520 +line = 521 +line = 522 +line = 523 + +#comment 125 +line = 524 +line = 525 +line = 526 +line = 527 + +#comment 126 +line = 528 +line = 529 +#comment 127 + + +line = 530 +line = 531 +#comment 128 + +line = 532 + +#comment 129 +line = 533 + +line = 534 +line = 535 +line = 536 +line = 537 +line = 538 + + +line = 539 +line = 540 +line = 541 +line = 542 +line = 543 +line = 544 +line = 545 + +line = 546 +line = 547 +#comment 130 +line = 548 +line = 549 + +line = 550 + +line = 551 +line = 552 +line = 553 +line = 554 +line = 555 +line = 556 +line = 557 +line = 558 +line = 559 +line = 560 +line = 561 +line = 562 +line = 563 +line = 564 +line = 565 + +#comment 131 +line = 566 +line = 567 +line = 568 +line = 569 + +line = 570 +line = 571 + +line = 572 + +line = 573 +line = 574 + +line = 575 +#comment 132 +line = 576 +line = 577 +line = 578 +line = 579 + +line = 580 +line = 581 +line = 582 + +line = 583 +line = 584 + +line = 585 +line = 586 + + + +line = 587 + +line = 588 +line = 589 + +line = 590 +line = 591 +line = 592 +#comment 133 +#comment 134 +line = 593 +#comment 135 + +line = 594 + +line = 595 +#comment 136 +line = 596 +line = 597 +line = 598 + + +line = 599 +line = 600 +#comment 137 +line = 601 + +line = 602 +line = 603 + +#comment 138 + +line = 604 +line = 605 +line = 606 +line = 607 +line = 608 +line = 609 +line = 610 + + + +line = 611 +line = 612 +line = 613 +line = 614 +line = 615 +#comment 139 +#comment 140 +line = 616 +line = 617 + + +#comment 141 +line = 618 +line = 619 +line = 620 +line = 621 +line = 622 +line = 623 +line = 624 +line = 625 +line = 626 + +line = 627 + +line = 628 +line = 629 +line = 630 +line = 631 +line = 632 + +line = 633 + +line = 634 +line = 635 +line = 636 +line = 637 +line = 638 +line = 639 +line = 640 + +#comment 142 + +line = 641 + +#comment 143 + +line = 642 +line = 643 +line = 644 + + +line = 645 + +line = 646 +#comment 144 + +line = 647 +line = 648 +line = 649 +line = 650 +line = 651 +line = 652 +#comment 145 +line = 653 +line = 654 +line = 655 +line = 656 +line = 657 +line = 658 +line = 659 + + +line = 660 + +#comment 146 + +line = 661 + +#comment 147 +line = 662 +#comment 148 +line = 663 + +line = 664 + + +line = 665 +line = 666 +line = 667 + + +line = 668 +line = 669 +line = 670 + +line = 671 +line = 672 +#comment 149 +#comment 150 +line = 673 +line = 674 +line = 675 +line = 676 +#comment 151 +line = 677 +line = 678 + +line = 679 +line = 680 +line = 681 + +line = 682 +line = 683 +line = 684 + +#comment 152 +line = 685 +line = 686 +line = 687 +line = 688 +line = 689 +line = 690 +line = 691 + +line = 692 + +#comment 153 + +line = 693 + +#comment 154 + +line = 694 +line = 695 +line = 696 +#comment 155 +line = 697 +line = 698 +#comment 156 +line = 699 +line = 700 +#comment 157 + + +#comment 158 +line = 701 + + +#comment 159 +line = 702 +line = 703 + +line = 704 +#comment 160 +line = 705 +#comment 161 + +line = 706 +line = 707 +line = 708 +line = 709 +line = 710 +#comment 162 +line = 711 + +line = 712 +line = 713 +line = 714 +#comment 163 +line = 715 + +line = 716 + +#comment 164 +#comment 165 +line = 717 +#comment 166 +line = 718 +line = 719 + +line = 720 +line = 721 +line = 722 + + +line = 723 +#comment 167 +#comment 168 +line = 724 +line = 725 +line = 726 +line = 727 +line = 728 + +#comment 169 +#comment 170 + +line = 729 +line = 730 + +line = 731 +line = 732 +#comment 171 +line = 733 +#comment 172 + +line = 734 + +line = 735 +line = 736 +line = 737 +line = 738 +line = 739 +line = 740 +line = 741 +line = 742 +line = 743 + +line = 744 +line = 745 +line = 746 +#comment 173 +line = 747 +#comment 174 +#comment 175 + +#comment 176 +line = 748 +line = 749 +line = 750 +#comment 177 +#comment 178 +#comment 179 + +#comment 180 -- Exactly 1200 lines diff --git a/python/ql/test/query-tests/Metrics/ratios/CodeRatio.expected b/python/ql/test/query-tests/Metrics/ratios/CodeRatio.expected new file mode 100644 index 00000000000..0c5d498b00d --- /dev/null +++ b/python/ql/test/query-tests/Metrics/ratios/CodeRatio.expected @@ -0,0 +1 @@ +| doc_string.py:0:0:0:0 | Module doc_string | 24.0 | diff --git a/python/ql/test/query-tests/Metrics/ratios/CodeRatio.ql b/python/ql/test/query-tests/Metrics/ratios/CodeRatio.ql new file mode 100644 index 00000000000..545453e93eb --- /dev/null +++ b/python/ql/test/query-tests/Metrics/ratios/CodeRatio.ql @@ -0,0 +1,7 @@ + +import python + +from Module m, ModuleMetrics mm +where mm = m.getMetrics() and mm.getNumberOfLines() > 0 +select m, 100.0 * ((float)mm.getNumberOfLinesOfCode() / (float)mm.getNumberOfLines()) as ratio +order by ratio desc \ No newline at end of file diff --git a/python/ql/test/query-tests/Metrics/ratios/CommentRatio.expected b/python/ql/test/query-tests/Metrics/ratios/CommentRatio.expected new file mode 100644 index 00000000000..43c2bcf7c11 --- /dev/null +++ b/python/ql/test/query-tests/Metrics/ratios/CommentRatio.expected @@ -0,0 +1 @@ +| doc_string.py:0:0:0:0 | Module doc_string | 12.0 | diff --git a/python/ql/test/query-tests/Metrics/ratios/CommentRatio.qlref b/python/ql/test/query-tests/Metrics/ratios/CommentRatio.qlref new file mode 100644 index 00000000000..dc273e16982 --- /dev/null +++ b/python/ql/test/query-tests/Metrics/ratios/CommentRatio.qlref @@ -0,0 +1 @@ +Metrics/CommentRatio.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Metrics/ratios/DocStringRatio.expected b/python/ql/test/query-tests/Metrics/ratios/DocStringRatio.expected new file mode 100644 index 00000000000..76e6e095d63 --- /dev/null +++ b/python/ql/test/query-tests/Metrics/ratios/DocStringRatio.expected @@ -0,0 +1 @@ +| doc_string.py:0:0:0:0 | Module doc_string | 50.0 | diff --git a/python/ql/test/query-tests/Metrics/ratios/DocStringRatio.qlref b/python/ql/test/query-tests/Metrics/ratios/DocStringRatio.qlref new file mode 100644 index 00000000000..ec66c5cdc83 --- /dev/null +++ b/python/ql/test/query-tests/Metrics/ratios/DocStringRatio.qlref @@ -0,0 +1 @@ +Metrics/DocStringRatio.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Metrics/ratios/doc_string.py b/python/ql/test/query-tests/Metrics/ratios/doc_string.py new file mode 100644 index 00000000000..13fe12c5f2d --- /dev/null +++ b/python/ql/test/query-tests/Metrics/ratios/doc_string.py @@ -0,0 +1,50 @@ +''' +A long docstring... + +The Zen of Python, by Tim Peters + +Beautiful is better than ugly. +Explicit is better than implicit. +Simple is better than complex. +Complex is better than complicated. +Flat is better than nested. +Sparse is better than dense. +Readability counts. +Special cases aren't special enough to break the rules. +Although practicality beats purity. +Errors should never pass silently. +Unless explicitly silenced. +In the face of ambiguity, refuse the temptation to guess. +There should be one-- and preferably only one --obvious way to do it. +Although that way may not be obvious at first unless you're Dutch. +Now is better than never. +Although never is often better than *right* now. +If the implementation is hard to explain, it's a bad idea. +If the implementation is easy to explain, it may be a good idea. +Namespaces are one honking great idea -- let's do more of those! +''' + +#25 lines of docstring in a 50 line module: 50% +#12 lines of code in a 50 line module: 24% +#6 lines of comment in a 50 line module: 12% + +#And some code +import nonexistent + +def function(): + meaning_of_life = 42 + return meaning_of_life + +class C: + + def __init__(self): + stuff() + more_stuff() + yet_more_stuff() + #Pointless return + return + + def m(self): + pass + +# A comment on the last line diff --git a/python/ql/test/query-tests/Metrics/tests/FNumberOfTests.expected b/python/ql/test/query-tests/Metrics/tests/FNumberOfTests.expected new file mode 100644 index 00000000000..a786f642391 --- /dev/null +++ b/python/ql/test/query-tests/Metrics/tests/FNumberOfTests.expected @@ -0,0 +1 @@ +| test.py:0:0:0:0 | test.py | 4 | diff --git a/python/ql/test/query-tests/Metrics/tests/FNumberOfTests.qlref b/python/ql/test/query-tests/Metrics/tests/FNumberOfTests.qlref new file mode 100644 index 00000000000..e7301c3b230 --- /dev/null +++ b/python/ql/test/query-tests/Metrics/tests/FNumberOfTests.qlref @@ -0,0 +1 @@ +Metrics/FNumberOfTests.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Metrics/tests/pytest.py b/python/ql/test/query-tests/Metrics/tests/pytest.py new file mode 100644 index 00000000000..680efc88e4b --- /dev/null +++ b/python/ql/test/query-tests/Metrics/tests/pytest.py @@ -0,0 +1,3 @@ +""" +Fake pytest module +""" \ No newline at end of file diff --git a/python/ql/test/query-tests/Metrics/tests/test.py b/python/ql/test/query-tests/Metrics/tests/test.py new file mode 100644 index 00000000000..24c00456afe --- /dev/null +++ b/python/ql/test/query-tests/Metrics/tests/test.py @@ -0,0 +1,36 @@ + +class Test: + + def setUp(self): + pass + + def tearDown(self): + pass + + def test_1(self): + pass + + def test_2(self): + pass + + def test_3(self): + pass + + +import pytest + +def test_something(x): + pass + + +def with_doctest(): + ''' + >>> 1 + 1 + 2 + + >>> 1 * 1 + 1 + ''' + +def without_doctest(): + pass \ No newline at end of file diff --git a/python/ql/test/query-tests/Resources/Dataflow.expected b/python/ql/test/query-tests/Resources/Dataflow.expected new file mode 100644 index 00000000000..ed7be1b3600 --- /dev/null +++ b/python/ql/test/query-tests/Resources/Dataflow.expected @@ -0,0 +1,119 @@ +| f1_0 = open() | open | | +| f1_1 = MethodCallsiteRefinement(f1_0) | open | | +| f1_2 = MethodCallsiteRefinement(f1_1) | closed | exit | +| f2_0 = open() | open | exit | +| f3_0 = open() | open | | +| f3_1 = MethodCallsiteRefinement(f3_0) | closed | exit | +| f4_0 = with | closed | | +| f4_1 = MethodCallsiteRefinement(f4_0) | closed | exit | +| f5_0 = open() | open | | +| f5_1 = MethodCallsiteRefinement(f5_0) | open | | +| f5_2 = MethodCallsiteRefinement(f5_1) | closed | exit | +| f5_3 = phi(f5_0, f5_1) | open | | +| f6_0 = None | closed | | +| f6_1 = open() | open | | +| f6_2 = MethodCallsiteRefinement(f6_1) | open | | +| f6_3 = phi(f6_0, f6_1, f6_2) | open | | +| f6_4 = SingleSuccessorGuard(f6_3) [true] | open | | +| f6_5 = Pi(f6_2) [true] | open | | +| f6_6 = MethodCallsiteRefinement(f6_5) | closed | | +| f6_7 = Pi(f6_2) [false] | closed | | +| f6_8 = phi(f6_6, f6_7) | closed | exit | +| f7_0 = None | closed | | +| f7_1 = open() | open | | +| f7_2 = MethodCallsiteRefinement(f7_1) | open | | +| f7_3 = phi(f7_0, f7_1, f7_2) | open | | +| f7_4 = SingleSuccessorGuard(f7_3) [true] | open | | +| f7_5 = Pi(f7_2) [true] | open | | +| f7_6 = MethodCallsiteRefinement(f7_5) | closed | | +| f7_7 = Pi(f7_2) [false] | closed | | +| f7_8 = phi(f7_6, f7_7) | closed | exit | +| f8_0 = None | closed | | +| f8_1 = open() | open | | +| f8_2 = MethodCallsiteRefinement(f8_1) | open | | +| f8_3 = phi(f8_0, f8_1, f8_2) | open | | +| f8_4 = SingleSuccessorGuard(f8_3) [true] | open | | +| f8_5 = Pi(f8_2) [true] | closed | | +| f8_6 = MethodCallsiteRefinement(f8_5) | closed | | +| f8_7 = Pi(f8_2) [false] | open | | +| f8_8 = phi(f8_6, f8_7) | open | exit | +| f9_0 = None | closed | | +| f9_1 = open() | open | | +| f9_2 = MethodCallsiteRefinement(f9_1) | open | | +| f9_3 = phi(f9_0, f9_1, f9_2) | open | | +| f9_4 = SingleSuccessorGuard(f9_3) [true] | open | | +| f9_5 = Pi(f9_2) [true] | closed | | +| f9_6 = MethodCallsiteRefinement(f9_5) | closed | | +| f9_7 = Pi(f9_2) [false] | open | | +| f9_8 = phi(f9_6, f9_7) | open | exit | +| f10_0 = open() | open | | +| f10_1 = MethodCallsiteRefinement(f10_0) | open | | +| f10_2 = MethodCallsiteRefinement(f10_1) | open | | +| f10_3 = MethodCallsiteRefinement(f10_2) | closed | | +| f10_4 = phi(f10_0, f10_1, f10_2, f10_3) | open | | +| f10_5 = MethodCallsiteRefinement(f10_4) | closed | | +| f10_6 = phi(f10_3, f10_5) | closed | exit | +| f11_0 = open() | open | | +| f11_1 = MethodCallsiteRefinement(f11_0) | open | | +| f11_2 = MethodCallsiteRefinement(f11_1) | open | | +| f11_3 = MethodCallsiteRefinement(f11_2) | closed | | +| f11_4 = phi(f11_0, f11_1, f11_2, f11_3) | open | | +| f11_5 = MethodCallsiteRefinement(f11_4) | closed | | +| f11_6 = phi(f11_3, f11_5) | closed | exit | +| f12_0 = open() | open | | +| f12_1 = MethodCallsiteRefinement(f12_0) | open | | +| f12_2 = MethodCallsiteRefinement(f12_1) | open | | +| f12_3 = MethodCallsiteRefinement(f12_2) | closed | | +| f12_4 = phi(f12_0, f12_1, f12_2, f12_3) | open | | +| f12_5 = MethodCallsiteRefinement(f12_4) | closed | | +| f12_6 = phi(f12_3, f12_5) | closed | exit | +| f13_0 = open() | open | | +| f13_1 = MethodCallsiteRefinement(f13_0) | open | exit | +| f14_0 = opener_func2() | open | | +| f14_1 = MethodCallsiteRefinement(f14_0) | open | | +| f14_2 = MethodCallsiteRefinement(f14_1) | closed | exit | +| f15_0 = opener_func2() | open | | +| f15_1 = ArgumentRefinement(f15_0) | closed | exit | +| f16_0 = ScopeEntryDefinition | closed | | +| f16_1 = open() | open | | +| f16_2 = MethodCallsiteRefinement(f16_1) | open | | +| f16_3 = MethodCallsiteRefinement(f16_2) | closed | | +| f16_4 = phi(f16_0, f16_1, f16_2, f16_3) | open | | +| f16_5 = phi(f16_3, f16_4) | open | exit | +| f17_0 = open() | open | | +| f17_1 = MethodCallsiteRefinement(f17_0) | open | | +| f17_2 = MethodCallsiteRefinement(f17_1) | open | | +| f17_3 = MethodCallsiteRefinement(f17_2) | closed | | +| f17_4 = phi(f17_0, f17_1, f17_2, f17_3) | open | | +| f17_5 = MethodCallsiteRefinement(f17_4) | closed | | +| f17_6 = phi(f17_3, f17_5) | closed | exit | +| f18_0 = open() | closed | | +| f18_1 = MethodCallsiteRefinement(f18_0) | closed | exit | +| f20_0 = open() | open | | +| f20_1 = ArgumentRefinement(f20_0) | closed | exit | +| f21_0 = open() | open | | +| f21_1 = MethodCallsiteRefinement(f21_0) | open | | +| f21_2 = MethodCallsiteRefinement(f21_1) | closed | | +| f21_3 = phi(f21_1, f21_2) | open | | +| f21_4 = phi(f21_0, f21_1, f21_2) | open | | +| f21_5 = SingleSuccessorGuard(f21_4) [true] | open | | +| f21_6 = Pi(f21_3) [true] | open | | +| f21_7 = MethodCallsiteRefinement(f21_6) | closed | | +| f21_8 = Pi(f21_3) [false] | closed | | +| f21_9 = phi(f21_7, f21_8) | closed | exit | +| f22_0 = open() | open | | +| f22_1 = MethodCallsiteRefinement(f22_0) | open | | +| f22_2 = MethodCallsiteRefinement(f22_1) | closed | | +| f22_3 = phi(f22_1, f22_2) | open | | +| f22_4 = phi(f22_0, f22_1, f22_2) | open | | +| f22_5 = SingleSuccessorGuard(f22_4) [true] | open | | +| f22_6 = Pi(f22_3) [true] | closed | | +| f22_7 = MethodCallsiteRefinement(f22_6) | closed | | +| f22_8 = Pi(f22_3) [false] | open | | +| f22_9 = phi(f22_7, f22_8) | open | exit | +| f_0 = FunctionExpr | closed | exit | +| file_0 = open() | open | | +| file_1 = open() | open | | +| file_2 = None | closed | | +| file_3 = phi(file_0, file_1, file_2) | open | exit | +| fp_0 = ParameterDefinition | closed | exit | diff --git a/python/ql/test/query-tests/Resources/Dataflow.ql b/python/ql/test/query-tests/Resources/Dataflow.ql new file mode 100644 index 00000000000..ee92ee981c3 --- /dev/null +++ b/python/ql/test/query-tests/Resources/Dataflow.ql @@ -0,0 +1,16 @@ + +import python +import Resources.FileOpen + + +from EssaVariable v, EssaDefinition def, string open, string exit +where def = v.getDefinition() and v.getSourceVariable().getName().charAt(0) = "f" and +( + var_is_open(v, _) and open = "open" + or + not var_is_open(v, _) and open = "closed" +) +and +if BaseFlow::reaches_exit(v) then exit = "exit" else exit = "" + +select v.getRepresentation() + " = " + v.getDefinition().getRepresentation(), open, exit diff --git a/python/ql/test/query-tests/Resources/FileNotAlwaysClosed.expected b/python/ql/test/query-tests/Resources/FileNotAlwaysClosed.expected new file mode 100644 index 00000000000..c0a6c413333 --- /dev/null +++ b/python/ql/test/query-tests/Resources/FileNotAlwaysClosed.expected @@ -0,0 +1,9 @@ +| resources_test.py:4:10:4:25 | open() | File may not be closed if an exception is raised. | +| resources_test.py:9:10:9:25 | open() | File is opened but is not closed. | +| resources_test.py:49:14:49:29 | open() | File is opened but is not closed. | +| resources_test.py:58:14:58:29 | open() | File is opened but is not closed. | +| resources_test.py:79:11:79:26 | open() | File may not be closed if an exception is raised. | +| resources_test.py:108:11:108:20 | open() | File is opened but is not closed. | +| resources_test.py:112:11:112:28 | opener_func2() | File may not be closed if an exception is raised. | +| resources_test.py:129:15:129:24 | open() | File is opened but is not closed. | +| resources_test.py:237:11:237:26 | open() | File is opened but is not closed. | diff --git a/python/ql/test/query-tests/Resources/FileNotAlwaysClosed.qlref b/python/ql/test/query-tests/Resources/FileNotAlwaysClosed.qlref new file mode 100644 index 00000000000..37e9a076680 --- /dev/null +++ b/python/ql/test/query-tests/Resources/FileNotAlwaysClosed.qlref @@ -0,0 +1 @@ +Resources/FileNotAlwaysClosed.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Resources/resources_test.py b/python/ql/test/query-tests/Resources/resources_test.py new file mode 100644 index 00000000000..73fa88b4401 --- /dev/null +++ b/python/ql/test/query-tests/Resources/resources_test.py @@ -0,0 +1,246 @@ +#File not always closed + +def not_close1(): + f1 = open("filename") + f1.write("Error could occur") + f1.close() + +def not_close2(): + f2 = open("filename") + +def closed3(): + f3 = open("filename") + f3.close() + +def closed4(): + with open("filename") as f4: + f4.write("Error could occur") + +def closed5(): + f5 = open("filename") + try: + f5.write("Error could occur") + finally: + f5.close() + +#Correctly guarded close() +def closed6(): + f6 = None + try: + f6 = open("filename") + f6.write("Error could occur") + finally: + if f6: + f6.close() + +def closed7(): + f7 = None + try: + f7 = open("filename") + f7.write("Error could occur") + finally: + if not f7 is None: + f7.close() + +#Incorrectly guarded close() +def not_closed8(): + f8 = None + try: + f8 = open("filename") + f8.write("Error could occur") + finally: + if f8 is None: + f8.close() + +def not_closed9(): + f9 = None + try: + f9 = open("filename") + f9.write("Error could occur") + finally: + if not f9: + f9.close() + +def not_closed_but_cant_tell_locally(): + return open("filename") + +#Closed by handling the correct exception +def closed10(): + f10 = open("filename") + try: + f10.write("IOError could occur") + f10.write("IOError could occur") + f10.close() + except IOError: + f10.close() + +#Not closed by handling the wrong exception +def not_closed11(): + f11 = open("filename") + try: + f11.write("IOError could occur") + f11.write("IOError could occur") + f11.close() + except AttributeError: + f11.close() + +def doesnt_raise(): + pass + +def mostly_closed12(): + f12 = open("filename") + try: + f12.write("IOError could occur") + f12.write("IOError could occur") + doesnt_raise("Potential false positive here") + f12.close() + except IOError: + f12.close() + +def opener_func1(name): + return open(name) + +def opener_func2(name): + t1 = opener_func1(name) + return t1 + +def not_closed13(name): + f13 = open(name) + f13.write("Hello") + +def may_not_be_closed14(name): + f14 = opener_func2(name) + f14.write("Hello") + f14.close() + +def closer1(t2): + t2.close() + +def closer2(t3): + closer1(t3) + +def closed15(): + f15 = opener_func2() + closer2(f15) + + +def may_not_be_closed16(name): + try: + f16 = open(name) + f16.write("Hello") + f16.close() + except IOError: + pass + +def may_raise(): + if random(): + raise ValueError() + +#Not handling all exceptions, but we'll tolerate the false negative +def not_closed17(): + f17 = open("filename") + try: + f17.write("IOError could occur") + f17.write("IOError could occur") + may_raise("ValueError could occur") # FN here. + f17.close() + except IOError: + f17.close() + +#ODASA-3779 +#With statement will close the fp +def closed18(path): + try: + f18 = open(path) + except IOError as ex: + print(ex) + raise ex + with f18: + f18.read() + +class Closed19(object): + + def __enter__(self): + self.fd = open("Filename") + + def __exit__(self, *args): + self.fd.close() + +class FileWrapper(object): + + def __init__(self, fp): + self.fp = fp + +def closed20(path): + f20 = open(path) + return FileWrapper(f20) + +#ODASA-3105 +def run(nodes_module): + use_file = len(sys.argv) > 1 + if use_file: + out = open(sys.argv[1], 'w', encoding='utf-8') + else: + out = sys.stdout + try: + out.write("spam") + finally: + if use_file: + out.close() + +#ODASA-3515 +class GraphVizTrapWriter(object): + + def __init__(self, out): + if out is None: + self.out = sys.stdout + else: + self.out = open(out, 'w') + self.pool = GraphVizIdPool(self.out) + + def __del__(self): + if self.out != sys.stdout: + self.out.close() + +#Returned as part of tuple +def f(name, path): + try: + path = path.attr + file = open(path, 'rb') + except AttributeError: + # ExtensionLoader has not attribute get_filename, instead it has a + # path attribute that we can use to retrieve the module path + try: + path = path.other_attr + file = open(path, 'rb') + except AttributeError: + path = name + file = None + + return file, path + + +#ODASA-5891 +def closed21(path): + f21 = open(path, "wb") + try: + f21.write(b"foo") + may_raise() + if foo: + f21.close() + finally: + if not f21.closed: + f21.close() + + +def not_closed22(path): + f22 = open(path, "wb") + try: + f22.write(b"foo") + may_raise() + if foo: + f22.close() + finally: + if f22.closed: # Wrong sense + f22.close() + diff --git a/python/ql/test/query-tests/Security/CWE-022/PathInjection.expected b/python/ql/test/query-tests/Security/CWE-022/PathInjection.expected new file mode 100644 index 00000000000..68979df27ed --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-022/PathInjection.expected @@ -0,0 +1,3 @@ +| path_injection.py:10:14:10:44 | argument to open() | This path depends on $@. | path_injection.py:9:12:9:23 | flask.request.args | a user-provided value | +| path_injection.py:17:14:17:18 | argument to open() | This path depends on $@. | path_injection.py:15:12:15:23 | flask.request.args | a user-provided value | +| path_injection.py:28:14:28:18 | argument to open() | This path depends on $@. | path_injection.py:24:12:24:23 | flask.request.args | a user-provided value | diff --git a/python/ql/test/query-tests/Security/CWE-022/PathInjection.qlref b/python/ql/test/query-tests/Security/CWE-022/PathInjection.qlref new file mode 100644 index 00000000000..d43482cc509 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-022/PathInjection.qlref @@ -0,0 +1 @@ +Security/CWE-022/PathInjection.ql diff --git a/python/ql/test/query-tests/Security/CWE-022/options b/python/ql/test/query-tests/Security/CWE-022/options new file mode 100644 index 00000000000..dce78f52325 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-022/options @@ -0,0 +1,2 @@ +semmle-extractor-options: -p ../lib/ --max-import-depth=3 +optimize: true diff --git a/python/ql/test/query-tests/Security/CWE-022/path_injection.py b/python/ql/test/query-tests/Security/CWE-022/path_injection.py new file mode 100644 index 00000000000..b409e2d0221 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-022/path_injection.py @@ -0,0 +1,36 @@ + +import os.path + +from flask import Flask, request +app = Flask(__name__) + +@app.route("/path1") +def path_injection(): + path = request.args.get('path', '') + f = open(os.path.join(os.getcwd(), path)) + +@app.route("/path2") +def path_injection(): + # Normalized, but not checked + path = request.args.get('path', '') + npath = os.path.normpath(os.path.join(os.getcwd(), path)) + f = open(npath) + +SAFE = "/tmp/scratch_area/" + +@app.route("/path3") +def safe_path(): + # Normalized, but check doesn't reach open(). + path = request.args.get('path', '') + npath = os.path.normpath(os.path.join(os.getcwd(), path)) + if npath.startswith(SAFE): + pass + f = open(npath) + +@app.route("/path4") +def safe_path(): + # Normalized, and checked properly + path = request.args.get('path', '') + npath = os.path.normpath(os.path.join(os.getcwd(), path)) + if npath.startswith(SAFE): + f = open(npath) diff --git a/python/ql/test/query-tests/Security/CWE-078/CommandInjection.expected b/python/ql/test/query-tests/Security/CWE-078/CommandInjection.expected new file mode 100644 index 00000000000..e48b14ad0aa --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-078/CommandInjection.expected @@ -0,0 +1,3 @@ +| command_injection.py:12:15:12:27 | shell command | This command depends on $@. | command_injection.py:10:13:10:24 | flask.request.args | a user-provided value | +| command_injection.py:19:22:19:34 | shell command | This command depends on $@. | command_injection.py:17:13:17:24 | flask.request.args | a user-provided value | +| command_injection.py:25:22:25:36 | OS command first argument | This command depends on $@. | command_injection.py:24:11:24:22 | flask.request.args | a user-provided value | diff --git a/python/ql/test/query-tests/Security/CWE-078/CommandInjection.qlref b/python/ql/test/query-tests/Security/CWE-078/CommandInjection.qlref new file mode 100644 index 00000000000..e38b88f2919 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-078/CommandInjection.qlref @@ -0,0 +1 @@ +Security/CWE-078/CommandInjection.ql diff --git a/python/ql/test/query-tests/Security/CWE-078/command_injection.py b/python/ql/test/query-tests/Security/CWE-078/command_injection.py new file mode 100644 index 00000000000..642ebc98d33 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-078/command_injection.py @@ -0,0 +1,25 @@ + +import os +import subprocess + +from flask import Flask, request +app = Flask(__name__) + +@app.route("/command1") +def command_injection1(): + files = request.args.get('files', '') + # Don't let files be `; rm -rf /` + os.system("ls " + files) + + +@app.route("/command2") +def command_injection2(): + files = request.args.get('files', '') + # Don't let files be `; rm -rf /` + subprocess.Popen(["ls", files], shell = True) + + +@app.route("/command3") +def first_arg_injection(): + cmd = request.args.get('cmd', '') + subprocess.Popen([cmd, "param1"]) diff --git a/python/ql/test/query-tests/Security/CWE-078/options b/python/ql/test/query-tests/Security/CWE-078/options new file mode 100644 index 00000000000..dce78f52325 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-078/options @@ -0,0 +1,2 @@ +semmle-extractor-options: -p ../lib/ --max-import-depth=3 +optimize: true diff --git a/python/ql/test/query-tests/Security/CWE-079/ReflectedXss.expected b/python/ql/test/query-tests/Security/CWE-079/ReflectedXss.expected new file mode 100644 index 00000000000..d9d226b6248 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-079/ReflectedXss.expected @@ -0,0 +1 @@ +| ../lib/flask/__init__.py:16:25:16:26 | flask.response.argument | Cross-site scripting vulnerability due to $@. | reflected_xss.py:7:18:7:29 | flask.request.args | user-provided value | diff --git a/python/ql/test/query-tests/Security/CWE-079/ReflectedXss.qlref b/python/ql/test/query-tests/Security/CWE-079/ReflectedXss.qlref new file mode 100644 index 00000000000..e0efe102416 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-079/ReflectedXss.qlref @@ -0,0 +1 @@ +Security/CWE-079/ReflectedXss.ql diff --git a/python/ql/test/query-tests/Security/CWE-079/options b/python/ql/test/query-tests/Security/CWE-079/options new file mode 100644 index 00000000000..492768b3481 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-079/options @@ -0,0 +1 @@ +semmle-extractor-options: -p ../lib/ --max-import-depth=3 diff --git a/python/ql/test/query-tests/Security/CWE-079/reflected_xss.py b/python/ql/test/query-tests/Security/CWE-079/reflected_xss.py new file mode 100644 index 00000000000..fecb84ef725 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-079/reflected_xss.py @@ -0,0 +1,18 @@ +from flask import Flask, request, make_response, escape + +app = Flask(__name__) + +@app.route('/unsafe') +def unsafe(): + first_name = request.args.get('name', '') + return make_response("Your name is " + first_name) + +@app.route('/safe') +def safe(): + first_name = request.args.get('name', '') + return make_response("Your name is " + escape(first_name)) + +urlpatterns = [ + url(r'^r1$', response_unsafe, name='response-unsafe'), + url(r'^r2$', response_safe, name='response-safe') +] diff --git a/python/ql/test/query-tests/Security/CWE-089/SqlInjection.expected b/python/ql/test/query-tests/Security/CWE-089/SqlInjection.expected new file mode 100644 index 00000000000..01a1f6f0b43 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-089/SqlInjection.expected @@ -0,0 +1,4 @@ +| sql_injection.py:19:13:19:66 | db.connection.execute | This SQL query depends on $@. | sql_injection.py:9:15:9:21 | Django request source | a user-provided value | +| sql_injection.py:22:38:22:91 | django.db.models.expressions.RawSQL(sink,...) | This SQL query depends on $@. | sql_injection.py:9:15:9:21 | Django request source | a user-provided value | +| sql_injection.py:23:26:23:79 | django.models.QuerySet.raw(sink,...) | This SQL query depends on $@. | sql_injection.py:9:15:9:21 | Django request source | a user-provided value | +| sql_injection.py:24:28:24:81 | django.models.QuerySet.extra(sink,...) | This SQL query depends on $@. | sql_injection.py:9:15:9:21 | Django request source | a user-provided value | diff --git a/python/ql/test/query-tests/Security/CWE-089/SqlInjection.qlref b/python/ql/test/query-tests/Security/CWE-089/SqlInjection.qlref new file mode 100644 index 00000000000..d1d02cbe8d3 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-089/SqlInjection.qlref @@ -0,0 +1 @@ +Security/CWE-089/SqlInjection.ql diff --git a/python/ql/test/query-tests/Security/CWE-089/options b/python/ql/test/query-tests/Security/CWE-089/options new file mode 100644 index 00000000000..492768b3481 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-089/options @@ -0,0 +1 @@ +semmle-extractor-options: -p ../lib/ --max-import-depth=3 diff --git a/python/ql/test/query-tests/Security/CWE-089/sql_injection.py b/python/ql/test/query-tests/Security/CWE-089/sql_injection.py new file mode 100644 index 00000000000..b312241b809 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-089/sql_injection.py @@ -0,0 +1,28 @@ + +from django.conf.urls import patterns, url +from django.db import connection, models +from django.db.models.expressions import RawSQL + +class Name(models.Model): + pass + +def save_name(request): + + if request.method == 'POST': + name = request.POST.get('name') + curs = connection.cursor() + #GOOD -- Using parameters + curs.execute( + "insert into names_file ('name') values ('%s')", name) + #BAD -- Using string formatting + curs.execute( + "insert into names_file ('name') values ('%s')" % name) + + #BAD -- other ways of executing raw SQL code with string interpolation + Name.objects.annotate(RawSQL("insert into names_file ('name') values ('%s')" % name)) + Name.objects.raw("insert into names_file ('name') values ('%s')" % name) + Name.objects.extra("insert into names_file ('name') values ('%s')" % name) + +urlpatterns = patterns(url(r'^save_name/$', + save_name, name='save_name')) + diff --git a/python/ql/test/query-tests/Security/CWE-094/CodeInjection.expected b/python/ql/test/query-tests/Security/CWE-094/CodeInjection.expected new file mode 100644 index 00000000000..02a6bc6255d --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-094/CodeInjection.expected @@ -0,0 +1 @@ +| code_injection.py:7:14:7:44 | exec or eval | $@ flows to here and is interpreted as code. | code_injection.py:4:20:4:26 | Django request source | User-provided value | diff --git a/python/ql/test/query-tests/Security/CWE-094/CodeInjection.qlref b/python/ql/test/query-tests/Security/CWE-094/CodeInjection.qlref new file mode 100644 index 00000000000..fe9adbf3b64 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-094/CodeInjection.qlref @@ -0,0 +1 @@ +Security/CWE-094/CodeInjection.ql diff --git a/python/ql/test/query-tests/Security/CWE-094/code_injection.py b/python/ql/test/query-tests/Security/CWE-094/code_injection.py new file mode 100644 index 00000000000..2633f55cbdb --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-094/code_injection.py @@ -0,0 +1,12 @@ +from django.conf.urls import url +import base64 + +def code_execution(request): + if request.method == 'POST': + first_name = request.POST.get('first_name', '') + exec(base64.decodestring(first_name)) + +urlpatterns = [ + # Route to code_execution + url(r'^code-ex$', code_execution, name='code-execution') +] diff --git a/python/ql/test/query-tests/Security/CWE-094/options b/python/ql/test/query-tests/Security/CWE-094/options new file mode 100644 index 00000000000..dce78f52325 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-094/options @@ -0,0 +1,2 @@ +semmle-extractor-options: -p ../lib/ --max-import-depth=3 +optimize: true diff --git a/python/ql/test/query-tests/Security/CWE-209/StackTraceExposure.expected b/python/ql/test/query-tests/Security/CWE-209/StackTraceExposure.expected new file mode 100644 index 00000000000..7c16a2d95f8 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-209/StackTraceExposure.expected @@ -0,0 +1 @@ +| test.py:16:16:16:37 | flask.routed.response | $@ may be exposed to an external user | test.py:16:16:16:37 | exception.info.source | Error information | diff --git a/python/ql/test/query-tests/Security/CWE-209/StackTraceExposure.qlref b/python/ql/test/query-tests/Security/CWE-209/StackTraceExposure.qlref new file mode 100644 index 00000000000..18cf2d49a1a --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-209/StackTraceExposure.qlref @@ -0,0 +1 @@ +Security/CWE-209/StackTraceExposure.ql diff --git a/python/ql/test/query-tests/Security/CWE-209/options b/python/ql/test/query-tests/Security/CWE-209/options new file mode 100644 index 00000000000..2729d5a143a --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-209/options @@ -0,0 +1 @@ +semmle-extractor-options: -p ../lib/ --max-import-depth=2 diff --git a/python/ql/test/query-tests/Security/CWE-209/test.py b/python/ql/test/query-tests/Security/CWE-209/test.py new file mode 100644 index 00000000000..169dc091ddd --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-209/test.py @@ -0,0 +1,25 @@ +from flask import Flask +app = Flask(__name__) + + +import traceback + +def do_computation(): + raise Exception("Secret info") + +# BAD +@app.route('/bad') +def server_bad(): + try: + do_computation() + except Exception as e: + return traceback.format_exc() + +# GOOD +@app.route('/good') +def server_good(): + try: + do_computation() + except Exception as e: + log(traceback.format_exc()) + return "An internal error has occurred!" diff --git a/python/ql/test/query-tests/Security/CWE-327/BrokenCryptoAlgorithm.expected b/python/ql/test/query-tests/Security/CWE-327/BrokenCryptoAlgorithm.expected new file mode 100644 index 00000000000..9fb4ed3ed5d --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-327/BrokenCryptoAlgorithm.expected @@ -0,0 +1,2 @@ +| test_cryptography.py:7:29:7:37 | Use of weak crypto algorithm | Sensitive data from $@ is used in a broken or weak cryptographic algorithm. | test_cryptography.py:4:17:4:30 | sensitive.data.source | sensitive.data.source | +| test_pycrypto.py:6:27:6:35 | Use of weak crypto algorithm ARC4 | Sensitive data from $@ is used in a broken or weak cryptographic algorithm. | test_pycrypto.py:4:17:4:30 | sensitive.data.source | sensitive.data.source | diff --git a/python/ql/test/query-tests/Security/CWE-327/BrokenCryptoAlgorithm.qlref b/python/ql/test/query-tests/Security/CWE-327/BrokenCryptoAlgorithm.qlref new file mode 100644 index 00000000000..3f7aff53700 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-327/BrokenCryptoAlgorithm.qlref @@ -0,0 +1 @@ +Security/CWE-327/BrokenCryptoAlgorithm.ql diff --git a/python/ql/test/query-tests/Security/CWE-327/TestNode.expected b/python/ql/test/query-tests/Security/CWE-327/TestNode.expected new file mode 100644 index 00000000000..0a184314a93 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-327/TestNode.expected @@ -0,0 +1,14 @@ +| Taint Crypto.Cipher.ARC4 | test_pycrypto.py:5:14:5:27 | test_pycrypto.py:5 | test_pycrypto.py:5:14:5:27 | Attribute() | | +| Taint Crypto.Cipher.ARC4 | test_pycrypto.py:6:12:6:17 | test_pycrypto.py:6 | test_pycrypto.py:6:12:6:17 | cipher | | +| Taint cryptography.Cipher.RC4 | test_cryptography.py:5:14:5:47 | test_cryptography.py:5 | test_cryptography.py:5:14:5:47 | Cipher() | | +| Taint cryptography.Cipher.RC4 | test_cryptography.py:6:17:6:22 | test_cryptography.py:6 | test_cryptography.py:6:17:6:22 | cipher | | +| Taint cryptography.encryptor.RC4 | test_cryptography.py:6:17:6:34 | test_cryptography.py:6 | test_cryptography.py:6:17:6:34 | Attribute() | | +| Taint cryptography.encryptor.RC4 | test_cryptography.py:7:12:7:20 | test_cryptography.py:7 | test_cryptography.py:7:12:7:20 | encryptor | | +| Taint cryptography.encryptor.RC4 | test_cryptography.py:7:42:7:50 | test_cryptography.py:7 | test_cryptography.py:7:42:7:50 | encryptor | | +| Taint sensitive.data | test_cryptography.py:4:17:4:28 | test_cryptography.py:4 | test_cryptography.py:4:17:4:28 | get_password | | +| Taint sensitive.data | test_cryptography.py:4:17:4:30 | test_cryptography.py:4 | test_cryptography.py:4:17:4:30 | get_password() | | +| Taint sensitive.data | test_cryptography.py:7:29:7:37 | test_cryptography.py:7 | test_cryptography.py:7:29:7:37 | dangerous | | +| Taint sensitive.data | test_cryptography.py:7:42:7:50 | test_cryptography.py:7 | test_cryptography.py:7:42:7:50 | encryptor | | +| Taint sensitive.data | test_pycrypto.py:4:17:4:28 | test_pycrypto.py:4 | test_pycrypto.py:4:17:4:28 | get_password | | +| Taint sensitive.data | test_pycrypto.py:4:17:4:30 | test_pycrypto.py:4 | test_pycrypto.py:4:17:4:30 | get_password() | | +| Taint sensitive.data | test_pycrypto.py:6:27:6:35 | test_pycrypto.py:6 | test_pycrypto.py:6:27:6:35 | dangerous | | diff --git a/python/ql/test/query-tests/Security/CWE-327/TestNode.ql b/python/ql/test/query-tests/Security/CWE-327/TestNode.ql new file mode 100644 index 00000000000..71ec310dd39 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-327/TestNode.ql @@ -0,0 +1,9 @@ +import python +import semmle.python.security.TaintTracking + +import python +import semmle.python.security.SensitiveData +import semmle.python.security.Crypto + +from TaintedNode n +select n.getTrackedValue(), n.getLocation(), n.getNode().getNode(), n.getContext() diff --git a/python/ql/test/query-tests/Security/CWE-327/options b/python/ql/test/query-tests/Security/CWE-327/options new file mode 100644 index 00000000000..492768b3481 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-327/options @@ -0,0 +1 @@ +semmle-extractor-options: -p ../lib/ --max-import-depth=3 diff --git a/python/ql/test/query-tests/Security/CWE-327/test_cryptography.py b/python/ql/test/query-tests/Security/CWE-327/test_cryptography.py new file mode 100644 index 00000000000..37baa1d1a80 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-327/test_cryptography.py @@ -0,0 +1,8 @@ +from cryptography.hazmat.primitives.ciphers import Cipher, algorithms + +def get_badly_encrypted_password(): + dangerous = get_password() + cipher = Cipher(algorithms.ARC4(key), _, _) + encryptor = cipher.encryptor() + return encryptor.update(dangerous) + encryptor.finalize() + diff --git a/python/ql/test/query-tests/Security/CWE-327/test_pycrypto.py b/python/ql/test/query-tests/Security/CWE-327/test_pycrypto.py new file mode 100644 index 00000000000..49f910f1af8 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-327/test_pycrypto.py @@ -0,0 +1,7 @@ +from Crypto.Cipher import ARC4 + +def get_badly_encrypted_password(): + dangerous = get_password() + cipher = ARC4.new(_, _) + return cipher.encrypt(dangerous) + diff --git a/python/ql/test/query-tests/Security/CWE-502/UnsafeDeserialization.expected b/python/ql/test/query-tests/Security/CWE-502/UnsafeDeserialization.expected new file mode 100644 index 00000000000..a0d1a9f8b4e --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-502/UnsafeDeserialization.expected @@ -0,0 +1,3 @@ +| test.py:12:18:12:24 | unpickling untrusted data | Deserializing of $@. | test.py:11:15:11:26 | flask.request.args | untrusted input | +| test.py:13:15:13:21 | yaml.load vulnerability | Deserializing of $@. | test.py:11:15:11:26 | flask.request.args | untrusted input | +| test.py:14:19:14:25 | unmarshaling vulnerability | Deserializing of $@. | test.py:11:15:11:26 | flask.request.args | untrusted input | diff --git a/python/ql/test/query-tests/Security/CWE-502/UnsafeDeserialization.qlref b/python/ql/test/query-tests/Security/CWE-502/UnsafeDeserialization.qlref new file mode 100644 index 00000000000..fa9c0ceb3cb --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-502/UnsafeDeserialization.qlref @@ -0,0 +1 @@ +Security/CWE-502/UnsafeDeserialization.ql diff --git a/python/ql/test/query-tests/Security/CWE-502/options b/python/ql/test/query-tests/Security/CWE-502/options new file mode 100644 index 00000000000..b63c517ee29 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-502/options @@ -0,0 +1,2 @@ +semmle-extractor-options: --max-import-depth=2 -p ../lib +optimize: true diff --git a/python/ql/test/query-tests/Security/CWE-502/test.py b/python/ql/test/query-tests/Security/CWE-502/test.py new file mode 100644 index 00000000000..27a003136c0 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-502/test.py @@ -0,0 +1,16 @@ +import flask +import pickle +import yaml +import marshal + +from flask import Flask, request +app = Flask(__name__) + +@app.route("/") +def hello(): + payload = request.args.get('payload') + pickle.loads(payload) + yaml.load(payload) + marshal.loads(payload) + + diff --git a/python/ql/test/query-tests/Security/CWE-601/UrlRedirect.expected b/python/ql/test/query-tests/Security/CWE-601/UrlRedirect.expected new file mode 100644 index 00000000000..a62664e2918 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-601/UrlRedirect.expected @@ -0,0 +1 @@ +| test.py:8:21:8:26 | flask.redirect | Untrusted URL redirection due to $@. | test.py:7:22:7:33 | flask.request.args | a user-provided value | diff --git a/python/ql/test/query-tests/Security/CWE-601/UrlRedirect.qlref b/python/ql/test/query-tests/Security/CWE-601/UrlRedirect.qlref new file mode 100644 index 00000000000..8b63d80f0db --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-601/UrlRedirect.qlref @@ -0,0 +1,2 @@ +Security/CWE-601/UrlRedirect.ql + diff --git a/python/ql/test/query-tests/Security/CWE-601/options b/python/ql/test/query-tests/Security/CWE-601/options new file mode 100644 index 00000000000..84717fe64cf --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-601/options @@ -0,0 +1 @@ +semmle-extractor-options: --max-import-depth=2 -p ../lib diff --git a/python/ql/test/query-tests/Security/CWE-601/test.py b/python/ql/test/query-tests/Security/CWE-601/test.py new file mode 100644 index 00000000000..34ad352db0e --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-601/test.py @@ -0,0 +1,18 @@ +from flask import Flask, request, redirect + +app = Flask(__name__) + +@app.route('/') +def hello(): + target = files = request.args.get('target', '') + return redirect(target, code=302) + + +#Check for safe prefixes + +@app.route('/ok') +def ok(): + untrusted = request.args.get('ok', '') + safe = "safe" + safe += untrusted + return redirect(safe, code=302) diff --git a/python/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.expected b/python/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.expected new file mode 100644 index 00000000000..d90e739799b --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.expected @@ -0,0 +1,2 @@ +| test.py:14:18:14:25 | Taint sink | Use of hardcoded credentials from $@. | test.py:5:12:5:24 | Taint source | Taint source | +| test.py:15:18:15:25 | Taint sink | Use of hardcoded credentials from $@. | test.py:6:12:6:25 | Taint source | Taint source | diff --git a/python/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.qlref b/python/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.qlref new file mode 100644 index 00000000000..0d0fafa271c --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.qlref @@ -0,0 +1 @@ +Security/CWE-798/HardcodedCredentials.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Security/CWE-798/test.py b/python/ql/test/query-tests/Security/CWE-798/test.py new file mode 100644 index 00000000000..bcfb1feee4c --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-798/test.py @@ -0,0 +1,19 @@ + + +HOST = "acme-trading.com" +PORT = 8000 +USERNAME = "road_runner" +PASSWORD = "insecure_pwd" + + +def sell(client, units): + + conn = client.connect( + host=HOST, + port=PORT, + username=USERNAME, + password=PASSWORD) + + conn.cmd("sell", 1000) + conn.close() + diff --git a/python/ql/test/query-tests/Security/lib/Crypto/Cipher/AES.py b/python/ql/test/query-tests/Security/lib/Crypto/Cipher/AES.py new file mode 100644 index 00000000000..bcab58405ea --- /dev/null +++ b/python/ql/test/query-tests/Security/lib/Crypto/Cipher/AES.py @@ -0,0 +1,3 @@ + +def new(*args): + pass diff --git a/python/ql/test/query-tests/Security/lib/Crypto/Cipher/ARC4.py b/python/ql/test/query-tests/Security/lib/Crypto/Cipher/ARC4.py new file mode 100644 index 00000000000..bcab58405ea --- /dev/null +++ b/python/ql/test/query-tests/Security/lib/Crypto/Cipher/ARC4.py @@ -0,0 +1,3 @@ + +def new(*args): + pass diff --git a/python/ql/test/query-tests/Security/lib/Crypto/Cipher/__init__.py b/python/ql/test/query-tests/Security/lib/Crypto/Cipher/__init__.py new file mode 100644 index 00000000000..ab22f65be6e --- /dev/null +++ b/python/ql/test/query-tests/Security/lib/Crypto/Cipher/__init__.py @@ -0,0 +1 @@ +__all__ = ['AES', 'ARC4'] diff --git a/python/ql/test/query-tests/Security/lib/Crypto/__init__.py b/python/ql/test/query-tests/Security/lib/Crypto/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/query-tests/Security/lib/cryptography/__init__.py b/python/ql/test/query-tests/Security/lib/cryptography/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/query-tests/Security/lib/cryptography/hazmat/__init__.py b/python/ql/test/query-tests/Security/lib/cryptography/hazmat/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/query-tests/Security/lib/cryptography/hazmat/primitives/__init__.py b/python/ql/test/query-tests/Security/lib/cryptography/hazmat/primitives/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/query-tests/Security/lib/cryptography/hazmat/primitives/ciphers/__init__.py b/python/ql/test/query-tests/Security/lib/cryptography/hazmat/primitives/ciphers/__init__.py new file mode 100644 index 00000000000..f37f14e88f8 --- /dev/null +++ b/python/ql/test/query-tests/Security/lib/cryptography/hazmat/primitives/ciphers/__init__.py @@ -0,0 +1,3 @@ + +class Cipher(object): + pass diff --git a/python/ql/test/query-tests/Security/lib/cryptography/hazmat/primitives/ciphers/algorithms.py b/python/ql/test/query-tests/Security/lib/cryptography/hazmat/primitives/ciphers/algorithms.py new file mode 100644 index 00000000000..e423804e4f5 --- /dev/null +++ b/python/ql/test/query-tests/Security/lib/cryptography/hazmat/primitives/ciphers/algorithms.py @@ -0,0 +1,3 @@ + +class ARC4(object): + name = "RC4" diff --git a/python/ql/test/query-tests/Security/lib/django/__init__.py b/python/ql/test/query-tests/Security/lib/django/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/query-tests/Security/lib/django/conf/__init__.py b/python/ql/test/query-tests/Security/lib/django/conf/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/query-tests/Security/lib/django/conf/urls.py b/python/ql/test/query-tests/Security/lib/django/conf/urls.py new file mode 100644 index 00000000000..cf65525e893 --- /dev/null +++ b/python/ql/test/query-tests/Security/lib/django/conf/urls.py @@ -0,0 +1,7 @@ + +def url(pattern, *args): + pass + +def patterns(*urls): + pass + diff --git a/python/ql/test/query-tests/Security/lib/django/db/__init__.py b/python/ql/test/query-tests/Security/lib/django/db/__init__.py new file mode 100644 index 00000000000..3e291c5731d --- /dev/null +++ b/python/ql/test/query-tests/Security/lib/django/db/__init__.py @@ -0,0 +1 @@ +connection = object() diff --git a/python/ql/test/query-tests/Security/lib/django/db/models/__init__.py b/python/ql/test/query-tests/Security/lib/django/db/models/__init__.py new file mode 100644 index 00000000000..eb9c72adc45 --- /dev/null +++ b/python/ql/test/query-tests/Security/lib/django/db/models/__init__.py @@ -0,0 +1,2 @@ +class Model: + pass diff --git a/python/ql/test/query-tests/Security/lib/django/db/models/expressions.py b/python/ql/test/query-tests/Security/lib/django/db/models/expressions.py new file mode 100644 index 00000000000..d7e0d1c27b6 --- /dev/null +++ b/python/ql/test/query-tests/Security/lib/django/db/models/expressions.py @@ -0,0 +1,2 @@ +class RawSQL: + pass diff --git a/python/ql/test/query-tests/Security/lib/flask/__init__.py b/python/ql/test/query-tests/Security/lib/flask/__init__.py new file mode 100644 index 00000000000..033c49b93cd --- /dev/null +++ b/python/ql/test/query-tests/Security/lib/flask/__init__.py @@ -0,0 +1,20 @@ + + +class Flask(object): + pass + +from .globals import request + +class Response(object): + pass + +def redirect(location, code=302, Response=None): + pass + +def make_response(rv): + if isinstance(rv, str): + return Response(rv) + elif isinstance(rv, Response): + return rv + else: + pass diff --git a/python/ql/test/query-tests/Security/lib/flask/globals.py b/python/ql/test/query-tests/Security/lib/flask/globals.py new file mode 100644 index 00000000000..ef717051f79 --- /dev/null +++ b/python/ql/test/query-tests/Security/lib/flask/globals.py @@ -0,0 +1,5 @@ + +class LocalProxy(object): + pass + +request = LocalProxy() diff --git a/python/ql/test/query-tests/Security/lib/flask/urls.py b/python/ql/test/query-tests/Security/lib/flask/urls.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/query-tests/Security/lib/flask/views.py b/python/ql/test/query-tests/Security/lib/flask/views.py new file mode 100644 index 00000000000..2cd20261dad --- /dev/null +++ b/python/ql/test/query-tests/Security/lib/flask/views.py @@ -0,0 +1,11 @@ + + + +class View(object): + pass + + +class MethodView(object): + pass + + diff --git a/python/ql/test/query-tests/Security/lib/yaml.py b/python/ql/test/query-tests/Security/lib/yaml.py new file mode 100644 index 00000000000..51fe2fd1d42 --- /dev/null +++ b/python/ql/test/query-tests/Security/lib/yaml.py @@ -0,0 +1,2 @@ +def load(s): + pass diff --git a/python/ql/test/query-tests/Security/options b/python/ql/test/query-tests/Security/options new file mode 100644 index 00000000000..58ad829f5a8 --- /dev/null +++ b/python/ql/test/query-tests/Security/options @@ -0,0 +1 @@ +optimize: true diff --git a/python/ql/test/query-tests/Statements/DocStrings/DocStrings.expected b/python/ql/test/query-tests/Statements/DocStrings/DocStrings.expected new file mode 100644 index 00000000000..29cebbf4f9d --- /dev/null +++ b/python/ql/test/query-tests/Statements/DocStrings/DocStrings.expected @@ -0,0 +1,4 @@ +| DocStrings.py:0:0:0:0 | Module DocStrings | Module DocStrings does not have a docstring | +| DocStrings.py:40:1:40:13 | Class Not_OK | Class Not_OK does not have a docstring | +| DocStrings.py:48:5:48:26 | Function meth_not_ok | Function meth_not_ok does not have a docstring | +| DocStrings.py:53:1:53:17 | Function not_ok | Function not_ok does not have a docstring | diff --git a/python/ql/test/query-tests/Statements/DocStrings/DocStrings.py b/python/ql/test/query-tests/Statements/DocStrings/DocStrings.py new file mode 100644 index 00000000000..9a5c0f01de9 --- /dev/null +++ b/python/ql/test/query-tests/Statements/DocStrings/DocStrings.py @@ -0,0 +1,59 @@ +#Modules should have docstrings + +class OK: + 'Classes need doc strings' + + 'Two strings' + pass + "Another string" +#All functions must be multi-line or there are ignored by the query + + +class _OK: + 'Unless they are private' + pass + pass + +def f_ok(x, y): + 'And functions' + pass + pass + +def _f_ok(y, z): + #Unless they are private + pass + pass + +class OK2: + 'doc-string' + + def meth_ok(self): + 'Methods need docstrings' + pass + pass + + def _meth_ok(self): + #Unless they are private + pass + pass + +class Not_OK: + #No docstring + + def meth_ok(self): + 'Methods need docstrings' + pass + pass + + def meth_not_ok(self): + #No doc-string + pass + pass + +def not_ok(x, y): + #Should have a doc-string + pass + pass + + + diff --git a/python/ql/test/query-tests/Statements/DocStrings/DocStrings.qlref b/python/ql/test/query-tests/Statements/DocStrings/DocStrings.qlref new file mode 100644 index 00000000000..1ff50d155fb --- /dev/null +++ b/python/ql/test/query-tests/Statements/DocStrings/DocStrings.qlref @@ -0,0 +1 @@ +Statements/DocStrings.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Statements/asserts/AssertLiteralConstant.expected b/python/ql/test/query-tests/Statements/asserts/AssertLiteralConstant.expected new file mode 100644 index 00000000000..b45a5f5d86d --- /dev/null +++ b/python/ql/test/query-tests/Statements/asserts/AssertLiteralConstant.expected @@ -0,0 +1,10 @@ +| assert.py:34:9:34:26 | Assert | Assert of literal constant True. | +| assert.py:36:9:36:19 | Assert | Assert of literal constant True. | +| assert.py:40:9:40:27 | Assert | Assert of literal constant False. | +| assert.py:44:9:44:23 | Assert | Assert of literal constant 0. | +| assert.py:48:9:48:23 | Assert | Assert of literal constant 1. | +| assert.py:52:9:52:24 | Assert | Assert of literal constant "". | +| assert.py:56:9:56:25 | Assert | Assert of literal constant "X". | +| assert.py:58:9:58:18 | Assert | Assert of literal constant "X". | +| assert.py:94:9:94:29 | Assert | Assert of literal constant False. | +| assert.py:102:9:102:29 | Assert | Assert of literal constant False. | diff --git a/python/ql/test/query-tests/Statements/asserts/AssertLiteralConstant.qlref b/python/ql/test/query-tests/Statements/asserts/AssertLiteralConstant.qlref new file mode 100644 index 00000000000..1f301867a08 --- /dev/null +++ b/python/ql/test/query-tests/Statements/asserts/AssertLiteralConstant.qlref @@ -0,0 +1 @@ +Statements/AssertLiteralConstant.ql diff --git a/python/ql/test/query-tests/Statements/asserts/AssertOnTuple.expected b/python/ql/test/query-tests/Statements/asserts/AssertOnTuple.expected new file mode 100644 index 00000000000..7945ccaf586 --- /dev/null +++ b/python/ql/test/query-tests/Statements/asserts/AssertOnTuple.expected @@ -0,0 +1,2 @@ +| assert.py:16:5:16:13 | Assert | Assertion of empty tuple is always False. | +| assert.py:17:5:17:17 | Assert | Assertion of non-empty tuple is always True. | diff --git a/python/ql/test/query-tests/Statements/asserts/AssertOnTuple.qlref b/python/ql/test/query-tests/Statements/asserts/AssertOnTuple.qlref new file mode 100644 index 00000000000..6fe2960c1c5 --- /dev/null +++ b/python/ql/test/query-tests/Statements/asserts/AssertOnTuple.qlref @@ -0,0 +1 @@ +Statements/AssertOnTuple.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Statements/asserts/SideEffectInAssert.expected b/python/ql/test/query-tests/Statements/asserts/SideEffectInAssert.expected new file mode 100644 index 00000000000..4f46cff1e76 --- /dev/null +++ b/python/ql/test/query-tests/Statements/asserts/SideEffectInAssert.expected @@ -0,0 +1,2 @@ +| assert.py:5:5:5:20 | Assert | This 'assert' statement contains $@ which may have side effects. | assert.py:5:13:5:19 | Yield | an expression | +| assert.py:8:5:8:22 | Assert | This 'assert' statement contains $@ which may have side effects. | assert.py:8:12:8:22 | Attribute() | an expression | diff --git a/python/ql/test/query-tests/Statements/asserts/SideEffectInAssert.qlref b/python/ql/test/query-tests/Statements/asserts/SideEffectInAssert.qlref new file mode 100644 index 00000000000..7dd70f3fed2 --- /dev/null +++ b/python/ql/test/query-tests/Statements/asserts/SideEffectInAssert.qlref @@ -0,0 +1 @@ +Statements/SideEffectInAssert.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Statements/asserts/assert.py b/python/ql/test/query-tests/Statements/asserts/assert.py new file mode 100644 index 00000000000..854fffa3382 --- /dev/null +++ b/python/ql/test/query-tests/Statements/asserts/assert.py @@ -0,0 +1,106 @@ +import sys +import six + +def _f(): + assert (yield 3) + x = [ 1 ] + assert len(x) #Call without side-effects + assert sys.exit(1) #Call with side-effects + expected_types = (Response, six.text_type, six.binary_type) + assert isinstance(obj, expected_types), \ + "obj must be %s, not %s" % ( + " or ".join(t.__name__ for t in expected_types), + type(obj).__name__) + +def assert_tuple(x, y): + assert () + assert (x, y) + + + + + + + + + + + + + + +def error_assert_true(x): + if x: + assert True, "Bad" + else: + assert True + +def error_assert_false(x): + if x: + assert False, "Bad" + +def error_assert_zero(x): + if x: + assert 0, "Bad" + +def error_assert_one(x): + if x: + assert 1, "Bad" + +def error_assert_empty_string(x): + if x: + assert "", "Bad" + +def error_assert_nonempty_string(x): + if x: + assert "X", "Bad" + else: + assert "X" + +def ok_assert_false(x): + if x: + assert 0==1, "Ok" + +class TestCase: + pass + +class MyTest(TestCase): + def test_ok_assert_in_test(self, x): + if x: + assert False, "Ok" + +def ok_assert_in_final_branch3(x): + if foo(x): + pass + elif bar(x): + pass + elif quux(x): + pass + else: + assert False, "Ok" + +def ok_assert_in_final_branch2(x): + if foo(x): + pass + elif bar(x): + pass + else: + assert False, "Ok" + +def error_assert_in_final_branch1(x): + if foo(x): + pass + else: + assert False, "Error" + +def error_assert_in_intermediate_branch(x): + if foo(x): + pass + elif bar(x): + pass + elif quux(x): + assert False, "Error" + elif yks(x): + pass + else: + pass \ No newline at end of file diff --git a/python/ql/test/query-tests/Statements/exit/UseOfExit.expected b/python/ql/test/query-tests/Statements/exit/UseOfExit.expected new file mode 100644 index 00000000000..76984527df6 --- /dev/null +++ b/python/ql/test/query-tests/Statements/exit/UseOfExit.expected @@ -0,0 +1 @@ +| test.py:7:9:7:15 | ControlFlowNode for exit() | The 'exit' site.Quitter object may not exist if the 'site' module is not loaded or is modified. | diff --git a/python/ql/test/query-tests/Statements/exit/UseOfExit.qlref b/python/ql/test/query-tests/Statements/exit/UseOfExit.qlref new file mode 100644 index 00000000000..5925d933914 --- /dev/null +++ b/python/ql/test/query-tests/Statements/exit/UseOfExit.qlref @@ -0,0 +1 @@ +Statements/UseOfExit.ql diff --git a/python/ql/test/query-tests/Statements/exit/test.py b/python/ql/test/query-tests/Statements/exit/test.py new file mode 100644 index 00000000000..ae03479497e --- /dev/null +++ b/python/ql/test/query-tests/Statements/exit/test.py @@ -0,0 +1,7 @@ + +def main(): + try: + process() + except Exception as ex: + print(ex) + exit(1) diff --git a/python/ql/test/query-tests/Statements/general/BreakOrReturnInFinally.expected b/python/ql/test/query-tests/Statements/general/BreakOrReturnInFinally.expected new file mode 100644 index 00000000000..57ec1428a5c --- /dev/null +++ b/python/ql/test/query-tests/Statements/general/BreakOrReturnInFinally.expected @@ -0,0 +1,3 @@ +| test.py:11:13:11:17 | Break | 'break' in a finally block will swallow any exceptions raised. | +| test.py:19:13:19:20 | Return | 'return' in a finally block will swallow any exceptions raised. | +| test.py:37:13:37:18 | Return | 'return' in a finally block will swallow any exceptions raised. | diff --git a/python/ql/test/query-tests/Statements/general/BreakOrReturnInFinally.qlref b/python/ql/test/query-tests/Statements/general/BreakOrReturnInFinally.qlref new file mode 100644 index 00000000000..0a710cdde9c --- /dev/null +++ b/python/ql/test/query-tests/Statements/general/BreakOrReturnInFinally.qlref @@ -0,0 +1 @@ +Statements/BreakOrReturnInFinally.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Statements/general/C_StyleParentheses.expected b/python/ql/test/query-tests/Statements/general/C_StyleParentheses.expected new file mode 100644 index 00000000000..a7fa79d219a --- /dev/null +++ b/python/ql/test/query-tests/Statements/general/C_StyleParentheses.expected @@ -0,0 +1,4 @@ +| test.py:109:5:109:8 | cond | Parenthesized condition in 'if' statement. | +| test.py:112:8:112:11 | cond | Parenthesized condition in 'while' statement. | +| test.py:115:9:115:12 | test | Parenthesized test in 'assert' statement. | +| test.py:118:13:118:13 | x | Parenthesized value in 'return' statement. | diff --git a/python/ql/test/query-tests/Statements/general/C_StyleParentheses.qlref b/python/ql/test/query-tests/Statements/general/C_StyleParentheses.qlref new file mode 100644 index 00000000000..6af1d43f7c6 --- /dev/null +++ b/python/ql/test/query-tests/Statements/general/C_StyleParentheses.qlref @@ -0,0 +1 @@ +Statements/C_StyleParentheses.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Statements/general/ConstantInConditional.expected b/python/ql/test/query-tests/Statements/general/ConstantInConditional.expected new file mode 100644 index 00000000000..95d67655558 --- /dev/null +++ b/python/ql/test/query-tests/Statements/general/ConstantInConditional.expected @@ -0,0 +1,2 @@ +| statements_test.py:5:8:5:11 | True | Testing a constant will always give the same result. | +| statements_test.py:9:8:9:8 | IntegerLiteral | Testing a constant will always give the same result. | diff --git a/python/ql/test/query-tests/Statements/general/ConstantInConditional.qlref b/python/ql/test/query-tests/Statements/general/ConstantInConditional.qlref new file mode 100644 index 00000000000..c4b9b9a555b --- /dev/null +++ b/python/ql/test/query-tests/Statements/general/ConstantInConditional.qlref @@ -0,0 +1 @@ +Statements/ConstantInConditional.ql diff --git a/python/ql/test/query-tests/Statements/general/MismatchInMultipleAssignment.expected b/python/ql/test/query-tests/Statements/general/MismatchInMultipleAssignment.expected new file mode 100644 index 00000000000..88b3dfbb008 --- /dev/null +++ b/python/ql/test/query-tests/Statements/general/MismatchInMultipleAssignment.expected @@ -0,0 +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:163:5:163:23 | AssignStmt | Left hand side of assignment contains 3 variables, but right hand side is a $@ of length 5. | statements_test.py:163:13:163:23 | statements_test.py:163 | list | +| statements_test.py:172:5:172:48 | AssignStmt | Left hand side of assignment contains 3 variables, but right hand side is a $@ of length 5. | statements_test.py:167:16:167:24 | statements_test.py:167 | tuple | +| statements_test.py:172:5:172:48 | AssignStmt | Left hand side of assignment contains 3 variables, but right hand side is a $@ of length 6. | statements_test.py:169:16:169:26 | statements_test.py:169 | tuple | diff --git a/python/ql/test/query-tests/Statements/general/MismatchInMultipleAssignment.qlref b/python/ql/test/query-tests/Statements/general/MismatchInMultipleAssignment.qlref new file mode 100644 index 00000000000..f7e01617f9e --- /dev/null +++ b/python/ql/test/query-tests/Statements/general/MismatchInMultipleAssignment.qlref @@ -0,0 +1 @@ +Statements/MismatchInMultipleAssignment.ql diff --git a/python/ql/test/query-tests/Statements/general/ModificationOfLocals.expected b/python/ql/test/query-tests/Statements/general/ModificationOfLocals.expected new file mode 100644 index 00000000000..547cec0c3b8 --- /dev/null +++ b/python/ql/test/query-tests/Statements/general/ModificationOfLocals.expected @@ -0,0 +1,5 @@ +| test.py:98:5:98:17 | Subscript | Modification of the locals() dictionary will have no effect on the local variables. | +| test.py:100:5:100:28 | Attribute() | Modification of the locals() dictionary will have no effect on the local variables. | +| test.py:101:5:101:14 | Attribute() | Modification of the locals() dictionary will have no effect on the local variables. | +| test.py:102:9:102:14 | Subscript | Modification of the locals() dictionary will have no effect on the local variables. | +| test.py:103:5:103:13 | Attribute() | Modification of the locals() dictionary will have no effect on the local variables. | diff --git a/python/ql/test/query-tests/Statements/general/ModificationOfLocals.qlref b/python/ql/test/query-tests/Statements/general/ModificationOfLocals.qlref new file mode 100644 index 00000000000..88a666435e3 --- /dev/null +++ b/python/ql/test/query-tests/Statements/general/ModificationOfLocals.qlref @@ -0,0 +1 @@ +Statements/ModificationOfLocals.ql diff --git a/python/ql/test/query-tests/Statements/general/NestedLoopsSameVariable.expected b/python/ql/test/query-tests/Statements/general/NestedLoopsSameVariable.expected new file mode 100644 index 00000000000..b7b3f0e56ed --- /dev/null +++ b/python/ql/test/query-tests/Statements/general/NestedLoopsSameVariable.expected @@ -0,0 +1,6 @@ +| nested.py:3:9:3:38 | For | Nested for statement uses loop variable 'repeated_var' of enclosing $@. | nested.py:2:5:2:34 | For | for statement | +| nested.py:19:13:19:23 | For | Nested for statement uses loop variable 'x' of enclosing $@. | nested.py:17:5:17:15 | For | for statement | +| nested.py:27:9:27:19 | For | Nested for statement uses loop variable 'x' of enclosing $@. | nested.py:25:5:25:15 | For | for statement | +| nested.py:35:9:35:19 | For | Nested for statement uses loop variable 'x' of enclosing $@. | nested.py:32:5:32:15 | For | for statement | +| nested.py:42:9:42:19 | For | Nested for statement uses loop variable 'x' of enclosing $@. | nested.py:41:5:41:15 | For | for statement | +| nested.py:50:9:50:19 | For | Nested for statement uses loop variable 'x' of enclosing $@. | nested.py:48:5:48:15 | For | for statement | diff --git a/python/ql/test/query-tests/Statements/general/NestedLoopsSameVariable.qlref b/python/ql/test/query-tests/Statements/general/NestedLoopsSameVariable.qlref new file mode 100644 index 00000000000..75a4032a05f --- /dev/null +++ b/python/ql/test/query-tests/Statements/general/NestedLoopsSameVariable.qlref @@ -0,0 +1 @@ +Statements/NestedLoopsSameVariable.ql diff --git a/python/ql/test/query-tests/Statements/general/NestedLoopsSameVariableWithReuse.expected b/python/ql/test/query-tests/Statements/general/NestedLoopsSameVariableWithReuse.expected new file mode 100644 index 00000000000..086f12ea27c --- /dev/null +++ b/python/ql/test/query-tests/Statements/general/NestedLoopsSameVariableWithReuse.expected @@ -0,0 +1,3 @@ +| nested.py:3:9:3:38 | For | Nested for statement $@ loop variable 'repeated_var' of enclosing $@. | nested.py:5:22:5:33 | repeated_var | uses | nested.py:2:5:2:34 | For | for statement | +| nested.py:27:9:27:19 | For | Nested for statement $@ loop variable 'x' of enclosing $@. | nested.py:29:13:29:13 | x | uses | nested.py:25:5:25:15 | For | for statement | +| nested.py:50:9:50:19 | For | Nested for statement $@ loop variable 'x' of enclosing $@. | nested.py:54:13:54:13 | x | uses | nested.py:48:5:48:15 | For | for statement | diff --git a/python/ql/test/query-tests/Statements/general/NestedLoopsSameVariableWithReuse.qlref b/python/ql/test/query-tests/Statements/general/NestedLoopsSameVariableWithReuse.qlref new file mode 100644 index 00000000000..d34f2ddb21a --- /dev/null +++ b/python/ql/test/query-tests/Statements/general/NestedLoopsSameVariableWithReuse.qlref @@ -0,0 +1 @@ +Statements/NestedLoopsSameVariableWithReuse.ql diff --git a/python/ql/test/query-tests/Statements/general/NonIteratorInForLoop.expected b/python/ql/test/query-tests/Statements/general/NonIteratorInForLoop.expected new file mode 100755 index 00000000000..308f0aa027e --- /dev/null +++ b/python/ql/test/query-tests/Statements/general/NonIteratorInForLoop.expected @@ -0,0 +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 | diff --git a/python/ql/test/query-tests/Statements/general/NonIteratorInForLoop.qlref b/python/ql/test/query-tests/Statements/general/NonIteratorInForLoop.qlref new file mode 100644 index 00000000000..fb09cace29a --- /dev/null +++ b/python/ql/test/query-tests/Statements/general/NonIteratorInForLoop.qlref @@ -0,0 +1 @@ +Statements/NonIteratorInForLoop.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Statements/general/RedundantAssignment.expected b/python/ql/test/query-tests/Statements/general/RedundantAssignment.expected new file mode 100644 index 00000000000..f997ac54932 --- /dev/null +++ b/python/ql/test/query-tests/Statements/general/RedundantAssignment.expected @@ -0,0 +1,3 @@ +| 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:117:9:117:23 | AssignStmt | This assignment assigns a variable to itself. | diff --git a/python/ql/test/query-tests/Statements/general/RedundantAssignment.qlref b/python/ql/test/query-tests/Statements/general/RedundantAssignment.qlref new file mode 100644 index 00000000000..2c3b08d8766 --- /dev/null +++ b/python/ql/test/query-tests/Statements/general/RedundantAssignment.qlref @@ -0,0 +1 @@ +Statements/RedundantAssignment.ql diff --git a/python/ql/test/query-tests/Statements/general/ShouldUseWithStatement.expected b/python/ql/test/query-tests/Statements/general/ShouldUseWithStatement.expected new file mode 100644 index 00000000000..41a8723db03 --- /dev/null +++ b/python/ql/test/query-tests/Statements/general/ShouldUseWithStatement.expected @@ -0,0 +1 @@ +| test.py:162:9:162:17 | Attribute() | Instance of context-manager class $@ is closed in a finally block. Consider using 'with' statement. | test.py:145:1:145:17 | class CM | CM | diff --git a/python/ql/test/query-tests/Statements/general/ShouldUseWithStatement.qlref b/python/ql/test/query-tests/Statements/general/ShouldUseWithStatement.qlref new file mode 100644 index 00000000000..e1b3d7276ff --- /dev/null +++ b/python/ql/test/query-tests/Statements/general/ShouldUseWithStatement.qlref @@ -0,0 +1 @@ +Statements/ShouldUseWithStatement.ql diff --git a/python/ql/test/query-tests/Statements/general/StringConcatenationInLoop.expected b/python/ql/test/query-tests/Statements/general/StringConcatenationInLoop.expected new file mode 100644 index 00000000000..418308f116d --- /dev/null +++ b/python/ql/test/query-tests/Statements/general/StringConcatenationInLoop.expected @@ -0,0 +1,2 @@ +| performance.py:6:9:6:20 | AugAssign | String concatenation in a loop is quadratic in the number of iterations. | +| performance.py:12:9:12:29 | AssignStmt | String concatenation in a loop is quadratic in the number of iterations. | diff --git a/python/ql/test/query-tests/Statements/general/StringConcatenationInLoop.qlref b/python/ql/test/query-tests/Statements/general/StringConcatenationInLoop.qlref new file mode 100644 index 00000000000..cf694f99e48 --- /dev/null +++ b/python/ql/test/query-tests/Statements/general/StringConcatenationInLoop.qlref @@ -0,0 +1 @@ +Statements/StringConcatenationInLoop.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Statements/general/UnnecessaryDelete.expected b/python/ql/test/query-tests/Statements/general/UnnecessaryDelete.expected new file mode 100644 index 00000000000..f6f7ca1bad2 --- /dev/null +++ b/python/ql/test/query-tests/Statements/general/UnnecessaryDelete.expected @@ -0,0 +1 @@ +| statements_test.py:181:5:181:9 | Delete | Unnecessary deletion of local variable $@ in function $@. | statements_test.py:181:9:181:9 | statements_test.py:181 | x | statements_test.py:179:1:179:31 | statements_test.py:179 | error_unnecessary_delete | diff --git a/python/ql/test/query-tests/Statements/general/UnnecessaryDelete.qlref b/python/ql/test/query-tests/Statements/general/UnnecessaryDelete.qlref new file mode 100644 index 00000000000..e97bf9a872b --- /dev/null +++ b/python/ql/test/query-tests/Statements/general/UnnecessaryDelete.qlref @@ -0,0 +1 @@ +Statements/UnnecessaryDelete.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Statements/general/UnnecessaryElseClause.expected b/python/ql/test/query-tests/Statements/general/UnnecessaryElseClause.expected new file mode 100644 index 00000000000..6f333fc7bbf --- /dev/null +++ b/python/ql/test/query-tests/Statements/general/UnnecessaryElseClause.expected @@ -0,0 +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:68:1:68:13 | While | This 'while' statement has a redundant 'else' as no 'break' is present in the body. | diff --git a/python/ql/test/query-tests/Statements/general/UnnecessaryElseClause.qlref b/python/ql/test/query-tests/Statements/general/UnnecessaryElseClause.qlref new file mode 100644 index 00000000000..8f92883475c --- /dev/null +++ b/python/ql/test/query-tests/Statements/general/UnnecessaryElseClause.qlref @@ -0,0 +1 @@ +Statements/UnnecessaryElseClause.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Statements/general/UnnecessaryPass.expected b/python/ql/test/query-tests/Statements/general/UnnecessaryPass.expected new file mode 100644 index 00000000000..43e81cd1e16 --- /dev/null +++ b/python/ql/test/query-tests/Statements/general/UnnecessaryPass.expected @@ -0,0 +1 @@ +| test.py:41:5:41:8 | Pass | Unnecessary 'pass' statement. | diff --git a/python/ql/test/query-tests/Statements/general/UnnecessaryPass.qlref b/python/ql/test/query-tests/Statements/general/UnnecessaryPass.qlref new file mode 100644 index 00000000000..259ad4df638 --- /dev/null +++ b/python/ql/test/query-tests/Statements/general/UnnecessaryPass.qlref @@ -0,0 +1 @@ +Statements/UnnecessaryPass.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Statements/general/nested.py b/python/ql/test/query-tests/Statements/general/nested.py new file mode 100644 index 00000000000..ac06f2974aa --- /dev/null +++ b/python/ql/test/query-tests/Statements/general/nested.py @@ -0,0 +1,54 @@ +def f1(): + for repeated_var in range(10): + for repeated_var in range(10): + pass + do_something(repeated_var) + +def f2(): + for repeated_but_ok in range(10): + if repeated_but_ok == 7: + break + else: + for repeated_but_ok in range(10): + pass + do_something(repeated_but_ok) + +def f3(y,p): + for x in y: + if p(y): + for x in y: + good1(x) + else: + good2(x) + +def f4(y): + for x in y: + good1(x) + for x in y: + good2(x) + bad(x) + +def f5(y): + for x in y: + good1(x) + temp = x + for x in y: + good2(x) + x = temp + good3(x) + +def f6(y, f): + for x in y: + for x in y: + good(x) + x = f(x) + bad(x) + +def f7(y,p): + for x in y: + good(x) + for x in y: + if p(x): + x = 1 + break + bad(x) diff --git a/python/ql/test/query-tests/Statements/general/performance.py b/python/ql/test/query-tests/Statements/general/performance.py new file mode 100644 index 00000000000..261f8bad1ef --- /dev/null +++ b/python/ql/test/query-tests/Statements/general/performance.py @@ -0,0 +1,12 @@ + +#String concat in loop +def y(seq): + y_accum = '' + for s in seq: + y_accum += s + + +def z(seq): + z_accum = '' + for s in seq: + z_accum = z_accum + s diff --git a/python/ql/test/query-tests/Statements/general/statements_test.py b/python/ql/test/query-tests/Statements/general/statements_test.py new file mode 100644 index 00000000000..37ed94ec57e --- /dev/null +++ b/python/ql/test/query-tests/Statements/general/statements_test.py @@ -0,0 +1,200 @@ + +#Constant in conditional + +def cc1(): + if True: + print("Hi") + +def cc2(): + if 3: + print("Hi") + +def not_cc(): + #Don't treat __debug__ as a constant. It may be immutable, but it is not constant from run to run. + if __debug__: + print("Hi") + +#Mismatch in multiple assignment +def mima(): + x, y, z = 1, 2 + return x, y, z + +#Statement has no effect (4 statements, 3 of which are violations) +"Not a docstring" # This is acceptable as strings can be used as comments. +len +sys.argv + [] +3 == 4 + +#The 'sys' statements have an effect +try: + sys +except: + do_something() + +def exec_used(val): + exec (val) + +#This has an effect: +def effectful(y): + [x for x in y] + + + + + +#Redundant assignment + +ok = 1 +# some people use self-assignment to shut Pyflakes up +ok = ok # Pyflakes + +class Redundant(object): + + x = x # OK + x = x # violation + + def __init__(self, args): + args = args # violation + +#Non redundant assignment +len = len + +#Pointless else clauses +for x in range(10): + func(x) +else: + do_something() + +while x < 10: + func(x) +else: + do_something() + +#OK else clauses: +for x in range(10): + if func(x): + break +else: + do_something() + +while x < 10: + if func(x): + break +else: + do_something() + + + + + + + + + + + +#Not a redundant assignment if a property. +class WithProp(object): + + @property + def x(self): + return self._x + + @prop.setter + def set_x(self, x): + side_effect(x) + self._x = x + + def meth(self): + self.x = self.x + +def maybe_property(x): + x.y = x.y + +class WithoutProp(object): + + def meth(self): + self.x = self.x + +#Accessing a property has an effect: +def prop_acc(): + p = WithProp() + p.x + +#Fake Enum class + +class EnumMeta(type): + def __iter__(self): + return unknown() + +import six + +@six.add_metaclass(EnumMeta) +class Enum: + pass + +#ODASA-3777 +class EnumDerived(Enum): + a = 0 + b = 1 + +for e in EnumDerived: + print(e) + +class SideEffectingAttr(object): + + def __setattr__(self, name, val): + print("hello!") + +s = SideEffectingAttr() +s.foo = s.foo + +#Unreachable, so don't flag as constant test. +if False: + a = 1 + + + + + + + +def error_mismatched_multi_assign_list(): + a,b,c = [1,2,3,4,5] + +def returning_different_tuple_sizes(x): + if x: + return 1,2,3,4,5 + else: + return 1,2,3,4,5,6 + +def error_indirect_mismatched_multi_assign(x): + a, b, c = returning_different_tuple_sizes(x) + return a, b, c + + + + +#ODASA-6754 +def error_unnecessary_delete(): + x = big_object() + del x + +def ok_delete_in_loop(): + y = 0 + for i in range(10): + x = big_object(i) + y += calculation(x) + del x + +def ok_delete_yield(): + x = big_object() + y = calculation(x) + del x + yield y + +def ok_delete_exc_info_cycle_breaker(): + import sys + t, v, tb = sys.exc_info() + y = calculation(t,v,tb) + del t, v, tb diff --git a/python/ql/test/query-tests/Statements/general/test.py b/python/ql/test/query-tests/Statements/general/test.py new file mode 100644 index 00000000000..ab3c53cfcae --- /dev/null +++ b/python/ql/test/query-tests/Statements/general/test.py @@ -0,0 +1,168 @@ + + + + + +def break_in_finally(seq, x): + for i in seq: + try: + x() + finally: + break + return 0 + +def return_in_finally(seq, x): + for i in seq: + try: + x() + finally: + return 1 + return 0 + +#Break in loop in finally +#This is OK +def return_in_loop_in_finally(f, seq): + try: + f() + finally: + for i in seq: + break + +#But this is not +def return_in_loop_in_finally(f, seq): + try: + f() + finally: + for i in seq: + return + +def unnecessary_pass(arg): + print (arg) + pass + +#Non-iterator in for loop + +class NonIterator(object): + + def __init__(self): + pass + +for x in NonIterator(): + do_something(x) + +#None in for loop + +def dodgy_iter(x): + if x: + s = None + else: + s = [0,1] + #Error -- Could be None + for i in s: + print(i) + #Ok Test for None + if s: + for i in s: + print(i) + if s is not None: + for i in s: + print(i) + +#OK to iterate over: +class GetItem(object): + + def __getitem__(self, i): + return i + +for y in GetItem(): + pass + +class D(dict): pass + +for z in D(): + pass + + + + + + + + + + + + +def modification_of_locals(): + x = 0 + locals()['x'] = 1 + l = locals() + l.update({'x':1, 'y':2}) + l.pop('y') + del l['x'] + l.clear() + return x + + +#C-style things + +if (cond): + pass + +while (cond): + pass + +assert (test) + +def parens(x): + return (x) + + +#ODASA-2038 +class classproperty(object): + + def __init__(self, getter): + self.getter = getter + + def __get__(self, instance, instance_type): + return self.getter(instance_type) + +class WithClassProperty(object): + + @classproperty + def x(self): + return [0] + +wcp = WithClassProperty() + +for i in wcp.x: + assert x == 0 +for i in WithClassProperty.x: + assert x == 0 + +#Should use context mamager + +class CM(object): + + def __enter__(self): + pass + + def __exit__(self, ex, cls, tb): + pass + + def write(self, data): + pass + +def no_with(): + f = CM() + try: + f.write("Hello ") + f.write(" World\n") + finally: + f.close() + +#Assert without side-effect +def assert_ok(seq): + assert all(isinstance(element, (str, unicode)) for element in seq) + + diff --git a/python/ql/test/query-tests/Statements/no_effect/StatementNoEffect.expected b/python/ql/test/query-tests/Statements/no_effect/StatementNoEffect.expected new file mode 100644 index 00000000000..5b1626128a4 --- /dev/null +++ b/python/ql/test/query-tests/Statements/no_effect/StatementNoEffect.expected @@ -0,0 +1,5 @@ +| test.py:24:1:24:3 | ExprStmt | This statement has no effect. | +| test.py:25:1:25:13 | ExprStmt | This statement has no effect. | +| test.py:26:1:26:6 | ExprStmt | This statement has no effect. | +| test.py:80:1:80:6 | ExprStmt | This statement has no effect. | +| test.py:116:5:116:9 | ExprStmt | This statement has no effect. | diff --git a/python/ql/test/query-tests/Statements/no_effect/StatementNoEffect.qlref b/python/ql/test/query-tests/Statements/no_effect/StatementNoEffect.qlref new file mode 100644 index 00000000000..300e28e96c6 --- /dev/null +++ b/python/ql/test/query-tests/Statements/no_effect/StatementNoEffect.qlref @@ -0,0 +1 @@ +Statements/StatementNoEffect.ql diff --git a/python/ql/test/query-tests/Statements/no_effect/UnusedExceptionObject.expected b/python/ql/test/query-tests/Statements/no_effect/UnusedExceptionObject.expected new file mode 100644 index 00000000000..217832385ad --- /dev/null +++ b/python/ql/test/query-tests/Statements/no_effect/UnusedExceptionObject.expected @@ -0,0 +1 @@ +| test.py:127:9:127:26 | ValueError() | Instantiating an exception, but not raising it, has no effect | diff --git a/python/ql/test/query-tests/Statements/no_effect/UnusedExceptionObject.qlref b/python/ql/test/query-tests/Statements/no_effect/UnusedExceptionObject.qlref new file mode 100644 index 00000000000..ae7783be6af --- /dev/null +++ b/python/ql/test/query-tests/Statements/no_effect/UnusedExceptionObject.qlref @@ -0,0 +1 @@ +Statements/UnusedExceptionObject.ql diff --git a/python/ql/test/query-tests/Statements/no_effect/assert_raises.py b/python/ql/test/query-tests/Statements/no_effect/assert_raises.py new file mode 100644 index 00000000000..d9bd6825252 --- /dev/null +++ b/python/ql/test/query-tests/Statements/no_effect/assert_raises.py @@ -0,0 +1,11 @@ +import unittest + +class T(unittest.TestCase): + + def test_thing(self): + l = 10 + s = [0] + with self.assertRaises(TypeError): + l[1000] + with self.assertRaises(IndexError): + s[1] diff --git a/python/ql/test/query-tests/Statements/no_effect/notebook.py b/python/ql/test/query-tests/Statements/no_effect/notebook.py new file mode 100644 index 00000000000..9e31b462e7e --- /dev/null +++ b/python/ql/test/query-tests/Statements/no_effect/notebook.py @@ -0,0 +1,26 @@ + +# This test is for IPython/Jupyter notebooks which can legitimately include bare expressions at the end of each code-cell. + +# 3.0 + +# +y = 1 + 1 +y + +# +z = 2 * 2 +z + +# +y + + + + + + + + + + + diff --git a/python/ql/test/query-tests/Statements/no_effect/options b/python/ql/test/query-tests/Statements/no_effect/options new file mode 100644 index 00000000000..b91afde0767 --- /dev/null +++ b/python/ql/test/query-tests/Statements/no_effect/options @@ -0,0 +1 @@ +semmle-extractor-options: --max-import-depth=2 diff --git a/python/ql/test/query-tests/Statements/no_effect/test.py b/python/ql/test/query-tests/Statements/no_effect/test.py new file mode 100644 index 00000000000..b31650a3b09 --- /dev/null +++ b/python/ql/test/query-tests/Statements/no_effect/test.py @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + +import sys + + +#Statement has no effect (4 statements, 3 of which are violations) +"Not a docstring" # This is acceptable as strings can be used as comments. +len +sys.argv + [] +3 == 4 + +#The 'sys' statements have an effect +try: + sys +except: + do_something() + +def exec_used(val): + exec (val) + +#This has an effect: +def effectful(y): + [x for x in y] + + +#Not a redundant assignment if a property. +class WithProp(object): + + @property + def x(self): + return self._x + + @prop.setter + def set_x(self, x): + side_effect(x) + self._x = x + + def meth(self): + self.x = self.x + +#Accessing a property has an effect: +def prop_acc(): + p = WithProp() + p.x + + +def mydecorator(func): + return property(fget=func) + +class X(object): + + @mydecorator + def deco(self): + pass + + def func(self): + pass + +x = X() +x.deco +x.deco + 2 + +#No effect +x.func + +#Cannot infer what attribute is, so be conservative +x.thing +other_thing.func + +#Name Error + +try: + unicode +except NameError: + #Python 3 + unicode = str + +try: + ascii +except NameError: + #Python 2 + def ascii(obj): + pass + + +#Overridden operator. yuck. +class Horrible(object): + + def __add__(self, other): + fire_missiles_at(other) + + def __lt__(self, other): + fire_guns_at(other) + + +def possible_fps(x): + h = Horrible() + h + "innocent bystander" + h < "upstanding citizen" + x - 3 #True positive + + +# Forgotten raise. + +def do_action_forgotten_raise(action): + if action == "go": + start() + elif action == "stop": + stop() + else: + ValueError(action) + +def do_action(action): + if action == "go": + start() + elif action == "stop": + stop() + else: + raise ValueError(action) diff --git a/python/ql/test/query-tests/Statements/unreachable/UnreachableCode.expected b/python/ql/test/query-tests/Statements/unreachable/UnreachableCode.expected new file mode 100644 index 00000000000..74e56473a61 --- /dev/null +++ b/python/ql/test/query-tests/Statements/unreachable/UnreachableCode.expected @@ -0,0 +1,6 @@ +| test.py:8:9:8:28 | AssignStmt | Unreachable statement. | +| test.py:10:9:10:28 | Return | Unreachable statement. | +| test.py:16:9:16:21 | ExprStmt | Unreachable statement. | +| test.py:21:5:21:38 | For | Unreachable statement. | +| test.py:28:9:28:21 | ExprStmt | Unreachable statement. | +| test.py:84:5:84:21 | ExceptStmt | Unreachable statement. | diff --git a/python/ql/test/query-tests/Statements/unreachable/UnreachableCode.qlref b/python/ql/test/query-tests/Statements/unreachable/UnreachableCode.qlref new file mode 100644 index 00000000000..5b7891f0026 --- /dev/null +++ b/python/ql/test/query-tests/Statements/unreachable/UnreachableCode.qlref @@ -0,0 +1 @@ +Statements/UnreachableCode.ql diff --git a/python/ql/test/query-tests/Statements/unreachable/test.py b/python/ql/test/query-tests/Statements/unreachable/test.py new file mode 100755 index 00000000000..b1b69942de9 --- /dev/null +++ b/python/ql/test/query-tests/Statements/unreachable/test.py @@ -0,0 +1,122 @@ + +#Unreachable code + +def f(x): + while x: + print (x) + while 0: + asgn = unreachable() + while False: + return unreachable() + while 7: + print(x) + +def g(x): + if False: + unreachable() + else: + reachable() + print(x) + return 5 + for x in first_unreachable_stmt(): + raise more_unreachable() + +def h(a,b): + if True: + reachable() + else: + unreachable() + +def intish(n): + """"Regression test - the 'except' statement is reachable""" + test = 0 + try: + test += n + except: + return False + return True + +#ODASA-2033 +def unexpected_return_result(): + try: + assert 0, "async.Return with argument inside async.generator function" + except AssertionError: + return (None, sys.exc_info()) + +#Yield may raise -- E.g. in a context manager +def handle_yield_exception(): + resources = get_resources() + try: + yield resources + except Exception as exc: + log(exc) + +#ODASA-ODASA-3790 +def isnt_iter(seq): + got_exc = False + try: + for x in seq: + pass + except Exception: + got_exc = True + return got_exc + + +class Odasa3686(object): + + def is_iterable(self, obj): + #special case string + if not object: + return False + if isinstance(obj, str): + return False + + #Test for iterability + try: + None in obj + return True + except TypeError: + return False + +def odasa5387(): + try: + str + except NameError: # Unreachable 'str' is always defined + pass + try: + unicode + except NameError: # Reachable as 'unicode' is undefined in Python 3 + pass + +#This is OK as type-hints require it +if False: + from typing import Any + +def foo(): + # type: () -> None + return + +#ODASA-6483 +def deliberate_name_error(cond): + if cond: + x = 0 + try: + x + except NameError: + x = 1 + return x + +#ODASA-6783 +def emtpy_gen(): + if False: + yield None + + +def foo(x): + if True: + if x < 3: + print(x, "< 3") + if x == 0: + print(x, "== 0") + + diff --git a/python/ql/test/query-tests/Testing/ImpreciseAssert.expected b/python/ql/test/query-tests/Testing/ImpreciseAssert.expected new file mode 100644 index 00000000000..e9e34a16769 --- /dev/null +++ b/python/ql/test/query-tests/Testing/ImpreciseAssert.expected @@ -0,0 +1,4 @@ +| test.py:6:9:6:31 | Attribute() | assertTrue(a == b) cannot provide an informative message. Using assertEqual(a, b) instead will give more informative messages. | +| test.py:7:9:7:31 | Attribute() | assertFalse(a > b) cannot provide an informative message. Using assertLessEqual(a, b) instead will give more informative messages. | +| test.py:8:9:8:33 | Attribute() | assertTrue(a in b) cannot provide an informative message. Using assertIn(a, b) instead will give more informative messages. | +| test.py:9:9:9:33 | Attribute() | assertFalse(a is b) cannot provide an informative message. Using assertIsNot(a, b) instead will give more informative messages. | diff --git a/python/ql/test/query-tests/Testing/ImpreciseAssert.qlref b/python/ql/test/query-tests/Testing/ImpreciseAssert.qlref new file mode 100644 index 00000000000..79dc019fe79 --- /dev/null +++ b/python/ql/test/query-tests/Testing/ImpreciseAssert.qlref @@ -0,0 +1 @@ +Testing/ImpreciseAssert.ql diff --git a/python/ql/test/query-tests/Testing/test.py b/python/ql/test/query-tests/Testing/test.py new file mode 100644 index 00000000000..1c79f177ac6 --- /dev/null +++ b/python/ql/test/query-tests/Testing/test.py @@ -0,0 +1,9 @@ +from unittest import TestCase + +class MyTest(TestCase): + + def test1(self): + self.assertTrue(1 == 1) + self.assertFalse(1 > 2) + self.assertTrue(1 in [1]) + self.assertFalse(0 is "") diff --git a/python/ql/test/query-tests/UselessCode/DuplicateCode/DuplicateBlock.expected b/python/ql/test/query-tests/UselessCode/DuplicateCode/DuplicateBlock.expected new file mode 100644 index 00000000000..9234fea78c7 --- /dev/null +++ b/python/ql/test/query-tests/UselessCode/DuplicateCode/DuplicateBlock.expected @@ -0,0 +1,8 @@ +| duplicate_test.py:47:9:60:17 | Duplicate code: 14 duplicated lines. | Duplicate code: 14 lines are duplicated at duplicate_test.py:9 | +| duplicate_test.py:56:18:66:25 | Duplicate code: 11 duplicated lines. | Duplicate code: 11 lines are duplicated at duplicate_test.py:18 | +| duplicate_test.py:61:24:80:32 | Duplicate code: 20 duplicated lines. | Duplicate code: 20 lines are duplicated at duplicate_test.py:23 | +| duplicate_test.py:166:18:245:24 | Duplicate code: 80 duplicated lines. | Duplicate code: 80 lines are duplicated at duplicate_test.py:84 | +| duplicate_test.py:287:9:300:17 | Duplicate code: 14 duplicated lines. | Duplicate code: 14 lines are duplicated at duplicate_test.py:9 | +| duplicate_test.py:287:9:300:17 | Duplicate code: 14 duplicated lines. | Duplicate code: 14 lines are duplicated at duplicate_test.py:47 | +| duplicate_test.py:299:22:318:32 | Duplicate code: 20 duplicated lines. | Duplicate code: 20 lines are duplicated at duplicate_test.py:23 | +| duplicate_test.py:299:22:318:32 | Duplicate code: 20 duplicated lines. | Duplicate code: 20 lines are duplicated at duplicate_test.py:61 | diff --git a/python/ql/test/query-tests/UselessCode/DuplicateCode/DuplicateBlock.qlref b/python/ql/test/query-tests/UselessCode/DuplicateCode/DuplicateBlock.qlref new file mode 100644 index 00000000000..6e6d439a040 --- /dev/null +++ b/python/ql/test/query-tests/UselessCode/DuplicateCode/DuplicateBlock.qlref @@ -0,0 +1 @@ +external/DuplicateBlock.ql diff --git a/python/ql/test/query-tests/UselessCode/DuplicateCode/DuplicateFunction.expected b/python/ql/test/query-tests/UselessCode/DuplicateCode/DuplicateFunction.expected new file mode 100644 index 00000000000..c85079e3811 --- /dev/null +++ b/python/ql/test/query-tests/UselessCode/DuplicateCode/DuplicateFunction.expected @@ -0,0 +1,4 @@ +| duplicate_test.py:9:1:9:16 | Function dis | All 26 statements in dis are identical in $@. | duplicate_test.py:47:1:47:17 | Function dis2 | dis2 | +| duplicate_test.py:47:1:47:17 | Function dis2 | All 26 statements in dis2 are identical in $@. | duplicate_test.py:9:1:9:16 | Function dis | dis | +| duplicate_test.py:287:1:287:17 | Function dis4 | All 24 statements in dis4 are identical in $@. | duplicate_test.py:9:1:9:16 | Function dis | dis | +| duplicate_test.py:287:1:287:17 | Function dis4 | All 24 statements in dis4 are identical in $@. | duplicate_test.py:47:1:47:17 | Function dis2 | dis2 | diff --git a/python/ql/test/query-tests/UselessCode/DuplicateCode/DuplicateFunction.qlref b/python/ql/test/query-tests/UselessCode/DuplicateCode/DuplicateFunction.qlref new file mode 100644 index 00000000000..bb7e3a45417 --- /dev/null +++ b/python/ql/test/query-tests/UselessCode/DuplicateCode/DuplicateFunction.qlref @@ -0,0 +1 @@ +external/DuplicateFunction.ql diff --git a/python/ql/test/query-tests/UselessCode/DuplicateCode/MostlyDuplicateClass.expected b/python/ql/test/query-tests/UselessCode/DuplicateCode/MostlyDuplicateClass.expected new file mode 100644 index 00000000000..e628b371944 --- /dev/null +++ b/python/ql/test/query-tests/UselessCode/DuplicateCode/MostlyDuplicateClass.expected @@ -0,0 +1,2 @@ +| duplicate_test.py:84:1:84:13 | Class Popen3 | All 55 statements in Popen3 are identical in $@. | duplicate_test.py:166:1:166:18 | Class Popen3Again | Popen3Again | +| duplicate_test.py:166:1:166:18 | Class Popen3Again | All 55 statements in Popen3Again are identical in $@. | duplicate_test.py:84:1:84:13 | Class Popen3 | Popen3 | diff --git a/python/ql/test/query-tests/UselessCode/DuplicateCode/MostlyDuplicateClass.qlref b/python/ql/test/query-tests/UselessCode/DuplicateCode/MostlyDuplicateClass.qlref new file mode 100644 index 00000000000..4af1d7b760b --- /dev/null +++ b/python/ql/test/query-tests/UselessCode/DuplicateCode/MostlyDuplicateClass.qlref @@ -0,0 +1 @@ +external/MostlyDuplicateClass.ql diff --git a/python/ql/test/query-tests/UselessCode/DuplicateCode/MostlyDuplicateFile.expected b/python/ql/test/query-tests/UselessCode/DuplicateCode/MostlyDuplicateFile.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/query-tests/UselessCode/DuplicateCode/MostlyDuplicateFile.qlref b/python/ql/test/query-tests/UselessCode/DuplicateCode/MostlyDuplicateFile.qlref new file mode 100644 index 00000000000..ae06f160dec --- /dev/null +++ b/python/ql/test/query-tests/UselessCode/DuplicateCode/MostlyDuplicateFile.qlref @@ -0,0 +1 @@ +external/MostlyDuplicateFile.ql diff --git a/python/ql/test/query-tests/UselessCode/DuplicateCode/MostlySimilarFile.expected b/python/ql/test/query-tests/UselessCode/DuplicateCode/MostlySimilarFile.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/query-tests/UselessCode/DuplicateCode/MostlySimilarFile.qlref b/python/ql/test/query-tests/UselessCode/DuplicateCode/MostlySimilarFile.qlref new file mode 100644 index 00000000000..f8d493b0a55 --- /dev/null +++ b/python/ql/test/query-tests/UselessCode/DuplicateCode/MostlySimilarFile.qlref @@ -0,0 +1 @@ +external/MostlySimilarFile.ql diff --git a/python/ql/test/query-tests/UselessCode/DuplicateCode/SimilarFunction.expected b/python/ql/test/query-tests/UselessCode/DuplicateCode/SimilarFunction.expected new file mode 100644 index 00000000000..55408a91345 --- /dev/null +++ b/python/ql/test/query-tests/UselessCode/DuplicateCode/SimilarFunction.expected @@ -0,0 +1,12 @@ +| duplicate_test.py:9:1:9:16 | Function dis | All statements in dis are similar in $@. | duplicate_test.py:249:1:249:17 | Function dis3 | dis3 | +| duplicate_test.py:9:1:9:16 | Function dis | All statements in dis are similar in $@. | duplicate_test.py:323:1:323:17 | Function dis5 | dis5 | +| duplicate_test.py:47:1:47:17 | Function dis2 | All statements in dis2 are similar in $@. | duplicate_test.py:249:1:249:17 | Function dis3 | dis3 | +| duplicate_test.py:47:1:47:17 | Function dis2 | All statements in dis2 are similar in $@. | duplicate_test.py:323:1:323:17 | Function dis5 | dis5 | +| duplicate_test.py:249:1:249:17 | Function dis3 | All statements in dis3 are similar in $@. | duplicate_test.py:9:1:9:16 | Function dis | dis | +| duplicate_test.py:249:1:249:17 | Function dis3 | All statements in dis3 are similar in $@. | duplicate_test.py:47:1:47:17 | Function dis2 | dis2 | +| duplicate_test.py:249:1:249:17 | Function dis3 | All statements in dis3 are similar in $@. | duplicate_test.py:323:1:323:17 | Function dis5 | dis5 | +| duplicate_test.py:287:1:287:17 | Function dis4 | All statements in dis4 are similar in $@. | duplicate_test.py:249:1:249:17 | Function dis3 | dis3 | +| duplicate_test.py:287:1:287:17 | Function dis4 | All statements in dis4 are similar in $@. | duplicate_test.py:323:1:323:17 | Function dis5 | dis5 | +| duplicate_test.py:323:1:323:17 | Function dis5 | All statements in dis5 are similar in $@. | duplicate_test.py:9:1:9:16 | Function dis | dis | +| duplicate_test.py:323:1:323:17 | Function dis5 | All statements in dis5 are similar in $@. | duplicate_test.py:47:1:47:17 | Function dis2 | dis2 | +| duplicate_test.py:323:1:323:17 | Function dis5 | All statements in dis5 are similar in $@. | duplicate_test.py:249:1:249:17 | Function dis3 | dis3 | diff --git a/python/ql/test/query-tests/UselessCode/DuplicateCode/SimilarFunction.qlref b/python/ql/test/query-tests/UselessCode/DuplicateCode/SimilarFunction.qlref new file mode 100644 index 00000000000..665253817d7 --- /dev/null +++ b/python/ql/test/query-tests/UselessCode/DuplicateCode/SimilarFunction.qlref @@ -0,0 +1 @@ +external/SimilarFunction.ql diff --git a/python/ql/test/query-tests/UselessCode/DuplicateCode/duplicate_test.py b/python/ql/test/query-tests/UselessCode/DuplicateCode/duplicate_test.py new file mode 100644 index 00000000000..cebfd7aca8a --- /dev/null +++ b/python/ql/test/query-tests/UselessCode/DuplicateCode/duplicate_test.py @@ -0,0 +1,358 @@ +#Code Duplication + + +#Exact duplication of function + +#Code copied from stdlib, copyright PSF. +#See http://www.python.org/download/releases/2.7/license/ + +def dis(x=None): + """Disassemble classes, methods, functions, or code. + + With no argument, disassemble the last traceback. + + """ + if x is None: + distb() + return + if isinstance(x, types.InstanceType): + x = x.__class__ + if hasattr(x, 'im_func'): + x = x.im_func + if hasattr(x, 'func_code'): + x = x.func_code + if hasattr(x, '__dict__'): + items = x.__dict__.items() + items.sort() + for name, x1 in items: + if isinstance(x1, _have_code): + print("Disassembly of %s:" % name) + try: + dis(x1) + except TypeError(msg): + print("Sorry:", msg) + print() + elif hasattr(x, 'co_code'): + disassemble(x) + elif isinstance(x, str): + disassemble_string(x) + else: + raise TypeError( + "don't know how to disassemble %s objects" % + type(x).__name__) + + +#And duplicate version + +def dis2(x=None): + """Disassemble classes, methods, functions, or code. + + With no argument, disassemble the last traceback. + + """ + if x is None: + distb() + return + if isinstance(x, types.InstanceType): + x = x.__class__ + if hasattr(x, 'im_func'): + x = x.im_func + if hasattr(x, 'func_code'): + x = x.func_code + if hasattr(x, '__dict__'): + items = x.__dict__.items() + items.sort() + for name, x1 in items: + if isinstance(x1, _have_code): + print("Disassembly of %s:" % name) + try: + dis(x1) + except TypeError(msg): + print("Sorry:", msg) + print() + elif hasattr(x, 'co_code'): + disassemble(x) + elif isinstance(x, str): + disassemble_string(x) + else: + raise TypeError( + "don't know how to disassemble %s objects" % + type(x).__name__) + +#Exactly duplicate class + +class Popen3: + """Class representing a child process. Normally, instances are created + internally by the functions popen2() and popen3().""" + + sts = -1 # Child not completed yet + + def __init__(self, cmd, capturestderr=False, bufsize=-1): + """The parameter 'cmd' is the shell command to execute in a + sub-process. On UNIX, 'cmd' may be a sequence, in which case arguments + will be passed directly to the program without shell intervention (as + with os.spawnv()). If 'cmd' is a string it will be passed to the shell + (as with os.system()). The 'capturestderr' flag, if true, specifies + that the object should capture standard error output of the child + process. The default is false. If the 'bufsize' parameter is + specified, it specifies the size of the I/O buffers to/from the child + process.""" + _cleanup() + self.cmd = cmd + p2cread, p2cwrite = os.pipe() + c2pread, c2pwrite = os.pipe() + if capturestderr: + errout, errin = os.pipe() + self.pid = os.fork() + if self.pid == 0: + # Child + os.dup2(p2cread, 0) + os.dup2(c2pwrite, 1) + if capturestderr: + os.dup2(errin, 2) + self._run_child(cmd) + os.close(p2cread) + self.tochild = os.fdopen(p2cwrite, 'w', bufsize) + os.close(c2pwrite) + self.fromchild = os.fdopen(c2pread, 'r', bufsize) + if capturestderr: + os.close(errin) + self.childerr = os.fdopen(errout, 'r', bufsize) + else: + self.childerr = None + + def __del__(self): + # In case the child hasn't been waited on, check if it's done. + self.poll(_deadstate=sys.maxint) + if self.sts < 0: + if _active is not None: + # Child is still running, keep us alive until we can wait on it. + _active.append(self) + + def _run_child(self, cmd): + if isinstance(cmd, basestring): + cmd = ['/bin/sh', '-c', cmd] + os.closerange(3, MAXFD) + try: + os.execvp(cmd[0], cmd) + finally: + os._exit(1) + + def poll(self, _deadstate=None): + """Return the exit status of the child process if it has finished, + or -1 if it hasn't finished yet.""" + if self.sts < 0: + try: + pid, sts = os.waitpid(self.pid, os.WNOHANG) + # pid will be 0 if self.pid hasn't terminated + if pid == self.pid: + self.sts = sts + except os.error: + if _deadstate is not None: + self.sts = _deadstate + return self.sts + + def wait(self): + """Wait for and return the exit status of the child process.""" + if self.sts < 0: + pid, sts = os.waitpid(self.pid, 0) + # This used to be a test, but it is believed to be + # always true, so I changed it to an assertion - mvl + assert pid == self.pid + self.sts = sts + return self.sts + + +class Popen3Again: + """Class representing a child process. Normally, instances are created + internally by the functions popen2() and popen3().""" + + sts = -1 # Child not completed yet + + def __init__(self, cmd, capturestderr=False, bufsize=-1): + """The parameter 'cmd' is the shell command to execute in a + sub-process. On UNIX, 'cmd' may be a sequence, in which case arguments + will be passed directly to the program without shell intervention (as + with os.spawnv()). If 'cmd' is a string it will be passed to the shell + (as with os.system()). The 'capturestderr' flag, if true, specifies + that the object should capture standard error output of the child + process. The default is false. If the 'bufsize' parameter is + specified, it specifies the size of the I/O buffers to/from the child + process.""" + _cleanup() + self.cmd = cmd + p2cread, p2cwrite = os.pipe() + c2pread, c2pwrite = os.pipe() + if capturestderr: + errout, errin = os.pipe() + self.pid = os.fork() + if self.pid == 0: + # Child + os.dup2(p2cread, 0) + os.dup2(c2pwrite, 1) + if capturestderr: + os.dup2(errin, 2) + self._run_child(cmd) + os.close(p2cread) + self.tochild = os.fdopen(p2cwrite, 'w', bufsize) + os.close(c2pwrite) + self.fromchild = os.fdopen(c2pread, 'r', bufsize) + if capturestderr: + os.close(errin) + self.childerr = os.fdopen(errout, 'r', bufsize) + else: + self.childerr = None + + def __del__(self): + # In case the child hasn't been waited on, check if it's done. + self.poll(_deadstate=sys.maxint) + if self.sts < 0: + if _active is not None: + # Child is still running, keep us alive until we can wait on it. + _active.append(self) + + def _run_child(self, cmd): + if isinstance(cmd, basestring): + cmd = ['/bin/sh', '-c', cmd] + os.closerange(3, MAXFD) + try: + os.execvp(cmd[0], cmd) + finally: + os._exit(1) + + def poll(self, _deadstate=None): + """Return the exit status of the child process if it has finished, + or -1 if it hasn't finished yet.""" + if self.sts < 0: + try: + pid, sts = os.waitpid(self.pid, os.WNOHANG) + # pid will be 0 if self.pid hasn't terminated + if pid == self.pid: + self.sts = sts + except os.error: + if _deadstate is not None: + self.sts = _deadstate + return self.sts + + def wait(self): + """Wait for and return the exit status of the child process.""" + if self.sts < 0: + pid, sts = os.waitpid(self.pid, 0) + # This used to be a test, but it is believed to be + # always true, so I changed it to an assertion - mvl + assert pid == self.pid + self.sts = sts + return self.sts + +#Duplicate function with identifiers changed + +def dis3(y=None): + """frobnicate classes, methods, functions, or code. + + With no argument, frobnicate the last traceback. + + """ + if y is None: + distb() + return + if isinstance(y, types.InstanceType): + y = y.__class__ + if hasattr(y, 'im_func'): + y = y.im_func + if hasattr(y, 'func_code'): + y = y.func_code + if hasattr(y, '__dict__'): + items = y.__dict__.items() + items.sort() + for name, y1 in items: + if isinstance(y1, _have_code): + print("Disassembly of %s:" % name) + try: + dis(y1) + except TypeError(msg): + print("Sorry:", msg) + print() + elif hasattr(y, 'co_code'): + frobnicate(y) + elif isinstance(y, str): + frobnicate_string(y) + else: + raise TypeError( + "don't know how to frobnicate %s objects" % + type(y).__name__) + + +#Mostly similar function + +def dis4(x=None): + """Disassemble classes, methods, functions, or code. + + With no argument, disassemble the last traceback. + + """ + if x is None: + distb() + return + if isinstance(x, types.InstanceType): + x = x.__class__ + if hasattr(x, 'im_func'): + x = x.im_func + if hasattr(x, '__dict__'): + items = x.__dict__.items() + items.sort() + for name, x1 in items: + if isinstance(x1, _have_code): + print("Disassembly of %s:" % name) + try: + dis(x1) + except TypeError(msg): + print("Sorry:", msg) + print() + elif hasattr(x, 'co_code'): + disassemble(x) + elif isinstance(x, str): + disassemble_string(x) + else: + raise TypeError( + "don't know how to disassemble %s objects" % + type(x).__name__) + + +#Similar function with changed identifiers + +def dis5(z=None): + """splat classes, methods, functions, or code. + + With no argument, splat the last traceback. + + """ + if z is None: + distb() + return + if isinstance(z, types.InstanceType): + z = z.__class__ + if hasattr(z, 'im_func'): + z = z.im_func + if hasattr(y, 'func_code'): + y = y.func_code + if hasattr(z, '__dict__'): + items = z.__dict__.items() + items.sort() + for name, z1 in items: + if isinstance(z1, _have_code): + print("Disassembly of %s:" % name) + try: + dis(z1) + except TypeError(msg): + print("Sorry:", msg) + print() + elif hasattr(z, 'co_code'): + splat(z) + elif isinstance(z, str): + splat_string(z) + else: + raise TypeError( + "don't know how to splat %s objects" % + type(z).__name__) + + diff --git a/python/ql/test/query-tests/UselessCode/DuplicateCode/similar.py b/python/ql/test/query-tests/UselessCode/DuplicateCode/similar.py new file mode 100644 index 00000000000..8f36c5e65ed --- /dev/null +++ b/python/ql/test/query-tests/UselessCode/DuplicateCode/similar.py @@ -0,0 +1,63 @@ + + +def original(the_ast): + def walk(node, in_function, in_name_main): + def flags(): + return in_function * 2 + in_name_main + if isinstance(node, ast.Module): + for import_node in walk(node.body, in_function, in_name_main): + yield import_node + elif isinstance(node, ast.ImportFrom): + aliases = [ Alias(a.name, a.asname) for a in node.names] + yield FromImport(node.level, node.module, aliases, flags()) + elif isinstance(node, ast.Import): + aliases = [ Alias(a.name, a.asname) for a in node.names] + yield Import(aliases, flags()) + elif isinstance(node, ast.FunctionDef): + for _, child in ast.iter_fields(node): + for import_node in walk(child, True, in_name_main): + yield import_node + elif isinstance(node, list): + for n in node: + for import_node in walk(n, in_function, in_name_main): + yield import_node + return list(walk(the_ast, False, False)) + +def similar_1(the_ast): + def walk(node, in_function, in_name_main): + def flags(): + return in_function * 2 + in_name_main + if isinstance(node, ast.Module): + for import_node in walk(node.body, in_function, in_name_main): + yield import_node + elif isinstance(node, ast.ImportFrom): + aliases = [ Alias(a.name, a.asname) for a in node.names] + yield FromImport(node.level, node.module, aliases, flags()) + elif isinstance(node, ast.Import): + aliases = [ Alias(a.name, a.asname) for a in node.names] + yield Import(aliases, flags()) + elif isinstance(node, ast.FunctionDef): + for _, child in ast.iter_fields(node): + for import_node in walk(child, True, in_name_main): + yield import_node + return list(walk(the_ast, False, False)) + +def similar_2(the_ast): + def walk(node, in_function, in_name_main): + def flags(): + return in_function * 2 + in_name_main + if isinstance(node, ast.Module): + for import_node in walk(node.body, in_function, in_name_main): + yield import_node + elif isinstance(node, ast.Import): + aliases = [ Alias(a.name, a.asname) for a in node.names] + yield Import(aliases, flags()) + elif isinstance(node, ast.FunctionDef): + for _, child in ast.iter_fields(node): + for import_node in walk(child, True, in_name_main): + yield import_node + elif isinstance(node, list): + for n in node: + for import_node in walk(n, in_function, in_name_main): + yield import_node + return list(walk(the_ast, False, False)) diff --git a/python/ql/test/query-tests/Variables/capture/LoopVariableCapture.expected b/python/ql/test/query-tests/Variables/capture/LoopVariableCapture.expected new file mode 100644 index 00000000000..cc9ae7029d6 --- /dev/null +++ b/python/ql/test/query-tests/Variables/capture/LoopVariableCapture.expected @@ -0,0 +1,8 @@ +| test.py:5:9:5:20 | FunctionExpr | Capture of loop variable '$@' | test.py:4:5:4:23 | For | x | +| test.py:10:6:10:14 | Lambda | Capture of loop variable '$@' | test.py:10:5:10:36 | ListComp | i | +| test.py:42:6:42:14 | Lambda | Capture of loop variable '$@' | test.py:42:5:42:56 | ListComp | i | +| test.py:43:6:43:14 | Lambda | Capture of loop variable '$@' | test.py:43:5:43:56 | ListComp | j | +| test.py:45:6:45:14 | Lambda | Capture of loop variable '$@' | test.py:45:5:45:36 | SetComp | i | +| test.py:49:8:49:16 | Lambda | Capture of loop variable '$@' | test.py:49:5:49:38 | DictComp | i | +| test.py:57:6:57:14 | Lambda | Capture of loop variable '$@' | test.py:57:6:57:35 | GeneratorExp | i | +| test.py:62:10:62:18 | Lambda | Capture of loop variable '$@' | test.py:62:10:62:39 | GeneratorExp | i | diff --git a/python/ql/test/query-tests/Variables/capture/LoopVariableCapture.qlref b/python/ql/test/query-tests/Variables/capture/LoopVariableCapture.qlref new file mode 100644 index 00000000000..1e2a71cd6a7 --- /dev/null +++ b/python/ql/test/query-tests/Variables/capture/LoopVariableCapture.qlref @@ -0,0 +1 @@ +Variables/LoopVariableCapture.ql diff --git a/python/ql/test/query-tests/Variables/capture/test.py b/python/ql/test/query-tests/Variables/capture/test.py new file mode 100644 index 00000000000..480bc58862e --- /dev/null +++ b/python/ql/test/query-tests/Variables/capture/test.py @@ -0,0 +1,67 @@ + +def bad1(): + results = [] + for x in range(10): + def inner(): + return x + results.append(inner) + return results + +a = [lambda: i for i in range(1, 4)] +for f in a: + print(f()) + +#OK: +#Using default argument +def good1(): + results = [] + for y in range(10): + def inner(y=y): + return y + results.append(inner) + return results + +#Factory function +l = [] +for r in range(10): + def make_foo(r): + def foo(): + return r + return foo + l.append(make_foo(r)) + +#The inner function does not escape loop. +def ok1(): + result = 0 + for z in range(10): + def inner(): + return z + result += inner() + return result + +b = [lambda: i for i in range(1, 4) for j in range(1,5)] +c = [lambda: j for i in range(1, 4) for j in range(1,5)] + +s = {lambda: i for i in range(1, 4)} +for f in s: + print(f()) + +d = {i:lambda: i for i in range(1, 4)} +for k, f in d.items(): + print(k, f()) + +#Generator expressions are sometimes OK, if they evaluate the iteration +#When the captured variable is used. +#So technically this is a false positive, but it is extremely fragile +#code, so I (Mark) think it is fine to report it as a violation. +g = (lambda: i for i in range(1, 4)) +for f in g: + print(f()) + +#But not if evaluated eagerly +l = list(lambda: i for i in range(1, 4)) +for f in l: + print(f()) + +def odasa4860(asset_ids): + return dict((asset_id, filter(lambda c : c.asset_id == asset_id, xxx)) for asset_id in asset_ids) diff --git a/python/ql/test/query-tests/Variables/general/Global.expected b/python/ql/test/query-tests/Variables/general/Global.expected new file mode 100644 index 00000000000..073dea682ed --- /dev/null +++ b/python/ql/test/query-tests/Variables/general/Global.expected @@ -0,0 +1 @@ +| variables_test.py:64:5:64:14 | Global | Updating global variables except at module initialization is discouraged | diff --git a/python/ql/test/query-tests/Variables/general/Global.qlref b/python/ql/test/query-tests/Variables/general/Global.qlref new file mode 100644 index 00000000000..c20333a006e --- /dev/null +++ b/python/ql/test/query-tests/Variables/general/Global.qlref @@ -0,0 +1 @@ +Variables/Global.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Variables/general/GlobalAtModuleLevel.expected b/python/ql/test/query-tests/Variables/general/GlobalAtModuleLevel.expected new file mode 100644 index 00000000000..159e6954819 --- /dev/null +++ b/python/ql/test/query-tests/Variables/general/GlobalAtModuleLevel.expected @@ -0,0 +1 @@ +| variables_test.py:57:1:57:10 | Global | Declaring 'g_x' as global at module-level is redundant. | diff --git a/python/ql/test/query-tests/Variables/general/GlobalAtModuleLevel.qlref b/python/ql/test/query-tests/Variables/general/GlobalAtModuleLevel.qlref new file mode 100644 index 00000000000..f12469499b7 --- /dev/null +++ b/python/ql/test/query-tests/Variables/general/GlobalAtModuleLevel.qlref @@ -0,0 +1 @@ +Variables/GlobalAtModuleLevel.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Variables/general/ShadowBuiltin.expected b/python/ql/test/query-tests/Variables/general/ShadowBuiltin.expected new file mode 100644 index 00000000000..0035c96d0d7 --- /dev/null +++ b/python/ql/test/query-tests/Variables/general/ShadowBuiltin.expected @@ -0,0 +1 @@ +| variables_test.py:7:5:7:7 | len | Local variable len shadows a builtin variable. | diff --git a/python/ql/test/query-tests/Variables/general/ShadowBuiltin.qlref b/python/ql/test/query-tests/Variables/general/ShadowBuiltin.qlref new file mode 100644 index 00000000000..d732a539e5f --- /dev/null +++ b/python/ql/test/query-tests/Variables/general/ShadowBuiltin.qlref @@ -0,0 +1 @@ +Variables/ShadowBuiltin.ql diff --git a/python/ql/test/query-tests/Variables/general/ShadowGlobal.expected b/python/ql/test/query-tests/Variables/general/ShadowGlobal.expected new file mode 100644 index 00000000000..ae59529932f --- /dev/null +++ b/python/ql/test/query-tests/Variables/general/ShadowGlobal.expected @@ -0,0 +1 @@ +| variables_test.py:14:5:14:7 | sh1 | Local variable 'sh1' shadows a global variable defined $@. | variables_test.py:6:5:6:7 | sh1 | here | diff --git a/python/ql/test/query-tests/Variables/general/ShadowGlobal.qlref b/python/ql/test/query-tests/Variables/general/ShadowGlobal.qlref new file mode 100644 index 00000000000..d3d632da035 --- /dev/null +++ b/python/ql/test/query-tests/Variables/general/ShadowGlobal.qlref @@ -0,0 +1 @@ +Variables/ShadowGlobal.ql diff --git a/python/ql/test/query-tests/Variables/general/pytest/__init__.py b/python/ql/test/query-tests/Variables/general/pytest/__init__.py new file mode 100644 index 00000000000..8ab6454477d --- /dev/null +++ b/python/ql/test/query-tests/Variables/general/pytest/__init__.py @@ -0,0 +1,4 @@ +#Fake pytest module for testing. + +def fixture(param): + return param diff --git a/python/ql/test/query-tests/Variables/general/random_string.py b/python/ql/test/query-tests/Variables/general/random_string.py new file mode 100644 index 00000000000..287eae49057 --- /dev/null +++ b/python/ql/test/query-tests/Variables/general/random_string.py @@ -0,0 +1,17 @@ + +#ODASA-3688 +def generate_random_string(char_sequences, length): + random_string = "" + + # Two tests of the same variable to force splitting of the flow-graph + if char_sequences: + for char_seq in char_sequences: + pass + + def func_used(): + pass + + #Only use the variable on one of the split arms. + if char_sequences: + while len(random_string) < length: + random_string += func_used() diff --git a/python/ql/test/query-tests/Variables/general/variables_test.py b/python/ql/test/query-tests/Variables/general/variables_test.py new file mode 100644 index 00000000000..e623ee5244d --- /dev/null +++ b/python/ql/test/query-tests/Variables/general/variables_test.py @@ -0,0 +1,100 @@ + +__all__ = [ 'is_used_var1' ] + +#Shadow Builtin + +def sh1(x): + len = x + 2 #Shadows + len = x + 0 # no shadowing warning for 2nd def + return len + +#Shadow Global + +def sh2(x): + sh1 = x + 1 #Shadows + sh1 = x + 0 # no shadowing warning for 2nd def + return sh1 + +#This is OK +import module1 +def ok1(): + import module1 + +#Unused parameter, local and global + +def u1(x): + return 0 + +def u2(): + x = 1 + return 1 + +#These parameters are OK due to (potential overriding) +class C(object): + + @abstractmethod + def ok2(self, p): + pass + + def ok3(self, arg): + pass + +class D(C): + + def ok3(self, arg): + pass + +#Unused module variable +unused_var1 = 17 +unused_var2 = 18 +is_used_var1 = 19 +is_used_var2 = 20 + +def func(): + return is_used_var2 + +#Redundant global declaration +global g_x + +g_x = 0 + +#Use global + +def uses_global(arg): + global g_x + g_x = arg + +use(g_x) + +#Benign case of global shadowing: +if __name__ == "__main__": + #x is used as a local throughout this file + x = 0 + use(x) + +import pytest +#Shadow global in pytest.fixture: +@pytest.fixture +def the_fixture(): + pass + +#Use it +the_fixture(1) + +def test_function(the_fixture): + #Use it + return the_fixture + +#This is OK. ODASA-2908 +def odasa2908_global(g_x=g_x): + #Use arg cached in function object for speed + return g_x + +def odasa2908_builtin(arg, len=len): + #Use arg cached in function object for speed + return len(arg) + +#OK if marked as unused: +def ok_unused(unused_1): + unused_2 = 1 + return 0 diff --git a/python/ql/test/query-tests/Variables/multiple/MultiplyDefined.expected b/python/ql/test/query-tests/Variables/multiple/MultiplyDefined.expected new file mode 100644 index 00000000000..68d01f762f6 --- /dev/null +++ b/python/ql/test/query-tests/Variables/multiple/MultiplyDefined.expected @@ -0,0 +1,7 @@ +| uselesscode_test.py:4:5:4:8 | mult | This assignment to 'mult' is unnecessary as it is redefined $@ before this value is used. | uselesscode_test.py:15:5:15:8 | mult | here | +| uselesscode_test.py:5:5:5:5 | x | This assignment to 'x' is unnecessary as it is redefined $@ before this value is used. | uselesscode_test.py:7:5:7:5 | x | here | +| uselesscode_test.py:28:7:28:10 | Mult | This assignment to 'Mult' is unnecessary as it is redefined $@ before this value is used. | uselesscode_test.py:37:7:37:10 | Mult | here | +| uselesscode_test.py:52:9:52:11 | bad | This assignment to 'bad' is unnecessary as it is redefined $@ before this value is used. | uselesscode_test.py:53:9:53:11 | bad | here | +| uselesscode_test.py:67:9:67:11 | bad | This assignment to 'bad' is unnecessary as it is redefined $@ before this value is used. | uselesscode_test.py:71:9:71:11 | bad | here | +| uselesscode_test.py:117:5:117:5 | x | This assignment to 'x' is unnecessary as it is redefined $@ before this value is used. | uselesscode_test.py:118:5:118:5 | x | here | +| uselesscode_test.py:117:8:117:8 | y | This assignment to 'y' is unnecessary as it is redefined $@ before this value is used. | uselesscode_test.py:118:8:118:8 | y | here | diff --git a/python/ql/test/query-tests/Variables/multiple/MultiplyDefined.qlref b/python/ql/test/query-tests/Variables/multiple/MultiplyDefined.qlref new file mode 100644 index 00000000000..293098be566 --- /dev/null +++ b/python/ql/test/query-tests/Variables/multiple/MultiplyDefined.qlref @@ -0,0 +1 @@ +Variables/MultiplyDefined.ql diff --git a/python/ql/test/query-tests/Variables/multiple/uselesscode_test.py b/python/ql/test/query-tests/Variables/multiple/uselesscode_test.py new file mode 100644 index 00000000000..49f367d6db3 --- /dev/null +++ b/python/ql/test/query-tests/Variables/multiple/uselesscode_test.py @@ -0,0 +1,128 @@ + +#Multiple declarations + +def mult(a): + x = 1 + y = a + x = 2 + #Need to use x, otherwise it is ignored + #(The UnusedLocalVariable query will pick it up) + return x + +def unique(): + pass + +def mult(x,y): + pass + +#OK for multiple definition +import M +M = none + +def _double_loop(seq): + for i in seq: + pass + for i in seq: + pass + +class Mult(object): + + pass + +class C(object): + + def m(self): + pass + +class Mult(object): + pass + +### Tests inspired by real-world false positives +def isStr(s): + ok = '' + try: + ok += s + except TypeError: + return 0 + return 1 + +# 'bad' actually *is* always redefined before being read. +def have_nosmp(): + try: + bad = os.environ['NPY_NOSMP'] + bad = 1 + except KeyError: + bad = 0 + return bad + +def simple_try(foo): + try: + ok = foo.bar + except AttributeError: + ok = 'default' + return ok + +def try_with_else(foo): + try: + bad = foo.bar + except AttributeError: + raise + else: + bad = 'overwrite' + return bad + +# This should be fine +def append_all(xs): + global __doc__ + __doc__ += "all xs:" + for x in xs: + __doc__ += x + +def append_local(xs): + doc = "" + doc += "xs:" + for x in xs: + doc += x + return doc + +#ODASA-4100 +def odasa4100(name, language, options = ''): + distro_files = [] + if language == 'distro-cpp': + distro_files = [ "file" ] + if distro_files: + emit_odasa_deps() + #Flow-graph splitting will make this definition unused on the distro_files is True branch + env = '' + if distro_files: + env = 'env "ODASA_HOME=' + _top + '/' + distro_path + '" ' + emit_cmd(env + "some other stuff") + +#ODASA-4166 + +#This is OK as the first definition is a "declaration" +def odasa4166(cond): + x = None + if cond: + x = some_value() + else: + x = default_value() + return x + + +#ODASA-5315 +def odasa5315(): + x, y = foo() # OK as y is used + use(y) + x, y = bar() # Not OK as neither x nor y are used. + x, y = baz() # OK as both used + return x + y + +@multimethod(int) +def foo(i): + pass + +@multimethod(float) +def foo(f): + pass + diff --git a/python/ql/test/query-tests/Variables/undefined/UndefinedGlobal.expected b/python/ql/test/query-tests/Variables/undefined/UndefinedGlobal.expected new file mode 100644 index 00000000000..ed465bffae1 --- /dev/null +++ b/python/ql/test/query-tests/Variables/undefined/UndefinedGlobal.expected @@ -0,0 +1,6 @@ +| UndefinedGlobal.py:22:5:22:7 | ug2 | This use of global variable 'ug2' may be undefined. | +| UndefinedGlobal.py:23:5:23:5 | e | This use of global variable 'e' may be undefined. | +| UndefinedGlobal.py:27:5:27:12 | __path__ | This use of global variable '__path__' may be undefined. | +| UndefinedGlobal.py:123:5:123:7 | ug3 | This use of global variable 'ug3' may be undefined. | +| UninitializedLocal.py:5:13:5:15 | ug1 | This use of global variable 'ug1' may be undefined. | +| UninitializedLocal.py:22:9:22:11 | ug1 | This use of global variable 'ug1' may be undefined. | diff --git a/python/ql/test/query-tests/Variables/undefined/UndefinedGlobal.py b/python/ql/test/query-tests/Variables/undefined/UndefinedGlobal.py new file mode 100644 index 00000000000..0438d8e84b3 --- /dev/null +++ b/python/ql/test/query-tests/Variables/undefined/UndefinedGlobal.py @@ -0,0 +1,176 @@ +from ud_helper import d +import ud_helper as helper +from ud_helper import * +try: + import __builtin__ as B +except: + import builtins as B +defined = 2 +#Monkey patch some builtins +B.__dict__["monkey1"] = 1 +setattr(B, "monkey2", 2) +B.monkey3 = 3 + +def f(parameter): + parameter + local = 3 + local + d # Explicitly from ud_helper + helper # Explicitly as import + a # Imlicitly from ud_helper + defined + ug2 # ERROR + e # ERROR Defined in ud_helper, but not in __all__ + int + float + __file__ #OK all files have __file__ defined + __path__ #ERROR only modules have __path__ defined + + len #Ok defined in builtins + monkey1 #Ok monkey-patched builtins + monkey2 #Ok monkey-patched builtins + monkey3 #Ok monkey-patched builtins + +import sys +if __name__ == '__main__': + if len(sys.argv) == 1: + print('usage') + sys.exit(0) + elif ('-s' in sys.argv): + server = sys.argv[2] + else: + server = '127.0.0.1' + server + +#Check that builtins are always defined even if conditionally shadowed. +bool + +if d: + bool = int + +bool +def t2(): + return bool + +def f(): + + global local_global + local_global = 1 + + local_global + +#ODASA-2021 +from elsewhere import gflags, a_function + + +def usage_and_quit(): + print("Usage: unusable") + sys.exit(1) + + +def main(): + + global from_hdb + try: + # Because of from_hdb, get_mp_hashes.py has a lot of extra unique flags + gflags.DEFINE_bool("from_hdb", False, "") + + from_hdb = gflags.FLAGS.from_hdb + + except Exception as ex: + usage_and_quit(str(ex)) + + if not from_hdb: + a_function() + +#ODASA-2432 +def globals_guard(): + if 'varname' in globals(): + f(varname) + +#Example taken from logging module +try: + import module1 + import module2 +except ImportError: + module1 = None + + +if module1: + inst = module2.Class() + +#Some possible false positives, observed in ERP5. +if 1: + pfp1 = 1 + +pfp1 + +def outer(): + global pfp2 + pfp2 = 2 + def inner(): + global pfp2 + pfp2 += 1 + +class Cls(object): + global pfp3 + pfp3 = 3 + def inner(): + global pfp3 + pfp3 += 1 + +def only_report_once(): + ug3 + ug3 + ug3 + ug3 + +#ODASA-5381 +from _ast import * + +try: + NameConstant +except NameError: + NameConstant = Name + +#ODASA-5486 +class modinit: + + global _time + import time + _time = time + try: + import datetime + _pydatetime = datetime.datetime + except ImportError: + # Set them to (), so that isinstance() works with them + _pydatetime = () + +del modinit + +# FP occurs in line below +def _isstring(arg, isinstance=isinstance, t=_time): + pass + +#ODASA-4688 +def outer(): + def inner(): + global glob + glob = 'asdf' + print(glob[2]) + + def otherInner(): + print(glob[3]) + + inner() + + +#ODASA-5896 +guesses_made = 0 +while guesses_made < 6: # This loop is guaranteed to execute at least once. + guess = int(input('Take a guess: ')) + guesses_made += 1 + +if guess == 1017: # FP here + pass + diff --git a/python/ql/test/query-tests/Variables/undefined/UndefinedGlobal.qlref b/python/ql/test/query-tests/Variables/undefined/UndefinedGlobal.qlref new file mode 100644 index 00000000000..ea9f5a03842 --- /dev/null +++ b/python/ql/test/query-tests/Variables/undefined/UndefinedGlobal.qlref @@ -0,0 +1 @@ +Variables/UndefinedGlobal.ql diff --git a/python/ql/test/query-tests/Variables/undefined/UninitializedLocal.expected b/python/ql/test/query-tests/Variables/undefined/UninitializedLocal.expected new file mode 100644 index 00000000000..f2782e7e888 --- /dev/null +++ b/python/ql/test/query-tests/Variables/undefined/UninitializedLocal.expected @@ -0,0 +1,14 @@ +| UninitializedLocal.py:13:16:13:17 | u2 | Local variable 'u2' may be used before it is initialized. | +| UninitializedLocal.py:19:16:19:17 | u3 | Local variable 'u3' may be used before it is initialized. | +| UninitializedLocal.py:37:12:37:13 | u4 | Local variable 'u4' may be used before it is initialized. | +| UninitializedLocal.py:46:5:46:6 | u6 | Local variable 'u6' may be used before it is initialized. | +| UninitializedLocal.py:69:5:69:6 | u8 | Local variable 'u8' may be used before it is initialized. | +| UninitializedLocal.py:75:5:75:6 | u9 | Local variable 'u9' may be used before it is initialized. | +| UninitializedLocal.py:85:5:85:7 | u11 | Local variable 'u11' may be used before it is initialized. | +| UninitializedLocal.py:88:9:88:11 | u12 | Local variable 'u12' may be used before it is initialized. | +| UninitializedLocal.py:119:16:119:18 | u14 | Local variable 'u14' may be used before it is initialized. | +| UninitializedLocal.py:151:16:151:18 | u19 | Local variable 'u19' may be used before it is initialized. | +| UninitializedLocal.py:163:7:163:7 | x | Local variable 'x' may be used before it is initialized. | +| UninitializedLocal.py:176:16:176:16 | x | Local variable 'x' may be used before it is initialized. | +| UninitializedLocal.py:178:16:178:16 | y | Local variable 'y' may be used before it is initialized. | +| odasa3987.py:11:8:11:10 | var | Local variable 'var' may be used before it is initialized. | diff --git a/python/ql/test/query-tests/Variables/undefined/UninitializedLocal.py b/python/ql/test/query-tests/Variables/undefined/UninitializedLocal.py new file mode 100644 index 00000000000..f8a8d76ad15 --- /dev/null +++ b/python/ql/test/query-tests/Variables/undefined/UninitializedLocal.py @@ -0,0 +1,290 @@ + +class C: + + def m1(self): + y = ug1 + x = 1 + return y + + def m2(self, p): + return p + + def m3(self, x1): + return u2 + u2 = x1 + + def m4(self, x2): + if x2: + u3 = 1 + return u3 + +def f(): + y = ug1 + x = 1 + return y + +def g(x3): + def h(): + y = x3 + +def q(x4): + def h(): + y = x4 + x = 1 + +def j(u4): + del u4 + return u4 + +def k(x5): + x5 + 1 + del x5 + +def m(x6): + if x6: + u6 = 1 + u6 + #The following are not uninitialized, but unreachable. + u6 + u6 + +#ODASA-1897 +def l(x7): + try: + if f(): + raise Exception + mod_name = x7[:-3] + mod = __import__(mod_name) + except ImportError: + raise ValueError(mod_name) + + + +def check_del(cond): + u8 = 1 + if cond: + del u8 + else: + pass + u8 + if cond: + u9 = 1 + del u9 + else: + u9 = 2 + u9 + if cond: + x10 = 1 + del x10 + x10 = 2 + else: + x10 = 3 + x10 + u11 = 1 + del u11 + u11 + u12 = "hi" + del u12 + del u12 + +#x will always be defined. +def const_range(): + for i in range(4): + x = i + return x + + +def asserts_false(cond1, cond2): + if cond1: + x13 = 1 + elif cond2: + x13 = 2 + else: + assert False, "Can't happen" + return x13 + +#Splitting +def use_def_conditional(cond3): + if cond3: + x14 = 1 + x15 = 2 + if cond3: + return x14 + +def use_def_conditional(cond4, cond5): + if cond4: + u14 = 1 + x16 = 2 + if cond5: + return u14 + + +def init_and_set_flag_in_try(f): + try: + f() + x17 = 1 + success = True + except: + success = False + if success: + return x17 + +#Check that we can rely on splitting +def split_OK(): + try: + f() + x18 = 1 + cond = not True + except: + cond = not False + if not cond: + return x18 + +def split_not_OK(): + try: + f() + u19 = 1 + cond = not True + except: + cond = not False + if not not cond: + return u19 + +def double_is_none(x): + if x is not None: + v = 0 + if x is None: + return 0 + else: + return v + +#ODASA-4241 +def def_in_post_loop(seq): + j(x) + x = [] + for p in seq: + x = p + +#Check that we are consistent with both sides of if statement +#ODASA-4615 +def f(cond1, cond2): + if cond1: + x = 1 + else: + y = 1 + if cond2: + return x + else: + return y + +def needs_splitting(var): + if var: + other = 0 + if not var or other: #other looks like it might be undefined, but it is defined. + pass + +def odasa4867(status): + fail = (status != 200) + if not fail: + 1 + if not fail: + var = 2 + if not fail: + 3 + if not fail and not l(var): # Observed FP - var is defined. + 4 + fail = True # It is possible that this was interfering with splitting. + if not fail: # Not the same SSA variable as earlier + 5 + +def odasa5896(number): + guesses_made = 0 + while guesses_made < 6: # This loop is guaranteed to execute at least once. + guess = int(input('Take a guess: ')) + guesses_made += 1 + + if guess == number: # FP here + pass + +#ODASA 6212 +class C(object): + + def fail(self): + raise Exception() + +def may_fail(cond, c): + if cond: + x = 0 + else: + c.fail() + return x + + +def deliberate_name_error(cond): + if cond: + x = 0 + try: + x # x is uninitialised, but guarded. So don't report it. + except NameError: + x = 1 + return x # x is initialised here, but we would need splitting to know that. + + +from unknown import x +may_fail(x, C()) + + +def with_definition(x): + with open(x) as y: + y + +def multiple_defn_in_try(x): + try: + for p, q in x: + p + except KeyError: + pass + +# ODASA-6742 + +import sys +class X(object): + + def leave(self, code = 1): + sys.exit(code) + +class Y(object): + + def __init__(self, x): + self._x = x + + def leave(self): + self._x.leave() + +def odasa6742(cond, obj): + y = Y(X()) + try: + var = may_fail(cond, obj) + except: + y.leave() + var + + +#ODASA-6904 +def avoid_redundant_split(a): + if a: # Should split here + b = x() + else: + b = None + if b: # but not here, + pass + if b: # or here, because + pass + pass + try: # we want to split here + import foo + var = True + except: + var = False + if var: + foo.bar() #foo is defined here. diff --git a/python/ql/test/query-tests/Variables/undefined/UninitializedLocal.qlref b/python/ql/test/query-tests/Variables/undefined/UninitializedLocal.qlref new file mode 100644 index 00000000000..f2d0e603554 --- /dev/null +++ b/python/ql/test/query-tests/Variables/undefined/UninitializedLocal.qlref @@ -0,0 +1 @@ +Variables/UninitializedLocal.ql diff --git a/python/ql/test/query-tests/Variables/undefined/import_star.py b/python/ql/test/query-tests/Variables/undefined/import_star.py new file mode 100644 index 00000000000..5bbf9171870 --- /dev/null +++ b/python/ql/test/query-tests/Variables/undefined/import_star.py @@ -0,0 +1,7 @@ + +#ODASA-4596 +from tokens import * + +#TOKEN_1 is defined in tokens, but we cannot determine that statically. +TOKEN_1 + diff --git a/python/ql/test/query-tests/Variables/undefined/module1.py b/python/ql/test/query-tests/Variables/undefined/module1.py new file mode 100644 index 00000000000..bf08ecae944 --- /dev/null +++ b/python/ql/test/query-tests/Variables/undefined/module1.py @@ -0,0 +1,2 @@ +#If we use the standard import form the test runner will import quite a lot of the standard library +os = __import__("os") \ No newline at end of file diff --git a/python/ql/test/query-tests/Variables/undefined/odasa3987.py b/python/ql/test/query-tests/Variables/undefined/odasa3987.py new file mode 100644 index 00000000000..9c3a5fa5b2f --- /dev/null +++ b/python/ql/test/query-tests/Variables/undefined/odasa3987.py @@ -0,0 +1,17 @@ + +from somwhere import may_raise, value, SomeException + +def f(cond1, cond2): + try: + may_raise() + var = value() + except Exception: + if cond2: + var = 7 + if var == 1: + var = var + 1 + elif var == 2: + var +- 3 + if cond2: + pass + var = var + 4 # var must be defined to have passed line 11 diff --git a/python/ql/test/query-tests/Variables/undefined/odasa6418.py b/python/ql/test/query-tests/Variables/undefined/odasa6418.py new file mode 100644 index 00000000000..958433c4287 --- /dev/null +++ b/python/ql/test/query-tests/Variables/undefined/odasa6418.py @@ -0,0 +1,19 @@ + +import sys + +def bump_version(version): + try: + parts = map(int, version.split('.')) + except ValueError: + fail('Current version is not numeric') + parts[-1] += 1 + return '.'.join(map(str, parts)) + + +def fail(message): + print(message) + sys.exit(1) + +# To get the FP result reported in ODASA-6418, +#bump_version must be called (directly or transitively) from the module scope +bump_version() diff --git a/python/ql/test/query-tests/Variables/undefined/odasa6800.py b/python/ql/test/query-tests/Variables/undefined/odasa6800.py new file mode 100644 index 00000000000..b69d665c335 --- /dev/null +++ b/python/ql/test/query-tests/Variables/undefined/odasa6800.py @@ -0,0 +1,9 @@ +#We don't (yet) follow this import +fail = __import__("odasa%s" % 6418).fail + +def foo(x): + if x: + var = 0 + else: + fail('Current version is not numeric') + return var diff --git a/python/ql/test/query-tests/Variables/undefined/options b/python/ql/test/query-tests/Variables/undefined/options new file mode 100644 index 00000000000..b91afde0767 --- /dev/null +++ b/python/ql/test/query-tests/Variables/undefined/options @@ -0,0 +1 @@ +semmle-extractor-options: --max-import-depth=2 diff --git a/python/ql/test/query-tests/Variables/undefined/regression.py b/python/ql/test/query-tests/Variables/undefined/regression.py new file mode 100644 index 00000000000..1e2f12f28fd --- /dev/null +++ b/python/ql/test/query-tests/Variables/undefined/regression.py @@ -0,0 +1,18 @@ +# Regression test for a false-positive in 'Uninitialized Local' + +def func(): + safe = 0 + for i in []: + safe = 1 + if True: + pass + print safe # wrongly flagged + +from module1 import * + +def func2(): + os + +def findPluginJars(dir): + return filter(lambda y: y, + (os.path.join(root, f) for root, _, files in os.walk(dir + '/plugins') for f in files)) diff --git a/python/ql/test/query-tests/Variables/undefined/tokens.py b/python/ql/test/query-tests/Variables/undefined/tokens.py new file mode 100644 index 00000000000..e3c7038eca6 --- /dev/null +++ b/python/ql/test/query-tests/Variables/undefined/tokens.py @@ -0,0 +1,11 @@ +TOKEN_0 = 0 +TOKEN_1 = 1 +TOKEN_2 = 2 +TOKEN_3 = 3 +TOKEN_4 = 4 +TOKEN_5 = 5 + +__all__ = [ "TOKEN_0" ] + +for i in range(1,6): + __all__.append("TOKEN_%d" % i) diff --git a/python/ql/test/query-tests/Variables/undefined/ud_helper.py b/python/ql/test/query-tests/Variables/undefined/ud_helper.py new file mode 100644 index 00000000000..d4cab7a6949 --- /dev/null +++ b/python/ql/test/query-tests/Variables/undefined/ud_helper.py @@ -0,0 +1,12 @@ + +def a(): pass + +def b(): pass + +def c(): pass + +def d(): pass + +def e(): pass + +__all__ = [ 'a', 'b', 'c' ] diff --git a/python/ql/test/query-tests/Variables/undefined/unknown_import.py b/python/ql/test/query-tests/Variables/undefined/unknown_import.py new file mode 100644 index 00000000000..217596ebee0 --- /dev/null +++ b/python/ql/test/query-tests/Variables/undefined/unknown_import.py @@ -0,0 +1,8 @@ + +from who_knows_what import * + +#Anything could be imported from who_knows_what +#So we have to assume the following could be defined +a +b +c diff --git a/python/ql/test/query-tests/Variables/undefined/uses_exec.py b/python/ql/test/query-tests/Variables/undefined/uses_exec.py new file mode 100644 index 00000000000..8a78c8e46d1 --- /dev/null +++ b/python/ql/test/query-tests/Variables/undefined/uses_exec.py @@ -0,0 +1,8 @@ +from other import setup + +exec('x/_version.py') + +setup( + name='x', + version=__version__ + ) diff --git a/python/ql/test/query-tests/Variables/unused/SuspiciousUnusedLoopIterationVariable.expected b/python/ql/test/query-tests/Variables/unused/SuspiciousUnusedLoopIterationVariable.expected new file mode 100644 index 00000000000..2b104a610a1 --- /dev/null +++ b/python/ql/test/query-tests/Variables/unused/SuspiciousUnusedLoopIterationVariable.expected @@ -0,0 +1,6 @@ +| test.py:4:5:4:28 | For | For loop variable 't' is not used in the loop body. | +| test.py:66:9:66:26 | For | For loop variable 'y' is not used in the loop body. | +| test.py:72:5:72:22 | For | For loop variable 'y' is not used in the loop body. | +| test.py:78:5:78:22 | For | For loop variable 's' is not used in the loop body. | +| test.py:106:5:106:25 | For | For loop variable 'sess' is deleted, but not used, in the loop body. | +| variables_test.py:133:5:133:32 | For | For loop variable 'tag' is not used in the loop body. | diff --git a/python/ql/test/query-tests/Variables/unused/SuspiciousUnusedLoopIterationVariable.qlref b/python/ql/test/query-tests/Variables/unused/SuspiciousUnusedLoopIterationVariable.qlref new file mode 100644 index 00000000000..4b9f136451e --- /dev/null +++ b/python/ql/test/query-tests/Variables/unused/SuspiciousUnusedLoopIterationVariable.qlref @@ -0,0 +1 @@ +Variables/SuspiciousUnusedLoopIterationVariable.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Variables/unused/UnusedLocalVariable.expected b/python/ql/test/query-tests/Variables/unused/UnusedLocalVariable.expected new file mode 100644 index 00000000000..a902cad04cb --- /dev/null +++ b/python/ql/test/query-tests/Variables/unused/UnusedLocalVariable.expected @@ -0,0 +1,5 @@ +| variables_test.py:29:5:29:5 | x | The value assigned to local variable 'x' is never used. | +| variables_test.py:89:5:89:5 | a | The value assigned to local variable 'a' is never used. | +| variables_test.py:89:7:89:7 | b | The value assigned to local variable 'b' is never used. | +| variables_test.py:89:9:89:9 | c | The value assigned to local variable 'c' is never used. | +| variables_test.py:95:5:95:7 | var | The value assigned to local variable 'var' is never used. | diff --git a/python/ql/test/query-tests/Variables/unused/UnusedLocalVariable.qlref b/python/ql/test/query-tests/Variables/unused/UnusedLocalVariable.qlref new file mode 100644 index 00000000000..bd6e5aaa069 --- /dev/null +++ b/python/ql/test/query-tests/Variables/unused/UnusedLocalVariable.qlref @@ -0,0 +1 @@ +Variables/UnusedLocalVariable.ql diff --git a/python/ql/test/query-tests/Variables/unused/UnusedModuleVariable.expected b/python/ql/test/query-tests/Variables/unused/UnusedModuleVariable.expected new file mode 100644 index 00000000000..248ce2d0637 --- /dev/null +++ b/python/ql/test/query-tests/Variables/unused/UnusedModuleVariable.expected @@ -0,0 +1,6 @@ +| variables_test.py:48:1:48:13 | not_used_var1 | The global variable 'not_used_var1' is not used. | +| variables_test.py:49:1:49:13 | not_used_var2 | The global variable 'not_used_var2' is not used. | +| variables_test.py:86:1:86:1 | a | The global variable 'a' is not used. | +| variables_test.py:86:3:86:3 | b | The global variable 'b' is not used. | +| variables_test.py:86:5:86:5 | c | The global variable 'c' is not used. | +| variables_test.py:100:1:100:8 | glob_var | The global variable 'glob_var' is not used. | diff --git a/python/ql/test/query-tests/Variables/unused/UnusedModuleVariable.qlref b/python/ql/test/query-tests/Variables/unused/UnusedModuleVariable.qlref new file mode 100644 index 00000000000..587ad951076 --- /dev/null +++ b/python/ql/test/query-tests/Variables/unused/UnusedModuleVariable.qlref @@ -0,0 +1 @@ +Variables/UnusedModuleVariable.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Variables/unused/UnusedParameter.expected b/python/ql/test/query-tests/Variables/unused/UnusedParameter.expected new file mode 100644 index 00000000000..a5c9320e33e --- /dev/null +++ b/python/ql/test/query-tests/Variables/unused/UnusedParameter.expected @@ -0,0 +1 @@ +| variables_test.py:25:1:25:10 | Function u1 | The parameter 'x' is never used. | diff --git a/python/ql/test/query-tests/Variables/unused/UnusedParameter.qlref b/python/ql/test/query-tests/Variables/unused/UnusedParameter.qlref new file mode 100644 index 00000000000..b37e4859c1b --- /dev/null +++ b/python/ql/test/query-tests/Variables/unused/UnusedParameter.qlref @@ -0,0 +1 @@ +Variables/UnusedParameter.ql diff --git a/python/ql/test/query-tests/Variables/unused/lazy_import.py b/python/ql/test/query-tests/Variables/unused/lazy_import.py new file mode 100644 index 00000000000..c838c77f06b --- /dev/null +++ b/python/ql/test/query-tests/Variables/unused/lazy_import.py @@ -0,0 +1,7 @@ + +from clever_lazy_module_thing import range + +#OK iteration over range +def OK4(n): + for i in range(n): + print("x") diff --git a/python/ql/test/query-tests/Variables/unused/test.py b/python/ql/test/query-tests/Variables/unused/test.py new file mode 100644 index 00000000000..855e9a5ddfd --- /dev/null +++ b/python/ql/test/query-tests/Variables/unused/test.py @@ -0,0 +1,108 @@ + +#Unused +def fail(): + for t in [TypeA, TypeB]: + x = TypeA() + run_test(x) + +#OK by name +def OK1(seq): + for _ in seq: + do_something() + print("Hi") + +#OK counting +def OK2(seq): + i = 3 + for x in seq: + i += 1 + return i + +#OK check emptiness +def OK3(seq): + for thing in seq: + return "Not empty" + return "empty" + +#OK iteration over range +def OK4(n): + r = range(n) + for i in r: + print("x") + +#OK named as unused +def OK5(seq): + for unused_x in seq: + print("x") + +#ODASA-3794 +def OK6(seq): + for thing in seq: + if sum(1 for s in STATUSES + if thing <= s < thing + 100) >= quorum: + return True + +#OK -- Implicitly using count +def OK7(seq): + for x in seq: + queue.add(None) + +def OK8(seq): + for x in seq: + output.append("") + +#Likewise with parameters +def OK7(seq, queue): + for x in seq: + queue.add(None) + +def OK8(seq, output): + for x in seq: + output.append("") + +#Not OK -- Use a constant, but also a variable +def fail2(sequence): + for x in sequence: + for y in sequence: + do_something(x+1) + +def fail3(sequence): + for x in sequence: + do_something(x+1) + for y in sequence: + do_something(x+1) + +def fail4(coll, sequence): + while coll: + x = coll.pop() + for s in sequence: + do_something(x+1) + +#OK See ODASA-4153 and ODASA-4533 +def fail5(t): + x, y = t + return x + + +class OK9(object): + cls_attr = 0 + def __init__(self): + self.attr = self.cls_attr + +__all__ = [ 'hello' ] +__all__.extend(foo()) +maybe_defined_in_all = 17 + +#ODASA-5895 +def rand_list(): + return [ random.random() for i in range(100) ] + +def kwargs_is_a_use(seq): + for arg in seq: + func(**arg) + +#A deletion is a use, but this is almost certainly an error +def cleanup(sessions): + for sess in sessions: + # Original code had some comment about deleting sessions + del sess diff --git a/python/ql/test/query-tests/Variables/unused/variables_test.py b/python/ql/test/query-tests/Variables/unused/variables_test.py new file mode 100644 index 00000000000..6a30b7945a6 --- /dev/null +++ b/python/ql/test/query-tests/Variables/unused/variables_test.py @@ -0,0 +1,139 @@ + +__all__ = [ 'is_used_var1' ] + +__author__ = "Mark" + +__hidden_marker = False + + + + + + + + + + + + + + + + +#Unused parameter, local and global + +def u1(x): + return 0 + +def u2(): + x = 1 + return 1 + +#These parameters are OK due to (potential overriding) +class C(object): + + @abstractmethod + def ok2(self, p): + pass + + def ok3(self, arg): + pass + +class D(C): + + def ok3(self, arg): + pass + +#Unused module variable +not_used_var1 = 17 +not_used_var2 = 18 +is_used_var1 = 19 +is_used_var2 = 20 + +def func(): + return is_used_var2 + +#Redundant global declaration +global g_x + +g_x = 0 + +#Use global + +def uses_global(arg): + global g_x + g_x = arg + +use(g_x) + + +#Unused but with acceptable names +unused_var3 = g_x + +#Use at least one element of the tuple + +_a, _b, c = t + +use(c) + +def f(t): + _a, _b, c = t + use(c) + + +# Entirely unused tuple + +a,b,c = t + +def f(t): + a,b,c = t + use(t) + +def second_def_undefined(): + var = 0 + use(var) + var = 1 # unused. + +#And gloablly +glob_var = 0 +use(glob_var) +glob_var = 1 # unused + + + + +#OK if marked as unused: +def ok_unused(unused_1): + unused_2 = 1 + return 0 + +#Decorators count as a use: + +@compound.decorator() +def _unused_but_decorated(): + pass + +def decorated_inner_function(): + + @flasklike.routing("/route") + def end_point(): + pass + + @complex.decorator("x") + class C(object): + pass + + return 0 + + + +#FP observed https://lgtm.com/projects/g/torchbox/wagtail/alerts/ +def test_dict_unpacking(queryset, field_name, value): + #True positive + for tag in value.split(','): + queryset = queryset.filter(**{field_name + '__name': tag1}) + return queryset + #False positive + for tag in value.split(','): + queryset = queryset.filter(**{field_name + '__name': tag}) + return queryset diff --git a/python/ql/test/query-tests/analysis/Sanity/Sanity.expected b/python/ql/test/query-tests/analysis/Sanity/Sanity.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/query-tests/analysis/Sanity/Sanity.qlref b/python/ql/test/query-tests/analysis/Sanity/Sanity.qlref new file mode 100644 index 00000000000..692b9cacd4e --- /dev/null +++ b/python/ql/test/query-tests/analysis/Sanity/Sanity.qlref @@ -0,0 +1 @@ +analysis/Sanity.ql diff --git a/python/ql/test/query-tests/analysis/Sanity/test.py b/python/ql/test/query-tests/analysis/Sanity/test.py new file mode 100644 index 00000000000..7877ec789fe --- /dev/null +++ b/python/ql/test/query-tests/analysis/Sanity/test.py @@ -0,0 +1,36 @@ + + +class BaseClass(object): + + cls_attr = 0 + + def __init__(self): + self.shadowing = 2 + +class DerivedClass(BaseClass): + + cls_attr = 3 + shadowing = 5 + + def __init__(self): + BaseClass.__init__(self) + self.inst_attr = 4 + + def method(self): + self.cls_attr + self.inst_attr + self.shadowing + +#ODASA-3836 +def comprehensions_and_generators(seq): + [y*y for y in seq] + (y*y for y in seq) + {y*y for y in seq} + {y:y*y for y in seq} + +#ODASA-5391 +@decorator(x) +class Decorated(object): + pass + +d = Decorated() diff --git a/python/ql/test/query-tests/analysis/jump_to_defn/Definitions.expected b/python/ql/test/query-tests/analysis/jump_to_defn/Definitions.expected new file mode 100644 index 00000000000..1162bce43fa --- /dev/null +++ b/python/ql/test/query-tests/analysis/jump_to_defn/Definitions.expected @@ -0,0 +1,28 @@ +| test.py:8:9:8:12 | self | test.py:7:18:7:21 | Definition test.py:7 | Definition | +| test.py:10:20:10:28 | BaseClass | test.py:3:1:3:24 | Definition test.py:3 | Definition | +| test.py:16:9:16:17 | BaseClass | test.py:3:1:3:24 | Definition test.py:3 | Definition | +| test.py:16:19:16:26 | Attribute | test.py:7:5:7:23 | Definition test.py:7 | Definition | +| test.py:16:28:16:31 | self | test.py:15:18:15:21 | Definition test.py:15 | Definition | +| test.py:17:9:17:12 | self | test.py:15:18:15:21 | Definition test.py:15 | Definition | +| test.py:20:9:20:12 | self | test.py:19:16:19:19 | Definition test.py:19 | Definition | +| test.py:20:14:20:21 | Attribute | test.py:12:16:12:16 | Definition test.py:12 | Definition | +| test.py:21:9:21:12 | self | test.py:19:16:19:19 | Definition test.py:19 | Definition | +| test.py:21:14:21:22 | Attribute | test.py:17:9:17:22 | Definition test.py:17 | Definition | +| test.py:22:9:22:12 | self | test.py:19:16:19:19 | Definition test.py:19 | Definition | +| test.py:22:14:22:22 | Attribute | test.py:13:17:13:17 | Definition test.py:13 | Definition | +| test.py:26:19:26:21 | seq | test.py:25:35:25:37 | Definition test.py:25 | Definition | +| test.py:27:19:27:21 | seq | test.py:25:35:25:37 | Definition test.py:25 | Definition | +| test.py:28:19:28:21 | seq | test.py:25:35:25:37 | Definition test.py:25 | Definition | +| test.py:29:21:29:23 | seq | test.py:25:35:25:37 | Definition test.py:25 | Definition | +| test.py:36:5:36:13 | Decorated | test.py:32:2:32:13 | Definition test.py:32 | Definition | +| test.py:38:8:38:13 | ImportExpr | module.py:0:0:0:0 | Definition module.py:0 | Definition | +| test.py:39:6:39:11 | ImportExpr | module.py:0:0:0:0 | Definition module.py:0 | Definition | +| test.py:39:20:39:22 | ImportMember | module.py:1:7:1:7 | Definition module.py:1 | Definition | +| test.py:40:1:40:3 | foo | test.py:39:20:39:22 | Definition test.py:39 | Definition | +| test.py:41:1:41:5 | thing | test.py:38:8:38:13 | Definition test.py:38 | Definition | +| test.py:41:7:41:9 | Attribute | module.py:2:7:2:7 | Definition module.py:2 | Definition | +| test.py:43:6:43:12 | ImportExpr | package/__init__.py:0:0:0:0 | Definition package/__init__.py:0 | Definition | +| test.py:43:21:43:21 | ImportMember | package/__init__.py:2:18:2:18 | Definition package/__init__.py:2 | Definition | +| test.py:44:8:44:14 | ImportExpr | package/__init__.py:0:0:0:0 | Definition package/__init__.py:0 | Definition | +| test.py:45:1:45:1 | p | test.py:44:8:44:14 | Definition test.py:44 | Definition | +| test.py:45:3:45:3 | Attribute | package/__init__.py:2:18:2:18 | Definition package/__init__.py:2 | Definition | diff --git a/python/ql/test/query-tests/analysis/jump_to_defn/Definitions.qlref b/python/ql/test/query-tests/analysis/jump_to_defn/Definitions.qlref new file mode 100644 index 00000000000..d4e89a35c97 --- /dev/null +++ b/python/ql/test/query-tests/analysis/jump_to_defn/Definitions.qlref @@ -0,0 +1 @@ +analysis/Definitions.ql diff --git a/python/ql/test/query-tests/analysis/jump_to_defn/module.py b/python/ql/test/query-tests/analysis/jump_to_defn/module.py new file mode 100644 index 00000000000..618f37ebbb4 --- /dev/null +++ b/python/ql/test/query-tests/analysis/jump_to_defn/module.py @@ -0,0 +1,2 @@ +foo = 1 +bar = 2 diff --git a/python/ql/test/query-tests/analysis/jump_to_defn/package/__init__.py b/python/ql/test/query-tests/analysis/jump_to_defn/package/__init__.py new file mode 100644 index 00000000000..e91fc44d9ba --- /dev/null +++ b/python/ql/test/query-tests/analysis/jump_to_defn/package/__init__.py @@ -0,0 +1,2 @@ + +from .mod import x diff --git a/python/ql/test/query-tests/analysis/jump_to_defn/package/mod.py b/python/ql/test/query-tests/analysis/jump_to_defn/package/mod.py new file mode 100644 index 00000000000..6e5a9d6cc26 --- /dev/null +++ b/python/ql/test/query-tests/analysis/jump_to_defn/package/mod.py @@ -0,0 +1,2 @@ + +x = 1 diff --git a/python/ql/test/query-tests/analysis/jump_to_defn/test.py b/python/ql/test/query-tests/analysis/jump_to_defn/test.py new file mode 100644 index 00000000000..0abfeb32c40 --- /dev/null +++ b/python/ql/test/query-tests/analysis/jump_to_defn/test.py @@ -0,0 +1,45 @@ + + +class BaseClass(object): + + cls_attr = 0 + + def __init__(self): + self.shadowing = 2 + +class DerivedClass(BaseClass): + + cls_attr = 3 + shadowing = 5 + + def __init__(self): + BaseClass.__init__(self) + self.inst_attr = 4 + + def method(self): + self.cls_attr + self.inst_attr + self.shadowing + +#ODASA-3836 +def comprehensions_and_generators(seq): + [y*y for y in seq] + (y*y for y in seq) + {y*y for y in seq} + {y:y*y for y in seq} + +#ODASA-5391 +@decorator(x) +class Decorated(object): + pass + +d = Decorated() + +import module as thing +from module import foo +foo +thing.bar + +from package import x +import package as p +p.x diff --git a/python/ql/test/query-tests/analysis/pointsto/CallGraphEfficiency.expected b/python/ql/test/query-tests/analysis/pointsto/CallGraphEfficiency.expected new file mode 100644 index 00000000000..a3d7def63d2 --- /dev/null +++ b/python/ql/test/query-tests/analysis/pointsto/CallGraphEfficiency.expected @@ -0,0 +1,2 @@ +| 0 | 29 | 29 | 100.0 | +| 1 | 4 | 40 | 10.0 | diff --git a/python/ql/test/query-tests/analysis/pointsto/CallGraphEfficiency.qlref b/python/ql/test/query-tests/analysis/pointsto/CallGraphEfficiency.qlref new file mode 100644 index 00000000000..6543a375317 --- /dev/null +++ b/python/ql/test/query-tests/analysis/pointsto/CallGraphEfficiency.qlref @@ -0,0 +1 @@ +analysis/CallGraphEfficiency.ql diff --git a/python/ql/test/query-tests/analysis/pointsto/CallGraphMarginalEfficiency.expected b/python/ql/test/query-tests/analysis/pointsto/CallGraphMarginalEfficiency.expected new file mode 100644 index 00000000000..0d3950e7a1e --- /dev/null +++ b/python/ql/test/query-tests/analysis/pointsto/CallGraphMarginalEfficiency.expected @@ -0,0 +1,2 @@ +| 0 | 29 | 29 | 100.0 | +| 1 | 3 | 40 | 7.5 | diff --git a/python/ql/test/query-tests/analysis/pointsto/CallGraphMarginalEfficiency.qlref b/python/ql/test/query-tests/analysis/pointsto/CallGraphMarginalEfficiency.qlref new file mode 100644 index 00000000000..90a59409cd6 --- /dev/null +++ b/python/ql/test/query-tests/analysis/pointsto/CallGraphMarginalEfficiency.qlref @@ -0,0 +1 @@ +analysis/CallGraphMarginalEfficiency.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/analysis/pointsto/FailedInference.expected b/python/ql/test/query-tests/analysis/pointsto/FailedInference.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/query-tests/analysis/pointsto/FailedInference.qlref b/python/ql/test/query-tests/analysis/pointsto/FailedInference.qlref new file mode 100644 index 00000000000..b08adfa00b5 --- /dev/null +++ b/python/ql/test/query-tests/analysis/pointsto/FailedInference.qlref @@ -0,0 +1 @@ +analysis/FailedInference.ql diff --git a/python/ql/test/query-tests/analysis/pointsto/KeyPointsToFailure.expected b/python/ql/test/query-tests/analysis/pointsto/KeyPointsToFailure.expected new file mode 100644 index 00000000000..197ffae7992 --- /dev/null +++ b/python/ql/test/query-tests/analysis/pointsto/KeyPointsToFailure.expected @@ -0,0 +1,33 @@ +| test.py:30:13:30:21 | Attribute | Expression does not 'point-to' any object, but all its sources do. | +| test.py:37:21:37:29 | Attribute | Expression does not 'point-to' any object, but all its sources do. | +| test.py:43:9:43:17 | Attribute | Expression does not 'point-to' any object, but all its sources do. | +| test.py:50:17:50:25 | Attribute | Expression does not 'point-to' any object, but all its sources do. | +| test.py:52:13:52:21 | Attribute | Expression does not 'point-to' any object, but all its sources do. | +| test.py:55:13:55:21 | Attribute | Expression does not 'point-to' any object, but all its sources do. | +| test.py:65:43:65:51 | Attribute | Expression does not 'point-to' any object, but all its sources do. | +| test.py:118:43:118:55 | Attribute | Expression does not 'point-to' any object, but all its sources do. | +| test.py:129:24:129:32 | Attribute | Expression does not 'point-to' any object, but all its sources do. | +| test.py:133:24:133:32 | Attribute | Expression does not 'point-to' any object, but all its sources do. | +| test.py:137:24:137:32 | Attribute | Expression does not 'point-to' any object, but all its sources do. | +| test.py:141:24:141:32 | Attribute | Expression does not 'point-to' any object, but all its sources do. | +| test.py:155:16:155:30 | Attribute | Expression does not 'point-to' any object, but all its sources do. | +| test.py:229:17:229:27 | Attribute | Expression does not 'point-to' any object, but all its sources do. | +| test.py:230:18:230:31 | Attribute | Expression does not 'point-to' any object, but all its sources do. | +| test.py:422:16:422:29 | Attribute | Expression does not 'point-to' any object, but all its sources do. | +| test.py:443:21:443:34 | Attribute | Expression does not 'point-to' any object, but all its sources do. | +| test.py:445:18:445:31 | Attribute | Expression does not 'point-to' any object, but all its sources do. | +| test.py:454:21:454:34 | Attribute | Expression does not 'point-to' any object, but all its sources do. | +| test.py:460:20:460:33 | Attribute | Expression does not 'point-to' any object, but all its sources do. | +| test.py:461:18:461:31 | Attribute | Expression does not 'point-to' any object, but all its sources do. | +| test.py:470:20:470:33 | Attribute | Expression does not 'point-to' any object, but all its sources do. | +| test.py:476:20:476:33 | Attribute | Expression does not 'point-to' any object, but all its sources do. | +| test.py:477:20:477:33 | Attribute | Expression does not 'point-to' any object, but all its sources do. | +| test.py:509:16:509:33 | Attribute | Expression does not 'point-to' any object, but all its sources do. | +| test.py:531:21:531:29 | Attribute | Expression does not 'point-to' any object, but all its sources do. | +| test.py:645:35:645:48 | Attribute | Expression does not 'point-to' any object, but all its sources do. | +| test.py:656:39:656:52 | Attribute | Expression does not 'point-to' any object, but all its sources do. | +| test.py:663:20:663:28 | Attribute | Expression does not 'point-to' any object, but all its sources do. | +| test.py:676:23:676:33 | Attribute | Expression does not 'point-to' any object, but all its sources do. | +| test.py:686:30:686:53 | Attribute | Expression does not 'point-to' any object, but all its sources do. | +| test.py:712:37:712:49 | Attribute | Expression does not 'point-to' any object, but all its sources do. | +| test.py:712:55:712:63 | Attribute | Expression does not 'point-to' any object, but all its sources do. | diff --git a/python/ql/test/query-tests/analysis/pointsto/KeyPointsToFailure.qlref b/python/ql/test/query-tests/analysis/pointsto/KeyPointsToFailure.qlref new file mode 100644 index 00000000000..db945187917 --- /dev/null +++ b/python/ql/test/query-tests/analysis/pointsto/KeyPointsToFailure.qlref @@ -0,0 +1 @@ +analysis/KeyPointsToFailure.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/analysis/pointsto/Pruned.expected b/python/ql/test/query-tests/analysis/pointsto/Pruned.expected new file mode 100644 index 00000000000..53854800e6f --- /dev/null +++ b/python/ql/test/query-tests/analysis/pointsto/Pruned.expected @@ -0,0 +1 @@ +| 1418 | diff --git a/python/ql/test/query-tests/analysis/pointsto/Pruned.qlref b/python/ql/test/query-tests/analysis/pointsto/Pruned.qlref new file mode 100644 index 00000000000..2d2c28dbc26 --- /dev/null +++ b/python/ql/test/query-tests/analysis/pointsto/Pruned.qlref @@ -0,0 +1 @@ +analysis/Pruned.ql diff --git a/python/ql/test/query-tests/analysis/pointsto/test.py b/python/ql/test/query-tests/analysis/pointsto/test.py new file mode 100644 index 00000000000..655af2bd4e0 --- /dev/null +++ b/python/ql/test/query-tests/analysis/pointsto/test.py @@ -0,0 +1,723 @@ + +class SmallSet(list): + + __slots__ = [] + + def update(self, other): + filtered = [x for x in other if x not in self] + self.extend(filtered) + + def add(self, item): + if item not in self: + self.append(item) + +class DiGraph(object): + '''A simple directed graph class (not necessarily a DAG). + Nodes must be hashable''' + + def __init__(self, name = ""): + self.name = name + self.pred = {} + self.succ = {} + self.all_nodes = [] + self.node_annotations = {} + self.edge_annotations = {} + + def add_node(self, n): + 'Add a node to the graph' + if n not in self.succ: + self.pred[n] = SmallSet() + self.succ[n] = SmallSet() + self.all_nodes.append(n) + + def add_edge(self, x, y): + '''Add an edge (x -> y) to the graph. Return true if x, y was + previously in graph''' + if x in self.succ: + if y in self.succ[x]: + return True + else: + self.add_node(x) + self.add_node(y) + self.pred[y].add(x) + self.succ[x].add(y) + return False + + def remove_node(self, x): + if x not in self.succ: + raise ValueError("Node %s does not exist." % x) + preds = self.pred[x] + succs = self.succ[x] + for p in preds: + self.succ[p].remove(x) + for s in succs: + self.pred[s].remove(x) + del self.succ[x] + del self.pred[x] + + def remove_edge(self, x, y): + self.pred[y].remove(x) + self.succ[x].remove(y) + + def annotate_edge(self, x, y, note): + '''Set the annotation on the edge (x -> y) to note. + ''' + if x not in self.succ or y not in self.succ[x]: + raise ValueError("Edge %s -> %s does not exist." % (x, y)) + self.edge_annotations[(x,y)] = note + + def annotate_node(self, x, note): + '''Set the annotation on the node x to note. + ''' + if x not in self.succ: + raise ValueError("Node %s does not exist." % x) + self.node_annotations[x] = note + + def nodes(self): + '''Return an iterator for all nodes, in the form (node, note) pairs. + Do not modify the graph while using this iterator''' + for node in self.all_nodes: + yield node, self.node_annotations.get(node) + + def edges(self): + '''Return an iterator for all edges, in the form of (pred, succ, note) triple. + Do not modify the graph while using this iterator''' + index = dict((n, i) for i, n in enumerate(self.all_nodes)) + for n in self.all_nodes: + n_succs = self.succ[n] + for succ in sorted(n_succs, key = lambda n : index[n]): + yield n, succ, self.edge_annotations.get((n,succ)) + + def sources(self): + '''Return an iterator for all nodes with no predecessors. + Do not modify the graph while using this iterator''' + for n, p in self.pred.items(): + if not p: + yield n + + def __contains__(self, node): + return node in self.succ + + +class FlowGraph(DiGraph): + '''A DiGraph that supports the concept of definitions and variables. + Used to compute dominance and SSA form. + For more explanation of the algorithms used see + 'Modern Compiler Implementation by Andrew W. Appel. + ''' + + def __init__(self, root, name): + DiGraph.__init__(self, name) + self.definitions = {} + self.deletions = {} + self.uses = {} + self.use_all_nodes = set() + self.root = root + + def clear_computed(self): + to_be_deleted = [attr for attr in self.__dict__ if attr[0] == '_'] + for attr in to_be_deleted: + delattr(self, attr) + + def _require(self, what): + '''Ensures that 'what' has been computed (computing if needed).''' + if hasattr(self, "_" + what): + return + setattr(self, "_" + what, getattr(self, "_compute_" + what)()) + + def add_deletion(self, node, var): + assert node in self.succ + self.deletions[node] = var + + def add_definition(self, node, var): + assert node in self.succ + self.definitions[node] = var + + def add_use(self, node, var): + assert node in self.succ, node + self.uses[node] = var + + def use_all_defined_variables(self, node): + assert node in self.succ + self.use_all_nodes.add(node) + + def _compute_depth_first_pre_order(self): + self._require("depth_first_pre_order_labels") + reachable = [ f for f in self.all_nodes if f in self._depth_first_pre_order_labels ] + return sorted(reachable, key = lambda f : -self._depth_first_pre_order_labels[f]) + + def _compute_reachable(self): + self._require("depth_first_pre_order") + return frozenset(self._depth_first_pre_order) + + def reachable_nodes(self): + self._require("reachable") + return self._reachable + + def _compute_reversed_depth_first_pre_order(self): + self._require("depth_first_pre_order") + return reversed(self._depth_first_pre_order) + + def _compute_bb_depth_first_pre_order(self): + self._require('depth_first_pre_order') + self._require('bb_heads') + bbs = [] + for n in self._depth_first_pre_order: + if n in self._bb_heads: + bbs.append(n) + return bbs + + def _compute_bb_reversed_depth_first_pre_order(self): + self._require("bb_depth_first_pre_order") + return reversed(self._bb_depth_first_pre_order) + + def _compute_depth_first_pre_order_labels(self): + 'Compute order with depth first search.' + orders = {} + order = 0 + nodes_to_visit = [ self.root ] + while nodes_to_visit: + node = nodes_to_visit[-1] + orders[node] = 0 + if node in self.succ: + for succ in self.succ[node]: + if succ not in orders: + nodes_to_visit.append(succ) + else: + order += 1 + orders[node] = order + if node is nodes_to_visit[-1]: + nodes_to_visit.pop() + order += 1 + orders[node] = order + return orders + + def _compute_idoms(self): + self._require("depth_first_pre_order") + idoms = {} + + def idom_intersection(n1, n2): + 'Determine the last common idom of n1, n2' + orders = self._depth_first_pre_order_labels + while n1 is not n2: + while orders[n1] < orders[n2]: + n1 = idoms[n1] + while orders[n2] < orders[n1]: + n2 = idoms[n2] + return n1 + + for node in self._depth_first_pre_order: + if len(self.pred[node]) == 1: + idoms[node] = next(iter(self.pred[node])) + else: + idom = None + for p in self.pred[node]: + if p == self.root: + idom = p + elif p in idoms: + if idom is None: + idom = p + else: + idom = idom_intersection(idom, p) + if idom is not None: + idoms[node] = idom + return idoms + + def idoms(self): + '''Returns an iterable of node pairs: node, idom(node)''' + self._require('idoms') + idoms = self._idoms + for n in self.all_nodes: + if n in idoms: + yield n, idoms[n] + + + def _compute_dominance_frontier(self): + '''Compute the dominance frontier: + DF[n] = DF_local[n] Union over C in children DF_up[c]''' + + def dominates(dom, node): + while node in idoms: + next_node = idoms[node] + if dom == next_node: + return True + node = next_node + return False + + self._require('idoms') + idoms = self._idoms + dominance_frontier = {} + df_up = {} + dom_tree = _reverse_map(idoms) + self._require('reversed_depth_first_pre_order') + for node in self._reversed_depth_first_pre_order: + df_local_n = set(n for n in self.succ[node] if node != idoms[n]) + dfn = df_local_n + if node in dom_tree: + for child in dom_tree[node]: + dfn.update(df_up[child]) + dominance_frontier[node] = dfn + if node in idoms: + imm_dom = idoms[node] + df_up[node] = set(n for n in dfn if not dominates(imm_dom, n)) + else: + df_up[node] = dfn + return dominance_frontier + + def _compute_phi_nodes(self): + '''Compute the phi nodes for this graph. + A minimal set of phi-nodes are computed; + No phi-nodes are added unless the variable is live. + ''' + self._require('dominance_frontier') + self._require('liveness') + dominance_frontier = self._dominance_frontier + definitions = dict(self.definitions) + # We must count deletions as definitions here. Otherwise, we can have + # uses of a deleted variable whose SSA definition is an actual definition, + # rather than a deletion. + definitions.update(self.deletions) + phi_nodes = {} + defsites = {} + for a in definitions.values(): + defsites[a] = set() + for n in definitions: + a = definitions[n] + defsites[a].add(n) + for a in defsites: + W = set(defsites[a]) + while W: + n = W.pop() + if n not in dominance_frontier: + continue + for y in dominance_frontier[n]: + if y not in phi_nodes: + phi_nodes[y] = set() + if a not in phi_nodes[y]: + phi_nodes[y].add(a) + if y not in definitions or a != definitions[y]: + W.add(y) + trimmed = {} + for node in phi_nodes: + assert node in self._bb_heads + if node not in self._liveness: + continue + new_phi_vars = set() + phi_vars = phi_nodes[node] + for v in phi_vars: + if v in self._liveness[node]: + new_phi_vars.add(v) + if new_phi_vars: + trimmed[node] = new_phi_vars + return trimmed + + def _compute_ssa_data(self): + ''' Compute the SSA variables, definitions, uses and phi-inputs. + ''' + self._require('basic_blocks') + self._require('phi_nodes') + self._require('bb_depth_first_pre_order') + self._require('use_all') + phi_nodes = self._phi_nodes + reaching_ssa_vars = {} + work_set = set() + work_set.add(self.root) + ssa_defns = {} + ssa_uses = {} + ssa_phis = {} + ssa_vars = set() + ssa_var_cache = {} + + def make_ssa_var(variable, node): + '''Ensure that there is no more than one SSA variable for each (variable, node) pair.''' + uid = (variable, node) + if uid in ssa_var_cache: + return ssa_var_cache[uid] + var = SSA_Var(variable, node) + ssa_var_cache[uid] = var + return var + + for bb in self._bb_depth_first_pre_order: + #Track SSA variables in each BB. + reaching_ssa_vars[bb] = {} + for bb in self._bb_depth_first_pre_order: + live_vars = reaching_ssa_vars[bb].copy() + #Add an SSA definition for each phi-node. + if bb in phi_nodes: + variables = phi_nodes[bb] + for v in variables: + var = make_ssa_var(v, bb) + ssa_defns[var] = bb + live_vars[v] = var + for node in self.nodes_in_bb(bb): + #Add an SSA use for each use. + if node in self.uses: + a = self.uses[node] + if a not in live_vars: + #Treat a use as adding a reaching variable, + #since a second use, if it can be reached, + #will always find the variable defined. + var = make_ssa_var(a, node) + live_vars[a] = var + else: + var = live_vars[a] + ssa_vars.add(var) + ssa_uses[node] = [ var ] + #Add an SSA use for all live SSA variables for + #each use_all (end of module/class scope). + if node in self._use_all: + all_live = [ var for var in live_vars.values() if var.variable in self._use_all[node]] + ssa_uses[node] = all_live + ssa_vars.update(all_live) + #Add an SSA definition for each definition. + if node in self.definitions: + a = self.definitions[node] + var = make_ssa_var(a, node) + ssa_defns[var] = node + live_vars[a] = var + #Although deletions are not definitions, we treat them as such. + #SSA form has no concept of deletion, so we have to treat `del x` + #as `x = Undefined`. + if node in self.deletions: + a = self.deletions[node] + if a in live_vars: + var = live_vars[a] + ssa_vars.add(var) + ssa_uses[node] = [ var ] + else: + #If no var is defined here we don't need to create one + #as a new one will be immediately be defined by the deletion. + pass + var = make_ssa_var(a, node) + ssa_defns[var] = node + live_vars[a] = var + #Propagate set of reaching variables to + #successor blocks. + for n in self.succ[node]: + reaching_ssa_vars[n].update(live_vars) + if n in phi_nodes: + for v in phi_nodes[n]: + if v in live_vars: + var = make_ssa_var(v, n) + if var not in ssa_phis: + ssa_phis[var] = set() + ssa_vars.add(live_vars[v]) + ssa_phis[var].add(live_vars[v]) + #Prune unused definitions. + used_ssa_defns = {} + for var in ssa_defns: + if var in ssa_vars: + used_ssa_defns[var] = ssa_defns[var] + ssa_defns = used_ssa_defns + sorted_vars = list(self._sort_ssa_variables(ssa_vars)) + assert set(sorted_vars) == ssa_vars + assert len(sorted_vars) == len(ssa_vars) + ssa_vars = sorted_vars + return ssa_vars, ssa_defns, ssa_uses, ssa_phis + + + def ssa_variables(self): + '''Returns all the SSA variables for this graph''' + self._require('ssa_data') + return self._ssa_data[0] + + def _sort_ssa_variables(self, ssa_vars): + node_to_var = {} + for v in ssa_vars: + node = v.node + if node in node_to_var: + vset = node_to_var[node] + else: + vset = set() + node_to_var[node] = vset + vset.add(v) + for n in self.all_nodes: + if n in node_to_var: + variables = node_to_var[n] + for v in sorted(variables, key=lambda v:v.variable.id): + yield v + + def ssa_definitions(self): + '''Returns all the SSA definition as an iterator of (node, variable) pairs.''' + self._require('ssa_data') + ssa_defns = self._ssa_data[1] + reversed_defns = _reverse_map(ssa_defns) + for n in self.all_nodes: + if n in reversed_defns: + variables = reversed_defns[n] + for v in sorted(variables, key=lambda v:v.variable.id): + yield n, v + + def get_ssa_definition(self, var): + '''Returns the definition node of var. Returns None if there is no definition.''' + self._require('ssa_data') + ssa_defns = self._ssa_data[1] + return ssa_defns.get(var) + + def ssa_uses(self): + '''Returns all the SSA uses as an iterator of (node, variable) pairs.''' + self._require('ssa_data') + ssa_uses = self._ssa_data[2] + for n in self.all_nodes: + if n in ssa_uses: + variables = ssa_uses[n] + for v in sorted(variables, key=lambda v:v.variable.id): + yield n, v + + def get_ssa_variables_used(self, node): + '''Returns all the SSA variables used at this node''' + self._require('ssa_data') + ssa_uses = self._ssa_data[2] + return ssa_uses.get(node, ()) + + def ssa_phis(self): + '''Return all SSA phi inputs as an iterator of (variable, input-variable) pairs.''' + self._require('ssa_data') + ssa_phis = self._ssa_data[3] + ssa_vars = self._ssa_data[0] + indexed = dict((v, index) for index, v in enumerate(ssa_vars)) + for v in ssa_vars: + if v not in ssa_phis: + continue + phis = ssa_phis[v] + for phi in sorted(phis, key=lambda v:indexed[v]): + yield v, phi + + def _compute_bb_heads(self): + '''Compute all flow nodes that are the first node in a basic block.''' + bb_heads = set() + for node in self.all_nodes: + preds = self.pred[node] + if len(preds) != 1 or len(self.succ[preds[0]]) != 1: + bb_heads.add(node) + return bb_heads + + def _compute_basic_blocks(self): + '''Compute Basic blocks membership''' + self._require('bb_heads') + basic_blocks = {} + bb_tails = {} + for bb in self._bb_heads: + for index, node in enumerate(self.nodes_in_bb(bb)): + basic_blocks[node] = bb, index + bb_tails[bb] = node + self._bb_tails = bb_tails + return basic_blocks + + def get_basic_blocks(self): + self._require('basic_blocks') + return self._basic_blocks + + def _compute_bb_succ(self): + self._require('basic_blocks') + bb_succs = {} + for bb in self._bb_heads: + bb_succs[bb] = self.succ[self._bb_tails[bb]] + return bb_succs + + def _compute_bb_pred(self): + self._require('basic_blocks') + bb_preds = {} + for bb in self._bb_heads: + preds_of_bb = self.pred[bb] + bb_preds[bb] = SmallSet(self._basic_blocks[p][0] for p in preds_of_bb) + return bb_preds + + def nodes_in_bb(self, bb): + '''Return an iterator over all node in basic block 'bb.''' + node = bb + while True: + yield node + succs = self.succ[node] + if not succs: + return + node = succs[0] + if node in self._bb_heads: + return + + + def _compute_use_all(self): + '''Compute which variables have been defined. + A variable is defined at node n, if there is a path to n which + passes through a definition, but not through a subsequent deletion. + ''' + + self._require('bb_heads') + self._require('bb_succ') + self._require('bb_pred') + use_all = {} + + def defined_in_block(bb): + defined = defined_at_start[bb].copy() + for node in self.nodes_in_bb(bb): + if node in self.definitions: + var = self.definitions[node] + defined.add(var) + if node in self.deletions: + var = self.deletions[node] + defined.discard(var) + if node in self.use_all_nodes: + use_all[node] = frozenset(defined) + return defined + + defined_at_start = {} + work_set = set() + for bb in self._bb_heads: + if not self._bb_pred[bb]: + work_set.add(bb) + defined_at_start[bb] = set() + work_list = list(work_set) + while work_list: + bb = work_list.pop() + work_set.remove(bb) + defined_at_bb_end = defined_in_block(bb) + for succ in self._bb_succ[bb]: + if succ not in defined_at_start: + defined_at_start[succ] = set() + elif defined_at_start[succ] >= defined_at_bb_end: + continue + defined_at_start[succ].update(defined_at_bb_end) + if succ not in work_set: + work_list.append(succ) + work_set.add(succ) + return use_all + + def _compute_liveness(self): + '''Compute liveness of all variables in this flow-graph. + Return a mapping of basic blocks to the set of variables + that are live at the start of that basic block. + See http://en.wikipedia.org/wiki/Live_variable_analysis.''' + + self._require('bb_pred') + self._require('use_all') + + def gen_and_kill_for_block(bb): + gen = set() + kill = set() + for node in reversed(list(self.nodes_in_bb(bb))): + if node in self.uses: + var = self.uses[node] + gen.add(var) + kill.discard(var) + if node in self.deletions: + var = self.deletions[node] + gen.add(var) + kill.discard(var) + if node in self.definitions: + var = self.definitions[node] + gen.discard(var) + kill.add(var) + if node in self._use_all: + for var in self._use_all[node]: + gen.add(var) + kill.discard(var) + return gen, kill + + def liveness_for_block(bb, live_out): + return gens[bb].union(live_out.difference(kills[bb])) + + live_at_end = {} + live_at_start = {} + gens = {} + kills = {} + work_set = set() + #Initialise + for bb in self._bb_heads: + gens[bb], kills[bb] = gen_and_kill_for_block(bb) + live_at_end[bb] = set() + live_at_start[bb] = set() + work_set.add(bb) + #Find fixed point + while work_set: + bb = work_set.pop() + live_in = liveness_for_block(bb, live_at_end[bb]) + if live_in != live_at_start[bb]: + assert len(live_in) > len(live_at_start[bb]) + live_at_start[bb] = live_in + for pred in self._bb_pred[bb]: + work_set.add(pred) + live_at_end[pred] = live_at_end[pred].union(live_in) + return live_at_start + + + def delete_unreachable_nodes(self): + self._require("reachable") + unreachable = [u for u in self.all_nodes if u not in self._reachable] + if not unreachable: + return + for mapping in (self.definitions, self.deletions, self.uses): + for u in unreachable: + if u in mapping: + del mapping[u] + for u in unreachable: + self.use_all_nodes.discard(u) + self.remove_node(u) + #Make sure we retain the order of all_nodes. + self.all_nodes = [r for r in self.all_nodes if r in self._reachable] + self.clear_computed() + + def dominated_by(self, node): + self._require('idoms') + assert node in self, str(node) + " is not in graph" + dominated = set([node]) + todo = set(self.succ[node]) + while todo: + n = todo.pop() + if n in dominated: + continue + #Unreachable nodes will not be in self._idoms + if n in self._idoms and self._idoms[n] in dominated: + dominated.add(n) + todo.update(self.succ[n]) + return dominated + + def strictly_dominates(self, pre, post): + self._require('idoms') + while post in self._idoms: + post = self._idoms[post] + if pre == post: + return True + return False + + def reaches_while_dominated(self, pre, post, control): + ''' Holds if `pre` reaches `post` while remaining in the + region dominated by `control`.''' + self._require('dominance_frontier') + dominance_frontier = self._dominance_frontier[control] + todo = { pre } + reached = set() + while todo: + node = todo.pop() + if node in dominance_frontier: + continue + if node == post: + return True + if node in reached: + continue + reached.add(node) + todo.update(self.succ[node]) + return False + + +class SSA_Var(object): + 'A single static assignment variable' + + __slots__ = [ 'variable', 'node' ] + + def __init__(self, variable, node): + self.variable = variable + self.node = node + + def __repr__(self): + return 'SSA_Var(%r, %r)' % (self.variable.id, self.node) + + +def _reverse_map(mapping): + 'Reverse a mapping of keys -> values to value->set(keys)' + inv_map = {} + for k, v in mapping.items(): + if v not in inv_map: + inv_map[v] = SmallSet() + inv_map[v].add(k) + return inv_map + diff --git a/python/ql/test/query-tests/analysis/suppression/AlertSuppression.expected b/python/ql/test/query-tests/analysis/suppression/AlertSuppression.expected new file mode 100644 index 00000000000..d74b3843872 --- /dev/null +++ b/python/ql/test/query-tests/analysis/suppression/AlertSuppression.expected @@ -0,0 +1,59 @@ +| test.py:4:4:4:9 | Comment # lgtm | lgtm | lgtm | test.py:4:1:4:9 | suppression range | +| test.py:5:4:5:27 | Comment # lgtm[py/line-too-long] | lgtm[py/line-too-long] | lgtm[py/line-too-long] | test.py:5:1:5:27 | suppression range | +| test.py:6:4:6:51 | Comment # lgtm[py/line-too-long, py/non-callable-called] | lgtm[py/line-too-long, py/non-callable-called] | lgtm[py/line-too-long, py/non-callable-called] | test.py:6:1:6:51 | suppression range | +| test.py:7:4:7:24 | Comment # lgtm[@tag:security] | lgtm[@tag:security] | lgtm[@tag:security] | test.py:7:1:7:24 | suppression range | +| test.py:8:4:8:41 | Comment # lgtm[@tag:security,py/line-too-long] | lgtm[@tag:security,py/line-too-long] | lgtm[@tag:security,py/line-too-long] | test.py:8:1:8:41 | suppression range | +| test.py:9:4:9:30 | Comment # lgtm[@expires:2017-06-11] | lgtm[@expires:2017-06-11] | lgtm[@expires:2017-06-11] | test.py:9:1:9:30 | suppression range | +| test.py:10:4:10:65 | Comment # lgtm[py/non-callable-called] because I know better than lgtm | lgtm[py/non-callable-called] because I know better than lgtm | lgtm[py/non-callable-called] | test.py:10:1:10:65 | suppression range | +| test.py:11:4:11:20 | Comment # lgtm: blah blah | lgtm: blah blah | lgtm | test.py:11:1:11:20 | suppression range | +| test.py:12:4:12:34 | Comment # lgtm blah blah #falsepositive | lgtm blah blah #falsepositive | lgtm | test.py:12:1:12:34 | suppression range | +| test.py:13:4:13:36 | Comment # lgtm blah blah -- falsepositive | lgtm blah blah -- falsepositive | lgtm | test.py:13:1:13:36 | suppression range | +| test.py:14:4:14:34 | Comment #lgtm [py/non-callable-called] | lgtm [py/non-callable-called] | lgtm [py/non-callable-called] | test.py:14:1:14:34 | suppression range | +| test.py:15:4:15:11 | Comment # lgtm[] | lgtm[] | lgtm[] | test.py:15:1:15:11 | suppression range | +| test.py:17:4:17:8 | Comment #lgtm | lgtm | lgtm | test.py:17:1:17:8 | suppression range | +| test.py:18:4:18:12 | Comment # lgtm | lgtm | lgtm | test.py:18:1:18:12 | suppression range | +| test.py:19:4:19:31 | Comment # lgtm [py/line-too-long] | lgtm [py/line-too-long] | lgtm [py/line-too-long] | test.py:19:1:19:31 | suppression range | +| test.py:20:4:20:14 | Comment # lgtm lgtm | lgtm lgtm | lgtm | test.py:20:1:20:14 | suppression range | +| test.py:27:12:27:23 | Comment #lgtm [func] | lgtm [func] | lgtm [func] | test.py:27:1:27:23 | suppression range | +| test.py:29:17:29:35 | Comment # lgtm on docstring | lgtm on docstring | lgtm | test.py:29:1:29:35 | suppression range | +| test.py:30:16:30:47 | Comment #lgtm [py/duplicate-key-in-dict] | lgtm [py/duplicate-key-in-dict] | lgtm [py/duplicate-key-in-dict] | test.py:30:1:30:47 | suppression range | +| test.py:35:10:35:21 | Comment # lgtm class | lgtm class | lgtm | test.py:35:1:35:21 | suppression range | +| test.py:36:21:36:33 | Comment # lgtm method | lgtm method | lgtm | test.py:36:1:36:33 | suppression range | +| test.py:39:4:39:8 | Comment #noqa | noqa | lgtm | test.py:39:1:39:8 | suppression range | +| test.py:40:4:40:9 | Comment # noqa | noqa | lgtm | test.py:40:1:40:9 | suppression range | +| test.py:50:34:50:117 | Comment # noqa: E501; (line too long) pylint: disable=invalid-name; lgtm [py/missing-equals] | noqa: E501; (line too long) pylint: disable=invalid-name; lgtm [py/missing-equals] | lgtm [py/missing-equals] | test.py:50:1:50:117 | suppression range | +| test.py:52:4:52:67 | Comment # noqa: E501; (line too long) pylint: disable=invalid-name; lgtm | noqa: E501; (line too long) pylint: disable=invalid-name; lgtm | lgtm | test.py:52:1:52:67 | suppression range | +| test.py:53:4:53:78 | Comment # random nonsense lgtm [py/missing-equals] and then some more commentary... | random nonsense lgtm [py/missing-equals] and then some more commentary... | lgtm [py/missing-equals] | test.py:53:1:53:78 | suppression range | +| test.py:58:4:58:9 | Comment # LGTM | LGTM | LGTM | test.py:58:1:58:9 | suppression range | +| test.py:59:4:59:27 | Comment # LGTM[py/line-too-long] | LGTM[py/line-too-long] | LGTM[py/line-too-long] | test.py:59:1:59:27 | suppression range | +| test.py:65:4:65:60 | Comment # lgtm[py/line-too-long] and lgtm[py/non-callable-called] | lgtm[py/line-too-long] and lgtm[py/non-callable-called] | lgtm[py/line-too-long] | test.py:65:1:65:60 | suppression range | +| test.py:65:4:65:60 | Comment # lgtm[py/line-too-long] and lgtm[py/non-callable-called] | lgtm[py/line-too-long] and lgtm[py/non-callable-called] | lgtm[py/non-callable-called] | test.py:65:1:65:60 | suppression range | +| test.py:66:4:66:33 | Comment # lgtm[py/line-too-long]; lgtm | lgtm[py/line-too-long]; lgtm | lgtm | test.py:66:1:66:33 | suppression range | +| test.py:66:4:66:33 | Comment # lgtm[py/line-too-long]; lgtm | lgtm[py/line-too-long]; lgtm | lgtm[py/line-too-long] | test.py:66:1:66:33 | suppression range | +| testWindows.py:4:4:4:9 | Comment # lgtm | lgtm | lgtm | testWindows.py:4:1:4:9 | suppression range | +| testWindows.py:5:4:5:27 | Comment # lgtm[py/line-too-long] | lgtm[py/line-too-long] | lgtm[py/line-too-long] | testWindows.py:5:1:5:27 | suppression range | +| testWindows.py:6:4:6:51 | Comment # lgtm[py/line-too-long, py/non-callable-called] | lgtm[py/line-too-long, py/non-callable-called] | lgtm[py/line-too-long, py/non-callable-called] | testWindows.py:6:1:6:51 | suppression range | +| testWindows.py:7:4:7:24 | Comment # lgtm[@tag:security] | lgtm[@tag:security] | lgtm[@tag:security] | testWindows.py:7:1:7:24 | suppression range | +| testWindows.py:8:4:8:41 | Comment # lgtm[@tag:security,py/line-too-long] | lgtm[@tag:security,py/line-too-long] | lgtm[@tag:security,py/line-too-long] | testWindows.py:8:1:8:41 | suppression range | +| testWindows.py:9:4:9:30 | Comment # lgtm[@expires:2017-06-11] | lgtm[@expires:2017-06-11] | lgtm[@expires:2017-06-11] | testWindows.py:9:1:9:30 | suppression range | +| testWindows.py:10:4:10:65 | Comment # lgtm[py/non-callable-called] because I know better than lgtm | lgtm[py/non-callable-called] because I know better than lgtm | lgtm[py/non-callable-called] | testWindows.py:10:1:10:65 | suppression range | +| testWindows.py:11:4:11:20 | Comment # lgtm: blah blah | lgtm: blah blah | lgtm | testWindows.py:11:1:11:20 | suppression range | +| testWindows.py:12:4:12:34 | Comment # lgtm blah blah #falsepositive | lgtm blah blah #falsepositive | lgtm | testWindows.py:12:1:12:34 | suppression range | +| testWindows.py:13:4:13:36 | Comment # lgtm blah blah -- falsepositive | lgtm blah blah -- falsepositive | lgtm | testWindows.py:13:1:13:36 | suppression range | +| testWindows.py:14:4:14:34 | Comment #lgtm [py/non-callable-called] | lgtm [py/non-callable-called] | lgtm [py/non-callable-called] | testWindows.py:14:1:14:34 | suppression range | +| testWindows.py:15:4:15:11 | Comment # lgtm[] | lgtm[] | lgtm[] | testWindows.py:15:1:15:11 | suppression range | +| testWindows.py:17:4:17:8 | Comment #lgtm | lgtm | lgtm | testWindows.py:17:1:17:8 | suppression range | +| testWindows.py:18:4:18:12 | Comment # lgtm | lgtm | lgtm | testWindows.py:18:1:18:12 | suppression range | +| testWindows.py:19:4:19:31 | Comment # lgtm [py/line-too-long] | lgtm [py/line-too-long] | lgtm [py/line-too-long] | testWindows.py:19:1:19:31 | suppression range | +| testWindows.py:20:4:20:14 | Comment # lgtm lgtm | lgtm lgtm | lgtm | testWindows.py:20:1:20:14 | suppression range | +| testWindows.py:27:12:27:23 | Comment #lgtm [func] | lgtm [func] | lgtm [func] | testWindows.py:27:1:27:23 | suppression range | +| testWindows.py:29:17:29:35 | Comment # lgtm on docstring | lgtm on docstring | lgtm | testWindows.py:29:1:29:35 | suppression range | +| testWindows.py:30:16:30:47 | Comment #lgtm [py/duplicate-key-in-dict] | lgtm [py/duplicate-key-in-dict] | lgtm [py/duplicate-key-in-dict] | testWindows.py:30:1:30:47 | suppression range | +| testWindows.py:35:10:35:21 | Comment # lgtm class | lgtm class | lgtm | testWindows.py:35:1:35:21 | suppression range | +| testWindows.py:36:21:36:33 | Comment # lgtm method | lgtm method | lgtm | testWindows.py:36:1:36:33 | suppression range | +| testWindows.py:39:3:39:7 | Comment #noqa | noqa | lgtm | testWindows.py:39:1:39:7 | suppression range | +| testWindows.py:40:4:40:9 | Comment # noqa | noqa | lgtm | testWindows.py:40:1:40:9 | suppression range | +| testWindows.py:48:4:48:60 | Comment # lgtm[py/line-too-long] and lgtm[py/non-callable-called] | lgtm[py/line-too-long] and lgtm[py/non-callable-called] | lgtm[py/line-too-long] | testWindows.py:48:1:48:60 | suppression range | +| testWindows.py:48:4:48:60 | Comment # lgtm[py/line-too-long] and lgtm[py/non-callable-called] | lgtm[py/line-too-long] and lgtm[py/non-callable-called] | lgtm[py/non-callable-called] | testWindows.py:48:1:48:60 | suppression range | +| testWindows.py:49:4:49:33 | Comment # lgtm[py/line-too-long]; lgtm | lgtm[py/line-too-long]; lgtm | lgtm | testWindows.py:49:1:49:33 | suppression range | +| testWindows.py:49:4:49:33 | Comment # lgtm[py/line-too-long]; lgtm | lgtm[py/line-too-long]; lgtm | lgtm[py/line-too-long] | testWindows.py:49:1:49:33 | suppression range | diff --git a/python/ql/test/query-tests/analysis/suppression/AlertSuppression.qlref b/python/ql/test/query-tests/analysis/suppression/AlertSuppression.qlref new file mode 100644 index 00000000000..7837430fbf9 --- /dev/null +++ b/python/ql/test/query-tests/analysis/suppression/AlertSuppression.qlref @@ -0,0 +1 @@ +analysis/AlertSuppression.ql diff --git a/python/ql/test/query-tests/analysis/suppression/test.py b/python/ql/test/query-tests/analysis/suppression/test.py new file mode 100644 index 00000000000..17c495ff1a4 --- /dev/null +++ b/python/ql/test/query-tests/analysis/suppression/test.py @@ -0,0 +1,66 @@ + +# Formatting tests: + +"" # lgtm +"" # lgtm[py/line-too-long] +"" # lgtm[py/line-too-long, py/non-callable-called] +"" # lgtm[@tag:security] +"" # lgtm[@tag:security,py/line-too-long] +"" # lgtm[@expires:2017-06-11] +"" # lgtm[py/non-callable-called] because I know better than lgtm +"" # lgtm: blah blah +"" # lgtm blah blah #falsepositive +"" # lgtm blah blah -- falsepositive +"" #lgtm [py/non-callable-called] +"" # lgtm[] +"" # lgtmfoo +"" #lgtm +"" # lgtm +"" # lgtm [py/line-too-long] +"" # lgtm lgtm + + +#lgtm -- Ignore this -- No line or scope. + +#On real code: + +def foo(): #lgtm [func] + # lgtm -- Blank line (ignore for now, maybe scope wide in future). + "docstring" # lgtm on docstring + return { #lgtm [py/duplicate-key-in-dict] + "a": 1, + "a": 2 + } + +class C: # lgtm class + def meth(self): # lgtm method + pass + +"" #noqa +"" # noqa + +"The following should be ignored" +"" # flake8: noqa +"" # noqa: F401 +"" # noqa -- Some extra detail. +"" #Ignore + +#Suppression for multiple tools +#LGTM-1929 +class frozenbidict(BidictBase): # noqa: E501; (line too long) pylint: disable=invalid-name; lgtm [py/missing-equals] + pass +"" # noqa: E501; (line too long) pylint: disable=invalid-name; lgtm +"" # random nonsense lgtm [py/missing-equals] and then some more commentary... + + +# Case insensitive comments + +"" # LGTM +"" # LGTM[py/line-too-long] + +#Avoid some erroneous matches +"" # foolgtm[py/missing-equals] +"" # foolgtm + +"" # lgtm[py/line-too-long] and lgtm[py/non-callable-called] +"" # lgtm[py/line-too-long]; lgtm diff --git a/python/ql/test/query-tests/analysis/suppression/testWindows.py b/python/ql/test/query-tests/analysis/suppression/testWindows.py new file mode 100644 index 00000000000..50c8f8a5aae --- /dev/null +++ b/python/ql/test/query-tests/analysis/suppression/testWindows.py @@ -0,0 +1,49 @@ + +# Formatting tests: + +"" # lgtm +"" # lgtm[py/line-too-long] +"" # lgtm[py/line-too-long, py/non-callable-called] +"" # lgtm[@tag:security] +"" # lgtm[@tag:security,py/line-too-long] +"" # lgtm[@expires:2017-06-11] +"" # lgtm[py/non-callable-called] because I know better than lgtm +"" # lgtm: blah blah +"" # lgtm blah blah #falsepositive +"" # lgtm blah blah -- falsepositive +"" #lgtm [py/non-callable-called] +"" # lgtm[] +"" # lgtmfoo +"" #lgtm +"" # lgtm +"" # lgtm [py/line-too-long] +"" # lgtm lgtm + + +#lgtm -- Ignore this -- No line or scope. + +#On real code: + +def foo(): #lgtm [func] + # lgtm -- Blank line (ignore for now, maybe scope wide in future). + "docstring" # lgtm on docstring + return { #lgtm [py/duplicate-key-in-dict] + "a": 1, + "a": 2 + } + +class C: # lgtm class + def meth(self): # lgtm method + pass + +""#noqa +"" # noqa + +"The following should be ignored" +# flake8: noqa +# noqa: F401 +# noqa -- Some extra detail. +#Ignore + +"" # lgtm[py/line-too-long] and lgtm[py/non-callable-called] +"" # lgtm[py/line-too-long]; lgtm diff --git a/python/ql/test/query-tests/options b/python/ql/test/query-tests/options new file mode 100644 index 00000000000..bd016eb1ce5 --- /dev/null +++ b/python/ql/test/query-tests/options @@ -0,0 +1,2 @@ +automatic_locations: true +semmle-extractor-options: --max-import-depth=1