├── tests ├── relative-import.test │ ├── __init__.py │ ├── baz │ │ ├── __init__.py │ │ └── rel.py │ ├── foo │ │ ├── __init__.py │ │ └── bar.py │ └── refs.json ├── references.test │ ├── basic.py │ └── refs.json ├── import │ ├── multi-level.test │ │ ├── kitchen │ │ │ ├── __init__.py │ │ │ └── oven.py │ │ ├── bedroom.py │ │ └── refs.json │ ├── import-from.test │ │ ├── drawer.py │ │ ├── import-same-level.py │ │ ├── kitchen │ │ │ ├── oven.py │ │ │ └── __init__.py │ │ ├── import-oven.py │ │ ├── import-star-from-init.py │ │ ├── import-pizza-from-oven.py │ │ └── import-star-from-oven.py │ └── same-level.test │ │ ├── mod2.py │ │ ├── mod1.py │ │ └── refs.json ├── bom.test │ ├── bom.py │ └── refs.json ├── unicode.test │ ├── test1.py │ └── refs.json ├── references-multi.test │ ├── multi.py │ └── refs.json ├── identity.test │ ├── test1.py │ └── refs.json ├── loop.test │ ├── test1.py │ └── refs.json ├── object-member.test │ ├── test1.py │ └── refs.json ├── field-assign.test │ ├── test1.py │ └── refs.json ├── union-inside-tuple.test │ ├── test1.py │ └── refs.json ├── lambda.test │ ├── test1.py │ └── refs.json ├── isinstance.test │ ├── test1.py │ └── refs.json ├── call.test │ ├── test1.py │ └── test-chained.py ├── return.test │ ├── test1.py │ └── refs.json ├── global.test │ ├── test1.py │ └── refs.json ├── infinity.test │ ├── test1.py │ └── refs.json ├── element-type.test │ ├── test1.py │ └── refs.json ├── recursion.test │ ├── test1.py │ └── refs.json ├── decorator.test │ ├── test1.py │ └── refs.json ├── redefine-op.test │ └── redefine-plus.py ├── override-arithmetic.test │ └── test1.py ├── branch.test │ ├── test1.py │ └── refs.json └── constructor.test │ └── test1.py ├── src ├── main │ ├── resources │ │ └── org │ │ │ └── yinwang │ │ │ └── pysonar │ │ │ ├── models │ │ │ └── __init__.py │ │ │ ├── javascript │ │ │ ├── highlight-debug.js │ │ │ └── highlight.js │ │ │ └── css │ │ │ └── demo.css │ └── java │ │ └── org │ │ └── yinwang │ │ └── pysonar │ │ ├── ast │ │ ├── NameType.java │ │ ├── Dummy.java │ │ ├── Break.java │ │ ├── Pass.java │ │ ├── Ellipsis.java │ │ ├── Continue.java │ │ ├── Unsupported.java │ │ ├── PySet.java │ │ ├── Sequence.java │ │ ├── Url.java │ │ ├── PyList.java │ │ ├── Repr.java │ │ ├── Await.java │ │ ├── Index.java │ │ ├── Bytes.java │ │ ├── Return.java │ │ ├── Starred.java │ │ ├── Yield.java │ │ ├── YieldFrom.java │ │ ├── Expr.java │ │ ├── Delete.java │ │ ├── ExtSlice.java │ │ ├── Global.java │ │ ├── Import.java │ │ ├── Block.java │ │ ├── PyComplex.java │ │ ├── Assert.java │ │ ├── UnaryOp.java │ │ ├── PyModule.java │ │ ├── Dict.java │ │ ├── Print.java │ │ ├── Alias.java │ │ ├── Str.java │ │ ├── Assign.java │ │ ├── Exec.java │ │ ├── Slice.java │ │ ├── Attribute.java │ │ ├── IfExp.java │ │ ├── While.java │ │ ├── If.java │ │ ├── SetComp.java │ │ ├── ListComp.java │ │ ├── BinOp.java │ │ ├── GeneratorExp.java │ │ ├── Raise.java │ │ ├── Subscript.java │ │ ├── PyFloat.java │ │ ├── DictComp.java │ │ ├── With.java │ │ ├── Comprehension.java │ │ ├── Handler.java │ │ ├── Keyword.java │ │ ├── For.java │ │ ├── Try.java │ │ ├── Withitem.java │ │ ├── Tuple.java │ │ ├── Call.java │ │ ├── NodeType.java │ │ ├── ClassDef.java │ │ ├── Name.java │ │ ├── PyInt.java │ │ ├── Op.java │ │ ├── ImportFrom.java │ │ ├── FunctionDef.java │ │ └── Node.java │ │ ├── hash │ │ ├── HashFunction.java │ │ ├── EqualFunction.java │ │ ├── GenericHashFunction.java │ │ ├── GenericEqualFunction.java │ │ ├── FunTypeEqualFunction.java │ │ └── MyHashSet.java │ │ ├── Globals.java │ │ ├── CallStackEntry.java │ │ ├── Pair.java │ │ ├── Stack.java │ │ ├── CallStack.java │ │ ├── Diagnostic.java │ │ ├── TypeStack.java │ │ ├── Stats.java │ │ ├── types │ │ ├── InstanceType.java │ │ ├── Types.java │ │ ├── ModuleType.java │ │ ├── ClassType.java │ │ ├── DictType.java │ │ ├── ListType.java │ │ ├── Type.java │ │ ├── TupleType.java │ │ └── UnionType.java │ │ ├── Options.java │ │ ├── demos │ │ ├── HtmlOutline.java │ │ ├── Style.java │ │ └── Demo.java │ │ ├── Progress.java │ │ └── AstCache.java └── test │ └── java │ └── org │ └── yinwang │ └── pysonar │ └── TestRefs.java ├── .travis.yml ├── README.md └── pom.xml /tests/relative-import.test/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/relative-import.test/baz/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/relative-import.test/foo/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/references.test/basic.py: -------------------------------------------------------------------------------- 1 | x = 1 2 | print x 3 | -------------------------------------------------------------------------------- /src/main/resources/org/yinwang/pysonar/models/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/import/multi-level.test/kitchen/__init__.py: -------------------------------------------------------------------------------- 1 | # empty 2 | -------------------------------------------------------------------------------- /tests/relative-import.test/foo/bar.py: -------------------------------------------------------------------------------- 1 | def f(x): 2 | return 0 3 | -------------------------------------------------------------------------------- /tests/bom.test/bom.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | x = 42 3 | print("BOM BOOM!", x) 4 | -------------------------------------------------------------------------------- /tests/unicode.test/test1.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | x = '猪头' 4 | y = x 5 | -------------------------------------------------------------------------------- /tests/import/import-from.test/drawer.py: -------------------------------------------------------------------------------- 1 | class Knife: 2 | length = "3in" 3 | -------------------------------------------------------------------------------- /tests/relative-import.test/baz/rel.py: -------------------------------------------------------------------------------- 1 | from ..foo.bar import f 2 | 3 | y = f(42) 4 | print y 5 | -------------------------------------------------------------------------------- /tests/import/same-level.test/mod2.py: -------------------------------------------------------------------------------- 1 | class B: 2 | a = 'hi' 3 | 4 | 5 | def foo(x): 6 | return x + 1 7 | -------------------------------------------------------------------------------- /tests/import/import-from.test/import-same-level.py: -------------------------------------------------------------------------------- 1 | from drawer import Knife 2 | 3 | k1 = Knife() 4 | print k1.length 5 | -------------------------------------------------------------------------------- /tests/import/import-from.test/kitchen/oven.py: -------------------------------------------------------------------------------- 1 | class Pizza: 2 | size = '9in' 3 | 4 | class Bread: 5 | size = 10 6 | -------------------------------------------------------------------------------- /tests/references-multi.test/multi.py: -------------------------------------------------------------------------------- 1 | x = int() 2 | 3 | if x: 4 | w = 1 5 | else: 6 | w = 'hi' 7 | 8 | print w 9 | -------------------------------------------------------------------------------- /tests/import/same-level.test/mod1.py: -------------------------------------------------------------------------------- 1 | import mod2 2 | 3 | o = mod2.B() 4 | print o.a 5 | 6 | u = mod2.foo(10) 7 | print u 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | 3 | cache: 4 | directories: 5 | - "$HOME/.m2" 6 | 7 | jdk: 8 | - openjdk8 9 | - oraclejdk12 10 | -------------------------------------------------------------------------------- /tests/import/multi-level.test/bedroom.py: -------------------------------------------------------------------------------- 1 | import kitchen.oven 2 | 3 | pizza = kitchen.oven.Pizza(['mushroom', 'sauage', 'cheeze']) 4 | print pizza.get_toppings() 5 | -------------------------------------------------------------------------------- /tests/identity.test/test1.py: -------------------------------------------------------------------------------- 1 | # test 2 | 3 | def foo(f): 4 | return f(1), f(True) 5 | 6 | def id(x): 7 | return x 8 | 9 | a = foo(id) 10 | print(a) 11 | 12 | 13 | -------------------------------------------------------------------------------- /tests/loop.test/test1.py: -------------------------------------------------------------------------------- 1 | # loop test 2 | 3 | a = "hello" 4 | k = 2 5 | while k <= 3: 6 | b = a 7 | print b 8 | k = k + 1 9 | a = 1 10 | 11 | print a, b 12 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/NameType.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | public enum NameType { 4 | LOCAL, 5 | INSTANCE, 6 | CLASS, 7 | GLOBAL 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/hash/HashFunction.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.hash; 2 | 3 | 4 | public abstract class HashFunction { 5 | public abstract int hash(Object o); 6 | } 7 | -------------------------------------------------------------------------------- /tests/import/multi-level.test/kitchen/oven.py: -------------------------------------------------------------------------------- 1 | class Pizza: 2 | def __init__(self, toppings): 3 | self.toppings = toppings 4 | 5 | def get_toppings(self): 6 | return self.toppings 7 | -------------------------------------------------------------------------------- /tests/object-member.test/test1.py: -------------------------------------------------------------------------------- 1 | # test reference to field created in object 2 | 3 | 4 | class A: 5 | x = 0 6 | 7 | a1 = A() 8 | a1.y = "hi" 9 | 10 | print a1.x 11 | print a1.y 12 | -------------------------------------------------------------------------------- /tests/field-assign.test/test1.py: -------------------------------------------------------------------------------- 1 | # test assign into field 2 | 3 | class A: 4 | x = 1 5 | 6 | a = A() 7 | a.x = "foo" 8 | a.y = 2 # create field in object here 9 | 10 | print a.x, a.y 11 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/hash/EqualFunction.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.hash; 2 | 3 | 4 | public abstract class EqualFunction { 5 | public abstract boolean equals(Object x, Object y); 6 | } 7 | -------------------------------------------------------------------------------- /tests/union-inside-tuple.test/test1.py: -------------------------------------------------------------------------------- 1 | # test union inside tuple 2 | 3 | def x(q): 4 | if q == 0: 5 | return (2, True) 6 | else: 7 | return ("hi", False) 8 | 9 | y, z = x(3) 10 | -------------------------------------------------------------------------------- /tests/lambda.test/test1.py: -------------------------------------------------------------------------------- 1 | # test lambda 2 | 3 | 4 | def foo(f): 5 | y = f(1, "hi") 6 | return y 7 | 8 | z = foo(lambda a,b: [a,b]) 9 | print z 10 | 11 | w = (lambda f: f(1))(lambda x: x+1) 12 | print w 13 | -------------------------------------------------------------------------------- /tests/import/import-from.test/import-oven.py: -------------------------------------------------------------------------------- 1 | # from kitchen import a module oven 2 | 3 | from kitchen import oven 4 | 5 | pizza = oven.Pizza() 6 | print pizza.size 7 | 8 | bread = oven.Bread() 9 | print bread.size 10 | -------------------------------------------------------------------------------- /tests/isinstance.test/test1.py: -------------------------------------------------------------------------------- 1 | # test isinstance inference 2 | 3 | x = random() 4 | 5 | 6 | def foo(): 7 | return int 8 | 9 | 10 | if isinstance(x, foo()): 11 | y = x 12 | else: 13 | z = x 14 | 15 | print(y, z) 16 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/Globals.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar; 2 | 3 | public class Globals { 4 | public static final String MODEL_LOCATION = "org/yinwang/pysonar/models"; 5 | public static final String FILE_SUFFIX = ".py"; 6 | } 7 | -------------------------------------------------------------------------------- /tests/call.test/test1.py: -------------------------------------------------------------------------------- 1 | def foo(x): 2 | return x 3 | 4 | 5 | def bar(y): 6 | return foo(y) 7 | 8 | 9 | def baz1(): 10 | return bar(1) 11 | 12 | 13 | def baz2(): 14 | return bar('hi') 15 | 16 | 17 | baz1() 18 | baz2() 19 | -------------------------------------------------------------------------------- /tests/return.test/test1.py: -------------------------------------------------------------------------------- 1 | u = 1 2 | v = 'hi' 3 | 4 | 5 | def f(x, y=None): 6 | if x < 5: 7 | return u 8 | else: 9 | print v 10 | return True 11 | y = 'hi' 12 | print y 13 | 14 | y = f(42) 15 | print y 16 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/hash/GenericHashFunction.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.hash; 2 | 3 | 4 | public class GenericHashFunction extends HashFunction { 5 | 6 | @Override 7 | public int hash(Object o) { 8 | return o.hashCode(); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tests/global.test/test1.py: -------------------------------------------------------------------------------- 1 | x = 1 2 | y = True 3 | 4 | def f(): 5 | global x 6 | x = False 7 | y = 42 8 | print x 9 | print y 10 | 11 | 12 | def g(): 13 | x = 'hi' 14 | print x 15 | y = 'foo' 16 | print y 17 | global x 18 | 19 | print y 20 | -------------------------------------------------------------------------------- /tests/import/import-from.test/import-star-from-init.py: -------------------------------------------------------------------------------- 1 | # import * from __init__.py of kitchen package 2 | 3 | from kitchen import * 4 | 5 | print spoon(1) 6 | print fork(2) 7 | 8 | # knife is not export from __init__.py 9 | # should not be able to find it 10 | print knife(3) 11 | -------------------------------------------------------------------------------- /tests/import/import-from.test/kitchen/__init__.py: -------------------------------------------------------------------------------- 1 | # knife is not exported 2 | __all__ = ["spoon", "fork"] 3 | 4 | 5 | def spoon(x): 6 | return x 7 | 8 | 9 | def fork(x): 10 | return [x,x] 11 | 12 | 13 | # knife is not exported 14 | def knife(x): 15 | return x+1 16 | -------------------------------------------------------------------------------- /tests/infinity.test/test1.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | 4 | x = int() 5 | 6 | if 1.5 < x and x < 10: 7 | if x < 6.2: 8 | w = x # [2, 6] 9 | else: 10 | w = x # [7, 10) 11 | else: 12 | w = x # (-∞, 1] [10, +∞) 13 | 14 | print w 15 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/hash/GenericEqualFunction.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.hash; 2 | 3 | 4 | public class GenericEqualFunction extends EqualFunction { 5 | @Override 6 | public boolean equals(Object x, Object y) { 7 | return x.equals(y); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /tests/import/import-from.test/import-pizza-from-oven.py: -------------------------------------------------------------------------------- 1 | # import Pizza and not Bread from module oven.py 2 | 3 | from kitchen.oven import Pizza 4 | 5 | pizza = Pizza() 6 | print(pizza.size) 7 | 8 | # Bread is not imported, should not find it 9 | bread = Bread() 10 | size = bread.size 11 | print(size) 12 | -------------------------------------------------------------------------------- /tests/import/import-from.test/import-star-from-oven.py: -------------------------------------------------------------------------------- 1 | # import * from module oven.py 2 | 3 | from kitchen.oven import * 4 | 5 | pizza = Pizza() 6 | print(pizza.size) 7 | 8 | bread1 = Bread() 9 | size1 = bread1.size 10 | bread2 = Bread() 11 | size2 = bread2.size 12 | 13 | print(size1) 14 | print(size2) 15 | -------------------------------------------------------------------------------- /tests/call.test/test-chained.py: -------------------------------------------------------------------------------- 1 | 2 | class A: 3 | def foo(self, x, y): 4 | t = x + 1 5 | return self 6 | 7 | a = A() 8 | y = a.foo(1, 2).foo(2, 3).foo(3, 4).foo(4, 5).foo(1, 2).foo(2, 3).foo(3, 4).foo(4, 5).foo(1, 2).foo(2, 3).foo(3, 4).foo(4, 5).foo(1, 2).foo(2, 3).foo(3, 4).foo(4, 5).foo(1, 2).foo(2, 3).foo(3, 4).foo(4, 5) 9 | print y -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/Dummy.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | /** 4 | * dummy node for locating purposes only 5 | * rarely used 6 | */ 7 | public class Dummy extends Node { 8 | 9 | public Dummy(String file, int start, int end, int line, int col) { 10 | super(NodeType.DUMMY, file, start, end, line, col); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /tests/element-type.test/test1.py: -------------------------------------------------------------------------------- 1 | # test inferring element type from subscript assignment, and append, update methods 2 | 3 | a = [] 4 | a[0] = 1 5 | print a 6 | 7 | b = {} 8 | b[0] = "hello" 9 | x = b[1] 10 | print x 11 | 12 | c = [] 13 | c.append(1) 14 | z = c[0] 15 | print z 16 | 17 | d = {} 18 | d.update({'x': 10}) 19 | d.update({'y': True}) 20 | u = d['foo'] 21 | print u 22 | -------------------------------------------------------------------------------- /tests/recursion.test/test1.py: -------------------------------------------------------------------------------- 1 | class Base: 2 | def x(self): 3 | return "" 4 | 5 | class A(Base): 6 | def x(self): 7 | return "A" 8 | 9 | class B(Base): 10 | def x(Base): 11 | return "B" 12 | 13 | def f1(n): 14 | if n == 0: 15 | a = A() 16 | return a 17 | else: 18 | return f1(0).x() 19 | 20 | 21 | k = f1(1) 22 | print k 23 | -------------------------------------------------------------------------------- /tests/decorator.test/test1.py: -------------------------------------------------------------------------------- 1 | # test decorators for staticmethod and classmethod 2 | 3 | class A: 4 | 5 | def normalm(self, x): 6 | return x 7 | 8 | @staticmethod 9 | def staticm(x, y): 10 | return x, y 11 | 12 | @classmethod 13 | def classm(cls, y): 14 | return cls, y 15 | 16 | a = A() 17 | a.normalm(10) 18 | a.staticm(10, "hi") 19 | a.classm("hi") 20 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/CallStackEntry.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar; 2 | 3 | import org.yinwang.pysonar.types.FunType; 4 | import org.yinwang.pysonar.types.Type; 5 | 6 | public class CallStackEntry 7 | { 8 | public FunType fun; 9 | public Type from; 10 | 11 | public CallStackEntry(FunType fun, Type from) 12 | { 13 | this.fun = fun; 14 | this.from = from; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tests/bom.test/refs.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "ref": { 4 | "name": "x", 5 | "file": "bom.py", 6 | "start": 43, 7 | "end": 44, 8 | "line": 3, 9 | "col": 20 10 | }, 11 | "dests": [ 12 | { 13 | "name": "x", 14 | "file": "bom.py", 15 | "start": 17, 16 | "end": 18, 17 | "line": 2, 18 | "col": 1, 19 | "type": "int" 20 | } 21 | ] 22 | } 23 | ] -------------------------------------------------------------------------------- /tests/unicode.test/refs.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "ref": { 4 | "name": "x", 5 | "file": "test1.py", 6 | "start": 30, 7 | "end": 31, 8 | "line": 4, 9 | "col": 5 10 | }, 11 | "dests": [ 12 | { 13 | "name": "x", 14 | "file": "test1.py", 15 | "start": 17, 16 | "end": 18, 17 | "line": 3, 18 | "col": 1, 19 | "type": "str" 20 | } 21 | ] 22 | } 23 | ] -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/Break.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | public class Break extends Node { 6 | 7 | public Break(String file, int start, int end, int line, int col) { 8 | super(NodeType.BREAK, file, start, end, line, col); 9 | } 10 | 11 | @NotNull 12 | @Override 13 | public String toString() { 14 | return "(break)"; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/Pass.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | public class Pass extends Node { 6 | 7 | public Pass(String file, int start, int end, int line, int col) { 8 | super(NodeType.PASS, file, start, end, line, col); 9 | } 10 | 11 | @NotNull 12 | @Override 13 | public String toString() { 14 | return ""; 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /tests/references.test/refs.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "ref": { 4 | "name": "x", 5 | "file": "basic.py", 6 | "start": 12, 7 | "end": 13, 8 | "line": 2, 9 | "col": 7 10 | }, 11 | "dests": [ 12 | { 13 | "name": "x", 14 | "file": "basic.py", 15 | "start": 0, 16 | "end": 1, 17 | "line": 1, 18 | "col": 1, 19 | "type": "int" 20 | } 21 | ] 22 | } 23 | ] -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/Ellipsis.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | public class Ellipsis extends Node { 6 | 7 | public Ellipsis(String file, int start, int end, int line, int col) { 8 | super(NodeType.ELLIPSIS, file, start, end, line, col); 9 | } 10 | 11 | @NotNull 12 | @Override 13 | public String toString() { 14 | return "..."; 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/Continue.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | public class Continue extends Node { 6 | 7 | public Continue(String file, int start, int end, int line, int col) { 8 | super(NodeType.CONTINUE, file, start, end, line, col); 9 | } 10 | 11 | @NotNull 12 | @Override 13 | public String toString() { 14 | return "(continue)"; 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/Unsupported.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | public class Unsupported extends Node { 6 | 7 | public Unsupported(String file, int start, int end, int line, int col) { 8 | super(NodeType.UNSUPPORTED, file, start, end, line, col); 9 | } 10 | 11 | @NotNull 12 | @Override 13 | public String toString() { 14 | return "(unsupported)"; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/PySet.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.util.List; 6 | 7 | public class PySet extends Sequence { 8 | 9 | public PySet(List elts, String file, int start, int end, int line, int col) { 10 | super(NodeType.PYSET, elts, file, start, end, line, col); 11 | } 12 | 13 | @NotNull 14 | @Override 15 | public String toString() { 16 | return ""; 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/Pair.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar; 2 | 3 | import java.util.Objects; 4 | 5 | public class Pair { 6 | public Object first; 7 | public Object second; 8 | 9 | public Pair(Object first, Object second) { 10 | this.first = first; 11 | this.second = second; 12 | } 13 | 14 | public boolean equals(Object first, Object second) { 15 | return this.first == first && this.second == second || 16 | this.first == second && this.second == first; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/Sequence.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.util.List; 6 | 7 | public abstract class Sequence extends Node { 8 | 9 | @NotNull 10 | public List elts; 11 | 12 | public Sequence(NodeType nodeType, @NotNull List elts, String file, int start, int end, int line, int col) { 13 | super(nodeType, file, start, end, line, col); 14 | this.elts = elts; 15 | addChildren(elts); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/Url.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | /** 6 | * virtual-AST node used to represent virtual source locations for builtins 7 | * as external urls. 8 | */ 9 | public class Url extends Node { 10 | 11 | public String url; 12 | 13 | public Url(String url) { 14 | this.url = url; 15 | } 16 | 17 | @NotNull 18 | @Override 19 | public String toString() { 20 | return ""; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/PyList.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.util.List; 6 | 7 | public class PyList extends Sequence { 8 | 9 | public PyList(@NotNull List elts, String file, int start, int end, int line, int col) { 10 | super(NodeType.PYLIST, elts, file, start, end, line, col); 11 | } 12 | 13 | @NotNull 14 | @Override 15 | public String toString() { 16 | return ""; 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/Repr.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | public class Repr extends Node { 6 | 7 | public Node value; 8 | 9 | public Repr(Node n, String file, int start, int end, int line, int col) { 10 | super(NodeType.REPR, file, start, end, line, col); 11 | this.value = n; 12 | addChildren(n); 13 | } 14 | 15 | @NotNull 16 | @Override 17 | public String toString() { 18 | return ""; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/Await.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | public class Await extends Node { 6 | 7 | public Node value; 8 | 9 | public Await(Node n, String file, int start, int end, int line, int col) { 10 | super(NodeType.AWAIT, file, start, end, line, col); 11 | this.value = n; 12 | addChildren(n); 13 | } 14 | 15 | @NotNull 16 | @Override 17 | public String toString() { 18 | return ""; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/Index.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | public class Index extends Node { 6 | 7 | public Node value; 8 | 9 | public Index(Node n, String file, int start, int end, int line, int col) { 10 | super(NodeType.INDEX, file, start, end, line, col); 11 | this.value = n; 12 | addChildren(n); 13 | } 14 | 15 | @NotNull 16 | @Override 17 | public String toString() { 18 | return ""; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/Bytes.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | public class Bytes extends Node { 6 | 7 | public Object value; 8 | 9 | public Bytes(@NotNull Object value, String file, int start, int end, int line, int col) { 10 | super(NodeType.BYTES, file, start, end, line, col); 11 | this.value = value.toString(); 12 | } 13 | 14 | @NotNull 15 | @Override 16 | public String toString() { 17 | return "(bytes: " + value + ")"; 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/Return.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | public class Return extends Node { 6 | 7 | public Node value; 8 | 9 | public Return(Node n, String file, int start, int end, int line, int col) { 10 | super(NodeType.RETURN, file, start, end, line, col); 11 | this.value = n; 12 | addChildren(n); 13 | } 14 | 15 | @NotNull 16 | @Override 17 | public String toString() { 18 | return ""; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/Starred.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | public class Starred extends Node { 6 | 7 | public Node value; 8 | 9 | public Starred(Node n, String file, int start, int end, int line, int col) { 10 | super(NodeType.STARRED, file, start, end, line, col); 11 | this.value = n; 12 | addChildren(n); 13 | } 14 | 15 | @NotNull 16 | @Override 17 | public String toString() { 18 | return ""; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/Yield.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | public class Yield extends Node { 6 | 7 | public Node value; 8 | 9 | public Yield(Node n, String file, int start, int end, int line, int col) { 10 | super(NodeType.YIELD, file, start, end, line, col); 11 | this.value = n; 12 | addChildren(n); 13 | } 14 | 15 | @NotNull 16 | @Override 17 | public String toString() { 18 | return ""; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /tests/redefine-op.test/redefine-plus.py: -------------------------------------------------------------------------------- 1 | # test 2 | 3 | 4 | class A: 5 | def __init__(self, value): 6 | self.value = value 7 | 8 | def __sub__(self, other): 9 | if isinstance(other, int): 10 | return 2 * other 11 | 12 | def __lt__(self, other): 13 | if isinstance(other, int): 14 | return len(str(self.value)) < other 15 | else: 16 | return False 17 | 18 | 19 | def fib(n): 20 | if n < 2: 21 | return 1 22 | else: 23 | return fib(n - 1) + fib(n - 2) 24 | 25 | 26 | x = A("foo") 27 | print fib(x) 28 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/YieldFrom.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | public class YieldFrom extends Node { 6 | 7 | public Node value; 8 | 9 | public YieldFrom(Node n, String file, int start, int end, int line, int col) { 10 | super(NodeType.YIELDFROM, file, start, end, line, col); 11 | this.value = n; 12 | addChildren(n); 13 | } 14 | 15 | @NotNull 16 | @Override 17 | public String toString() { 18 | return ""; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/Expr.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | /** 6 | * Expression statement. 7 | */ 8 | public class Expr extends Node { 9 | 10 | public Node value; 11 | 12 | public Expr(Node n, String file, int start, int end, int line, int col) { 13 | super(NodeType.EXPR, file, start, end, line, col); 14 | this.value = n; 15 | addChildren(n); 16 | } 17 | 18 | @NotNull 19 | @Override 20 | public String toString() { 21 | return ""; 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/hash/FunTypeEqualFunction.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.hash; 2 | 3 | import org.yinwang.pysonar.types.FunType; 4 | 5 | 6 | public class FunTypeEqualFunction extends EqualFunction { 7 | 8 | @Override 9 | public boolean equals(Object x, Object y) { 10 | if (x instanceof FunType && y instanceof FunType) { 11 | FunType xx = (FunType) x; 12 | FunType yy = (FunType) y; 13 | return xx == yy || 14 | xx.table.path.equals(yy.table.path); 15 | } else { 16 | return x.equals(y); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/Delete.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.util.List; 6 | 7 | public class Delete extends Node { 8 | 9 | public List targets; 10 | 11 | public Delete(List elts, String file, int start, int end, int line, int col) { 12 | super(NodeType.DELETE, file, start, end, line, col); 13 | this.targets = elts; 14 | addChildren(elts); 15 | } 16 | 17 | @NotNull 18 | @Override 19 | public String toString() { 20 | return ""; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/ExtSlice.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.util.List; 6 | 7 | public class ExtSlice extends Node { 8 | 9 | public List dims; 10 | 11 | public ExtSlice(List dims, String file, int start, int end, int line, int col) { 12 | super(NodeType.EXTSLICE, file, start, end, line, col); 13 | this.dims = dims; 14 | addChildren(dims); 15 | } 16 | 17 | @NotNull 18 | @Override 19 | public String toString() { 20 | return ""; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/Global.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.util.List; 6 | 7 | public class Global extends Node { 8 | 9 | public List names; 10 | 11 | public Global(List names, String file, int start, int end, int line, int col) { 12 | super(NodeType.GLOBAL, file, start, end, line, col); 13 | this.names = names; 14 | addChildren(names); 15 | } 16 | 17 | @NotNull 18 | @Override 19 | public String toString() { 20 | return ""; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/Import.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.util.List; 6 | 7 | public class Import extends Node { 8 | 9 | public List names; 10 | 11 | public Import(List names, String file, int start, int end, int line, int col) { 12 | super(NodeType.IMPORT, file, start, end, line, col); 13 | this.names = names; 14 | addChildren(names); 15 | } 16 | 17 | @NotNull 18 | @Override 19 | public String toString() { 20 | return ""; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/Block.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.util.List; 6 | 7 | public class Block extends Node { 8 | 9 | @NotNull 10 | public List seq; 11 | 12 | public Block(@NotNull List seq, String file, int start, int end, int line, int col) { 13 | super(NodeType.BLOCK, file, start, end, line, col); 14 | this.seq = seq; 15 | addChildren(seq); 16 | } 17 | 18 | @NotNull 19 | @Override 20 | public String toString() { 21 | return "(block:" + seq + ")"; 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/PyComplex.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | public class PyComplex extends Node { 6 | 7 | public double real; 8 | public double imag; 9 | 10 | public PyComplex(double real, double imag, String file, int start, int end, int line, int col) { 11 | super(NodeType.PYCOMPLEX, file, start, end, line, col); 12 | this.real = real; 13 | this.imag = imag; 14 | } 15 | 16 | @NotNull 17 | @Override 18 | public String toString() { 19 | return "(" + real + "+" + imag + "j)"; 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /tests/override-arithmetic.test/test1.py: -------------------------------------------------------------------------------- 1 | # t4 2 | 3 | 4 | class A: 5 | 6 | def __init__(self, value): 7 | self.value = value 8 | 9 | def __sub__(self, other): 10 | if isinstance(other, int): 11 | return self.value * other 12 | else: 13 | return 0 14 | 15 | def __lt__(self, other): 16 | if isinstance(other, int): 17 | return self.value + other 18 | else: 19 | return False 20 | 21 | 22 | def fib(n): 23 | if n < 2: 24 | return 1 25 | else: 26 | return fib(n - 1) + fib(n - 2) 27 | 28 | 29 | x = A(42) 30 | print fib(x) 31 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/Stack.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class Stack 7 | { 8 | private List content = new ArrayList<>(); 9 | 10 | public void push(T item) 11 | { 12 | content.add(item); 13 | } 14 | 15 | public T top() 16 | { 17 | return content.get(content.size() - 1); 18 | } 19 | 20 | public T pop() 21 | { 22 | if (!content.isEmpty()) 23 | { 24 | return content.remove(content.size() - 1); 25 | } else { 26 | return null; 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/Assert.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | public class Assert extends Node { 6 | 7 | public Node test; 8 | public Node msg; 9 | 10 | public Assert(Node test, Node msg, String file, int start, int end, int line, int col) { 11 | super(NodeType.ASSERT, file, start, end, line, col); 12 | this.test = test; 13 | this.msg = msg; 14 | addChildren(test, msg); 15 | } 16 | 17 | @NotNull 18 | @Override 19 | public String toString() { 20 | return ""; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/UnaryOp.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | public class UnaryOp extends Node { 6 | 7 | public Op op; 8 | public Node operand; 9 | 10 | public UnaryOp(Op op, Node operand, String file, int start, int end, int line, int col) { 11 | super(NodeType.UNARYOP, file, start, end, line, col); 12 | this.op = op; 13 | this.operand = operand; 14 | addChildren(operand); 15 | } 16 | 17 | @NotNull 18 | @Override 19 | public String toString() { 20 | return "(" + op + " " + operand + ")"; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/PyModule.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import org.yinwang.pysonar.$; 5 | 6 | public class PyModule extends Node { 7 | 8 | public Block body; 9 | 10 | public PyModule(Block body, String file, int start, int end, int line, int col) { 11 | super(NodeType.MODULE, file, start, end, line, col); 12 | this.name = $.moduleName(file); 13 | this.body = body; 14 | addChildren(this.body); 15 | } 16 | 17 | @NotNull 18 | @Override 19 | public String toString() { 20 | return "(module:" + file + ")"; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/resources/org/yinwang/pysonar/javascript/highlight-debug.js: -------------------------------------------------------------------------------- 1 | var highlighted = new Array(); 2 | function highlight() 3 | { 4 | // clear existing highlights 5 | for (var i = 0; i < highlighted.length; i++) { 6 | var elm = document.getElementById(highlighted[i]); 7 | if (elm != null) { 8 | elm.style.backgroundColor = 'white'; 9 | } 10 | } 11 | highlighted = new Array(); 12 | for (var i = 0; i < arguments.length; i++) { 13 | var elm = document.getElementById(arguments[i]); 14 | if (elm != null) { 15 | elm.style.backgroundColor = '#dddddd'; 16 | } 17 | highlighted.push(arguments[i]); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/CallStack.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import org.yinwang.pysonar.ast.Node; 5 | import org.yinwang.pysonar.types.Type; 6 | 7 | import java.util.HashSet; 8 | import java.util.Set; 9 | 10 | 11 | public class CallStack { 12 | 13 | @NotNull 14 | private Set stack = new HashSet<>(); 15 | 16 | 17 | public void push(Node call, Type type) { 18 | stack.add(call); 19 | } 20 | 21 | 22 | public void pop(Node call, Type type) { 23 | stack.remove(call); 24 | } 25 | 26 | 27 | public boolean contains(Node call, Type type) { 28 | return stack.contains(call); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/Dict.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.util.List; 6 | 7 | public class Dict extends Node { 8 | 9 | public List keys; 10 | public List values; 11 | 12 | public Dict(List keys, List values, String file, int start, int end, int line, int col) { 13 | super(NodeType.DICT, file, start, end, line, col); 14 | this.keys = keys; 15 | this.values = values; 16 | addChildren(keys); 17 | addChildren(values); 18 | } 19 | 20 | @NotNull 21 | @Override 22 | public String toString() { 23 | return ""; 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/Print.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.util.List; 6 | 7 | public class Print extends Node { 8 | 9 | public Node dest; 10 | public List values; 11 | 12 | public Print(Node dest, List elts, String file, int start, int end, int line, int col) { 13 | super(NodeType.PRINT, file, start, end, line, col); 14 | this.dest = dest; 15 | this.values = elts; 16 | addChildren(dest); 17 | addChildren(elts); 18 | } 19 | 20 | @NotNull 21 | @Override 22 | public String toString() { 23 | return ""; 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/Alias.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.util.List; 6 | 7 | public class Alias extends Node { 8 | 9 | public List name; 10 | public Name asname; 11 | 12 | public Alias(List name, Name asname, String file, int start, int end, int line, int col) { 13 | super(NodeType.ALIAS, file, start, end, line, col); 14 | this.name = name; 15 | this.asname = asname; 16 | addChildren(name); 17 | addChildren(asname); 18 | } 19 | 20 | @NotNull 21 | @Override 22 | public String toString() { 23 | return ""; 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/Str.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | public class Str extends Node { 6 | 7 | public String value; 8 | 9 | public Str(@NotNull Object value, String file, int start, int end, int line, int col) { 10 | super(NodeType.STR, file, start, end, line, col); 11 | this.value = value.toString(); 12 | } 13 | 14 | @NotNull 15 | @Override 16 | public String toString() { 17 | String summary; 18 | if (value.length() > 10) { 19 | summary = value.substring(0, 10); 20 | } else { 21 | summary = value; 22 | } 23 | return "'" + summary + "'"; 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/Assign.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | public class Assign extends Node { 6 | 7 | @NotNull 8 | public Node target; 9 | @NotNull 10 | public Node value; 11 | 12 | public Assign(@NotNull Node target, @NotNull Node value, String file, int start, int end, int line, int col) { 13 | super(NodeType.ASSIGN, file, start, end, line, col); 14 | this.target = target; 15 | this.value = value; 16 | addChildren(target); 17 | addChildren(value); 18 | } 19 | 20 | @NotNull 21 | @Override 22 | public String toString() { 23 | return "(" + target + " = " + value + ")"; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/Exec.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | public class Exec extends Node { 6 | 7 | public Node body; 8 | public Node globals; 9 | public Node locals; 10 | 11 | public Exec(Node body, Node globals, Node locals, String file, int start, int end, int line, int col) { 12 | super(NodeType.EXEC, file, start, end, line, col); 13 | this.body = body; 14 | this.globals = globals; 15 | this.locals = locals; 16 | addChildren(body, globals, locals); 17 | } 18 | 19 | @NotNull 20 | @Override 21 | public String toString() { 22 | return ""; 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/Slice.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | public class Slice extends Node { 6 | 7 | public Node lower; 8 | public Node step; 9 | public Node upper; 10 | 11 | public Slice(Node lower, Node step, Node upper, String file, int start, int end, int line, int col) { 12 | super(NodeType.SLICE, file, start, end, line, col); 13 | this.lower = lower; 14 | this.step = step; 15 | this.upper = upper; 16 | addChildren(lower, step, upper); 17 | } 18 | 19 | @NotNull 20 | @Override 21 | public String toString() { 22 | return ""; 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/Attribute.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | public class Attribute extends Node { 6 | 7 | @NotNull 8 | public Node target; 9 | @NotNull 10 | public Name attr; 11 | 12 | public Attribute(@NotNull Node target, @NotNull Name attr, String file, int start, int end, int line, int col) { 13 | super(NodeType.ATTRIBUTE, file, start, end, line, col); 14 | this.target = target; 15 | this.attr = attr; 16 | addChildren(target, attr); 17 | } 18 | 19 | @NotNull 20 | @Override 21 | public String toString() { 22 | return ""; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/branch.test/test1.py: -------------------------------------------------------------------------------- 1 | # test if branches 2 | 3 | 4 | def test1(x): 5 | a = "hi" 6 | if x > 1: 7 | a = 3 8 | print a 9 | 10 | 11 | def test2(x): 12 | a = "hi" 13 | if x > 1: 14 | a = 3 15 | else: 16 | a = True 17 | print a 18 | 19 | 20 | def test3(x): 21 | a = "hi" 22 | if x > 1: 23 | a = 3 24 | else: 25 | if x < 10: 26 | a = True 27 | else: 28 | a = "hi" 29 | print a 30 | 31 | 32 | def test4(x): 33 | a = "hi" 34 | b = "foo" 35 | if x > 1: 36 | a = 3 37 | b = 4 38 | else: 39 | if x < 10: 40 | b = True 41 | else: 42 | a = "hi" 43 | b = False 44 | print a, b 45 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/IfExp.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | public class IfExp extends Node { 6 | 7 | public Node test; 8 | public Node body; 9 | public Node orelse; 10 | 11 | public IfExp(Node test, Node body, Node orelse, String file, int start, int end, int line, int col) { 12 | super(NodeType.IFEXP, file, start, end, line, col); 13 | this.test = test; 14 | this.body = body; 15 | this.orelse = orelse; 16 | addChildren(test, body, orelse); 17 | } 18 | 19 | @NotNull 20 | @Override 21 | public String toString() { 22 | return ""; 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/While.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | public class While extends Node { 6 | 7 | public Node test; 8 | public Node body; 9 | public Node orelse; 10 | 11 | public While(Node test, Node body, Node orelse, String file, int start, int end, int line, int col) { 12 | super(NodeType.WHILE, file, start, end, line, col); 13 | this.test = test; 14 | this.body = body; 15 | this.orelse = orelse; 16 | addChildren(test, body, orelse); 17 | } 18 | 19 | @NotNull 20 | @Override 21 | public String toString() { 22 | return ""; 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /tests/constructor.test/test1.py: -------------------------------------------------------------------------------- 1 | # Test constructor __init__ 2 | 3 | 4 | class TestInit1: 5 | def test(self): 6 | x = self.my_field 7 | 8 | def test2(self): 9 | y = self.my_field 10 | 11 | def __init__(self, x): 12 | self.my_field = x 13 | 14 | # with invocation 15 | y = TestInit1(5) 16 | z = TestInit1(6) 17 | y.my_field = z.my_field 18 | 19 | 20 | # without invocation 21 | class TestInit2: 22 | def test(self): 23 | x = self.my_field 24 | 25 | def __init__(self, x): 26 | self.my_field = x 27 | 28 | def test2(self): 29 | y = self.my_field 30 | 31 | 32 | # without invocation and other methods 33 | class TestInit3: 34 | def __init__(self): 35 | self.my_field = 3 36 | print self.my_field 37 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/If.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | public class If extends Node { 6 | 7 | @NotNull 8 | public Node test; 9 | public Node body; 10 | public Node orelse; 11 | 12 | public If(@NotNull Node test, Node body, Node orelse, String file, int start, int end, int line, int col) { 13 | super(NodeType.IF, file, start, end, line, col); 14 | this.test = test; 15 | this.body = body; 16 | this.orelse = orelse; 17 | addChildren(test, body, orelse); 18 | } 19 | 20 | @NotNull 21 | @Override 22 | public String toString() { 23 | return ""; 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/SetComp.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.util.List; 6 | 7 | public class SetComp extends Node { 8 | 9 | public Node elt; 10 | public List generators; 11 | 12 | public SetComp(Node elt, List generators, String file, int start, int end, int line, int col) { 13 | super(NodeType.SETCOMP, file, start, end, line, col); 14 | this.elt = elt; 15 | this.generators = generators; 16 | addChildren(elt); 17 | addChildren(generators); 18 | } 19 | 20 | @NotNull 21 | @Override 22 | public String toString() { 23 | return ""; 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/ListComp.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.util.List; 6 | 7 | public class ListComp extends Node { 8 | 9 | public Node elt; 10 | public List generators; 11 | 12 | public ListComp(Node elt, List generators, String file, int start, int end, int line, int col) { 13 | super(NodeType.LISTCOMP, file, start, end, line, col); 14 | this.elt = elt; 15 | this.generators = generators; 16 | addChildren(elt); 17 | addChildren(generators); 18 | } 19 | 20 | @NotNull 21 | @Override 22 | public String toString() { 23 | return ""; 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/BinOp.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | public class BinOp extends Node { 6 | 7 | @NotNull 8 | public Node left; 9 | @NotNull 10 | public Node right; 11 | @NotNull 12 | public Op op; 13 | 14 | public BinOp(@NotNull Op op, @NotNull Node left, @NotNull Node right, String file, int start, int end, int line, int col) { 15 | super(NodeType.BINOP, file, start, end, line, col); 16 | this.left = left; 17 | this.right = right; 18 | this.op = op; 19 | addChildren(left, right); 20 | } 21 | 22 | @NotNull 23 | @Override 24 | public String toString() { 25 | return "(" + left + " " + op + " " + right + ")"; 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/GeneratorExp.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.util.List; 6 | 7 | public class GeneratorExp extends Node { 8 | 9 | public Node elt; 10 | public List generators; 11 | 12 | public GeneratorExp(Node elt, List generators, String file, int start, int end, int line, int col) { 13 | super(NodeType.GENERATOREXP, file, start, end, line, col); 14 | this.elt = elt; 15 | this.generators = generators; 16 | addChildren(elt); 17 | addChildren(generators); 18 | } 19 | 20 | @NotNull 21 | @Override 22 | public String toString() { 23 | return ""; 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/Raise.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | public class Raise extends Node { 6 | 7 | public Node exceptionType; 8 | public Node inst; 9 | public Node traceback; 10 | 11 | public Raise(Node exceptionType, Node inst, Node traceback, String file, int start, int end, int line, int col) { 12 | super(NodeType.RAISE, file, start, end, line, col); 13 | this.exceptionType = exceptionType; 14 | this.inst = inst; 15 | this.traceback = traceback; 16 | addChildren(exceptionType, inst, traceback); 17 | } 18 | 19 | @NotNull 20 | @Override 21 | public String toString() { 22 | return ""; 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/Subscript.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import org.jetbrains.annotations.Nullable; 5 | 6 | public class Subscript extends Node { 7 | 8 | @NotNull 9 | public Node value; 10 | @Nullable 11 | public Node slice; // an NIndex or NSlice 12 | 13 | public Subscript(@NotNull Node value, @Nullable Node slice, String file, int start, int end, int line, int col) { 14 | super(NodeType.SUBSCRIPT, file, start, end, line, col); 15 | this.value = value; 16 | this.slice = slice; 17 | addChildren(value, slice); 18 | } 19 | 20 | @NotNull 21 | @Override 22 | public String toString() { 23 | return ""; 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/test/java/org/yinwang/pysonar/TestRefs.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.fail; 6 | 7 | import java.util.List; 8 | 9 | public class TestRefs 10 | { 11 | @Test 12 | public void testRefs() 13 | { 14 | List failed = TestInference.testAll("tests", false); 15 | if (failed != null) 16 | { 17 | String msg = "Some tests failed. "; 18 | msg += "\n----------------------------- FAILED TESTS ---------------------------"; 19 | for (String fail : failed) 20 | { 21 | msg += "\n - " + fail; 22 | } 23 | msg += "\n----------------------------------------------------------------------"; 24 | fail(msg); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/PyFloat.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | public class PyFloat extends Node { 6 | 7 | public double value; 8 | 9 | public PyFloat(String s, String file, int start, int end, int line, int col) { 10 | super(NodeType.PYFLOAT, file, start, end, line, col); 11 | s = s.replaceAll("_", ""); 12 | if (s.equals("inf")) { 13 | this.value = Double.POSITIVE_INFINITY; 14 | } else if (s.equals("-inf")) { 15 | this.value = Double.NEGATIVE_INFINITY; 16 | } else { 17 | this.value = Double.parseDouble(s); 18 | } 19 | } 20 | 21 | @NotNull 22 | @Override 23 | public String toString() { 24 | return "(float:" + value + ")"; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/Diagnostic.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | 6 | public class Diagnostic { 7 | public enum Category { 8 | INFO, WARNING, ERROR 9 | } 10 | 11 | 12 | public String file; 13 | public Category category; 14 | public int start; 15 | public int end; 16 | public String msg; 17 | 18 | 19 | public Diagnostic(String file, Category category, int start, int end, String msg) { 20 | this.category = category; 21 | this.file = file; 22 | this.start = start; 23 | this.end = end; 24 | this.msg = msg; 25 | } 26 | 27 | 28 | @NotNull 29 | @Override 30 | public String toString() { 31 | return ""; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/DictComp.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.util.List; 6 | 7 | public class DictComp extends Node { 8 | 9 | public Node key; 10 | public Node value; 11 | public List generators; 12 | 13 | public DictComp(Node key, Node value, List generators, String file, int start, int end, int line, int col) { 14 | super(NodeType.DICTCOMP, file, start, end, line, col); 15 | this.key = key; 16 | this.value = value; 17 | this.generators = generators; 18 | addChildren(key); 19 | addChildren(generators); 20 | } 21 | 22 | @NotNull 23 | @Override 24 | public String toString() { 25 | return ""; 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/With.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.util.List; 6 | 7 | public class With extends Node { 8 | 9 | @NotNull 10 | public List items; 11 | public Block body; 12 | public boolean isAsync = false; 13 | 14 | public With(@NotNull List items, Block body, String file, boolean isAsync, int start, int end, int line, int col) { 15 | super(NodeType.WITH, file, start, end, line, col); 16 | this.items = items; 17 | this.body = body; 18 | this.isAsync = isAsync; 19 | addChildren(items); 20 | addChildren(body); 21 | } 22 | 23 | @NotNull 24 | @Override 25 | public String toString() { 26 | return ""; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/Comprehension.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.util.List; 6 | 7 | public class Comprehension extends Node { 8 | 9 | public Node target; 10 | public Node iter; 11 | public List ifs; 12 | 13 | public Comprehension(Node target, Node iter, List ifs, String file, int start, int end, int line, int col) { 14 | super(NodeType.COMPREHENSION, file, start, end, line, col); 15 | this.target = target; 16 | this.iter = iter; 17 | this.ifs = ifs; 18 | addChildren(target, iter); 19 | addChildren(ifs); 20 | } 21 | 22 | @NotNull 23 | @Override 24 | public String toString() { 25 | return ""; 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/Handler.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.util.List; 6 | 7 | public class Handler extends Node { 8 | 9 | public List exceptions; 10 | public Node binder; 11 | public Block body; 12 | 13 | public Handler(List exceptions, Node binder, Block body, String file, int start, int end, int line, int col) { 14 | super(NodeType.HANDLER, file, start, end, line, col); 15 | this.binder = binder; 16 | this.exceptions = exceptions; 17 | this.body = body; 18 | addChildren(binder, body); 19 | addChildren(exceptions); 20 | } 21 | 22 | @NotNull 23 | @Override 24 | public String toString() { 25 | return "(handler:" + start + ":" + exceptions + ":" + binder + ")"; 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/Keyword.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | /** 6 | * Represents a keyword argument (name=value) in a function call. 7 | */ 8 | public class Keyword extends Node { 9 | 10 | public String arg; 11 | @NotNull 12 | public Node value; 13 | 14 | public Keyword(String arg, @NotNull Node value, String file, int start, int end, int line, int col) { 15 | super(NodeType.KEYWORD, file, start, end, line, col); 16 | this.arg = arg; 17 | this.value = value; 18 | addChildren(value); 19 | } 20 | 21 | @NotNull 22 | @Override 23 | public String toString() { 24 | return "(keyword:" + arg + ":" + value + ")"; 25 | } 26 | 27 | @NotNull 28 | @Override 29 | public String toDisplay() { 30 | return arg; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /tests/union-inside-tuple.test/refs.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "ref": { 4 | "name": "x", 5 | "file": "test1.py", 6 | "start": 124, 7 | "end": 125, 8 | "line": 9, 9 | "col": 8 10 | }, 11 | "dests": [ 12 | { 13 | "name": "x", 14 | "file": "test1.py", 15 | "start": 31, 16 | "end": 32, 17 | "line": 3, 18 | "col": 5, 19 | "type": "int -> ({int | str}, bool)" 20 | } 21 | ] 22 | }, 23 | { 24 | "ref": { 25 | "name": "q", 26 | "file": "test1.py", 27 | "start": 44, 28 | "end": 45, 29 | "line": 4, 30 | "col": 8 31 | }, 32 | "dests": [ 33 | { 34 | "name": "q", 35 | "file": "test1.py", 36 | "start": 33, 37 | "end": 34, 38 | "line": 3, 39 | "col": 7, 40 | "type": "int" 41 | } 42 | ] 43 | } 44 | ] -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/For.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | public class For extends Node { 6 | 7 | public Node target; 8 | public Node iter; 9 | public Block body; 10 | public Block orelse; 11 | public boolean isAsync = false; 12 | 13 | public For(Node target, Node iter, Block body, Block orelse, boolean isAsync, 14 | String file, int start, int end, int line, int col) { 15 | super(NodeType.FOR, file, start, end, line, col); 16 | this.target = target; 17 | this.iter = iter; 18 | this.body = body; 19 | this.orelse = orelse; 20 | this.isAsync = isAsync; 21 | addChildren(target, iter, body, orelse); 22 | } 23 | 24 | @NotNull 25 | @Override 26 | public String toString() { 27 | return ""; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/Try.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.util.List; 6 | 7 | public class Try extends Node { 8 | 9 | public List handlers; 10 | public Block body; 11 | public Block orelse; 12 | public Block finalbody; 13 | 14 | public Try(List handlers, Block body, Block orelse, Block finalbody, 15 | String file, int start, int end, int line, int col) { 16 | super(NodeType.TRY, file, start, end, line, col); 17 | this.handlers = handlers; 18 | this.body = body; 19 | this.orelse = orelse; 20 | this.finalbody = finalbody; 21 | addChildren(handlers); 22 | addChildren(body, orelse); 23 | } 24 | 25 | @NotNull 26 | @Override 27 | public String toString() { 28 | return ""; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/resources/org/yinwang/pysonar/javascript/highlight.js: -------------------------------------------------------------------------------- 1 | var highlighted; 2 | 3 | function highlight(xid) 4 | { 5 | var elms = document.querySelectorAll('[xid="' + xid + '"]'); 6 | for (k in elms) { 7 | v = elms[k] 8 | v.className = "active"; 9 | } 10 | highlighted = xid; 11 | } 12 | 13 | function clearHighlight() { 14 | var elms = document.querySelectorAll('[xid="' + highlighted + '"]'); 15 | for (k in elms) { 16 | v = elms[k] 17 | v.className = ""; 18 | } 19 | } 20 | 21 | window.onload = 22 | function (e) { 23 | var tags = document.getElementsByTagName("A") 24 | for (var i = 0; i < tags.length; i++) { 25 | tags[i].onmouseover = 26 | function (e) { 27 | clearHighlight(); 28 | var xid = e.toElement.getAttribute('xid'); 29 | highlight(xid); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/Withitem.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import org.jetbrains.annotations.Nullable; 5 | 6 | /** 7 | * A name alias. Used for the components of import and import-from statements. 8 | */ 9 | public class Withitem extends Node { 10 | 11 | @Nullable 12 | public Node optional_vars; 13 | @NotNull 14 | public Node context_expr; 15 | 16 | public Withitem(@NotNull Node context_expr, @Nullable Node optional_vars, String file, int start, int end, int line, int col) { 17 | super(NodeType.WITHITEM, file, start, end, line, col); 18 | this.context_expr = context_expr; 19 | this.optional_vars = optional_vars; 20 | addChildren(context_expr, optional_vars); 21 | } 22 | 23 | @NotNull 24 | @Override 25 | public String toString() { 26 | return "(withitem:" + context_expr + " as " + optional_vars + ")"; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/Tuple.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.util.List; 6 | 7 | public class Tuple extends Sequence { 8 | 9 | public Tuple(List elts, String file, int start, int end, int line, int col) { 10 | super(NodeType.TUPLE, elts, file, start, end, line, col); 11 | } 12 | 13 | @NotNull 14 | @Override 15 | public String toString() { 16 | return ""; 17 | } 18 | 19 | @NotNull 20 | @Override 21 | public String toDisplay() { 22 | StringBuilder sb = new StringBuilder(); 23 | sb.append("("); 24 | 25 | int idx = 0; 26 | for (Node n : elts) { 27 | if (idx != 0) { 28 | sb.append(", "); 29 | } 30 | idx++; 31 | sb.append(n.toDisplay()); 32 | } 33 | 34 | sb.append(")"); 35 | return sb.toString(); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/resources/org/yinwang/pysonar/css/demo.css: -------------------------------------------------------------------------------- 1 | body { color: #666666; } 2 | a { 3 | text-decoration: none; color: #5AA2A7; 4 | border: solid 1px rgba(255,255,255,0); 5 | } 6 | a.active { 7 | background: -webkit-linear-gradient(top,rgba(255, 255, 200, 0.35) 0,rgba(255, 255, 200, 0.55) 100%); 8 | border: solid 1px #E5E600; 9 | } 10 | table, th, td { border: 1px solid lightgrey; padding: 5px; corner: rounded; } 11 | .builtin {color: #B17E41;} 12 | .comment, .block-comment {color: #aaaaaa; font-style: italic;} 13 | .constant {color: #888888;} 14 | .decorator {color: #778899;} 15 | .doc-string {color: #aaaaaa;} 16 | .error {border-bottom: 1px solid red;} 17 | .field-name {color: #2e8b57;} 18 | .function {color: #4682b4;} 19 | .identifier {color: #8b7765;} 20 | .info {border-bottom: 1px dotted RoyalBlue;} 21 | .keyword {color: #0000cd;} 22 | .lineno {color: #cccccc;} 23 | .number {color: #483d8b;} 24 | .parameter {color: #777777;} 25 | .string {color: #999999;} 26 | .type-name {color: #4682b4;} 27 | .warning {border-bottom: 1px solid orange; padding-bottom: 1px} 28 | -------------------------------------------------------------------------------- /tests/references-multi.test/refs.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "ref": { 4 | "name": "x", 5 | "file": "multi.py", 6 | "start": 14, 7 | "end": 15, 8 | "line": 3, 9 | "col": 4 10 | }, 11 | "dests": [ 12 | { 13 | "name": "x", 14 | "file": "multi.py", 15 | "start": 0, 16 | "end": 1, 17 | "line": 1, 18 | "col": 1, 19 | "type": "int" 20 | } 21 | ] 22 | }, 23 | { 24 | "ref": { 25 | "name": "w", 26 | "file": "multi.py", 27 | "start": 53, 28 | "end": 54, 29 | "line": 8, 30 | "col": 7 31 | }, 32 | "dests": [ 33 | { 34 | "name": "w", 35 | "file": "multi.py", 36 | "start": 21, 37 | "end": 22, 38 | "line": 4, 39 | "col": 5, 40 | "type": "int" 41 | }, 42 | { 43 | "name": "w", 44 | "file": "multi.py", 45 | "start": 37, 46 | "end": 38, 47 | "line": 6, 48 | "col": 5, 49 | "type": "str" 50 | } 51 | ] 52 | } 53 | ] -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/Call.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import org.jetbrains.annotations.Nullable; 5 | 6 | import java.util.List; 7 | 8 | public class Call extends Node { 9 | 10 | public Node func; 11 | public List args; 12 | @Nullable 13 | public List keywords; 14 | public Node kwargs; 15 | public Node starargs; 16 | 17 | public Call(Node func, List args, @Nullable List keywords, 18 | Node kwargs, Node starargs, String file, int start, int end, int line, int col) { 19 | super(NodeType.CALL, file, start, end, line, col); 20 | this.func = func; 21 | this.args = args; 22 | this.keywords = keywords; 23 | this.kwargs = kwargs; 24 | this.starargs = starargs; 25 | addChildren(func, kwargs, starargs); 26 | addChildren(args); 27 | addChildren(keywords); 28 | } 29 | 30 | @NotNull 31 | @Override 32 | public String toString() { 33 | return "(call:" + func + ":" + args + ":" + start + ")"; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/TypeStack.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | 9 | public class TypeStack { 10 | 11 | class Pair { 12 | public Object first; 13 | public Object second; 14 | 15 | 16 | public Pair(Object first, Object second) { 17 | this.first = first; 18 | this.second = second; 19 | } 20 | } 21 | 22 | 23 | @NotNull 24 | private List stack = new ArrayList<>(); 25 | 26 | 27 | public void push(Object first, Object second) { 28 | stack.add(new Pair(first, second)); 29 | } 30 | 31 | 32 | public void pop(Object first, Object second) { 33 | stack.remove(stack.size() - 1); 34 | } 35 | 36 | 37 | public boolean contains(Object first, Object second) { 38 | for (Pair p : stack) { 39 | if (p.first == first && p.second == second || 40 | p.first == second && p.second == first) 41 | { 42 | return true; 43 | } 44 | } 45 | return false; 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/NodeType.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | public enum NodeType { 4 | ALIAS, 5 | ASSERT, 6 | ASSIGN, 7 | ATTRIBUTE, 8 | AWAIT, 9 | BINOP, 10 | BLOCK, 11 | BREAK, 12 | BYTES, 13 | CALL, 14 | CLASSDEF, 15 | COMPREHENSION, 16 | CONTINUE, 17 | DELETE, 18 | DICT, 19 | DICTCOMP, 20 | DUMMY, 21 | ELLIPSIS, 22 | EXEC, 23 | EXPR, 24 | EXTSLICE, 25 | FOR, 26 | FUNCTIONDEF, 27 | GENERATOREXP, 28 | GLOBAL, 29 | HANDLER, 30 | IF, 31 | IFEXP, 32 | IMPORT, 33 | IMPORTFROM, 34 | INDEX, 35 | KEYWORD, 36 | LISTCOMP, 37 | MODULE, 38 | NAME, 39 | NAMETYPE, 40 | NODE, 41 | OP, 42 | PASS, 43 | PRINT, 44 | PYCOMPLEX, 45 | PYFLOAT, 46 | PYINT, 47 | PYLIST, 48 | PYSET, 49 | RAISE, 50 | REPR, 51 | RETURN, 52 | SEQUENCE, 53 | SETCOMP, 54 | SLICE, 55 | STARRED, 56 | STR, 57 | SUBSCRIPT, 58 | TRY, 59 | TUPLE, 60 | UNARYOP, 61 | UNSUPPORTED, 62 | URL, 63 | WHILE, 64 | WITH, 65 | WITHITEM, 66 | YIELD, 67 | YIELDFROM, 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/Stats.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | 7 | public class Stats { 8 | Map contents = new HashMap<>(); 9 | 10 | 11 | public void putInt(String key, long value) { 12 | contents.put(key, value); 13 | } 14 | 15 | 16 | public void inc(String key, long x) { 17 | Long old = getInt(key); 18 | 19 | if (old == null) { 20 | contents.put(key, x); 21 | } else { 22 | contents.put(key, old + x); 23 | } 24 | } 25 | 26 | 27 | public void inc(String key) { 28 | inc(key, 1); 29 | } 30 | 31 | 32 | public Long getInt(String key) { 33 | Long ret = (Long) contents.get(key); 34 | if (ret == null) { 35 | return 0L; 36 | } else { 37 | return ret; 38 | } 39 | } 40 | 41 | 42 | public String print() { 43 | StringBuilder sb = new StringBuilder(); 44 | 45 | for (Map.Entry e : contents.entrySet()) { 46 | sb.append("\n- ").append(e.getKey()).append(": ").append(e.getValue()); 47 | } 48 | 49 | return sb.toString(); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/ClassDef.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import org.yinwang.pysonar.Binding; 5 | import org.yinwang.pysonar.Builtins; 6 | import org.yinwang.pysonar.State; 7 | import org.yinwang.pysonar.types.Type; 8 | 9 | import java.util.List; 10 | 11 | public class ClassDef extends Node { 12 | 13 | @NotNull 14 | public Name name; 15 | public List bases; 16 | public Node body; 17 | 18 | public ClassDef(@NotNull Name name, List bases, Node body, String file, int start, int end, int line, int col) { 19 | super(NodeType.CLASSDEF, file, start, end, line, col); 20 | this.name = name; 21 | this.bases = bases; 22 | this.body = body; 23 | addChildren(name, this.body); 24 | addChildren(bases); 25 | } 26 | 27 | public void addSpecialAttribute(@NotNull State s, String name, Type proptype) { 28 | Binding b = new Binding(name, Builtins.newTutUrl("classes.html"), proptype, Binding.Kind.ATTRIBUTE); 29 | s.update(name, b); 30 | b.markSynthetic(); 31 | b.markStatic(); 32 | 33 | } 34 | 35 | @NotNull 36 | @Override 37 | public String toString() { 38 | return "(class:" + name.id + ":" + start + ")"; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/Name.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | public class Name extends Node { 6 | 7 | @NotNull 8 | public final String id; // identifier 9 | public NameType type; 10 | 11 | public Name(String id) { 12 | // generated name 13 | this(id, null, -1, -1, -1, -1); 14 | } 15 | 16 | public Name(@NotNull String id, String file, int start, int end, int line, int col) { 17 | super(NodeType.NAME, file, start, end, line, col); 18 | this.id = id; 19 | this.name = id; 20 | this.type = NameType.LOCAL; 21 | } 22 | 23 | public Name(@NotNull String id, NameType type, String file, int start, int end, int line, int col) { 24 | super(NodeType.NAME, file, start, end, line, col); 25 | this.id = id; 26 | this.type = type; 27 | } 28 | 29 | /** 30 | * Returns {@code true} if this name node is the {@code attr} child 31 | * (i.e. the attribute being accessed) of an {@link Attribute} node. 32 | */ 33 | public boolean isAttribute() { 34 | return parent instanceof Attribute 35 | && ((Attribute) parent).attr == this; 36 | } 37 | 38 | @NotNull 39 | @Override 40 | public String toString() { 41 | return "(" + id + ":" + line + ":" + col + ")"; 42 | } 43 | 44 | @NotNull 45 | @Override 46 | public String toDisplay() { 47 | return id; 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/PyInt.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.math.BigInteger; 6 | 7 | public class PyInt extends Node { 8 | 9 | public BigInteger value; 10 | 11 | public PyInt(String s, String file, int start, int end, int line, int col) { 12 | super(NodeType.PYINT, file, start, end, line, col); 13 | 14 | s = s.replaceAll("_", ""); 15 | int sign = 1; 16 | 17 | if (s.startsWith("+")) { 18 | s = s.substring(1); 19 | } else if (s.startsWith("-")) { 20 | s = s.substring(1); 21 | sign = -1; 22 | } 23 | 24 | int base; 25 | if (s.startsWith("0b")) { 26 | base = 2; 27 | s = s.substring(2); 28 | } else if (s.startsWith("0x")) { 29 | base = 16; 30 | s = s.substring(2); 31 | } else if (s.startsWith("x")) { 32 | base = 16; 33 | s = s.substring(1); 34 | } else if (s.startsWith("0o")) { 35 | base = 8; 36 | s = s.substring(2); 37 | } else if (s.startsWith("0") && s.length() >= 2) { 38 | base = 8; 39 | s = s.substring(1); 40 | } else { 41 | base = 10; 42 | } 43 | 44 | value = new BigInteger(s, base); 45 | if (sign == -1) { 46 | value = value.negate(); 47 | } 48 | } 49 | 50 | @NotNull 51 | @Override 52 | public String toString() { 53 | return "(int:" + value + ")"; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/types/InstanceType.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.types; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import org.yinwang.pysonar.State; 5 | import org.yinwang.pysonar.ast.Node; 6 | import org.yinwang.pysonar.visitor.TypeInferencer; 7 | 8 | import java.util.List; 9 | 10 | 11 | public class InstanceType extends Type { 12 | 13 | public Type classType; 14 | 15 | 16 | public InstanceType(@NotNull Type c) { 17 | table.setStateType(State.StateType.INSTANCE); 18 | table.addSuper(c.table); 19 | table.setPath(c.table.path); 20 | classType = c; 21 | } 22 | 23 | public InstanceType(@NotNull Type c, List args, TypeInferencer inferencer, Node call) 24 | { 25 | this(c); 26 | 27 | // call constructor 28 | Type initFunc = table.lookupAttrType("__init__"); 29 | if (initFunc != null && 30 | initFunc instanceof FunType && 31 | ((FunType) initFunc).func != null) 32 | { 33 | inferencer.apply((FunType) initFunc, this, args, null, null, null, call); 34 | } 35 | 36 | if (classType instanceof ClassType) 37 | { 38 | ((ClassType) classType).setInstance(this); 39 | } 40 | } 41 | 42 | 43 | @Override 44 | public boolean typeEquals(Object other) { 45 | if (other instanceof InstanceType) { 46 | return classType.typeEquals(((InstanceType) other).classType); 47 | } 48 | return false; 49 | } 50 | 51 | 52 | @Override 53 | public int hashCode() { 54 | return classType.hashCode(); 55 | } 56 | 57 | 58 | @Override 59 | protected String printType(CyclicTypeRecorder ctr) { 60 | return ((ClassType) classType).name; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/types/Types.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.types; 2 | 3 | public class Types { 4 | public static ClassType ObjectClass = new ClassType("object", null, null); 5 | public static Type ObjectInstance = ObjectClass.getInstance(); 6 | 7 | public static ClassType TypeClass = new ClassType("type", null, null); 8 | public static Type TypeInstance = TypeClass.getInstance(); 9 | 10 | public static ClassType BoolClass = new ClassType("bool", null, ObjectClass); 11 | public static Type BoolInstance = BoolClass.getInstance(); 12 | 13 | public static ClassType IntClass = new ClassType("int", null, ObjectClass); 14 | public static Type IntInstance = IntClass.getInstance(); 15 | 16 | public static ClassType LongClass = new ClassType("long", null, ObjectClass); 17 | public static Type LongInstance = LongClass.getInstance(); 18 | 19 | public static ClassType StrClass = new ClassType("str", null, ObjectClass); 20 | public static Type StrInstance = StrClass.getInstance(); 21 | 22 | public static ClassType FloatClass = new ClassType("float", null, ObjectClass); 23 | public static Type FloatInstance = FloatClass.getInstance(); 24 | 25 | public static ClassType ComplexClass = new ClassType("complex", null, ObjectClass); 26 | public static Type ComplexInstance = ComplexClass.getInstance(); 27 | 28 | public static ClassType NoneClass = new ClassType("None", null, ObjectClass); 29 | public static Type NoneInstance = NoneClass.getInstance(); 30 | 31 | // Synthetic types used only for inference purposes 32 | // They don't exist in Python 33 | public static Type UNKNOWN = new InstanceType(new ClassType("?", null, ObjectClass)); 34 | public static Type CONT = new InstanceType(new ClassType("None", null, null)); 35 | 36 | public static ClassType BaseDict = new ClassType("dict", null, ObjectClass); 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/types/ModuleType.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.types; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import org.jetbrains.annotations.Nullable; 5 | import org.yinwang.pysonar.Analyzer; 6 | import org.yinwang.pysonar.State; 7 | import org.yinwang.pysonar.$; 8 | 9 | public class ModuleType extends Type { 10 | 11 | @NotNull 12 | public String name; 13 | @Nullable 14 | public String qname; 15 | 16 | 17 | public ModuleType(@NotNull String name, @Nullable String file, @NotNull State parent) { 18 | this.name = name; 19 | this.file = file; // null for builtin modules 20 | if (file != null) { 21 | // This will return null iff specified file is not prefixed by 22 | // any path in the module search path -- i.e., the caller asked 23 | // the analyzer to load a file not in the search path. 24 | qname = $.moduleQname(file); 25 | } 26 | if (qname == null) { 27 | qname = name; 28 | } 29 | setTable(new State(parent, State.StateType.MODULE)); 30 | table.setPath(qname); 31 | table.setType(this); 32 | 33 | // null during bootstrapping of built-in types 34 | if (Analyzer.self.builtins != null) { 35 | table.addSuper(Analyzer.self.builtins.BaseModule.table); 36 | } 37 | } 38 | 39 | 40 | public void setName(String name) { 41 | this.name = name; 42 | } 43 | 44 | 45 | @Override 46 | public int hashCode() { 47 | return "ModuleType".hashCode(); 48 | } 49 | 50 | 51 | @Override 52 | public boolean typeEquals(Object other) { 53 | if (other instanceof ModuleType) { 54 | ModuleType co = (ModuleType) other; 55 | if (file != null) { 56 | return file.equals(co.file); 57 | } 58 | } 59 | return this == other; 60 | } 61 | 62 | 63 | @Override 64 | protected String printType(CyclicTypeRecorder ctr) { 65 | return name; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/Options.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar; 2 | 3 | import java.util.ArrayList; 4 | import java.util.LinkedHashMap; 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | public class Options { 9 | 10 | private Map optionsMap = new LinkedHashMap<>(); 11 | 12 | 13 | private List args = new ArrayList<>(); 14 | 15 | 16 | public Options(String[] args) { 17 | for (int i = 0; i < args.length; i++) { 18 | String key = args[i]; 19 | if (key.startsWith("--")) { 20 | if (i + 1 >= args.length) { 21 | $.die("option needs a value: " + key); 22 | } else { 23 | key = key.substring(2); 24 | String value = args[i + 1]; 25 | if (!value.startsWith("-")) { 26 | optionsMap.put(key, value); 27 | i++; 28 | } 29 | } 30 | } else if (key.startsWith("-")) { 31 | key = key.substring(1); 32 | optionsMap.put(key, true); 33 | } else { 34 | this.args.add(key); 35 | } 36 | } 37 | } 38 | 39 | 40 | public Object get(String key) { 41 | return optionsMap.get(key); 42 | } 43 | 44 | 45 | public boolean hasOption(String key) { 46 | Object v = optionsMap.get(key); 47 | if (v instanceof Boolean) { 48 | return (boolean) v; 49 | } else { 50 | return false; 51 | } 52 | } 53 | 54 | 55 | public void put(String key, Object value) { 56 | optionsMap.put(key, value); 57 | } 58 | 59 | 60 | public List getArgs() { 61 | return args; 62 | } 63 | 64 | 65 | public Map getOptionsMap() { 66 | return optionsMap; 67 | } 68 | 69 | 70 | public static void main(String[] args) { 71 | Options options = new Options(args); 72 | for (String key : options.optionsMap.keySet()) { 73 | System.out.println(key + " = " + options.get(key)); 74 | } 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/hash/MyHashSet.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.hash; 2 | 3 | import java.util.AbstractSet; 4 | import java.util.Collection; 5 | import java.util.Iterator; 6 | import java.util.Set; 7 | 8 | 9 | public class MyHashSet 10 | extends AbstractSet 11 | implements Set 12 | { 13 | private transient MyHashMap map; 14 | private static final Object PRESENT = new Object(); 15 | 16 | 17 | public MyHashSet(HashFunction hashFunction, EqualFunction equalFunction) { 18 | map = new MyHashMap<>(hashFunction, equalFunction); 19 | } 20 | 21 | 22 | public MyHashSet(Collection c, HashFunction hashFunction, EqualFunction equalFunction) { 23 | map = new MyHashMap<>(Math.max((int) (c.size() / .75f) + 1, 16), hashFunction, equalFunction); 24 | addAll(c); 25 | } 26 | 27 | 28 | public MyHashSet(int initialCapacity, float loadFactor, HashFunction hashFunction, EqualFunction equalFunction) { 29 | map = new MyHashMap<>(initialCapacity, loadFactor, hashFunction, equalFunction); 30 | } 31 | 32 | 33 | public MyHashSet(int initialCapacity, HashFunction hashFunction, EqualFunction equalFunction) { 34 | map = new MyHashMap<>(initialCapacity, hashFunction, equalFunction); 35 | } 36 | 37 | 38 | public MyHashSet() { 39 | map = new MyHashMap<>(new GenericHashFunction(), new GenericEqualFunction()); 40 | } 41 | 42 | 43 | @Override 44 | public Iterator iterator() { 45 | return map.keySet().iterator(); 46 | } 47 | 48 | 49 | @Override 50 | public int size() { 51 | return map.size(); 52 | } 53 | 54 | 55 | @Override 56 | public boolean isEmpty() { 57 | return map.isEmpty(); 58 | } 59 | 60 | 61 | @Override 62 | public boolean contains(Object o) { 63 | return map.containsKey(o); 64 | } 65 | 66 | 67 | @Override 68 | public boolean add(E e) { 69 | return map.put(e, PRESENT) == null; 70 | } 71 | 72 | 73 | @Override 74 | public boolean remove(Object o) { 75 | return map.remove(o) == PRESENT; 76 | } 77 | 78 | 79 | @Override 80 | public void clear() { 81 | map.clear(); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /tests/relative-import.test/refs.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "ref": { 4 | "name": "foo", 5 | "file": "baz/rel.py", 6 | "start": 7, 7 | "end": 10, 8 | "line": 0, 9 | "col": 0 10 | }, 11 | "dests": [ 12 | { 13 | "name": "foo", 14 | "file": "foo/__init__.py", 15 | "start": 0, 16 | "end": 0, 17 | "line": 0, 18 | "col": 0, 19 | "type": "foo" 20 | } 21 | ] 22 | }, 23 | { 24 | "ref": { 25 | "name": "bar", 26 | "file": "baz/rel.py", 27 | "start": 11, 28 | "end": 14, 29 | "line": 0, 30 | "col": 0 31 | }, 32 | "dests": [ 33 | { 34 | "name": "bar", 35 | "file": "foo/bar.py", 36 | "start": 0, 37 | "end": 0, 38 | "line": 0, 39 | "col": 0, 40 | "type": "bar" 41 | } 42 | ] 43 | }, 44 | { 45 | "ref": { 46 | "name": "f", 47 | "file": "baz/rel.py", 48 | "start": 0, 49 | "end": 1, 50 | "line": 0, 51 | "col": 0 52 | }, 53 | "dests": [ 54 | { 55 | "name": "f", 56 | "file": "foo/bar.py", 57 | "start": 4, 58 | "end": 5, 59 | "line": 1, 60 | "col": 5, 61 | "type": "int -> int" 62 | } 63 | ] 64 | }, 65 | { 66 | "ref": { 67 | "name": "f", 68 | "file": "baz/rel.py", 69 | "start": 29, 70 | "end": 30, 71 | "line": 3, 72 | "col": 5 73 | }, 74 | "dests": [ 75 | { 76 | "name": "f", 77 | "file": "foo/bar.py", 78 | "start": 4, 79 | "end": 5, 80 | "line": 1, 81 | "col": 5, 82 | "type": "int -> int" 83 | } 84 | ] 85 | }, 86 | { 87 | "ref": { 88 | "name": "y", 89 | "file": "baz/rel.py", 90 | "start": 41, 91 | "end": 42, 92 | "line": 4, 93 | "col": 7 94 | }, 95 | "dests": [ 96 | { 97 | "name": "y", 98 | "file": "baz/rel.py", 99 | "start": 25, 100 | "end": 26, 101 | "line": 3, 102 | "col": 1, 103 | "type": "int" 104 | } 105 | ] 106 | } 107 | ] -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/types/ClassType.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.types; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import org.jetbrains.annotations.Nullable; 5 | import org.yinwang.pysonar.State; 6 | import org.yinwang.pysonar.ast.Node; 7 | import org.yinwang.pysonar.visitor.TypeInferencer; 8 | 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | 12 | public class ClassType extends Type { 13 | 14 | public String name; 15 | public Type superclass; 16 | private InstanceType instance; 17 | 18 | public ClassType(@NotNull String name, @Nullable State parent) { 19 | this.name = name; 20 | this.setTable(new State(parent, State.StateType.CLASS)); 21 | table.setType(this); 22 | if (parent != null) { 23 | table.setPath(parent.extendPath(name)); 24 | } else { 25 | table.setPath(name); 26 | } 27 | } 28 | 29 | 30 | public ClassType(@NotNull String name, State parent, @Nullable Type superClass) { 31 | this(name, parent); 32 | if (superClass != null) { 33 | addSuper(superClass); 34 | } 35 | } 36 | 37 | 38 | public void setName(String name) { 39 | this.name = name; 40 | } 41 | 42 | 43 | public void addSuper(@NotNull Type superclass) { 44 | this.superclass = superclass; 45 | table.addSuper(superclass.table); 46 | } 47 | 48 | public InstanceType getInstance() { 49 | if (instance == null) { 50 | instance = new InstanceType(this); 51 | } 52 | return instance; 53 | } 54 | 55 | public InstanceType getInstance(List args, TypeInferencer inferencer, Node call) { 56 | if (instance == null) { 57 | List initArgs = args == null ? new ArrayList<>() : args; 58 | instance = new InstanceType(this, initArgs, inferencer, call); 59 | } 60 | return instance; 61 | } 62 | 63 | public void setInstance(InstanceType instance) { 64 | this.instance = instance; 65 | } 66 | 67 | @Override 68 | public boolean typeEquals(Object other) { 69 | return this == other; 70 | } 71 | 72 | @Override 73 | protected String printType(CyclicTypeRecorder ctr) { 74 | return "<" + name + ">"; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/demos/HtmlOutline.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.demos; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import org.jetbrains.annotations.Nullable; 5 | import org.yinwang.pysonar.Analyzer; 6 | import org.yinwang.pysonar.Outliner; 7 | import org.yinwang.pysonar.$; 8 | 9 | import java.util.List; 10 | 11 | 12 | class HtmlOutline { 13 | 14 | private Analyzer analyzer; 15 | @Nullable 16 | private StringBuilder buffer; 17 | 18 | 19 | public HtmlOutline(Analyzer idx) { 20 | this.analyzer = idx; 21 | } 22 | 23 | 24 | @NotNull 25 | public String generate(String path) { 26 | buffer = new StringBuilder(1024); 27 | List entries = generateOutline(analyzer, path); 28 | addOutline(entries); 29 | String html = buffer.toString(); 30 | buffer = null; 31 | return html; 32 | } 33 | 34 | 35 | @NotNull 36 | public List generateOutline(Analyzer analyzer, @NotNull String file) { 37 | return new Outliner().generate(analyzer, file); 38 | } 39 | 40 | 41 | private void addOutline(@NotNull List entries) { 42 | add("
    \n"); 43 | for (Outliner.Entry e : entries) { 44 | addEntry(e); 45 | } 46 | add("
