From deaf4a013709de69c0e2932f8865b4cf32c40da1 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Wed, 8 May 2013 18:28:13 +0400 Subject: [PATCH 01/12] TypeEvalContext for docstring types inspection from inspection session --- .../python/inspections/PyDocstringTypesInspection.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/python/src/com/jetbrains/python/inspections/PyDocstringTypesInspection.java b/python/src/com/jetbrains/python/inspections/PyDocstringTypesInspection.java index 557c729bf1c5..6116ad2f9e51 100644 --- a/python/src/com/jetbrains/python/inspections/PyDocstringTypesInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyDocstringTypesInspection.java @@ -16,7 +16,6 @@ import com.jetbrains.python.psi.PyStringLiteralExpression; import com.jetbrains.python.psi.types.PyType; import com.jetbrains.python.psi.types.PyTypeChecker; import com.jetbrains.python.psi.types.PyTypeParser; -import com.jetbrains.python.psi.types.TypeEvalContext; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -98,10 +97,10 @@ public class PyDocstringTypesInspection extends PyInspection { } } - private static boolean match(PsiElement anchor, String dynamicTypeName, String specifiedTypeName) { + private boolean match(PsiElement anchor, String dynamicTypeName, String specifiedTypeName) { final PyType dynamicType = PyTypeParser.getTypeByName(anchor, dynamicTypeName); final PyType specifiedType = PyTypeParser.getTypeByName(anchor, specifiedTypeName); - return PyTypeChecker.match(specifiedType, dynamicType, TypeEvalContext.slow()); + return PyTypeChecker.match(specifiedType, dynamicType, myTypeEvalContext); } } From 990006bea2fc2bca688a87df327a5e9eebccbd64 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Wed, 8 May 2013 18:46:27 +0400 Subject: [PATCH 02/12] Fast stub only TypeEvalContext for checking intentions availability and for resolve --- .../codeInsight/intentions/ImportFromToImportIntention.java | 6 ++++-- .../intentions/PyDictConstructorToLiteralFormIntention.java | 2 +- .../jetbrains/python/psi/impl/CallArgumentsMappingImpl.java | 2 +- .../com/jetbrains/python/psi/resolve/ResolveImportUtil.java | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/ImportFromToImportIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/ImportFromToImportIntention.java index 509513ff32cc..b8de041f6085 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/ImportFromToImportIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/ImportFromToImportIntention.java @@ -145,10 +145,12 @@ public class ImportFromToImportIntention implements IntentionAction { PyReferenceExpression ref = import_element.getImportReferenceExpression(); if (ref != null && ref.isValid()) { PsiElement target = ref.getReference().resolve(); - if (target instanceof PyExpression && TypeEvalContext.fast().getType((PyExpression)target) instanceof PyModuleType) return false; + final TypeEvalContext context = TypeEvalContext.fastStubOnly(file); + if (target instanceof PyExpression && context.getType((PyExpression)target) instanceof PyModuleType) { + return false; + } } } - } } if (info.myModuleReference != null) { diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/PyDictConstructorToLiteralFormIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/PyDictConstructorToLiteralFormIntention.java index c25580b1fd8d..4b6f460b179c 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/PyDictConstructorToLiteralFormIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/PyDictConstructorToLiteralFormIntention.java @@ -41,7 +41,7 @@ public class PyDictConstructorToLiteralFormIntention extends BaseIntentionAction PsiTreeUtil.getParentOfType(file.findElementAt(editor.getCaretModel().getOffset()), PyCallExpression.class); if (expression != null && expression.isCalleeText("dict")) { - final TypeEvalContext context = TypeEvalContext.fast(); + final TypeEvalContext context = TypeEvalContext.fastStubOnly(file); PyType type = context.getType(expression); if (type != null && type.isBuiltin(context)) { PyExpression[] argumentList = expression.getArguments(); diff --git a/python/src/com/jetbrains/python/psi/impl/CallArgumentsMappingImpl.java b/python/src/com/jetbrains/python/psi/impl/CallArgumentsMappingImpl.java index 376fa5fe669d..b1805715a3e7 100644 --- a/python/src/com/jetbrains/python/psi/impl/CallArgumentsMappingImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/CallArgumentsMappingImpl.java @@ -54,7 +54,7 @@ public class CallArgumentsMappingImpl implements CallArgumentsMapping { @Nullable TypeEvalContext type_context ) { PyExpression[] arguments = myArgumentList.getArguments(); - if (type_context == null) type_context = TypeEvalContext.fast(); + if (type_context == null) type_context = TypeEvalContext.fastStubOnly(null); myMarkedCallee = resolved_callee; List unmatched_args = new LinkedList(); Collections.addAll(unmatched_args, arguments); diff --git a/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java b/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java index 466c58c6f9fa..c344ebe6ac18 100644 --- a/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java +++ b/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java @@ -271,7 +271,7 @@ public class ResolveImportUtil { dir = (PsiDirectory)parent; } else if (parent != null) { - PyType refType = PyReferenceExpressionImpl.getReferenceTypeFromProviders(parent, TypeEvalContext.fast(), null); + PyType refType = PyReferenceExpressionImpl.getReferenceTypeFromProviders(parent, TypeEvalContext.fastStubOnly(null), null); if (refType != null) { final List result = refType.resolveMember(referencedName, null, AccessDirection.READ, PyResolveContext.defaultContext()); From 23ed6bcdaaf61d596dd621b4f061ba9b2d97857b Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Wed, 8 May 2013 19:02:56 +0400 Subject: [PATCH 03/12] Slow TypeEvalContext for completion, documentation, find usages, quick-fixes --- .../jetbrains/python/psi/types/TypeEvalContext.java | 5 +++++ .../PyDictKeyNamesCompletionContributor.java | 2 +- .../python/documentation/DocStringTypeReference.java | 2 +- .../python/documentation/PyDocumentationBuilder.java | 2 +- .../documentation/PythonDocumentationProvider.java | 2 +- .../python/findUsages/PyUsageTypeProvider.java | 2 +- .../inspections/quickfix/AddMethodQuickFix.java | 2 +- .../python/psi/impl/references/PyImportReference.java | 11 +++++++---- .../com/jetbrains/python/PyTypeParserTest.java | 4 ++-- 9 files changed, 20 insertions(+), 12 deletions(-) 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 e7790bec470d..23f9cf885024 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 @@ -53,6 +53,11 @@ public class TypeEvalContext { return myAllowDataFlow || element.getContainingFile() == myOrigin; } + /** + * The most detailed type evaluation context for user-initiated actions. + * + * Should be used for code completion, go to definition, find usages, refactorings, documentation. + */ public static TypeEvalContext slow() { return new TypeEvalContext(true, true, null); } diff --git a/python/src/com/jetbrains/python/codeInsight/completion/PyDictKeyNamesCompletionContributor.java b/python/src/com/jetbrains/python/codeInsight/completion/PyDictKeyNamesCompletionContributor.java index ee5c6a315ac8..ca6e440cb922 100644 --- a/python/src/com/jetbrains/python/codeInsight/completion/PyDictKeyNamesCompletionContributor.java +++ b/python/src/com/jetbrains/python/codeInsight/completion/PyDictKeyNamesCompletionContributor.java @@ -114,7 +114,7 @@ public class PyDictKeyNamesCompletionContributor extends CompletionContributor { if (callee == null) return; final String name = callee.getText(); if ("dict".equals(name)) { - final TypeEvalContext context = TypeEvalContext.fast(); + final TypeEvalContext context = TypeEvalContext.slow(); final PyType type = context.getType(dictConstructor); if (type != null && type.isBuiltin(context)) { final PyArgumentList list = dictConstructor.getArgumentList(); diff --git a/python/src/com/jetbrains/python/documentation/DocStringTypeReference.java b/python/src/com/jetbrains/python/documentation/DocStringTypeReference.java index 722d8e8168cc..6c3b1c8dfb01 100644 --- a/python/src/com/jetbrains/python/documentation/DocStringTypeReference.java +++ b/python/src/com/jetbrains/python/documentation/DocStringTypeReference.java @@ -113,7 +113,7 @@ public class DocStringTypeReference extends PsiPolyVariantReferenceBase 0) { - PyType first_arg_type = TypeEvalContext.fast().getType(args[0]); + PyType first_arg_type = TypeEvalContext.slow().getType(args[0]); if (first_arg_type instanceof PyClassType && ((PyClassType)first_arg_type).getPyClass().isSubclass(cls)) { // class, first arg ok: instance method builder.parameter("self"); // NOTE: might use a name other than 'self', according to code style. 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 cffc4a2790c2..a83df0b203e1 100644 --- a/python/src/com/jetbrains/python/psi/impl/references/PyImportReference.java +++ b/python/src/com/jetbrains/python/psi/impl/references/PyImportReference.java @@ -81,9 +81,10 @@ public class PyImportReference extends PyReferenceImpl { } PyExpression qualifier = myElement.getQualifier(); + final TypeEvalContext context = TypeEvalContext.slow(); if (qualifier != null) { // qualifier's type must be module, it should know how to complete - PyType type = TypeEvalContext.fast().getType(qualifier); + PyType type = context.getType(qualifier); if (type != null) { Object[] variants = getTypeCompletionVariants(myElement, type); if (!alreadyHasImportKeyword()) { @@ -97,7 +98,7 @@ public class PyImportReference extends PyReferenceImpl { } else { // complete to possible modules - return new ImportVariantCollector().execute(); + return new ImportVariantCollector(context).execute(); } } @@ -153,8 +154,10 @@ public class PyImportReference extends PyReferenceImpl { private final PsiFile myCurrentFile; private final Set myNamesAlready; private final List myObjects; + @NotNull private final TypeEvalContext myContext; - public ImportVariantCollector() { + public ImportVariantCollector(@NotNull TypeEvalContext context) { + myContext = context; PsiFile currentFile = myElement.getContainingFile(); if (currentFile != null) currentFile = currentFile.getOriginalFile(); myCurrentFile = currentFile; @@ -177,7 +180,7 @@ public class PyImportReference extends PyReferenceImpl { addImportedNames(from_import.getImportElements()); // don't propose already imported items // try to collect submodules PyExpression module = (PyExpression)mod_candidate; - PyType qualifierType = TypeEvalContext.fast().getType(module); + PyType qualifierType = myContext.getType(module); if (qualifierType != null) { ProcessingContext ctx = new ProcessingContext(); ctx.put(PyType.CTX_NAMES, myNamesAlready); diff --git a/python/testSrc/com/jetbrains/python/PyTypeParserTest.java b/python/testSrc/com/jetbrains/python/PyTypeParserTest.java index ac59d7594cc0..601878d77c06 100644 --- a/python/testSrc/com/jetbrains/python/PyTypeParserTest.java +++ b/python/testSrc/com/jetbrains/python/PyTypeParserTest.java @@ -33,7 +33,7 @@ public class PyTypeParserTest extends PyTestCase { myFixture.configureByFile("typeParser/typeParser.py"); final PyCollectionType type = (PyCollectionType) PyTypeParser.getTypeByName(myFixture.getFile(), "list of MyObject"); assertClassType(type, "list"); - assertClassType(type.getElementType(TypeEvalContext.fast()), "MyObject"); + assertClassType(type.getElementType(TypeEvalContext.slow()), "MyObject"); } public void testDictType() { @@ -41,7 +41,7 @@ public class PyTypeParserTest extends PyTestCase { final PyCollectionType type = (PyCollectionType) PyTypeParser.getTypeByName(myFixture.getFile(), "dict from str to MyObject"); assertNotNull(type); assertClassType(type, "dict"); - final PyType elementType = type.getElementType(TypeEvalContext.fast()); + final PyType elementType = type.getElementType(TypeEvalContext.slow()); assertInstanceOf(elementType, PyTupleType.class); final PyTupleType tupleType = (PyTupleType)elementType; assertEquals(2, tupleType.getElementCount()); From 4f0702e71ddbbfc39b9d8deaa0f8068e2d1ce034 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Wed, 8 May 2013 19:05:55 +0400 Subject: [PATCH 04/12] Current TypeEvalContext for comparing references to methods --- .../impl/references/PyQualifiedReference.java | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) 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 0673d098cdcc..090b1e012580 100644 --- a/python/src/com/jetbrains/python/psi/impl/references/PyQualifiedReference.java +++ b/python/src/com/jetbrains/python/psi/impl/references/PyQualifiedReference.java @@ -382,18 +382,8 @@ public class PyQualifiedReference extends PyReferenceImpl { return false; } final String referencedName = myElement.getReferencedName(); - if (element instanceof PyFunction && Comparing.equal(referencedName, ((PyFunction)element).getName()) && - ((PyFunction)element).getContainingClass() != null && !PyNames.INIT.equals(referencedName)) { - final PyExpression qualifier = myElement.getQualifier(); - if (qualifier != null) { - final TypeEvalContext context = TypeEvalContext.fast(); - PyType qualifierType = context.getType(qualifier); - if (qualifierType == null || qualifierType instanceof PyTypeReference) { - return true; - } - } - } PyResolveContext resolveContext = myContext.withoutImplicits(); + // Guess type eval context origin for switching to local dataflow and return type analysis if (resolveContext.getTypeEvalContext().getOrigin() == null) { final PsiFile containingFile = myElement.getContainingFile(); if (containingFile instanceof StubBasedPsiElement) { @@ -402,6 +392,16 @@ public class PyQualifiedReference extends PyReferenceImpl { final TypeEvalContext context = TypeEvalContext.fastStubOnly(containingFile); resolveContext = resolveContext.withTypeEvalContext(context); } + if (element instanceof PyFunction && Comparing.equal(referencedName, ((PyFunction)element).getName()) && + ((PyFunction)element).getContainingClass() != null && !PyNames.INIT.equals(referencedName)) { + final PyExpression qualifier = myElement.getQualifier(); + if (qualifier != null) { + final PyType qualifierType = resolveContext.getTypeEvalContext().getType(qualifier); + if (qualifierType == null || qualifierType instanceof PyTypeReference) { + return true; + } + } + } for (ResolveResult result : copyWithResolveContext(resolveContext).multiResolve(false)) { LOG.assertTrue(!(result instanceof ImplicitResolveResult)); PsiElement resolveResult = result.getElement(); From e6e730d2a12a7f2949d4075c4e9369d85e3637d8 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Wed, 8 May 2013 19:20:34 +0400 Subject: [PATCH 05/12] Use inspection session type eval context --- .../PyUnresolvedReferencesInspection.java | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java b/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java index f2b8d4636468..4a519c2c4a6a 100644 --- a/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java @@ -640,7 +640,7 @@ public class PyUnresolvedReferencesInspection extends PyInspection { } if (qtype instanceof PyClassTypeImpl) { PyClass cls = ((PyClassType)qtype).getPyClass(); - if (overridesGetAttr(cls)) { + if (overridesGetAttr(cls, myTypeEvalContext)) { return true; } if (cls.findProperty(refText) != null) { @@ -799,13 +799,11 @@ public class PyUnresolvedReferencesInspection extends PyInspection { } @Nullable - private static PsiElement resolveClassMember(@NotNull PyClass cls, @NotNull String name) { - final TypeEvalContext context = TypeEvalContext.fastStubOnly(null); + private static PsiElement resolveClassMember(@NotNull PyClass cls, @NotNull String name, @NotNull TypeEvalContext context) { final PyType type = context.getType(cls); if (type != null) { - final List results = type.resolveMember(name, null, AccessDirection.READ, - PyResolveContext.noImplicits().withTypeEvalContext(context) - ); + final PyResolveContext resolveContext = PyResolveContext.noImplicits().withTypeEvalContext(context); + final List results = type.resolveMember(name, null, AccessDirection.READ, resolveContext); if (results != null && !results.isEmpty()) { return results.get(0).getElement(); } @@ -813,12 +811,12 @@ public class PyUnresolvedReferencesInspection extends PyInspection { return null; } - private static boolean overridesGetAttr(@NotNull PyClass cls) { - PsiElement method = resolveClassMember(cls, PyNames.GETATTR); + 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); + method = resolveClassMember(cls, PyNames.GETATTRIBUTE, context); if (method != null && !PyBuiltinCache.getInstance(cls).hasInBuiltins(method)) { return true; } From c8502bb914e3a610dafd7efc7cb4d2a7b9f5ed55 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Wed, 8 May 2013 19:47:41 +0400 Subject: [PATCH 06/12] Added TypeEvalContext.codeInsightFallback() constructor --- .../python/psi/resolve/PyResolveContext.java | 2 +- .../python/psi/types/TypeEvalContext.java | 21 ++++++++++++++----- .../src/com/jetbrains/python/psi/PyUtil.java | 4 ++-- .../psi/impl/CallArgumentsMappingImpl.java | 2 +- .../python/psi/impl/PyBuiltinCache.java | 2 +- .../python/psi/impl/PyClassImpl.java | 10 ++++----- .../psi/impl/PyTargetExpressionImpl.java | 2 +- .../python/psi/resolve/ResolveImportUtil.java | 2 +- .../python/testing/PythonUnitTestUtil.java | 4 ++-- .../PythonAtTestConfigurationProducer.java | 2 +- .../python/testing/pytest/PyTestUtil.java | 2 +- .../python/codeInsight/PyClassMROTest.java | 2 +- 12 files changed, 33 insertions(+), 22 deletions(-) diff --git a/python/psi-api/src/com/jetbrains/python/psi/resolve/PyResolveContext.java b/python/psi-api/src/com/jetbrains/python/psi/resolve/PyResolveContext.java index 4795a3e9ff79..5775b24a8c79 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/resolve/PyResolveContext.java +++ b/python/psi-api/src/com/jetbrains/python/psi/resolve/PyResolveContext.java @@ -56,7 +56,7 @@ public class PyResolveContext { } public TypeEvalContext getTypeEvalContext() { - return myTypeEvalContext != null ? myTypeEvalContext : TypeEvalContext.fastStubOnly(null); + return myTypeEvalContext != null ? myTypeEvalContext : TypeEvalContext.codeInsightFallback(); } @Override 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 23f9cf885024..313bebe81ac6 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 @@ -54,7 +54,7 @@ public class TypeEvalContext { } /** - * The most detailed type evaluation context for user-initiated actions. + * Create the most detailed type evaluation context for user-initiated actions. * * Should be used for code completion, go to definition, find usages, refactorings, documentation. */ @@ -62,20 +62,31 @@ public class TypeEvalContext { return new TypeEvalContext(true, true, null); } + /** + * Create a type evaluation context for deeper and slower code analysis. + * + * Should be used only when normal analysis context is not enough for getting good results. + */ public static TypeEvalContext fast() { return new TypeEvalContext(false, true, null); } /** - * Creates a TypeEvalContext for performing analysis operations on the specified file which is currently open in the editor, + * Create a type evaluation context for performing analysis operations on the specified file which is currently open in the editor, * without accessing stubs. For such a file, additional slow operations are allowed. - * - * @param origin the file open in the editor - * @return the type eval context for the file. */ public static TypeEvalContext fastStubOnly(@Nullable PsiFile origin) { return new TypeEvalContext(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. + */ + public static TypeEvalContext codeInsightFallback() { + return new TypeEvalContext(false, false, null); + } public TypeEvalContext withTracing() { if (myTrace == null) { diff --git a/python/src/com/jetbrains/python/psi/PyUtil.java b/python/src/com/jetbrains/python/psi/PyUtil.java index e96870c1a0d1..4abf744b131f 100644 --- a/python/src/com/jetbrains/python/psi/PyUtil.java +++ b/python/src/com/jetbrains/python/psi/PyUtil.java @@ -618,7 +618,7 @@ public class PyUtil { } public static boolean hasUnresolvedAncestors(@NotNull PyClass cls) { - for (PyClassLikeType type : cls.getAncestorTypes(TypeEvalContext.fastStubOnly(null))) { + for (PyClassLikeType type : cls.getAncestorTypes(TypeEvalContext.codeInsightFallback())) { if (type == null) { return true; } @@ -968,7 +968,7 @@ public class PyUtil { if (isBaseException(pyClass.getQualifiedName())) { return true; } - for (PyClassLikeType type : pyClass.getAncestorTypes(TypeEvalContext.fastStubOnly(null))) { + for (PyClassLikeType type : pyClass.getAncestorTypes(TypeEvalContext.codeInsightFallback())) { if (type != null && isBaseException(type.getClassQName())) { return true; } diff --git a/python/src/com/jetbrains/python/psi/impl/CallArgumentsMappingImpl.java b/python/src/com/jetbrains/python/psi/impl/CallArgumentsMappingImpl.java index b1805715a3e7..c3b958b6e558 100644 --- a/python/src/com/jetbrains/python/psi/impl/CallArgumentsMappingImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/CallArgumentsMappingImpl.java @@ -54,7 +54,7 @@ public class CallArgumentsMappingImpl implements CallArgumentsMapping { @Nullable TypeEvalContext type_context ) { PyExpression[] arguments = myArgumentList.getArguments(); - if (type_context == null) type_context = TypeEvalContext.fastStubOnly(null); + if (type_context == null) type_context = TypeEvalContext.codeInsightFallback(); myMarkedCallee = resolved_callee; List unmatched_args = new LinkedList(); Collections.addAll(unmatched_args, arguments); diff --git a/python/src/com/jetbrains/python/psi/impl/PyBuiltinCache.java b/python/src/com/jetbrains/python/psi/impl/PyBuiltinCache.java index 11f4d999e220..75e7040cdf32 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyBuiltinCache.java +++ b/python/src/com/jetbrains/python/psi/impl/PyBuiltinCache.java @@ -329,7 +329,7 @@ public class PyBuiltinCache { private static boolean isValid(@Nullable PyType type) { if (type instanceof PyCollectionType) { - final PyType elementType = ((PyCollectionType)type).getElementType(TypeEvalContext.fastStubOnly(null)); + final PyType elementType = ((PyCollectionType)type).getElementType(TypeEvalContext.codeInsightFallback()); if (!isValid(elementType)) { return false; } diff --git a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java index ad48778420eb..0faad3f49cbc 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java @@ -58,7 +58,7 @@ public class PyClassImpl extends PyPresentableElementImpl implement @Nullable @Override public Result> compute() { - final TypeEvalContext context = myCachedContext != null ? myCachedContext : TypeEvalContext.fastStubOnly(null); + final TypeEvalContext context = myCachedContext != null ? myCachedContext : TypeEvalContext.codeInsightFallback(); final List ancestorTypes = isNewStyleClass() ? getMROAncestorTypes(context) : getOldStyleAncestorTypes(context); return Result.create(ancestorTypes, PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT); } @@ -194,7 +194,7 @@ public class PyClassImpl extends PyPresentableElementImpl implement @NotNull @Override public List getAncestorClasses() { - return getAncestorClasses(TypeEvalContext.fastStubOnly(null)); + return getAncestorClasses(TypeEvalContext.codeInsightFallback()); } @NotNull @@ -224,7 +224,7 @@ public class PyClassImpl extends PyPresentableElementImpl implement if (superClassQName.equals(getQualifiedName())) { return true; } - for (PyClassLikeType type : getAncestorTypes(TypeEvalContext.fastStubOnly(null))) { + for (PyClassLikeType type : getAncestorTypes(TypeEvalContext.codeInsightFallback())) { if (type != null && superClassQName.equals(type.getClassQName())) { return true; } @@ -287,7 +287,7 @@ public class PyClassImpl extends PyPresentableElementImpl implement @NotNull public PyClass[] getSuperClasses() { - final List superTypes = getSuperClassTypes(TypeEvalContext.fastStubOnly(null)); + final List superTypes = getSuperClassTypes(TypeEvalContext.codeInsightFallback()); if (superTypes.isEmpty()) { return EMPTY_ARRAY; } @@ -925,7 +925,7 @@ public class PyClassImpl extends PyPresentableElementImpl implement final PyClass objClass = PyBuiltinCache.getInstance(this).getClass("object"); if (this == objClass) return true; // a rare but possible case if (hasNewStyleMetaClass(this)) return true; - for (PyClassLikeType type : getOldStyleAncestorTypes(TypeEvalContext.fastStubOnly(null))) { + for (PyClassLikeType type : getOldStyleAncestorTypes(TypeEvalContext.codeInsightFallback())) { if (type == null) { // unknown, assume new-style class return true; diff --git a/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java index 33f6ab67140e..0fa8cf546190 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java @@ -451,7 +451,7 @@ public class PyTargetExpressionImpl extends PyPresentableElementImpl results = type.resolveMember(name, null, AccessDirection.READ, PyResolveContext.noImplicits()); diff --git a/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java b/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java index c344ebe6ac18..47385ee210eb 100644 --- a/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java +++ b/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java @@ -271,7 +271,7 @@ public class ResolveImportUtil { dir = (PsiDirectory)parent; } else if (parent != null) { - PyType refType = PyReferenceExpressionImpl.getReferenceTypeFromProviders(parent, TypeEvalContext.fastStubOnly(null), null); + PyType refType = PyReferenceExpressionImpl.getReferenceTypeFromProviders(parent, TypeEvalContext.codeInsightFallback(), null); if (refType != null) { final List result = refType.resolveMember(referencedName, null, AccessDirection.READ, PyResolveContext.defaultContext()); diff --git a/python/src/com/jetbrains/python/testing/PythonUnitTestUtil.java b/python/src/com/jetbrains/python/testing/PythonUnitTestUtil.java index 9e7d1da87091..183d18c45d0d 100644 --- a/python/src/com/jetbrains/python/testing/PythonUnitTestUtil.java +++ b/python/src/com/jetbrains/python/testing/PythonUnitTestUtil.java @@ -50,7 +50,7 @@ public class PythonUnitTestUtil { } private static boolean isUnitTestCaseClass(PyClass cls, HashSet testQualifiedNames) { - for (PyClassLikeType type : cls.getAncestorTypes(TypeEvalContext.fastStubOnly(null))) { + for (PyClassLikeType type : cls.getAncestorTypes(TypeEvalContext.codeInsightFallback())) { if (type != null && testQualifiedNames.contains(type.getClassQName())) { return true; } @@ -121,7 +121,7 @@ public class PythonUnitTestUtil { } public static boolean isTestCaseClass(@NotNull PyClass cls, Set testQualifiedNames) { - for (PyClassLikeType type : cls.getAncestorTypes(TypeEvalContext.fastStubOnly(null))) { + for (PyClassLikeType type : cls.getAncestorTypes(TypeEvalContext.codeInsightFallback())) { if (type != null) { if (testQualifiedNames.contains(type.getClassQName())) { return true; diff --git a/python/src/com/jetbrains/python/testing/attest/PythonAtTestConfigurationProducer.java b/python/src/com/jetbrains/python/testing/attest/PythonAtTestConfigurationProducer.java index c9c49e055f98..055b5238dfa4 100644 --- a/python/src/com/jetbrains/python/testing/attest/PythonAtTestConfigurationProducer.java +++ b/python/src/com/jetbrains/python/testing/attest/PythonAtTestConfigurationProducer.java @@ -29,7 +29,7 @@ public class PythonAtTestConfigurationProducer extends protected boolean isTestClass(PyClass pyClass) { if (pyClass == null) return false; - for (PyClassLikeType type : pyClass.getAncestorTypes(TypeEvalContext.fastStubOnly(null))) { + for (PyClassLikeType type : pyClass.getAncestorTypes(TypeEvalContext.codeInsightFallback())) { if (type != null && "TestBase".equals(type.getName()) && hasTestFunction(pyClass)) { return true; } diff --git a/python/src/com/jetbrains/python/testing/pytest/PyTestUtil.java b/python/src/com/jetbrains/python/testing/pytest/PyTestUtil.java index e32945a561e2..880d2e43ef8e 100644 --- a/python/src/com/jetbrains/python/testing/pytest/PyTestUtil.java +++ b/python/src/com/jetbrains/python/testing/pytest/PyTestUtil.java @@ -56,7 +56,7 @@ public class PyTestUtil { } public static boolean isPyTestClass(PyClass pyClass) { - for (PyClassLikeType type : pyClass.getAncestorTypes(TypeEvalContext.fastStubOnly(null))) { + for (PyClassLikeType type : pyClass.getAncestorTypes(TypeEvalContext.codeInsightFallback())) { if (type != null && PYTHON_TEST_QUALIFIED_CLASSES.contains(type.getClassQName())) { return true; } diff --git a/python/testSrc/com/jetbrains/python/codeInsight/PyClassMROTest.java b/python/testSrc/com/jetbrains/python/codeInsight/PyClassMROTest.java index c506969839f6..8a6ef7073805 100644 --- a/python/testSrc/com/jetbrains/python/codeInsight/PyClassMROTest.java +++ b/python/testSrc/com/jetbrains/python/codeInsight/PyClassMROTest.java @@ -53,7 +53,7 @@ public class PyClassMROTest extends PyTestCase { } public void assertMRO(@NotNull PyClass cls, @NotNull String... mro) { - final List types = cls.getAncestorTypes(TypeEvalContext.fastStubOnly(null)); + final List types = cls.getAncestorTypes(TypeEvalContext.codeInsightFallback()); final List classNames = new ArrayList(); for (PyClassLikeType type : types) { if (type != null) { From c1b39569a193183f402dea569f17e01a0b143ff2 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Wed, 8 May 2013 19:48:48 +0400 Subject: [PATCH 07/12] Share TypeEvalContext among several iterations --- .../python/psi/impl/PyBaseElementImpl.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/python/src/com/jetbrains/python/psi/impl/PyBaseElementImpl.java b/python/src/com/jetbrains/python/psi/impl/PyBaseElementImpl.java index 4bea56bffe8f..8af023bc8b18 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyBaseElementImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyBaseElementImpl.java @@ -131,8 +131,12 @@ public class PyBaseElementImpl extends StubBasedPsiElemen offset = getTextRange().getStartOffset() + offset - element.getTextRange().getStartOffset(); List referencesList = new ArrayList(); + final PsiFile file = element.getContainingFile(); + final PyResolveContext resolveContext = file != null ? + PyResolveContext.defaultContext().withTypeEvalContext(TypeEvalContext.fastStubOnly(file)) : + PyResolveContext.defaultContext(); while (element != null) { - addReferences(offset, element, referencesList); + addReferences(offset, element, referencesList, resolveContext); offset = element.getStartOffsetInParent() + offset; if (element instanceof PsiFile) break; element = element.getParent(); @@ -144,14 +148,11 @@ public class PyBaseElementImpl extends StubBasedPsiElemen referencesList.get(referencesList.size() - 1).getElement()); } - private static void addReferences(int offset, PsiElement element, final Collection outReferences) { + private static void addReferences(int offset, PsiElement element, final Collection outReferences, + PyResolveContext resolveContext) { final PsiReference[] references; if (element instanceof PyReferenceOwner) { - final PsiFile file = element.getContainingFile(); - final PyResolveContext context = file != null ? - PyResolveContext.defaultContext().withTypeEvalContext(TypeEvalContext.fastStubOnly(file)) : - PyResolveContext.defaultContext(); - final PsiPolyVariantReference reference = ((PyReferenceOwner)element).getReference(context); + final PsiPolyVariantReference reference = ((PyReferenceOwner)element).getReference(resolveContext); references = reference == null ? PsiReference.EMPTY_ARRAY : new PsiReference[] {reference}; } else { From 0eb7ccfa97fba55d6301e6bd0aa21d92f51eb401 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Wed, 8 May 2013 19:50:00 +0400 Subject: [PATCH 08/12] Slow TypeEvalContext for completion variants, current context for resolve --- .../python/psi/types/PyClassTypeImpl.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java b/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java index fc3215950ca3..dcf2a2877f06 100644 --- a/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java +++ b/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java @@ -201,7 +201,7 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { } if (isDefinition() && myClass.isNewStyleClass()) { - PyClassType typeType = getMetaclassType(); + PyClassType typeType = getMetaclassType(context); if (typeType != null) { List typeMembers = typeType.resolveMember(name, location, direction, resolveContext); if (typeMembers != null && !typeMembers.isEmpty()) { @@ -237,10 +237,10 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { } @Nullable - private PyClassType getMetaclassType() { + private PyClassType getMetaclassType(@NotNull TypeEvalContext context) { final PyTargetExpression metaClassAttribute = myClass.findClassAttribute(PyNames.DUNDER_METACLASS, true); if (metaClassAttribute != null) { - final PyType type = TypeEvalContext.fastStubOnly(null).getType(metaClassAttribute); + final PyType type = context.getType(metaClassAttribute); if (type instanceof PyClassType) { return (PyClassType)type; } @@ -348,7 +348,8 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { boolean suppressParentheses = context.get(CTX_SUPPRESS_PARENTHESES) != null; addOwnClassMembers(location, namesAlready, suppressParentheses, ret); - addInheritedMembers(prefix, location, namesAlready, context, ret); + final TypeEvalContext typeEvalContext = TypeEvalContext.slow(); + addInheritedMembers(prefix, location, namesAlready, context, ret, typeEvalContext); // from providers for (PyClassMembersProvider provider : Extensions.getExtensions(PyClassMembersProvider.EP_NAME)) { @@ -374,7 +375,7 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { } if (isDefinition() && myClass.isNewStyleClass()) { - PyClassType typeType = getMetaclassType(); + final PyClassType typeType = getMetaclassType(typeEvalContext); if (typeType != null) { Collections.addAll(ret, typeType.getCompletionVariants(prefix, location, context)); } @@ -432,7 +433,8 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { PyExpression expressionHook, Set namesAlready, ProcessingContext context, - List ret) { + List ret, + @NotNull TypeEvalContext typeEvalContext) { for (PyExpression expression : myClass.getSuperClassExpressions()) { final PsiReference reference = expression.getReference(); PsiElement element = null; @@ -444,7 +446,6 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { type = new PyClassTypeImpl((PyClass)element, myIsDefinition); } else { - final TypeEvalContext typeEvalContext = TypeEvalContext.fastStubOnly(myClass.getContainingFile()); type = typeEvalContext.getType(expression); if (type instanceof PyClassType && !myIsDefinition) { type = ((PyClassType)type).toInstance(); From 9ffac767d123cceb058112bc787df7c33e1b6f91 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Wed, 8 May 2013 19:53:06 +0400 Subject: [PATCH 09/12] Renamed TypeEvalContext constructors --- .../python/psi/types/TypeEvalContext.java | 6 ++-- .../PyDictKeyNamesCompletionContributor.java | 2 +- .../ImportFromToImportIntention.java | 2 +- ...DictConstructorToLiteralFormIntention.java | 2 +- ...yStringConcatenationToFormatIntention.java | 4 +-- .../intentions/TypeAssertionIntention.java | 2 +- .../codeInsight/intentions/TypeIntention.java | 2 +- .../override/PyOverrideImplementUtil.java | 2 +- .../documentation/DocStringTypeReference.java | 2 +- .../documentation/PyDocumentationBuilder.java | 8 ++--- .../PythonDocumentationProvider.java | 8 ++--- .../findUsages/PyUsageTypeProvider.java | 2 +- .../inspections/PyInspectionVisitor.java | 2 +- .../quickfix/AddMethodQuickFix.java | 2 +- .../python/psi/impl/PyBaseElementImpl.java | 2 +- .../impl/references/PyImportReference.java | 2 +- .../impl/references/PyQualifiedReference.java | 4 +-- .../python/psi/types/PyClassTypeImpl.java | 2 +- .../refactoring/PyReplaceExpressionUtil.java | 2 +- .../introduce/IntroduceHandler.java | 2 +- .../jetbrains/python/PyTypeParserTest.java | 4 +-- .../com/jetbrains/python/PyTypeTest.java | 30 +++++++++---------- 22 files changed, 47 insertions(+), 47 deletions(-) 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 313bebe81ac6..1301b7e655b4 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 @@ -58,7 +58,7 @@ public class TypeEvalContext { * * Should be used for code completion, go to definition, find usages, refactorings, documentation. */ - public static TypeEvalContext slow() { + public static TypeEvalContext userInitiated() { return new TypeEvalContext(true, true, null); } @@ -67,7 +67,7 @@ public class TypeEvalContext { * * Should be used only when normal analysis context is not enough for getting good results. */ - public static TypeEvalContext fast() { + public static TypeEvalContext deepCodeAnalysis() { return new TypeEvalContext(false, true, null); } @@ -75,7 +75,7 @@ public class TypeEvalContext { * Create a type evaluation context for performing analysis operations on the specified file which is currently open in the editor, * without accessing stubs. For such a file, additional slow operations are allowed. */ - public static TypeEvalContext fastStubOnly(@Nullable PsiFile origin) { + public static TypeEvalContext codeAnalysis(@Nullable PsiFile origin) { return new TypeEvalContext(false, false, origin); } diff --git a/python/src/com/jetbrains/python/codeInsight/completion/PyDictKeyNamesCompletionContributor.java b/python/src/com/jetbrains/python/codeInsight/completion/PyDictKeyNamesCompletionContributor.java index ca6e440cb922..5bf6b125049a 100644 --- a/python/src/com/jetbrains/python/codeInsight/completion/PyDictKeyNamesCompletionContributor.java +++ b/python/src/com/jetbrains/python/codeInsight/completion/PyDictKeyNamesCompletionContributor.java @@ -114,7 +114,7 @@ public class PyDictKeyNamesCompletionContributor extends CompletionContributor { if (callee == null) return; final String name = callee.getText(); if ("dict".equals(name)) { - final TypeEvalContext context = TypeEvalContext.slow(); + final TypeEvalContext context = TypeEvalContext.userInitiated(); final PyType type = context.getType(dictConstructor); if (type != null && type.isBuiltin(context)) { final PyArgumentList list = dictConstructor.getArgumentList(); diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/ImportFromToImportIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/ImportFromToImportIntention.java index b8de041f6085..ca959fbec8d1 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/ImportFromToImportIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/ImportFromToImportIntention.java @@ -145,7 +145,7 @@ public class ImportFromToImportIntention implements IntentionAction { PyReferenceExpression ref = import_element.getImportReferenceExpression(); if (ref != null && ref.isValid()) { PsiElement target = ref.getReference().resolve(); - final TypeEvalContext context = TypeEvalContext.fastStubOnly(file); + final TypeEvalContext context = TypeEvalContext.codeAnalysis(file); if (target instanceof PyExpression && context.getType((PyExpression)target) instanceof PyModuleType) { return false; } diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/PyDictConstructorToLiteralFormIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/PyDictConstructorToLiteralFormIntention.java index 4b6f460b179c..ab5ab8b1e592 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/PyDictConstructorToLiteralFormIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/PyDictConstructorToLiteralFormIntention.java @@ -41,7 +41,7 @@ public class PyDictConstructorToLiteralFormIntention extends BaseIntentionAction PsiTreeUtil.getParentOfType(file.findElementAt(editor.getCaretModel().getOffset()), PyCallExpression.class); if (expression != null && expression.isCalleeText("dict")) { - final TypeEvalContext context = TypeEvalContext.fastStubOnly(file); + final TypeEvalContext context = TypeEvalContext.codeAnalysis(file); PyType type = context.getType(expression); if (type != null && type.isBuiltin(context)) { PyExpression[] argumentList = expression.getArguments(); diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/PyStringConcatenationToFormatIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/PyStringConcatenationToFormatIntention.java index aadbaa1897ef..174f15dd148c 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/PyStringConcatenationToFormatIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/PyStringConcatenationToFormatIntention.java @@ -66,9 +66,9 @@ public class PyStringConcatenationToFormatIntention extends BaseIntentionAction } if (expression instanceof PyStringLiteralExpression) continue; - final PyType type = TypeEvalContext.fastStubOnly(file).getType(expression); + final PyType type = TypeEvalContext.codeAnalysis(file).getType(expression); final boolean isStringReference = PyTypeChecker.match(cache.getStringType(LanguageLevel.forElement(expression)), - type, TypeEvalContext.fastStubOnly(file)) && type != null; + type, TypeEvalContext.codeAnalysis(file)) && type != null; if (!isStringReference) { return false; } diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/TypeAssertionIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/TypeAssertionIntention.java index e3cea61295bd..d006d4d17831 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/TypeAssertionIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/TypeAssertionIntention.java @@ -63,7 +63,7 @@ public class TypeAssertionIntention implements IntentionAction { (reference != null && reference.resolve() == null)) { return false; } - final PyType type = TypeEvalContext.fastStubOnly(file).getType(problemElement); + final PyType type = TypeEvalContext.codeAnalysis(file).getType(problemElement); return (type == null || type instanceof PyReturnTypeReference); } diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/TypeIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/TypeIntention.java index 37c309997b4d..9f855fc38ef8 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/TypeIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/TypeIntention.java @@ -162,7 +162,7 @@ public abstract class TypeIntention implements IntentionAction { } protected PyResolveContext getResolveContext(@NotNull PsiElement origin) { - return PyResolveContext.defaultContext().withTypeEvalContext(TypeEvalContext.fastStubOnly(origin.getContainingFile())); + return PyResolveContext.defaultContext().withTypeEvalContext(TypeEvalContext.codeAnalysis(origin.getContainingFile())); } public boolean startInWriteAction() { diff --git a/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java b/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java index 29b20be5bab5..a244b69a795b 100644 --- a/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java +++ b/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java @@ -196,7 +196,7 @@ public class PyOverrideImplementUtil { statementBody.append(PyNames.PASS); } else { - if (!PyNames.INIT.equals(baseFunction.getName()) && baseFunction.getReturnType(TypeEvalContext.slow(), null) != PyNoneType.INSTANCE) { + if (!PyNames.INIT.equals(baseFunction.getName()) && baseFunction.getReturnType(TypeEvalContext.userInitiated(), null) != PyNoneType.INSTANCE) { statementBody.append("return "); } if (baseClass.isNewStyleClass()) { diff --git a/python/src/com/jetbrains/python/documentation/DocStringTypeReference.java b/python/src/com/jetbrains/python/documentation/DocStringTypeReference.java index 6c3b1c8dfb01..8966ed176271 100644 --- a/python/src/com/jetbrains/python/documentation/DocStringTypeReference.java +++ b/python/src/com/jetbrains/python/documentation/DocStringTypeReference.java @@ -113,7 +113,7 @@ public class DocStringTypeReference extends PsiPolyVariantReferenceBase body) { - final TypeEvalContext context = TypeEvalContext.slow(); + final TypeEvalContext context = TypeEvalContext.userInitiated(); PyTypeModelBuilder builder = new PyTypeModelBuilder(context); builder.build(fun).toBodyWithLinks(body, fun); } @@ -481,7 +481,7 @@ public class PythonDocumentationProvider extends AbstractDocumentationProvider i @Nullable private static PyClass inferClassOfParameter(PsiElement context) { if (context instanceof PyNamedParameter) { - final PyType type = TypeEvalContext.slow().getType((PyNamedParameter)context); + final PyType type = TypeEvalContext.userInitiated().getType((PyNamedParameter)context); if (type instanceof PyClassType) { return ((PyClassType)type).getPyClass(); } diff --git a/python/src/com/jetbrains/python/findUsages/PyUsageTypeProvider.java b/python/src/com/jetbrains/python/findUsages/PyUsageTypeProvider.java index 71e3a437acf6..b4a9de818885 100644 --- a/python/src/com/jetbrains/python/findUsages/PyUsageTypeProvider.java +++ b/python/src/com/jetbrains/python/findUsages/PyUsageTypeProvider.java @@ -39,7 +39,7 @@ public class PyUsageTypeProvider implements UsageTypeProviderEx { if (element instanceof PyQualifiedExpression) { final PyExpression qualifier = ((PyQualifiedExpression)element).getQualifier(); if (qualifier != null) { - final PyType type = TypeEvalContext.slow().getType(qualifier); + final PyType type = TypeEvalContext.userInitiated().getType(qualifier); if (type == null || type instanceof PyTypeReference) { final PyCallExpression call = PsiTreeUtil.getParentOfType(element, PyCallExpression.class); if (call != null && element == call.getCallee()) { diff --git a/python/src/com/jetbrains/python/inspections/PyInspectionVisitor.java b/python/src/com/jetbrains/python/inspections/PyInspectionVisitor.java index 6658017cb4d5..6cba4dc2d589 100644 --- a/python/src/com/jetbrains/python/inspections/PyInspectionVisitor.java +++ b/python/src/com/jetbrains/python/inspections/PyInspectionVisitor.java @@ -30,7 +30,7 @@ public abstract class PyInspectionVisitor extends PyElementVisitor { synchronized (INSPECTION_TYPE_EVAL_CONTEXT) { context = session.getUserData(INSPECTION_TYPE_EVAL_CONTEXT); if (context == null) { - context = TypeEvalContext.fastStubOnly(session.getFile()); + context = TypeEvalContext.codeAnalysis(session.getFile()); session.putUserData(INSPECTION_TYPE_EVAL_CONTEXT, context); } } diff --git a/python/src/com/jetbrains/python/inspections/quickfix/AddMethodQuickFix.java b/python/src/com/jetbrains/python/inspections/quickfix/AddMethodQuickFix.java index 20aee092d2a6..26ffaeed5030 100644 --- a/python/src/com/jetbrains/python/inspections/quickfix/AddMethodQuickFix.java +++ b/python/src/com/jetbrains/python/inspections/quickfix/AddMethodQuickFix.java @@ -75,7 +75,7 @@ public class AddMethodQuickFix implements LocalQuickFix { boolean made_instance = false; if (call_by_class) { if (args.length > 0) { - PyType first_arg_type = TypeEvalContext.slow().getType(args[0]); + PyType first_arg_type = TypeEvalContext.userInitiated().getType(args[0]); if (first_arg_type instanceof PyClassType && ((PyClassType)first_arg_type).getPyClass().isSubclass(cls)) { // class, first arg ok: instance method builder.parameter("self"); // NOTE: might use a name other than 'self', according to code style. diff --git a/python/src/com/jetbrains/python/psi/impl/PyBaseElementImpl.java b/python/src/com/jetbrains/python/psi/impl/PyBaseElementImpl.java index 8af023bc8b18..1d4b7dc5e9ee 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyBaseElementImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyBaseElementImpl.java @@ -133,7 +133,7 @@ public class PyBaseElementImpl extends StubBasedPsiElemen List referencesList = new ArrayList(); final PsiFile file = element.getContainingFile(); final PyResolveContext resolveContext = file != null ? - PyResolveContext.defaultContext().withTypeEvalContext(TypeEvalContext.fastStubOnly(file)) : + PyResolveContext.defaultContext().withTypeEvalContext(TypeEvalContext.codeAnalysis(file)) : PyResolveContext.defaultContext(); while (element != null) { addReferences(offset, element, referencesList, resolveContext); 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 a83df0b203e1..2629dc62a926 100644 --- a/python/src/com/jetbrains/python/psi/impl/references/PyImportReference.java +++ b/python/src/com/jetbrains/python/psi/impl/references/PyImportReference.java @@ -81,7 +81,7 @@ public class PyImportReference extends PyReferenceImpl { } PyExpression qualifier = myElement.getQualifier(); - final TypeEvalContext context = TypeEvalContext.slow(); + final TypeEvalContext context = TypeEvalContext.userInitiated(); 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 090b1e012580..b3ce5a3b3cd4 100644 --- a/python/src/com/jetbrains/python/psi/impl/references/PyQualifiedReference.java +++ b/python/src/com/jetbrains/python/psi/impl/references/PyQualifiedReference.java @@ -247,7 +247,7 @@ public class PyQualifiedReference extends PyReferenceImpl { } final PyQualifiedExpression element = CompletionUtil.getOriginalOrSelf(myElement); - PyType qualifierType = TypeEvalContext.slow().getType(qualifier); + PyType qualifierType = TypeEvalContext.userInitiated().getType(qualifier); ProcessingContext ctx = new ProcessingContext(); final Set namesAlready = new HashSet(); ctx.put(PyType.CTX_NAMES, namesAlready); @@ -389,7 +389,7 @@ public class PyQualifiedReference extends PyReferenceImpl { if (containingFile instanceof StubBasedPsiElement) { assert ((StubBasedPsiElement)containingFile).getStub() == null : "Stub origin for type eval context in isReferenceTo()"; } - final TypeEvalContext context = TypeEvalContext.fastStubOnly(containingFile); + final TypeEvalContext context = TypeEvalContext.codeAnalysis(containingFile); resolveContext = resolveContext.withTypeEvalContext(context); } if (element instanceof PyFunction && Comparing.equal(referencedName, ((PyFunction)element).getName()) && diff --git a/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java b/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java index dcf2a2877f06..a78f9e7c2d51 100644 --- a/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java +++ b/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java @@ -348,7 +348,7 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { boolean suppressParentheses = context.get(CTX_SUPPRESS_PARENTHESES) != null; addOwnClassMembers(location, namesAlready, suppressParentheses, ret); - final TypeEvalContext typeEvalContext = TypeEvalContext.slow(); + final TypeEvalContext typeEvalContext = TypeEvalContext.userInitiated(); addInheritedMembers(prefix, location, namesAlready, context, ret, typeEvalContext); // from providers diff --git a/python/src/com/jetbrains/python/refactoring/PyReplaceExpressionUtil.java b/python/src/com/jetbrains/python/refactoring/PyReplaceExpressionUtil.java index abd91f32fc58..1013ac3a6038 100644 --- a/python/src/com/jetbrains/python/refactoring/PyReplaceExpressionUtil.java +++ b/python/src/com/jetbrains/python/refactoring/PyReplaceExpressionUtil.java @@ -110,7 +110,7 @@ public class PyReplaceExpressionUtil implements PyElementTypes { return replaceSubstringWithDictFormatting(oldExpression, quotes, prefix, suffix, formatValue, newText); } else { - final TypeEvalContext context = TypeEvalContext.slow(); + final TypeEvalContext context = TypeEvalContext.userInitiated(); final PyType valueType = context.getType(formatValue); final PyBuiltinCache builtinCache = PyBuiltinCache.getInstance(oldExpression); final PyType tupleType = builtinCache.getTupleType(); diff --git a/python/src/com/jetbrains/python/refactoring/introduce/IntroduceHandler.java b/python/src/com/jetbrains/python/refactoring/introduce/IntroduceHandler.java index 6f6bed984a18..65c831ee94fe 100644 --- a/python/src/com/jetbrains/python/refactoring/introduce/IntroduceHandler.java +++ b/python/src/com/jetbrains/python/refactoring/introduce/IntroduceHandler.java @@ -188,7 +188,7 @@ abstract public class IntroduceHandler implements RefactoringActionHandler { if (text != null) { candidates.addAll(NameSuggesterUtil.generateNames(text)); } - final TypeEvalContext context = TypeEvalContext.slow(); + final TypeEvalContext context = TypeEvalContext.userInitiated(); PyType type = context.getType(expression); if (type != null && type != PyNoneType.INSTANCE) { String typeName = type.getName(); diff --git a/python/testSrc/com/jetbrains/python/PyTypeParserTest.java b/python/testSrc/com/jetbrains/python/PyTypeParserTest.java index 601878d77c06..35997f16b957 100644 --- a/python/testSrc/com/jetbrains/python/PyTypeParserTest.java +++ b/python/testSrc/com/jetbrains/python/PyTypeParserTest.java @@ -33,7 +33,7 @@ public class PyTypeParserTest extends PyTestCase { myFixture.configureByFile("typeParser/typeParser.py"); final PyCollectionType type = (PyCollectionType) PyTypeParser.getTypeByName(myFixture.getFile(), "list of MyObject"); assertClassType(type, "list"); - assertClassType(type.getElementType(TypeEvalContext.slow()), "MyObject"); + assertClassType(type.getElementType(TypeEvalContext.userInitiated()), "MyObject"); } public void testDictType() { @@ -41,7 +41,7 @@ public class PyTypeParserTest extends PyTestCase { final PyCollectionType type = (PyCollectionType) PyTypeParser.getTypeByName(myFixture.getFile(), "dict from str to MyObject"); assertNotNull(type); assertClassType(type, "dict"); - final PyType elementType = type.getElementType(TypeEvalContext.slow()); + final PyType elementType = type.getElementType(TypeEvalContext.userInitiated()); assertInstanceOf(elementType, PyTupleType.class); final PyTupleType tupleType = (PyTupleType)elementType; assertEquals(2, tupleType.getElementCount()); diff --git a/python/testSrc/com/jetbrains/python/PyTypeTest.java b/python/testSrc/com/jetbrains/python/PyTypeTest.java index b1d5a66e95ec..f8cc1f9398d4 100644 --- a/python/testSrc/com/jetbrains/python/PyTypeTest.java +++ b/python/testSrc/com/jetbrains/python/PyTypeTest.java @@ -220,7 +220,7 @@ public class PyTypeTest extends PyTestCase { " return x\n" + "expr = f(1, 2)\n"; PyExpression expr = parseExpr(text); - PyType t = TypeEvalContext.slow().getType(expr); + PyType t = TypeEvalContext.userInitiated().getType(expr); assertTrue(PyTypeChecker.isUnknown(t)); doTest("int", text); } @@ -234,7 +234,7 @@ public class PyTypeTest extends PyTestCase { " return foo(x)\n" + "expr = xyzzy(a, b)"; PyExpression expr = parseExpr(text); - PyType t = TypeEvalContext.slow().getType(expr); + PyType t = TypeEvalContext.userInitiated().getType(expr); assertInstanceOf(t, PyTypeReference.class); } @@ -296,7 +296,7 @@ public class PyTypeTest extends PyTestCase { public void testSOEOnRecursiveCall() { PyExpression expr = parseExpr("def foo(x): return foo(x)\n" + "expr = foo(1)"); - TypeEvalContext context = TypeEvalContext.slow().withTracing(); + TypeEvalContext context = TypeEvalContext.userInitiated().withTracing(); PyType actual = context.getType(expr); assertFalse(actual.isBuiltin(context)); } @@ -310,7 +310,7 @@ public class PyTypeTest extends PyTestCase { " return x\n" + "\n" + "expr = f(1)\n"); - TypeEvalContext context = TypeEvalContext.slow().withTracing(); + TypeEvalContext context = TypeEvalContext.userInitiated().withTracing(); PyType actual = context.getType(expr); assertNotNull(actual); assertEquals("int", actual.getName()); @@ -325,7 +325,7 @@ public class PyTypeTest extends PyTestCase { " return x\n" + "\n" + "expr = f(1)\n"); - TypeEvalContext context = TypeEvalContext.slow().withTracing(); + TypeEvalContext context = TypeEvalContext.userInitiated().withTracing(); PyType actual = context.getType(expr); assertNotNull(actual); assertEquals("int", actual.getName()); @@ -335,7 +335,7 @@ public class PyTypeTest extends PyTestCase { public void testYieldType() { PyExpression expr = parseExpr("def f():\n" + " expr = yield 2\n"); - TypeEvalContext context = TypeEvalContext.slow().withTracing(); + TypeEvalContext context = TypeEvalContext.userInitiated().withTracing(); PyType actual = context.getType(expr); assertNull(actual); } @@ -344,7 +344,7 @@ public class PyTypeTest extends PyTestCase { public void testYieldParensType() { PyExpression expr = parseExpr("def f():\n" + " expr = (yield 2)\n"); - TypeEvalContext context = TypeEvalContext.slow().withTracing(); + TypeEvalContext context = TypeEvalContext.userInitiated().withTracing(); PyType actual = context.getType(expr); assertNull(actual); } @@ -389,7 +389,7 @@ public class PyTypeTest extends PyTestCase { "\n" + "x = f()\n" + "expr = x.start\n"); - TypeEvalContext context = TypeEvalContext.slow().withTracing(); + TypeEvalContext context = TypeEvalContext.userInitiated().withTracing(); PyType actual = context.getType(expr); assertNull(actual); } @@ -401,7 +401,7 @@ public class PyTypeTest extends PyTestCase { "\n" + "x = C()\n" + "expr = type(x)\n"); - TypeEvalContext context = TypeEvalContext.slow().withTracing(); + TypeEvalContext context = TypeEvalContext.userInitiated().withTracing(); PyType type = context.getType(expr); assertInstanceOf(type, PyClassType.class); assertTrue("Got instance type instead of class type", ((PyClassType)type).isDefinition()); @@ -413,7 +413,7 @@ public class PyTypeTest extends PyTestCase { " pass\n" + "\n" + "expr = type(C)\n"); - TypeEvalContext context = TypeEvalContext.slow().withTracing(); + TypeEvalContext context = TypeEvalContext.userInitiated().withTracing(); PyType type = context.getType(expr); assertInstanceOf(type, PyClassType.class); assertEquals(type.getName(), "type"); @@ -423,7 +423,7 @@ public class PyTypeTest extends PyTestCase { public void testReturnTypeOfTypeForUnknown() { PyExpression expr = parseExpr("def f(x):\n" + " expr = type(x)\n"); - TypeEvalContext context = TypeEvalContext.slow().withTracing(); + TypeEvalContext context = TypeEvalContext.userInitiated().withTracing(); PyType type = context.getType(expr); assertNull(type); } @@ -453,7 +453,7 @@ public class PyTypeTest extends PyTestCase { // PY-7020 public void testListComprehensionType() { final PyExpression expr = parseExpr("expr = [str(x) for x in range(10)]\n"); - final TypeEvalContext context = TypeEvalContext.slow().withTracing(); + final TypeEvalContext context = TypeEvalContext.userInitiated().withTracing(); final PyType type = context.getType(expr); assertNotNull(type); assertInstanceOf(type, PyCollectionType.class); @@ -467,7 +467,7 @@ public class PyTypeTest extends PyTestCase { // PY-7021 public void testGeneratorComprehensionType() { final PyExpression expr = parseExpr("expr = (str(x) for x in range(10))\n"); - final TypeEvalContext context = TypeEvalContext.slow().withTracing(); + final TypeEvalContext context = TypeEvalContext.userInitiated().withTracing(); final PyType type = context.getType(expr); assertNotNull(type); assertInstanceOf(type, PyCollectionType.class); @@ -558,7 +558,7 @@ public class PyTypeTest extends PyTestCase { public void testDefaultParameterIgnoreNone() { final PyExpression expr = parseExpr("def f(x=None):\n" + " expr = x\n"); - final TypeEvalContext context = TypeEvalContext.slow().withTracing(); + final TypeEvalContext context = TypeEvalContext.userInitiated().withTracing(); final PyType type = context.getType(expr); assertNull(type); } @@ -576,7 +576,7 @@ public class PyTypeTest extends PyTestCase { private void doTest(final String expectedType, final String text) { PyExpression expr = parseExpr(text); - TypeEvalContext context = TypeEvalContext.slow().withTracing(); + TypeEvalContext context = TypeEvalContext.userInitiated().withTracing(); PyType actual = context.getType(expr); PyType expected = PyTypeParser.getTypeByName(expr, expectedType); if (expected != null) { From fd54bc9000e03bc046bbd068e5e7d4cd67f56c81 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Wed, 8 May 2013 20:12:48 +0400 Subject: [PATCH 10/12] Reused available TypeEvalContext instead of codeInsightFallback() --- .../stdlib/PyStdlibTypeProvider.java | 25 +++++++++++-------- .../findUsages/PyUsageTypeProvider.java | 9 ++++--- .../PyUnresolvedReferencesInspection.java | 2 +- .../src/com/jetbrains/python/psi/PyUtil.java | 4 +-- .../psi/impl/CallArgumentsMappingImpl.java | 16 +++++------- .../python/psi/impl/PyBuiltinCache.java | 12 ++++----- .../python/psi/impl/PyNamedParameterImpl.java | 2 +- .../psi/impl/PyReferenceExpressionImpl.java | 5 ++-- .../psi/impl/PyTargetExpressionImpl.java | 6 ++--- .../python/psi/resolve/ResolveImportUtil.java | 12 +++++---- .../python/psi/types/PyTypeChecker.java | 10 ++++---- 11 files changed, 53 insertions(+), 50 deletions(-) diff --git a/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java b/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java index c6eaaa5762ba..6d3d232d4e1c 100644 --- a/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java +++ b/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java @@ -87,30 +87,30 @@ public class PyStdlibTypeProvider extends PyTypeProviderBase { } } } - return getReturnTypeByQName(qname, function); + return getReturnTypeByQName(qname, function, context); } return null; } @Nullable - public PyType getConstructorType(@NotNull PyClass cls) { + public PyType getConstructorType(@NotNull PyClass cls, @NotNull TypeEvalContext context) { final String classQName = cls.getQualifiedName(); if (classQName != null) { final PyQualifiedName canonicalQName = PyStdlibCanonicalPathProvider.restoreStdlibCanonicalPath(PyQualifiedName.fromDottedString(classQName)); if (canonicalQName != null) { final PyQualifiedName qname = canonicalQName.append(PyNames.INIT); - return getReturnTypeByQName(qname.toString(), cls); + return getReturnTypeByQName(qname.toString(), cls, context); } } return null; } @Nullable - private PyType getReturnTypeByQName(@NotNull String qname, @NotNull PsiElement anchor) { + private PyType getReturnTypeByQName(@NotNull String qname, @NotNull PsiElement anchor, @NotNull TypeEvalContext context) { final LanguageLevel level = LanguageLevel.forElement(anchor); final String key = String.format("Python%d/%s.return", level.getVersion(), qname); final PyBuiltinCache cache = PyBuiltinCache.getInstance(anchor); - final Ref cached = cache.getStdlibType(key); + final Ref cached = cache.getStdlibType(key, context); if (cached != null) { return cached.get(); } @@ -133,7 +133,7 @@ public class PyStdlibTypeProvider extends PyTypeProviderBase { final String name = param.getName(); final String qname = getQualifiedName(func, param); if (qname != null && name != null) { - return getParameterTypeByQName(qname, name, func); + return getParameterTypeByQName(qname, name, func, context); } return null; } @@ -175,7 +175,7 @@ public class PyStdlibTypeProvider extends PyTypeProviderBase { PyType rtype; do { final String overloadedQName = String.format("%s.%d", qname, i); - rtype = getReturnTypeByQName(overloadedQName, anchor); + rtype = getReturnTypeByQName(overloadedQName, anchor, context); if (rtype != null) { boolean matched = true; boolean notNullParameterMatch = false; @@ -192,7 +192,7 @@ public class PyStdlibTypeProvider extends PyTypeProviderBase { continue; } final PyType argType = context.getType(entry.getKey()); - final PyType paramType = getParameterTypeByQName(overloadedQName, name, anchor); + final PyType paramType = getParameterTypeByQName(overloadedQName, name, anchor, context); if (PyTypeChecker.match(paramType, argType, context)) { if (paramType != null && !PyTypeChecker.isUnknown(argType)) { notNullParameterMatch = true; @@ -230,7 +230,7 @@ public class PyStdlibTypeProvider extends PyTypeProviderBase { } final PyBuiltinCache cache = PyBuiltinCache.getInstance(anchor); final LanguageLevel level = LanguageLevel.forElement(anchor); - final PyType paramType = getParameterTypeByQName(overloadedQName, "mode", anchor); + final PyType paramType = getParameterTypeByQName(overloadedQName, "mode", anchor, context); final PyType argType; // Binary mode if (mode.contains("b")) { @@ -249,11 +249,14 @@ public class PyStdlibTypeProvider extends PyTypeProviderBase { } @Nullable - private PyType getParameterTypeByQName(@NotNull String functionQName, @NotNull String name, @NotNull PsiElement anchor) { + private PyType getParameterTypeByQName(@NotNull String functionQName, + @NotNull String name, + @NotNull PsiElement anchor, + @NotNull TypeEvalContext context) { final LanguageLevel level = LanguageLevel.forElement(anchor); final String key = String.format("Python%d/%s.%s", level.getVersion(), functionQName, name); final PyBuiltinCache cache = PyBuiltinCache.getInstance(anchor); - final Ref cached = cache.getStdlibType(key); + final Ref cached = cache.getStdlibType(key, context); if (cached != null) { return cached.get(); } diff --git a/python/src/com/jetbrains/python/findUsages/PyUsageTypeProvider.java b/python/src/com/jetbrains/python/findUsages/PyUsageTypeProvider.java index b4a9de818885..97480fed2e40 100644 --- a/python/src/com/jetbrains/python/findUsages/PyUsageTypeProvider.java +++ b/python/src/com/jetbrains/python/findUsages/PyUsageTypeProvider.java @@ -39,11 +39,12 @@ public class PyUsageTypeProvider implements UsageTypeProviderEx { if (element instanceof PyQualifiedExpression) { final PyExpression qualifier = ((PyQualifiedExpression)element).getQualifier(); if (qualifier != null) { - final PyType type = TypeEvalContext.userInitiated().getType(qualifier); + final TypeEvalContext context = TypeEvalContext.userInitiated(); + final PyType type = context.getType(qualifier); if (type == null || type instanceof PyTypeReference) { final PyCallExpression call = PsiTreeUtil.getParentOfType(element, PyCallExpression.class); if (call != null && element == call.getCallee()) { - return checkMatchingSignatureGroup(call, targets); + return checkMatchingSignatureGroup(call, targets, context); } return UNTYPED; } @@ -74,7 +75,7 @@ public class PyUsageTypeProvider implements UsageTypeProviderEx { } @Nullable - private static UsageType checkMatchingSignatureGroup(PyCallExpression call, UsageTarget[] targets) { + private static UsageType checkMatchingSignatureGroup(PyCallExpression call, UsageTarget[] targets, TypeEvalContext context) { if (targets.length == 1 && targets[0] instanceof PsiElementUsageTarget) { final PsiElement element = ((PsiElementUsageTarget)targets[0]).getElement(); if (element instanceof PyFunction) { @@ -82,7 +83,7 @@ public class PyUsageTypeProvider implements UsageTypeProviderEx { final PyFunction.Modifier modifier = function.getModifier(); PyCallExpression.PyMarkedCallee callee = new PyCallExpression.PyMarkedCallee(function, modifier, 1, true); CallArgumentsMappingImpl mapping = new CallArgumentsMappingImpl(call.getArgumentList()); - mapping.mapArguments(callee, null); + mapping.mapArguments(callee, context); if (mapping.hasProblems()) { return SIGNATURE_MISMATCH; } diff --git a/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java b/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java index 4a519c2c4a6a..dc75c6f20e30 100644 --- a/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java @@ -646,7 +646,7 @@ public class PyUnresolvedReferencesInspection extends PyInspection { if (cls.findProperty(refText) != null) { return true; } - if (PyUtil.hasUnresolvedAncestors(cls)) { + if (PyUtil.hasUnresolvedAncestors(cls, myTypeEvalContext)) { return true; } if (isDecoratedAsDynamic(cls, true)) { diff --git a/python/src/com/jetbrains/python/psi/PyUtil.java b/python/src/com/jetbrains/python/psi/PyUtil.java index 4abf744b131f..cc614bed1850 100644 --- a/python/src/com/jetbrains/python/psi/PyUtil.java +++ b/python/src/com/jetbrains/python/psi/PyUtil.java @@ -617,8 +617,8 @@ public class PyUtil { : psiNamedElement.getName(); } - public static boolean hasUnresolvedAncestors(@NotNull PyClass cls) { - for (PyClassLikeType type : cls.getAncestorTypes(TypeEvalContext.codeInsightFallback())) { + public static boolean hasUnresolvedAncestors(@NotNull PyClass cls, @NotNull TypeEvalContext context) { + for (PyClassLikeType type : cls.getAncestorTypes(context)) { if (type == null) { return true; } diff --git a/python/src/com/jetbrains/python/psi/impl/CallArgumentsMappingImpl.java b/python/src/com/jetbrains/python/psi/impl/CallArgumentsMappingImpl.java index c3b958b6e558..e8cddd605855 100644 --- a/python/src/com/jetbrains/python/psi/impl/CallArgumentsMappingImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/CallArgumentsMappingImpl.java @@ -47,14 +47,10 @@ public class CallArgumentsMappingImpl implements CallArgumentsMapping { * positional paramaters, but at least one item long. * @param arguments what to map, get if from call site * @param resolved_callee what to map parameters of - * @param type_context optional shared type evaluator / cache. + * @param context optional shared type evaluator / cache. */ - public void mapArguments( - PyCallExpression.PyMarkedCallee resolved_callee, - @Nullable TypeEvalContext type_context - ) { + public void mapArguments(PyCallExpression.PyMarkedCallee resolved_callee, @Nullable TypeEvalContext context) { PyExpression[] arguments = myArgumentList.getArguments(); - if (type_context == null) type_context = TypeEvalContext.codeInsightFallback(); myMarkedCallee = resolved_callee; List unmatched_args = new LinkedList(); Collections.addAll(unmatched_args, arguments); @@ -144,8 +140,8 @@ public class CallArgumentsMappingImpl implements CallArgumentsMapping { mapped_args.add(arg); // tuple itself is always mapped; its insides can fail } else { - PyType arg_type = type_context.getType(arg); - if (arg_type != null && arg_type.isBuiltin(type_context) && "list".equals(arg_type.getName())) { + PyType arg_type = context.getType(arg); + if (arg_type != null && arg_type.isBuiltin(context) && "list".equals(arg_type.getName())) { mapped_args.add(arg); // we can't really analyze arbitrary lists statically yet // but ListLiteralExpressions are handled by visitor } @@ -210,10 +206,10 @@ public class CallArgumentsMappingImpl implements CallArgumentsMapping { if (cnt < parameters.length && cnt < positional_index && myTupleArg != null) { // check length of myTupleArg PyType tuple_arg_type = null; - if (type_context != null) { + if (context != null) { final PyExpression expression = PsiTreeUtil.getChildOfType(myTupleArg, PyExpression.class); if (expression != null) { - tuple_arg_type = type_context.getType(expression); + tuple_arg_type = context.getType(expression); } } int tuple_length; diff --git a/python/src/com/jetbrains/python/psi/impl/PyBuiltinCache.java b/python/src/com/jetbrains/python/psi/impl/PyBuiltinCache.java index 75e7040cdf32..0f450fd9fee7 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyBuiltinCache.java +++ b/python/src/com/jetbrains/python/psi/impl/PyBuiltinCache.java @@ -314,11 +314,11 @@ public class PyBuiltinCache { } @Nullable - public Ref getStdlibType(@NotNull String key) { + public Ref getStdlibType(@NotNull String key, @NotNull TypeEvalContext context) { synchronized (myStdlibTypeCache) { final Ref ref = myStdlibTypeCache.get(key); if (ref != null) { - if (!isValid(ref.get())) { + if (!isValid(ref.get(), context)) { myStdlibTypeCache.clear(); return null; } @@ -327,10 +327,10 @@ public class PyBuiltinCache { } } - private static boolean isValid(@Nullable PyType type) { + private static boolean isValid(@Nullable PyType type, @NotNull TypeEvalContext context) { if (type instanceof PyCollectionType) { - final PyType elementType = ((PyCollectionType)type).getElementType(TypeEvalContext.codeInsightFallback()); - if (!isValid(elementType)) { + final PyType elementType = ((PyCollectionType)type).getElementType(context); + if (!isValid(elementType, context)) { return false; } } @@ -340,7 +340,7 @@ public class PyBuiltinCache { } else if (type instanceof PyUnionType) { for (PyType member : ((PyUnionType)type).getMembers()) { - if (!isValid(member)) { + if (!isValid(member, context)) { return false; } } diff --git a/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java b/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java index ad9be49db02f..6812fc8bd4aa 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java @@ -179,7 +179,7 @@ public class PyNamedParameterImpl extends PyPresentableElementImpl results = type.resolveMember(name, null, AccessDirection.READ, PyResolveContext.noImplicits()); diff --git a/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java b/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java index 47385ee210eb..9527d30f82ea 100644 --- a/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java +++ b/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java @@ -6,14 +6,16 @@ import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.*; +import com.intellij.psi.PsiDirectory; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiInvalidElementAccessException; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.containers.HashSet; import com.jetbrains.python.PyNames; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.impl.*; import com.jetbrains.python.psi.types.PyType; -import com.jetbrains.python.psi.types.TypeEvalContext; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -271,10 +273,10 @@ public class ResolveImportUtil { dir = (PsiDirectory)parent; } else if (parent != null) { - PyType refType = PyReferenceExpressionImpl.getReferenceTypeFromProviders(parent, TypeEvalContext.codeInsightFallback(), null); + final PyResolveContext resolveContext = PyResolveContext.defaultContext(); + PyType refType = PyReferenceExpressionImpl.getReferenceTypeFromProviders(parent, resolveContext.getTypeEvalContext(), null); if (refType != null) { - final List result = refType.resolveMember(referencedName, null, AccessDirection.READ, - PyResolveContext.defaultContext()); + final List result = refType.resolveMember(referencedName, null, AccessDirection.READ, resolveContext); if (result != null && !result.isEmpty()) { return result.get(0).getElement(); } diff --git a/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java b/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java index eefb1636612f..57641c8cec3b 100644 --- a/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java +++ b/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java @@ -104,7 +104,7 @@ public class PyTypeChecker { final PyClass superClass = ((PyClassType)expected).getPyClass(); final PyClass subClass = ((PyClassType)actual).getPyClass(); if (expected instanceof PyCollectionType && actual instanceof PyCollectionType) { - if (!matchClasses(superClass, subClass)) { + if (!matchClasses(superClass, subClass, context)) { return false; } final PyType superElementType = ((PyCollectionType)expected).getElementType(context); @@ -126,7 +126,7 @@ public class PyTypeChecker { return true; } } - else if (matchClasses(superClass, subClass)) { + else if (matchClasses(superClass, subClass, context)) { return true; } else if (((PyClassType)actual).isDefinition() && PyNames.CALLABLE.equals(expected.getName())) { @@ -287,7 +287,7 @@ public class PyTypeChecker { // Unify generics in stdlib pseudo-constructor final PyStdlibTypeProvider stdlib = PyStdlibTypeProvider.getInstance(); if (stdlib != null) { - final PyType initType = stdlib.getConstructorType(cls); + final PyType initType = stdlib.getConstructorType(cls, context); if (initType != null) { match(initType, qualifierType, context, substitutions); } @@ -297,11 +297,11 @@ public class PyTypeChecker { return substitutions; } - private static boolean matchClasses(@Nullable PyClass superClass, @Nullable PyClass subClass) { + private static boolean matchClasses(@Nullable PyClass superClass, @Nullable PyClass subClass, @NotNull TypeEvalContext context) { if (superClass == null || subClass == null || subClass.isSubclass(superClass) || PyABCUtil.isSubclass(subClass, superClass)) { return true; } - else if (PyUtil.hasUnresolvedAncestors(subClass)) { + else if (PyUtil.hasUnresolvedAncestors(subClass, context)) { return true; } else { From a55e50525c7d6dc57bc616a465cf3153c08ed244 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Mon, 13 May 2013 16:03:39 +0400 Subject: [PATCH 11/12] Renamed deepCodeAnalysis() context to deepCodeInsight() --- .../python/psi/types/TypeEvalContext.java | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) 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 1301b7e655b4..773651e5e590 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 @@ -62,18 +62,11 @@ public class TypeEvalContext { return new TypeEvalContext(true, true, null); } - /** - * Create a type evaluation context for deeper and slower code analysis. - * - * Should be used only when normal analysis context is not enough for getting good results. - */ - public static TypeEvalContext deepCodeAnalysis() { - return new TypeEvalContext(false, true, null); - } - /** * Create a type evaluation context for performing analysis operations on the specified file which is currently open in the editor, * without accessing stubs. For such a file, additional slow operations are allowed. + * + * Inspections should not create a new type evaluation context. They should re-use the context of the inspection session. */ public static TypeEvalContext codeAnalysis(@Nullable PsiFile origin) { return new TypeEvalContext(false, false, origin); @@ -87,7 +80,16 @@ public class TypeEvalContext { public static TypeEvalContext codeInsightFallback() { return new TypeEvalContext(false, false, null); } - + + /** + * Create a type evaluation context for deeper and slower code insight. + * + * Should be used only when normal code insight context is not enough for getting good results. + */ + public static TypeEvalContext deepCodeInsight() { + return new TypeEvalContext(false, true, null); + } + public TypeEvalContext withTracing() { if (myTrace == null) { myTrace = new ArrayList(); From 968f550e0c8042511fb891388585309d93d13ffa Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Mon, 13 May 2013 16:05:35 +0400 Subject: [PATCH 12/12] Don't perform extra computations in type checker inspection if formal parameter type is unknown --- .../python/inspections/PyTypeCheckerInspection.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java b/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java index 90d7a5aa45eb..602db9139323 100644 --- a/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java @@ -64,15 +64,22 @@ public class PyTypeCheckerInspection extends PyInspection { final Map substitutions = new LinkedHashMap(); final PyTypeChecker.AnalyzeCallResults results = PyTypeChecker.analyzeCallSite(callSite, myTypeEvalContext); if (results != null) { - substitutions.putAll(PyTypeChecker.collectCallGenerics(results.getCallable(), results.getReceiver(), myTypeEvalContext)); + boolean genericsCollected = false; for (Map.Entry entry : results.getArguments().entrySet()) { final PyNamedParameter p = entry.getValue(); if (p.isPositionalContainer() || p.isKeywordContainer()) { // TODO: Support *args, **kwargs continue; } - final PyType argType = myTypeEvalContext.getType(entry.getKey()); final PyType paramType = myTypeEvalContext.getType(p); + if (paramType == null) { + continue; + } + final PyType argType = myTypeEvalContext.getType(entry.getKey()); + if (!genericsCollected) { + substitutions.putAll(PyTypeChecker.collectCallGenerics(results.getCallable(), results.getReceiver(), myTypeEvalContext)); + genericsCollected = true; + } checkTypes(paramType, argType, entry.getKey(), myTypeEvalContext, substitutions); } }