use of org.yinwang.pysonar.types.ClassType 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.types.ClassType in project pysonar2 by yinwang0.
the class TypeInferencer method visit.
@NotNull
@Override
public Type visit(ClassDef node, State s) {
ClassType classType = new ClassType(node.name.id, s);
List<Type> baseTypes = new ArrayList<>();
for (Node base : node.bases) {
Type baseType = visit(base, s);
if (baseType instanceof ClassType) {
classType.addSuper(baseType);
} else if (baseType instanceof UnionType) {
for (Type parent : ((UnionType) baseType).types) {
classType.addSuper(parent);
}
} else {
addWarningToNode(base, base + " is not a class");
}
baseTypes.add(baseType);
}
// XXX: Not sure if we should add "bases", "name" and "dict" here. They
// must be added _somewhere_ but I'm just not sure if it should be HERE.
node.addSpecialAttribute(classType.table, "__bases__", new TupleType(baseTypes));
node.addSpecialAttribute(classType.table, "__name__", Types.StrInstance);
node.addSpecialAttribute(classType.table, "__dict__", new DictType(Types.StrInstance, Types.UNKNOWN));
node.addSpecialAttribute(classType.table, "__module__", Types.StrInstance);
node.addSpecialAttribute(classType.table, "__doc__", Types.StrInstance);
// Bind ClassType to name here before resolving the body because the
// methods need node type as self.
bind(s, node.name, classType, CLASS);
if (node.body != null) {
visit(node.body, classType.table);
}
return Types.CONT;
}
use of org.yinwang.pysonar.types.ClassType in project pysonar2 by yinwang0.
the class TypeInferencer method inferInstance.
/**
* Helper for branch inference for 'isinstance'
*/
private void inferInstance(Node test, State s, State s1) {
if (test instanceof Call) {
Call testCall = (Call) test;
if (testCall.func instanceof Name) {
Name testFunc = (Name) testCall.func;
if (testFunc.id.equals("isinstance")) {
if (testCall.args.size() >= 2) {
Node id = testCall.args.get(0);
if (id instanceof Name) {
Node typeExp = testCall.args.get(1);
Type type = visit(typeExp, s);
if (type instanceof ClassType) {
type = ((ClassType) type).getInstance(null, this, test);
}
s1.insert(((Name) id).id, id, type, VARIABLE);
}
}
if (testCall.args.size() != 2) {
addWarningToNode(test, "Incorrect number of arguments for isinstance");
}
}
}
}
}
use of org.yinwang.pysonar.types.ClassType in project pysonar2 by yinwang0.
the class Outliner method generate.
/**
* Create an outline for a symbol table.
*
* @param state the file state
* @param path the file for which we're building the outline
* @return a list of entries constituting the outline
*/
@NotNull
public List<Entry> generate(@NotNull State state, @NotNull String path) {
List<Entry> result = new ArrayList<>();
Set<Binding> entries = new TreeSet<>();
for (Binding b : state.values()) {
if (!b.isSynthetic() && !b.isBuiltin() && path.equals(b.getFile())) {
entries.add(b);
}
}
for (Binding nb : entries) {
List<Entry> kids = null;
if (nb.kind == Binding.Kind.CLASS) {
Type realType = nb.type;
if (realType instanceof UnionType) {
for (Type t : ((UnionType) realType).types) {
if (t instanceof ClassType) {
realType = t;
break;
}
}
}
kids = generate(realType.table, path);
}
Entry kid = kids != null ? new Branch() : new Leaf();
kid.setOffset(nb.start);
kid.setQname(nb.qname);
kid.setKind(nb.kind);
if (kids != null) {
kid.setChildren(kids);
}
result.add(kid);
}
return result;
}
use of org.yinwang.pysonar.types.ClassType 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;
}
}
Aggregations