Search in sources :

Example 1 with ClassType

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;
    }
}
Also used : ClassType(org.yinwang.pysonar.types.ClassType) ListType(org.yinwang.pysonar.types.ListType) DictType(org.yinwang.pysonar.types.DictType) InstanceType(org.yinwang.pysonar.types.InstanceType) Type(org.yinwang.pysonar.types.Type) UnionType(org.yinwang.pysonar.types.UnionType) TupleType(org.yinwang.pysonar.types.TupleType) FunType(org.yinwang.pysonar.types.FunType) ModuleType(org.yinwang.pysonar.types.ModuleType) State(org.yinwang.pysonar.State) ListType(org.yinwang.pysonar.types.ListType) DictType(org.yinwang.pysonar.types.DictType) ArrayList(java.util.ArrayList) CallStackEntry(org.yinwang.pysonar.CallStackEntry) InstanceType(org.yinwang.pysonar.types.InstanceType) NotNull(org.jetbrains.annotations.NotNull)

Example 2 with ClassType

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;
}
Also used : UnionType(org.yinwang.pysonar.types.UnionType) ClassType(org.yinwang.pysonar.types.ClassType) ListType(org.yinwang.pysonar.types.ListType) DictType(org.yinwang.pysonar.types.DictType) InstanceType(org.yinwang.pysonar.types.InstanceType) Type(org.yinwang.pysonar.types.Type) UnionType(org.yinwang.pysonar.types.UnionType) TupleType(org.yinwang.pysonar.types.TupleType) FunType(org.yinwang.pysonar.types.FunType) ModuleType(org.yinwang.pysonar.types.ModuleType) ArrayList(java.util.ArrayList) TupleType(org.yinwang.pysonar.types.TupleType) DictType(org.yinwang.pysonar.types.DictType) ClassType(org.yinwang.pysonar.types.ClassType) NotNull(org.jetbrains.annotations.NotNull)

Example 3 with ClassType

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");
                }
            }
        }
    }
}
Also used : ClassType(org.yinwang.pysonar.types.ClassType) ListType(org.yinwang.pysonar.types.ListType) DictType(org.yinwang.pysonar.types.DictType) InstanceType(org.yinwang.pysonar.types.InstanceType) Type(org.yinwang.pysonar.types.Type) UnionType(org.yinwang.pysonar.types.UnionType) TupleType(org.yinwang.pysonar.types.TupleType) FunType(org.yinwang.pysonar.types.FunType) ModuleType(org.yinwang.pysonar.types.ModuleType) ClassType(org.yinwang.pysonar.types.ClassType)

Example 4 with ClassType

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;
}
Also used : UnionType(org.yinwang.pysonar.types.UnionType) ClassType(org.yinwang.pysonar.types.ClassType) Type(org.yinwang.pysonar.types.Type) UnionType(org.yinwang.pysonar.types.UnionType) TreeSet(java.util.TreeSet) ArrayList(java.util.ArrayList) ClassType(org.yinwang.pysonar.types.ClassType) NotNull(org.jetbrains.annotations.NotNull)

Example 5 with ClassType

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;
    }
}
Also used : Binding(org.yinwang.pysonar.Binding) ClassType(org.yinwang.pysonar.types.ClassType) ListType(org.yinwang.pysonar.types.ListType) DictType(org.yinwang.pysonar.types.DictType) InstanceType(org.yinwang.pysonar.types.InstanceType) Type(org.yinwang.pysonar.types.Type) UnionType(org.yinwang.pysonar.types.UnionType) TupleType(org.yinwang.pysonar.types.TupleType) FunType(org.yinwang.pysonar.types.FunType) ModuleType(org.yinwang.pysonar.types.ModuleType) State(org.yinwang.pysonar.State) FunType(org.yinwang.pysonar.types.FunType) ClassType(org.yinwang.pysonar.types.ClassType) NotNull(org.jetbrains.annotations.NotNull)

Aggregations

ClassType (org.yinwang.pysonar.types.ClassType)6 Type (org.yinwang.pysonar.types.Type)6 UnionType (org.yinwang.pysonar.types.UnionType)6 DictType (org.yinwang.pysonar.types.DictType)5 FunType (org.yinwang.pysonar.types.FunType)5 InstanceType (org.yinwang.pysonar.types.InstanceType)5 ListType (org.yinwang.pysonar.types.ListType)5 ModuleType (org.yinwang.pysonar.types.ModuleType)5 TupleType (org.yinwang.pysonar.types.TupleType)5 NotNull (org.jetbrains.annotations.NotNull)4 ArrayList (java.util.ArrayList)3 State (org.yinwang.pysonar.State)2 TreeSet (java.util.TreeSet)1 Binding (org.yinwang.pysonar.Binding)1 CallStackEntry (org.yinwang.pysonar.CallStackEntry)1