Search in sources :

Example 1 with PyBuiltinCache

use of com.jetbrains.python.psi.impl.PyBuiltinCache in project intellij-community by JetBrains.

the class NumpyDocStringTypeProvider method getNominalType.

/**
   * Converts literal into type, e.g. -1 -> int, 'fro' -> str
   */
@Nullable
private static PyType getNominalType(@NotNull PsiElement anchor, @NotNull String typeString) {
    final PyExpressionCodeFragmentImpl codeFragment = new PyExpressionCodeFragmentImpl(anchor.getProject(), "dummy.py", typeString, false);
    final PsiElement element = codeFragment.getFirstChild();
    if (element instanceof PyExpressionStatement) {
        final PyExpression expression = ((PyExpressionStatement) element).getExpression();
        final PyBuiltinCache builtinCache = PyBuiltinCache.getInstance(anchor);
        if (expression instanceof PyStringLiteralExpression) {
            return builtinCache.getStrType();
        }
        if (expression instanceof PyNumericLiteralExpression) {
            return builtinCache.getIntType();
        }
    }
    return null;
}
Also used : PyExpressionCodeFragmentImpl(com.jetbrains.python.psi.impl.PyExpressionCodeFragmentImpl) PsiElement(com.intellij.psi.PsiElement) PyBuiltinCache(com.jetbrains.python.psi.impl.PyBuiltinCache) Nullable(org.jetbrains.annotations.Nullable)

Example 2 with PyBuiltinCache

use of com.jetbrains.python.psi.impl.PyBuiltinCache in project intellij-community by JetBrains.

the class PyTypeChecker method match.

