diff --git a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaImportResolver.java b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaImportResolver.java index abf47be0a4f5..8cf80d762633 100644 --- a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaImportResolver.java +++ b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaImportResolver.java @@ -11,16 +11,10 @@ import org.jetbrains.annotations.Nullable; */ public class PyJavaImportResolver implements PyImportResolver { @Nullable - public PsiElement resolveImportReference(final PyElement importElement, final String importText, PsiElement importFrom) { - String fqn = importText; - if (importFrom instanceof PsiDirectory) { - PsiPackage fromPackage = JavaDirectoryService.getInstance().getPackage((PsiDirectory) importFrom); - if (fromPackage != null) { - importFrom = fromPackage; - } - } - if (importFrom instanceof PsiPackage) { - fqn = ((PsiPackage) importFrom).getQualifiedName() + "." + fqn; + public PsiElement resolveImportReference(final PyElement importElement, final PyQualifiedName importText, PyQualifiedName importFrom) { + String fqn = importText.toString(); + if (importFrom != null) { + fqn = importFrom.toString() + "." + fqn; } final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(importElement.getProject()); diff --git a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaPackageType.java b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaPackageType.java new file mode 100644 index 000000000000..5ee09893d4bf --- /dev/null +++ b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaPackageType.java @@ -0,0 +1,82 @@ +package com.jetbrains.python.psi.impl; + +import com.intellij.codeInsight.lookup.LookupElementBuilder; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.Project; +import com.intellij.psi.JavaPsiFacade; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiPackage; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.search.ProjectScope; +import com.intellij.util.ArrayUtil; +import com.intellij.util.ProcessingContext; +import com.jetbrains.python.psi.AccessDirection; +import com.jetbrains.python.psi.PyExpression; +import com.jetbrains.python.psi.resolve.PyResolveContext; +import com.jetbrains.python.psi.types.PyType; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * @author yole + */ +public class PyJavaPackageType implements PyType { + private final PsiPackage myPackage; + @Nullable private final Module myModule; + + public PyJavaPackageType(PsiPackage aPackage, @Nullable Module module) { + myPackage = aPackage; + myModule = module; + } + + @Override + public List resolveMember(String name, + @Nullable PyExpression location, + AccessDirection direction, + PyResolveContext resolveContext) { + Project project = myPackage.getProject(); + JavaPsiFacade facade = JavaPsiFacade.getInstance(project); + String childName = myPackage.getQualifiedName() + "." + name; + GlobalSearchScope scope = getScope(project); + List result = new ArrayList(); + Collections.addAll(result, facade.findClasses(childName, scope)); + final PsiPackage psiPackage = facade.findPackage(childName); + if (psiPackage != null) { + result.add(psiPackage); + } + return result; + } + + private GlobalSearchScope getScope(Project project) { + return myModule != null ? myModule.getModuleWithDependenciesAndLibrariesScope(false) : ProjectScope.getAllScope(project); + } + + @Override + public Object[] getCompletionVariants(String completionPrefix, PyExpression location, ProcessingContext context) { + List variants = new ArrayList(); + final GlobalSearchScope scope = getScope(location.getProject()); + final PsiClass[] classes = myPackage.getClasses(scope); + for (PsiClass psiClass : classes) { + variants.add(LookupElementBuilder.create(psiClass).setIcon(psiClass.getIcon(0))); + } + final PsiPackage[] subPackages = myPackage.getSubPackages(scope); + for (PsiPackage subPackage : subPackages) { + variants.add(LookupElementBuilder.create(subPackage).setIcon(subPackage.getIcon(0))); + } + return ArrayUtil.toObjectArray(variants); + } + + @Override + public String getName() { + return myPackage.getQualifiedName(); + } + + @Override + public boolean isBuiltin() { + return false; + } +} diff --git a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaTypeProvider.java b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaTypeProvider.java index 602f58a150fc..ae327c61856e 100644 --- a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaTypeProvider.java +++ b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaTypeProvider.java @@ -1,11 +1,11 @@ package com.jetbrains.python.psi.impl; +import com.intellij.openapi.module.ModuleUtil; import com.intellij.psi.*; import com.intellij.util.Processor; import com.jetbrains.python.psi.PyFunction; import com.jetbrains.python.psi.PyNamedParameter; import com.jetbrains.python.psi.PyParameterList; -import com.jetbrains.python.psi.PyReferenceExpression; import com.jetbrains.python.psi.search.PySuperMethodsSearch; import com.jetbrains.python.psi.types.PyType; import com.jetbrains.python.psi.types.PyTypeProviderBase; @@ -21,10 +21,13 @@ import java.util.List; */ public class PyJavaTypeProvider extends PyTypeProviderBase { @Nullable - public PyType getReferenceType(@NotNull final PsiElement referenceTarget, TypeEvalContext context) { + public PyType getReferenceType(@NotNull final PsiElement referenceTarget, TypeEvalContext context, @Nullable PsiElement anchor) { if (referenceTarget instanceof PsiClass) { return new PyJavaClassType((PsiClass) referenceTarget); } + if (referenceTarget instanceof PsiPackage) { + return new PyJavaPackageType((PsiPackage) referenceTarget, anchor == null ? null : ModuleUtil.findModuleForPsiElement(anchor)); + } if (referenceTarget instanceof PsiMethod) { PsiMethod method = (PsiMethod) referenceTarget; final PsiType type = method.getReturnType(); diff --git a/python/pluginTestSrc/com/jetbrains/jython/PyToJavaResolveTest.java b/python/pluginTestSrc/com/jetbrains/jython/PyToJavaResolveTest.java index b253755cc6bd..cc0c6840bea1 100644 --- a/python/pluginTestSrc/com/jetbrains/jython/PyToJavaResolveTest.java +++ b/python/pluginTestSrc/com/jetbrains/jython/PyToJavaResolveTest.java @@ -1,7 +1,5 @@ package com.jetbrains.jython; -import com.intellij.openapi.projectRoots.Sdk; -import com.intellij.openapi.projectRoots.impl.JavaSdkImpl; import com.intellij.psi.*; import com.intellij.testFramework.ResolveTestCase; import com.intellij.testFramework.TestDataPath; @@ -42,6 +40,24 @@ public class PyToJavaResolveTest extends ResolveTestCase { Assert.assertEquals("java.util.List", ((PsiMethod) target).getContainingClass().getQualifiedName()); } + public void testPackageType() throws Exception { + PsiElement target = resolve(); + Assert.assertTrue(target instanceof PsiClass); + Assert.assertEquals("java.util.ArrayList", ((PsiClass) target).getQualifiedName()); + } + + public void testJavaPackage() throws Exception { + PsiElement target = resolve(); + Assert.assertTrue(target instanceof PsiPackage); + Assert.assertEquals("java", ((PsiPackage) target).getQualifiedName()); + } + + public void testJavaLangPackage() throws Exception { + PsiElement target = resolve(); + Assert.assertTrue(target instanceof PsiPackage); + Assert.assertEquals("java.lang", ((PsiPackage) target).getQualifiedName()); + } + @Override protected String getTestDataPath() { return PythonTestUtil.getTestDataPath() + "/resolve/pyToJava/"; diff --git a/python/src/com/jetbrains/python/psi/impl/PyCallExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyCallExpressionImpl.java index 0564ad356396..d662a25743b3 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyCallExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyCallExpressionImpl.java @@ -99,7 +99,7 @@ public class PyCallExpressionImpl extends PyElementImpl implements PyCallExpress return new PyClassType(((PyFunction)target).getContainingClass(), false); // resolved to __init__, back to class } // TODO: look at well-known functions and their return types - final PyType providedType = PyReferenceExpressionImpl.getReferenceTypeFromProviders(target, context); + final PyType providedType = PyReferenceExpressionImpl.getReferenceTypeFromProviders(target, context, this); if (providedType != null) { return providedType; } diff --git a/python/src/com/jetbrains/python/psi/impl/PyImportResolver.java b/python/src/com/jetbrains/python/psi/impl/PyImportResolver.java index 119fed1a8a91..49a2ead0e01c 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyImportResolver.java +++ b/python/src/com/jetbrains/python/psi/impl/PyImportResolver.java @@ -12,5 +12,5 @@ public interface PyImportResolver { ExtensionPointName EP_NAME = ExtensionPointName.create("Pythonid.importResolver"); @Nullable - PsiElement resolveImportReference(PyElement importElement, String importText, final PsiElement importFrom); + PsiElement resolveImportReference(PyElement importElement, PyQualifiedName importText, PyQualifiedName importFrom); } diff --git a/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java index 6b40344e3914..710059bd7a0b 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java @@ -279,7 +279,7 @@ public class PyReferenceExpressionImpl extends PyElementImpl implements PyRefere public static PyType getTypeFromTarget(@NotNull final PsiElement target, final TypeEvalContext context, @Nullable PyReferenceExpression anchor) { - final PyType pyType = getReferenceTypeFromProviders(target, context); + final PyType pyType = getReferenceTypeFromProviders(target, context, anchor); if (pyType != null) { return pyType; } @@ -350,9 +350,11 @@ public class PyReferenceExpressionImpl extends PyElementImpl implements PyRefere } @Nullable - public static PyType getReferenceTypeFromProviders(@NotNull final PsiElement target, TypeEvalContext context) { + public static PyType getReferenceTypeFromProviders(@NotNull final PsiElement target, + TypeEvalContext context, + @Nullable PsiElement anchor) { for (PyTypeProvider provider : Extensions.getExtensions(PyTypeProvider.EP_NAME)) { - final PyType result = provider.getReferenceType(target, context); + final PyType result = provider.getReferenceType(target, context, anchor); if (result != null) return result; } diff --git a/python/src/com/jetbrains/python/psi/impl/PyTypeProvider.java b/python/src/com/jetbrains/python/psi/impl/PyTypeProvider.java index 2ca08981407f..7853cdace40f 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyTypeProvider.java +++ b/python/src/com/jetbrains/python/psi/impl/PyTypeProvider.java @@ -21,7 +21,7 @@ public interface PyTypeProvider { PyType getReferenceExpressionType(PyReferenceExpression referenceExpression, TypeEvalContext context); @Nullable - PyType getReferenceType(@NotNull PsiElement referenceTarget, TypeEvalContext context); + PyType getReferenceType(@NotNull PsiElement referenceTarget, TypeEvalContext context, @Nullable PsiElement anchor); @Nullable PyType getParameterType(PyNamedParameter param, final PyFunction func, TypeEvalContext context); diff --git a/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java b/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java index 893bb5c5ae28..c006ee13e7ec 100644 --- a/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java +++ b/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java @@ -138,16 +138,14 @@ public class ResolveImportUtil { } } else if (importStatement instanceof PyImportStatement) { // "import foo" - return resolveModule(qName, file, absolute_import_enabled, 0); + final List result = resolveModule(qName, file, absolute_import_enabled, 0); + if (result.size() > 0) { + return result; + } } // in-python resolution failed - if (moduleQName != null) { - final List importFrom = resolveModule(moduleQName, file, false, 0); - final PsiElement result = resolveForeignImport(import_element, StringUtil.join(qName.getComponents(), "."), - importFrom.isEmpty() ? null : importFrom.get(0)); - return result != null ? Collections.singletonList(result) : Collections.emptyList(); - } - return Collections.emptyList(); + final PsiElement result = resolveForeignImport(import_element, qName, moduleQName); + return result != null ? Collections.singletonList(result) : Collections.emptyList(); } @NotNull @@ -500,7 +498,7 @@ public class ResolveImportUtil { } @Nullable - private static PsiElement resolveForeignImport(final PyElement importElement, final String importText, final PsiElement importFrom) { + private static PsiElement resolveForeignImport(final PyElement importElement, final PyQualifiedName importText, final PyQualifiedName importFrom) { for (PyImportResolver resolver : Extensions.getExtensions(PyImportResolver.EP_NAME)) { PsiElement result = resolver.resolveImportReference(importElement, importText, importFrom); if (result != null) { diff --git a/python/src/com/jetbrains/python/psi/types/PyTypeProviderBase.java b/python/src/com/jetbrains/python/psi/types/PyTypeProviderBase.java index 6e49c3236acb..a361d3d1d7d1 100644 --- a/python/src/com/jetbrains/python/psi/types/PyTypeProviderBase.java +++ b/python/src/com/jetbrains/python/psi/types/PyTypeProviderBase.java @@ -69,7 +69,7 @@ public class PyTypeProviderBase implements PyTypeProvider { } @Override - public PyType getReferenceType(@NotNull PsiElement referenceTarget, TypeEvalContext context) { + public PyType getReferenceType(@NotNull PsiElement referenceTarget, TypeEvalContext context, @Nullable PsiElement anchor) { return null; } diff --git a/python/testData/resolve/pyToJava/JavaLangPackage.py b/python/testData/resolve/pyToJava/JavaLangPackage.py new file mode 100644 index 000000000000..d4a9a25a09e5 --- /dev/null +++ b/python/testData/resolve/pyToJava/JavaLangPackage.py @@ -0,0 +1,3 @@ +import java + +java.lang.System.out \ No newline at end of file diff --git a/python/testData/resolve/pyToJava/JavaPackage.py b/python/testData/resolve/pyToJava/JavaPackage.py new file mode 100644 index 000000000000..2f6353ed80ec --- /dev/null +++ b/python/testData/resolve/pyToJava/JavaPackage.py @@ -0,0 +1 @@ +import java \ No newline at end of file diff --git a/python/testData/resolve/pyToJava/PackageType.py b/python/testData/resolve/pyToJava/PackageType.py new file mode 100644 index 000000000000..539843343d11 --- /dev/null +++ b/python/testData/resolve/pyToJava/PackageType.py @@ -0,0 +1,4 @@ +import java +from java import util + +l = util.ArrayList() \ No newline at end of file