diff --git a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java index 75fa31e3f3fe..6e9166e104df 100644 --- a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java +++ b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java @@ -34,7 +34,8 @@ public class PyJavaClassType implements PyClassLikeType { public List resolveMember(@NotNull final String name, PyExpression location, AccessDirection direction, - PyResolveContext resolveContext) { + PyResolveContext resolveContext, + boolean inherited) { final PsiMethod[] methods = myClass.findMethodsByName(name, true); if (methods.length > 0) { ResolveResultList resultList = new ResolveResultList(); diff --git a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaMethodType.java b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaMethodType.java index d13a0c9d1280..066b374035f8 100644 --- a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaMethodType.java +++ b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaMethodType.java @@ -43,7 +43,8 @@ public class PyJavaMethodType implements PyCallableType { public List resolveMember(@NotNull String name, @Nullable PyExpression location, AccessDirection direction, - PyResolveContext resolveContext) { + PyResolveContext resolveContext, + boolean inherited) { return Collections.emptyList(); } diff --git a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaPackageType.java b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaPackageType.java index 977e7d2a3573..973c39b42b66 100644 --- a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaPackageType.java +++ b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaPackageType.java @@ -38,7 +38,8 @@ public class PyJavaPackageType implements PyType { public List resolveMember(@NotNull String name, @Nullable PyExpression location, AccessDirection direction, - PyResolveContext resolveContext) { + PyResolveContext resolveContext, + boolean inherited) { Project project = myPackage.getProject(); JavaPsiFacade facade = JavaPsiFacade.getInstance(project); String childName = myPackage.getQualifiedName() + "." + name; diff --git a/python/psi-api/src/com/jetbrains/python/psi/types/PyType.java b/python/psi-api/src/com/jetbrains/python/psi/types/PyType.java index 99075827ef97..308ee9f0692c 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/types/PyType.java +++ b/python/psi-api/src/com/jetbrains/python/psi/types/PyType.java @@ -22,18 +22,18 @@ public interface PyType { /** * Resolves an attribute of type. * - * * @param name attribute name * @param location the expression of type qualifierType on which the member is being resolved (optional) * @param direction * @param resolveContext + * @param inherited look up inherited members and members provided by class providers * @return null if name definitely cannot be found (e.g. in a qualified reference), * or an empty list if name is not found but other contexts are worth looking at, * or a list of elements that define the name, a la multiResolve(). */ @Nullable List resolveMember(@NotNull final String name, @Nullable PyExpression location, AccessDirection direction, - PyResolveContext resolveContext); + PyResolveContext resolveContext, boolean inherited); /** * Proposes completion variants from type's attributes. diff --git a/python/src/com/jetbrains/python/codeInsight/controlflow/PyControlFlowBuilder.java b/python/src/com/jetbrains/python/codeInsight/controlflow/PyControlFlowBuilder.java index c11d146b66f6..de61831e52ac 100644 --- a/python/src/com/jetbrains/python/codeInsight/controlflow/PyControlFlowBuilder.java +++ b/python/src/com/jetbrains/python/codeInsight/controlflow/PyControlFlowBuilder.java @@ -299,15 +299,43 @@ public class PyControlFlowBuilder extends PyRecursiveElementVisitor { }); myBuilder.addPendingEdge(node, myBuilder.prevInstruction); } + boolean noPendingInScopeEdges = false; + if (!assertionEvaluator.getDefinitions().isEmpty()) { + final Ref pendingInScopeEdges = Ref.create(false); + myBuilder.processPending(new ControlFlowBuilder.PendingProcessor() { + @Override + public void process(PsiElement pendingScope, Instruction instruction) { + if (pendingScope != null && PsiTreeUtil.isAncestor(node, pendingScope, false)) { + pendingInScopeEdges.set(true); + } + myBuilder.addPendingEdge(pendingScope, instruction); + } + }); + noPendingInScopeEdges = !pendingInScopeEdges.get(); + } + final PyTypeAssertionEvaluator negativeAssertionEvaluator = new PyTypeAssertionEvaluator(false); + final PyExpression ifCondition = ifPart.getCondition(); + // TODO: Add support for 'elif' + if (ifCondition != null) { + ifCondition.accept(negativeAssertionEvaluator); + } final PyElsePart elseBranch = node.getElsePart(); if (elseBranch != null) { // Set the head as the false branch myBuilder.prevInstruction = lastBranchingPoint; myBuilder.startConditionalNode(elseBranch, lastCondition, false); + InstructionBuilder.addAssertInstructions(myBuilder, negativeAssertionEvaluator); elseBranch.accept(this); myBuilder.addPendingEdge(node, myBuilder.prevInstruction); } else { - myBuilder.addPendingEdge(node, lastBranchingPoint); + if (noPendingInScopeEdges) { + myBuilder.prevInstruction = lastBranchingPoint; + InstructionBuilder.addAssertInstructions(myBuilder, negativeAssertionEvaluator); + myBuilder.addPendingEdge(node, myBuilder.prevInstruction); + } + else { + myBuilder.addPendingEdge(node, lastBranchingPoint); + } } } diff --git a/python/src/com/jetbrains/python/codeInsight/controlflow/PyTypeAssertionEvaluator.java b/python/src/com/jetbrains/python/codeInsight/controlflow/PyTypeAssertionEvaluator.java index 890e3c484adb..9dfcfefcd8ce 100644 --- a/python/src/com/jetbrains/python/codeInsight/controlflow/PyTypeAssertionEvaluator.java +++ b/python/src/com/jetbrains/python/codeInsight/controlflow/PyTypeAssertionEvaluator.java @@ -16,7 +16,15 @@ import java.util.Stack; */ public class PyTypeAssertionEvaluator extends PyRecursiveElementVisitor { private Stack myStack = new Stack(); - private boolean myPositive = true; + private boolean myPositive; + + public PyTypeAssertionEvaluator() { + this(true); + } + + public PyTypeAssertionEvaluator(boolean positive) { + myPositive = positive; + } public List getDefinitions() { return myStack; @@ -24,7 +32,7 @@ public class PyTypeAssertionEvaluator extends PyRecursiveElementVisitor { @Override public void visitPyPrefixExpression(PyPrefixExpression node) { - if (myPositive && node.getOperator() == PyTokenTypes.NOT_KEYWORD) { + if (node.getOperator() == PyTokenTypes.NOT_KEYWORD) { myPositive = !myPositive; super.visitPyPrefixExpression(node); myPositive = !myPositive; @@ -74,12 +82,13 @@ public class PyTypeAssertionEvaluator extends PyRecursiveElementVisitor { @Override public void visitPyReferenceExpression(final PyReferenceExpression node) { if (node.getParent() instanceof PyIfPart) { + final boolean positive = myPositive; pushAssertion(node, new InstructionTypeCallback() { @Override public PyType getType(TypeEvalContext context, PsiElement anchor) { final List types = new ArrayList(); types.add(PyNoneType.INSTANCE); - return createAssertionType(context.getType(node), types, false, context); + return createAssertionType(context.getType(node), types, !positive, context); } }); return; @@ -95,12 +104,13 @@ public class PyTypeAssertionEvaluator extends PyRecursiveElementVisitor { if (lhs instanceof PyReferenceExpression && rhs instanceof PyReferenceExpression) { final PyReferenceExpression target = (PyReferenceExpression)lhs; if (PyNames.NONE.equals(rhs.getName())) { + final boolean positive = myPositive; pushAssertion(target, new InstructionTypeCallback() { @Override public PyType getType(TypeEvalContext context, @Nullable PsiElement anchor) { final List types = new ArrayList(); types.add(PyNoneType.INSTANCE); - return createAssertionType(context.getType(target), types, false, context); + return createAssertionType(context.getType(target), types, !positive, context); } }); return; diff --git a/python/src/com/jetbrains/python/codeInsight/stdlib/PyNamedTupleType.java b/python/src/com/jetbrains/python/codeInsight/stdlib/PyNamedTupleType.java index 858ea2712712..af3eafb58b7a 100644 --- a/python/src/com/jetbrains/python/codeInsight/stdlib/PyNamedTupleType.java +++ b/python/src/com/jetbrains/python/codeInsight/stdlib/PyNamedTupleType.java @@ -45,8 +45,9 @@ public class PyNamedTupleType extends PyClassTypeImpl implements PyCallableType public List resolveMember(@NotNull String name, @Nullable PyExpression location, AccessDirection direction, - PyResolveContext resolveContext) { - final List classMembers = super.resolveMember(name, location, direction, resolveContext); + PyResolveContext resolveContext, + boolean inherited) { + final List classMembers = super.resolveMember(name, location, direction, resolveContext, inherited); if (classMembers != null && !classMembers.isEmpty()) { return classMembers; } diff --git a/python/src/com/jetbrains/python/inspections/PyStatementEffectInspection.java b/python/src/com/jetbrains/python/inspections/PyStatementEffectInspection.java index ef9a0a050e47..3b2e851360ad 100644 --- a/python/src/com/jetbrains/python/inspections/PyStatementEffectInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyStatementEffectInspection.java @@ -123,7 +123,7 @@ public class PyStatementEffectInspection extends PyInspection { PyType type = myTypeEvalContext.getType(binary.getLeftExpression()); if (type != null && !type.isBuiltin(myTypeEvalContext) && - type.resolveMember(method, null, AccessDirection.READ, resolveWithoutImplicits()) != null) { + type.resolveMember(method, null, AccessDirection.READ, resolveWithoutImplicits(), true) != null) { return true; } final PyExpression rhs = binary.getRightExpression(); @@ -131,7 +131,8 @@ public class PyStatementEffectInspection extends PyInspection { type = myTypeEvalContext.getType(rhs); if (type != null) { String rmethod = "__r" + method.substring(2); // __add__ -> __radd__ - if (!type.isBuiltin(myTypeEvalContext) && type.resolveMember(rmethod, null, AccessDirection.READ, resolveWithoutImplicits()) != null) { + if (!type.isBuiltin(myTypeEvalContext) && type.resolveMember(rmethod, null, AccessDirection.READ, resolveWithoutImplicits(), + true) != null) { return true; } } diff --git a/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java b/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java index 55d85a0ce20c..d695b504f2e2 100644 --- a/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java @@ -805,7 +805,8 @@ public class PyUnresolvedReferencesInspection extends PyInspection { final PyType type = context.getType(cls); if (type != null) { final List results = type.resolveMember(name, null, AccessDirection.READ, - PyResolveContext.noImplicits().withTypeEvalContext(context)); + PyResolveContext.noImplicits().withTypeEvalContext(context), + true); if (results != null && !results.isEmpty()) { return results.get(0).getElement(); } diff --git a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java index 62d397d718e0..ad48778420eb 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java @@ -1091,11 +1091,6 @@ public class PyClassImpl extends PyPresentableElementImpl implement @NotNull @Override public List getAncestorTypes(@NotNull TypeEvalContext context) { - return calculateAncestorTypes(context); - } - - @NotNull - private List calculateAncestorTypes(@NotNull TypeEvalContext context) { myCachedAncestorsProvider.setTypeEvalContext(context); try { // TODO: Return different cached copies depending on the type eval context parameters diff --git a/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java index 117983e93c69..9da2e5cded3b 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java @@ -135,7 +135,10 @@ public class PyTargetExpressionImpl extends PyPresentableElementImpl results = type.resolveMember(name, null, AccessDirection.READ, - PyResolveContext.noImplicits()); + PyResolveContext.noImplicits(), true); if (results != null && !results.isEmpty()) { return results.get(0).getElement(); } diff --git a/python/src/com/jetbrains/python/psi/impl/references/PyOperatorReference.java b/python/src/com/jetbrains/python/psi/impl/references/PyOperatorReference.java index 48614982b79c..6f59ff424a9e 100644 --- a/python/src/com/jetbrains/python/psi/impl/references/PyOperatorReference.java +++ b/python/src/com/jetbrains/python/psi/impl/references/PyOperatorReference.java @@ -131,7 +131,7 @@ public class PyOperatorReference extends PyReferenceImpl { final PyType type = typeEvalContext.getType(object); typeEvalContext.trace("Side text is %s, type is %s", object.getText(), type); if (type != null && !(type instanceof PyTypeReference)) { - List res = type.resolveMember(name, object, AccessDirection.of(myElement), myContext); + List res = type.resolveMember(name, object, AccessDirection.of(myElement), myContext, true); if (res != null && res.size() > 0) { results.addAll(res); } @@ -141,7 +141,7 @@ public class PyOperatorReference extends PyReferenceImpl { final PyClass pyClass = ((PyClassType)type).getPyClass(); vFile = pyClass.getContainingFile().getVirtualFile(); } - type.resolveMember(name, object, AccessDirection.of(myElement), myContext); + type.resolveMember(name, object, AccessDirection.of(myElement), myContext, true); typeEvalContext.trace("Could not resolve member %s in type %s from file %s", name, type, vFile); } } diff --git a/python/src/com/jetbrains/python/psi/impl/references/PyQualifiedReference.java b/python/src/com/jetbrains/python/psi/impl/references/PyQualifiedReference.java index 234f1ac9b099..11d9f1a928c9 100644 --- a/python/src/com/jetbrains/python/psi/impl/references/PyQualifiedReference.java +++ b/python/src/com/jetbrains/python/psi/impl/references/PyQualifiedReference.java @@ -71,7 +71,8 @@ public class PyQualifiedReference extends PyReferenceImpl { qualifierType.assertValid("qualifier: " + qualifier); // resolve within the type proper AccessDirection ctx = AccessDirection.of(myElement); - final List membersOfQualifier = qualifierType.resolveMember(referencedName, qualifier, ctx, myContext); + final List membersOfQualifier = qualifierType.resolveMember(referencedName, qualifier, ctx, myContext, + true); if (membersOfQualifier == null) { return ret; // qualifier is positive that such name cannot exist in it } @@ -238,8 +239,13 @@ public class PyQualifiedReference extends PyReferenceImpl { @NotNull @Override public Object[] getVariants() { - PyExpression qualifier = CompletionUtil.getOriginalOrSelf(myElement.getQualifier()); - assert qualifier != null; + PyExpression qualifier = myElement.getQualifier(); + if (qualifier != null) { + qualifier = CompletionUtil.getOriginalOrSelf(qualifier); + } + if (qualifier == null) { + return EMPTY_ARRAY; + } final PyQualifiedExpression element = CompletionUtil.getOriginalOrSelf(myElement); PyType qualifierType = TypeEvalContext.slow().getType(qualifier); diff --git a/python/src/com/jetbrains/python/psi/impl/references/PyReferenceImpl.java b/python/src/com/jetbrains/python/psi/impl/references/PyReferenceImpl.java index b50b16e490ac..c0081f5269a1 100644 --- a/python/src/com/jetbrains/python/psi/impl/references/PyReferenceImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/references/PyReferenceImpl.java @@ -302,7 +302,7 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference if (PyModuleType.MODULE_MEMBERS.contains(name)) { PyType otype = builtins_cache.getObjectType(); // "object" as a closest kin to "module" if (otype != null && name != null) { - ret.addAll(otype.resolveMember(name, null, AccessDirection.READ, myContext)); + ret.addAll(otype.resolveMember(name, null, AccessDirection.READ, myContext, true)); } } } diff --git a/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java b/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java index 466c58c6f9fa..51b4205d5ee9 100644 --- a/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java +++ b/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java @@ -274,7 +274,7 @@ public class ResolveImportUtil { PyType refType = PyReferenceExpressionImpl.getReferenceTypeFromProviders(parent, TypeEvalContext.fast(), null); if (refType != null) { final List result = refType.resolveMember(referencedName, null, AccessDirection.READ, - PyResolveContext.defaultContext()); + PyResolveContext.defaultContext(), true); if (result != null && !result.isEmpty()) { return result.get(0).getElement(); } diff --git a/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java b/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java index b172ec83553b..cd2ad2eaaefa 100644 --- a/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java +++ b/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java @@ -102,7 +102,8 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { public List resolveMember(@NotNull final String name, @Nullable PyExpression location, AccessDirection direction, - PyResolveContext resolveContext) { + PyResolveContext resolveContext, + boolean inherited) { final Set> resolving = ourResolveMemberStack.get(); final Pair key = Pair.create(myClass, name); if (resolving.contains(key)) { @@ -110,7 +111,7 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { } resolving.add(key); try { - return doResolveMember(name, location, direction, resolveContext); + return doResolveMember(name, location, direction, resolveContext, inherited); } finally { resolving.remove(key); @@ -121,7 +122,8 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { private List doResolveMember(@NotNull String name, @Nullable PyExpression location, @NotNull AccessDirection direction, - @NotNull PyResolveContext resolveContext) { + @NotNull PyResolveContext resolveContext, + boolean inherited) { final TypeEvalContext context = resolveContext.getTypeEvalContext(); PsiElement classMember = resolveByOverridingMembersProviders(this, name); //overriding members provers have priority to normal resolve if (classMember != null) { @@ -157,7 +159,7 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { PyClass derived_class = ((PyClassType)first_arg_type).getPyClass(); final Iterator base_it = derived_class.getAncestorClasses(context).iterator(); if (base_it.hasNext()) { - return new PyClassTypeImpl(base_it.next(), true).resolveMember(name, location, direction, resolveContext); + return new PyClassTypeImpl(base_it.next(), true).resolveMember(name, location, direction, resolveContext, true); } else { return null; // no base classes = super() cannot proxy anything meaningful from a base class @@ -171,17 +173,19 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { return ResolveResultList.to(classMember); } - for (PyClassLikeType type : myClass.getAncestorTypes(context)) { - if (type instanceof PyClassType) { - PsiElement superMember = resolveClassMember(((PyClassType)type).getPyClass(), myIsDefinition, name, null); - if (superMember != null) { - return ResolveResultList.to(superMember); + if (inherited) { + for (PyClassLikeType type : myClass.getAncestorTypes(context)) { + if (type instanceof PyClassType) { + PsiElement superMember = resolveClassMember(((PyClassType)type).getPyClass(), myIsDefinition, name, null); + if (superMember != null) { + return ResolveResultList.to(superMember); + } } - } - if (type != null) { - final List results = type.resolveMember(name, location, direction, resolveContext); - if (results != null && !results.isEmpty()) { - return results; + else if (type != null) { + final List results = type.resolveMember(name, location, direction, resolveContext, false); + if (results != null && !results.isEmpty()) { + return results; + } } } } @@ -189,27 +193,31 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { if (isDefinition() && myClass.isNewStyleClass()) { PyClassType typeType = getMetaclassType(); if (typeType != null) { - List typeMembers = typeType.resolveMember(name, location, direction, resolveContext); + List typeMembers = typeType.resolveMember(name, location, direction, resolveContext, true); if (typeMembers != null && !typeMembers.isEmpty()) { return typeMembers; } } } - classMember = resolveByMembersProviders(this, name); //ask providers after real class introspection as providers have less priority + if (inherited) { + classMember = resolveByMembersProviders(this, name); //ask providers after real class introspection as providers have less priority + } if (classMember != null) { return ResolveResultList.to(classMember); } - for (PyClassLikeType type : myClass.getAncestorTypes(context)) { - if (type instanceof PyClassType) { - final PyClass pyClass = ((PyClassType)type).getPyClass(); - if (pyClass != null) { - PsiElement superMember = resolveByMembersProviders(new PyClassTypeImpl(pyClass, isDefinition()), name); + if (inherited) { + for (PyClassLikeType type : myClass.getAncestorTypes(context)) { + if (type instanceof PyClassType) { + final PyClass pyClass = ((PyClassType)type).getPyClass(); + if (pyClass != null) { + PsiElement superMember = resolveByMembersProviders(new PyClassTypeImpl(pyClass, isDefinition()), name); - if (superMember != null) { - return ResolveResultList.to(superMember); + if (superMember != null) { + return ResolveResultList.to(superMember); + } } } } diff --git a/python/src/com/jetbrains/python/psi/types/PyFunctionType.java b/python/src/com/jetbrains/python/psi/types/PyFunctionType.java index 3bbfce984a95..e2ff1f05826c 100644 --- a/python/src/com/jetbrains/python/psi/types/PyFunctionType.java +++ b/python/src/com/jetbrains/python/psi/types/PyFunctionType.java @@ -37,7 +37,7 @@ public class PyFunctionType implements PyCallableType { public List resolveMember(@NotNull String name, @Nullable PyExpression location, AccessDirection direction, - PyResolveContext resolveContext) { + PyResolveContext resolveContext, boolean inherited) { return Collections.emptyList(); } diff --git a/python/src/com/jetbrains/python/psi/types/PyGenericType.java b/python/src/com/jetbrains/python/psi/types/PyGenericType.java index 9c0b0245c764..649bc72e3281 100644 --- a/python/src/com/jetbrains/python/psi/types/PyGenericType.java +++ b/python/src/com/jetbrains/python/psi/types/PyGenericType.java @@ -25,7 +25,7 @@ public class PyGenericType implements PyType { public List resolveMember(@NotNull String name, @Nullable PyExpression location, AccessDirection direction, - PyResolveContext resolveContext) { + PyResolveContext resolveContext, boolean inherited) { return null; } diff --git a/python/src/com/jetbrains/python/psi/types/PyImportedModuleType.java b/python/src/com/jetbrains/python/psi/types/PyImportedModuleType.java index fd4b93f5f7fe..cfa0d325d2a6 100644 --- a/python/src/com/jetbrains/python/psi/types/PyImportedModuleType.java +++ b/python/src/com/jetbrains/python/psi/types/PyImportedModuleType.java @@ -38,11 +38,11 @@ public class PyImportedModuleType implements PyType { public List resolveMember(@NotNull String name, PyExpression location, AccessDirection direction, - PyResolveContext resolveContext) { + PyResolveContext resolveContext, boolean inherited) { final PsiElement resolved = myImportedModule.resolve(); if (resolved instanceof PyFile) { final PyFile file = (PyFile)resolved; - return new PyModuleType(file, myImportedModule).resolveMember(name, location, direction, resolveContext); + return new PyModuleType(file, myImportedModule).resolveMember(name, location, direction, resolveContext, true); } else if (resolved instanceof PsiDirectory) { final List elements = Collections.singletonList(ResolveImportUtil.resolveChild(resolved, name, null, true, true)); diff --git a/python/src/com/jetbrains/python/psi/types/PyModuleType.java b/python/src/com/jetbrains/python/psi/types/PyModuleType.java index 6a16835a05c9..79cb39fff107 100644 --- a/python/src/com/jetbrains/python/psi/types/PyModuleType.java +++ b/python/src/com/jetbrains/python/psi/types/PyModuleType.java @@ -62,7 +62,7 @@ public class PyModuleType implements PyType { // Modules don't descend from obje public List resolveMember(@NotNull final String name, @Nullable PyExpression location, AccessDirection direction, - PyResolveContext resolveContext) { + PyResolveContext resolveContext, boolean inherited) { for (PyModuleMembersProvider provider : Extensions.getExtensions(PyModuleMembersProvider.EP_NAME)) { final PsiElement element = provider.resolveMember(myModule, name); if (element != null) { diff --git a/python/src/com/jetbrains/python/psi/types/PyNoneType.java b/python/src/com/jetbrains/python/psi/types/PyNoneType.java index e34ba6f94c6c..2905f46abbe7 100644 --- a/python/src/com/jetbrains/python/psi/types/PyNoneType.java +++ b/python/src/com/jetbrains/python/psi/types/PyNoneType.java @@ -24,7 +24,7 @@ public class PyNoneType implements PyType { // TODO must extend ClassType. It's public List resolveMember(@NotNull final String name, PyExpression location, AccessDirection direction, - PyResolveContext resolveContext) { + PyResolveContext resolveContext, boolean inherited) { return null; } diff --git a/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java b/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java index 50b05c8abac5..020f2acf4d35 100644 --- a/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java +++ b/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java @@ -7,7 +7,6 @@ import com.intellij.psi.ResolveResult; import com.jetbrains.python.PyNames; import com.jetbrains.python.codeInsight.stdlib.PyStdlibTypeProvider; import com.jetbrains.python.psi.*; -import com.jetbrains.python.psi.impl.PyBuiltinCache; import com.jetbrains.python.psi.resolve.PyResolveContext; import com.jetbrains.python.psi.resolve.RatedResolveResult; import org.jetbrains.annotations.NotNull; @@ -465,7 +464,8 @@ public class PyTypeChecker { for (PyType member : unionType.getMembers()) { if (member != null) { final PyResolveContext resolveContext = PyResolveContext.noImplicits().withTypeEvalContext(context); - final List results = member.resolveMember(name, callee, AccessDirection.READ, resolveContext); + final List results = member.resolveMember(name, callee, AccessDirection.READ, resolveContext, + true); if (results != null && !results.isEmpty()) { sameNameCount++; } diff --git a/python/src/com/jetbrains/python/psi/types/PyTypeParser.java b/python/src/com/jetbrains/python/psi/types/PyTypeParser.java index f7e20b6c94d2..0a6ea6067ada 100644 --- a/python/src/com/jetbrains/python/psi/types/PyTypeParser.java +++ b/python/src/com/jetbrains/python/psi/types/PyTypeParser.java @@ -241,7 +241,7 @@ public class PyTypeParser { final String shortName = classRange.substring(qName); if (moduleType != null) { final PyResolveContext context = PyResolveContext.defaultContext(); - final List results = moduleType.resolveMember(shortName, null, AccessDirection.READ, context); + final List results = moduleType.resolveMember(shortName, null, AccessDirection.READ, context, true); if (results != null && !results.isEmpty()) { final RatedResolveResult result = results.get(0); final PsiElement resolved = result.getElement(); diff --git a/python/src/com/jetbrains/python/psi/types/PyTypeReferenceImpl.java b/python/src/com/jetbrains/python/psi/types/PyTypeReferenceImpl.java index 1727ed264e64..2077c55afb5e 100644 --- a/python/src/com/jetbrains/python/psi/types/PyTypeReferenceImpl.java +++ b/python/src/com/jetbrains/python/psi/types/PyTypeReferenceImpl.java @@ -23,7 +23,7 @@ public abstract class PyTypeReferenceImpl implements PyTypeReference { public List resolveMember(@NotNull String name, PyExpression location, AccessDirection direction, - PyResolveContext resolveContext) { + PyResolveContext resolveContext, boolean inherited) { return Collections.emptyList(); } diff --git a/python/src/com/jetbrains/python/psi/types/PyUnionType.java b/python/src/com/jetbrains/python/psi/types/PyUnionType.java index 466733d97b4f..ca774a21f61a 100644 --- a/python/src/com/jetbrains/python/psi/types/PyUnionType.java +++ b/python/src/com/jetbrains/python/psi/types/PyUnionType.java @@ -27,12 +27,12 @@ public class PyUnionType implements PyType { public List resolveMember(@NotNull String name, PyExpression location, AccessDirection direction, - PyResolveContext resolveContext) { + PyResolveContext resolveContext, boolean inherited) { SmartList ret = new SmartList(); boolean all_nulls = true; for (PyType member : myMembers) { if (member != null) { - List result = member.resolveMember(name, null, direction, resolveContext); + List result = member.resolveMember(name, null, direction, resolveContext, true); if (result != null) { all_nulls = false; ret.addAll(result); diff --git a/python/testData/codeInsight/controlflow/break.txt b/python/testData/codeInsight/controlflow/break.txt index f00c85098ebb..251976aa5e0f 100644 --- a/python/testData/codeInsight/controlflow/break.txt +++ b/python/testData/codeInsight/controlflow/break.txt @@ -1,11 +1,12 @@ 0(1) element: null 1(2) element: PyWhileStatement -2(3,10) READ ACCESS: foo +2(3,11) READ ACCESS: foo 3(4) element: PyStatementList. Condition: foo:true 4(5) element: PyIfStatement 5(6,9) READ ACCESS: condition 6(7) element: PyStatementList. Condition: condition:true 7(8) ASSERTTYPE ACCESS: condition -8(10) element: PyBreakStatement -9(1) element: PyPrintStatement -10() element: null \ No newline at end of file +8(11) element: PyBreakStatement +9(10) ASSERTTYPE ACCESS: condition +10(1) element: PyPrintStatement +11() element: null diff --git a/python/testData/codeInsight/controlflow/continue.txt b/python/testData/codeInsight/controlflow/continue.txt index 0da087d6cfe7..6c8a8ef79391 100644 --- a/python/testData/codeInsight/controlflow/continue.txt +++ b/python/testData/codeInsight/controlflow/continue.txt @@ -1,11 +1,12 @@ 0(1) element: null 1(2) element: PyWhileStatement -2(3,10) READ ACCESS: foo +2(3,11) READ ACCESS: foo 3(4) element: PyStatementList. Condition: foo:true 4(5) element: PyIfStatement 5(6,9) READ ACCESS: condition 6(7) element: PyStatementList. Condition: condition:true 7(8) ASSERTTYPE ACCESS: condition 8(1) element: PyContinueStatement -9(1) element: PyPrintStatement -10() element: null \ No newline at end of file +9(10) ASSERTTYPE ACCESS: condition +10(1) element: PyPrintStatement +11() element: null diff --git a/python/testData/codeInsight/controlflow/ifelsereturn.txt b/python/testData/codeInsight/controlflow/ifelsereturn.txt index d0513796c26a..482f55a7af78 100644 --- a/python/testData/codeInsight/controlflow/ifelsereturn.txt +++ b/python/testData/codeInsight/controlflow/ifelsereturn.txt @@ -6,12 +6,13 @@ 5(6) element: PyTryExceptStatement 6(7,9) element: PyTryPart 7(8,9) element: PyReturnStatement -8(9,16) READ ACCESS: renderer +8(9,17) READ ACCESS: renderer 9(10) element: PyExceptPart 10(11) READ ACCESS: KeyError 11(12) element: PyRaiseStatement -12(16) READ ACCESS: Error +12(17) READ ACCESS: Error 13(14) element: PyElsePart. Condition: markup:false -14(15) element: PyReturnStatement -15(16) READ ACCESS: body -16() element: null \ No newline at end of file +14(15) ASSERTTYPE ACCESS: markup +15(16) element: PyReturnStatement +16(17) READ ACCESS: body +17() element: null diff --git a/python/testData/codeInsight/controlflow/isinstance.txt b/python/testData/codeInsight/controlflow/isinstance.txt index f7459afa9508..9540334ec50f 100644 --- a/python/testData/codeInsight/controlflow/isinstance.txt +++ b/python/testData/codeInsight/controlflow/isinstance.txt @@ -9,9 +9,10 @@ 8(9) ASSERTTYPE ACCESS: s 9(10) element: PyAssignmentStatement 10(11) READ ACCESS: s -11(16) WRITE ACCESS: s2 +11(17) WRITE ACCESS: s2 12(13) element: PyElsePart. Condition: (isinstance(s, basestring)):false -13(14) element: PyAssignmentStatement -14(15) READ ACCESS: s -15(16) WRITE ACCESS: x -16() element: null \ No newline at end of file +13(14) ASSERTTYPE ACCESS: s +14(15) element: PyAssignmentStatement +15(16) READ ACCESS: s +16(17) WRITE ACCESS: x +17() element: null diff --git a/python/testData/codeInsight/controlflow/return.txt b/python/testData/codeInsight/controlflow/return.txt index 00235aed635c..b701e7e6a9ed 100644 --- a/python/testData/codeInsight/controlflow/return.txt +++ b/python/testData/codeInsight/controlflow/return.txt @@ -1,11 +1,12 @@ 0(1) element: null 1(2) element: PyWhileStatement -2(3,10) READ ACCESS: foo +2(3,11) READ ACCESS: foo 3(4) element: PyStatementList. Condition: foo:true 4(5) element: PyIfStatement 5(6,9) READ ACCESS: condition 6(7) element: PyStatementList. Condition: condition:true 7(8) ASSERTTYPE ACCESS: condition -8(10) element: PyReturnStatement -9(1) element: PyPrintStatement -10() element: null \ No newline at end of file +8(11) element: PyReturnStatement +9(10) ASSERTTYPE ACCESS: condition +10(1) element: PyPrintStatement +11() element: null diff --git a/python/testData/codeInsight/controlflow/while.txt b/python/testData/codeInsight/controlflow/while.txt index 92ff8994097b..ec6e39392afb 100644 --- a/python/testData/codeInsight/controlflow/while.txt +++ b/python/testData/codeInsight/controlflow/while.txt @@ -17,7 +17,7 @@ 16(17) element: PyAssignmentStatement 17(18) WRITE ACCESS: c 18(19) element: PyWhileStatement -19(20,30) READ ACCESS: c3 +19(20,31) READ ACCESS: c3 20(21) element: PyStatementList. Condition: c3:true 21(22) element: PyAssignmentStatement 22(23) WRITE ACCESS: m @@ -25,9 +25,10 @@ 24(25,28) READ ACCESS: m 25(26) element: PyStatementList. Condition: m:true 26(27) ASSERTTYPE ACCESS: m -27(32) element: PyBreakStatement -28(29) element: PyAssignmentStatement -29(18) WRITE ACCESS: n -30(31) element: PyAssignmentStatement -31(32) WRITE ACCESS: o -32() element: null \ No newline at end of file +27(33) element: PyBreakStatement +28(29) ASSERTTYPE ACCESS: m +29(30) element: PyAssignmentStatement +30(18) WRITE ACCESS: n +31(32) element: PyAssignmentStatement +32(33) WRITE ACCESS: o +33() element: null diff --git a/python/testData/inspections/PyTypeCheckerInspection/NegativeIsInstance.py b/python/testData/inspections/PyTypeCheckerInspection/NegativeIsInstance.py new file mode 100644 index 000000000000..1de86d74b03f --- /dev/null +++ b/python/testData/inspections/PyTypeCheckerInspection/NegativeIsInstance.py @@ -0,0 +1,19 @@ +def method_a(): + """ + :rtype: dict or int + """ + pass + + +def method_b(d): + """ + :type d: dict + """ + pass + + +def f(): + var = method_a() + if isinstance(var, int): + return var + method_b(var) # pass \ No newline at end of file diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/negativeAssertType.py b/python/testData/inspections/PyUnresolvedReferencesInspection/negativeAssertType.py new file mode 100644 index 000000000000..b42d0ccd5657 --- /dev/null +++ b/python/testData/inspections/PyUnresolvedReferencesInspection/negativeAssertType.py @@ -0,0 +1,5 @@ +def f(c): + x = 'foo' if c else ['f', 'o', 'o'] + if not isinstance(x, str): + raise TypeError('foo') + return x.pop() # should warn about using 'pop()' on a 'str' instance diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/negativeIf.py b/python/testData/inspections/PyUnresolvedReferencesInspection/negativeIf.py new file mode 100644 index 000000000000..c91c29712873 --- /dev/null +++ b/python/testData/inspections/PyUnresolvedReferencesInspection/negativeIf.py @@ -0,0 +1,4 @@ +def f(x): + if x: + return x + return x.upper(), 2 + x diff --git a/python/testSrc/com/jetbrains/python/PyTypeTest.java b/python/testSrc/com/jetbrains/python/PyTypeTest.java index d023461516fe..7c32aff8999c 100644 --- a/python/testSrc/com/jetbrains/python/PyTypeTest.java +++ b/python/testSrc/com/jetbrains/python/PyTypeTest.java @@ -340,6 +340,15 @@ public class PyTypeTest extends PyTestCase { assertNull(actual); } + // PY-9590 + public void testYieldParensType() { + PyExpression expr = parseExpr("def f():\n" + + " expr = (yield 2)\n"); + TypeEvalContext context = TypeEvalContext.slow().withTracing(); + PyType actual = context.getType(expr); + assertNull(actual); + } + // PY-6702 public void testYieldFromType() { PythonLanguageLevelPusher.setForcedLanguageLevel(myFixture.getProject(), LanguageLevel.PYTHON33); @@ -477,6 +486,17 @@ public class PyTypeTest extends PyTestCase { "expr = f()\n"); } + // PY-5084 + public void testIfIsInstanceElse() { + doTest("str", + "def test(c):\n" + + " x = 'foo' if c else 42\n" + + " if isinstance(x, int):\n" + + " print(x)\n" + + " else:\n" + + " expr = x\n"); + } + private PyExpression parseExpr(String text) { myFixture.configureByText(PythonFileType.INSTANCE, text); return myFixture.findElementByText("expr", PyExpression.class); diff --git a/python/testSrc/com/jetbrains/python/inspections/PyTypeCheckerInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyTypeCheckerInspectionTest.java index 2c6a3119b618..f561664f9e4b 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyTypeCheckerInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyTypeCheckerInspectionTest.java @@ -160,4 +160,9 @@ public class PyTypeCheckerInspectionTest extends PyTestCase { public void testBytesSubclassAsStr() { doTest(); } + + // PY-9118 + public void testNegativeIsInstance() { + doTest(); + } } diff --git a/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java index da626814890c..d64bde673520 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java @@ -267,6 +267,15 @@ public class PyUnresolvedReferencesInspectionTest extends PyTestCase { doTest(); } + // PY-7694 + public void testNegativeAssertType() { + doTest(); + } + + public void testNegativeIf() { + doTest(); + } + private void doTest() { myFixture.configureByFile(TEST_DIRECTORY + getTestName(true) + ".py"); myFixture.enableInspections(PyUnresolvedReferencesInspection.class);