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/psi/impl/PyNamedParameterImpl.java b/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java index 222a98df8a5f..921c43e2b866 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java @@ -244,8 +244,8 @@ public class PyNamedParameterImpl extends PyBaseElementImpl