private static boolean match(@Nullable PyType expected, @Nullable PyType actual, @NotNull TypeEvalContext context, @Nullable Map<PyGenericType, PyType> substitutions, boolean recursive) {
    // TODO: subscriptable types?, module types?, etc.
    final PyClassType expectedClassType = as(expected, PyClassType.class);
    final PyClassType actualClassType = as(actual, PyClassType.class);
    // Special cases: object and type
    if (expectedClassType != null && ArrayUtil.contains(expectedClassType.getName(), PyNames.OBJECT, PyNames.TYPE)) {
        final PyBuiltinCache builtinCache = PyBuiltinCache.getInstance(expectedClassType.getPyClass());
        if (expectedClassType.equals(builtinCache.getObjectType())) {
            return true;
        }
        if (expectedClassType.equals(builtinCache.getTypeType()) && actual instanceof PyInstantiableType && ((PyInstantiableType) actual).isDefinition()) {
            return true;
        }
    }
    if (expected instanceof PyInstantiableType && actual instanceof PyInstantiableType && !(expected instanceof PyGenericType && typeVarAcceptsBothClassAndInstanceTypes((PyGenericType) expected)) && ((PyInstantiableType) expected).isDefinition() ^ ((PyInstantiableType) actual).isDefinition()) {
        return false;
    }
    if (actualClassType != null && PyNames.BASESTRING.equals(actualClassType.getName())) {
        final PyBuiltinCache builtinCache = PyBuiltinCache.getInstance(actualClassType.getPyClass());
        if (actualClassType.equals(builtinCache.getObjectType(PyNames.BASESTRING))) {
            return match(expected, builtinCache.getStrOrUnicodeType(), context, substitutions, recursive);
        }
    }
    if (expected instanceof PyGenericType && substitutions != null) {
        final PyGenericType generic = (PyGenericType) expected;
        final PyType subst = substitutions.get(generic);
        PyType bound = generic.getBound();
        // Promote int in Type[TypeVar('T', int)] to Type[int] before checking that bounds match
        if (generic.isDefinition() && bound instanceof PyInstantiableType) {
            bound = ((PyInstantiableType) bound).toClass();
        }
        if (!match(bound, actual, context, substitutions, recursive)) {
            return false;
        } else if (subst != null) {
            if (expected.equals(actual)) {
                return true;
            } else if (recursive) {
                return match(subst, actual, context, substitutions, false);
            } else {
                return false;
            }
        } else if (actual != null) {
            substitutions.put(generic, actual);
        } else if (bound != null) {
            substitutions.put(generic, bound);
        }
        return true;
    }
    if (expected == null || actual == null) {
        return true;
    }
    if (isUnknown(actual)) {
        return true;
    }
    if (actual instanceof PyUnionType) {
        final PyUnionType actualUnionType = (PyUnionType) actual;
        if (expected instanceof PyTupleType) {
            final PyTupleType expectedTupleType = (PyTupleType) expected;
            final int elementCount = expectedTupleType.getElementCount();
            if (!expectedTupleType.isHomogeneous() && consistsOfSameElementNumberTuples(actualUnionType, elementCount)) {
                return substituteExpectedElementsWithUnions(expectedTupleType, elementCount, actualUnionType, context, substitutions, recursive);
            }
        }
        for (PyType m : actualUnionType.getMembers()) {
            if (match(expected, m, context, substitutions, recursive)) {
                return true;
            }
        }
        return false;
    }
    if (expected instanceof PyUnionType) {
        final Collection<PyType> expectedUnionTypeMembers = ((PyUnionType) expected).getMembers();
        final StreamEx<PyType> notGenericTypes = StreamEx.of(expectedUnionTypeMembers).filter(type -> !PyGenericType.class.isInstance(type));
        final StreamEx<PyGenericType> genericTypes = StreamEx.of(expectedUnionTypeMembers).select(PyGenericType.class);
        for (PyType t : notGenericTypes.append(genericTypes)) {
            if (match(t, actual, context, substitutions, recursive)) {
                return true;
            }
        }
        return false;
    }
    if (expectedClassType != null && actualClassType != null) {
        final PyClass superClass = expectedClassType.getPyClass();
        final PyClass subClass = actualClassType.getPyClass();
        if (expected instanceof PyTupleType && actual instanceof PyTupleType) {
            final PyTupleType superTupleType = (PyTupleType) expected;
            final PyTupleType subTupleType = (PyTupleType) actual;
            if (!superTupleType.isHomogeneous() && !subTupleType.isHomogeneous()) {
                if (superTupleType.getElementCount() != subTupleType.getElementCount()) {
                    return false;
                } else {
                    for (int i = 0; i < superTupleType.getElementCount(); i++) {
                        if (!match(superTupleType.getElementType(i), subTupleType.getElementType(i), context, substitutions, recursive)) {
                            return false;
                        }
                    }
                    return true;
                }
            } else if (superTupleType.isHomogeneous() && !subTupleType.isHomogeneous()) {
                final PyType expectedElementType = superTupleType.getIteratedItemType();
                for (int i = 0; i < subTupleType.getElementCount(); i++) {
                    if (!match(expectedElementType, subTupleType.getElementType(i), context)) {
                        return false;
                    }
                }
                return true;
            } else if (!superTupleType.isHomogeneous() && subTupleType.isHomogeneous()) {
                return false;
            } else {
                return match(superTupleType.getIteratedItemType(), subTupleType.getIteratedItemType(), context);
            }
        } else if (expected instanceof PyCollectionType && actual instanceof PyTupleType) {
            if (!matchClasses(superClass, subClass, context)) {
                return false;
            }
            final PyType superElementType = ((PyCollectionType) expected).getIteratedItemType();
            final PyType subElementType = ((PyTupleType) actual).getIteratedItemType();
            if (!match(superElementType, subElementType, context, substitutions, recursive)) {
                return false;
            }
            return true;
        } else if (expected instanceof PyCollectionType) {
            if (!matchClasses(superClass, subClass, context)) {
                return false;
            }
            // TODO: Match generic parameters based on the correspondence between the generic parameters of subClass and its base classes
            final List<PyType> superElementTypes = ((PyCollectionType) expected).getElementTypes(context);
            final PyCollectionType actualCollectionType = as(actual, PyCollectionType.class);
            final List<PyType> subElementTypes = actualCollectionType != null ? actualCollectionType.getElementTypes(context) : Collections.emptyList();
            for (int i = 0; i < superElementTypes.size(); i++) {
                final PyType subElementType = i < subElementTypes.size() ? subElementTypes.get(i) : null;
                if (!match(superElementTypes.get(i), subElementType, context, substitutions, recursive)) {
                    return false;
                }
            }
            return true;
        } else if (matchClasses(superClass, subClass, context)) {
            return true;
        } else if (actualClassType.isDefinition() && PyNames.CALLABLE.equals(expected.getName())) {
            return true;
        }
        if (expected.equals(actual)) {
            return true;
        }
    }
    if (actual instanceof PyFunctionTypeImpl && expectedClassType != null) {
        final PyClass superClass = expectedClassType.getPyClass();
        if (PyNames.CALLABLE.equals(superClass.getName())) {
            return true;
        }
    }
    if (actual instanceof PyStructuralType && ((PyStructuralType) actual).isInferredFromUsages()) {
        return true;
    }
    if (expected instanceof PyStructuralType && actual instanceof PyStructuralType) {
        final PyStructuralType expectedStructural = (PyStructuralType) expected;
        final PyStructuralType actualStructural = (PyStructuralType) actual;
        if (expectedStructural.isInferredFromUsages()) {
            return true;
        }
        return expectedStructural.getAttributeNames().containsAll(actualStructural.getAttributeNames());
    }
    if (expected instanceof PyStructuralType && actualClassType != null) {
        if (overridesGetAttr(actualClassType.getPyClass(), context)) {
            return true;
        }
        final Set<String> actualAttributes = actualClassType.getMemberNames(true, context);
        return actualAttributes.containsAll(((PyStructuralType) expected).getAttributeNames());
    }
    if (actual instanceof PyStructuralType && expectedClassType != null) {
        final Set<String> expectedAttributes = expectedClassType.getMemberNames(true, context);
        return expectedAttributes.containsAll(((PyStructuralType) actual).getAttributeNames());
    }
    if (actual instanceof PyCallableType && expected instanceof PyCallableType) {
        final PyCallableType expectedCallable = (PyCallableType) expected;
        final PyCallableType actualCallable = (PyCallableType) actual;
        if (expectedCallable.isCallable() && actualCallable.isCallable()) {
            final List<PyCallableParameter> expectedParameters = expectedCallable.getParameters(context);
            final List<PyCallableParameter> actualParameters = actualCallable.getParameters(context);
            if (expectedParameters != null && actualParameters != null) {
                final int size = Math.min(expectedParameters.size(), actualParameters.size());
                for (int i = 0; i < size; i++) {
                    final PyCallableParameter expectedParam = expectedParameters.get(i);
                    final PyCallableParameter actualParam = actualParameters.get(i);
                    // TODO: Check named and star params, not only positional ones
                    if (!match(expectedParam.getType(context), actualParam.getType(context), context, substitutions, recursive)) {
                        return false;
                    }
                }
            }
            if (!match(expectedCallable.getReturnType(context), actualCallable.getReturnType(context), context, substitutions, recursive)) {
                return false;
            }
            return true;
        }
    }
    return matchNumericTypes(expected, actual);
}
Also used : PyBuiltinCache(com.jetbrains.python.psi.impl.PyBuiltinCache)

