use of org.yinwang.pysonar.State in project pysonar2 by yinwang0.
the class TypeInferencer method apply.
@NotNull
public Type apply(@NotNull FunType func, @Nullable Type selfType, @Nullable List<Type> positional, @Nullable Map<String, Type> kwTypes, @Nullable Type kwArg, @Nullable Type starArg, @Nullable Node call) {
if (call instanceof Call && ((Call) call).func instanceof Attribute && ((Attribute) ((Call) call).func).attr.id.equals("append")) {
if (selfType instanceof ListType) {
ListType listType = (ListType) selfType;
if (positional != null && positional.size() == 1) {
listType.add(positional.get(0));
} else {
Analyzer.self.putProblem(call, "Calling append with wrong argument types");
}
}
}
if (call instanceof Call && ((Call) call).func instanceof Attribute && ((Attribute) ((Call) call).func).attr.id.equals("update")) {
if (selfType instanceof DictType) {
DictType dict = (DictType) selfType;
if (positional != null && positional.size() == 1) {
Type argType = positional.get(0);
if (argType instanceof DictType) {
dict.keyType = UnionType.union(dict.keyType, ((DictType) argType).keyType);
dict.valueType = UnionType.union(dict.valueType, ((DictType) argType).valueType);
}
} else {
Analyzer.self.putProblem(call, "Calling update with wrong argument types");
}
}
}
Analyzer.self.removeUncalled(func);
if (func.func != null && !func.func.called) {
Analyzer.self.nCalled++;
func.func.called = true;
}
if (func.func == null) {
// func without definition (possibly builtins)
return func.getReturnType();
}
List<Type> argTypes = new ArrayList<>();
// Add class or object as first argument if it is not static method
if (!func.func.isStaticMethod()) {
if (func.func.isClassMethod()) {
if (func.cls != null) {
argTypes.add(func.cls);
} else if (selfType != null && selfType instanceof InstanceType) {
argTypes.add(((InstanceType) selfType).classType);
}
} else {
// usual method
if (selfType != null) {
argTypes.add(selfType);
} else {
if (func.cls != null) {
if (!func.func.name.id.equals("__init__")) {
argTypes.add(func.cls.getInstance(null, this, call));
} else {
argTypes.add(func.cls.getInstance());
}
}
}
}
}
// Put in positional arguments
if (positional != null) {
argTypes.addAll(positional);
}
bindMethodAttrs(func);
State callState = new State(func.env, State.StateType.FUNCTION);
if (func.table.parent != null) {
callState.setPath(func.table.parent.extendPath(func.func.name.id));
} else {
callState.setPath(func.func.name.id);
}
Type fromType = bindParams(callState, func.func, argTypes, func.defaultTypes, kwTypes, kwArg, starArg);
Type cachedTo = func.getMapping(fromType);
if (cachedTo != null) {
return cachedTo;
} else if (func.oversized()) {
return Types.UNKNOWN;
} else {
func.addMapping(fromType, Types.UNKNOWN);
Analyzer.self.callStack.push(new CallStackEntry(func, fromType));
Type toType = visit(func.func.body, callState);
Analyzer.self.callStack.pop();
if (missingReturn(toType)) {
addWarningToNode(func.func.name, "Function not always return a value");
if (call != null) {
addWarningToNode(call, "Call not always return a value");
}
}
toType = UnionType.remove(toType, Types.CONT);
if (!func.func.name.id.equals("__init__")) {
func.addMapping(fromType, toType);
} else {
func.removeMapping(fromType);
}
return toType;
}
}
use of org.yinwang.pysonar.State in project pysonar2 by yinwang0.
the class TypeInferencer method visit.
@NotNull
@Override
public Type visit(While node, State s) {
visit(node.test, s);
Type t1 = Types.UNKNOWN;
Type t2 = Types.UNKNOWN;
Type t3 = Types.UNKNOWN;
State s1 = s.copy();
State s2 = s.copy();
if (node.body != null) {
t1 = visit(node.body, s1);
s.merge(s1);
t2 = visit(node.body, s1);
s.merge(s1);
}
if (node.orelse != null) {
t3 = visit(node.orelse, s2);
s.merge(s2);
}
return UnionType.union(UnionType.union(t1, t2), t3);
}
use of org.yinwang.pysonar.State in project pysonar2 by yinwang0.
the class TypeInferencer method visit.
@NotNull
@Override
public Type visit(For node, State s) {
bindIter(s, node.target, node.iter, SCOPE);
Type t1 = Types.UNKNOWN;
Type t2 = Types.UNKNOWN;
Type t3 = Types.UNKNOWN;
State s1 = s.copy();
State s2 = s.copy();
if (node.body != null) {
t1 = visit(node.body, s1);
s.merge(s1);
t2 = visit(node.body, s1);
s.merge(s1);
}
if (node.orelse != null) {
t3 = visit(node.orelse, s2);
s.merge(s2);
}
return UnionType.union(UnionType.union(t1, t2), t3);
}
use of org.yinwang.pysonar.State in project pysonar2 by yinwang0.
the class TypeInferencer method visit.
@NotNull
@Override
public Type visit(FunctionDef node, State s) {
State env = s.getForwarding();
FunType fun = new FunType(node, env);
fun.table.setParent(s);
fun.table.setPath(s.extendPath(node.name.id));
fun.setDefaultTypes(visit(node.defaults, s));
Analyzer.self.addUncalled(fun);
Binding.Kind funkind;
if (node.isLamba) {
return fun;
} else {
if (s.stateType == State.StateType.CLASS) {
if ("__init__".equals(node.name.id)) {
funkind = CONSTRUCTOR;
} else {
funkind = METHOD;
}
} else {
funkind = FUNCTION;
}
Type outType = s.type;
if (outType instanceof ClassType) {
fun.setCls((ClassType) outType);
}
bind(s, node.name, fun, funkind);
return Types.CONT;
}
}
use of org.yinwang.pysonar.State in project pysonar2 by yinwang0.
the class TypeInferencer method visit.
@NotNull
@Override
public Type visit(If node, State s) {
Type type1, type2;
State s1 = s.copy();
State s2 = s.copy();
// Ignore result because Python can treat anything as bool
visit(node.test, s);
inferInstance(node.test, s, s1);
if (node.body != null) {
type1 = visit(node.body, s1);
} else {
type1 = Types.CONT;
}
if (node.orelse != null) {
type2 = visit(node.orelse, s2);
} else {
type2 = Types.CONT;
}
boolean cont1 = UnionType.contains(type1, Types.CONT);
boolean cont2 = UnionType.contains(type2, Types.CONT);
// decide which branch affects the downstream state
if (cont1 && cont2) {
s1.merge(s2);
s.overwrite(s1);
} else if (cont1) {
s.overwrite(s1);
} else if (cont2) {
s.overwrite(s2);
}
return UnionType.union(type1, type2);
}
Aggregations