From ce70c75c699f5aa117638a2200cbb512adb91b53 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Thu, 20 Jan 2011 20:23:45 +0100 Subject: [PATCH] cleanup for resolve of class members; prefer resolving to definition of instance variable in containing method rather than in first method of class (PY-2740) --- .../python/psi/impl/PyJavaClassType.java | 5 +- python/src/com/jetbrains/python/PyNames.java | 2 + .../PyCallingNonCallableInspection.java | 2 +- .../PyStatementEffectInspection.java | 4 +- .../python/psi/impl/PropertyBunch.java | 5 +- .../python/psi/impl/PyClassImpl.java | 25 +++++++--- .../python/psi/impl/PyNamedParameterImpl.java | 1 - .../psi/impl/PyQualifiedReferenceImpl.java | 27 +++------- .../psi/impl/PyReferenceExpressionImpl.java | 49 +++++++++++-------- .../python/psi/impl/PyReferenceImpl.java | 2 +- .../psi/impl/PyTargetExpressionImpl.java | 9 +++- .../python/psi/types/PyClassType.java | 17 ++++--- .../psi/types/PyImportedModuleType.java | 5 +- .../python/psi/types/PyModuleType.java | 5 +- .../python/psi/types/PyNoneType.java | 5 +- .../jetbrains/python/psi/types/PyType.java | 10 ++-- .../python/psi/types/PyTypeReferenceImpl.java | 5 +- .../python/psi/types/PyUnionType.java | 7 ++- .../testData/resolve/RedeclaredInstanceVar.py | 15 ++++++ .../com/jetbrains/python/PyResolveTest.java | 4 ++ 20 files changed, 131 insertions(+), 73 deletions(-) create mode 100644 python/testData/resolve/RedeclaredInstanceVar.py diff --git a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java index 251fb49fca17..babdfd98e67f 100644 --- a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java +++ b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java @@ -24,7 +24,10 @@ public class PyJavaClassType implements PyType { } @Nullable - public List resolveMember(final String name, AccessDirection direction, PyResolveContext resolveContext) { + public List resolveMember(final String name, + PyExpression location, + AccessDirection direction, + PyResolveContext resolveContext) { final PsiMethod[] methods = myClass.findMethodsByName(name, true); if (methods.length > 0) { return Arrays.asList(methods); // TODO[yole]: correct resolve diff --git a/python/src/com/jetbrains/python/PyNames.java b/python/src/com/jetbrains/python/PyNames.java index fe0622bb0554..5515224445f5 100644 --- a/python/src/com/jetbrains/python/PyNames.java +++ b/python/src/com/jetbrains/python/PyNames.java @@ -36,6 +36,8 @@ public class PyNames { @NonNls public static final String CLASSMETHOD = "classmethod"; @NonNls public static final String STATICMETHOD = "staticmethod"; + @NonNls public static final String PROPERTY = "property"; + @NonNls public static final String ALL = "__all__"; @NonNls public static final String SLOTS = "__slots__"; @NonNls public static final String DEBUG = "__debug__"; diff --git a/python/src/com/jetbrains/python/inspections/PyCallingNonCallableInspection.java b/python/src/com/jetbrains/python/inspections/PyCallingNonCallableInspection.java index 3c7a13f0ec3e..a810bb630098 100644 --- a/python/src/com/jetbrains/python/inspections/PyCallingNonCallableInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyCallingNonCallableInspection.java @@ -51,7 +51,7 @@ public class PyCallingNonCallableInspection extends PyInspection { return; } if (!classType.isDefinition()) { - final List calls = classType.resolveMember("__call__", AccessDirection.READ, + final List calls = classType.resolveMember("__call__", null, AccessDirection.READ, PyResolveContext.defaultContext().withTypeEvalContext(myTypeEvalContext)); if (calls == null || calls.size() == 0) { PyClass pyClass = classType.getPyClass(); diff --git a/python/src/com/jetbrains/python/inspections/PyStatementEffectInspection.java b/python/src/com/jetbrains/python/inspections/PyStatementEffectInspection.java index c6bc44206920..d3a93503ac46 100644 --- a/python/src/com/jetbrains/python/inspections/PyStatementEffectInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyStatementEffectInspection.java @@ -95,7 +95,7 @@ public class PyStatementEffectInspection extends PyInspection { PyType type = myTypeEvalContext.getType(binary.getLeftExpression()); if (type != null && !type.isBuiltin() && - type.resolveMember(method, AccessDirection.READ, PyResolveContext.defaultContext()) != null) { + type.resolveMember(method, null, AccessDirection.READ, PyResolveContext.defaultContext()) != null) { return true; } final PyExpression rhs = binary.getRightExpression(); @@ -103,7 +103,7 @@ public class PyStatementEffectInspection extends PyInspection { type = myTypeEvalContext.getType(rhs); if (type != null) { String rmethod = "__r" + method.substring(2); // __add__ -> __radd__ - if (!type.isBuiltin() && type.resolveMember(rmethod, AccessDirection.READ, PyResolveContext.defaultContext()) != null) { + if (!type.isBuiltin() && type.resolveMember(rmethod, null, AccessDirection.READ, PyResolveContext.defaultContext()) != null) { return true; } } diff --git a/python/src/com/jetbrains/python/psi/impl/PropertyBunch.java b/python/src/com/jetbrains/python/psi/impl/PropertyBunch.java index 1ef347def7ea..3e9a9835b4c7 100644 --- a/python/src/com/jetbrains/python/psi/impl/PropertyBunch.java +++ b/python/src/com/jetbrains/python/psi/impl/PropertyBunch.java @@ -4,6 +4,7 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.ArrayUtil; +import com.jetbrains.python.PyNames; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.resolve.PyResolveUtil; import com.jetbrains.python.psi.resolve.ResolveProcessor; @@ -54,7 +55,7 @@ public abstract class PropertyBunch { @Nullable - protected static PyCallExpression findPropertyCallSite(@Nullable PyExpression source) { + public static PyCallExpression findPropertyCallSite(@Nullable PyExpression source) { if (source instanceof PyCallExpression) { final PyCallExpression call = (PyCallExpression)source; PyExpression callee = call.getCallee(); @@ -64,7 +65,7 @@ public abstract class PropertyBunch { boolean is_inside_builtins = false; PsiFile psifile = source.getContainingFile(); is_inside_builtins = psifile != null && psifile.getUserData(PyBuiltinCache.MARKER_KEY) != null; - if ("property".equals(callee.getName()) && (is_inside_builtins || !resolvesLocally(ref))) { + if (PyNames.PROPERTY.equals(callee.getName()) && (is_inside_builtins || !resolvesLocally(ref))) { // we assume that a non-local name 'property' is a built-in name. // ref.resolve() is not used because we run in stub building phase where resolve() is frowned upon. // NOTE: this logic fails if (quite unusually) name 'property' is directly imported from builtins. diff --git a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java index 645e3c447ef5..92ea85b16130 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java @@ -420,7 +420,7 @@ public class PyClassImpl extends PyPresentableElementImpl implement for (PyDecorator deco : decolist.getDecorators()) { PyQualifiedName deco_name = deco.getQualifiedName(); if (deco_name != null) { - if (deco_name.matches("property")) { + if (deco_name.matches(PyNames.PROPERTY)) { getter = new Maybe(method); } else if (advanced && deco_name.matches(name, "setter")) { @@ -680,7 +680,7 @@ public class PyClassImpl extends PyPresentableElementImpl implement final PyFunction[] methods = getMethods(); for (PyFunction method : methods) { if (!PyNames.INIT.equals(method.getName())) { - collectInstanceAttributes((PyFunctionImpl)method, result); + collectInstanceAttributes(method, result); } } @@ -688,7 +688,7 @@ public class PyClassImpl extends PyPresentableElementImpl implement return new ArrayList(expressions); } - private static void collectInstanceAttributes(PyFunctionImpl method, final Map result) { + private static void collectInstanceAttributes(PyFunction method, final Map result) { final PyParameter[] params = method.getParameterList().getParameters(); if (params.length == 0) { return; @@ -761,9 +761,9 @@ public class PyClassImpl extends PyPresentableElementImpl implement return false; } - public void processDeclarations(@NotNull PsiScopeProcessor processor) { + public void processDeclarations(@NotNull PsiScopeProcessor processor, @Nullable PyExpression location) { if (!processClassLevelDeclarations(processor)) return; - if (!processInstanceLevelDeclarations(processor)) return; + if (!processInstanceLevelDeclarations(processor, location)) return; processor.execute(this, ResolveState.initial()); } @@ -784,8 +784,21 @@ public class PyClassImpl extends PyPresentableElementImpl implement return true; } - public boolean processInstanceLevelDeclarations(PsiScopeProcessor processor) { + public boolean processInstanceLevelDeclarations(PsiScopeProcessor processor, @Nullable PyExpression location) { + Map declarationsInMethod = new HashMap(); + PyFunction instanceMethod = PsiTreeUtil.getParentOfType(location, PyFunction.class); + if (instanceMethod != null && instanceMethod.getContainingClass() == this) { + collectInstanceAttributes(instanceMethod, declarationsInMethod); + for (PyTargetExpression targetExpression : declarationsInMethod.values()) { + if (!processor.execute(targetExpression, ResolveState.initial())) { + return false; + } + } + } for(PyTargetExpression expr: getInstanceAttributes()) { + if (declarationsInMethod.containsKey(expr.getName())) { + continue; + } if (!processor.execute(expr, ResolveState.initial())) return false; } return true; diff --git a/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java b/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java index e88e976dc5aa..2004b4e5d162 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java @@ -3,7 +3,6 @@ package com.jetbrains.python.psi.impl; import com.intellij.lang.ASTNode; import com.intellij.openapi.extensions.Extensions; import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiPolyVariantReference; import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.search.SearchScope; import com.intellij.psi.util.PsiTreeUtil; diff --git a/python/src/com/jetbrains/python/psi/impl/PyQualifiedReferenceImpl.java b/python/src/com/jetbrains/python/psi/impl/PyQualifiedReferenceImpl.java index d5fa7229671a..dc4f5b1d85fa 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyQualifiedReferenceImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyQualifiedReferenceImpl.java @@ -51,19 +51,19 @@ public class PyQualifiedReferenceImpl extends PyReferenceImpl { if (qualifierType != null && !(qualifierType instanceof PyTypeReference)) { // resolve within the type proper AccessDirection ctx = AccessDirection.of(myElement); - final List member_of_qualifier = qualifierType.resolveMember(referencedName, ctx, myContext); - if (member_of_qualifier == null) { + final List membersOfQualifier = qualifierType.resolveMember(referencedName, qualifier, ctx, myContext); + if (membersOfQualifier == null) { return ret; // qualifier is positive that such name cannot exist in it } - for (PsiElement resolved : member_of_qualifier) { + int rate = RatedResolveResult.RATE_NORMAL; + for (PsiElement resolved : membersOfQualifier) { PsiElement ref_elt = PyUtil.turnDirIntoInit(resolved); - if (ref_elt != null) ret.poke(ref_elt, RatedResolveResult.RATE_NORMAL); - // NOTE: maybe rate non-first results lower. + if (ref_elt != null) ret.poke(ref_elt, rate); + rate = RatedResolveResult.RATE_LOW; } - // resolve within the type proper - addResolveMember(ret, referencedName, qualifierType, ctx); + // enrich the type info with any fields assigned nearby - if (qualifier instanceof PyQualifiedExpression && !ret.isEmpty()) { + if (qualifier instanceof PyQualifiedExpression && ret.isEmpty()) { if (addAssignedAttributes(ret, referencedName, qualifier)) return ret; } } @@ -82,17 +82,6 @@ public class PyQualifiedReferenceImpl extends PyReferenceImpl { return ret; } - private void addResolveMember(ResultList ret, String referencedName, PyType qualifierType, AccessDirection context) { - final List members = qualifierType.resolveMember(referencedName, context, myContext); - if (members != null) { - int rate = RatedResolveResult.RATE_NORMAL; - for (PsiElement member : members) { - ret.poke(PyUtil.turnDirIntoInit(member), rate); - rate = RatedResolveResult.RATE_LOW; - } - } - } - private static boolean addAssignedAttributes(ResultList ret, String referencedName, PyExpression qualifier) { List qualifier_path = PyResolveUtil.unwindQualifiers((PyQualifiedExpression)qualifier); if (qualifier_path != null) { diff --git a/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java index 60a9c7d50bae..bd99ff97c29d 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java @@ -3,6 +3,7 @@ package com.jetbrains.python.psi.impl; import com.intellij.lang.ASTNode; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.Extensions; +import com.intellij.openapi.util.Ref; import com.intellij.psi.*; import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.psi.util.PsiTreeUtil; @@ -191,7 +192,6 @@ public class PyReferenceExpressionImpl extends PyElementImpl implements PyRefere } try { final PyExpression qualifier = getQualifier(); - PyType type; if (qualifier == null) { String name = getReferencedName(); if (PyNames.NONE.equals(name)) { @@ -201,27 +201,12 @@ public class PyReferenceExpressionImpl extends PyElementImpl implements PyRefere else { PyType maybe_type = PyUtil.getSpecialAttributeType(this, context); if (maybe_type != null) return maybe_type; - final String name = getName(); - if (name != null) { - PyType qualifier_type = context.getType(qualifier); - if (qualifier_type instanceof PyClassType) { - Property property = ((PyClassType)qualifier_type).getPyClass().findProperty(name); - if (property != null) { - final Maybe accessor = property.getByDirection(AccessDirection.of(this)); - if (!accessor.isDefined()) { - return null; - } - PsiElement resolved = this.getReference().resolve(); // to a correct accessor - if (resolved instanceof Callable) { - type = ((Callable)resolved).getReturnType(context, this); - if (type != null) return type; - } - } - } + Ref typeOfProperty = getTypeOfProperty(context); + if (typeOfProperty != null) { + return typeOfProperty.get(); } - } - type = getTypeFromProviders(context); + PyType type = getTypeFromProviders(context); if (type != null) { return type; } @@ -245,6 +230,30 @@ public class PyReferenceExpressionImpl extends PyElementImpl implements PyRefere } } + @Nullable + public Ref getTypeOfProperty(@NotNull TypeEvalContext context) { + PyExpression qualifier = getQualifier(); + final String name = getName(); + if (name != null && qualifier != null) { + PyType qualifier_type = context.getType(qualifier); + if (qualifier_type instanceof PyClassType) { + Property property = ((PyClassType)qualifier_type).getPyClass().findProperty(name); + if (property != null) { + final Maybe accessor = property.getByDirection(AccessDirection.of(this)); + if (!accessor.isDefined()) { + return Ref.create(null); + } + PsiElement resolved = this.getReference().resolve(); // to a correct accessor + if (resolved instanceof Callable) { + PyType type = ((Callable)resolved).getReturnType(context, this); + if (type != null) return Ref.create(type); + } + } + } + } + return null; + } + @Nullable private PyType getTypeFromProviders(TypeEvalContext context) { for (PyTypeProvider provider : Extensions.getExtensions(PyTypeProvider.EP_NAME)) { diff --git a/python/src/com/jetbrains/python/psi/impl/PyReferenceImpl.java b/python/src/com/jetbrains/python/psi/impl/PyReferenceImpl.java index afa4171a33b3..85c8abf006c9 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyReferenceImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyReferenceImpl.java @@ -193,7 +193,7 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference // ...as a part of current module PyType otype = builtins_cache.getObjectType(); // "object" as a closest kin to "module" if (otype != null) { - final List members = otype.resolveMember(myElement.getName(), AccessDirection.READ, myContext); + final List members = otype.resolveMember(myElement.getName(), null, AccessDirection.READ, myContext); if (members != null) { int rate = RatedResolveResult.RATE_NORMAL; for (PsiElement member : members) { diff --git a/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java index 99e6f810d7b9..777bbeba6b67 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java @@ -3,6 +3,7 @@ package com.jetbrains.python.psi.impl; import com.intellij.lang.ASTNode; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.Ref; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiReference; import com.intellij.psi.ResolveResult; @@ -128,8 +129,8 @@ public class PyTargetExpressionImpl extends PyPresentableElementImpl typeOfProperty = refex.getTypeOfProperty(context); + if (typeOfProperty != null) { + return typeOfProperty.get(); + } return typeFromTarget; } } diff --git a/python/src/com/jetbrains/python/psi/types/PyClassType.java b/python/src/com/jetbrains/python/psi/types/PyClassType.java index a5139b1b06e4..96009e14d129 100644 --- a/python/src/com/jetbrains/python/psi/types/PyClassType.java +++ b/python/src/com/jetbrains/python/psi/types/PyClassType.java @@ -93,7 +93,8 @@ public class PyClassType extends UserDataHolderBase implements PyType { } @Nullable - public List resolveMember(final String name, AccessDirection direction, PyResolveContext resolveContext) { + public List resolveMember(final String name, @Nullable PyExpression location, AccessDirection direction, + PyResolveContext resolveContext) { final Set> resolving = ourResolveMemberStack.get(); final Pair key = Pair.create(myClass, name); if (resolving.contains(key)) { @@ -122,13 +123,13 @@ public class PyClassType extends UserDataHolderBase implements PyType { } } - final PsiElement classMember = resolveClassMember(myClass, name); + final PsiElement classMember = resolveClassMember(myClass, name, location); if (classMember != null) { return new SmartList(classMember); } for (PyClass superClass : myClass.iterateAncestors()) { - PsiElement superMember = resolveClassMember(superClass, name); + PsiElement superMember = resolveClassMember(superClass, name, null); if (superMember != null) { return new SmartList(superMember); } @@ -141,8 +142,8 @@ public class PyClassType extends UserDataHolderBase implements PyType { } @Nullable - private static PsiElement resolveClassMember(PyClass aClass, String name) { - PsiElement result = resolveInner(aClass, name); + private static PsiElement resolveClassMember(PyClass aClass, String name, @Nullable PyExpression location) { + PsiElement result = resolveInner(aClass, name, location); if (result != null) { return result; } @@ -155,9 +156,9 @@ public class PyClassType extends UserDataHolderBase implements PyType { } @Nullable - private static PsiElement resolveInner(PyClass aClass, String name) { + private static PsiElement resolveInner(PyClass aClass, String name, @Nullable PyExpression location) { ResolveProcessor processor = new ResolveProcessor(name); - ((PyClassImpl)aClass).processDeclarations(processor); // our members are strictly within us. + ((PyClassImpl)aClass).processDeclarations(processor, location); // our members are strictly within us. final PsiElement resolveResult = processor.getResult(); //final PsiElement resolveResult = PyResolveUtil.treeWalkUp(new PyResolveUtil.ResolveProcessor(name), myClass, null, null); if (resolveResult != null && resolveResult != aClass) { @@ -212,7 +213,7 @@ public class PyClassType extends UserDataHolderBase implements PyType { if (slots != null) { processor.setAllowedNames(slots); } - ((PyClassImpl)myClass).processInstanceLevelDeclarations(processor); + ((PyClassImpl)myClass).processInstanceLevelDeclarations(processor, expressionHook); for (LookupElement le : processor.getResultList()) { String name = le.getLookupString(); diff --git a/python/src/com/jetbrains/python/psi/types/PyImportedModuleType.java b/python/src/com/jetbrains/python/psi/types/PyImportedModuleType.java index f1d2661c29e0..5d2d9763bdbf 100644 --- a/python/src/com/jetbrains/python/psi/types/PyImportedModuleType.java +++ b/python/src/com/jetbrains/python/psi/types/PyImportedModuleType.java @@ -29,7 +29,10 @@ public class PyImportedModuleType implements PyType { } @NotNull - public List resolveMember(String name, AccessDirection direction, PyResolveContext resolveContext) { + public List resolveMember(String name, + PyExpression location, + AccessDirection direction, + PyResolveContext resolveContext) { final PsiElement element = myImportedModule.getElementNamed(name); if (element != null) { return new SmartList(element); diff --git a/python/src/com/jetbrains/python/psi/types/PyModuleType.java b/python/src/com/jetbrains/python/psi/types/PyModuleType.java index 0dc4e4e94cc3..f6bedf8b4e92 100644 --- a/python/src/com/jetbrains/python/psi/types/PyModuleType.java +++ b/python/src/com/jetbrains/python/psi/types/PyModuleType.java @@ -47,7 +47,10 @@ public class PyModuleType implements PyType { // Modules don't descend from obje } @Nullable - public List resolveMember(final String name, AccessDirection direction, PyResolveContext resolveContext) { + public List resolveMember(final String name, + PyExpression location, + AccessDirection direction, + PyResolveContext resolveContext) { 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 49f19924a5a9..5fa7ed51bb55 100644 --- a/python/src/com/jetbrains/python/psi/types/PyNoneType.java +++ b/python/src/com/jetbrains/python/psi/types/PyNoneType.java @@ -20,7 +20,10 @@ public class PyNoneType implements PyType { // TODO must extend ClassType. It's } @Nullable - public List resolveMember(final String name, AccessDirection direction, PyResolveContext resolveContext) { + public List resolveMember(final String name, + PyExpression location, + AccessDirection direction, + PyResolveContext resolveContext) { return null; } diff --git a/python/src/com/jetbrains/python/psi/types/PyType.java b/python/src/com/jetbrains/python/psi/types/PyType.java index 749004ce1022..97ffea81aafc 100644 --- a/python/src/com/jetbrains/python/psi/types/PyType.java +++ b/python/src/com/jetbrains/python/psi/types/PyType.java @@ -21,15 +21,17 @@ public interface PyType { /** * Resolves an attribute of type. * + * * @param name attribute name - * @param direction - * @param resolveContext - * @return null if name definitely cannot be found (e.g. in a qualified reference), + * @param location the expression of type qualifierType on which the member is being resolved (optional) + *@param direction + * @param resolveContext @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(final String name, AccessDirection direction, PyResolveContext resolveContext); + List resolveMember(final String name, @Nullable PyExpression location, AccessDirection direction, + PyResolveContext resolveContext); /** * Proposes completion variants from type's attributes. diff --git a/python/src/com/jetbrains/python/psi/types/PyTypeReferenceImpl.java b/python/src/com/jetbrains/python/psi/types/PyTypeReferenceImpl.java index 2a1616bb47c8..9fbfb50ab6ee 100644 --- a/python/src/com/jetbrains/python/psi/types/PyTypeReferenceImpl.java +++ b/python/src/com/jetbrains/python/psi/types/PyTypeReferenceImpl.java @@ -16,7 +16,10 @@ import java.util.List; */ public abstract class PyTypeReferenceImpl implements PyTypeReference { @NotNull - public List resolveMember(String name, AccessDirection direction, PyResolveContext resolveContext) { + public List resolveMember(String name, + PyExpression location, + AccessDirection direction, + PyResolveContext resolveContext) { 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 3893935ed141..5fdd143e46d7 100644 --- a/python/src/com/jetbrains/python/psi/types/PyUnionType.java +++ b/python/src/com/jetbrains/python/psi/types/PyUnionType.java @@ -23,12 +23,15 @@ public class PyUnionType implements PyType { } @Nullable - public List resolveMember(String name, AccessDirection direction, PyResolveContext resolveContext) { + public List resolveMember(String name, + PyExpression location, + AccessDirection direction, + PyResolveContext resolveContext) { SmartList ret = new SmartList(); boolean all_nulls = true; for (PyType member : myMembers) { if (member != null) { - List result = member.resolveMember(name, direction, resolveContext); + List result = member.resolveMember(name, null, direction, resolveContext); if (result != null) { all_nulls = false; ret.addAll(result); diff --git a/python/testData/resolve/RedeclaredInstanceVar.py b/python/testData/resolve/RedeclaredInstanceVar.py new file mode 100644 index 000000000000..eef329c11703 --- /dev/null +++ b/python/testData/resolve/RedeclaredInstanceVar.py @@ -0,0 +1,15 @@ +class Manager: + pass + +class Programmer: + def jobsDoneCount(self): + pass + +class EmployeeTest: + def firstMethod(self): + self.deadBeat = Manager() + + def secondMethod(self): + self.deadBeat = Programmer() + self.deadBeat.jobsDoneCount() +# diff --git a/python/testSrc/com/jetbrains/python/PyResolveTest.java b/python/testSrc/com/jetbrains/python/PyResolveTest.java index 22080efc9d4e..99cda9831c75 100644 --- a/python/testSrc/com/jetbrains/python/PyResolveTest.java +++ b/python/testSrc/com/jetbrains/python/PyResolveTest.java @@ -392,4 +392,8 @@ public class PyResolveTest extends PyResolveTestCase { public void testPrivateInsideModule() { // PY-2618 assertResolvesTo(PyClass.class, "__VeryPrivate"); } + + public void testRedeclaredInstanceVar() { // PY-2740 + assertResolvesTo(PyFunction.class, "jobsDoneCount"); + } } \ No newline at end of file