\n"); 47 | } 48 | 49 | 50 | private void addEntry(@NotNull Outliner.Entry e) { 51 | add("
  • "); 52 | 53 | String style = null; 54 | switch (e.kind) { 55 | case FUNCTION: 56 | case METHOD: 57 | case CONSTRUCTOR: 58 | style = "function"; 59 | break; 60 | case CLASS: 61 | style = "type-name"; 62 | break; 63 | case PARAMETER: 64 | style = "parameter"; 65 | break; 66 | case VARIABLE: 67 | case SCOPE: 68 | style = "identifier"; 69 | break; 70 | } 71 | 72 | add(""); 75 | add(e.getName()); 76 | add(""); 77 | 78 | if (e.isBranch()) { 79 | addOutline(e.getChildren()); 80 | } 81 | add("
  • "); 82 | } 83 | 84 | 85 | private void add(String text) { 86 | buffer.append(text); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/types/DictType.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.types; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | public class DictType extends Type { 6 | 7 | public Type keyType; 8 | public Type valueType; 9 | 10 | public DictType(Type key0, Type val0) { 11 | keyType = key0; 12 | valueType = val0; 13 | table.addSuper(Types.BaseDict.table); 14 | table.setPath(Types.BaseDict.table.path); 15 | } 16 | 17 | public void add(@NotNull Type key, @NotNull Type val) { 18 | keyType = UnionType.union(keyType, key); 19 | valueType = UnionType.union(valueType, val); 20 | } 21 | 22 | @NotNull 23 | public TupleType toTupleType(int n) { 24 | TupleType ret = new TupleType(); 25 | for (int i = 0; i < n; i++) { 26 | ret.add(keyType); 27 | } 28 | return ret; 29 | } 30 | 31 | @Override 32 | public boolean typeEquals(Object other) { 33 | if (typeStack.contains(this, other)) { 34 | return true; 35 | } else if (other instanceof DictType) { 36 | typeStack.push(this, other); 37 | DictType co = (DictType) other; 38 | boolean result = co.keyType.typeEquals(keyType) && 39 | co.valueType.typeEquals(valueType); 40 | typeStack.pop(this, other); 41 | return result; 42 | } else { 43 | return false; 44 | } 45 | } 46 | 47 | @Override 48 | public int hashCode() { 49 | return "DictType".hashCode(); 50 | } 51 | 52 | public void setKeyType(Type keyType) 53 | { 54 | this.keyType = keyType; 55 | } 56 | 57 | public void setValueType(Type valueType) 58 | { 59 | this.valueType = valueType; 60 | } 61 | 62 | @Override 63 | protected String printType(@NotNull CyclicTypeRecorder ctr) { 64 | // StringBuilder sb = new StringBuilder(); 65 | // 66 | // Integer num = ctr.visit(this); 67 | // if (num != null) { 68 | // sb.append("#").append(num); 69 | // } else { 70 | // ctr.push(this); 71 | // sb.append("{"); 72 | // sb.append(keyType.printType(ctr)); 73 | // sb.append(" : "); 74 | // sb.append(valueType.printType(ctr)); 75 | // sb.append("}"); 76 | // ctr.pop(this); 77 | // } 78 | // 79 | // return sb.toString(); 80 | return "dict"; 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /tests/object-member.test/refs.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "ref": { 4 | "name": "A", 5 | "file": "test1.py", 6 | "start": 71, 7 | "end": 72, 8 | "line": 7, 9 | "col": 6 10 | }, 11 | "dests": [ 12 | { 13 | "name": "A", 14 | "file": "test1.py", 15 | "start": 52, 16 | "end": 53, 17 | "line": 4, 18 | "col": 7, 19 | "type": "" 20 | } 21 | ] 22 | }, 23 | { 24 | "ref": { 25 | "name": "a1", 26 | "file": "test1.py", 27 | "start": 75, 28 | "end": 77, 29 | "line": 8, 30 | "col": 1 31 | }, 32 | "dests": [ 33 | { 34 | "name": "a1", 35 | "file": "test1.py", 36 | "start": 66, 37 | "end": 68, 38 | "line": 7, 39 | "col": 1, 40 | "type": "A" 41 | } 42 | ] 43 | }, 44 | { 45 | "ref": { 46 | "name": "a1", 47 | "file": "test1.py", 48 | "start": 94, 49 | "end": 96, 50 | "line": 10, 51 | "col": 7 52 | }, 53 | "dests": [ 54 | { 55 | "name": "a1", 56 | "file": "test1.py", 57 | "start": 66, 58 | "end": 68, 59 | "line": 7, 60 | "col": 1, 61 | "type": "A" 62 | } 63 | ] 64 | }, 65 | { 66 | "ref": { 67 | "name": "x", 68 | "file": "test1.py", 69 | "start": 97, 70 | "end": 98, 71 | "line": 10, 72 | "col": 10 73 | }, 74 | "dests": [ 75 | { 76 | "name": "x", 77 | "file": "test1.py", 78 | "start": 59, 79 | "end": 60, 80 | "line": 5, 81 | "col": 5, 82 | "type": "int" 83 | } 84 | ] 85 | }, 86 | { 87 | "ref": { 88 | "name": "a1", 89 | "file": "test1.py", 90 | "start": 105, 91 | "end": 107, 92 | "line": 11, 93 | "col": 7 94 | }, 95 | "dests": [ 96 | { 97 | "name": "a1", 98 | "file": "test1.py", 99 | "start": 66, 100 | "end": 68, 101 | "line": 7, 102 | "col": 1, 103 | "type": "A" 104 | } 105 | ] 106 | }, 107 | { 108 | "ref": { 109 | "name": "y", 110 | "file": "test1.py", 111 | "start": 108, 112 | "end": 109, 113 | "line": 11, 114 | "col": 10 115 | }, 116 | "dests": [ 117 | { 118 | "name": "y", 119 | "file": "test1.py", 120 | "start": 78, 121 | "end": 79, 122 | "line": 8, 123 | "col": 4, 124 | "type": "str" 125 | } 126 | ] 127 | } 128 | ] -------------------------------------------------------------------------------- /tests/isinstance.test/refs.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "ref": { 4 | "name": "x", 5 | "file": "test1.py", 6 | "start": 86, 7 | "end": 87, 8 | "line": 10, 9 | "col": 15 10 | }, 11 | "dests": [ 12 | { 13 | "name": "x", 14 | "file": "test1.py", 15 | "start": 29, 16 | "end": 30, 17 | "line": 3, 18 | "col": 1, 19 | "type": "?" 20 | } 21 | ] 22 | }, 23 | { 24 | "ref": { 25 | "name": "foo", 26 | "file": "test1.py", 27 | "start": 89, 28 | "end": 92, 29 | "line": 10, 30 | "col": 18 31 | }, 32 | "dests": [ 33 | { 34 | "name": "foo", 35 | "file": "test1.py", 36 | "start": 48, 37 | "end": 51, 38 | "line": 6, 39 | "col": 5, 40 | "type": "() -> " 41 | } 42 | ] 43 | }, 44 | { 45 | "ref": { 46 | "name": "x", 47 | "file": "test1.py", 48 | "start": 105, 49 | "end": 106, 50 | "line": 11, 51 | "col": 9 52 | }, 53 | "dests": [ 54 | { 55 | "name": "x", 56 | "file": "test1.py", 57 | "start": 86, 58 | "end": 87, 59 | "line": 10, 60 | "col": 15, 61 | "type": "int" 62 | } 63 | ] 64 | }, 65 | { 66 | "ref": { 67 | "name": "x", 68 | "file": "test1.py", 69 | "start": 121, 70 | "end": 122, 71 | "line": 13, 72 | "col": 9 73 | }, 74 | "dests": [ 75 | { 76 | "name": "x", 77 | "file": "test1.py", 78 | "start": 29, 79 | "end": 30, 80 | "line": 3, 81 | "col": 1, 82 | "type": "?" 83 | } 84 | ] 85 | }, 86 | { 87 | "ref": { 88 | "name": "y", 89 | "file": "test1.py", 90 | "start": 130, 91 | "end": 131, 92 | "line": 15, 93 | "col": 7 94 | }, 95 | "dests": [ 96 | { 97 | "name": "y", 98 | "file": "test1.py", 99 | "start": 101, 100 | "end": 102, 101 | "line": 11, 102 | "col": 5, 103 | "type": "int" 104 | } 105 | ] 106 | }, 107 | { 108 | "ref": { 109 | "name": "z", 110 | "file": "test1.py", 111 | "start": 133, 112 | "end": 134, 113 | "line": 15, 114 | "col": 10 115 | }, 116 | "dests": [ 117 | { 118 | "name": "z", 119 | "file": "test1.py", 120 | "start": 117, 121 | "end": 118, 122 | "line": 13, 123 | "col": 5, 124 | "type": "?" 125 | } 126 | ] 127 | } 128 | ] -------------------------------------------------------------------------------- /tests/return.test/refs.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "ref": { 4 | "name": "f", 5 | "file": "test1.py", 6 | "start": 138, 7 | "end": 139, 8 | "line": 14, 9 | "col": 5 10 | }, 11 | "dests": [ 12 | { 13 | "name": "f", 14 | "file": "test1.py", 15 | "start": 21, 16 | "end": 22, 17 | "line": 5, 18 | "col": 5, 19 | "type": "(int, None) -> {bool | int}" 20 | } 21 | ] 22 | }, 23 | { 24 | "ref": { 25 | "name": "x", 26 | "file": "test1.py", 27 | "start": 42, 28 | "end": 43, 29 | "line": 6, 30 | "col": 8 31 | }, 32 | "dests": [ 33 | { 34 | "name": "x", 35 | "file": "test1.py", 36 | "start": 23, 37 | "end": 24, 38 | "line": 5, 39 | "col": 7, 40 | "type": "int" 41 | } 42 | ] 43 | }, 44 | { 45 | "ref": { 46 | "name": "u", 47 | "file": "test1.py", 48 | "start": 64, 49 | "end": 65, 50 | "line": 7, 51 | "col": 16 52 | }, 53 | "dests": [ 54 | { 55 | "name": "u", 56 | "file": "test1.py", 57 | "start": 0, 58 | "end": 1, 59 | "line": 1, 60 | "col": 1, 61 | "type": "int" 62 | } 63 | ] 64 | }, 65 | { 66 | "ref": { 67 | "name": "v", 68 | "file": "test1.py", 69 | "start": 90, 70 | "end": 91, 71 | "line": 9, 72 | "col": 15 73 | }, 74 | "dests": [ 75 | { 76 | "name": "v", 77 | "file": "test1.py", 78 | "start": 6, 79 | "end": 7, 80 | "line": 2, 81 | "col": 1, 82 | "type": "str" 83 | } 84 | ] 85 | }, 86 | { 87 | "ref": { 88 | "name": "y", 89 | "file": "test1.py", 90 | "start": 131, 91 | "end": 132, 92 | "line": 12, 93 | "col": 11 94 | }, 95 | "dests": [ 96 | { 97 | "name": "y", 98 | "file": "test1.py", 99 | "start": 112, 100 | "end": 113, 101 | "line": 11, 102 | "col": 5, 103 | "type": "str" 104 | } 105 | ] 106 | }, 107 | { 108 | "ref": { 109 | "name": "y", 110 | "file": "test1.py", 111 | "start": 150, 112 | "end": 151, 113 | "line": 15, 114 | "col": 7 115 | }, 116 | "dests": [ 117 | { 118 | "name": "y", 119 | "file": "test1.py", 120 | "start": 134, 121 | "end": 135, 122 | "line": 14, 123 | "col": 1, 124 | "type": "{bool | int}" 125 | } 126 | ] 127 | } 128 | ] -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/ast/Op.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.ast; 2 | 3 | import org.jetbrains.annotations.Nullable; 4 | import org.yinwang.pysonar.$; 5 | 6 | public enum Op { 7 | // numeral 8 | Add("+", "__add__"), 9 | Sub("-", "__sub__"), 10 | Mul("*", "__mul__"), 11 | MatMult("@", "__matmult__"), 12 | Div("/", "__div__"), 13 | Mod("%", "__mod__"), 14 | Pow("**", "__pow__"), 15 | FloorDiv("//", "__floordiv__"), 16 | 17 | // comparison 18 | Eq("is"), 19 | Equal("==", "__eq__"), 20 | Lt("<", "__lt__"), 21 | Gt(">", "__gt__"), 22 | 23 | // bit 24 | BitAnd("&", "__and__"), 25 | BitOr("|", "__or__"), 26 | BitXor("^", "__xor__"), 27 | In("in"), 28 | LShift("<<", "__lshift__"), 29 | RShift(">>", "__rshift__"), 30 | Invert("~", "__invert__"), 31 | 32 | // boolean 33 | And("and"), 34 | Or("or"), 35 | Not("not"), 36 | 37 | // synthetic 38 | NotEqual("!=", "__neq__"), 39 | NotEq("is not"), 40 | LtE("<=", "__lte__"), 41 | GtE(">=", "__gte__"), 42 | NotIn("not in"), 43 | 44 | // unsupported new operator 45 | Unsupported("??"); 46 | 47 | private String rep; 48 | 49 | @Nullable 50 | private String method; 51 | 52 | Op(String rep, @Nullable String method) { 53 | this.rep = rep; 54 | this.method = method; 55 | } 56 | 57 | Op(String rep) { 58 | this.rep = rep; 59 | this.method = null; 60 | } 61 | 62 | public String getRep() { 63 | return rep; 64 | } 65 | 66 | @Nullable 67 | public String getMethod() { 68 | return method; 69 | } 70 | 71 | public static Op invert(Op op) { 72 | if (op == Op.Lt) { 73 | return Op.Gt; 74 | } 75 | 76 | if (op == Op.Gt) { 77 | return Op.Lt; 78 | } 79 | 80 | if (op == Op.Eq) { 81 | return Op.Eq; 82 | } 83 | 84 | if (op == Op.And) { 85 | return Op.Or; 86 | } 87 | 88 | if (op == Op.Or) { 89 | return Op.And; 90 | } 91 | 92 | $.die("invalid operator name for invert: " + op); 93 | return null; // unreacheable 94 | } 95 | 96 | public static boolean isBoolean(Op op) { 97 | return op == Eq || 98 | op == Equal || 99 | op == Lt || 100 | op == Gt || 101 | op == NotEqual || 102 | op == NotEq || 103 | op == LtE || 104 | op == GtE || 105 | op == In || 106 | op == NotIn; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/main/java/org/yinwang/pysonar/demos/Style.java: -------------------------------------------------------------------------------- 1 | package org.yinwang.pysonar.demos; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import org.jetbrains.annotations.Nullable; 5 | import org.yinwang.pysonar.$; 6 | 7 | import java.util.List; 8 | 9 | 10 | /** 11 | * Represents a simple style run for purposes of source highlighting. 12 | */ 13 | public class Style implements Comparable\n") 122 | .append("\n") 125 | .append("\n\n") 126 | .append("
    ") 127 | .append(outline) 128 | .append("") 129 | .append("
    ")
    130 |             .append(addLineNumbers(styledSource))
    131 |             .append("
    ") 132 | .append("
    "); 133 | return sb.toString(); 134 | } 135 | 136 | 137 | @NotNull 138 | private String addLineNumbers(@NotNull String source) { 139 | StringBuilder result = new StringBuilder((int) (source.length() * 1.2)); 140 | int count = 1; 141 | for (String line : source.split("\n")) { 142 | result.append(""); 143 | result.append(String.format("%1$4d", count++)); 144 | result.append(" "); 145 | result.append(line); 146 | result.append("\n"); 147 | } 148 | return result.toString(); 149 | } 150 | 151 | 152 | private static void usage() { 153 | $.msg("Usage: java -jar pysonar-2.0-SNAPSHOT.jar "); 154 | $.msg("Example that generates an index for Python 2.7 standard library:"); 155 | $.msg(" java -jar pysonar-2.0-SNAPSHOT.jar /usr/lib/python2.7 ./html"); 156 | System.exit(0); 157 | } 158 | 159 | 160 | @NotNull 161 | private static File checkFile(String path) { 162 | File f = new File(path); 163 | if (!f.canRead()) { 164 | $.die("Path not found or not readable: " + path); 165 | } 166 | return f; 167 | } 168 | 169 | 170 | public static void main(@NotNull String[] args) throws Exception { 171 | Options options = new Options(args); 172 | 173 | List argsList = options.getArgs(); 174 | String fileOrDir = argsList.get(0); 175 | OUTPUT_DIR = new File(argsList.get(1)); 176 | 177 | // System.out.println("options: " + options.getOptionsMap()); 178 | new Demo().start(fileOrDir, options.getOptionsMap()); 179 | $.msg($.getGCStats()); 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /tests/branch.test/refs.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "ref": { 4 | "name": "x", 5 | "file": "test1.py", 6 | "start": 55, 7 | "end": 56, 8 | "line": 6, 9 | "col": 8 10 | }, 11 | "dests": [ 12 | { 13 | "name": "x", 14 | "file": "test1.py", 15 | "start": 31, 16 | "end": 32, 17 | "line": 4, 18 | "col": 11, 19 | "type": "?" 20 | } 21 | ] 22 | }, 23 | { 24 | "ref": { 25 | "name": "a", 26 | "file": "test1.py", 27 | "start": 86, 28 | "end": 87, 29 | "line": 8, 30 | "col": 11 31 | }, 32 | "dests": [ 33 | { 34 | "name": "a", 35 | "file": "test1.py", 36 | "start": 39, 37 | "end": 40, 38 | "line": 5, 39 | "col": 5, 40 | "type": "str" 41 | }, 42 | { 43 | "name": "a", 44 | "file": "test1.py", 45 | "start": 70, 46 | "end": 71, 47 | "line": 7, 48 | "col": 9, 49 | "type": "int" 50 | } 51 | ] 52 | }, 53 | { 54 | "ref": { 55 | "name": "x", 56 | "file": "test1.py", 57 | "start": 124, 58 | "end": 125, 59 | "line": 13, 60 | "col": 8 61 | }, 62 | "dests": [ 63 | { 64 | "name": "x", 65 | "file": "test1.py", 66 | "start": 100, 67 | "end": 101, 68 | "line": 11, 69 | "col": 11, 70 | "type": "?" 71 | } 72 | ] 73 | }, 74 | { 75 | "ref": { 76 | "name": "a", 77 | "file": "test1.py", 78 | "start": 182, 79 | "end": 183, 80 | "line": 17, 81 | "col": 11 82 | }, 83 | "dests": [ 84 | { 85 | "name": "a", 86 | "file": "test1.py", 87 | "start": 139, 88 | "end": 140, 89 | "line": 14, 90 | "col": 9, 91 | "type": "int" 92 | }, 93 | { 94 | "name": "a", 95 | "file": "test1.py", 96 | "start": 163, 97 | "end": 164, 98 | "line": 16, 99 | "col": 9, 100 | "type": "bool" 101 | } 102 | ] 103 | }, 104 | { 105 | "ref": { 106 | "name": "x", 107 | "file": "test1.py", 108 | "start": 220, 109 | "end": 221, 110 | "line": 22, 111 | "col": 8 112 | }, 113 | "dests": [ 114 | { 115 | "name": "x", 116 | "file": "test1.py", 117 | "start": 196, 118 | "end": 197, 119 | "line": 20, 120 | "col": 11, 121 | "type": "?" 122 | } 123 | ] 124 | }, 125 | { 126 | "ref": { 127 | "name": "x", 128 | "file": "test1.py", 129 | "start": 262, 130 | "end": 263, 131 | "line": 25, 132 | "col": 12 133 | }, 134 | "dests": [ 135 | { 136 | "name": "x", 137 | "file": "test1.py", 138 | "start": 196, 139 | "end": 197, 140 | "line": 20, 141 | "col": 11, 142 | "type": "?" 143 | } 144 | ] 145 | }, 146 | { 147 | "ref": { 148 | "name": "a", 149 | "file": "test1.py", 150 | "start": 336, 151 | "end": 337, 152 | "line": 29, 153 | "col": 11 154 | }, 155 | "dests": [ 156 | { 157 | "name": "a", 158 | "file": "test1.py", 159 | "start": 235, 160 | "end": 236, 161 | "line": 23, 162 | "col": 9, 163 | "type": "int" 164 | }, 165 | { 166 | "name": "a", 167 | "file": "test1.py", 168 | "start": 282, 169 | "end": 283, 170 | "line": 26, 171 | "col": 13, 172 | "type": "bool" 173 | }, 174 | { 175 | "name": "a", 176 | "file": "test1.py", 177 | "start": 317, 178 | "end": 318, 179 | "line": 28, 180 | "col": 13, 181 | "type": "str" 182 | } 183 | ] 184 | }, 185 | { 186 | "ref": { 187 | "name": "x", 188 | "file": "test1.py", 189 | "start": 388, 190 | "end": 389, 191 | "line": 35, 192 | "col": 8 193 | }, 194 | "dests": [ 195 | { 196 | "name": "x", 197 | "file": "test1.py", 198 | "start": 350, 199 | "end": 351, 200 | "line": 32, 201 | "col": 11, 202 | "type": "?" 203 | } 204 | ] 205 | }, 206 | { 207 | "ref": { 208 | "name": "x", 209 | "file": "test1.py", 210 | "start": 444, 211 | "end": 445, 212 | "line": 39, 213 | "col": 12 214 | }, 215 | "dests": [ 216 | { 217 | "name": "x", 218 | "file": "test1.py", 219 | "start": 350, 220 | "end": 351, 221 | "line": 32, 222 | "col": 11, 223 | "type": "?" 224 | } 225 | ] 226 | }, 227 | { 228 | "ref": { 229 | "name": "a", 230 | "file": "test1.py", 231 | "start": 540, 232 | "end": 541, 233 | "line": 44, 234 | "col": 11 235 | }, 236 | "dests": [ 237 | { 238 | "name": "a", 239 | "file": "test1.py", 240 | "start": 358, 241 | "end": 359, 242 | "line": 33, 243 | "col": 5, 244 | "type": "str" 245 | }, 246 | { 247 | "name": "a", 248 | "file": "test1.py", 249 | "start": 403, 250 | "end": 404, 251 | "line": 36, 252 | "col": 9, 253 | "type": "int" 254 | }, 255 | { 256 | "name": "a", 257 | "file": "test1.py", 258 | "start": 499, 259 | "end": 500, 260 | "line": 42, 261 | "col": 13, 262 | "type": "str" 263 | } 264 | ] 265 | }, 266 | { 267 | "ref": { 268 | "name": "b", 269 | "file": "test1.py", 270 | "start": 543, 271 | "end": 544, 272 | "line": 44, 273 | "col": 14 274 | }, 275 | "dests": [ 276 | { 277 | "name": "b", 278 | "file": "test1.py", 279 | "start": 417, 280 | "end": 418, 281 | "line": 37, 282 | "col": 9, 283 | "type": "int" 284 | }, 285 | { 286 | "name": "b", 287 | "file": "test1.py", 288 | "start": 464, 289 | "end": 465, 290 | "line": 40, 291 | "col": 13, 292 | "type": "bool" 293 | }, 294 | { 295 | "name": "b", 296 | "file": "test1.py", 297 | "start": 520, 298 | "end": 521, 299 | "line": 43, 300 | "col": 13, 301 | "type": "bool" 302 | } 303 | ] 304 | } 305 | ] --------------------------------------------------------------------------------