Example 3 with PyBuiltinCache

use of com.jetbrains.python.psi.impl.PyBuiltinCache in project intellij-community by JetBrains.

the class PythonBuiltinReferenceResolveProvider method resolveName.

@NotNull
@Override
public List<RatedResolveResult> resolveName(@NotNull PyQualifiedExpression element, @NotNull TypeEvalContext context) {
    final String referencedName = element.getReferencedName();
    if (referencedName == null) {
        return Collections.emptyList();
    }
    final List<RatedResolveResult> result = new ArrayList<>();
    final PyBuiltinCache builtinCache = PyBuiltinCache.getInstance(PyPsiUtils.getRealContext(element));
    // resolve to module __doc__
    if (PyNames.DOC.equals(referencedName)) {
        result.addAll(Optional.ofNullable(builtinCache.getObjectType()).map(type -> type.resolveMember(referencedName, element, AccessDirection.of(element), PyResolveContext.noImplicits().withTypeEvalContext(context))).orElse(Collections.emptyList()));
    }
    // ...as a builtin symbol
    final PyFile builtinsFile = builtinCache.getBuiltinsFile();
    if (builtinsFile != null && !PyUtil.isClassPrivateName(referencedName)) {
        for (RatedResolveResult resolveResult : builtinsFile.multiResolveName(referencedName)) {
            result.add(new ImportedResolveResult(resolveResult.getElement(), resolveResult.getRate(), null));
        }
    }
    return result;
}
Also used : ArrayList(java.util.ArrayList) PyFile(com.jetbrains.python.psi.PyFile) PyBuiltinCache(com.jetbrains.python.psi.impl.PyBuiltinCache) NotNull(org.jetbrains.annotations.NotNull)

