diff --git a/python/psi-api/src/com/jetbrains/python/PyNames.java b/python/psi-api/src/com/jetbrains/python/PyNames.java
index b82576428c3c..21e5be632d59 100644
--- a/python/psi-api/src/com/jetbrains/python/PyNames.java
+++ b/python/psi-api/src/com/jetbrains/python/PyNames.java
@@ -472,7 +472,7 @@ public class PyNames {
}
public static boolean isRightOperatorName(@Nullable String name) {
- return name != null && name.matches("__r[a-z]+__");
+ return name != null && (name.matches("__r[a-z]+__") || CONTAINS.equals(name));
}
/**
diff --git a/python/psi-api/src/com/jetbrains/python/psi/types/TypeEvalConstraints.java b/python/psi-api/src/com/jetbrains/python/psi/types/TypeEvalConstraints.java
index ebeaf366a6ad..f3a94b336de2 100644
--- a/python/psi-api/src/com/jetbrains/python/psi/types/TypeEvalConstraints.java
+++ b/python/psi-api/src/com/jetbrains/python/psi/types/TypeEvalConstraints.java
@@ -30,14 +30,17 @@ import org.jetbrains.annotations.Nullable;
class TypeEvalConstraints {
final boolean myAllowDataFlow;
final boolean myAllowStubToAST;
+ final boolean myAllowCallContext;
@Nullable final PsiFile myOrigin;
/**
* @see com.jetbrains.python.psi.types.TypeEvalContext
*/
- TypeEvalConstraints(final boolean allowDataFlow, final boolean allowStubToAST, @Nullable final PsiFile origin) {
+ TypeEvalConstraints(final boolean allowDataFlow, final boolean allowStubToAST, final boolean allowCallContext,
+ @Nullable final PsiFile origin) {
myAllowDataFlow = allowDataFlow;
myAllowStubToAST = allowStubToAST;
+ myAllowCallContext = allowCallContext;
myOrigin = origin;
}
@@ -50,6 +53,7 @@ class TypeEvalConstraints {
if (myAllowDataFlow != that.myAllowDataFlow) return false;
if (myAllowStubToAST != that.myAllowStubToAST) return false;
+ if (myAllowCallContext != that.myAllowCallContext) return false;
if (myOrigin != null ? !myOrigin.equals(that.myOrigin) : that.myOrigin != null) return false;
return true;
@@ -60,11 +64,12 @@ class TypeEvalConstraints {
int result = (myAllowDataFlow ? 1 : 0);
result = 31 * result + (myAllowStubToAST ? 1 : 0);
result = 31 * result + (myOrigin != null ? myOrigin.hashCode() : 0);
+ result = 31 * result + (myAllowCallContext ? 1 : 0);
return result;
}
@Override
public String toString() {
- return String.format("TypeEvalConstraints(%b, %b, %s)", myAllowDataFlow, myAllowStubToAST, myOrigin);
+ return String.format("TypeEvalConstraints(%b, %b, %b, %s)", myAllowDataFlow, myAllowStubToAST, myAllowCallContext, myOrigin);
}
}
diff --git a/python/psi-api/src/com/jetbrains/python/psi/types/TypeEvalContext.java b/python/psi-api/src/com/jetbrains/python/psi/types/TypeEvalContext.java
index 002a566eeb39..54af2a23e3c4 100644
--- a/python/psi-api/src/com/jetbrains/python/psi/types/TypeEvalContext.java
+++ b/python/psi-api/src/com/jetbrains/python/psi/types/TypeEvalContext.java
@@ -65,8 +65,8 @@ public class TypeEvalContext {
}
};
- private TypeEvalContext(boolean allowDataFlow, boolean allowStubToAST, @Nullable PsiFile origin) {
- myConstraints = new TypeEvalConstraints(allowDataFlow, allowStubToAST, origin);
+ private TypeEvalContext(boolean allowDataFlow, boolean allowStubToAST, boolean allowCallContext, @Nullable PsiFile origin) {
+ myConstraints = new TypeEvalConstraints(allowDataFlow, allowStubToAST, allowCallContext, origin);
}
@Override
@@ -83,17 +83,29 @@ public class TypeEvalContext {
return myConstraints.myAllowDataFlow || element.getContainingFile() == myConstraints.myOrigin;
}
- public boolean allowLocalUsages(@NotNull PsiElement element) {
- return myConstraints.myAllowStubToAST && myConstraints.myAllowDataFlow && element.getContainingFile() == myConstraints.myOrigin;
+ public boolean allowCallContext(@NotNull PsiElement element) {
+ return myConstraints.myAllowCallContext && element.getContainingFile() == myConstraints.myOrigin;
+ }
+
+ /**
+ * Create a context for code completion.
+ *
+ * It is as detailed as {@link TypeEvalContext#userInitiated(Project, PsiFile)}, but allows inferring types based on the context in which
+ * the analyzed code was called or may be called. Since this is basically guesswork, the results should be used only for code completion.
+ */
+ public static TypeEvalContext codeCompletion(@NotNull final Project project, @Nullable final PsiFile origin) {
+ return CACHE.getContext(project, new TypeEvalContext(true, true, true, origin));
}
/**
* Create the most detailed type evaluation context for user-initiated actions.
*
- * Should be used for code completion, go to definition, find usages, refactorings, documentation.
+ * Should be used go to definition, find usages, refactorings, documentation.
+ *
+ * For code completion see {@link TypeEvalContext#codeCompletion(Project, PsiFile)}.
*/
public static TypeEvalContext userInitiated(@NotNull final Project project, @Nullable final PsiFile origin) {
- return CACHE.getContext(project, new TypeEvalContext(true, true, origin));
+ return CACHE.getContext(project, new TypeEvalContext(true, true, false, origin));
}
/**
@@ -103,20 +115,18 @@ public class TypeEvalContext {
* Inspections should not create a new type evaluation context. They should re-use the context of the inspection session.
*/
public static TypeEvalContext codeAnalysis(@NotNull final Project project, @Nullable final PsiFile origin) {
- return CACHE.getContext(project, new TypeEvalContext(false, false, origin));
+ return CACHE.getContext(project, new TypeEvalContext(false, false, false, origin));
}
/**
* Create the most shallow type evaluation context for code insight purposes when other more detailed contexts are not available.
* It's use should be minimized.
- *
- *
*
* @param project pass project here to enable cache. Pass null if you do not have any project.
* Always do your best to pass project here: it increases performance!
*/
public static TypeEvalContext codeInsightFallback(@Nullable final Project project) {
- final TypeEvalContext anchor = new TypeEvalContext(false, false, null);
+ final TypeEvalContext anchor = new TypeEvalContext(false, false, false, null);
if (project != null) {
return CACHE.getContext(project, anchor);
}
@@ -129,7 +139,7 @@ public class TypeEvalContext {
* Should be used only when normal code insight context is not enough for getting good results.
*/
public static TypeEvalContext deepCodeInsight(@NotNull final Project project) {
- return CACHE.getContext(project, new TypeEvalContext(false, true, null));
+ return CACHE.getContext(project, new TypeEvalContext(false, true, false, null));
}
public TypeEvalContext withTracing() {
diff --git a/python/src/com/jetbrains/python/codeInsight/completion/PyDictKeyNamesCompletionContributor.java b/python/src/com/jetbrains/python/codeInsight/completion/PyDictKeyNamesCompletionContributor.java
index e5b2dcc2dc65..efdb192ae6f4 100644
--- a/python/src/com/jetbrains/python/codeInsight/completion/PyDictKeyNamesCompletionContributor.java
+++ b/python/src/com/jetbrains/python/codeInsight/completion/PyDictKeyNamesCompletionContributor.java
@@ -129,7 +129,7 @@ public class PyDictKeyNamesCompletionContributor extends CompletionContributor {
if (callee == null) return;
final String name = callee.getText();
if ("dict".equals(name)) {
- final TypeEvalContext context = TypeEvalContext.userInitiated(callee.getProject(), callee.getContainingFile());
+ final TypeEvalContext context = TypeEvalContext.codeCompletion(callee.getProject(), callee.getContainingFile());
final PyType type = context.getType(dictConstructor);
if (type != null && type.isBuiltin()) {
final PyArgumentList list = dictConstructor.getArgumentList();
diff --git a/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java b/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java
index 389e4efd15f3..50230b05c795 100644
--- a/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java
+++ b/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java
@@ -15,13 +15,16 @@
*/
package com.jetbrains.python.inspections;
+import com.google.common.collect.Sets;
import com.intellij.codeInspection.LocalInspectionToolSession;
import com.intellij.codeInspection.ProblemHighlightType;
import com.intellij.codeInspection.ProblemsHolder;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Key;
+import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementVisitor;
+import com.intellij.util.Function;
import com.intellij.util.containers.hash.LinkedHashMap;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.documentation.PythonDocumentationProvider;
@@ -32,6 +35,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Map;
+import java.util.Set;
/**
* @author vlan
@@ -108,26 +112,45 @@ public class PyTypeCheckerInspection extends PyInspection {
}
@Nullable
- private String checkTypes(@Nullable PyType superType, @Nullable PyType subType, @Nullable PsiElement node,
+ private String checkTypes(@Nullable PyType expected, @Nullable PyType actual, @Nullable PsiElement node,
@NotNull TypeEvalContext context, @NotNull Map substitutions) {
- if (subType != null && superType != null) {
- if (!PyTypeChecker.match(superType, subType, context, substitutions)) {
- final String superName = PythonDocumentationProvider.getTypeName(superType, context);
- String expected = String.format("'%s'", superName);
- final boolean hasGenerics = PyTypeChecker.hasGenerics(superType, context);
+ if (actual != null && expected != null) {
+ if (!PyTypeChecker.match(expected, actual, context, substitutions)) {
+ final String expectedName = PythonDocumentationProvider.getTypeName(expected, context);
+ String quotedExpectedName = String.format("'%s'", expectedName);
+ final boolean hasGenerics = PyTypeChecker.hasGenerics(expected, context);
ProblemHighlightType highlightType = ProblemHighlightType.GENERIC_ERROR_OR_WARNING;
if (hasGenerics) {
- final PyType subst = PyTypeChecker.substitute(superType, substitutions, context);
- if (subst != null) {
- expected = String.format("'%s' (matched generic type '%s')",
- PythonDocumentationProvider.getTypeName(subst, context),
- superName);
+ final PyType substitute = PyTypeChecker.substitute(expected, substitutions, context);
+ if (substitute != null) {
+ quotedExpectedName = String.format("'%s' (matched generic type '%s')",
+ PythonDocumentationProvider.getTypeName(substitute, context),
+ expectedName);
highlightType = ProblemHighlightType.WEAK_WARNING;
}
}
- final String msg = String.format("Expected type %s, got '%s' instead",
- expected,
- PythonDocumentationProvider.getTypeName(subType, context));
+ final String actualName = PythonDocumentationProvider.getTypeName(actual, context);
+ String msg= String.format("Expected type %s, got '%s' instead", quotedExpectedName, actualName);
+ if (expected instanceof PyStructuralType) {
+ final Set expectedAttributes = ((PyStructuralType)expected).getAttributeNames();
+ final Set actualAttributes = getAttributes(actual);
+ if (actualAttributes != null) {
+ final Sets.SetView missingAttributes = Sets.difference(expectedAttributes, actualAttributes);
+ if (missingAttributes.size() == 1) {
+ msg = String.format("Type '%s' doesn't have expected attribute '%s'", actualName, missingAttributes.iterator().next());
+ }
+ else {
+ msg = String.format("Type '%s' doesn't have expected attributes %s",
+ actualName,
+ StringUtil.join(missingAttributes, new Function() {
+ @Override
+ public String fun(String s) {
+ return String.format("'%s'", s);
+ }
+ }, ", "));
+ }
+ }
+ }
registerProblem(node, msg, highlightType);
return msg;
}
@@ -136,6 +159,17 @@ public class PyTypeCheckerInspection extends PyInspection {
}
}
+ @Nullable
+ private static Set getAttributes(@NotNull PyType type) {
+ if (type instanceof PyStructuralType) {
+ return ((PyStructuralType)type).getAttributeNames();
+ }
+ else if (type instanceof PyClassType) {
+ return PyTypeChecker.getClassAttributes(((PyClassType)type).getPyClass(), true);
+ }
+ return null;
+ }
+
@Override
public void inspectionFinished(@NotNull LocalInspectionToolSession session, @NotNull ProblemsHolder problemsHolder) {
if (LOG.isDebugEnabled()) {
diff --git a/python/src/com/jetbrains/python/inspections/unresolvedReference/PyUnresolvedReferencesInspection.java b/python/src/com/jetbrains/python/inspections/unresolvedReference/PyUnresolvedReferencesInspection.java
index 43bc2a925c1c..781ad21bb88b 100644
--- a/python/src/com/jetbrains/python/inspections/unresolvedReference/PyUnresolvedReferencesInspection.java
+++ b/python/src/com/jetbrains/python/inspections/unresolvedReference/PyUnresolvedReferencesInspection.java
@@ -64,7 +64,6 @@ import com.jetbrains.python.psi.impl.references.PyOperatorReference;
import com.jetbrains.python.psi.resolve.ImportedResolveResult;
import com.jetbrains.python.psi.resolve.PyResolveContext;
import com.jetbrains.python.psi.resolve.QualifiedNameFinder;
-import com.jetbrains.python.psi.resolve.RatedResolveResult;
import com.jetbrains.python.psi.types.*;
import com.jetbrains.python.sdk.PythonSdkType;
import com.jetbrains.python.sdk.skeletons.PySkeletonRefresher;
@@ -705,6 +704,9 @@ public class PyUnresolvedReferencesInspection extends PyInspection {
// this almost always means that we don't know the type, so don't show an error in this case
return true;
}
+ if (type instanceof PyStructuralType && ((PyStructuralType)type).isInferredFromUsages()) {
+ return true;
+ }
if (type instanceof PyImportedModuleType) {
PyImportedModule module = ((PyImportedModuleType)type).getImportedModule();
if (module.resolve() == null) {
@@ -720,7 +722,7 @@ public class PyUnresolvedReferencesInspection extends PyInspection {
}
if (type instanceof PyClassTypeImpl) {
PyClass cls = ((PyClassType)type).getPyClass();
- if (overridesGetAttr(cls, myTypeEvalContext)) {
+ if (PyTypeChecker.overridesGetAttr(cls, myTypeEvalContext)) {
return true;
}
if (cls.findProperty(name, true) != null) {
@@ -910,31 +912,6 @@ public class PyUnresolvedReferencesInspection extends PyInspection {
return callExpression != null && node == callExpression.getCallee();
}
- @Nullable
- private static PsiElement resolveClassMember(@NotNull PyClass cls, @NotNull String name, @NotNull TypeEvalContext context) {
- final PyType type = context.getType(cls);
- if (type != null) {
- final PyResolveContext resolveContext = PyResolveContext.noImplicits().withTypeEvalContext(context);
- final List extends RatedResolveResult> results = type.resolveMember(name, null, AccessDirection.READ, resolveContext);
- if (results != null && !results.isEmpty()) {
- return results.get(0).getElement();
- }
- }
- return null;
- }
-
- private static boolean overridesGetAttr(@NotNull PyClass cls, @NotNull TypeEvalContext context) {
- PsiElement method = resolveClassMember(cls, PyNames.GETATTR, context);
- if (method != null) {
- return true;
- }
- method = resolveClassMember(cls, PyNames.GETATTRIBUTE, context);
- if (method != null && !PyBuiltinCache.getInstance(cls).isBuiltin(method)) {
- return true;
- }
- return false;
- }
-
private static void addPluginQuickFixes(PsiReference reference, final List actions) {
for (PyUnresolvedReferenceQuickFixProvider provider : Extensions.getExtensions(PyUnresolvedReferenceQuickFixProvider.EP_NAME)) {
provider.registerQuickFixes(reference, new Consumer() {
diff --git a/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java b/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java
index e43a51f3de36..f5355dc56bd9 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java
@@ -42,9 +42,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
/**
* @author yole
@@ -246,8 +244,8 @@ public class PyNamedParameterImpl extends PyBaseElementImpl types = new ArrayList();
processLocalCalls(func, new Processor() {
@Override
@@ -276,6 +274,12 @@ public class PyNamedParameterImpl extends PyBaseElementImpl attributes = collectUsedAttributes(context);
+ if (!attributes.isEmpty()) {
+ return new PyStructuralType(attributes, true);
+ }
+ }
}
}
return null;
@@ -286,6 +290,86 @@ public class PyNamedParameterImpl extends PyBaseElementImpl collectUsedAttributes(@NotNull final TypeEvalContext context) {
+ final Set result = new LinkedHashSet();
+ final ScopeOwner owner = ScopeUtil.getScopeOwner(this);
+ final String name = getName();
+ if (owner != null && name != null) {
+ owner.accept(new PyRecursiveElementVisitor() {
+ @Override
+ public void visitPyElement(PyElement node) {
+ if (node instanceof ScopeOwner && node != owner) {
+ return;
+ }
+ if (node instanceof PyQualifiedExpression) {
+ final PyQualifiedExpression expr = (PyQualifiedExpression)node;
+ final PyExpression qualifier = expr.getQualifier();
+ if (qualifier != null) {
+ final String attributeName = expr.getReferencedName();
+ final PyExpression referencedExpr = node instanceof PyBinaryExpression && PyNames.isRightOperatorName(attributeName) ?
+ ((PyBinaryExpression)node).getRightExpression() : qualifier;
+ if (referencedExpr != null) {
+ final PsiReference ref = referencedExpr.getReference();
+ if (ref != null && ref.isReferenceTo(PyNamedParameterImpl.this)) {
+ if (attributeName != null && !result.contains(attributeName)) {
+ result.add(attributeName);
+ }
+ }
+ }
+ }
+ else {
+ final PsiReference ref = expr.getReference();
+ if (ref != null && ref.isReferenceTo(PyNamedParameterImpl.this)) {
+ final PyNamedParameter parameter = getParameterByCallArgument(expr, context);
+ if (parameter != null) {
+ final PyType type = context.getType(parameter);
+ if (type instanceof PyStructuralType) {
+ result.addAll(((PyStructuralType)type).getAttributeNames());
+ }
+ }
+ }
+ }
+ }
+ super.visitPyElement(node);
+ }
+
+ @Override
+ public void visitPyIfStatement(PyIfStatement node) {
+ final PyExpression ifCondition = node.getIfPart().getCondition();
+ if (ifCondition != null) {
+ ifCondition.accept(this);
+ }
+ for (PyIfPart part : node.getElifParts()) {
+ final PyExpression elseIfCondition = part.getCondition();
+ if (elseIfCondition != null) {
+ elseIfCondition.accept(this);
+ }
+ }
+ }
+ });
+ }
+ return result;
+ }
+
+ @Nullable
+ private static PyNamedParameter getParameterByCallArgument(@NotNull PsiElement element, @NotNull TypeEvalContext context) {
+ final PyCallExpression call = PsiTreeUtil.getParentOfType(element, PyCallExpression.class);
+ if (call != null) {
+ final PyArgumentList argumentList = call.getArgumentList();
+ if (argumentList != null) {
+ final PyResolveContext resolveContext = PyResolveContext.noImplicits().withTypeEvalContext(context);
+ final CallArgumentsMapping mapping = argumentList.analyzeCall(resolveContext);
+ for (Map.Entry entry : mapping.getPlainMappedParams().entrySet()) {
+ if (entry.getKey() == element) {
+ return entry.getValue();
+ }
+ }
+ }
+ }
+ return null;
+ }
+
private static void processLocalCalls(@NotNull PyFunction function, @NotNull Processor processor) {
final PsiFile file = function.getContainingFile();
final String name = function.getName();
diff --git a/python/src/com/jetbrains/python/psi/impl/references/KeywordArgumentCompletionUtil.java b/python/src/com/jetbrains/python/psi/impl/references/KeywordArgumentCompletionUtil.java
index e6edd70a516e..8736e54766ac 100644
--- a/python/src/com/jetbrains/python/psi/impl/references/KeywordArgumentCompletionUtil.java
+++ b/python/src/com/jetbrains/python/psi/impl/references/KeywordArgumentCompletionUtil.java
@@ -66,7 +66,7 @@ public class KeywordArgumentCompletionUtil {
visited.add(def);
boolean needSelf = def.getContainingClass() != null && def.getModifier() != PyFunction.Modifier.STATICMETHOD;
final KwArgParameterCollector collector = new KwArgParameterCollector(needSelf, ret);
- final TypeEvalContext context = TypeEvalContext.userInitiated(def.getProject(), def.getContainingFile());
+ final TypeEvalContext context = TypeEvalContext.codeCompletion(def.getProject(), def.getContainingFile());
final List parameters = PyUtil.getParameters(def, context);
for (PyParameter parameter : parameters) {
parameter.accept(collector);
diff --git a/python/src/com/jetbrains/python/psi/impl/references/PyImportReference.java b/python/src/com/jetbrains/python/psi/impl/references/PyImportReference.java
index be7921bd6b22..13100e9c0600 100644
--- a/python/src/com/jetbrains/python/psi/impl/references/PyImportReference.java
+++ b/python/src/com/jetbrains/python/psi/impl/references/PyImportReference.java
@@ -97,7 +97,8 @@ public class PyImportReference extends PyReferenceImpl {
}
PyExpression qualifier = myElement.getQualifier();
- final TypeEvalContext context = TypeEvalContext.userInitiated(myElement.getProject(), CompletionUtil.getOriginalOrSelf(myElement).getContainingFile());
+ final TypeEvalContext context = TypeEvalContext.codeCompletion(myElement.getProject(),
+ CompletionUtil.getOriginalOrSelf(myElement).getContainingFile());
if (qualifier != null) {
// qualifier's type must be module, it should know how to complete
PyType type = context.getType(qualifier);
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 cc772f32554e..070ee1165c36 100644
--- a/python/src/com/jetbrains/python/psi/impl/references/PyQualifiedReference.java
+++ b/python/src/com/jetbrains/python/psi/impl/references/PyQualifiedReference.java
@@ -43,7 +43,10 @@ import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.PyBuiltinCache;
import com.jetbrains.python.psi.impl.PyImportedModule;
import com.jetbrains.python.psi.impl.ResolveResultList;
-import com.jetbrains.python.psi.resolve.*;
+import com.jetbrains.python.psi.resolve.ImplicitResolveResult;
+import com.jetbrains.python.psi.resolve.PyResolveContext;
+import com.jetbrains.python.psi.resolve.QualifiedNameFinder;
+import com.jetbrains.python.psi.resolve.RatedResolveResult;
import com.jetbrains.python.psi.search.PyProjectScopeBuilder;
import com.jetbrains.python.psi.stubs.PyClassNameIndexInsensitive;
import com.jetbrains.python.psi.stubs.PyFunctionNameIndex;
@@ -102,7 +105,8 @@ public class PyQualifiedReference extends PyReferenceImpl {
}
}
- if (PyTypeChecker.isUnknown(qualifierType) &&
+ if ((PyTypeChecker.isUnknown(qualifierType) ||
+ (qualifierType instanceof PyStructuralType && ((PyStructuralType)qualifierType).isInferredFromUsages())) &&
myContext.allowImplicits() && canQualifyAnImplicitName(qualifier, qualifierType)) {
addImplicitResolveResults(referencedName, ret);
}
@@ -260,13 +264,19 @@ public class PyQualifiedReference extends PyReferenceImpl {
}
final PyQualifiedExpression element = CompletionUtil.getOriginalOrSelf(myElement);
- PyType qualifierType = TypeEvalContext.userInitiated(element.getProject(), element.getContainingFile()).getType(qualifier);
+ PyType qualifierType = TypeEvalContext.codeCompletion(element.getProject(), element.getContainingFile()).getType(qualifier);
ProcessingContext ctx = new ProcessingContext();
final Set namesAlready = new HashSet();
ctx.put(PyType.CTX_NAMES, namesAlready);
+ final Collection