Example 4 with PyBuiltinCache

use of com.jetbrains.python.psi.impl.PyBuiltinCache in project intellij-community by JetBrains.

the class QualifiedNameFinder method getQualifiedName.

@Nullable
public static String getQualifiedName(@NotNull PyElement element) {
    final String name = element.getName();
    if (name != null) {
        final ScopeOwner owner = ScopeUtil.getScopeOwner(element);
        final PyBuiltinCache builtinCache = PyBuiltinCache.getInstance(element);
        if (owner instanceof PyClass) {
            final String classQName = ((PyClass) owner).getQualifiedName();
            if (classQName != null) {
                return classQName + "." + name;
            }
        } else if (owner instanceof PyFile) {
            if (builtinCache.isBuiltin(element)) {
                return name;
            } else {
                final VirtualFile virtualFile = ((PyFile) owner).getVirtualFile();
                if (virtualFile != null) {
                    final String fileQName = findShortestImportableName(element, virtualFile);
                    if (fileQName != null) {
                        return fileQName + "." + name;
                    }
                }
            }
        }
    }
    return null;
}
Also used : VirtualFile(com.intellij.openapi.vfs.VirtualFile) ScopeOwner(com.jetbrains.python.codeInsight.controlflow.ScopeOwner) PyBuiltinCache(com.jetbrains.python.psi.impl.PyBuiltinCache) Nullable(org.jetbrains.annotations.Nullable)

Example 5 with PyBuiltinCache

use of com.jetbrains.python.psi.impl.PyBuiltinCache in project intellij-community by JetBrains.

the class PyUtil method isSuperCall.

public static boolean isSuperCall(@NotNull PyCallExpression node) {
    PyClass klass = PsiTreeUtil.getParentOfType(node, PyClass.class);
    if (klass == null)
        return false;
    PyExpression callee = node.getCallee();
    if (callee == null)
        return false;
    String name = callee.getName();
    if (PyNames.SUPER.equals(name)) {
        PsiReference reference = callee.getReference();
        if (reference == null)
            return false;
        PsiElement resolved = reference.resolve();
        PyBuiltinCache cache = PyBuiltinCache.getInstance(node);
        if (resolved != null && cache.isBuiltin(resolved)) {
            PyExpression[] args = node.getArguments();
            if (args.length > 0) {
                String firstArg = args[0].getText();
                if (firstArg.equals(klass.getName()) || firstArg.equals(PyNames.CANONICAL_SELF + "." + PyNames.__CLASS__)) {
                    return true;
                }
                for (PyClass s : klass.getAncestorClasses(null)) {
                    if (firstArg.equals(s.getName())) {
                        return true;
                    }
                }
            } else {
                return true;
            }
        }
    }
    return false;
}
Also used : PyBuiltinCache(com.jetbrains.python.psi.impl.PyBuiltinCache)

Aggregations

PyBuiltinCache (com.jetbrains.python.psi.impl.PyBuiltinCache)10 PsiElement (com.intellij.psi.PsiElement)4 Nullable (org.jetbrains.annotations.Nullable)3 PyFile (com.jetbrains.python.psi.PyFile)2 VirtualFile (com.intellij.openapi.vfs.VirtualFile)1 ScopeOwner (com.jetbrains.python.codeInsight.controlflow.ScopeOwner)1 PyUtil.guessLanguageLevel (com.jetbrains.python.psi.PyUtil.guessLanguageLevel)1 PyExpressionCodeFragmentImpl (com.jetbrains.python.psi.impl.PyExpressionCodeFragmentImpl)1 ImportedResolveResult (com.jetbrains.python.psi.resolve.ImportedResolveResult)1 PyResolveContext (com.jetbrains.python.psi.resolve.PyResolveContext)1 RatedResolveResult (com.jetbrains.python.psi.resolve.RatedResolveResult)1 PyType (com.jetbrains.python.psi.types.PyType)1 ArrayList (java.util.ArrayList)1 NotNull (org.jetbrains.annotations.NotNull)1